widget/gtk/nsWindow.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/gtk/nsWindow.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,6302 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim:expandtab:shiftwidth=4:tabstop=4:
     1.6 + */
     1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +#include "mozilla/ArrayUtils.h"
    1.12 +#include "mozilla/MiscEvents.h"
    1.13 +#include "mozilla/MouseEvents.h"
    1.14 +#include "mozilla/TextEvents.h"
    1.15 +#include <algorithm>
    1.16 +
    1.17 +#include "prlink.h"
    1.18 +#include "nsGTKToolkit.h"
    1.19 +#include "nsIRollupListener.h"
    1.20 +#include "nsIDOMNode.h"
    1.21 +
    1.22 +#include "nsWidgetsCID.h"
    1.23 +#include "nsDragService.h"
    1.24 +#include "nsIWidgetListener.h"
    1.25 +
    1.26 +#include "nsGtkKeyUtils.h"
    1.27 +#include "nsGtkCursors.h"
    1.28 +
    1.29 +#include <gtk/gtk.h>
    1.30 +#if (MOZ_WIDGET_GTK == 3)
    1.31 +#include <gtk/gtkx.h>
    1.32 +#endif
    1.33 +#ifdef MOZ_X11
    1.34 +#include <gdk/gdkx.h>
    1.35 +#include <X11/Xatom.h>
    1.36 +#include <X11/extensions/XShm.h>
    1.37 +#include <X11/extensions/shape.h>
    1.38 +#if (MOZ_WIDGET_GTK == 3)
    1.39 +#include <gdk/gdkkeysyms-compat.h>
    1.40 +#endif
    1.41 +
    1.42 +#ifdef AIX
    1.43 +#include <X11/keysym.h>
    1.44 +#else
    1.45 +#include <X11/XF86keysym.h>
    1.46 +#endif
    1.47 +
    1.48 +#if (MOZ_WIDGET_GTK == 2)
    1.49 +#include "gtk2xtbin.h"
    1.50 +#endif
    1.51 +#endif /* MOZ_X11 */
    1.52 +#include <gdk/gdkkeysyms.h>
    1.53 +#if (MOZ_WIDGET_GTK == 2)
    1.54 +#include <gtk/gtkprivate.h>
    1.55 +#endif
    1.56 +
    1.57 +#include "nsGkAtoms.h"
    1.58 +
    1.59 +#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
    1.60 +#define SN_API_NOT_YET_FROZEN
    1.61 +#include <startup-notification-1.0/libsn/sn.h>
    1.62 +#endif
    1.63 +
    1.64 +#include "mozilla/Likely.h"
    1.65 +#include "mozilla/Preferences.h"
    1.66 +#include "nsIPrefService.h"
    1.67 +#include "nsIGConfService.h"
    1.68 +#include "nsIServiceManager.h"
    1.69 +#include "nsIStringBundle.h"
    1.70 +#include "nsGfxCIID.h"
    1.71 +#include "nsGtkUtils.h"
    1.72 +#include "nsIObserverService.h"
    1.73 +#include "mozilla/layers/LayersTypes.h"
    1.74 +#include "nsIIdleServiceInternal.h"
    1.75 +#include "nsIPropertyBag2.h"
    1.76 +#include "GLContext.h"
    1.77 +#include "gfx2DGlue.h"
    1.78 +
    1.79 +#ifdef ACCESSIBILITY
    1.80 +#include "mozilla/a11y/Accessible.h"
    1.81 +#include "mozilla/a11y/Platform.h"
    1.82 +#include "nsAccessibilityService.h"
    1.83 +
    1.84 +using namespace mozilla;
    1.85 +using namespace mozilla::widget;
    1.86 +#endif
    1.87 +
    1.88 +/* For SetIcon */
    1.89 +#include "nsAppDirectoryServiceDefs.h"
    1.90 +#include "nsXPIDLString.h"
    1.91 +#include "nsIFile.h"
    1.92 +
    1.93 +/* SetCursor(imgIContainer*) */
    1.94 +#include <gdk/gdk.h>
    1.95 +#include <wchar.h>
    1.96 +#include "imgIContainer.h"
    1.97 +#include "nsGfxCIID.h"
    1.98 +#include "nsImageToPixbuf.h"
    1.99 +#include "nsIInterfaceRequestorUtils.h"
   1.100 +#include "nsAutoPtr.h"
   1.101 +#include "ClientLayerManager.h"
   1.102 +
   1.103 +extern "C" {
   1.104 +#define PIXMAN_DONT_DEFINE_STDINT
   1.105 +#include "pixman.h"
   1.106 +}
   1.107 +#include "gfxPlatformGtk.h"
   1.108 +#include "gfxContext.h"
   1.109 +#include "gfxImageSurface.h"
   1.110 +#include "gfxUtils.h"
   1.111 +#include "Layers.h"
   1.112 +#include "GLContextProvider.h"
   1.113 +#include "mozilla/gfx/2D.h"
   1.114 +#include "mozilla/layers/CompositorParent.h"
   1.115 +
   1.116 +#ifdef MOZ_X11
   1.117 +#include "gfxXlibSurface.h"
   1.118 +#include "cairo-xlib.h"
   1.119 +#endif
   1.120 +  
   1.121 +#include "nsShmImage.h"
   1.122 +
   1.123 +#include "nsIDOMWheelEvent.h"
   1.124 +
   1.125 +#include "NativeKeyBindings.h"
   1.126 +#include "nsWindow.h"
   1.127 +
   1.128 +using namespace mozilla;
   1.129 +using namespace mozilla::gfx;
   1.130 +using namespace mozilla::widget;
   1.131 +using namespace mozilla::layers;
   1.132 +using mozilla::gl::GLContext;
   1.133 +
   1.134 +// Don't put more than this many rects in the dirty region, just fluff
   1.135 +// out to the bounding-box if there are more
   1.136 +#define MAX_RECTS_IN_REGION 100
   1.137 +
   1.138 +const gint kEvents = GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
   1.139 +                     GDK_VISIBILITY_NOTIFY_MASK |
   1.140 +                     GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
   1.141 +                     GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
   1.142 +                     GDK_SCROLL_MASK |
   1.143 +                     GDK_POINTER_MOTION_MASK;
   1.144 +
   1.145 +/* utility functions */
   1.146 +static bool       is_mouse_in_window(GdkWindow* aWindow,
   1.147 +                                     gdouble aMouseX, gdouble aMouseY);
   1.148 +static nsWindow  *get_window_for_gtk_widget(GtkWidget *widget);
   1.149 +static nsWindow  *get_window_for_gdk_window(GdkWindow *window);
   1.150 +static GtkWidget *get_gtk_widget_for_gdk_window(GdkWindow *window);
   1.151 +static GdkCursor *get_gtk_cursor(nsCursor aCursor);
   1.152 +
   1.153 +static GdkWindow *get_inner_gdk_window (GdkWindow *aWindow,
   1.154 +                                        gint x, gint y,
   1.155 +                                        gint *retx, gint *rety);
   1.156 +
   1.157 +static inline bool is_context_menu_key(const WidgetKeyboardEvent& inKeyEvent);
   1.158 +
   1.159 +static int    is_parent_ungrab_enter(GdkEventCrossing *aEvent);
   1.160 +static int    is_parent_grab_leave(GdkEventCrossing *aEvent);
   1.161 +
   1.162 +static void GetBrandName(nsXPIDLString& brandName);
   1.163 +
   1.164 +/* callbacks from widgets */
   1.165 +#if (MOZ_WIDGET_GTK == 2)
   1.166 +static gboolean expose_event_cb           (GtkWidget *widget,
   1.167 +                                           GdkEventExpose *event);
   1.168 +#else
   1.169 +static gboolean expose_event_cb           (GtkWidget *widget,
   1.170 +                                           cairo_t *rect);
   1.171 +#endif
   1.172 +static gboolean configure_event_cb        (GtkWidget *widget,
   1.173 +                                           GdkEventConfigure *event);
   1.174 +static void     container_unrealize_cb    (GtkWidget *widget);
   1.175 +static void     size_allocate_cb          (GtkWidget *widget,
   1.176 +                                           GtkAllocation *allocation);
   1.177 +static gboolean delete_event_cb           (GtkWidget *widget,
   1.178 +                                           GdkEventAny *event);
   1.179 +static gboolean enter_notify_event_cb     (GtkWidget *widget,
   1.180 +                                           GdkEventCrossing *event);
   1.181 +static gboolean leave_notify_event_cb     (GtkWidget *widget,
   1.182 +                                           GdkEventCrossing *event);
   1.183 +static gboolean motion_notify_event_cb    (GtkWidget *widget,
   1.184 +                                           GdkEventMotion *event);
   1.185 +static gboolean button_press_event_cb     (GtkWidget *widget,
   1.186 +                                           GdkEventButton *event);
   1.187 +static gboolean button_release_event_cb   (GtkWidget *widget,
   1.188 +                                           GdkEventButton *event);
   1.189 +static gboolean focus_in_event_cb         (GtkWidget *widget,
   1.190 +                                           GdkEventFocus *event);
   1.191 +static gboolean focus_out_event_cb        (GtkWidget *widget,
   1.192 +                                           GdkEventFocus *event);
   1.193 +static gboolean key_press_event_cb        (GtkWidget *widget,
   1.194 +                                           GdkEventKey *event);
   1.195 +static gboolean key_release_event_cb      (GtkWidget *widget,
   1.196 +                                           GdkEventKey *event);
   1.197 +static gboolean scroll_event_cb           (GtkWidget *widget,
   1.198 +                                           GdkEventScroll *event);
   1.199 +static gboolean visibility_notify_event_cb(GtkWidget *widget,
   1.200 +                                           GdkEventVisibility *event);
   1.201 +static void     hierarchy_changed_cb      (GtkWidget *widget,
   1.202 +                                           GtkWidget *previous_toplevel);
   1.203 +static gboolean window_state_event_cb     (GtkWidget *widget,
   1.204 +                                           GdkEventWindowState *event);
   1.205 +static void     theme_changed_cb          (GtkSettings *settings,
   1.206 +                                           GParamSpec *pspec,
   1.207 +                                           nsWindow *data);
   1.208 +static nsWindow* GetFirstNSWindowForGDKWindow (GdkWindow *aGdkWindow);
   1.209 +
   1.210 +#ifdef __cplusplus
   1.211 +extern "C" {
   1.212 +#endif /* __cplusplus */
   1.213 +#ifdef MOZ_X11
   1.214 +static GdkFilterReturn popup_take_focus_filter (GdkXEvent *gdk_xevent,
   1.215 +                                                GdkEvent *event,
   1.216 +                                                gpointer data);
   1.217 +static GdkFilterReturn plugin_window_filter_func (GdkXEvent *gdk_xevent,
   1.218 +                                                  GdkEvent *event,
   1.219 +                                                  gpointer data);
   1.220 +static GdkFilterReturn plugin_client_message_filter (GdkXEvent *xevent,
   1.221 +                                                     GdkEvent *event,
   1.222 +                                                     gpointer data);
   1.223 +#endif /* MOZ_X11 */
   1.224 +#ifdef __cplusplus
   1.225 +}
   1.226 +#endif /* __cplusplus */
   1.227 +
   1.228 +static gboolean drag_motion_event_cb      (GtkWidget *aWidget,
   1.229 +                                           GdkDragContext *aDragContext,
   1.230 +                                           gint aX,
   1.231 +                                           gint aY,
   1.232 +                                           guint aTime,
   1.233 +                                           gpointer aData);
   1.234 +static void     drag_leave_event_cb       (GtkWidget *aWidget,
   1.235 +                                           GdkDragContext *aDragContext,
   1.236 +                                           guint aTime,
   1.237 +                                           gpointer aData);
   1.238 +static gboolean drag_drop_event_cb        (GtkWidget *aWidget,
   1.239 +                                           GdkDragContext *aDragContext,
   1.240 +                                           gint aX,
   1.241 +                                           gint aY,
   1.242 +                                           guint aTime,
   1.243 +                                           gpointer aData);
   1.244 +static void    drag_data_received_event_cb(GtkWidget *aWidget,
   1.245 +                                           GdkDragContext *aDragContext,
   1.246 +                                           gint aX,
   1.247 +                                           gint aY,
   1.248 +                                           GtkSelectionData  *aSelectionData,
   1.249 +                                           guint aInfo,
   1.250 +                                           guint32 aTime,
   1.251 +                                           gpointer aData);
   1.252 +
   1.253 +/* initialization static functions */
   1.254 +static nsresult    initialize_prefs        (void);
   1.255 +
   1.256 +static guint32 sLastUserInputTime = GDK_CURRENT_TIME;
   1.257 +static guint32 sRetryGrabTime;
   1.258 +
   1.259 +static NS_DEFINE_IID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
   1.260 +
   1.261 +// The window from which the focus manager asks us to dispatch key events.
   1.262 +static nsWindow         *gFocusWindow          = nullptr;
   1.263 +static bool              gBlockActivateEvent   = false;
   1.264 +static bool              gGlobalsInitialized   = false;
   1.265 +static bool              gRaiseWindows         = true;
   1.266 +static nsWindow         *gPluginFocusWindow    = nullptr;
   1.267 +
   1.268 +
   1.269 +#define NS_WINDOW_TITLE_MAX_LENGTH 4095
   1.270 +
   1.271 +// If after selecting profile window, the startup fail, please refer to
   1.272 +// http://bugzilla.gnome.org/show_bug.cgi?id=88940
   1.273 +
   1.274 +// needed for imgIContainer cursors
   1.275 +// GdkDisplay* was added in 2.2
   1.276 +typedef struct _GdkDisplay GdkDisplay;
   1.277 +
   1.278 +#define kWindowPositionSlop 20
   1.279 +
   1.280 +// cursor cache
   1.281 +static GdkCursor *gCursorCache[eCursorCount];
   1.282 +
   1.283 +static GtkWidget *gInvisibleContainer = nullptr;
   1.284 +
   1.285 +// Sometimes this actually also includes the state of the modifier keys, but
   1.286 +// only the button state bits are used.
   1.287 +static guint gButtonState;
   1.288 +
   1.289 +// nsAutoRef<pixman_region32> uses nsSimpleRef<> to know how to automatically
   1.290 +// destroy regions.
   1.291 +template <>
   1.292 +class nsSimpleRef<pixman_region32> : public pixman_region32 {
   1.293 +protected:
   1.294 +    typedef pixman_region32 RawRef;
   1.295 +
   1.296 +    nsSimpleRef() { data = nullptr; }
   1.297 +    nsSimpleRef(const RawRef &aRawRef) : pixman_region32(aRawRef) { }
   1.298 +
   1.299 +    static void Release(pixman_region32& region) {
   1.300 +        pixman_region32_fini(&region);
   1.301 +    }
   1.302 +    // Whether this needs to be released:
   1.303 +    bool HaveResource() const { return data != nullptr; }
   1.304 +
   1.305 +    pixman_region32& get() { return *this; }
   1.306 +};
   1.307 +
   1.308 +static inline int32_t
   1.309 +GetBitmapStride(int32_t width)
   1.310 +{
   1.311 +#if defined(MOZ_X11) || (MOZ_WIDGET_GTK == 2)
   1.312 +  return (width+7)/8;
   1.313 +#else
   1.314 +  return cairo_format_stride_for_width(CAIRO_FORMAT_A1, width);
   1.315 +#endif
   1.316 +}
   1.317 +
   1.318 +static inline bool TimestampIsNewerThan(guint32 a, guint32 b)
   1.319 +{
   1.320 +    // Timestamps are just the least significant bits of a monotonically
   1.321 +    // increasing function, and so the use of unsigned overflow arithmetic.
   1.322 +    return a - b <= G_MAXUINT32/2;
   1.323 +}
   1.324 +
   1.325 +static void
   1.326 +UpdateLastInputEventTime(void *aGdkEvent)
   1.327 +{
   1.328 +    nsCOMPtr<nsIIdleServiceInternal> idleService =
   1.329 +        do_GetService("@mozilla.org/widget/idleservice;1");
   1.330 +    if (idleService) {
   1.331 +        idleService->ResetIdleTimeOut(0);
   1.332 +    }
   1.333 +
   1.334 +    guint timestamp = gdk_event_get_time(static_cast<GdkEvent*>(aGdkEvent));
   1.335 +    if (timestamp == GDK_CURRENT_TIME)
   1.336 +        return;
   1.337 +
   1.338 +    sLastUserInputTime = timestamp;
   1.339 +}
   1.340 +
   1.341 +nsWindow::nsWindow()
   1.342 +{
   1.343 +    mIsTopLevel       = false;
   1.344 +    mIsDestroyed      = false;
   1.345 +    mNeedsResize      = false;
   1.346 +    mNeedsMove        = false;
   1.347 +    mListenForResizes = false;
   1.348 +    mIsShown          = false;
   1.349 +    mNeedsShow        = false;
   1.350 +    mEnabled          = true;
   1.351 +    mCreated          = false;
   1.352 +
   1.353 +    mContainer           = nullptr;
   1.354 +    mGdkWindow           = nullptr;
   1.355 +    mShell               = nullptr;
   1.356 +    mHasMappedToplevel   = false;
   1.357 +    mIsFullyObscured     = false;
   1.358 +    mRetryPointerGrab    = false;
   1.359 +    mWindowType          = eWindowType_child;
   1.360 +    mSizeState           = nsSizeMode_Normal;
   1.361 +    mLastSizeMode        = nsSizeMode_Normal;
   1.362 +    mSizeConstraints.mMaxSize = GetSafeWindowSize(mSizeConstraints.mMaxSize);
   1.363 +
   1.364 +#ifdef MOZ_X11
   1.365 +    mOldFocusWindow      = 0;
   1.366 +#endif /* MOZ_X11 */
   1.367 +    mPluginType          = PluginType_NONE;
   1.368 +
   1.369 +    if (!gGlobalsInitialized) {
   1.370 +        gGlobalsInitialized = true;
   1.371 +
   1.372 +        // It's OK if either of these fail, but it may not be one day.
   1.373 +        initialize_prefs();
   1.374 +    }
   1.375 +
   1.376 +    mLastMotionPressure = 0;
   1.377 +
   1.378 +#ifdef ACCESSIBILITY
   1.379 +    mRootAccessible  = nullptr;
   1.380 +#endif
   1.381 +
   1.382 +    mIsTransparent = false;
   1.383 +    mTransparencyBitmap = nullptr;
   1.384 +
   1.385 +    mTransparencyBitmapWidth  = 0;
   1.386 +    mTransparencyBitmapHeight = 0;
   1.387 +}
   1.388 +
   1.389 +nsWindow::~nsWindow()
   1.390 +{
   1.391 +    LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
   1.392 +
   1.393 +    delete[] mTransparencyBitmap;
   1.394 +    mTransparencyBitmap = nullptr;
   1.395 +
   1.396 +    Destroy();
   1.397 +}
   1.398 +
   1.399 +/* static */ void
   1.400 +nsWindow::ReleaseGlobals()
   1.401 +{
   1.402 +  for (uint32_t i = 0; i < ArrayLength(gCursorCache); ++i) {
   1.403 +    if (gCursorCache[i]) {
   1.404 +      gdk_cursor_unref(gCursorCache[i]);
   1.405 +      gCursorCache[i] = nullptr;
   1.406 +    }
   1.407 +  }
   1.408 +}
   1.409 +
   1.410 +NS_IMPL_ISUPPORTS_INHERITED(nsWindow, nsBaseWidget,
   1.411 +                            nsISupportsWeakReference)
   1.412 +
   1.413 +void
   1.414 +nsWindow::CommonCreate(nsIWidget *aParent, bool aListenForResizes)
   1.415 +{
   1.416 +    mParent = aParent;
   1.417 +    mListenForResizes = aListenForResizes;
   1.418 +    mCreated = true;
   1.419 +}
   1.420 +
   1.421 +void
   1.422 +nsWindow::DispatchActivateEvent(void)
   1.423 +{
   1.424 +    NS_ASSERTION(mContainer || mIsDestroyed,
   1.425 +                 "DispatchActivateEvent only intended for container windows");
   1.426 +
   1.427 +#ifdef ACCESSIBILITY
   1.428 +    DispatchActivateEventAccessible();
   1.429 +#endif //ACCESSIBILITY
   1.430 +
   1.431 +    if (mWidgetListener)
   1.432 +      mWidgetListener->WindowActivated();
   1.433 +}
   1.434 +
   1.435 +void
   1.436 +nsWindow::DispatchDeactivateEvent(void)
   1.437 +{
   1.438 +    if (mWidgetListener)
   1.439 +      mWidgetListener->WindowDeactivated();
   1.440 +
   1.441 +#ifdef ACCESSIBILITY
   1.442 +    DispatchDeactivateEventAccessible();
   1.443 +#endif //ACCESSIBILITY
   1.444 +}
   1.445 +
   1.446 +void
   1.447 +nsWindow::DispatchResized(int32_t aWidth, int32_t aHeight)
   1.448 +{
   1.449 +    nsIWidgetListener *listeners[] =
   1.450 +        { mWidgetListener, mAttachedWidgetListener };
   1.451 +    for (size_t i = 0; i < ArrayLength(listeners); ++i) {
   1.452 +        if (listeners[i]) {
   1.453 +            listeners[i]->WindowResized(this, aWidth, aHeight);
   1.454 +        }
   1.455 +    }
   1.456 +}
   1.457 +
   1.458 +nsresult
   1.459 +nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
   1.460 +{
   1.461 +#ifdef DEBUG
   1.462 +    debug_DumpEvent(stdout, aEvent->widget, aEvent,
   1.463 +                    nsAutoCString("something"), 0);
   1.464 +#endif
   1.465 +
   1.466 +    aStatus = nsEventStatus_eIgnore;
   1.467 +    nsIWidgetListener* listener =
   1.468 +        mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
   1.469 +    if (listener) {
   1.470 +      aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
   1.471 +    }
   1.472 +
   1.473 +    return NS_OK;
   1.474 +}
   1.475 +
   1.476 +void
   1.477 +nsWindow::OnDestroy(void)
   1.478 +{
   1.479 +    if (mOnDestroyCalled)
   1.480 +        return;
   1.481 +
   1.482 +    mOnDestroyCalled = true;
   1.483 +    
   1.484 +    // Prevent deletion.
   1.485 +    nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
   1.486 +
   1.487 +    // release references to children, device context, toolkit + app shell
   1.488 +    nsBaseWidget::OnDestroy(); 
   1.489 +    
   1.490 +    // Remove association between this object and its parent and siblings.
   1.491 +    nsBaseWidget::Destroy();
   1.492 +    mParent = nullptr;
   1.493 +
   1.494 +    NotifyWindowDestroyed();
   1.495 +}
   1.496 +
   1.497 +bool
   1.498 +nsWindow::AreBoundsSane(void)
   1.499 +{
   1.500 +    if (mBounds.width > 0 && mBounds.height > 0)
   1.501 +        return true;
   1.502 +
   1.503 +    return false;
   1.504 +}
   1.505 +
   1.506 +static GtkWidget*
   1.507 +EnsureInvisibleContainer()
   1.508 +{
   1.509 +    if (!gInvisibleContainer) {
   1.510 +        // GtkWidgets need to be anchored to a GtkWindow to be realized (to
   1.511 +        // have a window).  Using GTK_WINDOW_POPUP rather than
   1.512 +        // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
   1.513 +        // initialization and window manager interaction.
   1.514 +        GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
   1.515 +        gInvisibleContainer = moz_container_new();
   1.516 +        gtk_container_add(GTK_CONTAINER(window), gInvisibleContainer);
   1.517 +        gtk_widget_realize(gInvisibleContainer);
   1.518 +
   1.519 +    }
   1.520 +    return gInvisibleContainer;
   1.521 +}
   1.522 +
   1.523 +static void
   1.524 +CheckDestroyInvisibleContainer()
   1.525 +{
   1.526 +    NS_PRECONDITION(gInvisibleContainer, "oh, no");
   1.527 +
   1.528 +    if (!gdk_window_peek_children(gtk_widget_get_window(gInvisibleContainer))) {
   1.529 +        // No children, so not in use.
   1.530 +        // Make sure to destroy the GtkWindow also.
   1.531 +        gtk_widget_destroy(gtk_widget_get_parent(gInvisibleContainer));
   1.532 +        gInvisibleContainer = nullptr;
   1.533 +    }
   1.534 +}
   1.535 +
   1.536 +// Change the containing GtkWidget on a sub-hierarchy of GdkWindows belonging
   1.537 +// to aOldWidget and rooted at aWindow, and reparent any child GtkWidgets of
   1.538 +// the GdkWindow hierarchy to aNewWidget.
   1.539 +static void
   1.540 +SetWidgetForHierarchy(GdkWindow *aWindow,
   1.541 +                      GtkWidget *aOldWidget,
   1.542 +                      GtkWidget *aNewWidget)
   1.543 +{
   1.544 +    gpointer data;
   1.545 +    gdk_window_get_user_data(aWindow, &data);
   1.546 +
   1.547 +    if (data != aOldWidget) {
   1.548 +        if (!GTK_IS_WIDGET(data))
   1.549 +            return;
   1.550 +
   1.551 +        GtkWidget* widget = static_cast<GtkWidget*>(data);
   1.552 +        if (gtk_widget_get_parent(widget) != aOldWidget)
   1.553 +            return;
   1.554 +
   1.555 +        // This window belongs to a child widget, which will no longer be a
   1.556 +        // child of aOldWidget.
   1.557 +        gtk_widget_reparent(widget, aNewWidget);
   1.558 +
   1.559 +        return;
   1.560 +    }
   1.561 +
   1.562 +    GList *children = gdk_window_get_children(aWindow);
   1.563 +    for(GList *list = children; list; list = list->next) {
   1.564 +        SetWidgetForHierarchy(GDK_WINDOW(list->data), aOldWidget, aNewWidget);
   1.565 +    }
   1.566 +    g_list_free(children);
   1.567 +
   1.568 +    gdk_window_set_user_data(aWindow, aNewWidget);
   1.569 +}
   1.570 +
   1.571 +// Walk the list of child windows and call destroy on them.
   1.572 +void
   1.573 +nsWindow::DestroyChildWindows()
   1.574 +{
   1.575 +    if (!mGdkWindow)
   1.576 +        return;
   1.577 +
   1.578 +    while (GList *children = gdk_window_peek_children(mGdkWindow)) {
   1.579 +        GdkWindow *child = GDK_WINDOW(children->data);
   1.580 +        nsWindow *kid = get_window_for_gdk_window(child);
   1.581 +        if (kid) {
   1.582 +            kid->Destroy();
   1.583 +        } else {
   1.584 +            // This child is not an nsWindow.
   1.585 +            // Destroy the child GtkWidget.
   1.586 +            gpointer data;
   1.587 +            gdk_window_get_user_data(child, &data);
   1.588 +            if (GTK_IS_WIDGET(data)) {
   1.589 +                gtk_widget_destroy(static_cast<GtkWidget*>(data));
   1.590 +            }
   1.591 +        }
   1.592 +    }
   1.593 +}
   1.594 +
   1.595 +NS_IMETHODIMP
   1.596 +nsWindow::Destroy(void)
   1.597 +{
   1.598 +    if (mIsDestroyed || !mCreated)
   1.599 +        return NS_OK;
   1.600 +
   1.601 +    LOG(("nsWindow::Destroy [%p]\n", (void *)this));
   1.602 +    mIsDestroyed = true;
   1.603 +    mCreated = false;
   1.604 +
   1.605 +    /** Need to clean our LayerManager up while still alive */
   1.606 +    if (mLayerManager) {
   1.607 +        mLayerManager->Destroy();
   1.608 +    }
   1.609 +    mLayerManager = nullptr;
   1.610 +
   1.611 +    // It is safe to call DestroyeCompositor several times (here and 
   1.612 +    // in the parent class) since it will take effect only once.
   1.613 +    // The reason we call it here is because on gtk platforms we need 
   1.614 +    // to destroy the compositor before we destroy the gdk window (which
   1.615 +    // destroys the the gl context attached to it).
   1.616 +    DestroyCompositor();
   1.617 +
   1.618 +    ClearCachedResources();
   1.619 +
   1.620 +    g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
   1.621 +                                         FuncToGpointer(theme_changed_cb),
   1.622 +                                         this);
   1.623 +
   1.624 +    nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
   1.625 +    if (rollupListener) {
   1.626 +        nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
   1.627 +        if (static_cast<nsIWidget *>(this) == rollupWidget) {
   1.628 +            rollupListener->Rollup(0, nullptr, nullptr);
   1.629 +        }
   1.630 +    }
   1.631 +
   1.632 +    // dragService will be null after shutdown of the service manager.
   1.633 +    nsDragService *dragService = nsDragService::GetInstance();
   1.634 +    if (dragService && this == dragService->GetMostRecentDestWindow()) {
   1.635 +        dragService->ScheduleLeaveEvent();
   1.636 +    }
   1.637 +
   1.638 +    NativeShow(false);
   1.639 +
   1.640 +    if (mIMModule) {
   1.641 +        mIMModule->OnDestroyWindow(this);
   1.642 +    }
   1.643 +
   1.644 +    // make sure that we remove ourself as the focus window
   1.645 +    if (gFocusWindow == this) {
   1.646 +        LOGFOCUS(("automatically losing focus...\n"));
   1.647 +        gFocusWindow = nullptr;
   1.648 +    }
   1.649 +
   1.650 +#if (MOZ_WIDGET_GTK == 2) && defined(MOZ_X11)
   1.651 +    // make sure that we remove ourself as the plugin focus window
   1.652 +    if (gPluginFocusWindow == this) {
   1.653 +        gPluginFocusWindow->LoseNonXEmbedPluginFocus();
   1.654 +    }
   1.655 +#endif /* MOZ_X11 && MOZ_WIDGET_GTK2 */
   1.656 +  
   1.657 +    // Destroy thebes surface now. Badness can happen if we destroy
   1.658 +    // the surface after its X Window.
   1.659 +    mThebesSurface = nullptr;
   1.660 +
   1.661 +    GtkWidget *owningWidget = GetMozContainerWidget();
   1.662 +    if (mShell) {
   1.663 +        gtk_widget_destroy(mShell);
   1.664 +        mShell = nullptr;
   1.665 +        mContainer = nullptr;
   1.666 +        NS_ABORT_IF_FALSE(!mGdkWindow,
   1.667 +                          "mGdkWindow should be NULL when mContainer is destroyed");
   1.668 +    }
   1.669 +    else if (mContainer) {
   1.670 +        gtk_widget_destroy(GTK_WIDGET(mContainer));
   1.671 +        mContainer = nullptr;
   1.672 +        NS_ABORT_IF_FALSE(!mGdkWindow,
   1.673 +                          "mGdkWindow should be NULL when mContainer is destroyed");
   1.674 +    }
   1.675 +    else if (mGdkWindow) {
   1.676 +        // Destroy child windows to ensure that their mThebesSurfaces are
   1.677 +        // released and to remove references from GdkWindows back to their
   1.678 +        // container widget.  (OnContainerUnrealize() does this when the
   1.679 +        // MozContainer widget is destroyed.)
   1.680 +        DestroyChildWindows();
   1.681 +
   1.682 +        gdk_window_set_user_data(mGdkWindow, nullptr);
   1.683 +        g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
   1.684 +        gdk_window_destroy(mGdkWindow);
   1.685 +        mGdkWindow = nullptr;
   1.686 +    }
   1.687 +
   1.688 +    if (gInvisibleContainer && owningWidget == gInvisibleContainer) {
   1.689 +        CheckDestroyInvisibleContainer();
   1.690 +    }
   1.691 +
   1.692 +#ifdef ACCESSIBILITY
   1.693 +     if (mRootAccessible) {
   1.694 +         mRootAccessible = nullptr;
   1.695 +     }
   1.696 +#endif
   1.697 +
   1.698 +    // Save until last because OnDestroy() may cause us to be deleted.
   1.699 +    OnDestroy();
   1.700 +
   1.701 +    return NS_OK;
   1.702 +}
   1.703 +
   1.704 +nsIWidget *
   1.705 +nsWindow::GetParent(void)
   1.706 +{
   1.707 +    return mParent;
   1.708 +}
   1.709 +
   1.710 +float
   1.711 +nsWindow::GetDPI()
   1.712 +{
   1.713 +    Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
   1.714 +    int defaultScreen = DefaultScreen(dpy);
   1.715 +    double heightInches = DisplayHeightMM(dpy, defaultScreen)/MM_PER_INCH_FLOAT;
   1.716 +    if (heightInches < 0.25) {
   1.717 +        // Something's broken, but we'd better not crash.
   1.718 +        return 96.0f;
   1.719 +    }
   1.720 +    return float(DisplayHeight(dpy, defaultScreen)/heightInches);
   1.721 +}
   1.722 +
   1.723 +NS_IMETHODIMP
   1.724 +nsWindow::SetParent(nsIWidget *aNewParent)
   1.725 +{
   1.726 +    if (mContainer || !mGdkWindow) {
   1.727 +        NS_NOTREACHED("nsWindow::SetParent called illegally");
   1.728 +        return NS_ERROR_NOT_IMPLEMENTED;
   1.729 +    }
   1.730 +
   1.731 +    nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
   1.732 +    if (mParent) {
   1.733 +        mParent->RemoveChild(this);
   1.734 +    }
   1.735 +
   1.736 +    mParent = aNewParent;
   1.737 +
   1.738 +    GtkWidget* oldContainer = GetMozContainerWidget();
   1.739 +    if (!oldContainer) {
   1.740 +        // The GdkWindows have been destroyed so there is nothing else to
   1.741 +        // reparent.
   1.742 +        NS_ABORT_IF_FALSE(gdk_window_is_destroyed(mGdkWindow),
   1.743 +                          "live GdkWindow with no widget");
   1.744 +        return NS_OK;
   1.745 +    }
   1.746 +
   1.747 +    if (aNewParent) {
   1.748 +        aNewParent->AddChild(this);
   1.749 +        ReparentNativeWidget(aNewParent);
   1.750 +    } else {
   1.751 +        // aNewParent is nullptr, but reparent to a hidden window to avoid
   1.752 +        // destroying the GdkWindow and its descendants.
   1.753 +        // An invisible container widget is needed to hold descendant
   1.754 +        // GtkWidgets.
   1.755 +        GtkWidget* newContainer = EnsureInvisibleContainer();
   1.756 +        GdkWindow* newParentWindow = gtk_widget_get_window(newContainer);
   1.757 +        ReparentNativeWidgetInternal(aNewParent, newContainer, newParentWindow,
   1.758 +                                     oldContainer);
   1.759 +    }
   1.760 +    return NS_OK;
   1.761 +}
   1.762 +
   1.763 +NS_IMETHODIMP
   1.764 +nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
   1.765 +{
   1.766 +    NS_PRECONDITION(aNewParent, "");
   1.767 +    NS_ASSERTION(!mIsDestroyed, "");
   1.768 +    NS_ASSERTION(!static_cast<nsWindow*>(aNewParent)->mIsDestroyed, "");
   1.769 +
   1.770 +    GtkWidget* oldContainer = GetMozContainerWidget();
   1.771 +    if (!oldContainer) {
   1.772 +        // The GdkWindows have been destroyed so there is nothing else to
   1.773 +        // reparent.
   1.774 +        NS_ABORT_IF_FALSE(gdk_window_is_destroyed(mGdkWindow),
   1.775 +                          "live GdkWindow with no widget");
   1.776 +        return NS_OK;
   1.777 +    }
   1.778 +    NS_ABORT_IF_FALSE(!gdk_window_is_destroyed(mGdkWindow),
   1.779 +                      "destroyed GdkWindow with widget");
   1.780 +    
   1.781 +    nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
   1.782 +    GdkWindow* newParentWindow = newParent->mGdkWindow;
   1.783 +    GtkWidget* newContainer = newParent->GetMozContainerWidget();
   1.784 +    GtkWindow* shell = GTK_WINDOW(mShell);
   1.785 +
   1.786 +    if (shell && gtk_window_get_transient_for(shell)) {
   1.787 +      GtkWindow* topLevelParent =
   1.788 +          GTK_WINDOW(gtk_widget_get_toplevel(newContainer));
   1.789 +      gtk_window_set_transient_for(shell, topLevelParent);
   1.790 +    }
   1.791 +
   1.792 +    ReparentNativeWidgetInternal(aNewParent, newContainer, newParentWindow,
   1.793 +                                 oldContainer);
   1.794 +    return NS_OK;
   1.795 +}
   1.796 +
   1.797 +void
   1.798 +nsWindow::ReparentNativeWidgetInternal(nsIWidget* aNewParent,
   1.799 +                                       GtkWidget* aNewContainer,
   1.800 +                                       GdkWindow* aNewParentWindow,
   1.801 +                                       GtkWidget* aOldContainer)
   1.802 +{
   1.803 +    if (!aNewContainer) {
   1.804 +        // The new parent GdkWindow has been destroyed.
   1.805 +        NS_ABORT_IF_FALSE(!aNewParentWindow ||
   1.806 +                          gdk_window_is_destroyed(aNewParentWindow),
   1.807 +                          "live GdkWindow with no widget");
   1.808 +        Destroy();
   1.809 +    } else {
   1.810 +        if (aNewContainer != aOldContainer) {
   1.811 +            NS_ABORT_IF_FALSE(!gdk_window_is_destroyed(aNewParentWindow),
   1.812 +                              "destroyed GdkWindow with widget");
   1.813 +            SetWidgetForHierarchy(mGdkWindow, aOldContainer, aNewContainer);
   1.814 +
   1.815 +            if (aOldContainer == gInvisibleContainer) {
   1.816 +                CheckDestroyInvisibleContainer();
   1.817 +            }
   1.818 +        }
   1.819 +
   1.820 +        if (!mIsTopLevel) {
   1.821 +            gdk_window_reparent(mGdkWindow, aNewParentWindow, mBounds.x,
   1.822 +                                mBounds.y);
   1.823 +        }
   1.824 +    }
   1.825 +
   1.826 +    nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
   1.827 +    bool parentHasMappedToplevel =
   1.828 +        newParent && newParent->mHasMappedToplevel;
   1.829 +    if (mHasMappedToplevel != parentHasMappedToplevel) {
   1.830 +        SetHasMappedToplevel(parentHasMappedToplevel);
   1.831 +    }
   1.832 +}
   1.833 +
   1.834 +NS_IMETHODIMP
   1.835 +nsWindow::SetModal(bool aModal)
   1.836 +{
   1.837 +    LOG(("nsWindow::SetModal [%p] %d\n", (void *)this, aModal));
   1.838 +    if (mIsDestroyed)
   1.839 +        return aModal ? NS_ERROR_NOT_AVAILABLE : NS_OK;
   1.840 +    if (!mIsTopLevel || !mShell)
   1.841 +        return NS_ERROR_FAILURE;
   1.842 +    gtk_window_set_modal(GTK_WINDOW(mShell), aModal ? TRUE : FALSE);
   1.843 +    return NS_OK;
   1.844 +}
   1.845 +
   1.846 +// nsIWidget method, which means IsShown.
   1.847 +bool
   1.848 +nsWindow::IsVisible() const
   1.849 +{
   1.850 +    return mIsShown;
   1.851 +}
   1.852 +
   1.853 +NS_IMETHODIMP
   1.854 +nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
   1.855 +{
   1.856 +    if (mIsTopLevel && mShell) {
   1.857 +        int32_t screenWidth = gdk_screen_width();
   1.858 +        int32_t screenHeight = gdk_screen_height();
   1.859 +        if (aAllowSlop) {
   1.860 +            if (*aX < (kWindowPositionSlop - mBounds.width))
   1.861 +                *aX = kWindowPositionSlop - mBounds.width;
   1.862 +            if (*aX > (screenWidth - kWindowPositionSlop))
   1.863 +                *aX = screenWidth - kWindowPositionSlop;
   1.864 +            if (*aY < (kWindowPositionSlop - mBounds.height))
   1.865 +                *aY = kWindowPositionSlop - mBounds.height;
   1.866 +            if (*aY > (screenHeight - kWindowPositionSlop))
   1.867 +                *aY = screenHeight - kWindowPositionSlop;
   1.868 +        } else {
   1.869 +            if (*aX < 0)
   1.870 +                *aX = 0;
   1.871 +            if (*aX > (screenWidth - mBounds.width))
   1.872 +                *aX = screenWidth - mBounds.width;
   1.873 +            if (*aY < 0)
   1.874 +                *aY = 0;
   1.875 +            if (*aY > (screenHeight - mBounds.height))
   1.876 +                *aY = screenHeight - mBounds.height;
   1.877 +        }
   1.878 +    }
   1.879 +    return NS_OK;
   1.880 +}
   1.881 +
   1.882 +void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
   1.883 +{
   1.884 +    mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize);
   1.885 +    mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize);
   1.886 +
   1.887 +    if (mShell) {
   1.888 +        GdkGeometry geometry;
   1.889 +        geometry.min_width = mSizeConstraints.mMinSize.width;
   1.890 +        geometry.min_height = mSizeConstraints.mMinSize.height;
   1.891 +        geometry.max_width = mSizeConstraints.mMaxSize.width;
   1.892 +        geometry.max_height = mSizeConstraints.mMaxSize.height;
   1.893 +
   1.894 +        uint32_t hints = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
   1.895 +        gtk_window_set_geometry_hints(GTK_WINDOW(mShell), nullptr,
   1.896 +                                      &geometry, GdkWindowHints(hints));
   1.897 +    }
   1.898 +}
   1.899 +
   1.900 +NS_IMETHODIMP
   1.901 +nsWindow::Show(bool aState)
   1.902 +{
   1.903 +    if (aState == mIsShown)
   1.904 +        return NS_OK;
   1.905 +
   1.906 +    // Clear our cached resources when the window is hidden.
   1.907 +    if (mIsShown && !aState) {
   1.908 +        ClearCachedResources();
   1.909 +    }
   1.910 +
   1.911 +    mIsShown = aState;
   1.912 +
   1.913 +    LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState));
   1.914 +
   1.915 +    if (aState) {
   1.916 +        // Now that this window is shown, mHasMappedToplevel needs to be
   1.917 +        // tracked on viewable descendants.
   1.918 +        SetHasMappedToplevel(mHasMappedToplevel);
   1.919 +    }
   1.920 +
   1.921 +    // Ok, someone called show on a window that isn't sized to a sane
   1.922 +    // value.  Mark this window as needing to have Show() called on it
   1.923 +    // and return.
   1.924 +    if ((aState && !AreBoundsSane()) || !mCreated) {
   1.925 +        LOG(("\tbounds are insane or window hasn't been created yet\n"));
   1.926 +        mNeedsShow = true;
   1.927 +        return NS_OK;
   1.928 +    }
   1.929 +
   1.930 +    // If someone is hiding this widget, clear any needing show flag.
   1.931 +    if (!aState)
   1.932 +        mNeedsShow = false;
   1.933 +
   1.934 +    // If someone is showing this window and it needs a resize then
   1.935 +    // resize the widget.
   1.936 +    if (aState) {
   1.937 +        if (mNeedsMove) {
   1.938 +            NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
   1.939 +                         false);
   1.940 +        } else if (mNeedsResize) {
   1.941 +            NativeResize(mBounds.width, mBounds.height, false);
   1.942 +        }
   1.943 +    }
   1.944 +
   1.945 +#ifdef ACCESSIBILITY
   1.946 +    if (aState && a11y::ShouldA11yBeEnabled())
   1.947 +        CreateRootAccessible();
   1.948 +#endif
   1.949 +
   1.950 +    NativeShow(aState);
   1.951 +
   1.952 +    return NS_OK;
   1.953 +}
   1.954 +
   1.955 +NS_IMETHODIMP
   1.956 +nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
   1.957 +{
   1.958 +    CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale()
   1.959 +                                    : CSSToLayoutDeviceScale(1.0);
   1.960 +    int32_t width = NSToIntRound(scale.scale * aWidth);
   1.961 +    int32_t height = NSToIntRound(scale.scale * aHeight);
   1.962 +    ConstrainSize(&width, &height);
   1.963 +
   1.964 +    // For top-level windows, aWidth and aHeight should possibly be
   1.965 +    // interpreted as frame bounds, but NativeResize treats these as window
   1.966 +    // bounds (Bug 581866).
   1.967 +
   1.968 +    mBounds.SizeTo(width, height);
   1.969 +
   1.970 +    if (!mCreated)
   1.971 +        return NS_OK;
   1.972 +
   1.973 +    // There are several cases here that we need to handle, based on a
   1.974 +    // matrix of the visibility of the widget, the sanity of this resize
   1.975 +    // and whether or not the widget was previously sane.
   1.976 +
   1.977 +    // Has this widget been set to visible?
   1.978 +    if (mIsShown) {
   1.979 +        // Are the bounds sane?
   1.980 +        if (AreBoundsSane()) {
   1.981 +            // Yep?  Resize the window
   1.982 +            //Maybe, the toplevel has moved
   1.983 +
   1.984 +            // Note that if the widget needs to be positioned because its
   1.985 +            // size was previously insane in Resize(x,y,w,h), then we need
   1.986 +            // to set the x and y here too, because the widget wasn't
   1.987 +            // moved back then
   1.988 +            if (mNeedsMove)
   1.989 +                NativeResize(mBounds.x, mBounds.y,
   1.990 +                             mBounds.width, mBounds.height, aRepaint);
   1.991 +            else
   1.992 +                NativeResize(mBounds.width, mBounds.height, aRepaint);
   1.993 +
   1.994 +            // Does it need to be shown because it was previously insane?
   1.995 +            if (mNeedsShow)
   1.996 +                NativeShow(true);
   1.997 +        }
   1.998 +        else {
   1.999 +            // If someone has set this so that the needs show flag is false
  1.1000 +            // and it needs to be hidden, update the flag and hide the
  1.1001 +            // window.  This flag will be cleared the next time someone
  1.1002 +            // hides the window or shows it.  It also prevents us from
  1.1003 +            // calling NativeShow(false) excessively on the window which
  1.1004 +            // causes unneeded X traffic.
  1.1005 +            if (!mNeedsShow) {
  1.1006 +                mNeedsShow = true;
  1.1007 +                NativeShow(false);
  1.1008 +            }
  1.1009 +        }
  1.1010 +    }
  1.1011 +    // If the widget hasn't been shown, mark the widget as needing to be
  1.1012 +    // resized before it is shown.
  1.1013 +    else {
  1.1014 +        if (AreBoundsSane() && mListenForResizes) {
  1.1015 +            // For widgets that we listen for resizes for (widgets created
  1.1016 +            // with native parents) we apparently _always_ have to resize.  I
  1.1017 +            // dunno why, but apparently we're lame like that.
  1.1018 +            NativeResize(width, height, aRepaint);
  1.1019 +        }
  1.1020 +        else {
  1.1021 +            mNeedsResize = true;
  1.1022 +        }
  1.1023 +    }
  1.1024 +
  1.1025 +    NotifyRollupGeometryChange();
  1.1026 +
  1.1027 +    // send a resize notification if this is a toplevel
  1.1028 +    if (mIsTopLevel || mListenForResizes) {
  1.1029 +        DispatchResized(width, height);
  1.1030 +    }
  1.1031 +
  1.1032 +    return NS_OK;
  1.1033 +}
  1.1034 +
  1.1035 +NS_IMETHODIMP
  1.1036 +nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
  1.1037 +                 bool aRepaint)
  1.1038 +{
  1.1039 +    CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale()
  1.1040 +                                    : CSSToLayoutDeviceScale(1.0);
  1.1041 +    int32_t width = NSToIntRound(scale.scale * aWidth);
  1.1042 +    int32_t height = NSToIntRound(scale.scale * aHeight);
  1.1043 +    ConstrainSize(&width, &height);
  1.1044 +
  1.1045 +    int32_t x = NSToIntRound(scale.scale * aX);
  1.1046 +    int32_t y = NSToIntRound(scale.scale * aY);
  1.1047 +    mBounds.x = x;
  1.1048 +    mBounds.y = y;
  1.1049 +    mBounds.SizeTo(width, height);
  1.1050 +
  1.1051 +    mNeedsMove = true;
  1.1052 +
  1.1053 +    if (!mCreated)
  1.1054 +        return NS_OK;
  1.1055 +
  1.1056 +    // There are several cases here that we need to handle, based on a
  1.1057 +    // matrix of the visibility of the widget, the sanity of this resize
  1.1058 +    // and whether or not the widget was previously sane.
  1.1059 +
  1.1060 +    // Has this widget been set to visible?
  1.1061 +    if (mIsShown) {
  1.1062 +        // Are the bounds sane?
  1.1063 +        if (AreBoundsSane()) {
  1.1064 +            // Yep?  Resize the window
  1.1065 +            NativeResize(x, y, width, height, aRepaint);
  1.1066 +            // Does it need to be shown because it was previously insane?
  1.1067 +            if (mNeedsShow)
  1.1068 +                NativeShow(true);
  1.1069 +        }
  1.1070 +        else {
  1.1071 +            // If someone has set this so that the needs show flag is false
  1.1072 +            // and it needs to be hidden, update the flag and hide the
  1.1073 +            // window.  This flag will be cleared the next time someone
  1.1074 +            // hides the window or shows it.  It also prevents us from
  1.1075 +            // calling NativeShow(false) excessively on the window which
  1.1076 +            // causes unneeded X traffic.
  1.1077 +            if (!mNeedsShow) {
  1.1078 +                mNeedsShow = true;
  1.1079 +                NativeShow(false);
  1.1080 +            }
  1.1081 +        }
  1.1082 +    }
  1.1083 +    // If the widget hasn't been shown, mark the widget as needing to be
  1.1084 +    // resized before it is shown
  1.1085 +    else {
  1.1086 +        if (AreBoundsSane() && mListenForResizes){
  1.1087 +            // For widgets that we listen for resizes for (widgets created
  1.1088 +            // with native parents) we apparently _always_ have to resize.  I
  1.1089 +            // dunno why, but apparently we're lame like that.
  1.1090 +            NativeResize(x, y, width, height, aRepaint);
  1.1091 +        }
  1.1092 +        else {
  1.1093 +            mNeedsResize = true;
  1.1094 +        }
  1.1095 +    }
  1.1096 +
  1.1097 +    NotifyRollupGeometryChange();
  1.1098 +
  1.1099 +    if (mIsTopLevel || mListenForResizes) {
  1.1100 +        DispatchResized(width, height);
  1.1101 +    }
  1.1102 +
  1.1103 +    return NS_OK;
  1.1104 +}
  1.1105 +
  1.1106 +NS_IMETHODIMP
  1.1107 +nsWindow::Enable(bool aState)
  1.1108 +{
  1.1109 +    mEnabled = aState;
  1.1110 +
  1.1111 +    return NS_OK;
  1.1112 +}
  1.1113 +
  1.1114 +bool
  1.1115 +nsWindow::IsEnabled() const
  1.1116 +{
  1.1117 +    return mEnabled;
  1.1118 +}
  1.1119 +
  1.1120 +
  1.1121 +
  1.1122 +NS_IMETHODIMP
  1.1123 +nsWindow::Move(double aX, double aY)
  1.1124 +{
  1.1125 +    LOG(("nsWindow::Move [%p] %f %f\n", (void *)this,
  1.1126 +         aX, aY));
  1.1127 +
  1.1128 +    CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale()
  1.1129 +                                   : CSSToLayoutDeviceScale(1.0);
  1.1130 +    int32_t x = NSToIntRound(aX * scale.scale);
  1.1131 +    int32_t y = NSToIntRound(aY * scale.scale);
  1.1132 +
  1.1133 +    if (mWindowType == eWindowType_toplevel ||
  1.1134 +        mWindowType == eWindowType_dialog) {
  1.1135 +        SetSizeMode(nsSizeMode_Normal);
  1.1136 +    }
  1.1137 +
  1.1138 +    // Since a popup window's x/y coordinates are in relation to to
  1.1139 +    // the parent, the parent might have moved so we always move a
  1.1140 +    // popup window.
  1.1141 +    if (x == mBounds.x && y == mBounds.y &&
  1.1142 +        mWindowType != eWindowType_popup)
  1.1143 +        return NS_OK;
  1.1144 +
  1.1145 +    // XXX Should we do some AreBoundsSane check here?
  1.1146 +
  1.1147 +    mBounds.x = x;
  1.1148 +    mBounds.y = y;
  1.1149 +
  1.1150 +    if (!mCreated)
  1.1151 +        return NS_OK;
  1.1152 +
  1.1153 +    mNeedsMove = false;
  1.1154 +
  1.1155 +    if (mIsTopLevel) {
  1.1156 +        gtk_window_move(GTK_WINDOW(mShell), x, y);
  1.1157 +    }
  1.1158 +    else if (mGdkWindow) {
  1.1159 +        gdk_window_move(mGdkWindow, x, y);
  1.1160 +    }
  1.1161 +
  1.1162 +    NotifyRollupGeometryChange();
  1.1163 +    return NS_OK;
  1.1164 +}
  1.1165 +
  1.1166 +NS_IMETHODIMP
  1.1167 +nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement  aPlacement,
  1.1168 +                      nsIWidget                  *aWidget,
  1.1169 +                      bool                        aActivate)
  1.1170 +{
  1.1171 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1172 +}
  1.1173 +
  1.1174 +void
  1.1175 +nsWindow::SetZIndex(int32_t aZIndex)
  1.1176 +{
  1.1177 +    nsIWidget* oldPrev = GetPrevSibling();
  1.1178 +
  1.1179 +    nsBaseWidget::SetZIndex(aZIndex);
  1.1180 +
  1.1181 +    if (GetPrevSibling() == oldPrev) {
  1.1182 +        return;
  1.1183 +    }
  1.1184 +
  1.1185 +    NS_ASSERTION(!mContainer, "Expected Mozilla child widget");
  1.1186 +
  1.1187 +    // We skip the nsWindows that don't have mGdkWindows.
  1.1188 +    // These are probably in the process of being destroyed.
  1.1189 +
  1.1190 +    if (!GetNextSibling()) {
  1.1191 +        // We're to be on top.
  1.1192 +        if (mGdkWindow)
  1.1193 +            gdk_window_raise(mGdkWindow);
  1.1194 +    } else {
  1.1195 +        // All the siblings before us need to be below our widget.
  1.1196 +        for (nsWindow* w = this; w;
  1.1197 +             w = static_cast<nsWindow*>(w->GetPrevSibling())) {
  1.1198 +            if (w->mGdkWindow)
  1.1199 +                gdk_window_lower(w->mGdkWindow);
  1.1200 +        }
  1.1201 +    }
  1.1202 +}
  1.1203 +
  1.1204 +NS_IMETHODIMP
  1.1205 +nsWindow::SetSizeMode(int32_t aMode)
  1.1206 +{
  1.1207 +    nsresult rv;
  1.1208 +
  1.1209 +    LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode));
  1.1210 +
  1.1211 +    // Save the requested state.
  1.1212 +    rv = nsBaseWidget::SetSizeMode(aMode);
  1.1213 +
  1.1214 +    // return if there's no shell or our current state is the same as
  1.1215 +    // the mode we were just set to.
  1.1216 +    if (!mShell || mSizeState == mSizeMode) {
  1.1217 +        return rv;
  1.1218 +    }
  1.1219 +
  1.1220 +    switch (aMode) {
  1.1221 +    case nsSizeMode_Maximized:
  1.1222 +        gtk_window_maximize(GTK_WINDOW(mShell));
  1.1223 +        break;
  1.1224 +    case nsSizeMode_Minimized:
  1.1225 +        gtk_window_iconify(GTK_WINDOW(mShell));
  1.1226 +        break;
  1.1227 +    case nsSizeMode_Fullscreen:
  1.1228 +        MakeFullScreen(true);
  1.1229 +        break;
  1.1230 +
  1.1231 +    default:
  1.1232 +        // nsSizeMode_Normal, really.
  1.1233 +        if (mSizeState == nsSizeMode_Minimized)
  1.1234 +            gtk_window_deiconify(GTK_WINDOW(mShell));
  1.1235 +        else if (mSizeState == nsSizeMode_Maximized)
  1.1236 +            gtk_window_unmaximize(GTK_WINDOW(mShell));
  1.1237 +        break;
  1.1238 +    }
  1.1239 +
  1.1240 +    mSizeState = mSizeMode;
  1.1241 +
  1.1242 +    return rv;
  1.1243 +}
  1.1244 +
  1.1245 +typedef void (* SetUserTimeFunc)(GdkWindow* aWindow, guint32 aTimestamp);
  1.1246 +
  1.1247 +// This will become obsolete when new GTK APIs are widely supported,
  1.1248 +// as described here: http://bugzilla.gnome.org/show_bug.cgi?id=347375
  1.1249 +static void
  1.1250 +SetUserTimeAndStartupIDForActivatedWindow(GtkWidget* aWindow)
  1.1251 +{
  1.1252 +    nsGTKToolkit* GTKToolkit = nsGTKToolkit::GetToolkit();
  1.1253 +    if (!GTKToolkit)
  1.1254 +        return;
  1.1255 +
  1.1256 +    nsAutoCString desktopStartupID;
  1.1257 +    GTKToolkit->GetDesktopStartupID(&desktopStartupID);
  1.1258 +    if (desktopStartupID.IsEmpty()) {
  1.1259 +        // We don't have the data we need. Fall back to an
  1.1260 +        // approximation ... using the timestamp of the remote command
  1.1261 +        // being received as a guess for the timestamp of the user event
  1.1262 +        // that triggered it.
  1.1263 +        uint32_t timestamp = GTKToolkit->GetFocusTimestamp();
  1.1264 +        if (timestamp) {
  1.1265 +            gdk_window_focus(gtk_widget_get_window(aWindow), timestamp);
  1.1266 +            GTKToolkit->SetFocusTimestamp(0);
  1.1267 +        }
  1.1268 +        return;
  1.1269 +    }
  1.1270 +
  1.1271 +#if defined(MOZ_ENABLE_STARTUP_NOTIFICATION)
  1.1272 +    GdkWindow* gdkWindow = gtk_widget_get_window(aWindow);
  1.1273 +  
  1.1274 +    GdkScreen* screen = gdk_window_get_screen(gdkWindow);
  1.1275 +    SnDisplay* snd =
  1.1276 +        sn_display_new(gdk_x11_display_get_xdisplay(gdk_window_get_display(gdkWindow)), 
  1.1277 +                       nullptr, nullptr);
  1.1278 +    if (!snd)
  1.1279 +        return;
  1.1280 +    SnLauncheeContext* ctx =
  1.1281 +        sn_launchee_context_new(snd, gdk_screen_get_number(screen),
  1.1282 +                                desktopStartupID.get());
  1.1283 +    if (!ctx) {
  1.1284 +        sn_display_unref(snd);
  1.1285 +        return;
  1.1286 +    }
  1.1287 +
  1.1288 +    if (sn_launchee_context_get_id_has_timestamp(ctx)) {
  1.1289 +        PRLibrary* gtkLibrary;
  1.1290 +        SetUserTimeFunc setUserTimeFunc = (SetUserTimeFunc)
  1.1291 +            PR_FindFunctionSymbolAndLibrary("gdk_x11_window_set_user_time", &gtkLibrary);
  1.1292 +        if (setUserTimeFunc) {
  1.1293 +            setUserTimeFunc(gdkWindow, sn_launchee_context_get_timestamp(ctx));
  1.1294 +            PR_UnloadLibrary(gtkLibrary);
  1.1295 +        }
  1.1296 +    }
  1.1297 +
  1.1298 +    sn_launchee_context_setup_window(ctx, gdk_x11_window_get_xid(gdkWindow));
  1.1299 +    sn_launchee_context_complete(ctx);
  1.1300 +
  1.1301 +    sn_launchee_context_unref(ctx);
  1.1302 +    sn_display_unref(snd);
  1.1303 +#endif
  1.1304 +
  1.1305 +    // If we used the startup ID, that already contains the focus timestamp;
  1.1306 +    // we don't want to reuse the timestamp next time we raise the window
  1.1307 +    GTKToolkit->SetFocusTimestamp(0);
  1.1308 +    GTKToolkit->SetDesktopStartupID(EmptyCString());
  1.1309 +}
  1.1310 +
  1.1311 +/* static */ guint32
  1.1312 +nsWindow::GetLastUserInputTime()
  1.1313 +{
  1.1314 +    // gdk_x11_display_get_user_time tracks button and key presses,
  1.1315 +    // DESKTOP_STARTUP_ID used to start the app, drop events from external
  1.1316 +    // drags, WM_DELETE_WINDOW delete events, but not usually mouse motion nor
  1.1317 +    // button and key releases.  Therefore use the most recent of
  1.1318 +    // gdk_x11_display_get_user_time and the last time that we have seen.
  1.1319 +    guint32 timestamp =
  1.1320 +            gdk_x11_display_get_user_time(gdk_display_get_default());
  1.1321 +    if (sLastUserInputTime != GDK_CURRENT_TIME &&
  1.1322 +        TimestampIsNewerThan(sLastUserInputTime, timestamp)) {
  1.1323 +        return sLastUserInputTime;
  1.1324 +    }       
  1.1325 +
  1.1326 +    return timestamp;
  1.1327 +}
  1.1328 +
  1.1329 +NS_IMETHODIMP
  1.1330 +nsWindow::SetFocus(bool aRaise)
  1.1331 +{
  1.1332 +    // Make sure that our owning widget has focus.  If it doesn't try to
  1.1333 +    // grab it.  Note that we don't set our focus flag in this case.
  1.1334 +
  1.1335 +    LOGFOCUS(("  SetFocus %d [%p]\n", aRaise, (void *)this));
  1.1336 +
  1.1337 +    GtkWidget *owningWidget = GetMozContainerWidget();
  1.1338 +    if (!owningWidget)
  1.1339 +        return NS_ERROR_FAILURE;
  1.1340 +
  1.1341 +    // Raise the window if someone passed in true and the prefs are
  1.1342 +    // set properly.
  1.1343 +    GtkWidget *toplevelWidget = gtk_widget_get_toplevel(owningWidget);
  1.1344 +
  1.1345 +    if (gRaiseWindows && aRaise && toplevelWidget &&
  1.1346 +        !gtk_widget_has_focus(owningWidget) &&
  1.1347 +        !gtk_widget_has_focus(toplevelWidget)) {
  1.1348 +        GtkWidget* top_window = GetToplevelWidget();
  1.1349 +        if (top_window && (gtk_widget_get_visible(top_window)))
  1.1350 +        {
  1.1351 +            gdk_window_show_unraised(gtk_widget_get_window(top_window));
  1.1352 +            // Unset the urgency hint if possible.
  1.1353 +            SetUrgencyHint(top_window, false);
  1.1354 +        }
  1.1355 +    }
  1.1356 +
  1.1357 +    nsRefPtr<nsWindow> owningWindow = get_window_for_gtk_widget(owningWidget);
  1.1358 +    if (!owningWindow)
  1.1359 +        return NS_ERROR_FAILURE;
  1.1360 +
  1.1361 +    if (aRaise) {
  1.1362 +        // aRaise == true means request toplevel activation.
  1.1363 +
  1.1364 +        // This is asynchronous.
  1.1365 +        // If and when the window manager accepts the request, then the focus
  1.1366 +        // widget will get a focus-in-event signal.
  1.1367 +        if (gRaiseWindows && owningWindow->mIsShown && owningWindow->mShell &&
  1.1368 +            !gtk_window_is_active(GTK_WINDOW(owningWindow->mShell))) {
  1.1369 +
  1.1370 +            uint32_t timestamp = GDK_CURRENT_TIME;
  1.1371 +
  1.1372 +            nsGTKToolkit* GTKToolkit = nsGTKToolkit::GetToolkit();
  1.1373 +            if (GTKToolkit)
  1.1374 +                timestamp = GTKToolkit->GetFocusTimestamp();
  1.1375 +
  1.1376 +            LOGFOCUS(("  requesting toplevel activation [%p]\n", (void *)this));
  1.1377 +            NS_ASSERTION(owningWindow->mWindowType != eWindowType_popup
  1.1378 +                         || mParent,
  1.1379 +                         "Presenting an override-redirect window");
  1.1380 +            gtk_window_present_with_time(GTK_WINDOW(owningWindow->mShell), timestamp);
  1.1381 +
  1.1382 +            if (GTKToolkit)
  1.1383 +                GTKToolkit->SetFocusTimestamp(0);
  1.1384 +        }
  1.1385 +
  1.1386 +        return NS_OK;
  1.1387 +    }
  1.1388 +
  1.1389 +    // aRaise == false means that keyboard events should be dispatched
  1.1390 +    // from this widget.
  1.1391 +
  1.1392 +    // Ensure owningWidget is the focused GtkWidget within its toplevel window.
  1.1393 +    //
  1.1394 +    // For eWindowType_popup, this GtkWidget may not actually be the one that
  1.1395 +    // receives the key events as it may be the parent window that is active.
  1.1396 +    if (!gtk_widget_is_focus(owningWidget)) {
  1.1397 +        // This is synchronous.  It takes focus from a plugin or from a widget
  1.1398 +        // in an embedder.  The focus manager already knows that this window
  1.1399 +        // is active so gBlockActivateEvent avoids another (unnecessary)
  1.1400 +        // activate notification.
  1.1401 +        gBlockActivateEvent = true;
  1.1402 +        gtk_widget_grab_focus(owningWidget);
  1.1403 +        gBlockActivateEvent = false;
  1.1404 +    }
  1.1405 +
  1.1406 +    // If this is the widget that already has focus, return.
  1.1407 +    if (gFocusWindow == this) {
  1.1408 +        LOGFOCUS(("  already have focus [%p]\n", (void *)this));
  1.1409 +        return NS_OK;
  1.1410 +    }
  1.1411 +
  1.1412 +    // Set this window to be the focused child window
  1.1413 +    gFocusWindow = this;
  1.1414 +
  1.1415 +    if (mIMModule) {
  1.1416 +        mIMModule->OnFocusWindow(this);
  1.1417 +    }
  1.1418 +
  1.1419 +    LOGFOCUS(("  widget now has focus in SetFocus() [%p]\n",
  1.1420 +              (void *)this));
  1.1421 +
  1.1422 +    return NS_OK;
  1.1423 +}
  1.1424 +
  1.1425 +NS_IMETHODIMP
  1.1426 +nsWindow::GetScreenBounds(nsIntRect &aRect)
  1.1427 +{
  1.1428 +    if (mIsTopLevel && mContainer) {
  1.1429 +        // use the point including window decorations
  1.1430 +        gint x, y;
  1.1431 +        gdk_window_get_root_origin(gtk_widget_get_window(GTK_WIDGET(mContainer)), &x, &y);
  1.1432 +        aRect.MoveTo(x, y);
  1.1433 +    }
  1.1434 +    else {
  1.1435 +        aRect.MoveTo(WidgetToScreenOffset());
  1.1436 +    }
  1.1437 +    // mBounds.Size() is the window bounds, not the window-manager frame
  1.1438 +    // bounds (bug 581863).  gdk_window_get_frame_extents would give the
  1.1439 +    // frame bounds, but mBounds.Size() is returned here for consistency
  1.1440 +    // with Resize.
  1.1441 +    aRect.SizeTo(mBounds.Size());
  1.1442 +    LOG(("GetScreenBounds %d,%d | %dx%d\n",
  1.1443 +         aRect.x, aRect.y, aRect.width, aRect.height));
  1.1444 +    return NS_OK;
  1.1445 +}
  1.1446 +
  1.1447 +NS_IMETHODIMP
  1.1448 +nsWindow::GetClientBounds(nsIntRect &aRect)
  1.1449 +{
  1.1450 +    // GetBounds returns a rect whose top left represents the top left of the
  1.1451 +    // outer bounds, but whose width/height represent the size of the inner
  1.1452 +    // bounds (which is messed up).
  1.1453 +    GetBounds(aRect);
  1.1454 +    aRect.MoveBy(GetClientOffset());
  1.1455 +
  1.1456 +    return NS_OK;
  1.1457 +}
  1.1458 +
  1.1459 +nsIntPoint
  1.1460 +nsWindow::GetClientOffset()
  1.1461 +{
  1.1462 +    if (!mIsTopLevel) {
  1.1463 +        return nsIntPoint(0, 0);
  1.1464 +    }
  1.1465 +
  1.1466 +    GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
  1.1467 +
  1.1468 +    GdkAtom type_returned;
  1.1469 +    int format_returned;
  1.1470 +    int length_returned;
  1.1471 +    long *frame_extents;
  1.1472 +    GdkWindow* window;
  1.1473 +
  1.1474 +    if (!mShell || !(window = gtk_widget_get_window(mShell)) ||
  1.1475 +        !gdk_property_get(window,
  1.1476 +                          gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
  1.1477 +                          cardinal_atom,
  1.1478 +                          0, // offset
  1.1479 +                          4*4, // length
  1.1480 +                          FALSE, // delete
  1.1481 +                          &type_returned,
  1.1482 +                          &format_returned,
  1.1483 +                          &length_returned,
  1.1484 +                          (guchar **) &frame_extents) ||
  1.1485 +        length_returned/sizeof(glong) != 4) {
  1.1486 +
  1.1487 +        return nsIntPoint(0, 0);
  1.1488 +    }
  1.1489 +
  1.1490 +    // data returned is in the order left, right, top, bottom
  1.1491 +    int32_t left = int32_t(frame_extents[0]);
  1.1492 +    int32_t top = int32_t(frame_extents[2]);
  1.1493 +
  1.1494 +    g_free(frame_extents);
  1.1495 +
  1.1496 +    return nsIntPoint(left, top);
  1.1497 +}
  1.1498 +
  1.1499 +NS_IMETHODIMP
  1.1500 +nsWindow::SetCursor(nsCursor aCursor)
  1.1501 +{
  1.1502 +    // if we're not the toplevel window pass up the cursor request to
  1.1503 +    // the toplevel window to handle it.
  1.1504 +    if (!mContainer && mGdkWindow) {
  1.1505 +        nsWindow *window = GetContainerWindow();
  1.1506 +        if (!window)
  1.1507 +            return NS_ERROR_FAILURE;
  1.1508 +
  1.1509 +        return window->SetCursor(aCursor);
  1.1510 +    }
  1.1511 +
  1.1512 +    // Only change cursor if it's actually been changed
  1.1513 +    if (aCursor != mCursor) {
  1.1514 +        GdkCursor *newCursor = nullptr;
  1.1515 +
  1.1516 +        newCursor = get_gtk_cursor(aCursor);
  1.1517 +
  1.1518 +        if (nullptr != newCursor) {
  1.1519 +            mCursor = aCursor;
  1.1520 +
  1.1521 +            if (!mContainer)
  1.1522 +                return NS_OK;
  1.1523 +
  1.1524 +            gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer)), newCursor);
  1.1525 +        }
  1.1526 +    }
  1.1527 +
  1.1528 +    return NS_OK;
  1.1529 +}
  1.1530 +
  1.1531 +NS_IMETHODIMP
  1.1532 +nsWindow::SetCursor(imgIContainer* aCursor,
  1.1533 +                    uint32_t aHotspotX, uint32_t aHotspotY)
  1.1534 +{
  1.1535 +    // if we're not the toplevel window pass up the cursor request to
  1.1536 +    // the toplevel window to handle it.
  1.1537 +    if (!mContainer && mGdkWindow) {
  1.1538 +        nsWindow *window = GetContainerWindow();
  1.1539 +        if (!window)
  1.1540 +            return NS_ERROR_FAILURE;
  1.1541 +
  1.1542 +        return window->SetCursor(aCursor, aHotspotX, aHotspotY);
  1.1543 +    }
  1.1544 +
  1.1545 +    mCursor = nsCursor(-1);
  1.1546 +
  1.1547 +    // Get the image's current frame
  1.1548 +    GdkPixbuf* pixbuf = nsImageToPixbuf::ImageToPixbuf(aCursor);
  1.1549 +    if (!pixbuf)
  1.1550 +        return NS_ERROR_NOT_AVAILABLE;
  1.1551 +
  1.1552 +    int width = gdk_pixbuf_get_width(pixbuf);
  1.1553 +    int height = gdk_pixbuf_get_height(pixbuf);
  1.1554 +    // Reject cursors greater than 128 pixels in some direction, to prevent
  1.1555 +    // spoofing.
  1.1556 +    // XXX ideally we should rescale. Also, we could modify the API to
  1.1557 +    // allow trusted content to set larger cursors.
  1.1558 +    if (width > 128 || height > 128) {
  1.1559 +        g_object_unref(pixbuf);
  1.1560 +        return NS_ERROR_NOT_AVAILABLE;
  1.1561 +    }
  1.1562 +
  1.1563 +    // Looks like all cursors need an alpha channel (tested on Gtk 2.4.4). This
  1.1564 +    // is of course not documented anywhere...
  1.1565 +    // So add one if there isn't one yet
  1.1566 +    if (!gdk_pixbuf_get_has_alpha(pixbuf)) {
  1.1567 +        GdkPixbuf* alphaBuf = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
  1.1568 +        g_object_unref(pixbuf);
  1.1569 +        if (!alphaBuf) {
  1.1570 +            return NS_ERROR_OUT_OF_MEMORY;
  1.1571 +        }
  1.1572 +        pixbuf = alphaBuf;
  1.1573 +    }
  1.1574 +
  1.1575 +    GdkCursor* cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
  1.1576 +                                                   pixbuf,
  1.1577 +                                                   aHotspotX, aHotspotY);
  1.1578 +    g_object_unref(pixbuf);
  1.1579 +    nsresult rv = NS_ERROR_OUT_OF_MEMORY;
  1.1580 +    if (cursor) {
  1.1581 +        if (mContainer) {
  1.1582 +            gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer)), cursor);
  1.1583 +            rv = NS_OK;
  1.1584 +        }
  1.1585 +        gdk_cursor_unref(cursor);
  1.1586 +    }
  1.1587 +
  1.1588 +    return rv;
  1.1589 +}
  1.1590 +
  1.1591 +NS_IMETHODIMP
  1.1592 +nsWindow::Invalidate(const nsIntRect &aRect)
  1.1593 +{
  1.1594 +    if (!mGdkWindow)
  1.1595 +        return NS_OK;
  1.1596 +
  1.1597 +    GdkRectangle rect;
  1.1598 +    rect.x = aRect.x;
  1.1599 +    rect.y = aRect.y;
  1.1600 +    rect.width = aRect.width;
  1.1601 +    rect.height = aRect.height;
  1.1602 +
  1.1603 +    LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
  1.1604 +             rect.x, rect.y, rect.width, rect.height));
  1.1605 +
  1.1606 +    gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
  1.1607 +
  1.1608 +    return NS_OK;
  1.1609 +}
  1.1610 +
  1.1611 +void*
  1.1612 +nsWindow::GetNativeData(uint32_t aDataType)
  1.1613 +{
  1.1614 +    switch (aDataType) {
  1.1615 +    case NS_NATIVE_WINDOW:
  1.1616 +    case NS_NATIVE_WIDGET: {
  1.1617 +        if (!mGdkWindow)
  1.1618 +            return nullptr;
  1.1619 +
  1.1620 +        return mGdkWindow;
  1.1621 +        break;
  1.1622 +    }
  1.1623 +
  1.1624 +    case NS_NATIVE_PLUGIN_PORT:
  1.1625 +        return SetupPluginPort();
  1.1626 +        break;
  1.1627 +
  1.1628 +    case NS_NATIVE_DISPLAY:
  1.1629 +#ifdef MOZ_X11
  1.1630 +        return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
  1.1631 +#else
  1.1632 +        return nullptr;
  1.1633 +#endif /* MOZ_X11 */
  1.1634 +        break;
  1.1635 +
  1.1636 +    case NS_NATIVE_SHELLWIDGET:
  1.1637 +        return GetToplevelWidget();
  1.1638 +
  1.1639 +    case NS_NATIVE_SHAREABLE_WINDOW:
  1.1640 +        return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow));
  1.1641 +
  1.1642 +    default:
  1.1643 +        NS_WARNING("nsWindow::GetNativeData called with bad value");
  1.1644 +        return nullptr;
  1.1645 +    }
  1.1646 +}
  1.1647 +
  1.1648 +NS_IMETHODIMP
  1.1649 +nsWindow::SetTitle(const nsAString& aTitle)
  1.1650 +{
  1.1651 +    if (!mShell)
  1.1652 +        return NS_OK;
  1.1653 +
  1.1654 +    // convert the string into utf8 and set the title.
  1.1655 +#define UTF8_FOLLOWBYTE(ch) (((ch) & 0xC0) == 0x80)
  1.1656 +    NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
  1.1657 +    if (titleUTF8.Length() > NS_WINDOW_TITLE_MAX_LENGTH) {
  1.1658 +        // Truncate overlong titles (bug 167315). Make sure we chop after a
  1.1659 +        // complete sequence by making sure the next char isn't a follow-byte.
  1.1660 +        uint32_t len = NS_WINDOW_TITLE_MAX_LENGTH;
  1.1661 +        while(UTF8_FOLLOWBYTE(titleUTF8[len]))
  1.1662 +            --len;
  1.1663 +        titleUTF8.Truncate(len);
  1.1664 +    }
  1.1665 +    gtk_window_set_title(GTK_WINDOW(mShell), (const char *)titleUTF8.get());
  1.1666 +
  1.1667 +    return NS_OK;
  1.1668 +}
  1.1669 +
  1.1670 +NS_IMETHODIMP
  1.1671 +nsWindow::SetIcon(const nsAString& aIconSpec)
  1.1672 +{
  1.1673 +    if (!mShell)
  1.1674 +        return NS_OK;
  1.1675 +
  1.1676 +    nsAutoCString iconName;
  1.1677 +    
  1.1678 +    if (aIconSpec.EqualsLiteral("default")) {
  1.1679 +        nsXPIDLString brandName;
  1.1680 +        GetBrandName(brandName);
  1.1681 +        AppendUTF16toUTF8(brandName, iconName);
  1.1682 +        ToLowerCase(iconName);
  1.1683 +    } else {
  1.1684 +        AppendUTF16toUTF8(aIconSpec, iconName);
  1.1685 +    }
  1.1686 +    
  1.1687 +    nsCOMPtr<nsIFile> iconFile;
  1.1688 +    nsAutoCString path;
  1.1689 +
  1.1690 +    gint *iconSizes =
  1.1691 +        gtk_icon_theme_get_icon_sizes(gtk_icon_theme_get_default(),
  1.1692 +                                      iconName.get());
  1.1693 +    bool foundIcon = (iconSizes[0] != 0);
  1.1694 +    g_free(iconSizes);
  1.1695 +
  1.1696 +    if (!foundIcon) {
  1.1697 +        // Look for icons with the following suffixes appended to the base name
  1.1698 +        // The last two entries (for the old XPM format) will be ignored unless
  1.1699 +        // no icons are found using other suffixes. XPM icons are deprecated.
  1.1700 +
  1.1701 +        const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png",
  1.1702 +                                    ".xpm", "16.xpm" };
  1.1703 +
  1.1704 +        for (uint32_t i = 0; i < ArrayLength(extensions); i++) {
  1.1705 +            // Don't bother looking for XPM versions if we found a PNG.
  1.1706 +            if (i == ArrayLength(extensions) - 2 && foundIcon)
  1.1707 +                break;
  1.1708 +
  1.1709 +            nsAutoString extension;
  1.1710 +            extension.AppendASCII(extensions[i]);
  1.1711 +
  1.1712 +            ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile));
  1.1713 +            if (iconFile) {
  1.1714 +                iconFile->GetNativePath(path);
  1.1715 +                GdkPixbuf *icon = gdk_pixbuf_new_from_file(path.get(), nullptr);
  1.1716 +                if (icon) {
  1.1717 +                    gtk_icon_theme_add_builtin_icon(iconName.get(),
  1.1718 +                                                    gdk_pixbuf_get_height(icon),
  1.1719 +                                                    icon);
  1.1720 +                    g_object_unref(icon);
  1.1721 +                    foundIcon = true;
  1.1722 +                }
  1.1723 +            }
  1.1724 +        }
  1.1725 +    }
  1.1726 +
  1.1727 +    // leave the default icon intact if no matching icons were found
  1.1728 +    if (foundIcon) {
  1.1729 +        gtk_window_set_icon_name(GTK_WINDOW(mShell), iconName.get());
  1.1730 +    }
  1.1731 +
  1.1732 +    return NS_OK;
  1.1733 +}
  1.1734 +
  1.1735 +
  1.1736 +nsIntPoint
  1.1737 +nsWindow::WidgetToScreenOffset()
  1.1738 +{
  1.1739 +    gint x = 0, y = 0;
  1.1740 +
  1.1741 +    if (mGdkWindow) {
  1.1742 +        gdk_window_get_origin(mGdkWindow, &x, &y);
  1.1743 +    }
  1.1744 +
  1.1745 +    return nsIntPoint(x, y);
  1.1746 +}
  1.1747 +
  1.1748 +NS_IMETHODIMP
  1.1749 +nsWindow::EnableDragDrop(bool aEnable)
  1.1750 +{
  1.1751 +    return NS_OK;
  1.1752 +}
  1.1753 +
  1.1754 +NS_IMETHODIMP
  1.1755 +nsWindow::CaptureMouse(bool aCapture)
  1.1756 +{
  1.1757 +    LOG(("CaptureMouse %p\n", (void *)this));
  1.1758 +
  1.1759 +    if (!mGdkWindow)
  1.1760 +        return NS_OK;
  1.1761 +
  1.1762 +    if (!mShell)
  1.1763 +        return NS_ERROR_FAILURE;
  1.1764 +
  1.1765 +    if (aCapture) {
  1.1766 +        gtk_grab_add(mShell);
  1.1767 +        GrabPointer(GetLastUserInputTime());
  1.1768 +    }
  1.1769 +    else {
  1.1770 +        ReleaseGrabs();
  1.1771 +        gtk_grab_remove(mShell);
  1.1772 +    }
  1.1773 +
  1.1774 +    return NS_OK;
  1.1775 +}
  1.1776 +
  1.1777 +NS_IMETHODIMP
  1.1778 +nsWindow::CaptureRollupEvents(nsIRollupListener *aListener,
  1.1779 +                              bool               aDoCapture)
  1.1780 +{
  1.1781 +    if (!mGdkWindow)
  1.1782 +        return NS_OK;
  1.1783 +
  1.1784 +    if (!mShell)
  1.1785 +        return NS_ERROR_FAILURE;
  1.1786 +
  1.1787 +    LOG(("CaptureRollupEvents %p %i\n", this, int(aDoCapture)));
  1.1788 +
  1.1789 +    if (aDoCapture) {
  1.1790 +        gRollupListener = aListener;
  1.1791 +        // real grab is only done when there is no dragging
  1.1792 +        if (!nsWindow::DragInProgress()) {
  1.1793 +            // This widget grab ensures that a Gecko GtkWidget receives mouse
  1.1794 +            // events even when embedded in non-Gecko-owned GtkWidgets.
  1.1795 +            // The grab is placed on the toplevel GtkWindow instead of the
  1.1796 +            // MozContainer to avoid double dispatch of keyboard events
  1.1797 +            // (bug 707623).
  1.1798 +            gtk_grab_add(mShell);
  1.1799 +            GrabPointer(GetLastUserInputTime());
  1.1800 +        }
  1.1801 +    }
  1.1802 +    else {
  1.1803 +        if (!nsWindow::DragInProgress()) {
  1.1804 +            ReleaseGrabs();
  1.1805 +        }
  1.1806 +        // There may not have been a drag in process when aDoCapture was set,
  1.1807 +        // so make sure to remove any added grab.  This is a no-op if the grab
  1.1808 +        // was not added to this widget.
  1.1809 +        gtk_grab_remove(mShell);
  1.1810 +        gRollupListener = nullptr;
  1.1811 +    }
  1.1812 +
  1.1813 +    return NS_OK;
  1.1814 +}
  1.1815 +
  1.1816 +NS_IMETHODIMP
  1.1817 +nsWindow::GetAttention(int32_t aCycleCount)
  1.1818 +{
  1.1819 +    LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
  1.1820 +
  1.1821 +    GtkWidget* top_window = GetToplevelWidget();
  1.1822 +    GtkWidget* top_focused_window =
  1.1823 +        gFocusWindow ? gFocusWindow->GetToplevelWidget() : nullptr;
  1.1824 +
  1.1825 +    // Don't get attention if the window is focused anyway.
  1.1826 +    if (top_window && (gtk_widget_get_visible(top_window)) &&
  1.1827 +        top_window != top_focused_window) {
  1.1828 +        SetUrgencyHint(top_window, true);
  1.1829 +    }
  1.1830 +
  1.1831 +    return NS_OK;
  1.1832 +}
  1.1833 +
  1.1834 +bool
  1.1835 +nsWindow::HasPendingInputEvent()
  1.1836 +{
  1.1837 +    // This sucks, but gtk/gdk has no way to answer the question we want while
  1.1838 +    // excluding paint events, and there's no X API that will let us peek
  1.1839 +    // without blocking or removing.  To prevent event reordering, peek
  1.1840 +    // anything except expose events.  Reordering expose and others should be
  1.1841 +    // ok, hopefully.
  1.1842 +    bool haveEvent;
  1.1843 +#ifdef MOZ_X11
  1.1844 +    XEvent ev;
  1.1845 +    Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
  1.1846 +    haveEvent =
  1.1847 +        XCheckMaskEvent(display,
  1.1848 +                        KeyPressMask | KeyReleaseMask | ButtonPressMask |
  1.1849 +                        ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
  1.1850 +                        PointerMotionMask | PointerMotionHintMask |
  1.1851 +                        Button1MotionMask | Button2MotionMask |
  1.1852 +                        Button3MotionMask | Button4MotionMask |
  1.1853 +                        Button5MotionMask | ButtonMotionMask | KeymapStateMask |
  1.1854 +                        VisibilityChangeMask | StructureNotifyMask |
  1.1855 +                        ResizeRedirectMask | SubstructureNotifyMask |
  1.1856 +                        SubstructureRedirectMask | FocusChangeMask |
  1.1857 +                        PropertyChangeMask | ColormapChangeMask |
  1.1858 +                        OwnerGrabButtonMask, &ev);
  1.1859 +    if (haveEvent) {
  1.1860 +        XPutBackEvent(display, &ev);
  1.1861 +    }
  1.1862 +#else
  1.1863 +    haveEvent = false;
  1.1864 +#endif
  1.1865 +    return haveEvent;
  1.1866 +}
  1.1867 +
  1.1868 +#if 0
  1.1869 +#ifdef DEBUG
  1.1870 +// Paint flashing code (disabled for cairo - see below)
  1.1871 +
  1.1872 +#define CAPS_LOCK_IS_ON \
  1.1873 +(KeymapWrapper::AreModifiersCurrentlyActive(KeymapWrapper::CAPS_LOCK))
  1.1874 +
  1.1875 +#define WANT_PAINT_FLASHING \
  1.1876 +(debug_WantPaintFlashing() && CAPS_LOCK_IS_ON)
  1.1877 +
  1.1878 +#ifdef MOZ_X11
  1.1879 +static void
  1.1880 +gdk_window_flash(GdkWindow *    aGdkWindow,
  1.1881 +                 unsigned int   aTimes,
  1.1882 +                 unsigned int   aInterval,  // Milliseconds
  1.1883 +                 GdkRegion *    aRegion)
  1.1884 +{
  1.1885 +  gint         x;
  1.1886 +  gint         y;
  1.1887 +  gint         width;
  1.1888 +  gint         height;
  1.1889 +  guint        i;
  1.1890 +  GdkGC *      gc = 0;
  1.1891 +  GdkColor     white;
  1.1892 +
  1.1893 +#if (MOZ_WIDGET_GTK == 2)
  1.1894 +  gdk_window_get_geometry(aGdkWindow,nullptr,nullptr,&width,&height,nullptr);
  1.1895 +#else
  1.1896 +  gdk_window_get_geometry(aGdkWindow,nullptr,nullptr,&width,&height);
  1.1897 +#endif
  1.1898 +
  1.1899 +  gdk_window_get_origin (aGdkWindow,
  1.1900 +                         &x,
  1.1901 +                         &y);
  1.1902 +
  1.1903 +  gc = gdk_gc_new(gdk_get_default_root_window());
  1.1904 +
  1.1905 +  white.pixel = WhitePixel(gdk_display,DefaultScreen(gdk_display));
  1.1906 +
  1.1907 +  gdk_gc_set_foreground(gc,&white);
  1.1908 +  gdk_gc_set_function(gc,GDK_XOR);
  1.1909 +  gdk_gc_set_subwindow(gc,GDK_INCLUDE_INFERIORS);
  1.1910 +
  1.1911 +  gdk_region_offset(aRegion, x, y);
  1.1912 +  gdk_gc_set_clip_region(gc, aRegion);
  1.1913 +
  1.1914 +  /*
  1.1915 +   * Need to do this twice so that the XOR effect can replace
  1.1916 +   * the original window contents.
  1.1917 +   */
  1.1918 +  for (i = 0; i < aTimes * 2; i++)
  1.1919 +  {
  1.1920 +    gdk_draw_rectangle(gdk_get_default_root_window(),
  1.1921 +                       gc,
  1.1922 +                       TRUE,
  1.1923 +                       x,
  1.1924 +                       y,
  1.1925 +                       width,
  1.1926 +                       height);
  1.1927 +
  1.1928 +    gdk_flush();
  1.1929 +
  1.1930 +    PR_Sleep(PR_MillisecondsToInterval(aInterval));
  1.1931 +  }
  1.1932 +
  1.1933 +  gdk_gc_destroy(gc);
  1.1934 +
  1.1935 +  gdk_region_offset(aRegion, -x, -y);
  1.1936 +}
  1.1937 +#endif /* MOZ_X11 */
  1.1938 +#endif // DEBUG
  1.1939 +#endif
  1.1940 +
  1.1941 +struct ExposeRegion
  1.1942 +{
  1.1943 +    nsIntRegion mRegion;
  1.1944 +
  1.1945 +#if (MOZ_WIDGET_GTK == 2)
  1.1946 +    GdkRectangle *mRects;
  1.1947 +    GdkRectangle *mRectsEnd;
  1.1948 +
  1.1949 +    ExposeRegion() : mRects(nullptr)
  1.1950 +    {
  1.1951 +    }
  1.1952 +    ~ExposeRegion()
  1.1953 +    {
  1.1954 +        g_free(mRects);
  1.1955 +    }
  1.1956 +    bool Init(GdkEventExpose *aEvent)
  1.1957 +    {
  1.1958 +        gint nrects;
  1.1959 +        gdk_region_get_rectangles(aEvent->region, &mRects, &nrects);
  1.1960 +
  1.1961 +        if (nrects > MAX_RECTS_IN_REGION) {
  1.1962 +            // Just use the bounding box
  1.1963 +            mRects[0] = aEvent->area;
  1.1964 +            nrects = 1;
  1.1965 +        }
  1.1966 +
  1.1967 +        mRectsEnd = mRects + nrects;
  1.1968 +
  1.1969 +        for (GdkRectangle *r = mRects; r < mRectsEnd; r++) {
  1.1970 +            mRegion.Or(mRegion, nsIntRect(r->x, r->y, r->width, r->height));
  1.1971 +            LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
  1.1972 +        }
  1.1973 +        return true;
  1.1974 +    }
  1.1975 +
  1.1976 +#else
  1.1977 +# ifdef cairo_copy_clip_rectangle_list
  1.1978 +#  error "Looks like we're including Mozilla's cairo instead of system cairo"
  1.1979 +# endif
  1.1980 +    cairo_rectangle_list_t *mRects;
  1.1981 +
  1.1982 +    ExposeRegion() : mRects(nullptr)
  1.1983 +    {
  1.1984 +    }
  1.1985 +    ~ExposeRegion()
  1.1986 +    {
  1.1987 +        cairo_rectangle_list_destroy(mRects);
  1.1988 +    }
  1.1989 +    bool Init(cairo_t* cr)
  1.1990 +    {
  1.1991 +        mRects = cairo_copy_clip_rectangle_list(cr);
  1.1992 +        if (mRects->status != CAIRO_STATUS_SUCCESS) {
  1.1993 +            NS_WARNING("Failed to obtain cairo rectangle list.");
  1.1994 +            return false;
  1.1995 +        }
  1.1996 +
  1.1997 +        for (int i = 0; i < mRects->num_rectangles; i++)  {
  1.1998 +            const cairo_rectangle_t& r = mRects->rectangles[i];
  1.1999 +            mRegion.Or(mRegion, nsIntRect(r.x, r.y, r.width, r.height));
  1.2000 +            LOGDRAW(("\t%d %d %d %d\n", r.x, r.y, r.width, r.height));
  1.2001 +        }
  1.2002 +        return true;
  1.2003 +    }
  1.2004 +#endif
  1.2005 +};
  1.2006 +
  1.2007 +#if (MOZ_WIDGET_GTK == 2)
  1.2008 +gboolean
  1.2009 +nsWindow::OnExposeEvent(GdkEventExpose *aEvent)
  1.2010 +#else
  1.2011 +gboolean
  1.2012 +nsWindow::OnExposeEvent(cairo_t *cr)
  1.2013 +#endif
  1.2014 +{
  1.2015 +    if (mIsDestroyed) {
  1.2016 +        return FALSE;
  1.2017 +    }
  1.2018 +
  1.2019 +    // Windows that are not visible will be painted after they become visible.
  1.2020 +    if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
  1.2021 +        return FALSE;
  1.2022 +
  1.2023 +    nsIWidgetListener *listener =
  1.2024 +        mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
  1.2025 +    if (!listener)
  1.2026 +        return FALSE;
  1.2027 +
  1.2028 +    ExposeRegion exposeRegion;
  1.2029 +#if (MOZ_WIDGET_GTK == 2)
  1.2030 +    if (!exposeRegion.Init(aEvent)) {
  1.2031 +#else
  1.2032 +    if (!exposeRegion.Init(cr)) {
  1.2033 +#endif
  1.2034 +        return FALSE;
  1.2035 +    }
  1.2036 +
  1.2037 +    nsIntRegion &region = exposeRegion.mRegion;
  1.2038 +
  1.2039 +    ClientLayerManager *clientLayers =
  1.2040 +        (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT)
  1.2041 +        ? static_cast<ClientLayerManager*>(GetLayerManager())
  1.2042 +        : nullptr;
  1.2043 +
  1.2044 +    if (clientLayers && mCompositorParent) {
  1.2045 +        // We need to paint to the screen even if nothing changed, since if we
  1.2046 +        // don't have a compositing window manager, our pixels could be stale.
  1.2047 +        clientLayers->SetNeedsComposite(true);
  1.2048 +        clientLayers->SendInvalidRegion(region);
  1.2049 +    }
  1.2050 +
  1.2051 +    // Dispatch WillPaintWindow notification to allow scripts etc. to run
  1.2052 +    // before we paint
  1.2053 +    {
  1.2054 +        listener->WillPaintWindow(this);
  1.2055 +
  1.2056 +        // If the window has been destroyed during the will paint notification,
  1.2057 +        // there is nothing left to do.
  1.2058 +        if (!mGdkWindow)
  1.2059 +            return TRUE;
  1.2060 +
  1.2061 +        // Re-get the listener since the will paint notification might have
  1.2062 +        // killed it.
  1.2063 +        listener =
  1.2064 +            mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
  1.2065 +        if (!listener)
  1.2066 +            return FALSE;
  1.2067 +    }
  1.2068 +
  1.2069 +    if (clientLayers && mCompositorParent && clientLayers->NeedsComposite()) {
  1.2070 +        mCompositorParent->ScheduleRenderOnCompositorThread();
  1.2071 +        clientLayers->SetNeedsComposite(false);
  1.2072 +    }
  1.2073 +
  1.2074 +    LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
  1.2075 +             (void *)this, (void *)mGdkWindow,
  1.2076 +             gdk_x11_window_get_xid(mGdkWindow)));
  1.2077 +
  1.2078 +    // Our bounds may have changed after calling WillPaintWindow.  Clip
  1.2079 +    // to the new bounds here.  The region is relative to this
  1.2080 +    // window.
  1.2081 +    region.And(region, nsIntRect(0, 0, mBounds.width, mBounds.height));
  1.2082 +
  1.2083 +    bool shaped = false;
  1.2084 +    if (eTransparencyTransparent == GetTransparencyMode()) {
  1.2085 +        GdkScreen *screen = gdk_window_get_screen(mGdkWindow);
  1.2086 +        if (gdk_screen_is_composited(screen) &&
  1.2087 +            gdk_window_get_visual(mGdkWindow) ==
  1.2088 +            gdk_screen_get_rgba_visual(screen)) {
  1.2089 +            // Remove possible shape mask from when window manger was not
  1.2090 +            // previously compositing.
  1.2091 +            static_cast<nsWindow*>(GetTopLevelWidget())->
  1.2092 +                ClearTransparencyBitmap();
  1.2093 +        } else {
  1.2094 +            shaped = true;
  1.2095 +        }
  1.2096 +    }
  1.2097 +
  1.2098 +    if (!shaped) {
  1.2099 +        GList *children =
  1.2100 +            gdk_window_peek_children(mGdkWindow);
  1.2101 +        while (children) {
  1.2102 +            GdkWindow *gdkWin = GDK_WINDOW(children->data);
  1.2103 +            nsWindow *kid = get_window_for_gdk_window(gdkWin);
  1.2104 +            if (kid && gdk_window_is_visible(gdkWin)) {
  1.2105 +                nsAutoTArray<nsIntRect,1> clipRects;
  1.2106 +                kid->GetWindowClipRegion(&clipRects);
  1.2107 +                nsIntRect bounds;
  1.2108 +                kid->GetBounds(bounds);
  1.2109 +                for (uint32_t i = 0; i < clipRects.Length(); ++i) {
  1.2110 +                    nsIntRect r = clipRects[i] + bounds.TopLeft();
  1.2111 +                    region.Sub(region, r);
  1.2112 +                }
  1.2113 +            }
  1.2114 +            children = children->next;
  1.2115 +        }
  1.2116 +    }
  1.2117 +
  1.2118 +    if (region.IsEmpty()) {
  1.2119 +        return TRUE;
  1.2120 +    }
  1.2121 +
  1.2122 +    // If this widget uses OMTC...
  1.2123 +    if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
  1.2124 +        listener->PaintWindow(this, region);
  1.2125 +        listener->DidPaintWindow();
  1.2126 +        return TRUE;
  1.2127 +    }
  1.2128 +
  1.2129 +    gfxASurface* surf;
  1.2130 +#if (MOZ_WIDGET_GTK == 2)
  1.2131 +    surf = GetThebesSurface();
  1.2132 +#else
  1.2133 +    surf = GetThebesSurface(cr);
  1.2134 +#endif
  1.2135 +
  1.2136 +    nsRefPtr<gfxContext> ctx;
  1.2137 +    if (gfxPlatform::GetPlatform()->
  1.2138 +            SupportsAzureContentForType(BackendType::CAIRO)) {
  1.2139 +        IntSize intSize(surf->GetSize().width, surf->GetSize().height);
  1.2140 +        ctx = new gfxContext(gfxPlatform::GetPlatform()->
  1.2141 +            CreateDrawTargetForSurface(surf, intSize));
  1.2142 +    } else if (gfxPlatform::GetPlatform()->
  1.2143 +                   SupportsAzureContentForType(BackendType::SKIA) &&
  1.2144 +               surf->GetType() == gfxSurfaceType::Image) {
  1.2145 +       gfxImageSurface* imgSurf = static_cast<gfxImageSurface*>(surf);
  1.2146 +       SurfaceFormat format = ImageFormatToSurfaceFormat(imgSurf->Format());
  1.2147 +       IntSize intSize(surf->GetSize().width, surf->GetSize().height);
  1.2148 +       ctx = new gfxContext(gfxPlatform::GetPlatform()->CreateDrawTargetForData(
  1.2149 +           imgSurf->Data(), intSize, imgSurf->Stride(), format));
  1.2150 +    }  else {
  1.2151 +        ctx = new gfxContext(surf);
  1.2152 +    }
  1.2153 +
  1.2154 +#ifdef MOZ_X11
  1.2155 +    nsIntRect boundsRect; // for shaped only
  1.2156 +
  1.2157 +    ctx->NewPath();
  1.2158 +    if (shaped) {
  1.2159 +        // Collapse update area to the bounding box. This is so we only have to
  1.2160 +        // call UpdateTranslucentWindowAlpha once. After we have dropped
  1.2161 +        // support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
  1.2162 +        // our private interface so we can rework things to avoid this.
  1.2163 +        boundsRect = region.GetBounds();
  1.2164 +        ctx->Rectangle(gfxRect(boundsRect.x, boundsRect.y,
  1.2165 +                               boundsRect.width, boundsRect.height));
  1.2166 +    } else {
  1.2167 +        gfxUtils::PathFromRegion(ctx, region);
  1.2168 +    }
  1.2169 +    ctx->Clip();
  1.2170 +
  1.2171 +    BufferMode layerBuffering;
  1.2172 +    if (shaped) {
  1.2173 +        // The double buffering is done here to extract the shape mask.
  1.2174 +        // (The shape mask won't be necessary when a visual with an alpha
  1.2175 +        // channel is used on compositing window managers.)
  1.2176 +        layerBuffering = mozilla::layers::BufferMode::BUFFER_NONE;
  1.2177 +        ctx->PushGroup(gfxContentType::COLOR_ALPHA);
  1.2178 +#ifdef MOZ_HAVE_SHMIMAGE
  1.2179 +    } else if (nsShmImage::UseShm()) {
  1.2180 +        // We're using an xshm mapping as a back buffer.
  1.2181 +        layerBuffering = mozilla::layers::BufferMode::BUFFER_NONE;
  1.2182 +#endif // MOZ_HAVE_SHMIMAGE
  1.2183 +    } else {
  1.2184 +        // Get the layer manager to do double buffering (if necessary).
  1.2185 +        layerBuffering = mozilla::layers::BufferMode::BUFFERED;
  1.2186 +    }
  1.2187 +
  1.2188 +#if 0
  1.2189 +    // NOTE: Paint flashing region would be wrong for cairo, since
  1.2190 +    // cairo inflates the update region, etc.  So don't paint flash
  1.2191 +    // for cairo.
  1.2192 +#ifdef DEBUG
  1.2193 +    // XXX aEvent->region may refer to a newly-invalid area.  FIXME
  1.2194 +    if (0 && WANT_PAINT_FLASHING && gtk_widget_get_window(aEvent))
  1.2195 +        gdk_window_flash(mGdkWindow, 1, 100, aEvent->region);
  1.2196 +#endif
  1.2197 +#endif
  1.2198 +
  1.2199 +#endif // MOZ_X11
  1.2200 +
  1.2201 +    bool painted = false;
  1.2202 +    {
  1.2203 +      if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
  1.2204 +        AutoLayerManagerSetup setupLayerManager(this, ctx, layerBuffering);
  1.2205 +        painted = listener->PaintWindow(this, region);
  1.2206 +      }
  1.2207 +    }
  1.2208 +
  1.2209 +#ifdef MOZ_X11
  1.2210 +    // PaintWindow can Destroy us (bug 378273), avoid doing any paint
  1.2211 +    // operations below if that happened - it will lead to XError and exit().
  1.2212 +    if (shaped) {
  1.2213 +        if (MOZ_LIKELY(!mIsDestroyed)) {
  1.2214 +            if (painted) {
  1.2215 +                nsRefPtr<gfxPattern> pattern = ctx->PopGroup();
  1.2216 +
  1.2217 +                UpdateAlpha(pattern, boundsRect);
  1.2218 +
  1.2219 +                ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  1.2220 +                ctx->SetPattern(pattern);
  1.2221 +                ctx->Paint();
  1.2222 +            }
  1.2223 +        }
  1.2224 +    }
  1.2225 +#  ifdef MOZ_HAVE_SHMIMAGE
  1.2226 +    if (mShmImage && MOZ_LIKELY(!mIsDestroyed)) {
  1.2227 +#if (MOZ_WIDGET_GTK == 2)
  1.2228 +        mShmImage->Put(mGdkWindow, exposeRegion.mRects, exposeRegion.mRectsEnd);
  1.2229 +#else
  1.2230 +        mShmImage->Put(mGdkWindow, exposeRegion.mRects);
  1.2231 +#endif
  1.2232 +    }
  1.2233 +#  endif  // MOZ_HAVE_SHMIMAGE
  1.2234 +#endif // MOZ_X11
  1.2235 +
  1.2236 +    listener->DidPaintWindow();
  1.2237 +
  1.2238 +    // Synchronously flush any new dirty areas
  1.2239 +#if (MOZ_WIDGET_GTK == 2)
  1.2240 +    GdkRegion* dirtyArea = gdk_window_get_update_area(mGdkWindow);
  1.2241 +#else
  1.2242 +    cairo_region_t* dirtyArea = gdk_window_get_update_area(mGdkWindow);
  1.2243 +#endif
  1.2244 +
  1.2245 +    if (dirtyArea) {
  1.2246 +        gdk_window_invalidate_region(mGdkWindow, dirtyArea, false);
  1.2247 +#if (MOZ_WIDGET_GTK == 2)
  1.2248 +        gdk_region_destroy(dirtyArea);
  1.2249 +#else
  1.2250 +        cairo_region_destroy(dirtyArea);
  1.2251 +#endif
  1.2252 +        gdk_window_process_updates(mGdkWindow, false);
  1.2253 +    }
  1.2254 +
  1.2255 +    // check the return value!
  1.2256 +    return TRUE;
  1.2257 +}
  1.2258 +
  1.2259 +void
  1.2260 +nsWindow::UpdateAlpha(gfxPattern* aPattern, nsIntRect aBoundsRect)
  1.2261 +{
  1.2262 +    // We need to create our own buffer to force the stride to match the
  1.2263 +    // expected stride.
  1.2264 +    int32_t stride = GetAlignedStride<4>(BytesPerPixel(SurfaceFormat::A8) *
  1.2265 +                                         aBoundsRect.width);
  1.2266 +    int32_t bufferSize = stride * aBoundsRect.height;
  1.2267 +    nsAutoArrayPtr<uint8_t> imageBuffer(new (std::nothrow) uint8_t[bufferSize]);
  1.2268 +    RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->
  1.2269 +        CreateDrawTargetForData(imageBuffer, ToIntSize(aBoundsRect.Size()),
  1.2270 +                                stride, SurfaceFormat::A8);
  1.2271 +
  1.2272 +    if (drawTarget) {
  1.2273 +        drawTarget->FillRect(Rect(0, 0, aBoundsRect.width, aBoundsRect.height),
  1.2274 +                             *aPattern->GetPattern(drawTarget),
  1.2275 +                             DrawOptions(1.0, CompositionOp::OP_SOURCE));
  1.2276 +    }
  1.2277 +    UpdateTranslucentWindowAlphaInternal(aBoundsRect, imageBuffer, stride);
  1.2278 +}
  1.2279 +
  1.2280 +gboolean
  1.2281 +nsWindow::OnConfigureEvent(GtkWidget *aWidget, GdkEventConfigure *aEvent)
  1.2282 +{
  1.2283 +    // These events are only received on toplevel windows.
  1.2284 +    //
  1.2285 +    // GDK ensures that the coordinates are the client window top-left wrt the
  1.2286 +    // root window.
  1.2287 +    //
  1.2288 +    //   GDK calculates the cordinates for real ConfigureNotify events on
  1.2289 +    //   managed windows (that would normally be relative to the parent
  1.2290 +    //   window).
  1.2291 +    //
  1.2292 +    //   Synthetic ConfigureNotify events are from the window manager and
  1.2293 +    //   already relative to the root window.  GDK creates all X windows with
  1.2294 +    //   border_width = 0, so synthetic events also indicate the top-left of
  1.2295 +    //   the client window.
  1.2296 +    //
  1.2297 +    //   Override-redirect windows are children of the root window so parent
  1.2298 +    //   coordinates are root coordinates.
  1.2299 +
  1.2300 +    LOG(("configure event [%p] %d %d %d %d\n", (void *)this,
  1.2301 +         aEvent->x, aEvent->y, aEvent->width, aEvent->height));
  1.2302 +
  1.2303 +    nsIntRect screenBounds;
  1.2304 +    GetScreenBounds(screenBounds);
  1.2305 +
  1.2306 +    if (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) {
  1.2307 +        // This check avoids unwanted rollup on spurious configure events from
  1.2308 +        // Cygwin/X (bug 672103).
  1.2309 +        if (mBounds.x != screenBounds.x ||
  1.2310 +            mBounds.y != screenBounds.y) {
  1.2311 +            CheckForRollup(0, 0, false, true);
  1.2312 +        }
  1.2313 +    }
  1.2314 +
  1.2315 +    // This event indicates that the window position may have changed.
  1.2316 +    // mBounds.Size() is updated in OnSizeAllocate().
  1.2317 +
  1.2318 +    // (The gtk_window_get_window_type() function is only available from
  1.2319 +    // version 2.20.)
  1.2320 +    NS_ASSERTION(GTK_IS_WINDOW(aWidget),
  1.2321 +                 "Configure event on widget that is not a GtkWindow");
  1.2322 +    gint type;
  1.2323 +    g_object_get(aWidget, "type", &type, nullptr);
  1.2324 +    if (type == GTK_WINDOW_POPUP) {
  1.2325 +        // Override-redirect window
  1.2326 +        //
  1.2327 +        // These windows should not be moved by the window manager, and so any
  1.2328 +        // change in position is a result of our direction.  mBounds has
  1.2329 +        // already been set in Move() or Resize(), and that is more
  1.2330 +        // up-to-date than the position in the ConfigureNotify event if the
  1.2331 +        // event is from an earlier window move.
  1.2332 +        //
  1.2333 +        // Skipping the WindowMoved call saves context menus from an infinite
  1.2334 +        // loop when nsXULPopupManager::PopupMoved moves the window to the new
  1.2335 +        // position and nsMenuPopupFrame::SetPopupPosition adds
  1.2336 +        // offsetForContextMenu on each iteration.
  1.2337 +        return FALSE;
  1.2338 +    }
  1.2339 +
  1.2340 +    mBounds.MoveTo(screenBounds.TopLeft());
  1.2341 +
  1.2342 +    // XXX mozilla will invalidate the entire window after this move
  1.2343 +    // complete.  wtf?
  1.2344 +    NotifyWindowMoved(mBounds.x, mBounds.y);
  1.2345 +
  1.2346 +    return FALSE;
  1.2347 +}
  1.2348 +
  1.2349 +void
  1.2350 +nsWindow::OnContainerUnrealize()
  1.2351 +{
  1.2352 +    // The GdkWindows are about to be destroyed (but not deleted), so remove
  1.2353 +    // their references back to their container widget while the GdkWindow
  1.2354 +    // hierarchy is still available.
  1.2355 +
  1.2356 +    if (mGdkWindow) {
  1.2357 +        DestroyChildWindows();
  1.2358 +
  1.2359 +        g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
  1.2360 +        mGdkWindow = nullptr;
  1.2361 +    }
  1.2362 +}
  1.2363 +
  1.2364 +void
  1.2365 +nsWindow::OnSizeAllocate(GtkAllocation *aAllocation)
  1.2366 +{
  1.2367 +    LOG(("size_allocate [%p] %d %d %d %d\n",
  1.2368 +         (void *)this, aAllocation->x, aAllocation->y,
  1.2369 +         aAllocation->width, aAllocation->height));
  1.2370 +
  1.2371 +    nsIntSize size(aAllocation->width, aAllocation->height);
  1.2372 +    if (mBounds.Size() == size)
  1.2373 +        return;
  1.2374 +
  1.2375 +    // Invalidate the new part of the window now for the pending paint to
  1.2376 +    // minimize background flashes (GDK does not do this for external resizes
  1.2377 +    // of toplevels.)
  1.2378 +    if (mBounds.width < size.width) {
  1.2379 +        GdkRectangle rect =
  1.2380 +            { mBounds.width, 0, size.width - mBounds.width, size.height };
  1.2381 +        gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
  1.2382 +    }
  1.2383 +    if (mBounds.height < size.height) {
  1.2384 +        GdkRectangle rect =
  1.2385 +            { 0, mBounds.height, size.width, size.height - mBounds.height };
  1.2386 +        gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
  1.2387 +    }
  1.2388 +
  1.2389 +    mBounds.SizeTo(size);
  1.2390 +
  1.2391 +    if (!mGdkWindow)
  1.2392 +        return;
  1.2393 +
  1.2394 +    DispatchResized(size.width, size.height);
  1.2395 +}
  1.2396 +
  1.2397 +void
  1.2398 +nsWindow::OnDeleteEvent()
  1.2399 +{
  1.2400 +    if (mWidgetListener)
  1.2401 +        mWidgetListener->RequestWindowClose(this);
  1.2402 +}
  1.2403 +
  1.2404 +void
  1.2405 +nsWindow::OnEnterNotifyEvent(GdkEventCrossing *aEvent)
  1.2406 +{
  1.2407 +    // This skips NotifyVirtual and NotifyNonlinearVirtual enter notify events
  1.2408 +    // when the pointer enters a child window.  If the destination window is a
  1.2409 +    // Gecko window then we'll catch the corresponding event on that window,
  1.2410 +    // but we won't notice when the pointer directly enters a foreign (plugin)
  1.2411 +    // child window without passing over a visible portion of a Gecko window.
  1.2412 +    if (aEvent->subwindow != nullptr)
  1.2413 +        return;
  1.2414 +
  1.2415 +    // Check before is_parent_ungrab_enter() as the button state may have
  1.2416 +    // changed while a non-Gecko ancestor window had a pointer grab.
  1.2417 +    DispatchMissedButtonReleases(aEvent);
  1.2418 +
  1.2419 +    if (is_parent_ungrab_enter(aEvent))
  1.2420 +        return;
  1.2421 +
  1.2422 +    WidgetMouseEvent event(true, NS_MOUSE_ENTER, this, WidgetMouseEvent::eReal);
  1.2423 +
  1.2424 +    event.refPoint.x = nscoord(aEvent->x);
  1.2425 +    event.refPoint.y = nscoord(aEvent->y);
  1.2426 +
  1.2427 +    event.time = aEvent->time;
  1.2428 +
  1.2429 +    LOG(("OnEnterNotify: %p\n", (void *)this));
  1.2430 +
  1.2431 +    nsEventStatus status;
  1.2432 +    DispatchEvent(&event, status);
  1.2433 +}
  1.2434 +
  1.2435 +// XXX Is this the right test for embedding cases?
  1.2436 +static bool
  1.2437 +is_top_level_mouse_exit(GdkWindow* aWindow, GdkEventCrossing *aEvent)
  1.2438 +{
  1.2439 +    gint x = gint(aEvent->x_root);
  1.2440 +    gint y = gint(aEvent->y_root);
  1.2441 +    GdkDisplay* display = gdk_window_get_display(aWindow);
  1.2442 +    GdkWindow* winAtPt = gdk_display_get_window_at_pointer(display, &x, &y);
  1.2443 +    if (!winAtPt)
  1.2444 +        return true;
  1.2445 +    GdkWindow* topLevelAtPt = gdk_window_get_toplevel(winAtPt);
  1.2446 +    GdkWindow* topLevelWidget = gdk_window_get_toplevel(aWindow);
  1.2447 +    return topLevelAtPt != topLevelWidget;
  1.2448 +}
  1.2449 +
  1.2450 +void
  1.2451 +nsWindow::OnLeaveNotifyEvent(GdkEventCrossing *aEvent)
  1.2452 +{
  1.2453 +    // This ignores NotifyVirtual and NotifyNonlinearVirtual leave notify
  1.2454 +    // events when the pointer leaves a child window.  If the destination
  1.2455 +    // window is a Gecko window then we'll catch the corresponding event on
  1.2456 +    // that window.
  1.2457 +    //
  1.2458 +    // XXXkt However, we will miss toplevel exits when the pointer directly
  1.2459 +    // leaves a foreign (plugin) child window without passing over a visible
  1.2460 +    // portion of a Gecko window.
  1.2461 +    if (aEvent->subwindow != nullptr)
  1.2462 +        return;
  1.2463 +
  1.2464 +    WidgetMouseEvent event(true, NS_MOUSE_EXIT, this, WidgetMouseEvent::eReal);
  1.2465 +
  1.2466 +    event.refPoint.x = nscoord(aEvent->x);
  1.2467 +    event.refPoint.y = nscoord(aEvent->y);
  1.2468 +
  1.2469 +    event.time = aEvent->time;
  1.2470 +
  1.2471 +    event.exit = is_top_level_mouse_exit(mGdkWindow, aEvent)
  1.2472 +        ? WidgetMouseEvent::eTopLevel : WidgetMouseEvent::eChild;
  1.2473 +
  1.2474 +    LOG(("OnLeaveNotify: %p\n", (void *)this));
  1.2475 +
  1.2476 +    nsEventStatus status;
  1.2477 +    DispatchEvent(&event, status);
  1.2478 +}
  1.2479 +
  1.2480 +void
  1.2481 +nsWindow::OnMotionNotifyEvent(GdkEventMotion *aEvent)
  1.2482 +{
  1.2483 +    // see if we can compress this event
  1.2484 +    // XXXldb Why skip every other motion event when we have multiple,
  1.2485 +    // but not more than that?
  1.2486 +    bool synthEvent = false;
  1.2487 +#ifdef MOZ_X11
  1.2488 +    XEvent xevent;
  1.2489 +
  1.2490 +    while (XPending (GDK_WINDOW_XDISPLAY(aEvent->window))) {
  1.2491 +        XEvent peeked;
  1.2492 +        XPeekEvent (GDK_WINDOW_XDISPLAY(aEvent->window), &peeked);
  1.2493 +        if (peeked.xany.window != gdk_x11_window_get_xid(aEvent->window)
  1.2494 +            || peeked.type != MotionNotify)
  1.2495 +            break;
  1.2496 +
  1.2497 +        synthEvent = true;
  1.2498 +        XNextEvent (GDK_WINDOW_XDISPLAY(aEvent->window), &xevent);
  1.2499 +    }
  1.2500 +#if (MOZ_WIDGET_GTK == 2)
  1.2501 +    // if plugins still keeps the focus, get it back
  1.2502 +    if (gPluginFocusWindow && gPluginFocusWindow != this) {
  1.2503 +        nsRefPtr<nsWindow> kungFuDeathGrip = gPluginFocusWindow;
  1.2504 +        gPluginFocusWindow->LoseNonXEmbedPluginFocus();
  1.2505 +    }
  1.2506 +#endif /* MOZ_WIDGET_GTK2 */
  1.2507 +#endif /* MOZ_X11 */
  1.2508 +
  1.2509 +    WidgetMouseEvent event(true, NS_MOUSE_MOVE, this, WidgetMouseEvent::eReal);
  1.2510 +
  1.2511 +    gdouble pressure = 0;
  1.2512 +    gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
  1.2513 +    // Sometime gdk generate 0 pressure value between normal values
  1.2514 +    // We have to ignore that and use last valid value
  1.2515 +    if (pressure)
  1.2516 +      mLastMotionPressure = pressure;
  1.2517 +    event.pressure = mLastMotionPressure;
  1.2518 +
  1.2519 +    guint modifierState;
  1.2520 +    if (synthEvent) {
  1.2521 +#ifdef MOZ_X11
  1.2522 +        event.refPoint.x = nscoord(xevent.xmotion.x);
  1.2523 +        event.refPoint.y = nscoord(xevent.xmotion.y);
  1.2524 +
  1.2525 +        modifierState = xevent.xmotion.state;
  1.2526 +
  1.2527 +        event.time = xevent.xmotion.time;
  1.2528 +#else
  1.2529 +        event.refPoint.x = nscoord(aEvent->x);
  1.2530 +        event.refPoint.y = nscoord(aEvent->y);
  1.2531 +
  1.2532 +        modifierState = aEvent->state;
  1.2533 +
  1.2534 +        event.time = aEvent->time;
  1.2535 +#endif /* MOZ_X11 */
  1.2536 +    }
  1.2537 +    else {
  1.2538 +        // XXX see OnScrollEvent()
  1.2539 +        if (aEvent->window == mGdkWindow) {
  1.2540 +            event.refPoint.x = nscoord(aEvent->x);
  1.2541 +            event.refPoint.y = nscoord(aEvent->y);
  1.2542 +        } else {
  1.2543 +            LayoutDeviceIntPoint point(NSToIntFloor(aEvent->x_root),
  1.2544 +                                       NSToIntFloor(aEvent->y_root));
  1.2545 +            event.refPoint = point -
  1.2546 +                LayoutDeviceIntPoint::FromUntyped(WidgetToScreenOffset());
  1.2547 +        }
  1.2548 +
  1.2549 +        modifierState = aEvent->state;
  1.2550 +
  1.2551 +        event.time = aEvent->time;
  1.2552 +    }
  1.2553 +
  1.2554 +    KeymapWrapper::InitInputEvent(event, modifierState);
  1.2555 +
  1.2556 +    nsEventStatus status;
  1.2557 +    DispatchEvent(&event, status);
  1.2558 +}
  1.2559 +
  1.2560 +// If the automatic pointer grab on ButtonPress has deactivated before
  1.2561 +// ButtonRelease, and the mouse button is released while the pointer is not
  1.2562 +// over any a Gecko window, then the ButtonRelease event will not be received.
  1.2563 +// (A similar situation exists when the pointer is grabbed with owner_events
  1.2564 +// True as the ButtonRelease may be received on a foreign [plugin] window).
  1.2565 +// Use this method to check for released buttons when the pointer returns to a
  1.2566 +// Gecko window.
  1.2567 +void
  1.2568 +nsWindow::DispatchMissedButtonReleases(GdkEventCrossing *aGdkEvent)
  1.2569 +{
  1.2570 +    guint changed = aGdkEvent->state ^ gButtonState;
  1.2571 +    // Only consider button releases.
  1.2572 +    // (Ignore button presses that occurred outside Gecko.)
  1.2573 +    guint released = changed & gButtonState;
  1.2574 +    gButtonState = aGdkEvent->state;
  1.2575 +
  1.2576 +    // Loop over each button, excluding mouse wheel buttons 4 and 5 for which
  1.2577 +    // GDK ignores releases.
  1.2578 +    for (guint buttonMask = GDK_BUTTON1_MASK;
  1.2579 +         buttonMask <= GDK_BUTTON3_MASK;
  1.2580 +         buttonMask <<= 1) {
  1.2581 +
  1.2582 +        if (released & buttonMask) {
  1.2583 +            int16_t buttonType;
  1.2584 +            switch (buttonMask) {
  1.2585 +            case GDK_BUTTON1_MASK:
  1.2586 +                buttonType = WidgetMouseEvent::eLeftButton;
  1.2587 +                break;
  1.2588 +            case GDK_BUTTON2_MASK:
  1.2589 +                buttonType = WidgetMouseEvent::eMiddleButton;
  1.2590 +                break;
  1.2591 +            default:
  1.2592 +                NS_ASSERTION(buttonMask == GDK_BUTTON3_MASK,
  1.2593 +                             "Unexpected button mask");
  1.2594 +                buttonType = WidgetMouseEvent::eRightButton;
  1.2595 +            }
  1.2596 +
  1.2597 +            LOG(("Synthesized button %u release on %p\n",
  1.2598 +                 guint(buttonType + 1), (void *)this));
  1.2599 +
  1.2600 +            // Dispatch a synthesized button up event to tell Gecko about the
  1.2601 +            // change in state.  This event is marked as synthesized so that
  1.2602 +            // it is not dispatched as a DOM event, because we don't know the
  1.2603 +            // position, widget, modifiers, or time/order.
  1.2604 +            WidgetMouseEvent synthEvent(true, NS_MOUSE_BUTTON_UP, this,
  1.2605 +                                        WidgetMouseEvent::eSynthesized);
  1.2606 +            synthEvent.button = buttonType;
  1.2607 +            nsEventStatus status;
  1.2608 +            DispatchEvent(&synthEvent, status);
  1.2609 +        }
  1.2610 +    }
  1.2611 +}
  1.2612 +
  1.2613 +void
  1.2614 +nsWindow::InitButtonEvent(WidgetMouseEvent& aEvent,
  1.2615 +                          GdkEventButton* aGdkEvent)
  1.2616 +{
  1.2617 +    // XXX see OnScrollEvent()
  1.2618 +    if (aGdkEvent->window == mGdkWindow) {
  1.2619 +        aEvent.refPoint.x = nscoord(aGdkEvent->x);
  1.2620 +        aEvent.refPoint.y = nscoord(aGdkEvent->y);
  1.2621 +    } else {
  1.2622 +        LayoutDeviceIntPoint point(NSToIntFloor(aGdkEvent->x_root),
  1.2623 +                                   NSToIntFloor(aGdkEvent->y_root));
  1.2624 +        aEvent.refPoint = point -
  1.2625 +            LayoutDeviceIntPoint::FromUntyped(WidgetToScreenOffset());
  1.2626 +    }
  1.2627 +
  1.2628 +    guint modifierState = aGdkEvent->state;
  1.2629 +    // aEvent's state doesn't include this event's information.  Therefore,
  1.2630 +    // if aEvent is mouse button down event, we need to set it manually.
  1.2631 +    // Note that we cannot do same thing for NS_MOUSE_BUTTON_UP because
  1.2632 +    // system may have two or more mice and same button of another mouse
  1.2633 +    // may be still pressed.
  1.2634 +    if (aGdkEvent->type != GDK_BUTTON_RELEASE) {
  1.2635 +        switch (aGdkEvent->button) {
  1.2636 +            case 1:
  1.2637 +                modifierState |= GDK_BUTTON1_MASK;
  1.2638 +                break;
  1.2639 +            case 2:
  1.2640 +                modifierState |= GDK_BUTTON2_MASK;
  1.2641 +                break;
  1.2642 +            case 3:
  1.2643 +                modifierState |= GDK_BUTTON3_MASK;
  1.2644 +                break;
  1.2645 +        }
  1.2646 +    }
  1.2647 +
  1.2648 +    KeymapWrapper::InitInputEvent(aEvent, modifierState);
  1.2649 +
  1.2650 +    aEvent.time = aGdkEvent->time;
  1.2651 +
  1.2652 +    switch (aGdkEvent->type) {
  1.2653 +    case GDK_2BUTTON_PRESS:
  1.2654 +        aEvent.clickCount = 2;
  1.2655 +        break;
  1.2656 +    case GDK_3BUTTON_PRESS:
  1.2657 +        aEvent.clickCount = 3;
  1.2658 +        break;
  1.2659 +        // default is one click
  1.2660 +    default:
  1.2661 +        aEvent.clickCount = 1;
  1.2662 +    }
  1.2663 +}
  1.2664 +
  1.2665 +static guint ButtonMaskFromGDKButton(guint button)
  1.2666 +{
  1.2667 +    return GDK_BUTTON1_MASK << (button - 1);
  1.2668 +}
  1.2669 +
  1.2670 +void
  1.2671 +nsWindow::OnButtonPressEvent(GdkEventButton *aEvent)
  1.2672 +{
  1.2673 +    LOG(("Button %u press on %p\n", aEvent->button, (void *)this));
  1.2674 +
  1.2675 +    nsEventStatus status;
  1.2676 +
  1.2677 +    // If you double click in GDK, it will actually generate a second
  1.2678 +    // GDK_BUTTON_PRESS before sending the GDK_2BUTTON_PRESS, and this is
  1.2679 +    // different than the DOM spec.  GDK puts this in the queue
  1.2680 +    // programatically, so it's safe to assume that if there's a
  1.2681 +    // double click in the queue, it was generated so we can just drop
  1.2682 +    // this click.
  1.2683 +    GdkEvent *peekedEvent = gdk_event_peek();
  1.2684 +    if (peekedEvent) {
  1.2685 +        GdkEventType type = peekedEvent->any.type;
  1.2686 +        gdk_event_free(peekedEvent);
  1.2687 +        if (type == GDK_2BUTTON_PRESS || type == GDK_3BUTTON_PRESS)
  1.2688 +            return;
  1.2689 +    }
  1.2690 +
  1.2691 +    nsWindow *containerWindow = GetContainerWindow();
  1.2692 +    if (!gFocusWindow && containerWindow) {
  1.2693 +        containerWindow->DispatchActivateEvent();
  1.2694 +    }
  1.2695 +
  1.2696 +    // check to see if we should rollup
  1.2697 +    if (CheckForRollup(aEvent->x_root, aEvent->y_root, false, false))
  1.2698 +        return;
  1.2699 +
  1.2700 +    gdouble pressure = 0;
  1.2701 +    gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
  1.2702 +    mLastMotionPressure = pressure;
  1.2703 +
  1.2704 +    uint16_t domButton;
  1.2705 +    switch (aEvent->button) {
  1.2706 +    case 1:
  1.2707 +        domButton = WidgetMouseEvent::eLeftButton;
  1.2708 +        break;
  1.2709 +    case 2:
  1.2710 +        domButton = WidgetMouseEvent::eMiddleButton;
  1.2711 +        break;
  1.2712 +    case 3:
  1.2713 +        domButton = WidgetMouseEvent::eRightButton;
  1.2714 +        break;
  1.2715 +    // These are mapped to horizontal scroll
  1.2716 +    case 6:
  1.2717 +    case 7:
  1.2718 +        NS_WARNING("We're not supporting legacy horizontal scroll event");
  1.2719 +        return;
  1.2720 +    // Map buttons 8-9 to back/forward
  1.2721 +    case 8:
  1.2722 +        DispatchCommandEvent(nsGkAtoms::Back);
  1.2723 +        return;
  1.2724 +    case 9:
  1.2725 +        DispatchCommandEvent(nsGkAtoms::Forward);
  1.2726 +        return;
  1.2727 +    default:
  1.2728 +        return;
  1.2729 +    }
  1.2730 +
  1.2731 +    gButtonState |= ButtonMaskFromGDKButton(aEvent->button);
  1.2732 +
  1.2733 +    WidgetMouseEvent event(true, NS_MOUSE_BUTTON_DOWN, this,
  1.2734 +                           WidgetMouseEvent::eReal);
  1.2735 +    event.button = domButton;
  1.2736 +    InitButtonEvent(event, aEvent);
  1.2737 +    event.pressure = mLastMotionPressure;
  1.2738 +
  1.2739 +    DispatchEvent(&event, status);
  1.2740 +
  1.2741 +    // right menu click on linux should also pop up a context menu
  1.2742 +    if (domButton == WidgetMouseEvent::eRightButton &&
  1.2743 +        MOZ_LIKELY(!mIsDestroyed)) {
  1.2744 +        WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
  1.2745 +                                          WidgetMouseEvent::eReal);
  1.2746 +        InitButtonEvent(contextMenuEvent, aEvent);
  1.2747 +        contextMenuEvent.pressure = mLastMotionPressure;
  1.2748 +        DispatchEvent(&contextMenuEvent, status);
  1.2749 +    }
  1.2750 +}
  1.2751 +
  1.2752 +void
  1.2753 +nsWindow::OnButtonReleaseEvent(GdkEventButton *aEvent)
  1.2754 +{
  1.2755 +    LOG(("Button %u release on %p\n", aEvent->button, (void *)this));
  1.2756 +
  1.2757 +    uint16_t domButton;
  1.2758 +    switch (aEvent->button) {
  1.2759 +    case 1:
  1.2760 +        domButton = WidgetMouseEvent::eLeftButton;
  1.2761 +        break;
  1.2762 +    case 2:
  1.2763 +        domButton = WidgetMouseEvent::eMiddleButton;
  1.2764 +        break;
  1.2765 +    case 3:
  1.2766 +        domButton = WidgetMouseEvent::eRightButton;
  1.2767 +        break;
  1.2768 +    default:
  1.2769 +        return;
  1.2770 +    }
  1.2771 +
  1.2772 +    gButtonState &= ~ButtonMaskFromGDKButton(aEvent->button);
  1.2773 +
  1.2774 +    WidgetMouseEvent event(true, NS_MOUSE_BUTTON_UP, this,
  1.2775 +                           WidgetMouseEvent::eReal);
  1.2776 +    event.button = domButton;
  1.2777 +    InitButtonEvent(event, aEvent);
  1.2778 +    gdouble pressure = 0;
  1.2779 +    gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
  1.2780 +    event.pressure = pressure ? pressure : mLastMotionPressure;
  1.2781 +
  1.2782 +    nsEventStatus status;
  1.2783 +    DispatchEvent(&event, status);
  1.2784 +    mLastMotionPressure = pressure;
  1.2785 +}
  1.2786 +
  1.2787 +void
  1.2788 +nsWindow::OnContainerFocusInEvent(GdkEventFocus *aEvent)
  1.2789 +{
  1.2790 +    LOGFOCUS(("OnContainerFocusInEvent [%p]\n", (void *)this));
  1.2791 +
  1.2792 +    // Unset the urgency hint, if possible
  1.2793 +    GtkWidget* top_window = GetToplevelWidget();
  1.2794 +    if (top_window && (gtk_widget_get_visible(top_window)))
  1.2795 +        SetUrgencyHint(top_window, false);
  1.2796 +
  1.2797 +    // Return if being called within SetFocus because the focus manager
  1.2798 +    // already knows that the window is active.
  1.2799 +    if (gBlockActivateEvent) {
  1.2800 +        LOGFOCUS(("activated notification is blocked [%p]\n", (void *)this));
  1.2801 +        return;
  1.2802 +    }
  1.2803 +
  1.2804 +    // If keyboard input will be accepted, the focus manager will call
  1.2805 +    // SetFocus to set the correct window.
  1.2806 +    gFocusWindow = nullptr;
  1.2807 +
  1.2808 +    DispatchActivateEvent();
  1.2809 +
  1.2810 +    if (!gFocusWindow) {
  1.2811 +        // We don't really have a window for dispatching key events, but
  1.2812 +        // setting a non-nullptr value here prevents OnButtonPressEvent() from
  1.2813 +        // dispatching an activation notification if the widget is already
  1.2814 +        // active.
  1.2815 +        gFocusWindow = this;
  1.2816 +    }
  1.2817 +
  1.2818 +    LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
  1.2819 +}
  1.2820 +
  1.2821 +void
  1.2822 +nsWindow::OnContainerFocusOutEvent(GdkEventFocus *aEvent)
  1.2823 +{
  1.2824 +    LOGFOCUS(("OnContainerFocusOutEvent [%p]\n", (void *)this));
  1.2825 +
  1.2826 +    if (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) {
  1.2827 +        nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
  1.2828 +        nsCOMPtr<nsIDragSession> dragSession;
  1.2829 +        dragService->GetCurrentSession(getter_AddRefs(dragSession));
  1.2830 +
  1.2831 +        // Rollup popups when a window is focused out unless a drag is occurring.
  1.2832 +        // This check is because drags grab the keyboard and cause a focus out on
  1.2833 +        // versions of GTK before 2.18.
  1.2834 +        bool shouldRollup = !dragSession;
  1.2835 +        if (!shouldRollup) {
  1.2836 +            // we also roll up when a drag is from a different application
  1.2837 +            nsCOMPtr<nsIDOMNode> sourceNode;
  1.2838 +            dragSession->GetSourceNode(getter_AddRefs(sourceNode));
  1.2839 +            shouldRollup = (sourceNode == nullptr);
  1.2840 +        }
  1.2841 +
  1.2842 +        if (shouldRollup) {
  1.2843 +            CheckForRollup(0, 0, false, true);
  1.2844 +        }
  1.2845 +    }
  1.2846 +
  1.2847 +#if (MOZ_WIDGET_GTK == 2) && defined(MOZ_X11)
  1.2848 +    // plugin lose focus
  1.2849 +    if (gPluginFocusWindow) {
  1.2850 +        nsRefPtr<nsWindow> kungFuDeathGrip = gPluginFocusWindow;
  1.2851 +        gPluginFocusWindow->LoseNonXEmbedPluginFocus();
  1.2852 +    }
  1.2853 +#endif /* MOZ_X11 && MOZ_WIDGET_GTK2 */
  1.2854 +
  1.2855 +    if (gFocusWindow) {
  1.2856 +        nsRefPtr<nsWindow> kungFuDeathGrip = gFocusWindow;
  1.2857 +        if (gFocusWindow->mIMModule) {
  1.2858 +            gFocusWindow->mIMModule->OnBlurWindow(gFocusWindow);
  1.2859 +        }
  1.2860 +        gFocusWindow = nullptr;
  1.2861 +    }
  1.2862 +
  1.2863 +    DispatchDeactivateEvent();
  1.2864 +
  1.2865 +    LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
  1.2866 +}
  1.2867 +
  1.2868 +bool
  1.2869 +nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
  1.2870 +{
  1.2871 +    nsEventStatus status;
  1.2872 +    WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this);
  1.2873 +    DispatchEvent(&event, status);
  1.2874 +    return TRUE;
  1.2875 +}
  1.2876 +
  1.2877 +bool
  1.2878 +nsWindow::DispatchContentCommandEvent(int32_t aMsg)
  1.2879 +{
  1.2880 +  nsEventStatus status;
  1.2881 +  WidgetContentCommandEvent event(true, aMsg, this);
  1.2882 +  DispatchEvent(&event, status);
  1.2883 +  return TRUE;
  1.2884 +}
  1.2885 +
  1.2886 +static bool
  1.2887 +IsCtrlAltTab(GdkEventKey *aEvent)
  1.2888 +{
  1.2889 +    return aEvent->keyval == GDK_Tab &&
  1.2890 +        KeymapWrapper::AreModifiersActive(
  1.2891 +            KeymapWrapper::CTRL | KeymapWrapper::ALT, aEvent->state);
  1.2892 +}
  1.2893 +
  1.2894 +bool
  1.2895 +nsWindow::DispatchKeyDownEvent(GdkEventKey *aEvent, bool *aCancelled)
  1.2896 +{
  1.2897 +    NS_PRECONDITION(aCancelled, "aCancelled must not be null");
  1.2898 +
  1.2899 +    *aCancelled = false;
  1.2900 +
  1.2901 +    if (IsCtrlAltTab(aEvent)) {
  1.2902 +        return false;
  1.2903 +    }
  1.2904 +
  1.2905 +    // send the key down event
  1.2906 +    nsEventStatus status;
  1.2907 +    WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this);
  1.2908 +    KeymapWrapper::InitKeyEvent(downEvent, aEvent);
  1.2909 +    DispatchEvent(&downEvent, status);
  1.2910 +    *aCancelled = (status == nsEventStatus_eConsumeNoDefault);
  1.2911 +    return true;
  1.2912 +}
  1.2913 +
  1.2914 +gboolean
  1.2915 +nsWindow::OnKeyPressEvent(GdkEventKey *aEvent)
  1.2916 +{
  1.2917 +    LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
  1.2918 +
  1.2919 +    // if we are in the middle of composing text, XIM gets to see it
  1.2920 +    // before mozilla does.
  1.2921 +    bool IMEWasEnabled = false;
  1.2922 +    if (mIMModule) {
  1.2923 +        IMEWasEnabled = mIMModule->IsEnabled();
  1.2924 +        if (mIMModule->OnKeyEvent(this, aEvent)) {
  1.2925 +            return TRUE;
  1.2926 +        }
  1.2927 +    }
  1.2928 +
  1.2929 +    nsEventStatus status;
  1.2930 +
  1.2931 +    // work around for annoying things.
  1.2932 +    if (IsCtrlAltTab(aEvent)) {
  1.2933 +        return TRUE;
  1.2934 +    }
  1.2935 +
  1.2936 +    nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
  1.2937 +
  1.2938 +    // Dispatch keydown event always.  At auto repeating, we should send
  1.2939 +    // KEYDOWN -> KEYPRESS -> KEYDOWN -> KEYPRESS ... -> KEYUP
  1.2940 +    // However, old distributions (e.g., Ubuntu 9.10) sent native key
  1.2941 +    // release event, so, on such platform, the DOM events will be:
  1.2942 +    // KEYDOWN -> KEYPRESS -> KEYUP -> KEYDOWN -> KEYPRESS -> KEYUP...
  1.2943 +
  1.2944 +    bool isKeyDownCancelled = false;
  1.2945 +    if (DispatchKeyDownEvent(aEvent, &isKeyDownCancelled) &&
  1.2946 +        (MOZ_UNLIKELY(mIsDestroyed) || isKeyDownCancelled)) {
  1.2947 +        return TRUE;
  1.2948 +    }
  1.2949 +
  1.2950 +    // If a keydown event handler causes to enable IME, i.e., it moves
  1.2951 +    // focus from IME unusable content to IME usable editor, we should
  1.2952 +    // send the native key event to IME for the first input on the editor.
  1.2953 +    if (!IMEWasEnabled && mIMModule && mIMModule->IsEnabled()) {
  1.2954 +        // Notice our keydown event was already dispatched.  This prevents
  1.2955 +        // unnecessary DOM keydown event in the editor.
  1.2956 +        if (mIMModule->OnKeyEvent(this, aEvent, true)) {
  1.2957 +            return TRUE;
  1.2958 +        }
  1.2959 +    }
  1.2960 +
  1.2961 +    // Don't pass modifiers as NS_KEY_PRESS events.
  1.2962 +    // TODO: Instead of selectively excluding some keys from NS_KEY_PRESS events,
  1.2963 +    //       we should instead selectively include (as per MSDN spec; no official
  1.2964 +    //       spec covers KeyPress events).
  1.2965 +    if (!KeymapWrapper::IsKeyPressEventNecessary(aEvent)) {
  1.2966 +        return TRUE;
  1.2967 +    }
  1.2968 +
  1.2969 +#ifdef MOZ_X11
  1.2970 +#if ! defined AIX // no XFree86 on AIX 5L
  1.2971 +    // Look for specialized app-command keys
  1.2972 +    switch (aEvent->keyval) {
  1.2973 +        case XF86XK_Back:
  1.2974 +            return DispatchCommandEvent(nsGkAtoms::Back);
  1.2975 +        case XF86XK_Forward:
  1.2976 +            return DispatchCommandEvent(nsGkAtoms::Forward);
  1.2977 +        case XF86XK_Refresh:
  1.2978 +            return DispatchCommandEvent(nsGkAtoms::Reload);
  1.2979 +        case XF86XK_Stop:
  1.2980 +            return DispatchCommandEvent(nsGkAtoms::Stop);
  1.2981 +        case XF86XK_Search:
  1.2982 +            return DispatchCommandEvent(nsGkAtoms::Search);
  1.2983 +        case XF86XK_Favorites:
  1.2984 +            return DispatchCommandEvent(nsGkAtoms::Bookmarks);
  1.2985 +        case XF86XK_HomePage:
  1.2986 +            return DispatchCommandEvent(nsGkAtoms::Home);
  1.2987 +        case XF86XK_Copy:
  1.2988 +        case GDK_F16:  // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo
  1.2989 +            return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY);
  1.2990 +        case XF86XK_Cut:
  1.2991 +        case GDK_F20:
  1.2992 +            return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT);
  1.2993 +        case XF86XK_Paste:
  1.2994 +        case GDK_F18:
  1.2995 +            return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE);
  1.2996 +        case GDK_Redo:
  1.2997 +            return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO);
  1.2998 +        case GDK_Undo:
  1.2999 +        case GDK_F14:
  1.3000 +            return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO);
  1.3001 +    }
  1.3002 +#endif /* ! AIX */
  1.3003 +#endif /* MOZ_X11 */
  1.3004 +
  1.3005 +    WidgetKeyboardEvent event(true, NS_KEY_PRESS, this);
  1.3006 +    KeymapWrapper::InitKeyEvent(event, aEvent);
  1.3007 +
  1.3008 +    // before we dispatch a key, check if it's the context menu key.
  1.3009 +    // If so, send a context menu key event instead.
  1.3010 +    if (is_context_menu_key(event)) {
  1.3011 +        WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this,
  1.3012 +                                          WidgetMouseEvent::eReal,
  1.3013 +                                          WidgetMouseEvent::eContextMenuKey);
  1.3014 +
  1.3015 +        contextMenuEvent.refPoint = LayoutDeviceIntPoint(0, 0);
  1.3016 +        contextMenuEvent.time = aEvent->time;
  1.3017 +        contextMenuEvent.clickCount = 1;
  1.3018 +        KeymapWrapper::InitInputEvent(contextMenuEvent, aEvent->state);
  1.3019 +        DispatchEvent(&contextMenuEvent, status);
  1.3020 +    }
  1.3021 +    else {
  1.3022 +        // If the character code is in the BMP, send the key press event.
  1.3023 +        // Otherwise, send a text event with the equivalent UTF-16 string.
  1.3024 +        if (IS_IN_BMP(event.charCode)) {
  1.3025 +            DispatchEvent(&event, status);
  1.3026 +        }
  1.3027 +        else {
  1.3028 +            WidgetTextEvent textEvent(true, NS_TEXT_TEXT, this);
  1.3029 +            char16_t textString[3];
  1.3030 +            textString[0] = H_SURROGATE(event.charCode);
  1.3031 +            textString[1] = L_SURROGATE(event.charCode);
  1.3032 +            textString[2] = 0;
  1.3033 +            textEvent.theText = textString;
  1.3034 +            textEvent.time = event.time;
  1.3035 +            DispatchEvent(&textEvent, status);
  1.3036 +        }
  1.3037 +    }
  1.3038 +
  1.3039 +    // If the event was consumed, return.
  1.3040 +    if (status == nsEventStatus_eConsumeNoDefault) {
  1.3041 +        return TRUE;
  1.3042 +    }
  1.3043 +
  1.3044 +    return FALSE;
  1.3045 +}
  1.3046 +
  1.3047 +gboolean
  1.3048 +nsWindow::OnKeyReleaseEvent(GdkEventKey *aEvent)
  1.3049 +{
  1.3050 +    LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
  1.3051 +
  1.3052 +    if (mIMModule && mIMModule->OnKeyEvent(this, aEvent)) {
  1.3053 +        return TRUE;
  1.3054 +    }
  1.3055 +
  1.3056 +    // send the key event as a key up event
  1.3057 +    WidgetKeyboardEvent event(true, NS_KEY_UP, this);
  1.3058 +    KeymapWrapper::InitKeyEvent(event, aEvent);
  1.3059 +
  1.3060 +    nsEventStatus status;
  1.3061 +    DispatchEvent(&event, status);
  1.3062 +
  1.3063 +    // If the event was consumed, return.
  1.3064 +    if (status == nsEventStatus_eConsumeNoDefault) {
  1.3065 +        return TRUE;
  1.3066 +    }
  1.3067 +
  1.3068 +    return FALSE;
  1.3069 +}
  1.3070 +
  1.3071 +void
  1.3072 +nsWindow::OnScrollEvent(GdkEventScroll *aEvent)
  1.3073 +{
  1.3074 +    // check to see if we should rollup
  1.3075 +    if (CheckForRollup(aEvent->x_root, aEvent->y_root, true, false))
  1.3076 +        return;
  1.3077 +
  1.3078 +    WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this);
  1.3079 +    wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
  1.3080 +    switch (aEvent->direction) {
  1.3081 +    case GDK_SCROLL_UP:
  1.3082 +        wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = -3;
  1.3083 +        break;
  1.3084 +    case GDK_SCROLL_DOWN:
  1.3085 +        wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = 3;
  1.3086 +        break;
  1.3087 +    case GDK_SCROLL_LEFT:
  1.3088 +        wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = -1;
  1.3089 +        break;
  1.3090 +    case GDK_SCROLL_RIGHT:
  1.3091 +        wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = 1;
  1.3092 +        break;
  1.3093 +    }
  1.3094 +
  1.3095 +    NS_ASSERTION(wheelEvent.deltaX || wheelEvent.deltaY,
  1.3096 +                 "deltaX or deltaY must be non-zero");
  1.3097 +
  1.3098 +    if (aEvent->window == mGdkWindow) {
  1.3099 +        // we are the window that the event happened on so no need for expensive WidgetToScreenOffset
  1.3100 +        wheelEvent.refPoint.x = nscoord(aEvent->x);
  1.3101 +        wheelEvent.refPoint.y = nscoord(aEvent->y);
  1.3102 +    } else {
  1.3103 +        // XXX we're never quite sure which GdkWindow the event came from due to our custom bubbling
  1.3104 +        // in scroll_event_cb(), so use ScreenToWidget to translate the screen root coordinates into
  1.3105 +        // coordinates relative to this widget.
  1.3106 +        LayoutDeviceIntPoint point(NSToIntFloor(aEvent->x_root),
  1.3107 +                                   NSToIntFloor(aEvent->y_root));
  1.3108 +        wheelEvent.refPoint = point -
  1.3109 +            LayoutDeviceIntPoint::FromUntyped(WidgetToScreenOffset());
  1.3110 +    }
  1.3111 +
  1.3112 +    KeymapWrapper::InitInputEvent(wheelEvent, aEvent->state);
  1.3113 +
  1.3114 +    wheelEvent.time = aEvent->time;
  1.3115 +
  1.3116 +    nsEventStatus status;
  1.3117 +    DispatchEvent(&wheelEvent, status);
  1.3118 +}
  1.3119 +
  1.3120 +void
  1.3121 +nsWindow::OnVisibilityNotifyEvent(GdkEventVisibility *aEvent)
  1.3122 +{
  1.3123 +    LOGDRAW(("Visibility event %i on [%p] %p\n",
  1.3124 +             aEvent->state, this, aEvent->window));
  1.3125 +
  1.3126 +    if (!mGdkWindow)
  1.3127 +        return;
  1.3128 +
  1.3129 +    switch (aEvent->state) {
  1.3130 +    case GDK_VISIBILITY_UNOBSCURED:
  1.3131 +    case GDK_VISIBILITY_PARTIAL:
  1.3132 +        if (mIsFullyObscured && mHasMappedToplevel) {
  1.3133 +            // GDK_EXPOSE events have been ignored, so make sure GDK
  1.3134 +            // doesn't think that the window has already been painted.
  1.3135 +            gdk_window_invalidate_rect(mGdkWindow, nullptr, FALSE);
  1.3136 +        }
  1.3137 +
  1.3138 +        mIsFullyObscured = false;
  1.3139 +
  1.3140 +        if (!nsGtkIMModule::IsVirtualKeyboardOpened()) {
  1.3141 +            // if we have to retry the grab, retry it.
  1.3142 +            EnsureGrabs();
  1.3143 +        }
  1.3144 +        break;
  1.3145 +    default: // includes GDK_VISIBILITY_FULLY_OBSCURED
  1.3146 +        mIsFullyObscured = true;
  1.3147 +        break;
  1.3148 +    }
  1.3149 +}
  1.3150 +
  1.3151 +void
  1.3152 +nsWindow::OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent)
  1.3153 +{
  1.3154 +    LOG(("nsWindow::OnWindowStateEvent [%p] changed %d new_window_state %d\n",
  1.3155 +         (void *)this, aEvent->changed_mask, aEvent->new_window_state));
  1.3156 +
  1.3157 +    if (IS_MOZ_CONTAINER(aWidget)) {
  1.3158 +        // This event is notifying the container widget of changes to the
  1.3159 +        // toplevel window.  Just detect changes affecting whether windows are
  1.3160 +        // viewable.
  1.3161 +        //
  1.3162 +        // (A visibility notify event is sent to each window that becomes
  1.3163 +        // viewable when the toplevel is mapped, but we can't rely on that for
  1.3164 +        // setting mHasMappedToplevel because these toplevel window state
  1.3165 +        // events are asynchronous.  The windows in the hierarchy now may not
  1.3166 +        // be the same windows as when the toplevel was mapped, so they may
  1.3167 +        // not get VisibilityNotify events.)
  1.3168 +        bool mapped =
  1.3169 +            !(aEvent->new_window_state &
  1.3170 +              (GDK_WINDOW_STATE_ICONIFIED|GDK_WINDOW_STATE_WITHDRAWN));
  1.3171 +        if (mHasMappedToplevel != mapped) {
  1.3172 +            SetHasMappedToplevel(mapped);
  1.3173 +        }
  1.3174 +        return;
  1.3175 +    }
  1.3176 +    // else the widget is a shell widget.
  1.3177 +
  1.3178 +    // We don't care about anything but changes in the maximized/icon/fullscreen
  1.3179 +    // states
  1.3180 +    if ((aEvent->changed_mask
  1.3181 +         & (GDK_WINDOW_STATE_ICONIFIED |
  1.3182 +            GDK_WINDOW_STATE_MAXIMIZED |
  1.3183 +            GDK_WINDOW_STATE_FULLSCREEN)) == 0) {
  1.3184 +        return;
  1.3185 +    }
  1.3186 +
  1.3187 +    if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) {
  1.3188 +        LOG(("\tIconified\n"));
  1.3189 +        mSizeState = nsSizeMode_Minimized;
  1.3190 +#ifdef ACCESSIBILITY
  1.3191 +        DispatchMinimizeEventAccessible();
  1.3192 +#endif //ACCESSIBILITY
  1.3193 +    }
  1.3194 +    else if (aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
  1.3195 +        LOG(("\tFullscreen\n"));
  1.3196 +        mSizeState = nsSizeMode_Fullscreen;
  1.3197 +    }
  1.3198 +    else if (aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
  1.3199 +        LOG(("\tMaximized\n"));
  1.3200 +        mSizeState = nsSizeMode_Maximized;
  1.3201 +#ifdef ACCESSIBILITY
  1.3202 +        DispatchMaximizeEventAccessible();
  1.3203 +#endif //ACCESSIBILITY
  1.3204 +    }
  1.3205 +    else {
  1.3206 +        LOG(("\tNormal\n"));
  1.3207 +        mSizeState = nsSizeMode_Normal;
  1.3208 +#ifdef ACCESSIBILITY
  1.3209 +        DispatchRestoreEventAccessible();
  1.3210 +#endif //ACCESSIBILITY
  1.3211 +    }
  1.3212 +
  1.3213 +    if (mWidgetListener)
  1.3214 +      mWidgetListener->SizeModeChanged(mSizeState);
  1.3215 +}
  1.3216 +
  1.3217 +void
  1.3218 +nsWindow::ThemeChanged()
  1.3219 +{
  1.3220 +    NotifyThemeChanged();
  1.3221 +
  1.3222 +    if (!mGdkWindow || MOZ_UNLIKELY(mIsDestroyed))
  1.3223 +        return;
  1.3224 +
  1.3225 +    // Dispatch theme change notification to all child windows
  1.3226 +    GList *children =
  1.3227 +        gdk_window_peek_children(mGdkWindow);
  1.3228 +    while (children) {
  1.3229 +        GdkWindow *gdkWin = GDK_WINDOW(children->data);
  1.3230 +
  1.3231 +        nsWindow *win = (nsWindow*) g_object_get_data(G_OBJECT(gdkWin),
  1.3232 +                                                      "nsWindow");
  1.3233 +
  1.3234 +        if (win && win != this) { // guard against infinite recursion
  1.3235 +            nsRefPtr<nsWindow> kungFuDeathGrip = win;
  1.3236 +            win->ThemeChanged();
  1.3237 +        }
  1.3238 +
  1.3239 +        children = children->next;
  1.3240 +    }
  1.3241 +}
  1.3242 +
  1.3243 +void
  1.3244 +nsWindow::DispatchDragEvent(uint32_t aMsg, const nsIntPoint& aRefPoint,
  1.3245 +                            guint aTime)
  1.3246 +{
  1.3247 +    WidgetDragEvent event(true, aMsg, this);
  1.3248 +
  1.3249 +    if (aMsg == NS_DRAGDROP_OVER) {
  1.3250 +        InitDragEvent(event);
  1.3251 +    }
  1.3252 +
  1.3253 +    event.refPoint = LayoutDeviceIntPoint::FromUntyped(aRefPoint);
  1.3254 +    event.time = aTime;
  1.3255 +
  1.3256 +    nsEventStatus status;
  1.3257 +    DispatchEvent(&event, status);
  1.3258 +}
  1.3259 +
  1.3260 +void
  1.3261 +nsWindow::OnDragDataReceivedEvent(GtkWidget *aWidget,
  1.3262 +                                  GdkDragContext *aDragContext,
  1.3263 +                                  gint aX,
  1.3264 +                                  gint aY,
  1.3265 +                                  GtkSelectionData  *aSelectionData,
  1.3266 +                                  guint aInfo,
  1.3267 +                                  guint aTime,
  1.3268 +                                  gpointer aData)
  1.3269 +{
  1.3270 +    LOGDRAG(("nsWindow::OnDragDataReceived(%p)\n", (void*)this));
  1.3271 +
  1.3272 +    nsDragService::GetInstance()->
  1.3273 +        TargetDataReceived(aWidget, aDragContext, aX, aY,
  1.3274 +                           aSelectionData, aInfo, aTime);
  1.3275 +}
  1.3276 +
  1.3277 +static void
  1.3278 +GetBrandName(nsXPIDLString& brandName)
  1.3279 +{
  1.3280 +    nsCOMPtr<nsIStringBundleService> bundleService =
  1.3281 +        do_GetService(NS_STRINGBUNDLE_CONTRACTID);
  1.3282 +
  1.3283 +    nsCOMPtr<nsIStringBundle> bundle;
  1.3284 +    if (bundleService)
  1.3285 +        bundleService->CreateBundle(
  1.3286 +            "chrome://branding/locale/brand.properties",
  1.3287 +            getter_AddRefs(bundle));
  1.3288 +
  1.3289 +    if (bundle)
  1.3290 +        bundle->GetStringFromName(
  1.3291 +            MOZ_UTF16("brandShortName"),
  1.3292 +            getter_Copies(brandName));
  1.3293 +
  1.3294 +    if (brandName.IsEmpty())
  1.3295 +        brandName.Assign(NS_LITERAL_STRING("Mozilla"));
  1.3296 +}
  1.3297 +
  1.3298 +static GdkWindow *
  1.3299 +CreateGdkWindow(GdkWindow *parent, GtkWidget *widget)
  1.3300 +{
  1.3301 +    GdkWindowAttr attributes;
  1.3302 +    gint          attributes_mask = GDK_WA_VISUAL;
  1.3303 +
  1.3304 +    attributes.event_mask = kEvents;
  1.3305 +
  1.3306 +    attributes.width = 1;
  1.3307 +    attributes.height = 1;
  1.3308 +    attributes.wclass = GDK_INPUT_OUTPUT;
  1.3309 +    attributes.visual = gtk_widget_get_visual(widget);
  1.3310 +    attributes.window_type = GDK_WINDOW_CHILD;
  1.3311 +
  1.3312 +#if (MOZ_WIDGET_GTK == 2)
  1.3313 +    attributes_mask |= GDK_WA_COLORMAP;
  1.3314 +    attributes.colormap = gtk_widget_get_colormap(widget);
  1.3315 +#endif
  1.3316 +
  1.3317 +    GdkWindow *window = gdk_window_new(parent, &attributes, attributes_mask);
  1.3318 +    gdk_window_set_user_data(window, widget);
  1.3319 +
  1.3320 +// GTK3 TODO?
  1.3321 +#if (MOZ_WIDGET_GTK == 2)
  1.3322 +    /* set the default pixmap to None so that you don't end up with the
  1.3323 +       gtk default which is BlackPixel. */
  1.3324 +    gdk_window_set_back_pixmap(window, nullptr, FALSE);
  1.3325 +#endif
  1.3326 +
  1.3327 +    return window;
  1.3328 +}
  1.3329 +
  1.3330 +nsresult
  1.3331 +nsWindow::Create(nsIWidget        *aParent,
  1.3332 +                 nsNativeWidget    aNativeParent,
  1.3333 +                 const nsIntRect  &aRect,
  1.3334 +                 nsDeviceContext *aContext,
  1.3335 +                 nsWidgetInitData *aInitData)
  1.3336 +{
  1.3337 +    // only set the base parent if we're going to be a dialog or a
  1.3338 +    // toplevel
  1.3339 +    nsIWidget *baseParent = aInitData &&
  1.3340 +        (aInitData->mWindowType == eWindowType_dialog ||
  1.3341 +         aInitData->mWindowType == eWindowType_toplevel ||
  1.3342 +         aInitData->mWindowType == eWindowType_invisible) ?
  1.3343 +        nullptr : aParent;
  1.3344 +
  1.3345 +#ifdef ACCESSIBILITY
  1.3346 +    // Send a DBus message to check whether a11y is enabled
  1.3347 +    a11y::PreInit();
  1.3348 +#endif
  1.3349 +
  1.3350 +    // Ensure that the toolkit is created.
  1.3351 +    nsGTKToolkit::GetToolkit();
  1.3352 +
  1.3353 +    // initialize all the common bits of this class
  1.3354 +    BaseCreate(baseParent, aRect, aContext, aInitData);
  1.3355 +
  1.3356 +    // Do we need to listen for resizes?
  1.3357 +    bool listenForResizes = false;;
  1.3358 +    if (aNativeParent || (aInitData && aInitData->mListenForResizes))
  1.3359 +        listenForResizes = true;
  1.3360 +
  1.3361 +    // and do our common creation
  1.3362 +    CommonCreate(aParent, listenForResizes);
  1.3363 +
  1.3364 +    // save our bounds
  1.3365 +    mBounds = aRect;
  1.3366 +    ConstrainSize(&mBounds.width, &mBounds.height);
  1.3367 +
  1.3368 +    // figure out our parent window
  1.3369 +    GtkWidget      *parentMozContainer = nullptr;
  1.3370 +    GtkContainer   *parentGtkContainer = nullptr;
  1.3371 +    GdkWindow      *parentGdkWindow = nullptr;
  1.3372 +    GtkWindow      *topLevelParent = nullptr;
  1.3373 +    nsWindow       *parentnsWindow = nullptr;
  1.3374 +    GtkWidget      *eventWidget = nullptr;
  1.3375 +
  1.3376 +    if (aParent) {
  1.3377 +        parentnsWindow = static_cast<nsWindow*>(aParent);
  1.3378 +        parentGdkWindow = parentnsWindow->mGdkWindow;
  1.3379 +    } else if (aNativeParent && GDK_IS_WINDOW(aNativeParent)) {
  1.3380 +        parentGdkWindow = GDK_WINDOW(aNativeParent);
  1.3381 +        parentnsWindow = get_window_for_gdk_window(parentGdkWindow);
  1.3382 +        if (!parentnsWindow)
  1.3383 +            return NS_ERROR_FAILURE;
  1.3384 +
  1.3385 +    } else if (aNativeParent && GTK_IS_CONTAINER(aNativeParent)) {
  1.3386 +        parentGtkContainer = GTK_CONTAINER(aNativeParent);
  1.3387 +    }
  1.3388 +
  1.3389 +    if (parentGdkWindow) {
  1.3390 +        // get the widget for the window - it should be a moz container
  1.3391 +        parentMozContainer = parentnsWindow->GetMozContainerWidget();
  1.3392 +        if (!parentMozContainer)
  1.3393 +            return NS_ERROR_FAILURE;
  1.3394 +
  1.3395 +        // get the toplevel window just in case someone needs to use it
  1.3396 +        // for setting transients or whatever.
  1.3397 +        topLevelParent =
  1.3398 +            GTK_WINDOW(gtk_widget_get_toplevel(parentMozContainer));
  1.3399 +    }
  1.3400 +
  1.3401 +    // ok, create our windows
  1.3402 +    switch (mWindowType) {
  1.3403 +    case eWindowType_dialog:
  1.3404 +    case eWindowType_popup:
  1.3405 +    case eWindowType_toplevel:
  1.3406 +    case eWindowType_invisible: {
  1.3407 +        mIsTopLevel = true;
  1.3408 +
  1.3409 +        // We only move a general managed toplevel window if someone has
  1.3410 +        // actually placed the window somewhere.  If no placement has taken
  1.3411 +        // place, we just let the window manager Do The Right Thing.
  1.3412 +        //
  1.3413 +        // Indicate that if we're shown, we at least need to have our size set.
  1.3414 +        // If we get explicitly moved, the position will also be set.
  1.3415 +        mNeedsResize = true;
  1.3416 +
  1.3417 +        if (mWindowType == eWindowType_dialog) {
  1.3418 +            mShell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  1.3419 +            SetDefaultIcon();
  1.3420 +            gtk_window_set_wmclass(GTK_WINDOW(mShell), "Dialog", 
  1.3421 +                                   gdk_get_program_class());
  1.3422 +            gtk_window_set_type_hint(GTK_WINDOW(mShell),
  1.3423 +                                     GDK_WINDOW_TYPE_HINT_DIALOG);
  1.3424 +            gtk_window_set_transient_for(GTK_WINDOW(mShell),
  1.3425 +                                         topLevelParent);
  1.3426 +        }
  1.3427 +        else if (mWindowType == eWindowType_popup) {
  1.3428 +            // With popup windows, we want to control their position, so don't
  1.3429 +            // wait for the window manager to place them (which wouldn't
  1.3430 +            // happen with override-redirect windows anyway).
  1.3431 +            mNeedsMove = true;
  1.3432 +
  1.3433 +            // Popups that are not noautohide are only temporary. The are used
  1.3434 +            // for menus and the like and disappear when another window is used.
  1.3435 +            // For most popups, use the standard GtkWindowType GTK_WINDOW_POPUP,
  1.3436 +            // which will use a Window with the override-redirect attribute
  1.3437 +            // (for temporary windows).
  1.3438 +            // For long-lived windows, their stacking order is managed by the
  1.3439 +            // window manager, as indicated by GTK_WINDOW_TOPLEVEL ...
  1.3440 +            GtkWindowType type = aInitData->mNoAutoHide ?
  1.3441 +                                     GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP;
  1.3442 +            mShell = gtk_window_new(type);
  1.3443 +            gtk_window_set_wmclass(GTK_WINDOW(mShell), "Popup",
  1.3444 +                                   gdk_get_program_class());
  1.3445 +
  1.3446 +            if (aInitData->mSupportTranslucency) {
  1.3447 +                // We need to select an ARGB visual here instead of in
  1.3448 +                // SetTransparencyMode() because it has to be done before the
  1.3449 +                // widget is realized.  An ARGB visual is only useful if we
  1.3450 +                // are on a compositing window manager.
  1.3451 +                GdkScreen *screen = gtk_widget_get_screen(mShell);
  1.3452 +                if (gdk_screen_is_composited(screen)) {
  1.3453 +#if (MOZ_WIDGET_GTK == 2)
  1.3454 +                    GdkColormap *colormap =
  1.3455 +                        gdk_screen_get_rgba_colormap(screen);
  1.3456 +                    gtk_widget_set_colormap(mShell, colormap);
  1.3457 +#else
  1.3458 +                    GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
  1.3459 +                    gtk_widget_set_visual(mShell, visual);
  1.3460 +#endif
  1.3461 +                }
  1.3462 +            }
  1.3463 +            if (aInitData->mNoAutoHide) {
  1.3464 +                // ... but the window manager does not decorate this window,
  1.3465 +                // nor provide a separate taskbar icon.
  1.3466 +                if (mBorderStyle == eBorderStyle_default) {
  1.3467 +                  gtk_window_set_decorated(GTK_WINDOW(mShell), FALSE);
  1.3468 +                }
  1.3469 +                else {
  1.3470 +                  bool decorate = mBorderStyle & eBorderStyle_title;
  1.3471 +                  gtk_window_set_decorated(GTK_WINDOW(mShell), decorate);
  1.3472 +                  if (decorate) {
  1.3473 +                    gtk_window_set_deletable(GTK_WINDOW(mShell), mBorderStyle & eBorderStyle_close);
  1.3474 +                  }
  1.3475 +                }
  1.3476 +                gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell), TRUE);
  1.3477 +                // Element focus is managed by the parent window so the
  1.3478 +                // WM_HINTS input field is set to False to tell the window
  1.3479 +                // manager not to set input focus to this window ...
  1.3480 +                gtk_window_set_accept_focus(GTK_WINDOW(mShell), FALSE);
  1.3481 +#ifdef MOZ_X11
  1.3482 +                // ... but when the window manager offers focus through
  1.3483 +                // WM_TAKE_FOCUS, focus is requested on the parent window.
  1.3484 +                gtk_widget_realize(mShell);
  1.3485 +                gdk_window_add_filter(gtk_widget_get_window(mShell),
  1.3486 +                                      popup_take_focus_filter, nullptr); 
  1.3487 +#endif
  1.3488 +            }
  1.3489 +
  1.3490 +            GdkWindowTypeHint gtkTypeHint;
  1.3491 +            if (aInitData->mIsDragPopup) {
  1.3492 +                gtkTypeHint = GDK_WINDOW_TYPE_HINT_DND;
  1.3493 +            }
  1.3494 +            else {
  1.3495 +                switch (aInitData->mPopupHint) {
  1.3496 +                    case ePopupTypeMenu:
  1.3497 +                        gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
  1.3498 +                        break;
  1.3499 +                    case ePopupTypeTooltip:
  1.3500 +                        gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
  1.3501 +                        break;
  1.3502 +                    default:
  1.3503 +                        gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
  1.3504 +                        break;
  1.3505 +                }
  1.3506 +            }
  1.3507 +            gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint);
  1.3508 +
  1.3509 +            if (topLevelParent) {
  1.3510 +                gtk_window_set_transient_for(GTK_WINDOW(mShell),
  1.3511 +                                            topLevelParent);
  1.3512 +            }
  1.3513 +        }
  1.3514 +        else { // must be eWindowType_toplevel
  1.3515 +            mShell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  1.3516 +            SetDefaultIcon();
  1.3517 +            gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel", 
  1.3518 +                                   gdk_get_program_class());
  1.3519 +
  1.3520 +            // each toplevel window gets its own window group
  1.3521 +            GtkWindowGroup *group = gtk_window_group_new();
  1.3522 +            gtk_window_group_add_window(group, GTK_WINDOW(mShell));
  1.3523 +            g_object_unref(group);
  1.3524 +        }
  1.3525 +
  1.3526 +        // Prevent GtkWindow from painting a background to flicker.
  1.3527 +        gtk_widget_set_app_paintable(mShell, TRUE);
  1.3528 +
  1.3529 +        // Create a container to hold child windows and child GtkWidgets.
  1.3530 +        GtkWidget *container = moz_container_new();
  1.3531 +        mContainer = MOZ_CONTAINER(container);
  1.3532 +        // Use mShell's window for drawing and events.
  1.3533 +        gtk_widget_set_has_window(container, FALSE);
  1.3534 +        eventWidget = mShell;
  1.3535 +        gtk_widget_add_events(eventWidget, kEvents);
  1.3536 +        gtk_container_add(GTK_CONTAINER(mShell), container);
  1.3537 +        gtk_widget_realize(container);
  1.3538 +
  1.3539 +        // make sure this is the focus widget in the container
  1.3540 +        gtk_widget_show(container);
  1.3541 +        gtk_widget_grab_focus(container);
  1.3542 +
  1.3543 +        // the drawing window
  1.3544 +        mGdkWindow = gtk_widget_get_window(mShell);
  1.3545 +
  1.3546 +        if (mWindowType == eWindowType_popup) {
  1.3547 +            // gdk does not automatically set the cursor for "temporary"
  1.3548 +            // windows, which are what gtk uses for popups.
  1.3549 +
  1.3550 +            mCursor = eCursor_wait; // force SetCursor to actually set the
  1.3551 +                                    // cursor, even though our internal state
  1.3552 +                                    // indicates that we already have the
  1.3553 +                                    // standard cursor.
  1.3554 +            SetCursor(eCursor_standard);
  1.3555 +
  1.3556 +            if (aInitData->mNoAutoHide) {
  1.3557 +                gint wmd = ConvertBorderStyles(mBorderStyle);
  1.3558 +                if (wmd != -1)
  1.3559 +                  gdk_window_set_decorations(gtk_widget_get_window(mShell), (GdkWMDecoration) wmd);
  1.3560 +            }
  1.3561 +
  1.3562 +            // If the popup ignores mouse events, set an empty input shape.
  1.3563 +            if (aInitData->mMouseTransparent) {
  1.3564 +#if (MOZ_WIDGET_GTK == 2)
  1.3565 +              GdkRectangle rect = { 0, 0, 0, 0 };
  1.3566 +              GdkRegion *region = gdk_region_rectangle(&rect);
  1.3567 +
  1.3568 +              gdk_window_input_shape_combine_region(mGdkWindow, region, 0, 0);
  1.3569 +              gdk_region_destroy(region);
  1.3570 +#else
  1.3571 +              cairo_rectangle_int_t rect = { 0, 0, 0, 0 };
  1.3572 +              cairo_region_t *region = cairo_region_create_rectangle(&rect);
  1.3573 +
  1.3574 +              gdk_window_input_shape_combine_region(mGdkWindow, region, 0, 0);
  1.3575 +              cairo_region_destroy(region);
  1.3576 +#endif
  1.3577 +            }
  1.3578 +        }
  1.3579 +    }
  1.3580 +        break;
  1.3581 +    case eWindowType_plugin:
  1.3582 +    case eWindowType_child: {
  1.3583 +        if (parentMozContainer) {
  1.3584 +            mGdkWindow = CreateGdkWindow(parentGdkWindow, parentMozContainer);
  1.3585 +            mHasMappedToplevel = parentnsWindow->mHasMappedToplevel;
  1.3586 +        }
  1.3587 +        else if (parentGtkContainer) {
  1.3588 +            // This MozContainer has its own window for drawing and receives
  1.3589 +            // events because there is no mShell widget (corresponding to this
  1.3590 +            // nsWindow).
  1.3591 +            GtkWidget *container = moz_container_new();
  1.3592 +            mContainer = MOZ_CONTAINER(container);
  1.3593 +            eventWidget = container;
  1.3594 +            gtk_widget_add_events(eventWidget, kEvents);
  1.3595 +            gtk_container_add(parentGtkContainer, container);
  1.3596 +            gtk_widget_realize(container);
  1.3597 +
  1.3598 +            mGdkWindow = gtk_widget_get_window(container);
  1.3599 +        }
  1.3600 +        else {
  1.3601 +            NS_WARNING("Warning: tried to create a new child widget with no parent!");
  1.3602 +            return NS_ERROR_FAILURE;
  1.3603 +        }
  1.3604 +    }
  1.3605 +        break;
  1.3606 +    default:
  1.3607 +        break;
  1.3608 +    }
  1.3609 +
  1.3610 +    // label the drawing window with this object so we can find our way home
  1.3611 +    g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this);
  1.3612 +
  1.3613 +    if (mContainer)
  1.3614 +        g_object_set_data(G_OBJECT(mContainer), "nsWindow", this);
  1.3615 +
  1.3616 +    if (mShell)
  1.3617 +        g_object_set_data(G_OBJECT(mShell), "nsWindow", this);
  1.3618 +
  1.3619 +    // attach listeners for events
  1.3620 +    if (mShell) {
  1.3621 +        g_signal_connect(mShell, "configure_event",
  1.3622 +                         G_CALLBACK(configure_event_cb), nullptr);
  1.3623 +        g_signal_connect(mShell, "delete_event",
  1.3624 +                         G_CALLBACK(delete_event_cb), nullptr);
  1.3625 +        g_signal_connect(mShell, "window_state_event",
  1.3626 +                         G_CALLBACK(window_state_event_cb), nullptr);
  1.3627 +
  1.3628 +        GtkSettings* default_settings = gtk_settings_get_default();
  1.3629 +        g_signal_connect_after(default_settings,
  1.3630 +                               "notify::gtk-theme-name",
  1.3631 +                               G_CALLBACK(theme_changed_cb), this);
  1.3632 +        g_signal_connect_after(default_settings,
  1.3633 +                               "notify::gtk-font-name",
  1.3634 +                               G_CALLBACK(theme_changed_cb), this);
  1.3635 +    }
  1.3636 +
  1.3637 +    if (mContainer) {
  1.3638 +        // Widget signals
  1.3639 +        g_signal_connect(mContainer, "unrealize",
  1.3640 +                         G_CALLBACK(container_unrealize_cb), nullptr);
  1.3641 +        g_signal_connect_after(mContainer, "size_allocate",
  1.3642 +                               G_CALLBACK(size_allocate_cb), nullptr);
  1.3643 +        g_signal_connect(mContainer, "hierarchy-changed",
  1.3644 +                         G_CALLBACK(hierarchy_changed_cb), nullptr);
  1.3645 +        // Initialize mHasMappedToplevel.
  1.3646 +        hierarchy_changed_cb(GTK_WIDGET(mContainer), nullptr);
  1.3647 +        // Expose, focus, key, and drag events are sent even to GTK_NO_WINDOW
  1.3648 +        // widgets.
  1.3649 +#if (MOZ_WIDGET_GTK == 2)
  1.3650 +        g_signal_connect(mContainer, "expose_event",
  1.3651 +                         G_CALLBACK(expose_event_cb), nullptr);
  1.3652 +#else
  1.3653 +        g_signal_connect(G_OBJECT(mContainer), "draw",
  1.3654 +                         G_CALLBACK(expose_event_cb), nullptr);
  1.3655 +#endif
  1.3656 +        g_signal_connect(mContainer, "focus_in_event",
  1.3657 +                         G_CALLBACK(focus_in_event_cb), nullptr);
  1.3658 +        g_signal_connect(mContainer, "focus_out_event",
  1.3659 +                         G_CALLBACK(focus_out_event_cb), nullptr);
  1.3660 +        g_signal_connect(mContainer, "key_press_event",
  1.3661 +                         G_CALLBACK(key_press_event_cb), nullptr);
  1.3662 +        g_signal_connect(mContainer, "key_release_event",
  1.3663 +                         G_CALLBACK(key_release_event_cb), nullptr);
  1.3664 +
  1.3665 +        gtk_drag_dest_set((GtkWidget *)mContainer,
  1.3666 +                          (GtkDestDefaults)0,
  1.3667 +                          nullptr,
  1.3668 +                          0,
  1.3669 +                          (GdkDragAction)0);
  1.3670 +
  1.3671 +        g_signal_connect(mContainer, "drag_motion",
  1.3672 +                         G_CALLBACK(drag_motion_event_cb), nullptr);
  1.3673 +        g_signal_connect(mContainer, "drag_leave",
  1.3674 +                         G_CALLBACK(drag_leave_event_cb), nullptr);
  1.3675 +        g_signal_connect(mContainer, "drag_drop",
  1.3676 +                         G_CALLBACK(drag_drop_event_cb), nullptr);
  1.3677 +        g_signal_connect(mContainer, "drag_data_received",
  1.3678 +                         G_CALLBACK(drag_data_received_event_cb), nullptr);
  1.3679 +
  1.3680 +        GtkWidget *widgets[] = { GTK_WIDGET(mContainer), mShell };
  1.3681 +        for (size_t i = 0; i < ArrayLength(widgets) && widgets[i]; ++i) {
  1.3682 +            // Visibility events are sent to the owning widget of the relevant
  1.3683 +            // window but do not propagate to parent widgets so connect on
  1.3684 +            // mShell (if it exists) as well as mContainer.
  1.3685 +            g_signal_connect(widgets[i], "visibility-notify-event",
  1.3686 +                             G_CALLBACK(visibility_notify_event_cb), nullptr);
  1.3687 +            // Similarly double buffering is controlled by the window's owning
  1.3688 +            // widget.  Disable double buffering for painting directly to the
  1.3689 +            // X Window.
  1.3690 +            gtk_widget_set_double_buffered(widgets[i], FALSE);
  1.3691 +        }
  1.3692 +
  1.3693 +        // We create input contexts for all containers, except for
  1.3694 +        // toplevel popup windows
  1.3695 +        if (mWindowType != eWindowType_popup) {
  1.3696 +            mIMModule = new nsGtkIMModule(this);
  1.3697 +        }
  1.3698 +    } else if (!mIMModule) {
  1.3699 +        nsWindow *container = GetContainerWindow();
  1.3700 +        if (container) {
  1.3701 +            mIMModule = container->mIMModule;
  1.3702 +        }
  1.3703 +    }
  1.3704 +
  1.3705 +    if (eventWidget) {
  1.3706 +#if (MOZ_WIDGET_GTK == 2)
  1.3707 +        // Don't let GTK mess with the shapes of our GdkWindows
  1.3708 +        GTK_PRIVATE_SET_FLAG(eventWidget, GTK_HAS_SHAPE_MASK);
  1.3709 +#endif
  1.3710 +
  1.3711 +        // These events are sent to the owning widget of the relevant window
  1.3712 +        // and propagate up to the first widget that handles the events, so we
  1.3713 +        // need only connect on mShell, if it exists, to catch events on its
  1.3714 +        // window and windows of mContainer.
  1.3715 +        g_signal_connect(eventWidget, "enter-notify-event",
  1.3716 +                         G_CALLBACK(enter_notify_event_cb), nullptr);
  1.3717 +        g_signal_connect(eventWidget, "leave-notify-event",
  1.3718 +                         G_CALLBACK(leave_notify_event_cb), nullptr);
  1.3719 +        g_signal_connect(eventWidget, "motion-notify-event",
  1.3720 +                         G_CALLBACK(motion_notify_event_cb), nullptr);
  1.3721 +        g_signal_connect(eventWidget, "button-press-event",
  1.3722 +                         G_CALLBACK(button_press_event_cb), nullptr);
  1.3723 +        g_signal_connect(eventWidget, "button-release-event",
  1.3724 +                         G_CALLBACK(button_release_event_cb), nullptr);
  1.3725 +        g_signal_connect(eventWidget, "scroll-event",
  1.3726 +                         G_CALLBACK(scroll_event_cb), nullptr);
  1.3727 +    }
  1.3728 +
  1.3729 +    LOG(("nsWindow [%p]\n", (void *)this));
  1.3730 +    if (mShell) {
  1.3731 +        LOG(("\tmShell %p mContainer %p mGdkWindow %p 0x%lx\n",
  1.3732 +             mShell, mContainer, mGdkWindow,
  1.3733 +             gdk_x11_window_get_xid(mGdkWindow)));
  1.3734 +    } else if (mContainer) {
  1.3735 +        LOG(("\tmContainer %p mGdkWindow %p\n", mContainer, mGdkWindow));
  1.3736 +    }
  1.3737 +    else if (mGdkWindow) {
  1.3738 +        LOG(("\tmGdkWindow %p parent %p\n",
  1.3739 +             mGdkWindow, gdk_window_get_parent(mGdkWindow)));
  1.3740 +    }
  1.3741 +
  1.3742 +    // resize so that everything is set to the right dimensions
  1.3743 +    if (!mIsTopLevel)
  1.3744 +        Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
  1.3745 +
  1.3746 +    return NS_OK;
  1.3747 +}
  1.3748 +
  1.3749 +NS_IMETHODIMP
  1.3750 +nsWindow::SetWindowClass(const nsAString &xulWinType)
  1.3751 +{
  1.3752 +  if (!mShell)
  1.3753 +    return NS_ERROR_FAILURE;
  1.3754 +
  1.3755 +  const char *res_class = gdk_get_program_class();
  1.3756 +  if (!res_class)
  1.3757 +    return NS_ERROR_FAILURE;
  1.3758 +  
  1.3759 +  char *res_name = ToNewCString(xulWinType);
  1.3760 +  if (!res_name)
  1.3761 +    return NS_ERROR_OUT_OF_MEMORY;
  1.3762 +
  1.3763 +  const char *role = nullptr;
  1.3764 +
  1.3765 +  // Parse res_name into a name and role. Characters other than
  1.3766 +  // [A-Za-z0-9_-] are converted to '_'. Anything after the first
  1.3767 +  // colon is assigned to role; if there's no colon, assign the
  1.3768 +  // whole thing to both role and res_name.
  1.3769 +  for (char *c = res_name; *c; c++) {
  1.3770 +    if (':' == *c) {
  1.3771 +      *c = 0;
  1.3772 +      role = c + 1;
  1.3773 +    }
  1.3774 +    else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
  1.3775 +      *c = '_';
  1.3776 +  }
  1.3777 +  res_name[0] = toupper(res_name[0]);
  1.3778 +  if (!role) role = res_name;
  1.3779 +
  1.3780 +  GdkWindow *shellWindow = gtk_widget_get_window(GTK_WIDGET(mShell));
  1.3781 +  gdk_window_set_role(shellWindow, role);
  1.3782 +
  1.3783 +#ifdef MOZ_X11
  1.3784 +  XClassHint *class_hint = XAllocClassHint();
  1.3785 +  if (!class_hint) {
  1.3786 +    nsMemory::Free(res_name);
  1.3787 +    return NS_ERROR_OUT_OF_MEMORY;
  1.3788 +  }
  1.3789 +  class_hint->res_name = res_name;
  1.3790 +  class_hint->res_class = const_cast<char*>(res_class);
  1.3791 +
  1.3792 +  // Can't use gtk_window_set_wmclass() for this; it prints
  1.3793 +  // a warning & refuses to make the change.
  1.3794 +  XSetClassHint(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
  1.3795 +                gdk_x11_window_get_xid(shellWindow),
  1.3796 +                class_hint);
  1.3797 +  XFree(class_hint);
  1.3798 +#endif /* MOZ_X11 */
  1.3799 +
  1.3800 +  nsMemory::Free(res_name);
  1.3801 +
  1.3802 +  return NS_OK;
  1.3803 +}
  1.3804 +
  1.3805 +void
  1.3806 +nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool    aRepaint)
  1.3807 +{
  1.3808 +    LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
  1.3809 +         aWidth, aHeight));
  1.3810 +
  1.3811 +    // clear our resize flag
  1.3812 +    mNeedsResize = false;
  1.3813 +
  1.3814 +    if (mIsTopLevel) {
  1.3815 +        gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
  1.3816 +    }
  1.3817 +    else if (mContainer) {
  1.3818 +        GtkWidget *widget = GTK_WIDGET(mContainer);
  1.3819 +        GtkAllocation allocation, prev_allocation;
  1.3820 +        gtk_widget_get_allocation(widget, &prev_allocation);
  1.3821 +        allocation.x = prev_allocation.x;
  1.3822 +        allocation.y = prev_allocation.y;
  1.3823 +        allocation.width = aWidth;
  1.3824 +        allocation.height = aHeight;
  1.3825 +        gtk_widget_size_allocate(widget, &allocation);
  1.3826 +    }
  1.3827 +    else if (mGdkWindow) {
  1.3828 +        gdk_window_resize(mGdkWindow, aWidth, aHeight);
  1.3829 +    }
  1.3830 +}
  1.3831 +
  1.3832 +void
  1.3833 +nsWindow::NativeResize(int32_t aX, int32_t aY,
  1.3834 +                       int32_t aWidth, int32_t aHeight,
  1.3835 +                       bool    aRepaint)
  1.3836 +{
  1.3837 +    mNeedsResize = false;
  1.3838 +    mNeedsMove = false;
  1.3839 +
  1.3840 +    LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
  1.3841 +         aX, aY, aWidth, aHeight));
  1.3842 +
  1.3843 +    if (mIsTopLevel) {
  1.3844 +        // aX and aY give the position of the window manager frame top-left.
  1.3845 +        gtk_window_move(GTK_WINDOW(mShell), aX, aY);
  1.3846 +        // This sets the client window size.
  1.3847 +        gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
  1.3848 +    }
  1.3849 +    else if (mContainer) {
  1.3850 +        GtkAllocation allocation;
  1.3851 +        allocation.x = aX;
  1.3852 +        allocation.y = aY;
  1.3853 +        allocation.width = aWidth;
  1.3854 +        allocation.height = aHeight;
  1.3855 +        gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
  1.3856 +    }
  1.3857 +    else if (mGdkWindow) {
  1.3858 +        gdk_window_move_resize(mGdkWindow, aX, aY, aWidth, aHeight);
  1.3859 +    }
  1.3860 +}
  1.3861 +
  1.3862 +void
  1.3863 +nsWindow::NativeShow(bool aAction)
  1.3864 +{
  1.3865 +    if (aAction) {
  1.3866 +        // unset our flag now that our window has been shown
  1.3867 +        mNeedsShow = false;
  1.3868 +
  1.3869 +        if (mIsTopLevel) {
  1.3870 +            // Set up usertime/startupID metadata for the created window.
  1.3871 +            if (mWindowType != eWindowType_invisible) {
  1.3872 +                SetUserTimeAndStartupIDForActivatedWindow(mShell);
  1.3873 +            }
  1.3874 +
  1.3875 +            gtk_widget_show(mShell);
  1.3876 +        }
  1.3877 +        else if (mContainer) {
  1.3878 +            gtk_widget_show(GTK_WIDGET(mContainer));
  1.3879 +        }
  1.3880 +        else if (mGdkWindow) {
  1.3881 +            gdk_window_show_unraised(mGdkWindow);
  1.3882 +        }
  1.3883 +    }
  1.3884 +    else {
  1.3885 +        if (mIsTopLevel) {
  1.3886 +            gtk_widget_hide(GTK_WIDGET(mShell));
  1.3887 +
  1.3888 +            ClearTransparencyBitmap(); // Release some resources
  1.3889 +        }
  1.3890 +        else if (mContainer) {
  1.3891 +            gtk_widget_hide(GTK_WIDGET(mContainer));
  1.3892 +        }
  1.3893 +        else if (mGdkWindow) {
  1.3894 +            gdk_window_hide(mGdkWindow);
  1.3895 +        }
  1.3896 +    }
  1.3897 +}
  1.3898 +
  1.3899 +void
  1.3900 +nsWindow::SetHasMappedToplevel(bool aState)
  1.3901 +{
  1.3902 +    // Even when aState == mHasMappedToplevel (as when this method is called
  1.3903 +    // from Show()), child windows need to have their state checked, so don't
  1.3904 +    // return early.
  1.3905 +    bool oldState = mHasMappedToplevel;
  1.3906 +    mHasMappedToplevel = aState;
  1.3907 +
  1.3908 +    // mHasMappedToplevel is not updated for children of windows that are
  1.3909 +    // hidden; GDK knows not to send expose events for these windows.  The
  1.3910 +    // state is recorded on the hidden window itself, but, for child trees of
  1.3911 +    // hidden windows, their state essentially becomes disconnected from their
  1.3912 +    // hidden parent.  When the hidden parent gets shown, the child trees are
  1.3913 +    // reconnected, and the state of the window being shown can be easily
  1.3914 +    // propagated.
  1.3915 +    if (!mIsShown || !mGdkWindow)
  1.3916 +        return;
  1.3917 +
  1.3918 +    if (aState && !oldState && !mIsFullyObscured) {
  1.3919 +        // GDK_EXPOSE events have been ignored but the window is now visible,
  1.3920 +        // so make sure GDK doesn't think that the window has already been
  1.3921 +        // painted.
  1.3922 +        gdk_window_invalidate_rect(mGdkWindow, nullptr, FALSE);
  1.3923 +
  1.3924 +        // Check that a grab didn't fail due to the window not being
  1.3925 +        // viewable.
  1.3926 +        EnsureGrabs();
  1.3927 +    }
  1.3928 +
  1.3929 +    for (GList *children = gdk_window_peek_children(mGdkWindow);
  1.3930 +         children;
  1.3931 +         children = children->next) {
  1.3932 +        GdkWindow *gdkWin = GDK_WINDOW(children->data);
  1.3933 +        nsWindow *child = get_window_for_gdk_window(gdkWin);
  1.3934 +
  1.3935 +        if (child && child->mHasMappedToplevel != aState) {
  1.3936 +            child->SetHasMappedToplevel(aState);
  1.3937 +        }
  1.3938 +    }
  1.3939 +}
  1.3940 +
  1.3941 +nsIntSize
  1.3942 +nsWindow::GetSafeWindowSize(nsIntSize aSize)
  1.3943 +{
  1.3944 +    // The X protocol uses CARD32 for window sizes, but the server (1.11.3)
  1.3945 +    // reads it as CARD16.  Sizes of pixmaps, used for drawing, are (unsigned)
  1.3946 +    // CARD16 in the protocol, but the server's ProcCreatePixmap returns
  1.3947 +    // BadAlloc if dimensions cannot be represented by signed shorts.
  1.3948 +    nsIntSize result = aSize;
  1.3949 +    const int32_t kInt16Max = 32767;
  1.3950 +    if (result.width > kInt16Max) {
  1.3951 +        result.width = kInt16Max;
  1.3952 +    }
  1.3953 +    if (result.height > kInt16Max) {
  1.3954 +        result.height = kInt16Max;
  1.3955 +    }
  1.3956 +    return result;
  1.3957 +}
  1.3958 +
  1.3959 +void
  1.3960 +nsWindow::EnsureGrabs(void)
  1.3961 +{
  1.3962 +    if (mRetryPointerGrab)
  1.3963 +        GrabPointer(sRetryGrabTime);
  1.3964 +}
  1.3965 +
  1.3966 +void
  1.3967 +nsWindow::CleanLayerManagerRecursive(void) {
  1.3968 +    if (mLayerManager) {
  1.3969 +        mLayerManager->Destroy();
  1.3970 +        mLayerManager = nullptr;
  1.3971 +    }
  1.3972 +
  1.3973 +    DestroyCompositor();
  1.3974 +
  1.3975 +    GList* children = gdk_window_peek_children(mGdkWindow);
  1.3976 +    for (GList* list = children; list; list = list->next) {
  1.3977 +        nsWindow* window = get_window_for_gdk_window(GDK_WINDOW(list->data));
  1.3978 +        if (window) {
  1.3979 +            window->CleanLayerManagerRecursive();
  1.3980 +        }
  1.3981 +    }
  1.3982 +}
  1.3983 +
  1.3984 +void
  1.3985 +nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
  1.3986 +{
  1.3987 +    if (!mShell) {
  1.3988 +        // Pass the request to the toplevel window
  1.3989 +        GtkWidget *topWidget = GetToplevelWidget();
  1.3990 +        if (!topWidget)
  1.3991 +            return;
  1.3992 +
  1.3993 +        nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
  1.3994 +        if (!topWindow)
  1.3995 +            return;
  1.3996 +
  1.3997 +        topWindow->SetTransparencyMode(aMode);
  1.3998 +        return;
  1.3999 +    }
  1.4000 +    bool isTransparent = aMode == eTransparencyTransparent;
  1.4001 +
  1.4002 +    if (mIsTransparent == isTransparent)
  1.4003 +        return;
  1.4004 +
  1.4005 +    if (!isTransparent) {
  1.4006 +        ClearTransparencyBitmap();
  1.4007 +    } // else the new default alpha values are "all 1", so we don't
  1.4008 +    // need to change anything yet
  1.4009 +
  1.4010 +    mIsTransparent = isTransparent;
  1.4011 +
  1.4012 +    // Need to clean our LayerManager up while still alive because
  1.4013 +    // we don't want to use layers acceleration on shaped windows
  1.4014 +    CleanLayerManagerRecursive();
  1.4015 +}
  1.4016 +
  1.4017 +nsTransparencyMode
  1.4018 +nsWindow::GetTransparencyMode()
  1.4019 +{
  1.4020 +    if (!mShell) {
  1.4021 +        // Pass the request to the toplevel window
  1.4022 +        GtkWidget *topWidget = GetToplevelWidget();
  1.4023 +        if (!topWidget) {
  1.4024 +            return eTransparencyOpaque;
  1.4025 +        }
  1.4026 +
  1.4027 +        nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
  1.4028 +        if (!topWindow) {
  1.4029 +            return eTransparencyOpaque;
  1.4030 +        }
  1.4031 +
  1.4032 +        return topWindow->GetTransparencyMode();
  1.4033 +    }
  1.4034 +
  1.4035 +    return mIsTransparent ? eTransparencyTransparent : eTransparencyOpaque;
  1.4036 +}
  1.4037 +
  1.4038 +nsresult
  1.4039 +nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
  1.4040 +{
  1.4041 +    for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
  1.4042 +        const Configuration& configuration = aConfigurations[i];
  1.4043 +        nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
  1.4044 +        NS_ASSERTION(w->GetParent() == this,
  1.4045 +                     "Configured widget is not a child");
  1.4046 +        w->SetWindowClipRegion(configuration.mClipRegion, true);
  1.4047 +        if (w->mBounds.Size() != configuration.mBounds.Size()) {
  1.4048 +            w->Resize(configuration.mBounds.x, configuration.mBounds.y,
  1.4049 +                      configuration.mBounds.width, configuration.mBounds.height,
  1.4050 +                      true);
  1.4051 +        } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
  1.4052 +            w->Move(configuration.mBounds.x, configuration.mBounds.y);
  1.4053 +        } 
  1.4054 +        w->SetWindowClipRegion(configuration.mClipRegion, false);
  1.4055 +    }
  1.4056 +    return NS_OK;
  1.4057 +}
  1.4058 +
  1.4059 +static pixman_box32
  1.4060 +ToPixmanBox(const nsIntRect& aRect)
  1.4061 +{
  1.4062 +    pixman_box32_t result;
  1.4063 +    result.x1 = aRect.x;
  1.4064 +    result.y1 = aRect.y;
  1.4065 +    result.x2 = aRect.XMost();
  1.4066 +    result.y2 = aRect.YMost();
  1.4067 +    return result;
  1.4068 +}
  1.4069 +
  1.4070 +static nsIntRect
  1.4071 +ToIntRect(const pixman_box32& aBox)
  1.4072 +{
  1.4073 +    nsIntRect result;
  1.4074 +    result.x = aBox.x1;
  1.4075 +    result.y = aBox.y1;
  1.4076 +    result.width = aBox.x2 - aBox.x1;
  1.4077 +    result.height = aBox.y2 - aBox.y1;
  1.4078 +    return result;
  1.4079 +}
  1.4080 +
  1.4081 +static void
  1.4082 +InitRegion(pixman_region32* aRegion,
  1.4083 +           const nsTArray<nsIntRect>& aRects)
  1.4084 +{
  1.4085 +    nsAutoTArray<pixman_box32,10> rects;
  1.4086 +    rects.SetCapacity(aRects.Length());
  1.4087 +    for (uint32_t i = 0; i < aRects.Length (); ++i) {
  1.4088 +        if (!aRects[i].IsEmpty()) {
  1.4089 +            rects.AppendElement(ToPixmanBox(aRects[i]));
  1.4090 +        }
  1.4091 +    }
  1.4092 +
  1.4093 +    pixman_region32_init_rects(aRegion,
  1.4094 +                               rects.Elements(), rects.Length());
  1.4095 +}
  1.4096 +
  1.4097 +static void
  1.4098 +GetIntRects(pixman_region32& aRegion, nsTArray<nsIntRect>* aRects)
  1.4099 +{
  1.4100 +    int nRects;
  1.4101 +    pixman_box32* boxes = pixman_region32_rectangles(&aRegion, &nRects);
  1.4102 +    aRects->SetCapacity(aRects->Length() + nRects);
  1.4103 +    for (int i = 0; i < nRects; ++i) {
  1.4104 +        aRects->AppendElement(ToIntRect(boxes[i]));
  1.4105 +    }
  1.4106 +}
  1.4107 +
  1.4108 +void
  1.4109 +nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
  1.4110 +                              bool aIntersectWithExisting)
  1.4111 +{
  1.4112 +    const nsTArray<nsIntRect>* newRects = &aRects;
  1.4113 +
  1.4114 +    nsAutoTArray<nsIntRect,1> intersectRects;
  1.4115 +    if (aIntersectWithExisting) {
  1.4116 +        nsAutoTArray<nsIntRect,1> existingRects;
  1.4117 +        GetWindowClipRegion(&existingRects);
  1.4118 +
  1.4119 +        nsAutoRef<pixman_region32> existingRegion;
  1.4120 +        InitRegion(&existingRegion, existingRects);
  1.4121 +        nsAutoRef<pixman_region32> newRegion;
  1.4122 +        InitRegion(&newRegion, aRects);
  1.4123 +        nsAutoRef<pixman_region32> intersectRegion;
  1.4124 +        pixman_region32_init(&intersectRegion);
  1.4125 +        pixman_region32_intersect(&intersectRegion,
  1.4126 +                                  &newRegion, &existingRegion);
  1.4127 +
  1.4128 +        // If mClipRects is null we haven't set a clip rect yet, so we
  1.4129 +        // need to set the clip even if it is equal.
  1.4130 +        if (mClipRects &&
  1.4131 +            pixman_region32_equal(&intersectRegion, &existingRegion)) {
  1.4132 +            return;
  1.4133 +        }
  1.4134 +
  1.4135 +        if (!pixman_region32_equal(&intersectRegion, &newRegion)) {
  1.4136 +            GetIntRects(intersectRegion, &intersectRects);
  1.4137 +            newRects = &intersectRects;
  1.4138 +        }
  1.4139 +    }
  1.4140 +
  1.4141 +    if (!StoreWindowClipRegion(*newRects))
  1.4142 +        return;
  1.4143 +
  1.4144 +    if (!mGdkWindow)
  1.4145 +        return;
  1.4146 +
  1.4147 +#if (MOZ_WIDGET_GTK == 2)
  1.4148 +    GdkRegion *region = gdk_region_new(); // aborts on OOM
  1.4149 +    for (uint32_t i = 0; i < newRects->Length(); ++i) {
  1.4150 +        const nsIntRect& r = newRects->ElementAt(i);
  1.4151 +        GdkRectangle rect = { r.x, r.y, r.width, r.height };
  1.4152 +        gdk_region_union_with_rect(region, &rect);
  1.4153 +    }
  1.4154 +
  1.4155 +    gdk_window_shape_combine_region(mGdkWindow, region, 0, 0);
  1.4156 +    gdk_region_destroy(region);
  1.4157 +#else
  1.4158 +    cairo_region_t *region = cairo_region_create();
  1.4159 +    for (uint32_t i = 0; i < newRects->Length(); ++i) {
  1.4160 +        const nsIntRect& r = newRects->ElementAt(i);
  1.4161 +        cairo_rectangle_int_t rect = { r.x, r.y, r.width, r.height };
  1.4162 +        cairo_region_union_rectangle(region, &rect);
  1.4163 +    }
  1.4164 +
  1.4165 +    gdk_window_shape_combine_region(mGdkWindow, region, 0, 0);
  1.4166 +    cairo_region_destroy(region);
  1.4167 +#endif
  1.4168 +  
  1.4169 +    return;
  1.4170 +}
  1.4171 +
  1.4172 +void
  1.4173 +nsWindow::ResizeTransparencyBitmap()
  1.4174 +{
  1.4175 +    if (!mTransparencyBitmap)
  1.4176 +        return;
  1.4177 +
  1.4178 +    if (mBounds.width == mTransparencyBitmapWidth &&
  1.4179 +        mBounds.height == mTransparencyBitmapHeight)
  1.4180 +        return;
  1.4181 +
  1.4182 +    int32_t newRowBytes = GetBitmapStride(mBounds.width);
  1.4183 +    int32_t newSize = newRowBytes * mBounds.height;
  1.4184 +    gchar* newBits = new gchar[newSize];
  1.4185 +    // fill new mask with "transparent", first
  1.4186 +    memset(newBits, 0, newSize);
  1.4187 +
  1.4188 +    // Now copy the intersection of the old and new areas into the new mask
  1.4189 +    int32_t copyWidth = std::min(mBounds.width, mTransparencyBitmapWidth);
  1.4190 +    int32_t copyHeight = std::min(mBounds.height, mTransparencyBitmapHeight);
  1.4191 +    int32_t oldRowBytes = GetBitmapStride(mTransparencyBitmapWidth);
  1.4192 +    int32_t copyBytes = GetBitmapStride(copyWidth);
  1.4193 +
  1.4194 +    int32_t i;
  1.4195 +    gchar* fromPtr = mTransparencyBitmap;
  1.4196 +    gchar* toPtr = newBits;
  1.4197 +    for (i = 0; i < copyHeight; i++) {
  1.4198 +        memcpy(toPtr, fromPtr, copyBytes);
  1.4199 +        fromPtr += oldRowBytes;
  1.4200 +        toPtr += newRowBytes;
  1.4201 +    }
  1.4202 +
  1.4203 +    delete[] mTransparencyBitmap;
  1.4204 +    mTransparencyBitmap = newBits;
  1.4205 +    mTransparencyBitmapWidth = mBounds.width;
  1.4206 +    mTransparencyBitmapHeight = mBounds.height;
  1.4207 +}
  1.4208 +
  1.4209 +static bool
  1.4210 +ChangedMaskBits(gchar* aMaskBits, int32_t aMaskWidth, int32_t aMaskHeight,
  1.4211 +        const nsIntRect& aRect, uint8_t* aAlphas, int32_t aStride)
  1.4212 +{
  1.4213 +    int32_t x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
  1.4214 +    int32_t maskBytesPerRow = GetBitmapStride(aMaskWidth);
  1.4215 +    for (y = aRect.y; y < yMax; y++) {
  1.4216 +        gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
  1.4217 +        uint8_t* alphas = aAlphas;
  1.4218 +        for (x = aRect.x; x < xMax; x++) {
  1.4219 +            bool newBit = *alphas > 0x7f;
  1.4220 +            alphas++;
  1.4221 +
  1.4222 +            gchar maskByte = maskBytes[x >> 3];
  1.4223 +            bool maskBit = (maskByte & (1 << (x & 7))) != 0;
  1.4224 +
  1.4225 +            if (maskBit != newBit) {
  1.4226 +                return true;
  1.4227 +            }
  1.4228 +        }
  1.4229 +        aAlphas += aStride;
  1.4230 +    }
  1.4231 +
  1.4232 +    return false;
  1.4233 +}
  1.4234 +
  1.4235 +static
  1.4236 +void UpdateMaskBits(gchar* aMaskBits, int32_t aMaskWidth, int32_t aMaskHeight,
  1.4237 +        const nsIntRect& aRect, uint8_t* aAlphas, int32_t aStride)
  1.4238 +{
  1.4239 +    int32_t x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
  1.4240 +    int32_t maskBytesPerRow = GetBitmapStride(aMaskWidth);
  1.4241 +    for (y = aRect.y; y < yMax; y++) {
  1.4242 +        gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
  1.4243 +        uint8_t* alphas = aAlphas;
  1.4244 +        for (x = aRect.x; x < xMax; x++) {
  1.4245 +            bool newBit = *alphas > 0x7f;
  1.4246 +            alphas++;
  1.4247 +
  1.4248 +            gchar mask = 1 << (x & 7);
  1.4249 +            gchar maskByte = maskBytes[x >> 3];
  1.4250 +            // Note: '-newBit' turns 0 into 00...00 and 1 into 11...11
  1.4251 +            maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask);
  1.4252 +        }
  1.4253 +        aAlphas += aStride;
  1.4254 +    }
  1.4255 +}
  1.4256 +
  1.4257 +void
  1.4258 +nsWindow::ApplyTransparencyBitmap()
  1.4259 +{
  1.4260 +#ifdef MOZ_X11
  1.4261 +    // We use X11 calls where possible, because GDK handles expose events
  1.4262 +    // for shaped windows in a way that's incompatible with us (Bug 635903).
  1.4263 +    // It doesn't occur when the shapes are set through X.
  1.4264 +    GdkWindow *shellWindow = gtk_widget_get_window(mShell);
  1.4265 +    Display* xDisplay = GDK_WINDOW_XDISPLAY(shellWindow);
  1.4266 +    Window xDrawable = GDK_WINDOW_XID(shellWindow);
  1.4267 +    Pixmap maskPixmap = XCreateBitmapFromData(xDisplay,
  1.4268 +                                              xDrawable,
  1.4269 +                                              mTransparencyBitmap,
  1.4270 +                                              mTransparencyBitmapWidth,
  1.4271 +                                              mTransparencyBitmapHeight);
  1.4272 +    XShapeCombineMask(xDisplay, xDrawable,
  1.4273 +                      ShapeBounding, 0, 0,
  1.4274 +                      maskPixmap, ShapeSet);
  1.4275 +    XFreePixmap(xDisplay, maskPixmap);
  1.4276 +#else
  1.4277 +#if (MOZ_WIDGET_GTK == 2)
  1.4278 +    gtk_widget_reset_shapes(mShell);
  1.4279 +    GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(gtk_widget_get_window(mShell),
  1.4280 +            mTransparencyBitmap,
  1.4281 +            mTransparencyBitmapWidth, mTransparencyBitmapHeight);
  1.4282 +    if (!maskBitmap)
  1.4283 +        return;
  1.4284 +
  1.4285 +    gtk_widget_shape_combine_mask(mShell, maskBitmap, 0, 0);
  1.4286 +    g_object_unref(maskBitmap);
  1.4287 +#else
  1.4288 +    cairo_surface_t *maskBitmap;
  1.4289 +    maskBitmap = cairo_image_surface_create_for_data((unsigned char*)mTransparencyBitmap, 
  1.4290 +                                                     CAIRO_FORMAT_A1, 
  1.4291 +                                                     mTransparencyBitmapWidth, 
  1.4292 +                                                     mTransparencyBitmapHeight,
  1.4293 +                                                     GetBitmapStride(mTransparencyBitmapWidth));
  1.4294 +    if (!maskBitmap)
  1.4295 +        return;
  1.4296 +
  1.4297 +    cairo_region_t * maskRegion = gdk_cairo_region_create_from_surface(maskBitmap);
  1.4298 +    gtk_widget_shape_combine_region(mShell, maskRegion);
  1.4299 +    cairo_region_destroy(maskRegion);
  1.4300 +    cairo_surface_destroy(maskBitmap);
  1.4301 +#endif // MOZ_WIDGET_GTK2
  1.4302 +#endif // MOZ_X11
  1.4303 +}
  1.4304 +
  1.4305 +void
  1.4306 +nsWindow::ClearTransparencyBitmap()
  1.4307 +{
  1.4308 +    if (!mTransparencyBitmap)
  1.4309 +        return;
  1.4310 +
  1.4311 +    delete[] mTransparencyBitmap;
  1.4312 +    mTransparencyBitmap = nullptr;
  1.4313 +    mTransparencyBitmapWidth = 0;
  1.4314 +    mTransparencyBitmapHeight = 0;
  1.4315 +
  1.4316 +    if (!mShell)
  1.4317 +        return;
  1.4318 +
  1.4319 +#ifdef MOZ_X11
  1.4320 +    GdkWindow *window = gtk_widget_get_window(mShell);
  1.4321 +    if (!window)
  1.4322 +        return;
  1.4323 +
  1.4324 +    Display* xDisplay = GDK_WINDOW_XDISPLAY(window);
  1.4325 +    Window xWindow = gdk_x11_window_get_xid(window);
  1.4326 +
  1.4327 +    XShapeCombineMask(xDisplay, xWindow, ShapeBounding, 0, 0, None, ShapeSet);
  1.4328 +#endif
  1.4329 +}
  1.4330 +
  1.4331 +nsresult
  1.4332 +nsWindow::UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
  1.4333 +                                               uint8_t* aAlphas, int32_t aStride)
  1.4334 +{
  1.4335 +    if (!mShell) {
  1.4336 +        // Pass the request to the toplevel window
  1.4337 +        GtkWidget *topWidget = GetToplevelWidget();
  1.4338 +        if (!topWidget)
  1.4339 +            return NS_ERROR_FAILURE;
  1.4340 +
  1.4341 +        nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
  1.4342 +        if (!topWindow)
  1.4343 +            return NS_ERROR_FAILURE;
  1.4344 +
  1.4345 +        return topWindow->UpdateTranslucentWindowAlphaInternal(aRect, aAlphas, aStride);
  1.4346 +    }
  1.4347 +
  1.4348 +    NS_ASSERTION(mIsTransparent, "Window is not transparent");
  1.4349 +
  1.4350 +    if (mTransparencyBitmap == nullptr) {
  1.4351 +        int32_t size = GetBitmapStride(mBounds.width)*mBounds.height;
  1.4352 +        mTransparencyBitmap = new gchar[size];
  1.4353 +        memset(mTransparencyBitmap, 255, size);
  1.4354 +        mTransparencyBitmapWidth = mBounds.width;
  1.4355 +        mTransparencyBitmapHeight = mBounds.height;
  1.4356 +    } else {
  1.4357 +        ResizeTransparencyBitmap();
  1.4358 +    }
  1.4359 +
  1.4360 +    nsIntRect rect;
  1.4361 +    rect.IntersectRect(aRect, nsIntRect(0, 0, mBounds.width, mBounds.height));
  1.4362 +
  1.4363 +    if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height,
  1.4364 +                         rect, aAlphas, aStride))
  1.4365 +        // skip the expensive stuff if the mask bits haven't changed; hopefully
  1.4366 +        // this is the common case
  1.4367 +        return NS_OK;
  1.4368 +
  1.4369 +    UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height,
  1.4370 +                   rect, aAlphas, aStride);
  1.4371 +
  1.4372 +    if (!mNeedsShow) {
  1.4373 +        ApplyTransparencyBitmap();
  1.4374 +    }
  1.4375 +    return NS_OK;
  1.4376 +}
  1.4377 +
  1.4378 +void
  1.4379 +nsWindow::GrabPointer(guint32 aTime)
  1.4380 +{
  1.4381 +    LOG(("GrabPointer time=0x%08x retry=%d\n",
  1.4382 +         (unsigned int)aTime, mRetryPointerGrab));
  1.4383 +
  1.4384 +    mRetryPointerGrab = false;
  1.4385 +    sRetryGrabTime = aTime;
  1.4386 +
  1.4387 +    // If the window isn't visible, just set the flag to retry the
  1.4388 +    // grab.  When this window becomes visible, the grab will be
  1.4389 +    // retried.
  1.4390 +    if (!mHasMappedToplevel || mIsFullyObscured) {
  1.4391 +        LOG(("GrabPointer: window not visible\n"));
  1.4392 +        mRetryPointerGrab = true;
  1.4393 +        return;
  1.4394 +    }
  1.4395 +
  1.4396 +    if (!mGdkWindow)
  1.4397 +        return;
  1.4398 +
  1.4399 +    gint retval;
  1.4400 +    retval = gdk_pointer_grab(mGdkWindow, TRUE,
  1.4401 +                              (GdkEventMask)(GDK_BUTTON_PRESS_MASK |
  1.4402 +                                             GDK_BUTTON_RELEASE_MASK |
  1.4403 +                                             GDK_ENTER_NOTIFY_MASK |
  1.4404 +                                             GDK_LEAVE_NOTIFY_MASK |
  1.4405 +                                             GDK_POINTER_MOTION_MASK),
  1.4406 +                              (GdkWindow *)nullptr, nullptr, aTime);
  1.4407 +
  1.4408 +    if (retval == GDK_GRAB_NOT_VIEWABLE) {
  1.4409 +        LOG(("GrabPointer: window not viewable; will retry\n"));
  1.4410 +        mRetryPointerGrab = true;
  1.4411 +    } else if (retval != GDK_GRAB_SUCCESS) {
  1.4412 +        LOG(("GrabPointer: pointer grab failed: %i\n", retval));
  1.4413 +        // A failed grab indicates that another app has grabbed the pointer.
  1.4414 +        // Check for rollup now, because, without the grab, we likely won't
  1.4415 +        // get subsequent button press events.
  1.4416 +        CheckForRollup(0, 0, false, true);
  1.4417 +    }
  1.4418 +}
  1.4419 +
  1.4420 +void
  1.4421 +nsWindow::ReleaseGrabs(void)
  1.4422 +{
  1.4423 +    LOG(("ReleaseGrabs\n"));
  1.4424 +
  1.4425 +    mRetryPointerGrab = false;
  1.4426 +    gdk_pointer_ungrab(GDK_CURRENT_TIME);
  1.4427 +}
  1.4428 +
  1.4429 +GtkWidget *
  1.4430 +nsWindow::GetToplevelWidget()
  1.4431 +{
  1.4432 +    if (mShell) {
  1.4433 +        return mShell;
  1.4434 +    }
  1.4435 +
  1.4436 +    GtkWidget *widget = GetMozContainerWidget();
  1.4437 +    if (!widget)
  1.4438 +        return nullptr;
  1.4439 +
  1.4440 +    return gtk_widget_get_toplevel(widget);
  1.4441 +}
  1.4442 +
  1.4443 +GtkWidget *
  1.4444 +nsWindow::GetMozContainerWidget()
  1.4445 +{
  1.4446 +    if (!mGdkWindow)
  1.4447 +        return nullptr;
  1.4448 +
  1.4449 +    if (mContainer)
  1.4450 +        return GTK_WIDGET(mContainer);
  1.4451 +
  1.4452 +    GtkWidget *owningWidget =
  1.4453 +        get_gtk_widget_for_gdk_window(mGdkWindow);
  1.4454 +    return owningWidget;
  1.4455 +}
  1.4456 +
  1.4457 +nsWindow *
  1.4458 +nsWindow::GetContainerWindow()
  1.4459 +{
  1.4460 +    GtkWidget *owningWidget = GetMozContainerWidget();
  1.4461 +    if (!owningWidget)
  1.4462 +        return nullptr;
  1.4463 +
  1.4464 +    nsWindow *window = get_window_for_gtk_widget(owningWidget);
  1.4465 +    NS_ASSERTION(window, "No nsWindow for container widget");
  1.4466 +    return window;
  1.4467 +}
  1.4468 +
  1.4469 +void
  1.4470 +nsWindow::SetUrgencyHint(GtkWidget *top_window, bool state)
  1.4471 +{
  1.4472 +    if (!top_window)
  1.4473 +        return;
  1.4474 +        
  1.4475 +    gdk_window_set_urgency_hint(gtk_widget_get_window(top_window), state);
  1.4476 +}
  1.4477 +
  1.4478 +void *
  1.4479 +nsWindow::SetupPluginPort(void)
  1.4480 +{
  1.4481 +    if (!mGdkWindow)
  1.4482 +        return nullptr;
  1.4483 +
  1.4484 +    if (gdk_window_is_destroyed(mGdkWindow) == TRUE)
  1.4485 +        return nullptr;
  1.4486 +
  1.4487 +    Window window = gdk_x11_window_get_xid(mGdkWindow);
  1.4488 +    
  1.4489 +    // we have to flush the X queue here so that any plugins that
  1.4490 +    // might be running on separate X connections will be able to use
  1.4491 +    // this window in case it was just created
  1.4492 +#ifdef MOZ_X11
  1.4493 +    XWindowAttributes xattrs;    
  1.4494 +    Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
  1.4495 +    XGetWindowAttributes(display, window, &xattrs);
  1.4496 +    XSelectInput (display, window,
  1.4497 +                  xattrs.your_event_mask |
  1.4498 +                  SubstructureNotifyMask);
  1.4499 +
  1.4500 +    gdk_window_add_filter(mGdkWindow, plugin_window_filter_func, this);
  1.4501 +
  1.4502 +    XSync(display, False);
  1.4503 +#endif /* MOZ_X11 */
  1.4504 +    
  1.4505 +    return (void *)window;
  1.4506 +}
  1.4507 +
  1.4508 +void
  1.4509 +nsWindow::SetDefaultIcon(void)
  1.4510 +{
  1.4511 +    SetIcon(NS_LITERAL_STRING("default"));
  1.4512 +}
  1.4513 +
  1.4514 +void
  1.4515 +nsWindow::SetPluginType(PluginType aPluginType)
  1.4516 +{
  1.4517 +    mPluginType = aPluginType;
  1.4518 +}
  1.4519 +
  1.4520 +#ifdef MOZ_X11
  1.4521 +void
  1.4522 +nsWindow::SetNonXEmbedPluginFocus()
  1.4523 +{
  1.4524 +    if (gPluginFocusWindow == this || mPluginType!=PluginType_NONXEMBED) {
  1.4525 +        return;
  1.4526 +    }
  1.4527 +
  1.4528 +    if (gPluginFocusWindow) {
  1.4529 +        nsRefPtr<nsWindow> kungFuDeathGrip = gPluginFocusWindow;
  1.4530 +        gPluginFocusWindow->LoseNonXEmbedPluginFocus();
  1.4531 +    }
  1.4532 +
  1.4533 +    LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus\n"));
  1.4534 +
  1.4535 +    Window curFocusWindow;
  1.4536 +    int focusState;
  1.4537 +    
  1.4538 +    GdkDisplay *gdkDisplay = gdk_window_get_display(mGdkWindow);
  1.4539 +    XGetInputFocus(gdk_x11_display_get_xdisplay(gdkDisplay),
  1.4540 +                   &curFocusWindow,
  1.4541 +                   &focusState);
  1.4542 +
  1.4543 +    LOGFOCUS(("\t curFocusWindow=%p\n", curFocusWindow));
  1.4544 +
  1.4545 +    GdkWindow* toplevel = gdk_window_get_toplevel(mGdkWindow);
  1.4546 +#if (MOZ_WIDGET_GTK == 2)
  1.4547 +    GdkWindow *gdkfocuswin = gdk_window_lookup(curFocusWindow);
  1.4548 +#else
  1.4549 +    GdkWindow *gdkfocuswin = gdk_x11_window_lookup_for_display(gdkDisplay,
  1.4550 +                                                               curFocusWindow);
  1.4551 +#endif
  1.4552 +
  1.4553 +    // lookup with the focus proxy window is supposed to get the
  1.4554 +    // same GdkWindow as toplevel. If the current focused window
  1.4555 +    // is not the focus proxy, we return without any change.
  1.4556 +    if (gdkfocuswin != toplevel) {
  1.4557 +        return;
  1.4558 +    }
  1.4559 +
  1.4560 +    // switch the focus from the focus proxy to the plugin window
  1.4561 +    mOldFocusWindow = curFocusWindow;
  1.4562 +    XRaiseWindow(GDK_WINDOW_XDISPLAY(mGdkWindow),
  1.4563 +                 gdk_x11_window_get_xid(mGdkWindow));
  1.4564 +    gdk_error_trap_push();
  1.4565 +    XSetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow),
  1.4566 +                   gdk_x11_window_get_xid(mGdkWindow),
  1.4567 +                   RevertToNone,
  1.4568 +                   CurrentTime);
  1.4569 +    gdk_flush();
  1.4570 +    gdk_error_trap_pop();
  1.4571 +    gPluginFocusWindow = this;
  1.4572 +    gdk_window_add_filter(nullptr, plugin_client_message_filter, this);
  1.4573 +
  1.4574 +    LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus oldfocus=%p new=%p\n",
  1.4575 +              mOldFocusWindow, gdk_x11_window_get_xid(mGdkWindow)));
  1.4576 +}
  1.4577 +
  1.4578 +void
  1.4579 +nsWindow::LoseNonXEmbedPluginFocus()
  1.4580 +{
  1.4581 +    LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus\n"));
  1.4582 +
  1.4583 +    // This method is only for the nsWindow which contains a
  1.4584 +    // Non-XEmbed plugin, for example, JAVA plugin.
  1.4585 +    if (gPluginFocusWindow != this || mPluginType!=PluginType_NONXEMBED) {
  1.4586 +        return;
  1.4587 +    }
  1.4588 +
  1.4589 +    Window curFocusWindow;
  1.4590 +    int focusState;
  1.4591 +
  1.4592 +    XGetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow),
  1.4593 +                   &curFocusWindow,
  1.4594 +                   &focusState);
  1.4595 +
  1.4596 +    // we only switch focus between plugin window and focus proxy. If the
  1.4597 +    // current focused window is not the plugin window, just removing the
  1.4598 +    // event filter that blocks the WM_TAKE_FOCUS is enough. WM and gtk2
  1.4599 +    // will take care of the focus later.
  1.4600 +    if (!curFocusWindow ||
  1.4601 +        curFocusWindow == gdk_x11_window_get_xid(mGdkWindow)) {
  1.4602 +
  1.4603 +        gdk_error_trap_push();
  1.4604 +        XRaiseWindow(GDK_WINDOW_XDISPLAY(mGdkWindow),
  1.4605 +                     mOldFocusWindow);
  1.4606 +        XSetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow),
  1.4607 +                       mOldFocusWindow,
  1.4608 +                       RevertToParent,
  1.4609 +                       CurrentTime);
  1.4610 +        gdk_flush();
  1.4611 +        gdk_error_trap_pop();
  1.4612 +    }
  1.4613 +    gPluginFocusWindow = nullptr;
  1.4614 +    mOldFocusWindow = 0;
  1.4615 +    gdk_window_remove_filter(nullptr, plugin_client_message_filter, this);
  1.4616 +
  1.4617 +    LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus end\n"));
  1.4618 +}
  1.4619 +#endif /* MOZ_X11 */
  1.4620 +
  1.4621 +gint
  1.4622 +nsWindow::ConvertBorderStyles(nsBorderStyle aStyle)
  1.4623 +{
  1.4624 +    gint w = 0;
  1.4625 +
  1.4626 +    if (aStyle == eBorderStyle_default)
  1.4627 +        return -1;
  1.4628 +
  1.4629 +    // note that we don't handle eBorderStyle_close yet
  1.4630 +    if (aStyle & eBorderStyle_all)
  1.4631 +        w |= GDK_DECOR_ALL;
  1.4632 +    if (aStyle & eBorderStyle_border)
  1.4633 +        w |= GDK_DECOR_BORDER;
  1.4634 +    if (aStyle & eBorderStyle_resizeh)
  1.4635 +        w |= GDK_DECOR_RESIZEH;
  1.4636 +    if (aStyle & eBorderStyle_title)
  1.4637 +        w |= GDK_DECOR_TITLE;
  1.4638 +    if (aStyle & eBorderStyle_menu)
  1.4639 +        w |= GDK_DECOR_MENU;
  1.4640 +    if (aStyle & eBorderStyle_minimize)
  1.4641 +        w |= GDK_DECOR_MINIMIZE;
  1.4642 +    if (aStyle & eBorderStyle_maximize)
  1.4643 +        w |= GDK_DECOR_MAXIMIZE;
  1.4644 +
  1.4645 +    return w;
  1.4646 +}
  1.4647 +
  1.4648 +NS_IMETHODIMP
  1.4649 +nsWindow::MakeFullScreen(bool aFullScreen)
  1.4650 +{
  1.4651 +    LOG(("nsWindow::MakeFullScreen [%p] aFullScreen %d\n",
  1.4652 +         (void *)this, aFullScreen));
  1.4653 +
  1.4654 +    if (aFullScreen) {
  1.4655 +        if (mSizeMode != nsSizeMode_Fullscreen)
  1.4656 +            mLastSizeMode = mSizeMode;
  1.4657 +
  1.4658 +        mSizeMode = nsSizeMode_Fullscreen;
  1.4659 +        gtk_window_fullscreen(GTK_WINDOW(mShell));
  1.4660 +    }
  1.4661 +    else {
  1.4662 +        mSizeMode = mLastSizeMode;
  1.4663 +        gtk_window_unfullscreen(GTK_WINDOW(mShell));
  1.4664 +    }
  1.4665 +
  1.4666 +    NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen,
  1.4667 +                 "mLastSizeMode should never be fullscreen");
  1.4668 +    return NS_OK;
  1.4669 +}
  1.4670 +
  1.4671 +NS_IMETHODIMP
  1.4672 +nsWindow::HideWindowChrome(bool aShouldHide)
  1.4673 +{
  1.4674 +    if (!mShell) {
  1.4675 +        // Pass the request to the toplevel window
  1.4676 +        GtkWidget *topWidget = GetToplevelWidget();
  1.4677 +        if (!topWidget)
  1.4678 +            return NS_ERROR_FAILURE;
  1.4679 +
  1.4680 +        nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
  1.4681 +        if (!topWindow)
  1.4682 +            return NS_ERROR_FAILURE;
  1.4683 +
  1.4684 +        return topWindow->HideWindowChrome(aShouldHide);
  1.4685 +    }
  1.4686 +
  1.4687 +    // Sawfish, metacity, and presumably other window managers get
  1.4688 +    // confused if we change the window decorations while the window
  1.4689 +    // is visible.
  1.4690 +    bool wasVisible = false;
  1.4691 +    GdkWindow *shellWindow = gtk_widget_get_window(mShell);
  1.4692 +    if (gdk_window_is_visible(shellWindow)) {
  1.4693 +        gdk_window_hide(shellWindow);
  1.4694 +        wasVisible = true;
  1.4695 +    }
  1.4696 +
  1.4697 +    gint wmd;
  1.4698 +    if (aShouldHide)
  1.4699 +        wmd = 0;
  1.4700 +    else
  1.4701 +        wmd = ConvertBorderStyles(mBorderStyle);
  1.4702 +
  1.4703 +    if (wmd != -1)
  1.4704 +      gdk_window_set_decorations(shellWindow, (GdkWMDecoration) wmd);
  1.4705 +
  1.4706 +    if (wasVisible)
  1.4707 +        gdk_window_show(shellWindow);
  1.4708 +
  1.4709 +    // For some window managers, adding or removing window decorations
  1.4710 +    // requires unmapping and remapping our toplevel window.  Go ahead
  1.4711 +    // and flush the queue here so that we don't end up with a BadWindow
  1.4712 +    // error later when this happens (when the persistence timer fires
  1.4713 +    // and GetWindowPos is called)
  1.4714 +#ifdef MOZ_X11
  1.4715 +    XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) , False);
  1.4716 +#else
  1.4717 +    gdk_flush ();
  1.4718 +#endif /* MOZ_X11 */
  1.4719 +
  1.4720 +    return NS_OK;
  1.4721 +}
  1.4722 +
  1.4723 +bool
  1.4724 +nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY,
  1.4725 +                         bool aIsWheel, bool aAlwaysRollup)
  1.4726 +{
  1.4727 +    nsIRollupListener* rollupListener = GetActiveRollupListener();
  1.4728 +    nsCOMPtr<nsIWidget> rollupWidget;
  1.4729 +    if (rollupListener) {
  1.4730 +        rollupWidget = rollupListener->GetRollupWidget();
  1.4731 +    }
  1.4732 +    if (!rollupWidget) {
  1.4733 +        nsBaseWidget::gRollupListener = nullptr;
  1.4734 +        return false;
  1.4735 +    }
  1.4736 +
  1.4737 +    bool retVal = false;
  1.4738 +    GdkWindow *currentPopup =
  1.4739 +        (GdkWindow *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
  1.4740 +    if (aAlwaysRollup || !is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
  1.4741 +        bool rollup = true;
  1.4742 +        if (aIsWheel) {
  1.4743 +            rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
  1.4744 +            retVal = rollupListener->ShouldConsumeOnMouseWheelEvent();
  1.4745 +        }
  1.4746 +        // if we're dealing with menus, we probably have submenus and
  1.4747 +        // we don't want to rollup if the click is in a parent menu of
  1.4748 +        // the current submenu
  1.4749 +        uint32_t popupsToRollup = UINT32_MAX;
  1.4750 +        if (!aAlwaysRollup) {
  1.4751 +            nsAutoTArray<nsIWidget*, 5> widgetChain;
  1.4752 +            uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
  1.4753 +            for (uint32_t i=0; i<widgetChain.Length(); ++i) {
  1.4754 +                nsIWidget* widget = widgetChain[i];
  1.4755 +                GdkWindow* currWindow =
  1.4756 +                    (GdkWindow*) widget->GetNativeData(NS_NATIVE_WINDOW);
  1.4757 +                if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
  1.4758 +                  // don't roll up if the mouse event occurred within a
  1.4759 +                  // menu of the same type. If the mouse event occurred
  1.4760 +                  // in a menu higher than that, roll up, but pass the
  1.4761 +                  // number of popups to Rollup so that only those of the
  1.4762 +                  // same type close up.
  1.4763 +                  if (i < sameTypeCount) {
  1.4764 +                    rollup = false;
  1.4765 +                  }
  1.4766 +                  else {
  1.4767 +                    popupsToRollup = sameTypeCount;
  1.4768 +                  }
  1.4769 +                  break;
  1.4770 +                }
  1.4771 +            } // foreach parent menu widget
  1.4772 +        } // if rollup listener knows about menus
  1.4773 +
  1.4774 +        // if we've determined that we should still rollup, do it.
  1.4775 +        bool usePoint = !aIsWheel && !aAlwaysRollup;
  1.4776 +        nsIntPoint point(aMouseX, aMouseY);
  1.4777 +        if (rollup && rollupListener->Rollup(popupsToRollup, usePoint ? &point : nullptr, nullptr)) {
  1.4778 +            retVal = true;
  1.4779 +        }
  1.4780 +    }
  1.4781 +    return retVal;
  1.4782 +}
  1.4783 +
  1.4784 +/* static */
  1.4785 +bool
  1.4786 +nsWindow::DragInProgress(void)
  1.4787 +{
  1.4788 +    nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
  1.4789 +
  1.4790 +    if (!dragService)
  1.4791 +        return false;
  1.4792 +
  1.4793 +    nsCOMPtr<nsIDragSession> currentDragSession;
  1.4794 +    dragService->GetCurrentSession(getter_AddRefs(currentDragSession));
  1.4795 +
  1.4796 +    return currentDragSession != nullptr;
  1.4797 +}
  1.4798 +
  1.4799 +static bool
  1.4800 +is_mouse_in_window (GdkWindow* aWindow, gdouble aMouseX, gdouble aMouseY)
  1.4801 +{
  1.4802 +    gint x = 0;
  1.4803 +    gint y = 0;
  1.4804 +    gint w, h;
  1.4805 +
  1.4806 +    gint offsetX = 0;
  1.4807 +    gint offsetY = 0;
  1.4808 +
  1.4809 +    GdkWindow *window = aWindow;
  1.4810 +
  1.4811 +    while (window) {
  1.4812 +        gint tmpX = 0;
  1.4813 +        gint tmpY = 0;
  1.4814 +
  1.4815 +        gdk_window_get_position(window, &tmpX, &tmpY);
  1.4816 +        GtkWidget *widget = get_gtk_widget_for_gdk_window(window);
  1.4817 +
  1.4818 +        // if this is a window, compute x and y given its origin and our
  1.4819 +        // offset
  1.4820 +        if (GTK_IS_WINDOW(widget)) {
  1.4821 +            x = tmpX + offsetX;
  1.4822 +            y = tmpY + offsetY;
  1.4823 +            break;
  1.4824 +        }
  1.4825 +
  1.4826 +        offsetX += tmpX;
  1.4827 +        offsetY += tmpY;
  1.4828 +        window = gdk_window_get_parent(window);
  1.4829 +    }
  1.4830 +
  1.4831 +#if (MOZ_WIDGET_GTK == 2)
  1.4832 +    gdk_drawable_get_size(aWindow, &w, &h);
  1.4833 +#else
  1.4834 +    w = gdk_window_get_width(aWindow);
  1.4835 +    h = gdk_window_get_height(aWindow);
  1.4836 +#endif
  1.4837 +
  1.4838 +    if (aMouseX > x && aMouseX < x + w &&
  1.4839 +        aMouseY > y && aMouseY < y + h)
  1.4840 +        return true;
  1.4841 +
  1.4842 +    return false;
  1.4843 +}
  1.4844 +
  1.4845 +static nsWindow *
  1.4846 +get_window_for_gtk_widget(GtkWidget *widget)
  1.4847 +{
  1.4848 +    gpointer user_data = g_object_get_data(G_OBJECT(widget), "nsWindow");
  1.4849 +
  1.4850 +    return static_cast<nsWindow *>(user_data);
  1.4851 +}
  1.4852 +
  1.4853 +static nsWindow *
  1.4854 +get_window_for_gdk_window(GdkWindow *window)
  1.4855 +{
  1.4856 +    gpointer user_data = g_object_get_data(G_OBJECT(window), "nsWindow");
  1.4857 +
  1.4858 +    return static_cast<nsWindow *>(user_data);
  1.4859 +}
  1.4860 +
  1.4861 +static GtkWidget *
  1.4862 +get_gtk_widget_for_gdk_window(GdkWindow *window)
  1.4863 +{
  1.4864 +    gpointer user_data = nullptr;
  1.4865 +    gdk_window_get_user_data(window, &user_data);
  1.4866 +
  1.4867 +    return GTK_WIDGET(user_data);
  1.4868 +}
  1.4869 +
  1.4870 +static GdkCursor *
  1.4871 +get_gtk_cursor(nsCursor aCursor)
  1.4872 +{
  1.4873 +    GdkCursor *gdkcursor = nullptr;
  1.4874 +    uint8_t newType = 0xff;
  1.4875 +
  1.4876 +    if ((gdkcursor = gCursorCache[aCursor])) {
  1.4877 +        return gdkcursor;
  1.4878 +    }
  1.4879 +    
  1.4880 +    GdkDisplay *defaultDisplay = gdk_display_get_default();
  1.4881 +
  1.4882 +    // The strategy here is to use standard GDK cursors, and, if not available,
  1.4883 +    // load by standard name with gdk_cursor_new_from_name.
  1.4884 +    // Spec is here: http://www.freedesktop.org/wiki/Specifications/cursor-spec/
  1.4885 +    switch (aCursor) {
  1.4886 +    case eCursor_standard:
  1.4887 +        gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
  1.4888 +        break;
  1.4889 +    case eCursor_wait:
  1.4890 +        gdkcursor = gdk_cursor_new(GDK_WATCH);
  1.4891 +        break;
  1.4892 +    case eCursor_select:
  1.4893 +        gdkcursor = gdk_cursor_new(GDK_XTERM);
  1.4894 +        break;
  1.4895 +    case eCursor_hyperlink:
  1.4896 +        gdkcursor = gdk_cursor_new(GDK_HAND2);
  1.4897 +        break;
  1.4898 +    case eCursor_n_resize:
  1.4899 +        gdkcursor = gdk_cursor_new(GDK_TOP_SIDE);
  1.4900 +        break;
  1.4901 +    case eCursor_s_resize:
  1.4902 +        gdkcursor = gdk_cursor_new(GDK_BOTTOM_SIDE);
  1.4903 +        break;
  1.4904 +    case eCursor_w_resize:
  1.4905 +        gdkcursor = gdk_cursor_new(GDK_LEFT_SIDE);
  1.4906 +        break;
  1.4907 +    case eCursor_e_resize:
  1.4908 +        gdkcursor = gdk_cursor_new(GDK_RIGHT_SIDE);
  1.4909 +        break;
  1.4910 +    case eCursor_nw_resize:
  1.4911 +        gdkcursor = gdk_cursor_new(GDK_TOP_LEFT_CORNER);
  1.4912 +        break;
  1.4913 +    case eCursor_se_resize:
  1.4914 +        gdkcursor = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
  1.4915 +        break;
  1.4916 +    case eCursor_ne_resize:
  1.4917 +        gdkcursor = gdk_cursor_new(GDK_TOP_RIGHT_CORNER);
  1.4918 +        break;
  1.4919 +    case eCursor_sw_resize:
  1.4920 +        gdkcursor = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER);
  1.4921 +        break;
  1.4922 +    case eCursor_crosshair:
  1.4923 +        gdkcursor = gdk_cursor_new(GDK_CROSSHAIR);
  1.4924 +        break;
  1.4925 +    case eCursor_move:
  1.4926 +        gdkcursor = gdk_cursor_new(GDK_FLEUR);
  1.4927 +        break;
  1.4928 +    case eCursor_help:
  1.4929 +        gdkcursor = gdk_cursor_new(GDK_QUESTION_ARROW);
  1.4930 +        break;
  1.4931 +    case eCursor_copy: // CSS3
  1.4932 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
  1.4933 +        if (!gdkcursor)
  1.4934 +            newType = MOZ_CURSOR_COPY;
  1.4935 +        break;
  1.4936 +    case eCursor_alias:
  1.4937 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
  1.4938 +        if (!gdkcursor)
  1.4939 +            newType = MOZ_CURSOR_ALIAS;
  1.4940 +        break;
  1.4941 +    case eCursor_context_menu:
  1.4942 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
  1.4943 +        if (!gdkcursor)
  1.4944 +            newType = MOZ_CURSOR_CONTEXT_MENU;
  1.4945 +        break;
  1.4946 +    case eCursor_cell:
  1.4947 +        gdkcursor = gdk_cursor_new(GDK_PLUS);
  1.4948 +        break;
  1.4949 +    // Those two aren’t standardized. Trying both KDE’s and GNOME’s names
  1.4950 +    case eCursor_grab:
  1.4951 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "openhand");
  1.4952 +        if (!gdkcursor)
  1.4953 +            gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "hand1");
  1.4954 +        if (!gdkcursor)
  1.4955 +            newType = MOZ_CURSOR_HAND_GRAB;
  1.4956 +        break;
  1.4957 +    case eCursor_grabbing:
  1.4958 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "closedhand");
  1.4959 +        if (!gdkcursor)
  1.4960 +            gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
  1.4961 +        if (!gdkcursor)
  1.4962 +            newType = MOZ_CURSOR_HAND_GRABBING;
  1.4963 +        break;
  1.4964 +    case eCursor_spinning:
  1.4965 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
  1.4966 +        if (!gdkcursor)
  1.4967 +            newType = MOZ_CURSOR_SPINNING;
  1.4968 +        break;
  1.4969 +    case eCursor_zoom_in:
  1.4970 +        newType = MOZ_CURSOR_ZOOM_IN;
  1.4971 +        break;
  1.4972 +    case eCursor_zoom_out:
  1.4973 +        newType = MOZ_CURSOR_ZOOM_OUT;
  1.4974 +        break;
  1.4975 +    case eCursor_not_allowed:
  1.4976 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
  1.4977 +        if (!gdkcursor) // nonstandard, yet common
  1.4978 +            gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "crossed_circle");
  1.4979 +        if (!gdkcursor)
  1.4980 +            newType = MOZ_CURSOR_NOT_ALLOWED;
  1.4981 +        break;
  1.4982 +    case eCursor_no_drop:
  1.4983 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
  1.4984 +        if (!gdkcursor) // this nonstandard sequence makes it work on KDE and GNOME
  1.4985 +            gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "forbidden");
  1.4986 +        if (!gdkcursor)
  1.4987 +            gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
  1.4988 +        if (!gdkcursor)
  1.4989 +            newType = MOZ_CURSOR_NOT_ALLOWED;
  1.4990 +        break;
  1.4991 +    case eCursor_vertical_text:
  1.4992 +        newType = MOZ_CURSOR_VERTICAL_TEXT;
  1.4993 +        break;
  1.4994 +    case eCursor_all_scroll:
  1.4995 +        gdkcursor = gdk_cursor_new(GDK_FLEUR);
  1.4996 +        break;
  1.4997 +    case eCursor_nesw_resize:
  1.4998 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_bdiag");
  1.4999 +        if (!gdkcursor)
  1.5000 +            newType = MOZ_CURSOR_NESW_RESIZE;
  1.5001 +        break;
  1.5002 +    case eCursor_nwse_resize:
  1.5003 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_fdiag");
  1.5004 +        if (!gdkcursor)
  1.5005 +            newType = MOZ_CURSOR_NWSE_RESIZE;
  1.5006 +        break;
  1.5007 +    case eCursor_ns_resize:
  1.5008 +        gdkcursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
  1.5009 +        break;
  1.5010 +    case eCursor_ew_resize:
  1.5011 +        gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
  1.5012 +        break;
  1.5013 +    // Here, two better fitting cursors exist in some cursor themes. Try those first
  1.5014 +    case eCursor_row_resize:
  1.5015 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_v");
  1.5016 +        if (!gdkcursor)
  1.5017 +            gdkcursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
  1.5018 +        break;
  1.5019 +    case eCursor_col_resize:
  1.5020 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_h");
  1.5021 +        if (!gdkcursor)
  1.5022 +            gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
  1.5023 +        break;
  1.5024 +    case eCursor_none:
  1.5025 +        newType = MOZ_CURSOR_NONE;
  1.5026 +        break;
  1.5027 +    default:
  1.5028 +        NS_ASSERTION(aCursor, "Invalid cursor type");
  1.5029 +        gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
  1.5030 +        break;
  1.5031 +    }
  1.5032 +
  1.5033 +    // If by now we don't have a xcursor, this means we have to make a custom
  1.5034 +    // one. First, we try creating a named cursor based on the hash of our
  1.5035 +    // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
  1.5036 +    // to themed cursors
  1.5037 +    if (newType != 0xFF && GtkCursors[newType].hash) {
  1.5038 +        gdkcursor = gdk_cursor_new_from_name(defaultDisplay, GtkCursors[newType].hash);
  1.5039 +    }
  1.5040 +
  1.5041 +    // If we still don't have a xcursor, we now really create a bitmap cursor
  1.5042 +    if (newType != 0xff && !gdkcursor) {
  1.5043 +        GdkPixbuf * cursor_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
  1.5044 +        if (!cursor_pixbuf)
  1.5045 +            return nullptr;
  1.5046 +      
  1.5047 +        guchar *data = gdk_pixbuf_get_pixels(cursor_pixbuf);
  1.5048 +        
  1.5049 +        // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and mask
  1.5050 +        // GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for each pixel)
  1.5051 +        // so it's 128 byte array (4 bytes for are one bitmap row and there are 32 rows here).
  1.5052 +        const unsigned char *bits = GtkCursors[newType].bits;
  1.5053 +        const unsigned char *mask_bits = GtkCursors[newType].mask_bits;
  1.5054 +        
  1.5055 +        for (int i = 0; i < 128; i++) {
  1.5056 +            char bit = *bits++;
  1.5057 +            char mask = *mask_bits++;
  1.5058 +            for (int j = 0; j < 8; j++) {
  1.5059 +                unsigned char pix = ~(((bit >> j) & 0x01) * 0xff);
  1.5060 +                *data++ = pix;
  1.5061 +                *data++ = pix;
  1.5062 +                *data++ = pix;
  1.5063 +                *data++ = (((mask >> j) & 0x01) * 0xff);
  1.5064 +            }
  1.5065 +        }
  1.5066 +      
  1.5067 +        gdkcursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), cursor_pixbuf,
  1.5068 +                                               GtkCursors[newType].hot_x,
  1.5069 +                                               GtkCursors[newType].hot_y);
  1.5070 +        
  1.5071 +        g_object_unref(cursor_pixbuf);
  1.5072 +    }
  1.5073 +
  1.5074 +    gCursorCache[aCursor] = gdkcursor;
  1.5075 +
  1.5076 +    return gdkcursor;
  1.5077 +}
  1.5078 +
  1.5079 +// gtk callbacks
  1.5080 +
  1.5081 +#if (MOZ_WIDGET_GTK == 2)
  1.5082 +static gboolean
  1.5083 +expose_event_cb(GtkWidget *widget, GdkEventExpose *event)
  1.5084 +{
  1.5085 +    nsRefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
  1.5086 +    if (!window)
  1.5087 +        return FALSE;
  1.5088 +
  1.5089 +    window->OnExposeEvent(event);
  1.5090 +    return FALSE;
  1.5091 +}
  1.5092 +#else
  1.5093 +void
  1.5094 +draw_window_of_widget(GtkWidget *widget, GdkWindow *aWindow, cairo_t *cr)
  1.5095 +{
  1.5096 +    if (gtk_cairo_should_draw_window(cr, aWindow)) {
  1.5097 +        nsRefPtr<nsWindow> window = get_window_for_gdk_window(aWindow);
  1.5098 +        if (!window) {
  1.5099 +            NS_WARNING("Cannot get nsWindow from GtkWidget");
  1.5100 +        }
  1.5101 +        else {      
  1.5102 +            cairo_save(cr);      
  1.5103 +            gtk_cairo_transform_to_window(cr, widget, aWindow);  
  1.5104 +            // TODO - window->OnExposeEvent() can destroy this or other windows,
  1.5105 +            // do we need to handle it somehow?
  1.5106 +            window->OnExposeEvent(cr);
  1.5107 +            cairo_restore(cr);
  1.5108 +        }
  1.5109 +    }
  1.5110 +    
  1.5111 +    GList *children = gdk_window_get_children(aWindow);
  1.5112 +    GList *child = children;
  1.5113 +    while (child) {
  1.5114 +        GdkWindow *window = GDK_WINDOW(child->data);
  1.5115 +        gpointer windowWidget;
  1.5116 +        gdk_window_get_user_data(window, &windowWidget);
  1.5117 +        if (windowWidget == widget) {
  1.5118 +            draw_window_of_widget(widget, window, cr);
  1.5119 +        }
  1.5120 +        child = g_list_next(child);
  1.5121 +    }  
  1.5122 +    g_list_free(children);
  1.5123 +}
  1.5124 +
  1.5125 +/* static */
  1.5126 +gboolean
  1.5127 +expose_event_cb(GtkWidget *widget, cairo_t *cr)
  1.5128 +{
  1.5129 +    draw_window_of_widget(widget, gtk_widget_get_window(widget), cr);
  1.5130 +    return FALSE;
  1.5131 +}
  1.5132 +#endif //MOZ_WIDGET_GTK2
  1.5133 +
  1.5134 +static gboolean
  1.5135 +configure_event_cb(GtkWidget *widget,
  1.5136 +                   GdkEventConfigure *event)
  1.5137 +{
  1.5138 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
  1.5139 +    if (!window)
  1.5140 +        return FALSE;
  1.5141 +
  1.5142 +    return window->OnConfigureEvent(widget, event);
  1.5143 +}
  1.5144 +
  1.5145 +static void
  1.5146 +container_unrealize_cb (GtkWidget *widget)
  1.5147 +{
  1.5148 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
  1.5149 +    if (!window)
  1.5150 +        return;
  1.5151 +
  1.5152 +    window->OnContainerUnrealize();
  1.5153 +}
  1.5154 +
  1.5155 +static void
  1.5156 +size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation)
  1.5157 +{
  1.5158 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
  1.5159 +    if (!window)
  1.5160 +        return;
  1.5161 +
  1.5162 +    window->OnSizeAllocate(allocation);
  1.5163 +}
  1.5164 +
  1.5165 +static gboolean
  1.5166 +delete_event_cb(GtkWidget *widget, GdkEventAny *event)
  1.5167 +{
  1.5168 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
  1.5169 +    if (!window)
  1.5170 +        return FALSE;
  1.5171 +
  1.5172 +    window->OnDeleteEvent();
  1.5173 +
  1.5174 +    return TRUE;
  1.5175 +}
  1.5176 +
  1.5177 +static gboolean
  1.5178 +enter_notify_event_cb(GtkWidget *widget,
  1.5179 +                      GdkEventCrossing *event)
  1.5180 +{
  1.5181 +    nsRefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
  1.5182 +    if (!window)
  1.5183 +        return TRUE;
  1.5184 +
  1.5185 +    window->OnEnterNotifyEvent(event);
  1.5186 +
  1.5187 +    return TRUE;
  1.5188 +}
  1.5189 +
  1.5190 +static gboolean
  1.5191 +leave_notify_event_cb(GtkWidget *widget,
  1.5192 +                      GdkEventCrossing *event)
  1.5193 +{
  1.5194 +    if (is_parent_grab_leave(event)) {
  1.5195 +        return TRUE;
  1.5196 +    }
  1.5197 +
  1.5198 +    // bug 369599: Suppress LeaveNotify events caused by pointer grabs to
  1.5199 +    // avoid generating spurious mouse exit events.
  1.5200 +    gint x = gint(event->x_root);
  1.5201 +    gint y = gint(event->y_root);
  1.5202 +    GdkDisplay* display = gtk_widget_get_display(widget);
  1.5203 +    GdkWindow* winAtPt = gdk_display_get_window_at_pointer(display, &x, &y);
  1.5204 +    if (winAtPt == event->window) {
  1.5205 +        return TRUE;
  1.5206 +    }
  1.5207 +
  1.5208 +    nsRefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
  1.5209 +    if (!window)
  1.5210 +        return TRUE;
  1.5211 +
  1.5212 +    window->OnLeaveNotifyEvent(event);
  1.5213 +
  1.5214 +    return TRUE;
  1.5215 +}
  1.5216 +
  1.5217 +static nsWindow*
  1.5218 +GetFirstNSWindowForGDKWindow(GdkWindow *aGdkWindow)
  1.5219 +{
  1.5220 +    nsWindow* window;
  1.5221 +    while (!(window = get_window_for_gdk_window(aGdkWindow))) {
  1.5222 +        // The event has bubbled to the moz_container widget as passed into each caller's *widget parameter,
  1.5223 +        // but its corresponding nsWindow is an ancestor of the window that we need.  Instead, look at
  1.5224 +        // event->window and find the first ancestor nsWindow of it because event->window may be in a plugin.
  1.5225 +        aGdkWindow = gdk_window_get_parent(aGdkWindow);
  1.5226 +        if (!aGdkWindow) {
  1.5227 +            window = nullptr;
  1.5228 +            break;
  1.5229 +        }
  1.5230 +    }
  1.5231 +    return window;
  1.5232 +}
  1.5233 +
  1.5234 +static gboolean
  1.5235 +motion_notify_event_cb(GtkWidget *widget, GdkEventMotion *event)
  1.5236 +{
  1.5237 +    UpdateLastInputEventTime(event);
  1.5238 +
  1.5239 +    nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
  1.5240 +    if (!window)
  1.5241 +        return FALSE;
  1.5242 +
  1.5243 +    window->OnMotionNotifyEvent(event);
  1.5244 +
  1.5245 +    return TRUE;
  1.5246 +}
  1.5247 +
  1.5248 +static gboolean
  1.5249 +button_press_event_cb(GtkWidget *widget, GdkEventButton *event)
  1.5250 +{
  1.5251 +    UpdateLastInputEventTime(event);
  1.5252 +
  1.5253 +    nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
  1.5254 +    if (!window)
  1.5255 +        return FALSE;
  1.5256 +
  1.5257 +    window->OnButtonPressEvent(event);
  1.5258 +
  1.5259 +    return TRUE;
  1.5260 +}
  1.5261 +
  1.5262 +static gboolean
  1.5263 +button_release_event_cb(GtkWidget *widget, GdkEventButton *event)
  1.5264 +{
  1.5265 +    UpdateLastInputEventTime(event);
  1.5266 +
  1.5267 +    nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
  1.5268 +    if (!window)
  1.5269 +        return FALSE;
  1.5270 +
  1.5271 +    window->OnButtonReleaseEvent(event);
  1.5272 +
  1.5273 +    return TRUE;
  1.5274 +}
  1.5275 +
  1.5276 +static gboolean
  1.5277 +focus_in_event_cb(GtkWidget *widget, GdkEventFocus *event)
  1.5278 +{
  1.5279 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
  1.5280 +    if (!window)
  1.5281 +        return FALSE;
  1.5282 +
  1.5283 +    window->OnContainerFocusInEvent(event);
  1.5284 +
  1.5285 +    return FALSE;
  1.5286 +}
  1.5287 +
  1.5288 +static gboolean
  1.5289 +focus_out_event_cb(GtkWidget *widget, GdkEventFocus *event)
  1.5290 +{
  1.5291 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
  1.5292 +    if (!window)
  1.5293 +        return FALSE;
  1.5294 +
  1.5295 +    window->OnContainerFocusOutEvent(event);
  1.5296 +
  1.5297 +    return FALSE;
  1.5298 +}
  1.5299 +
  1.5300 +#ifdef MOZ_X11
  1.5301 +// For long-lived popup windows that don't really take focus themselves but
  1.5302 +// may have elements that accept keyboard input when the parent window is
  1.5303 +// active, focus is handled specially.  These windows include noautohide
  1.5304 +// panels.  (This special handling is not necessary for temporary popups where
  1.5305 +// the keyboard is grabbed.)
  1.5306 +//
  1.5307 +// Mousing over or clicking on these windows should not cause them to steal
  1.5308 +// focus from their parent windows, so, the input field of WM_HINTS is set to
  1.5309 +// False to request that the window manager not set the input focus to this
  1.5310 +// window.  http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7
  1.5311 +//
  1.5312 +// However, these windows can still receive WM_TAKE_FOCUS messages from the
  1.5313 +// window manager, so they can still detect when the user has indicated that
  1.5314 +// they wish to direct keyboard input at these windows.  When the window
  1.5315 +// manager offers focus to these windows (after a mouse over or click, for
  1.5316 +// example), a request to make the parent window active is issued.  When the
  1.5317 +// parent window becomes active, keyboard events will be received.
  1.5318 +
  1.5319 +static GdkFilterReturn
  1.5320 +popup_take_focus_filter(GdkXEvent *gdk_xevent,
  1.5321 +                        GdkEvent *event,
  1.5322 +                        gpointer data)
  1.5323 +{
  1.5324 +    XEvent* xevent = static_cast<XEvent*>(gdk_xevent);
  1.5325 +    if (xevent->type != ClientMessage)
  1.5326 +        return GDK_FILTER_CONTINUE;
  1.5327 +
  1.5328 +    XClientMessageEvent& xclient = xevent->xclient;
  1.5329 +    if (xclient.message_type != gdk_x11_get_xatom_by_name("WM_PROTOCOLS"))
  1.5330 +        return GDK_FILTER_CONTINUE;
  1.5331 +
  1.5332 +    Atom atom = xclient.data.l[0];
  1.5333 +    if (atom != gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS"))
  1.5334 +        return GDK_FILTER_CONTINUE;
  1.5335 +
  1.5336 +    guint32 timestamp = xclient.data.l[1];
  1.5337 +
  1.5338 +    GtkWidget* widget = get_gtk_widget_for_gdk_window(event->any.window);
  1.5339 +    if (!widget)
  1.5340 +        return GDK_FILTER_CONTINUE;
  1.5341 +
  1.5342 +    GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(widget));
  1.5343 +    if (!parent)
  1.5344 +        return GDK_FILTER_CONTINUE;
  1.5345 +
  1.5346 +    if (gtk_window_is_active(parent))
  1.5347 +        return GDK_FILTER_REMOVE; // leave input focus on the parent
  1.5348 +
  1.5349 +    GdkWindow* parent_window = gtk_widget_get_window(GTK_WIDGET(parent));
  1.5350 +    if (!parent_window)
  1.5351 +        return GDK_FILTER_CONTINUE;
  1.5352 +
  1.5353 +    // In case the parent has not been deconified.
  1.5354 +    gdk_window_show_unraised(parent_window);
  1.5355 +
  1.5356 +    // Request focus on the parent window.
  1.5357 +    // Use gdk_window_focus rather than gtk_window_present to avoid
  1.5358 +    // raising the parent window.
  1.5359 +    gdk_window_focus(parent_window, timestamp);
  1.5360 +    return GDK_FILTER_REMOVE;
  1.5361 +}
  1.5362 +
  1.5363 +static GdkFilterReturn
  1.5364 +plugin_window_filter_func(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
  1.5365 +{
  1.5366 +    GdkWindow  *plugin_window;
  1.5367 +    XEvent     *xevent;
  1.5368 +    Window      xeventWindow;
  1.5369 +
  1.5370 +    nsRefPtr<nsWindow> nswindow = (nsWindow*)data;
  1.5371 +    GdkFilterReturn return_val;
  1.5372 +
  1.5373 +    xevent = (XEvent *)gdk_xevent;
  1.5374 +    return_val = GDK_FILTER_CONTINUE;
  1.5375 +
  1.5376 +    switch (xevent->type)
  1.5377 +    {
  1.5378 +        case CreateNotify:
  1.5379 +        case ReparentNotify:
  1.5380 +            if (xevent->type==CreateNotify) {
  1.5381 +                xeventWindow = xevent->xcreatewindow.window;
  1.5382 +            }
  1.5383 +            else {
  1.5384 +                if (xevent->xreparent.event != xevent->xreparent.parent)
  1.5385 +                    break;
  1.5386 +                xeventWindow = xevent->xreparent.window;
  1.5387 +            }
  1.5388 +#if (MOZ_WIDGET_GTK == 2)
  1.5389 +            plugin_window = gdk_window_lookup(xeventWindow);
  1.5390 +#else
  1.5391 +            plugin_window = gdk_x11_window_lookup_for_display(
  1.5392 +                                  gdk_x11_lookup_xdisplay(xevent->xcreatewindow.display), xeventWindow);
  1.5393 +#endif        
  1.5394 +            if (plugin_window) {
  1.5395 +                GtkWidget *widget =
  1.5396 +                    get_gtk_widget_for_gdk_window(plugin_window);
  1.5397 +
  1.5398 +// TODO GTK3
  1.5399 +#if (MOZ_WIDGET_GTK == 2)
  1.5400 +                if (GTK_IS_XTBIN(widget)) {
  1.5401 +                    nswindow->SetPluginType(nsWindow::PluginType_NONXEMBED);
  1.5402 +                    break;
  1.5403 +                }
  1.5404 +                else 
  1.5405 +#endif
  1.5406 +                if(GTK_IS_SOCKET(widget)) {
  1.5407 +                    if (!g_object_get_data(G_OBJECT(widget), "enable-xt-focus")) {
  1.5408 +                        nswindow->SetPluginType(nsWindow::PluginType_XEMBED);
  1.5409 +                        break;
  1.5410 +                    }
  1.5411 +                }
  1.5412 +            }
  1.5413 +            nswindow->SetPluginType(nsWindow::PluginType_NONXEMBED);
  1.5414 +            return_val = GDK_FILTER_REMOVE;
  1.5415 +            break;
  1.5416 +        case EnterNotify:
  1.5417 +            nswindow->SetNonXEmbedPluginFocus();
  1.5418 +            break;
  1.5419 +        case DestroyNotify:
  1.5420 +            gdk_window_remove_filter
  1.5421 +                ((GdkWindow*)(nswindow->GetNativeData(NS_NATIVE_WINDOW)),
  1.5422 +                 plugin_window_filter_func,
  1.5423 +                 nswindow);
  1.5424 +            // Currently we consider all plugins are non-xembed and calls
  1.5425 +            // LoseNonXEmbedPluginFocus without any checking.
  1.5426 +            nswindow->LoseNonXEmbedPluginFocus();
  1.5427 +            break;
  1.5428 +        default:
  1.5429 +            break;
  1.5430 +    }
  1.5431 +    return return_val;
  1.5432 +}
  1.5433 +
  1.5434 +static GdkFilterReturn
  1.5435 +plugin_client_message_filter(GdkXEvent *gdk_xevent,
  1.5436 +                             GdkEvent *event,
  1.5437 +                             gpointer data)
  1.5438 +{
  1.5439 +    XEvent    *xevent;
  1.5440 +    xevent = (XEvent *)gdk_xevent;
  1.5441 +
  1.5442 +    GdkFilterReturn return_val;
  1.5443 +    return_val = GDK_FILTER_CONTINUE;
  1.5444 +
  1.5445 +    if (!gPluginFocusWindow || xevent->type!=ClientMessage) {
  1.5446 +        return return_val;
  1.5447 +    }
  1.5448 +
  1.5449 +    // When WM sends out WM_TAKE_FOCUS, gtk2 will use XSetInputFocus
  1.5450 +    // to set the focus to the focus proxy. To prevent this happen
  1.5451 +    // while the focus is on the plugin, we filter the WM_TAKE_FOCUS
  1.5452 +    // out.
  1.5453 +    if (gdk_x11_get_xatom_by_name("WM_PROTOCOLS")
  1.5454 +            != xevent->xclient.message_type) {
  1.5455 +        return return_val;
  1.5456 +    }
  1.5457 +
  1.5458 +    if ((Atom) xevent->xclient.data.l[0] ==
  1.5459 +            gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS")) {
  1.5460 +        // block it from gtk2.0 focus proxy
  1.5461 +        return_val = GDK_FILTER_REMOVE;
  1.5462 +    }
  1.5463 +
  1.5464 +    return return_val;
  1.5465 +}
  1.5466 +#endif /* MOZ_X11 */
  1.5467 +
  1.5468 +static gboolean
  1.5469 +key_press_event_cb(GtkWidget *widget, GdkEventKey *event)
  1.5470 +{
  1.5471 +    LOG(("key_press_event_cb\n"));
  1.5472 +
  1.5473 +    UpdateLastInputEventTime(event);
  1.5474 +
  1.5475 +    // find the window with focus and dispatch this event to that widget
  1.5476 +    nsWindow *window = get_window_for_gtk_widget(widget);
  1.5477 +    if (!window)
  1.5478 +        return FALSE;
  1.5479 +
  1.5480 +    nsRefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
  1.5481 +
  1.5482 +#ifdef MOZ_X11
  1.5483 +    // Keyboard repeat can cause key press events to queue up when there are
  1.5484 +    // slow event handlers (bug 301029).  Throttle these events by removing
  1.5485 +    // consecutive pending duplicate KeyPress events to the same window.
  1.5486 +    // We use the event time of the last one.
  1.5487 +    // Note: GDK calls XkbSetDetectableAutorepeat so that KeyRelease events
  1.5488 +    // are generated only when the key is physically released.
  1.5489 +#define NS_GDKEVENT_MATCH_MASK 0x1FFF /* GDK_SHIFT_MASK .. GDK_BUTTON5_MASK */
  1.5490 +    GdkDisplay* gdkDisplay = gtk_widget_get_display(widget);
  1.5491 +    Display* dpy = GDK_DISPLAY_XDISPLAY(gdkDisplay);
  1.5492 +    while (XPending(dpy)) {
  1.5493 +        XEvent next_event;
  1.5494 +        XPeekEvent(dpy, &next_event);
  1.5495 +        GdkWindow* nextGdkWindow =
  1.5496 +            gdk_x11_window_lookup_for_display(gdkDisplay, next_event.xany.window);
  1.5497 +        if (nextGdkWindow != event->window ||
  1.5498 +            next_event.type != KeyPress ||
  1.5499 +            next_event.xkey.keycode != event->hardware_keycode ||
  1.5500 +            next_event.xkey.state != (event->state & NS_GDKEVENT_MATCH_MASK)) {
  1.5501 +            break;
  1.5502 +        }
  1.5503 +        XNextEvent(dpy, &next_event);
  1.5504 +        event->time = next_event.xkey.time;
  1.5505 +    }
  1.5506 +#endif
  1.5507 +
  1.5508 +    return focusWindow->OnKeyPressEvent(event);
  1.5509 +}
  1.5510 +
  1.5511 +static gboolean
  1.5512 +key_release_event_cb(GtkWidget *widget, GdkEventKey *event)
  1.5513 +{
  1.5514 +    LOG(("key_release_event_cb\n"));
  1.5515 +
  1.5516 +    UpdateLastInputEventTime(event);
  1.5517 +
  1.5518 +    // find the window with focus and dispatch this event to that widget
  1.5519 +    nsWindow *window = get_window_for_gtk_widget(widget);
  1.5520 +    if (!window)
  1.5521 +        return FALSE;
  1.5522 +
  1.5523 +    nsRefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
  1.5524 +
  1.5525 +    return focusWindow->OnKeyReleaseEvent(event);
  1.5526 +}
  1.5527 +
  1.5528 +static gboolean
  1.5529 +scroll_event_cb(GtkWidget *widget, GdkEventScroll *event)
  1.5530 +{
  1.5531 +    nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
  1.5532 +    if (!window)
  1.5533 +        return FALSE;
  1.5534 +
  1.5535 +    window->OnScrollEvent(event);
  1.5536 +
  1.5537 +    return TRUE;
  1.5538 +}
  1.5539 +
  1.5540 +static gboolean
  1.5541 +visibility_notify_event_cb (GtkWidget *widget, GdkEventVisibility *event)
  1.5542 +{
  1.5543 +    nsRefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
  1.5544 +    if (!window)
  1.5545 +        return FALSE;
  1.5546 +
  1.5547 +    window->OnVisibilityNotifyEvent(event);
  1.5548 +
  1.5549 +    return TRUE;
  1.5550 +}
  1.5551 +
  1.5552 +static void
  1.5553 +hierarchy_changed_cb (GtkWidget *widget,
  1.5554 +                      GtkWidget *previous_toplevel)
  1.5555 +{
  1.5556 +    GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
  1.5557 +    GdkWindowState old_window_state = GDK_WINDOW_STATE_WITHDRAWN;
  1.5558 +    GdkEventWindowState event;
  1.5559 +
  1.5560 +    event.new_window_state = GDK_WINDOW_STATE_WITHDRAWN;
  1.5561 +
  1.5562 +    if (GTK_IS_WINDOW(previous_toplevel)) {
  1.5563 +        g_signal_handlers_disconnect_by_func(previous_toplevel,
  1.5564 +                                             FuncToGpointer(window_state_event_cb),
  1.5565 +                                             widget);
  1.5566 +        GdkWindow *win = gtk_widget_get_window(previous_toplevel);
  1.5567 +        if (win) {
  1.5568 +            old_window_state = gdk_window_get_state(win);
  1.5569 +        }
  1.5570 +    }
  1.5571 +
  1.5572 +    if (GTK_IS_WINDOW(toplevel)) {
  1.5573 +        g_signal_connect_swapped(toplevel, "window-state-event",
  1.5574 +                                 G_CALLBACK(window_state_event_cb), widget);
  1.5575 +        GdkWindow *win = gtk_widget_get_window(toplevel);
  1.5576 +        if (win) {
  1.5577 +            event.new_window_state = gdk_window_get_state(win);
  1.5578 +        }
  1.5579 +    }
  1.5580 +
  1.5581 +    event.changed_mask = static_cast<GdkWindowState>
  1.5582 +        (old_window_state ^ event.new_window_state);
  1.5583 +
  1.5584 +    if (event.changed_mask) {
  1.5585 +        event.type = GDK_WINDOW_STATE;
  1.5586 +        event.window = nullptr;
  1.5587 +        event.send_event = TRUE;
  1.5588 +        window_state_event_cb(widget, &event);
  1.5589 +    }
  1.5590 +}
  1.5591 +
  1.5592 +static gboolean
  1.5593 +window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event)
  1.5594 +{
  1.5595 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
  1.5596 +    if (!window)
  1.5597 +        return FALSE;
  1.5598 +
  1.5599 +    window->OnWindowStateEvent(widget, event);
  1.5600 +
  1.5601 +    return FALSE;
  1.5602 +}
  1.5603 +
  1.5604 +static void
  1.5605 +theme_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data)
  1.5606 +{
  1.5607 +    nsRefPtr<nsWindow> window = data;
  1.5608 +    window->ThemeChanged();
  1.5609 +}
  1.5610 +
  1.5611 +//////////////////////////////////////////////////////////////////////
  1.5612 +// These are all of our drag and drop operations
  1.5613 +
  1.5614 +void
  1.5615 +nsWindow::InitDragEvent(WidgetDragEvent &aEvent)
  1.5616 +{
  1.5617 +    // set the keyboard modifiers
  1.5618 +    guint modifierState = KeymapWrapper::GetCurrentModifierState();
  1.5619 +    KeymapWrapper::InitInputEvent(aEvent, modifierState);
  1.5620 +}
  1.5621 +
  1.5622 +static gboolean
  1.5623 +drag_motion_event_cb(GtkWidget *aWidget,
  1.5624 +                     GdkDragContext *aDragContext,
  1.5625 +                     gint aX,
  1.5626 +                     gint aY,
  1.5627 +                     guint aTime,
  1.5628 +                     gpointer aData)
  1.5629 +{
  1.5630 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
  1.5631 +    if (!window)
  1.5632 +        return FALSE;
  1.5633 +
  1.5634 +    // figure out which internal widget this drag motion actually happened on
  1.5635 +    nscoord retx = 0;
  1.5636 +    nscoord rety = 0;
  1.5637 +
  1.5638 +    GdkWindow *innerWindow =
  1.5639 +        get_inner_gdk_window(gtk_widget_get_window(aWidget), aX, aY,
  1.5640 +                             &retx, &rety);
  1.5641 +    nsRefPtr<nsWindow> innerMostWindow = get_window_for_gdk_window(innerWindow);
  1.5642 +
  1.5643 +    if (!innerMostWindow) {
  1.5644 +        innerMostWindow = window;
  1.5645 +    }
  1.5646 +
  1.5647 +    LOGDRAG(("nsWindow drag-motion signal for %p\n", (void*)innerMostWindow));
  1.5648 +
  1.5649 +    return nsDragService::GetInstance()->
  1.5650 +        ScheduleMotionEvent(innerMostWindow, aDragContext,
  1.5651 +                            nsIntPoint(retx, rety), aTime);
  1.5652 +}
  1.5653 +
  1.5654 +static void
  1.5655 +drag_leave_event_cb(GtkWidget *aWidget,
  1.5656 +                    GdkDragContext *aDragContext,
  1.5657 +                    guint aTime,
  1.5658 +                    gpointer aData)
  1.5659 +{
  1.5660 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
  1.5661 +    if (!window)
  1.5662 +        return;
  1.5663 +
  1.5664 +    nsDragService *dragService = nsDragService::GetInstance();
  1.5665 +
  1.5666 +    nsWindow *mostRecentDragWindow = dragService->GetMostRecentDestWindow();
  1.5667 +    if (!mostRecentDragWindow) {
  1.5668 +        // This can happen when the target will not accept a drop.  A GTK drag
  1.5669 +        // source sends the leave message to the destination before the
  1.5670 +        // drag-failed signal on the source widget, but the leave message goes
  1.5671 +        // via the X server, and so doesn't get processed at least until the
  1.5672 +        // event loop runs again.
  1.5673 +        return;
  1.5674 +    }
  1.5675 +
  1.5676 +    GtkWidget *mozContainer = mostRecentDragWindow->GetMozContainerWidget();
  1.5677 +    if (aWidget != mozContainer)
  1.5678 +    {
  1.5679 +        // When the drag moves between widgets, GTK can send leave signal for
  1.5680 +        // the old widget after the motion or drop signal for the new widget.
  1.5681 +        // We'll send the leave event when the motion or drop event is run.
  1.5682 +        return;
  1.5683 +    }
  1.5684 +
  1.5685 +    LOGDRAG(("nsWindow drag-leave signal for %p\n",
  1.5686 +             (void*)mostRecentDragWindow));
  1.5687 +
  1.5688 +    dragService->ScheduleLeaveEvent();
  1.5689 +}
  1.5690 +
  1.5691 +
  1.5692 +static gboolean
  1.5693 +drag_drop_event_cb(GtkWidget *aWidget,
  1.5694 +                   GdkDragContext *aDragContext,
  1.5695 +                   gint aX,
  1.5696 +                   gint aY,
  1.5697 +                   guint aTime,
  1.5698 +                   gpointer aData)
  1.5699 +{
  1.5700 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
  1.5701 +    if (!window)
  1.5702 +        return FALSE;
  1.5703 +
  1.5704 +    // figure out which internal widget this drag motion actually happened on
  1.5705 +    nscoord retx = 0;
  1.5706 +    nscoord rety = 0;
  1.5707 +
  1.5708 +    GdkWindow *innerWindow =
  1.5709 +        get_inner_gdk_window(gtk_widget_get_window(aWidget), aX, aY,
  1.5710 +                             &retx, &rety);
  1.5711 +    nsRefPtr<nsWindow> innerMostWindow = get_window_for_gdk_window(innerWindow);
  1.5712 +
  1.5713 +    if (!innerMostWindow) {
  1.5714 +        innerMostWindow = window;
  1.5715 +    }
  1.5716 +
  1.5717 +    LOGDRAG(("nsWindow drag-drop signal for %p\n", (void*)innerMostWindow));
  1.5718 +
  1.5719 +    return nsDragService::GetInstance()->
  1.5720 +        ScheduleDropEvent(innerMostWindow, aDragContext,
  1.5721 +                          nsIntPoint(retx, rety), aTime);
  1.5722 +}
  1.5723 +
  1.5724 +static void
  1.5725 +drag_data_received_event_cb(GtkWidget *aWidget,
  1.5726 +                            GdkDragContext *aDragContext,
  1.5727 +                            gint aX,
  1.5728 +                            gint aY,
  1.5729 +                            GtkSelectionData  *aSelectionData,
  1.5730 +                            guint aInfo,
  1.5731 +                            guint aTime,
  1.5732 +                            gpointer aData)
  1.5733 +{
  1.5734 +    nsRefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
  1.5735 +    if (!window)
  1.5736 +        return;
  1.5737 +
  1.5738 +    window->OnDragDataReceivedEvent(aWidget,
  1.5739 +                                    aDragContext,
  1.5740 +                                    aX, aY,
  1.5741 +                                    aSelectionData,
  1.5742 +                                    aInfo, aTime, aData);
  1.5743 +}
  1.5744 +
  1.5745 +static nsresult
  1.5746 +initialize_prefs(void)
  1.5747 +{
  1.5748 +    gRaiseWindows =
  1.5749 +        Preferences::GetBool("mozilla.widget.raise-on-setfocus", true);
  1.5750 +
  1.5751 +    return NS_OK;
  1.5752 +}
  1.5753 +
  1.5754 +static GdkWindow *
  1.5755 +get_inner_gdk_window (GdkWindow *aWindow,
  1.5756 +                      gint x, gint y,
  1.5757 +                      gint *retx, gint *rety)
  1.5758 +{
  1.5759 +    gint cx, cy, cw, ch;
  1.5760 +    GList *children = gdk_window_peek_children(aWindow);
  1.5761 +    for (GList *child = g_list_last(children);
  1.5762 +         child;
  1.5763 +         child = g_list_previous(child)) {
  1.5764 +        GdkWindow *childWindow = (GdkWindow *) child->data;
  1.5765 +        if (get_window_for_gdk_window(childWindow)) {
  1.5766 +#if (MOZ_WIDGET_GTK == 2)
  1.5767 +            gdk_window_get_geometry(childWindow, &cx, &cy, &cw, &ch, nullptr);
  1.5768 +#else
  1.5769 +            gdk_window_get_geometry(childWindow, &cx, &cy, &cw, &ch);
  1.5770 +#endif
  1.5771 +            if ((cx < x) && (x < (cx + cw)) &&
  1.5772 +                (cy < y) && (y < (cy + ch)) &&
  1.5773 +                gdk_window_is_visible(childWindow)) {
  1.5774 +                return get_inner_gdk_window(childWindow,
  1.5775 +                                            x - cx, y - cy,
  1.5776 +                                            retx, rety);
  1.5777 +            }
  1.5778 +        }
  1.5779 +    }
  1.5780 +    *retx = x;
  1.5781 +    *rety = y;
  1.5782 +    return aWindow;
  1.5783 +}
  1.5784 +
  1.5785 +static inline bool
  1.5786 +is_context_menu_key(const WidgetKeyboardEvent& aKeyEvent)
  1.5787 +{
  1.5788 +    return ((aKeyEvent.keyCode == NS_VK_F10 && aKeyEvent.IsShift() &&
  1.5789 +             !aKeyEvent.IsControl() && !aKeyEvent.IsMeta() &&
  1.5790 +             !aKeyEvent.IsAlt()) ||
  1.5791 +            (aKeyEvent.keyCode == NS_VK_CONTEXT_MENU && !aKeyEvent.IsShift() &&
  1.5792 +             !aKeyEvent.IsControl() && !aKeyEvent.IsMeta() &&
  1.5793 +             !aKeyEvent.IsAlt()));
  1.5794 +}
  1.5795 +
  1.5796 +static int
  1.5797 +is_parent_ungrab_enter(GdkEventCrossing *aEvent)
  1.5798 +{
  1.5799 +    return (GDK_CROSSING_UNGRAB == aEvent->mode) &&
  1.5800 +        ((GDK_NOTIFY_ANCESTOR == aEvent->detail) ||
  1.5801 +         (GDK_NOTIFY_VIRTUAL == aEvent->detail));
  1.5802 +
  1.5803 +}
  1.5804 +
  1.5805 +static int
  1.5806 +is_parent_grab_leave(GdkEventCrossing *aEvent)
  1.5807 +{
  1.5808 +    return (GDK_CROSSING_GRAB == aEvent->mode) &&
  1.5809 +        ((GDK_NOTIFY_ANCESTOR == aEvent->detail) ||
  1.5810 +            (GDK_NOTIFY_VIRTUAL == aEvent->detail));
  1.5811 +}
  1.5812 +
  1.5813 +#ifdef ACCESSIBILITY
  1.5814 +void
  1.5815 +nsWindow::CreateRootAccessible()
  1.5816 +{
  1.5817 +    if (mIsTopLevel && !mRootAccessible) {
  1.5818 +        LOG(("nsWindow:: Create Toplevel Accessibility\n"));
  1.5819 +        mRootAccessible = GetRootAccessible();
  1.5820 +    }
  1.5821 +}
  1.5822 +
  1.5823 +void
  1.5824 +nsWindow::DispatchEventToRootAccessible(uint32_t aEventType)
  1.5825 +{
  1.5826 +    if (!a11y::ShouldA11yBeEnabled()) {
  1.5827 +        return;
  1.5828 +    }
  1.5829 +
  1.5830 +    nsCOMPtr<nsIAccessibilityService> accService =
  1.5831 +        do_GetService("@mozilla.org/accessibilityService;1");
  1.5832 +    if (!accService) {
  1.5833 +        return;
  1.5834 +    }
  1.5835 +
  1.5836 +    // Get the root document accessible and fire event to it.
  1.5837 +    a11y::Accessible* acc = GetRootAccessible();
  1.5838 +    if (acc) {
  1.5839 +        accService->FireAccessibleEvent(aEventType, acc);
  1.5840 +    }
  1.5841 +}
  1.5842 +
  1.5843 +void
  1.5844 +nsWindow::DispatchActivateEventAccessible(void)
  1.5845 +{
  1.5846 +    DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE);
  1.5847 +}
  1.5848 +
  1.5849 +void
  1.5850 +nsWindow::DispatchDeactivateEventAccessible(void)
  1.5851 +{
  1.5852 +    DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE);
  1.5853 +}
  1.5854 +
  1.5855 +void
  1.5856 +nsWindow::DispatchMaximizeEventAccessible(void)
  1.5857 +{
  1.5858 +    DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE);
  1.5859 +}
  1.5860 +
  1.5861 +void
  1.5862 +nsWindow::DispatchMinimizeEventAccessible(void)
  1.5863 +{
  1.5864 +    DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE);
  1.5865 +}
  1.5866 +
  1.5867 +void
  1.5868 +nsWindow::DispatchRestoreEventAccessible(void)
  1.5869 +{
  1.5870 +    DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_RESTORE);
  1.5871 +}
  1.5872 +
  1.5873 +#endif /* #ifdef ACCESSIBILITY */
  1.5874 +
  1.5875 +// nsChildWindow class
  1.5876 +
  1.5877 +nsChildWindow::nsChildWindow()
  1.5878 +{
  1.5879 +}
  1.5880 +
  1.5881 +nsChildWindow::~nsChildWindow()
  1.5882 +{
  1.5883 +}
  1.5884 +
  1.5885 +NS_IMETHODIMP
  1.5886 +nsWindow::NotifyIME(const IMENotification& aIMENotification)
  1.5887 +{
  1.5888 +    if (MOZ_UNLIKELY(!mIMModule)) {
  1.5889 +        switch (aIMENotification.mMessage) {
  1.5890 +            case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
  1.5891 +            case REQUEST_TO_COMMIT_COMPOSITION:
  1.5892 +            case REQUEST_TO_CANCEL_COMPOSITION:
  1.5893 +            case NOTIFY_IME_OF_FOCUS:
  1.5894 +            case NOTIFY_IME_OF_BLUR:
  1.5895 +              return NS_ERROR_NOT_AVAILABLE;
  1.5896 +            default:
  1.5897 +              break;
  1.5898 +        }
  1.5899 +    }
  1.5900 +    switch (aIMENotification.mMessage) {
  1.5901 +        // TODO: We should replace NOTIFY_IME_OF_CURSOR_POS_CHANGED with
  1.5902 +        //       NOTIFY_IME_OF_SELECTION_CHANGE.  The required behavior is
  1.5903 +        //       really different from committing composition.
  1.5904 +        case NOTIFY_IME_OF_CURSOR_POS_CHANGED:
  1.5905 +        case REQUEST_TO_COMMIT_COMPOSITION:
  1.5906 +            return mIMModule->CommitIMEComposition(this);
  1.5907 +        case REQUEST_TO_CANCEL_COMPOSITION:
  1.5908 +            return mIMModule->CancelIMEComposition(this);
  1.5909 +        case NOTIFY_IME_OF_FOCUS:
  1.5910 +            mIMModule->OnFocusChangeInGecko(true);
  1.5911 +            return NS_OK;
  1.5912 +        case NOTIFY_IME_OF_BLUR:
  1.5913 +            mIMModule->OnFocusChangeInGecko(false);
  1.5914 +            return NS_OK;
  1.5915 +        case NOTIFY_IME_OF_COMPOSITION_UPDATE:
  1.5916 +            mIMModule->OnUpdateComposition();
  1.5917 +            return NS_OK;
  1.5918 +        default:
  1.5919 +            return NS_ERROR_NOT_IMPLEMENTED;
  1.5920 +    }
  1.5921 +}
  1.5922 +
  1.5923 +NS_IMETHODIMP_(void)
  1.5924 +nsWindow::SetInputContext(const InputContext& aContext,
  1.5925 +                          const InputContextAction& aAction)
  1.5926 +{
  1.5927 +    if (!mIMModule) {
  1.5928 +        return;
  1.5929 +    }
  1.5930 +    mIMModule->SetInputContext(this, &aContext, &aAction);
  1.5931 +}
  1.5932 +
  1.5933 +NS_IMETHODIMP_(InputContext)
  1.5934 +nsWindow::GetInputContext()
  1.5935 +{
  1.5936 +  InputContext context;
  1.5937 +  if (!mIMModule) {
  1.5938 +      context.mIMEState.mEnabled = IMEState::DISABLED;
  1.5939 +      context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
  1.5940 +      // If IME context isn't available on this widget, we should set |this|
  1.5941 +      // instead of nullptr since nullptr means that the platform has only one
  1.5942 +      // context per process.
  1.5943 +      context.mNativeIMEContext = this;
  1.5944 +  } else {
  1.5945 +      context = mIMModule->GetInputContext();
  1.5946 +      context.mNativeIMEContext = mIMModule;
  1.5947 +  }
  1.5948 +  return context;
  1.5949 +}
  1.5950 +
  1.5951 +NS_IMETHODIMP_(bool)
  1.5952 +nsWindow::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
  1.5953 +                                  const WidgetKeyboardEvent& aEvent,
  1.5954 +                                  DoCommandCallback aCallback,
  1.5955 +                                  void* aCallbackData)
  1.5956 +{
  1.5957 +    NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
  1.5958 +    return keyBindings->Execute(aEvent, aCallback, aCallbackData);
  1.5959 +}
  1.5960 +
  1.5961 +NS_IMETHODIMP
  1.5962 +nsWindow::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState)
  1.5963 +{
  1.5964 +    NS_ENSURE_ARG_POINTER(aLEDState);
  1.5965 +
  1.5966 +    KeymapWrapper::Modifiers modifier;
  1.5967 +    switch (aKeyCode) {
  1.5968 +        case NS_VK_CAPS_LOCK:   modifier = KeymapWrapper::CAPS_LOCK;   break;
  1.5969 +        case NS_VK_NUM_LOCK:    modifier = KeymapWrapper::NUM_LOCK;    break;
  1.5970 +        case NS_VK_SCROLL_LOCK: modifier = KeymapWrapper::SCROLL_LOCK; break;
  1.5971 +        default: return NS_ERROR_INVALID_ARG;
  1.5972 +    }
  1.5973 +
  1.5974 +    *aLEDState =
  1.5975 +        KeymapWrapper::AreModifiersCurrentlyActive(modifier);
  1.5976 +    return NS_OK;
  1.5977 +}
  1.5978 +
  1.5979 +#if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
  1.5980 +/* static */ already_AddRefed<gfxASurface>
  1.5981 +nsWindow::GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
  1.5982 +                                   const nsIntSize& aSize)
  1.5983 +{
  1.5984 +    GdkVisual* visual = gdk_drawable_get_visual(aDrawable);
  1.5985 +    Screen* xScreen =
  1.5986 +        gdk_x11_screen_get_xscreen(gdk_drawable_get_screen(aDrawable));
  1.5987 +    Display* xDisplay = DisplayOfScreen(xScreen);
  1.5988 +    Drawable xDrawable = gdk_x11_drawable_get_xid(aDrawable);
  1.5989 +
  1.5990 +    nsRefPtr<gfxASurface> result;
  1.5991 +
  1.5992 +    if (visual) {
  1.5993 +        Visual* xVisual = gdk_x11_visual_get_xvisual(visual);
  1.5994 +
  1.5995 +        result = new gfxXlibSurface(xDisplay, xDrawable, xVisual,
  1.5996 +                                    gfxIntSize(aSize.width, aSize.height));
  1.5997 +    } else {
  1.5998 +        // no visual? we must be using an xrender format.  Find a format
  1.5999 +        // for this depth.
  1.6000 +        XRenderPictFormat *pf = nullptr;
  1.6001 +        switch (gdk_drawable_get_depth(aDrawable)) {
  1.6002 +            case 32:
  1.6003 +                pf = XRenderFindStandardFormat(xDisplay, PictStandardARGB32);
  1.6004 +                break;
  1.6005 +            case 24:
  1.6006 +                pf = XRenderFindStandardFormat(xDisplay, PictStandardRGB24);
  1.6007 +                break;
  1.6008 +            default:
  1.6009 +                NS_ERROR("Don't know how to handle the given depth!");
  1.6010 +                break;
  1.6011 +        }
  1.6012 +
  1.6013 +        result = new gfxXlibSurface(xScreen, xDrawable, pf,
  1.6014 +                                    gfxIntSize(aSize.width, aSize.height));
  1.6015 +    }
  1.6016 +
  1.6017 +    return result.forget();
  1.6018 +}
  1.6019 +#endif
  1.6020 +
  1.6021 +TemporaryRef<DrawTarget>
  1.6022 +nsWindow::StartRemoteDrawing()
  1.6023 +{
  1.6024 +#if (MOZ_WIDGET_GTK == 2)
  1.6025 +  gfxASurface *surf = GetThebesSurface();
  1.6026 +#else
  1.6027 +  // TODO GTK3
  1.6028 +  gfxASurface *surf = nullptr;
  1.6029 +#endif
  1.6030 +  if (!surf) {
  1.6031 +    return nullptr;
  1.6032 +  }
  1.6033 +
  1.6034 +  IntSize size(surf->GetSize().width, surf->GetSize().height);
  1.6035 +  if (size.width <= 0 || size.height <= 0) {
  1.6036 +    return nullptr;
  1.6037 +  }
  1.6038 +
  1.6039 +  return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, size);
  1.6040 +}
  1.6041 +
  1.6042 +// return the gfxASurface for rendering to this widget
  1.6043 +gfxASurface*
  1.6044 +#if (MOZ_WIDGET_GTK == 2)
  1.6045 +nsWindow::GetThebesSurface()
  1.6046 +#else
  1.6047 +nsWindow::GetThebesSurface(cairo_t *cr)
  1.6048 +#endif
  1.6049 +{
  1.6050 +    if (!mGdkWindow)
  1.6051 +        return nullptr;
  1.6052 +
  1.6053 +#if (MOZ_WIDGET_GTK != 2)
  1.6054 +    cairo_surface_t *surf = cairo_get_target(cr);
  1.6055 +    if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
  1.6056 +      NS_NOTREACHED("Missing cairo target?");
  1.6057 +      return nullptr;
  1.6058 +    }
  1.6059 +#endif // MOZ_WIDGET_GTK2
  1.6060 +
  1.6061 +#ifdef MOZ_X11
  1.6062 +    gint width, height;
  1.6063 +
  1.6064 +#if (MOZ_WIDGET_GTK == 2)
  1.6065 +    gdk_drawable_get_size(GDK_DRAWABLE(mGdkWindow), &width, &height);
  1.6066 +#else
  1.6067 +    width = gdk_window_get_width(mGdkWindow);
  1.6068 +    height = gdk_window_get_height(mGdkWindow);
  1.6069 +#endif
  1.6070 +
  1.6071 +    // Owen Taylor says this is the right thing to do!
  1.6072 +    width = std::min(32767, width);
  1.6073 +    height = std::min(32767, height);
  1.6074 +    gfxIntSize size(width, height);
  1.6075 +
  1.6076 +    GdkVisual *gdkVisual = gdk_window_get_visual(mGdkWindow);
  1.6077 +    Visual* visual = gdk_x11_visual_get_xvisual(gdkVisual);
  1.6078 +
  1.6079 +#  ifdef MOZ_HAVE_SHMIMAGE
  1.6080 +    bool usingShm = false;
  1.6081 +    if (nsShmImage::UseShm()) {
  1.6082 +        // EnsureShmImage() is a dangerous interface, but we guarantee
  1.6083 +        // that the thebes surface and the shmimage have the same
  1.6084 +        // lifetime
  1.6085 +        mThebesSurface =
  1.6086 +            nsShmImage::EnsureShmImage(size,
  1.6087 +                                       visual, gdk_visual_get_depth(gdkVisual),
  1.6088 +                                       mShmImage);
  1.6089 +        usingShm = mThebesSurface != nullptr;
  1.6090 +    }
  1.6091 +    if (!usingShm)
  1.6092 +#  endif  // MOZ_HAVE_SHMIMAGE
  1.6093 +
  1.6094 +#if (MOZ_WIDGET_GTK == 2)
  1.6095 +    mThebesSurface = new gfxXlibSurface
  1.6096 +        (GDK_WINDOW_XDISPLAY(mGdkWindow),
  1.6097 +         gdk_x11_window_get_xid(mGdkWindow),
  1.6098 +         visual,
  1.6099 +         size);
  1.6100 +#else
  1.6101 +#if MOZ_TREE_CAIRO
  1.6102 +#error "cairo-gtk3 target must be built with --enable-system-cairo"
  1.6103 +#else
  1.6104 +    mThebesSurface = gfxASurface::Wrap(surf);
  1.6105 +#endif
  1.6106 +#endif
  1.6107 +
  1.6108 +#endif
  1.6109 +
  1.6110 +    // if the surface creation is reporting an error, then
  1.6111 +    // we don't have a surface to give back
  1.6112 +    if (mThebesSurface && mThebesSurface->CairoStatus() != 0) {
  1.6113 +        mThebesSurface = nullptr;
  1.6114 +    }
  1.6115 +
  1.6116 +    return mThebesSurface;
  1.6117 +}
  1.6118 +
  1.6119 +// Code shared begin BeginMoveDrag and BeginResizeDrag
  1.6120 +bool
  1.6121 +nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent,
  1.6122 +                      GdkWindow** aWindow, gint* aButton,
  1.6123 +                      gint* aRootX, gint* aRootY)
  1.6124 +{
  1.6125 +    if (aMouseEvent->button != WidgetMouseEvent::eLeftButton) {
  1.6126 +        // we can only begin a move drag with the left mouse button
  1.6127 +        return false;
  1.6128 +    }
  1.6129 +    *aButton = 1;
  1.6130 +
  1.6131 +    // get the gdk window for this widget
  1.6132 +    GdkWindow* gdk_window = mGdkWindow;
  1.6133 +    if (!gdk_window) {
  1.6134 +        return false;
  1.6135 +    }
  1.6136 +    NS_ABORT_IF_FALSE(GDK_IS_WINDOW(gdk_window), "must really be window");
  1.6137 +
  1.6138 +    // find the top-level window
  1.6139 +    gdk_window = gdk_window_get_toplevel(gdk_window);
  1.6140 +    NS_ABORT_IF_FALSE(gdk_window,
  1.6141 +                      "gdk_window_get_toplevel should not return null");
  1.6142 +    *aWindow = gdk_window;
  1.6143 +
  1.6144 +    if (!aMouseEvent->widget) {
  1.6145 +        return false;
  1.6146 +    }
  1.6147 +
  1.6148 +    // FIXME: It would be nice to have the widget position at the time
  1.6149 +    // of the event, but it's relatively unlikely that the widget has
  1.6150 +    // moved since the mousedown.  (On the other hand, it's quite likely
  1.6151 +    // that the mouse has moved, which is why we use the mouse position
  1.6152 +    // from the event.)
  1.6153 +    nsIntPoint offset = aMouseEvent->widget->WidgetToScreenOffset();
  1.6154 +    *aRootX = aMouseEvent->refPoint.x + offset.x;
  1.6155 +    *aRootY = aMouseEvent->refPoint.y + offset.y;
  1.6156 +
  1.6157 +    return true;
  1.6158 +}
  1.6159 +
  1.6160 +NS_IMETHODIMP
  1.6161 +nsWindow::BeginMoveDrag(WidgetMouseEvent* aEvent)
  1.6162 +{
  1.6163 +    NS_ABORT_IF_FALSE(aEvent, "must have event");
  1.6164 +    NS_ABORT_IF_FALSE(aEvent->eventStructType == NS_MOUSE_EVENT,
  1.6165 +                      "event must have correct struct type");
  1.6166 +
  1.6167 +    GdkWindow *gdk_window;
  1.6168 +    gint button, screenX, screenY;
  1.6169 +    if (!GetDragInfo(aEvent, &gdk_window, &button, &screenX, &screenY)) {
  1.6170 +        return NS_ERROR_FAILURE;
  1.6171 +    }
  1.6172 +
  1.6173 +    // tell the window manager to start the move
  1.6174 +    gdk_window_begin_move_drag(gdk_window, button, screenX, screenY,
  1.6175 +                               aEvent->time);
  1.6176 +
  1.6177 +    return NS_OK;
  1.6178 +}
  1.6179 +
  1.6180 +NS_IMETHODIMP
  1.6181 +nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent,
  1.6182 +                          int32_t aHorizontal,
  1.6183 +                          int32_t aVertical)
  1.6184 +{
  1.6185 +    NS_ENSURE_ARG_POINTER(aEvent);
  1.6186 +
  1.6187 +    if (aEvent->eventStructType != NS_MOUSE_EVENT) {
  1.6188 +        // you can only begin a resize drag with a mouse event
  1.6189 +        return NS_ERROR_INVALID_ARG;
  1.6190 +    }
  1.6191 +
  1.6192 +    GdkWindow *gdk_window;
  1.6193 +    gint button, screenX, screenY;
  1.6194 +    if (!GetDragInfo(aEvent->AsMouseEvent(), &gdk_window, &button,
  1.6195 +                     &screenX, &screenY)) {
  1.6196 +        return NS_ERROR_FAILURE;
  1.6197 +    }
  1.6198 +
  1.6199 +    // work out what GdkWindowEdge we're talking about
  1.6200 +    GdkWindowEdge window_edge;
  1.6201 +    if (aVertical < 0) {
  1.6202 +        if (aHorizontal < 0) {
  1.6203 +            window_edge = GDK_WINDOW_EDGE_NORTH_WEST;
  1.6204 +        } else if (aHorizontal == 0) {
  1.6205 +            window_edge = GDK_WINDOW_EDGE_NORTH;
  1.6206 +        } else {
  1.6207 +            window_edge = GDK_WINDOW_EDGE_NORTH_EAST;
  1.6208 +        }
  1.6209 +    } else if (aVertical == 0) {
  1.6210 +        if (aHorizontal < 0) {
  1.6211 +            window_edge = GDK_WINDOW_EDGE_WEST;
  1.6212 +        } else if (aHorizontal == 0) {
  1.6213 +            return NS_ERROR_INVALID_ARG;
  1.6214 +        } else {
  1.6215 +            window_edge = GDK_WINDOW_EDGE_EAST;
  1.6216 +        }
  1.6217 +    } else {
  1.6218 +        if (aHorizontal < 0) {
  1.6219 +            window_edge = GDK_WINDOW_EDGE_SOUTH_WEST;
  1.6220 +        } else if (aHorizontal == 0) {
  1.6221 +            window_edge = GDK_WINDOW_EDGE_SOUTH;
  1.6222 +        } else {
  1.6223 +            window_edge = GDK_WINDOW_EDGE_SOUTH_EAST;
  1.6224 +        }
  1.6225 +    }
  1.6226 +
  1.6227 +    // tell the window manager to start the resize
  1.6228 +    gdk_window_begin_resize_drag(gdk_window, window_edge, button,
  1.6229 +                                 screenX, screenY, aEvent->time);
  1.6230 +
  1.6231 +    return NS_OK;
  1.6232 +}
  1.6233 +
  1.6234 +nsIWidget::LayerManager*
  1.6235 +nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
  1.6236 +                          LayersBackend aBackendHint,
  1.6237 +                          LayerManagerPersistence aPersistence,
  1.6238 +                          bool* aAllowRetaining)
  1.6239 +{
  1.6240 +    if (!mLayerManager && eTransparencyTransparent == GetTransparencyMode()) {
  1.6241 +        mLayerManager = CreateBasicLayerManager();
  1.6242 +    }
  1.6243 +
  1.6244 +    return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint,
  1.6245 +                                         aPersistence, aAllowRetaining);
  1.6246 +}
  1.6247 +
  1.6248 +void
  1.6249 +nsWindow::ClearCachedResources()
  1.6250 +{
  1.6251 +    if (mLayerManager &&
  1.6252 +        mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC) {
  1.6253 +        mLayerManager->ClearCachedResources();
  1.6254 +    }
  1.6255 +
  1.6256 +    GList* children = gdk_window_peek_children(mGdkWindow);
  1.6257 +    for (GList* list = children; list; list = list->next) {
  1.6258 +        nsWindow* window = get_window_for_gdk_window(GDK_WINDOW(list->data));
  1.6259 +        if (window) {
  1.6260 +            window->ClearCachedResources();
  1.6261 +        }
  1.6262 +    }
  1.6263 +}
  1.6264 +
  1.6265 +nsresult
  1.6266 +nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
  1.6267 +                                     uint32_t aNativeMessage,
  1.6268 +                                     uint32_t aModifierFlags)
  1.6269 +{
  1.6270 +  if (!mGdkWindow) {
  1.6271 +    return NS_OK;
  1.6272 +  }
  1.6273 +
  1.6274 +  GdkDisplay* display = gdk_window_get_display(mGdkWindow);
  1.6275 +
  1.6276 +  // When a button-release event is requested, create it here and put it in the
  1.6277 +  // event queue. This will not emit a motion event - this needs to be done
  1.6278 +  // explicitly *before* requesting a button-release. You will also need to wait
  1.6279 +  // for the motion event to be dispatched before requesting a button-release
  1.6280 +  // event to maintain the desired event order.
  1.6281 +  if (aNativeMessage == GDK_BUTTON_RELEASE) {
  1.6282 +    GdkEvent event;
  1.6283 +    memset(&event, 0, sizeof(GdkEvent));
  1.6284 +    event.type = (GdkEventType)aNativeMessage;
  1.6285 +    event.button.button = 1;
  1.6286 +    event.button.window = mGdkWindow;
  1.6287 +    event.button.time = GDK_CURRENT_TIME;
  1.6288 +
  1.6289 +#if (MOZ_WIDGET_GTK == 3)
  1.6290 +    // Get device for event source
  1.6291 +    GdkDeviceManager *device_manager = gdk_display_get_device_manager(display);
  1.6292 +    event.button.device = gdk_device_manager_get_client_pointer(device_manager);
  1.6293 +#endif
  1.6294 +
  1.6295 +    gdk_event_put(&event);
  1.6296 +  } else {
  1.6297 +    // We don't support specific events other than button-release. In case
  1.6298 +    // aNativeMessage != GDK_BUTTON_RELEASE we'll synthesize a motion event
  1.6299 +    // that will be emitted by gdk_display_warp_pointer().
  1.6300 +    GdkScreen* screen = gdk_window_get_screen(mGdkWindow);
  1.6301 +    gdk_display_warp_pointer(display, screen, aPoint.x, aPoint.y);
  1.6302 +  }
  1.6303 +
  1.6304 +  return NS_OK;
  1.6305 +}

mercurial