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(®ion); 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", >kLibrary); 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 ®ion = 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 +}