1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/ArrayUtils.h"
9 #include "mozilla/MiscEvents.h"
10 #include "mozilla/MouseEvents.h"
11 #include "mozilla/TextEvents.h"
15 #include "nsGTKToolkit.h"
16 #include "nsIRollupListener.h"
17 #include "nsIDOMNode.h"
19 #include "nsWidgetsCID.h"
20 #include "nsDragService.h"
21 #include "nsIWidgetListener.h"
23 #include "nsGtkKeyUtils.h"
24 #include "nsGtkCursors.h"
27 #if (MOZ_WIDGET_GTK == 3)
32 #include <X11/Xatom.h>
33 #include <X11/extensions/XShm.h>
34 #include <X11/extensions/shape.h>
35 #if (MOZ_WIDGET_GTK == 3)
36 #include <gdk/gdkkeysyms-compat.h>
40 #include <X11/keysym.h>
42 #include <X11/XF86keysym.h>
45 #if (MOZ_WIDGET_GTK == 2)
46 #include "gtk2xtbin.h"
49 #include <gdk/gdkkeysyms.h>
50 #if (MOZ_WIDGET_GTK == 2)
51 #include <gtk/gtkprivate.h>
54 #include "nsGkAtoms.h"
56 #ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
57 #define SN_API_NOT_YET_FROZEN
58 #include <startup-notification-1.0/libsn/sn.h>
61 #include "mozilla/Likely.h"
62 #include "mozilla/Preferences.h"
63 #include "nsIPrefService.h"
64 #include "nsIGConfService.h"
65 #include "nsIServiceManager.h"
66 #include "nsIStringBundle.h"
67 #include "nsGfxCIID.h"
68 #include "nsGtkUtils.h"
69 #include "nsIObserverService.h"
70 #include "mozilla/layers/LayersTypes.h"
71 #include "nsIIdleServiceInternal.h"
72 #include "nsIPropertyBag2.h"
73 #include "GLContext.h"
74 #include "gfx2DGlue.h"
77 #include "mozilla/a11y/Accessible.h"
78 #include "mozilla/a11y/Platform.h"
79 #include "nsAccessibilityService.h"
81 using namespace mozilla
;
82 using namespace mozilla::widget
;
86 #include "nsAppDirectoryServiceDefs.h"
87 #include "nsXPIDLString.h"
90 /* SetCursor(imgIContainer*) */
93 #include "imgIContainer.h"
94 #include "nsGfxCIID.h"
95 #include "nsImageToPixbuf.h"
96 #include "nsIInterfaceRequestorUtils.h"
97 #include "nsAutoPtr.h"
98 #include "ClientLayerManager.h"
101 #define PIXMAN_DONT_DEFINE_STDINT
104 #include "gfxPlatformGtk.h"
105 #include "gfxContext.h"
106 #include "gfxImageSurface.h"
107 #include "gfxUtils.h"
109 #include "GLContextProvider.h"
110 #include "mozilla/gfx/2D.h"
111 #include "mozilla/layers/CompositorParent.h"
114 #include "gfxXlibSurface.h"
115 #include "cairo-xlib.h"
118 #include "nsShmImage.h"
120 #include "nsIDOMWheelEvent.h"
122 #include "NativeKeyBindings.h"
123 #include "nsWindow.h"
125 using namespace mozilla
;
126 using namespace mozilla::gfx
;
127 using namespace mozilla::widget
;
128 using namespace mozilla::layers
;
129 using mozilla::gl::GLContext
;
131 // Don't put more than this many rects in the dirty region, just fluff
132 // out to the bounding-box if there are more
133 #define MAX_RECTS_IN_REGION 100
135 const gint kEvents
= GDK_EXPOSURE_MASK
| GDK_STRUCTURE_MASK
|
136 GDK_VISIBILITY_NOTIFY_MASK
|
137 GDK_ENTER_NOTIFY_MASK
| GDK_LEAVE_NOTIFY_MASK
|
138 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
139 #if GTK_CHECK_VERSION(3,4,0)
140 GDK_SMOOTH_SCROLL_MASK
|
143 GDK_POINTER_MOTION_MASK
;
145 /* utility functions */
146 static bool is_mouse_in_window(GdkWindow
* aWindow
,
147 gdouble aMouseX
, gdouble aMouseY
);
148 static nsWindow
*get_window_for_gtk_widget(GtkWidget
*widget
);
149 static nsWindow
*get_window_for_gdk_window(GdkWindow
*window
);
150 static GtkWidget
*get_gtk_widget_for_gdk_window(GdkWindow
*window
);
151 static GdkCursor
*get_gtk_cursor(nsCursor aCursor
);
153 static GdkWindow
*get_inner_gdk_window (GdkWindow
*aWindow
,
155 gint
*retx
, gint
*rety
);
157 static inline bool is_context_menu_key(const WidgetKeyboardEvent
& inKeyEvent
);
159 static int is_parent_ungrab_enter(GdkEventCrossing
*aEvent
);
160 static int is_parent_grab_leave(GdkEventCrossing
*aEvent
);
162 static void GetBrandName(nsXPIDLString
& brandName
);
164 /* callbacks from widgets */
165 #if (MOZ_WIDGET_GTK == 2)
166 static gboolean
expose_event_cb (GtkWidget
*widget
,
167 GdkEventExpose
*event
);
169 static gboolean
expose_event_cb (GtkWidget
*widget
,
172 static gboolean
configure_event_cb (GtkWidget
*widget
,
173 GdkEventConfigure
*event
);
174 static void container_unrealize_cb (GtkWidget
*widget
);
175 static void size_allocate_cb (GtkWidget
*widget
,
176 GtkAllocation
*allocation
);
177 static gboolean
delete_event_cb (GtkWidget
*widget
,
179 static gboolean
enter_notify_event_cb (GtkWidget
*widget
,
180 GdkEventCrossing
*event
);
181 static gboolean
leave_notify_event_cb (GtkWidget
*widget
,
182 GdkEventCrossing
*event
);
183 static gboolean
motion_notify_event_cb (GtkWidget
*widget
,
184 GdkEventMotion
*event
);
185 static gboolean
button_press_event_cb (GtkWidget
*widget
,
186 GdkEventButton
*event
);
187 static gboolean
button_release_event_cb (GtkWidget
*widget
,
188 GdkEventButton
*event
);
189 static gboolean
focus_in_event_cb (GtkWidget
*widget
,
190 GdkEventFocus
*event
);
191 static gboolean
focus_out_event_cb (GtkWidget
*widget
,
192 GdkEventFocus
*event
);
193 static gboolean
key_press_event_cb (GtkWidget
*widget
,
195 static gboolean
key_release_event_cb (GtkWidget
*widget
,
197 static gboolean
scroll_event_cb (GtkWidget
*widget
,
198 GdkEventScroll
*event
);
199 static gboolean
visibility_notify_event_cb(GtkWidget
*widget
,
200 GdkEventVisibility
*event
);
201 static void hierarchy_changed_cb (GtkWidget
*widget
,
202 GtkWidget
*previous_toplevel
);
203 static gboolean
window_state_event_cb (GtkWidget
*widget
,
204 GdkEventWindowState
*event
);
205 static void theme_changed_cb (GtkSettings
*settings
,
208 static nsWindow
* GetFirstNSWindowForGDKWindow (GdkWindow
*aGdkWindow
);
212 #endif /* __cplusplus */
214 static GdkFilterReturn
popup_take_focus_filter (GdkXEvent
*gdk_xevent
,
217 static GdkFilterReturn
plugin_window_filter_func (GdkXEvent
*gdk_xevent
,
220 static GdkFilterReturn
plugin_client_message_filter (GdkXEvent
*xevent
,
226 #endif /* __cplusplus */
228 static gboolean
drag_motion_event_cb (GtkWidget
*aWidget
,
229 GdkDragContext
*aDragContext
,
234 static void drag_leave_event_cb (GtkWidget
*aWidget
,
235 GdkDragContext
*aDragContext
,
238 static gboolean
drag_drop_event_cb (GtkWidget
*aWidget
,
239 GdkDragContext
*aDragContext
,
244 static void drag_data_received_event_cb(GtkWidget
*aWidget
,
245 GdkDragContext
*aDragContext
,
248 GtkSelectionData
*aSelectionData
,
253 /* initialization static functions */
254 static nsresult
initialize_prefs (void);
256 static guint32 sLastUserInputTime
= GDK_CURRENT_TIME
;
257 static guint32 sRetryGrabTime
;
259 static NS_DEFINE_IID(kCDragServiceCID
, NS_DRAGSERVICE_CID
);
261 // The window from which the focus manager asks us to dispatch key events.
262 static nsWindow
*gFocusWindow
= nullptr;
263 static bool gBlockActivateEvent
= false;
264 static bool gGlobalsInitialized
= false;
265 static bool gRaiseWindows
= true;
266 static nsWindow
*gPluginFocusWindow
= nullptr;
269 #define NS_WINDOW_TITLE_MAX_LENGTH 4095
271 // If after selecting profile window, the startup fail, please refer to
272 // http://bugzilla.gnome.org/show_bug.cgi?id=88940
274 // needed for imgIContainer cursors
275 // GdkDisplay* was added in 2.2
276 typedef struct _GdkDisplay GdkDisplay
;
278 #define kWindowPositionSlop 20
281 static GdkCursor
*gCursorCache
[eCursorCount
];
283 static GtkWidget
*gInvisibleContainer
= nullptr;
285 // Sometimes this actually also includes the state of the modifier keys, but
286 // only the button state bits are used.
287 static guint gButtonState
;
289 // nsAutoRef<pixman_region32> uses nsSimpleRef<> to know how to automatically
292 class nsSimpleRef
<pixman_region32
> : public pixman_region32
{
294 typedef pixman_region32 RawRef
;
296 nsSimpleRef() { data
= nullptr; }
297 nsSimpleRef(const RawRef
&aRawRef
) : pixman_region32(aRawRef
) { }
299 static void Release(pixman_region32
& region
) {
300 pixman_region32_fini(®ion
);
302 // Whether this needs to be released:
303 bool HaveResource() const { return data
!= nullptr; }
305 pixman_region32
& get() { return *this; }
308 static inline int32_t
309 GetBitmapStride(int32_t width
)
311 #if defined(MOZ_X11) || (MOZ_WIDGET_GTK == 2)
314 return cairo_format_stride_for_width(CAIRO_FORMAT_A1
, width
);
318 static inline bool TimestampIsNewerThan(guint32 a
, guint32 b
)
320 // Timestamps are just the least significant bits of a monotonically
321 // increasing function, and so the use of unsigned overflow arithmetic.
322 return a
- b
<= G_MAXUINT32
/2;
326 UpdateLastInputEventTime(void *aGdkEvent
)
328 nsCOMPtr
<nsIIdleServiceInternal
> idleService
=
329 do_GetService("@mozilla.org/widget/idleservice;1");
331 idleService
->ResetIdleTimeOut(0);
334 guint timestamp
= gdk_event_get_time(static_cast<GdkEvent
*>(aGdkEvent
));
335 if (timestamp
== GDK_CURRENT_TIME
)
338 sLastUserInputTime
= timestamp
;
344 mIsDestroyed
= false;
345 mNeedsResize
= false;
347 mListenForResizes
= false;
353 mContainer
= nullptr;
354 mGdkWindow
= nullptr;
356 mHasMappedToplevel
= false;
357 mIsFullyObscured
= false;
358 mRetryPointerGrab
= false;
359 mWindowType
= eWindowType_child
;
360 mSizeState
= nsSizeMode_Normal
;
361 mLastSizeMode
= nsSizeMode_Normal
;
362 mSizeConstraints
.mMaxSize
= GetSafeWindowSize(mSizeConstraints
.mMaxSize
);
367 mPluginType
= PluginType_NONE
;
369 if (!gGlobalsInitialized
) {
370 gGlobalsInitialized
= true;
372 // It's OK if either of these fail, but it may not be one day.
376 mLastMotionPressure
= 0;
379 mRootAccessible
= nullptr;
382 mIsTransparent
= false;
383 mTransparencyBitmap
= nullptr;
385 mTransparencyBitmapWidth
= 0;
386 mTransparencyBitmapHeight
= 0;
388 #if GTK_CHECK_VERSION(3,4,0)
389 mLastScrollEventTime
= GDK_CURRENT_TIME
;
393 nsWindow::~nsWindow()
395 LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
397 delete[] mTransparencyBitmap
;
398 mTransparencyBitmap
= nullptr;
404 nsWindow::ReleaseGlobals()
406 for (uint32_t i
= 0; i
< ArrayLength(gCursorCache
); ++i
) {
407 if (gCursorCache
[i
]) {
408 #if (MOZ_WIDGET_GTK == 3)
409 g_object_unref(gCursorCache
[i
]);
411 gdk_cursor_unref(gCursorCache
[i
]);
413 gCursorCache
[i
] = nullptr;
418 NS_IMPL_ISUPPORTS_INHERITED(nsWindow
, nsBaseWidget
,
419 nsISupportsWeakReference
)
422 nsWindow::CommonCreate(nsIWidget
*aParent
, bool aListenForResizes
)
425 mListenForResizes
= aListenForResizes
;
430 nsWindow::DispatchActivateEvent(void)
432 NS_ASSERTION(mContainer
|| mIsDestroyed
,
433 "DispatchActivateEvent only intended for container windows");
436 DispatchActivateEventAccessible();
437 #endif //ACCESSIBILITY
440 mWidgetListener
->WindowActivated();
444 nsWindow::DispatchDeactivateEvent(void)
447 mWidgetListener
->WindowDeactivated();
450 DispatchDeactivateEventAccessible();
451 #endif //ACCESSIBILITY
455 nsWindow::DispatchResized(int32_t aWidth
, int32_t aHeight
)
457 nsIWidgetListener
*listeners
[] =
458 { mWidgetListener
, mAttachedWidgetListener
};
459 for (size_t i
= 0; i
< ArrayLength(listeners
); ++i
) {
461 listeners
[i
]->WindowResized(this, aWidth
, aHeight
);
467 nsWindow::DispatchEvent(WidgetGUIEvent
* aEvent
, nsEventStatus
& aStatus
)
470 debug_DumpEvent(stdout
, aEvent
->widget
, aEvent
,
471 nsAutoCString("something"), 0);
474 aStatus
= nsEventStatus_eIgnore
;
475 nsIWidgetListener
* listener
=
476 mAttachedWidgetListener
? mAttachedWidgetListener
: mWidgetListener
;
478 aStatus
= listener
->HandleEvent(aEvent
, mUseAttachedEvents
);
485 nsWindow::OnDestroy(void)
487 if (mOnDestroyCalled
)
490 mOnDestroyCalled
= true;
493 nsCOMPtr
<nsIWidget
> kungFuDeathGrip
= this;
495 // release references to children, device context, toolkit + app shell
496 nsBaseWidget::OnDestroy();
498 // Remove association between this object and its parent and siblings.
499 nsBaseWidget::Destroy();
502 NotifyWindowDestroyed();
506 nsWindow::AreBoundsSane(void)
508 if (mBounds
.width
> 0 && mBounds
.height
> 0)
515 EnsureInvisibleContainer()
517 if (!gInvisibleContainer
) {
518 // GtkWidgets need to be anchored to a GtkWindow to be realized (to
519 // have a window). Using GTK_WINDOW_POPUP rather than
520 // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
521 // initialization and window manager interaction.
522 GtkWidget
* window
= gtk_window_new(GTK_WINDOW_POPUP
);
523 gInvisibleContainer
= moz_container_new();
524 gtk_container_add(GTK_CONTAINER(window
), gInvisibleContainer
);
525 gtk_widget_realize(gInvisibleContainer
);
528 return gInvisibleContainer
;
532 CheckDestroyInvisibleContainer()
534 NS_PRECONDITION(gInvisibleContainer
, "oh, no");
536 if (!gdk_window_peek_children(gtk_widget_get_window(gInvisibleContainer
))) {
537 // No children, so not in use.
538 // Make sure to destroy the GtkWindow also.
539 gtk_widget_destroy(gtk_widget_get_parent(gInvisibleContainer
));
540 gInvisibleContainer
= nullptr;
544 // Change the containing GtkWidget on a sub-hierarchy of GdkWindows belonging
545 // to aOldWidget and rooted at aWindow, and reparent any child GtkWidgets of
546 // the GdkWindow hierarchy to aNewWidget.
548 SetWidgetForHierarchy(GdkWindow
*aWindow
,
549 GtkWidget
*aOldWidget
,
550 GtkWidget
*aNewWidget
)
553 gdk_window_get_user_data(aWindow
, &data
);
555 if (data
!= aOldWidget
) {
556 if (!GTK_IS_WIDGET(data
))
559 GtkWidget
* widget
= static_cast<GtkWidget
*>(data
);
560 if (gtk_widget_get_parent(widget
) != aOldWidget
)
563 // This window belongs to a child widget, which will no longer be a
564 // child of aOldWidget.
565 gtk_widget_reparent(widget
, aNewWidget
);
570 GList
*children
= gdk_window_get_children(aWindow
);
571 for(GList
*list
= children
; list
; list
= list
->next
) {
572 SetWidgetForHierarchy(GDK_WINDOW(list
->data
), aOldWidget
, aNewWidget
);
574 g_list_free(children
);
576 gdk_window_set_user_data(aWindow
, aNewWidget
);
579 // Walk the list of child windows and call destroy on them.
581 nsWindow::DestroyChildWindows()
586 while (GList
*children
= gdk_window_peek_children(mGdkWindow
)) {
587 GdkWindow
*child
= GDK_WINDOW(children
->data
);
588 nsWindow
*kid
= get_window_for_gdk_window(child
);
592 // This child is not an nsWindow.
593 // Destroy the child GtkWidget.
595 gdk_window_get_user_data(child
, &data
);
596 if (GTK_IS_WIDGET(data
)) {
597 gtk_widget_destroy(static_cast<GtkWidget
*>(data
));
604 nsWindow::Destroy(void)
606 if (mIsDestroyed
|| !mCreated
)
609 LOG(("nsWindow::Destroy [%p]\n", (void *)this));
613 /** Need to clean our LayerManager up while still alive */
615 mLayerManager
->Destroy();
617 mLayerManager
= nullptr;
619 // It is safe to call DestroyeCompositor several times (here and
620 // in the parent class) since it will take effect only once.
621 // The reason we call it here is because on gtk platforms we need
622 // to destroy the compositor before we destroy the gdk window (which
623 // destroys the the gl context attached to it).
626 ClearCachedResources();
628 g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
629 FuncToGpointer(theme_changed_cb
),
632 nsIRollupListener
* rollupListener
= nsBaseWidget::GetActiveRollupListener();
633 if (rollupListener
) {
634 nsCOMPtr
<nsIWidget
> rollupWidget
= rollupListener
->GetRollupWidget();
635 if (static_cast<nsIWidget
*>(this) == rollupWidget
) {
636 rollupListener
->Rollup(0, nullptr, nullptr);
640 // dragService will be null after shutdown of the service manager.
641 nsDragService
*dragService
= nsDragService::GetInstance();
642 if (dragService
&& this == dragService
->GetMostRecentDestWindow()) {
643 dragService
->ScheduleLeaveEvent();
649 mIMModule
->OnDestroyWindow(this);
652 // make sure that we remove ourself as the focus window
653 if (gFocusWindow
== this) {
654 LOGFOCUS(("automatically losing focus...\n"));
655 gFocusWindow
= nullptr;
658 #if (MOZ_WIDGET_GTK == 2) && defined(MOZ_X11)
659 // make sure that we remove ourself as the plugin focus window
660 if (gPluginFocusWindow
== this) {
661 gPluginFocusWindow
->LoseNonXEmbedPluginFocus();
663 #endif /* MOZ_X11 && MOZ_WIDGET_GTK2 */
665 // Destroy thebes surface now. Badness can happen if we destroy
666 // the surface after its X Window.
667 mThebesSurface
= nullptr;
669 GtkWidget
*owningWidget
= GetMozContainerWidget();
671 gtk_widget_destroy(mShell
);
673 mContainer
= nullptr;
674 NS_ABORT_IF_FALSE(!mGdkWindow
,
675 "mGdkWindow should be NULL when mContainer is destroyed");
677 else if (mContainer
) {
678 gtk_widget_destroy(GTK_WIDGET(mContainer
));
679 mContainer
= nullptr;
680 NS_ABORT_IF_FALSE(!mGdkWindow
,
681 "mGdkWindow should be NULL when mContainer is destroyed");
683 else if (mGdkWindow
) {
684 // Destroy child windows to ensure that their mThebesSurfaces are
685 // released and to remove references from GdkWindows back to their
686 // container widget. (OnContainerUnrealize() does this when the
687 // MozContainer widget is destroyed.)
688 DestroyChildWindows();
690 gdk_window_set_user_data(mGdkWindow
, nullptr);
691 g_object_set_data(G_OBJECT(mGdkWindow
), "nsWindow", nullptr);
692 gdk_window_destroy(mGdkWindow
);
693 mGdkWindow
= nullptr;
696 if (gInvisibleContainer
&& owningWidget
== gInvisibleContainer
) {
697 CheckDestroyInvisibleContainer();
701 if (mRootAccessible
) {
702 mRootAccessible
= nullptr;
706 // Save until last because OnDestroy() may cause us to be deleted.
713 nsWindow::GetParent(void)
721 Display
*dpy
= GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
722 int defaultScreen
= DefaultScreen(dpy
);
723 double heightInches
= DisplayHeightMM(dpy
, defaultScreen
)/MM_PER_INCH_FLOAT
;
724 if (heightInches
< 0.25) {
725 // Something's broken, but we'd better not crash.
728 return float(DisplayHeight(dpy
, defaultScreen
)/heightInches
);
732 nsWindow::SetParent(nsIWidget
*aNewParent
)
734 if (mContainer
|| !mGdkWindow
) {
735 NS_NOTREACHED("nsWindow::SetParent called illegally");
736 return NS_ERROR_NOT_IMPLEMENTED
;
739 nsCOMPtr
<nsIWidget
> kungFuDeathGrip
= this;
741 mParent
->RemoveChild(this);
744 mParent
= aNewParent
;
746 GtkWidget
* oldContainer
= GetMozContainerWidget();
748 // The GdkWindows have been destroyed so there is nothing else to
750 NS_ABORT_IF_FALSE(gdk_window_is_destroyed(mGdkWindow
),
751 "live GdkWindow with no widget");
756 aNewParent
->AddChild(this);
757 ReparentNativeWidget(aNewParent
);
759 // aNewParent is nullptr, but reparent to a hidden window to avoid
760 // destroying the GdkWindow and its descendants.
761 // An invisible container widget is needed to hold descendant
763 GtkWidget
* newContainer
= EnsureInvisibleContainer();
764 GdkWindow
* newParentWindow
= gtk_widget_get_window(newContainer
);
765 ReparentNativeWidgetInternal(aNewParent
, newContainer
, newParentWindow
,
772 nsWindow::ReparentNativeWidget(nsIWidget
* aNewParent
)
774 NS_PRECONDITION(aNewParent
, "");
775 NS_ASSERTION(!mIsDestroyed
, "");
776 NS_ASSERTION(!static_cast<nsWindow
*>(aNewParent
)->mIsDestroyed
, "");
778 GtkWidget
* oldContainer
= GetMozContainerWidget();
780 // The GdkWindows have been destroyed so there is nothing else to
782 NS_ABORT_IF_FALSE(gdk_window_is_destroyed(mGdkWindow
),
783 "live GdkWindow with no widget");
786 NS_ABORT_IF_FALSE(!gdk_window_is_destroyed(mGdkWindow
),
787 "destroyed GdkWindow with widget");
789 nsWindow
* newParent
= static_cast<nsWindow
*>(aNewParent
);
790 GdkWindow
* newParentWindow
= newParent
->mGdkWindow
;
791 GtkWidget
* newContainer
= newParent
->GetMozContainerWidget();
792 GtkWindow
* shell
= GTK_WINDOW(mShell
);
794 if (shell
&& gtk_window_get_transient_for(shell
)) {
795 GtkWindow
* topLevelParent
=
796 GTK_WINDOW(gtk_widget_get_toplevel(newContainer
));
797 gtk_window_set_transient_for(shell
, topLevelParent
);
800 ReparentNativeWidgetInternal(aNewParent
, newContainer
, newParentWindow
,
806 nsWindow::ReparentNativeWidgetInternal(nsIWidget
* aNewParent
,
807 GtkWidget
* aNewContainer
,
808 GdkWindow
* aNewParentWindow
,
809 GtkWidget
* aOldContainer
)
811 if (!aNewContainer
) {
812 // The new parent GdkWindow has been destroyed.
813 NS_ABORT_IF_FALSE(!aNewParentWindow
||
814 gdk_window_is_destroyed(aNewParentWindow
),
815 "live GdkWindow with no widget");
818 if (aNewContainer
!= aOldContainer
) {
819 NS_ABORT_IF_FALSE(!gdk_window_is_destroyed(aNewParentWindow
),
820 "destroyed GdkWindow with widget");
821 SetWidgetForHierarchy(mGdkWindow
, aOldContainer
, aNewContainer
);
823 if (aOldContainer
== gInvisibleContainer
) {
824 CheckDestroyInvisibleContainer();
829 gdk_window_reparent(mGdkWindow
, aNewParentWindow
, mBounds
.x
,
834 nsWindow
* newParent
= static_cast<nsWindow
*>(aNewParent
);
835 bool parentHasMappedToplevel
=
836 newParent
&& newParent
->mHasMappedToplevel
;
837 if (mHasMappedToplevel
!= parentHasMappedToplevel
) {
838 SetHasMappedToplevel(parentHasMappedToplevel
);
843 nsWindow::SetModal(bool aModal
)
845 LOG(("nsWindow::SetModal [%p] %d\n", (void *)this, aModal
));
847 return aModal
? NS_ERROR_NOT_AVAILABLE
: NS_OK
;
848 if (!mIsTopLevel
|| !mShell
)
849 return NS_ERROR_FAILURE
;
850 gtk_window_set_modal(GTK_WINDOW(mShell
), aModal
? TRUE
: FALSE
);
854 // nsIWidget method, which means IsShown.
856 nsWindow::IsVisible() const
862 nsWindow::ConstrainPosition(bool aAllowSlop
, int32_t *aX
, int32_t *aY
)
864 if (mIsTopLevel
&& mShell
) {
865 int32_t screenWidth
= gdk_screen_width();
866 int32_t screenHeight
= gdk_screen_height();
868 if (*aX
< (kWindowPositionSlop
- mBounds
.width
))
869 *aX
= kWindowPositionSlop
- mBounds
.width
;
870 if (*aX
> (screenWidth
- kWindowPositionSlop
))
871 *aX
= screenWidth
- kWindowPositionSlop
;
872 if (*aY
< (kWindowPositionSlop
- mBounds
.height
))
873 *aY
= kWindowPositionSlop
- mBounds
.height
;
874 if (*aY
> (screenHeight
- kWindowPositionSlop
))
875 *aY
= screenHeight
- kWindowPositionSlop
;
879 if (*aX
> (screenWidth
- mBounds
.width
))
880 *aX
= screenWidth
- mBounds
.width
;
883 if (*aY
> (screenHeight
- mBounds
.height
))
884 *aY
= screenHeight
- mBounds
.height
;
890 void nsWindow::SetSizeConstraints(const SizeConstraints
& aConstraints
)
892 mSizeConstraints
.mMinSize
= GetSafeWindowSize(aConstraints
.mMinSize
);
893 mSizeConstraints
.mMaxSize
= GetSafeWindowSize(aConstraints
.mMaxSize
);
896 GdkGeometry geometry
;
897 geometry
.min_width
= mSizeConstraints
.mMinSize
.width
;
898 geometry
.min_height
= mSizeConstraints
.mMinSize
.height
;
899 geometry
.max_width
= mSizeConstraints
.mMaxSize
.width
;
900 geometry
.max_height
= mSizeConstraints
.mMaxSize
.height
;
902 uint32_t hints
= GDK_HINT_MIN_SIZE
| GDK_HINT_MAX_SIZE
;
903 gtk_window_set_geometry_hints(GTK_WINDOW(mShell
), nullptr,
904 &geometry
, GdkWindowHints(hints
));
909 nsWindow::Show(bool aState
)
911 if (aState
== mIsShown
)
914 // Clear our cached resources when the window is hidden.
915 if (mIsShown
&& !aState
) {
916 ClearCachedResources();
921 LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState
));
924 // Now that this window is shown, mHasMappedToplevel needs to be
925 // tracked on viewable descendants.
926 SetHasMappedToplevel(mHasMappedToplevel
);
929 // Ok, someone called show on a window that isn't sized to a sane
930 // value. Mark this window as needing to have Show() called on it
932 if ((aState
&& !AreBoundsSane()) || !mCreated
) {
933 LOG(("\tbounds are insane or window hasn't been created yet\n"));
938 // If someone is hiding this widget, clear any needing show flag.
942 // If someone is showing this window and it needs a resize then
943 // resize the widget.
946 NativeResize(mBounds
.x
, mBounds
.y
, mBounds
.width
, mBounds
.height
,
948 } else if (mNeedsResize
) {
949 NativeResize(mBounds
.width
, mBounds
.height
, false);
954 if (aState
&& a11y::ShouldA11yBeEnabled())
955 CreateRootAccessible();
964 nsWindow::Resize(double aWidth
, double aHeight
, bool aRepaint
)
966 CSSToLayoutDeviceScale scale
= BoundsUseDisplayPixels() ? GetDefaultScale()
967 : CSSToLayoutDeviceScale(1.0);
968 int32_t width
= NSToIntRound(scale
.scale
* aWidth
);
969 int32_t height
= NSToIntRound(scale
.scale
* aHeight
);
970 ConstrainSize(&width
, &height
);
972 // For top-level windows, aWidth and aHeight should possibly be
973 // interpreted as frame bounds, but NativeResize treats these as window
974 // bounds (Bug 581866).
976 mBounds
.SizeTo(width
, height
);
981 // There are several cases here that we need to handle, based on a
982 // matrix of the visibility of the widget, the sanity of this resize
983 // and whether or not the widget was previously sane.
985 // Has this widget been set to visible?
987 // Are the bounds sane?
988 if (AreBoundsSane()) {
989 // Yep? Resize the window
990 //Maybe, the toplevel has moved
992 // Note that if the widget needs to be positioned because its
993 // size was previously insane in Resize(x,y,w,h), then we need
994 // to set the x and y here too, because the widget wasn't
997 NativeResize(mBounds
.x
, mBounds
.y
,
998 mBounds
.width
, mBounds
.height
, aRepaint
);
1000 NativeResize(mBounds
.width
, mBounds
.height
, aRepaint
);
1002 // Does it need to be shown because it was previously insane?
1007 // If someone has set this so that the needs show flag is false
1008 // and it needs to be hidden, update the flag and hide the
1009 // window. This flag will be cleared the next time someone
1010 // hides the window or shows it. It also prevents us from
1011 // calling NativeShow(false) excessively on the window which
1012 // causes unneeded X traffic.
1019 // If the widget hasn't been shown, mark the widget as needing to be
1020 // resized before it is shown.
1022 if (AreBoundsSane() && mListenForResizes
) {
1023 // For widgets that we listen for resizes for (widgets created
1024 // with native parents) we apparently _always_ have to resize. I
1025 // dunno why, but apparently we're lame like that.
1026 NativeResize(width
, height
, aRepaint
);
1029 mNeedsResize
= true;
1033 NotifyRollupGeometryChange();
1035 // send a resize notification if this is a toplevel
1036 if (mIsTopLevel
|| mListenForResizes
) {
1037 DispatchResized(width
, height
);
1044 nsWindow::Resize(double aX
, double aY
, double aWidth
, double aHeight
,
1047 CSSToLayoutDeviceScale scale
= BoundsUseDisplayPixels() ? GetDefaultScale()
1048 : CSSToLayoutDeviceScale(1.0);
1049 int32_t width
= NSToIntRound(scale
.scale
* aWidth
);
1050 int32_t height
= NSToIntRound(scale
.scale
* aHeight
);
1051 ConstrainSize(&width
, &height
);
1053 int32_t x
= NSToIntRound(scale
.scale
* aX
);
1054 int32_t y
= NSToIntRound(scale
.scale
* aY
);
1057 mBounds
.SizeTo(width
, height
);
1064 // There are several cases here that we need to handle, based on a
1065 // matrix of the visibility of the widget, the sanity of this resize
1066 // and whether or not the widget was previously sane.
1068 // Has this widget been set to visible?
1070 // Are the bounds sane?
1071 if (AreBoundsSane()) {
1072 // Yep? Resize the window
1073 NativeResize(x
, y
, width
, height
, aRepaint
);
1074 // Does it need to be shown because it was previously insane?
1079 // If someone has set this so that the needs show flag is false
1080 // and it needs to be hidden, update the flag and hide the
1081 // window. This flag will be cleared the next time someone
1082 // hides the window or shows it. It also prevents us from
1083 // calling NativeShow(false) excessively on the window which
1084 // causes unneeded X traffic.
1091 // If the widget hasn't been shown, mark the widget as needing to be
1092 // resized before it is shown
1094 if (AreBoundsSane() && mListenForResizes
){
1095 // For widgets that we listen for resizes for (widgets created
1096 // with native parents) we apparently _always_ have to resize. I
1097 // dunno why, but apparently we're lame like that.
1098 NativeResize(x
, y
, width
, height
, aRepaint
);
1101 mNeedsResize
= true;
1105 NotifyRollupGeometryChange();
1107 if (mIsTopLevel
|| mListenForResizes
) {
1108 DispatchResized(width
, height
);
1115 nsWindow::Enable(bool aState
)
1123 nsWindow::IsEnabled() const
1131 nsWindow::Move(double aX
, double aY
)
1133 LOG(("nsWindow::Move [%p] %f %f\n", (void *)this,
1136 CSSToLayoutDeviceScale scale
= BoundsUseDisplayPixels() ? GetDefaultScale()
1137 : CSSToLayoutDeviceScale(1.0);
1138 int32_t x
= NSToIntRound(aX
* scale
.scale
);
1139 int32_t y
= NSToIntRound(aY
* scale
.scale
);
1141 if (mWindowType
== eWindowType_toplevel
||
1142 mWindowType
== eWindowType_dialog
) {
1143 SetSizeMode(nsSizeMode_Normal
);
1146 // Since a popup window's x/y coordinates are in relation to to
1147 // the parent, the parent might have moved so we always move a
1149 if (x
== mBounds
.x
&& y
== mBounds
.y
&&
1150 mWindowType
!= eWindowType_popup
)
1153 // XXX Should we do some AreBoundsSane check here?
1164 gtk_window_move(GTK_WINDOW(mShell
), x
, y
);
1166 else if (mGdkWindow
) {
1167 gdk_window_move(mGdkWindow
, x
, y
);
1170 NotifyRollupGeometryChange();
1175 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement
,
1179 return NS_ERROR_NOT_IMPLEMENTED
;
1183 nsWindow::SetZIndex(int32_t aZIndex
)
1185 nsIWidget
* oldPrev
= GetPrevSibling();
1187 nsBaseWidget::SetZIndex(aZIndex
);
1189 if (GetPrevSibling() == oldPrev
) {
1193 NS_ASSERTION(!mContainer
, "Expected Mozilla child widget");
1195 // We skip the nsWindows that don't have mGdkWindows.
1196 // These are probably in the process of being destroyed.
1198 if (!GetNextSibling()) {
1199 // We're to be on top.
1201 gdk_window_raise(mGdkWindow
);
1203 // All the siblings before us need to be below our widget.
1204 for (nsWindow
* w
= this; w
;
1205 w
= static_cast<nsWindow
*>(w
->GetPrevSibling())) {
1207 gdk_window_lower(w
->mGdkWindow
);
1213 nsWindow::SetSizeMode(int32_t aMode
)
1217 LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode
));
1219 // Save the requested state.
1220 rv
= nsBaseWidget::SetSizeMode(aMode
);
1222 // return if there's no shell or our current state is the same as
1223 // the mode we were just set to.
1224 if (!mShell
|| mSizeState
== mSizeMode
) {
1229 case nsSizeMode_Maximized
:
1230 gtk_window_maximize(GTK_WINDOW(mShell
));
1232 case nsSizeMode_Minimized
:
1233 gtk_window_iconify(GTK_WINDOW(mShell
));
1235 case nsSizeMode_Fullscreen
:
1236 MakeFullScreen(true);
1240 // nsSizeMode_Normal, really.
1241 if (mSizeState
== nsSizeMode_Minimized
)
1242 gtk_window_deiconify(GTK_WINDOW(mShell
));
1243 else if (mSizeState
== nsSizeMode_Maximized
)
1244 gtk_window_unmaximize(GTK_WINDOW(mShell
));
1248 mSizeState
= mSizeMode
;
1253 typedef void (* SetUserTimeFunc
)(GdkWindow
* aWindow
, guint32 aTimestamp
);
1255 // This will become obsolete when new GTK APIs are widely supported,
1256 // as described here: http://bugzilla.gnome.org/show_bug.cgi?id=347375
1258 SetUserTimeAndStartupIDForActivatedWindow(GtkWidget
* aWindow
)
1260 nsGTKToolkit
* GTKToolkit
= nsGTKToolkit::GetToolkit();
1264 nsAutoCString desktopStartupID
;
1265 GTKToolkit
->GetDesktopStartupID(&desktopStartupID
);
1266 if (desktopStartupID
.IsEmpty()) {
1267 // We don't have the data we need. Fall back to an
1268 // approximation ... using the timestamp of the remote command
1269 // being received as a guess for the timestamp of the user event
1270 // that triggered it.
1271 uint32_t timestamp
= GTKToolkit
->GetFocusTimestamp();
1273 gdk_window_focus(gtk_widget_get_window(aWindow
), timestamp
);
1274 GTKToolkit
->SetFocusTimestamp(0);
1279 #if defined(MOZ_ENABLE_STARTUP_NOTIFICATION)
1280 GdkWindow
* gdkWindow
= gtk_widget_get_window(aWindow
);
1282 GdkScreen
* screen
= gdk_window_get_screen(gdkWindow
);
1284 sn_display_new(gdk_x11_display_get_xdisplay(gdk_window_get_display(gdkWindow
)),
1288 SnLauncheeContext
* ctx
=
1289 sn_launchee_context_new(snd
, gdk_screen_get_number(screen
),
1290 desktopStartupID
.get());
1292 sn_display_unref(snd
);
1296 if (sn_launchee_context_get_id_has_timestamp(ctx
)) {
1297 PRLibrary
* gtkLibrary
;
1298 SetUserTimeFunc setUserTimeFunc
= (SetUserTimeFunc
)
1299 PR_FindFunctionSymbolAndLibrary("gdk_x11_window_set_user_time", >kLibrary
);
1300 if (setUserTimeFunc
) {
1301 setUserTimeFunc(gdkWindow
, sn_launchee_context_get_timestamp(ctx
));
1302 PR_UnloadLibrary(gtkLibrary
);
1306 sn_launchee_context_setup_window(ctx
, gdk_x11_window_get_xid(gdkWindow
));
1307 sn_launchee_context_complete(ctx
);
1309 sn_launchee_context_unref(ctx
);
1310 sn_display_unref(snd
);
1313 // If we used the startup ID, that already contains the focus timestamp;
1314 // we don't want to reuse the timestamp next time we raise the window
1315 GTKToolkit
->SetFocusTimestamp(0);
1316 GTKToolkit
->SetDesktopStartupID(EmptyCString());
1319 /* static */ guint32
1320 nsWindow::GetLastUserInputTime()
1322 // gdk_x11_display_get_user_time tracks button and key presses,
1323 // DESKTOP_STARTUP_ID used to start the app, drop events from external
1324 // drags, WM_DELETE_WINDOW delete events, but not usually mouse motion nor
1325 // button and key releases. Therefore use the most recent of
1326 // gdk_x11_display_get_user_time and the last time that we have seen.
1328 gdk_x11_display_get_user_time(gdk_display_get_default());
1329 if (sLastUserInputTime
!= GDK_CURRENT_TIME
&&
1330 TimestampIsNewerThan(sLastUserInputTime
, timestamp
)) {
1331 return sLastUserInputTime
;
1338 nsWindow::SetFocus(bool aRaise
)
1340 // Make sure that our owning widget has focus. If it doesn't try to
1341 // grab it. Note that we don't set our focus flag in this case.
1343 LOGFOCUS((" SetFocus %d [%p]\n", aRaise
, (void *)this));
1345 GtkWidget
*owningWidget
= GetMozContainerWidget();
1347 return NS_ERROR_FAILURE
;
1349 // Raise the window if someone passed in true and the prefs are
1351 GtkWidget
*toplevelWidget
= gtk_widget_get_toplevel(owningWidget
);
1353 if (gRaiseWindows
&& aRaise
&& toplevelWidget
&&
1354 !gtk_widget_has_focus(owningWidget
) &&
1355 !gtk_widget_has_focus(toplevelWidget
)) {
1356 GtkWidget
* top_window
= GetToplevelWidget();
1357 if (top_window
&& (gtk_widget_get_visible(top_window
)))
1359 gdk_window_show_unraised(gtk_widget_get_window(top_window
));
1360 // Unset the urgency hint if possible.
1361 SetUrgencyHint(top_window
, false);
1365 nsRefPtr
<nsWindow
> owningWindow
= get_window_for_gtk_widget(owningWidget
);
1367 return NS_ERROR_FAILURE
;
1370 // aRaise == true means request toplevel activation.
1372 // This is asynchronous.
1373 // If and when the window manager accepts the request, then the focus
1374 // widget will get a focus-in-event signal.
1375 if (gRaiseWindows
&& owningWindow
->mIsShown
&& owningWindow
->mShell
&&
1376 !gtk_window_is_active(GTK_WINDOW(owningWindow
->mShell
))) {
1378 uint32_t timestamp
= GDK_CURRENT_TIME
;
1380 nsGTKToolkit
* GTKToolkit
= nsGTKToolkit::GetToolkit();
1382 timestamp
= GTKToolkit
->GetFocusTimestamp();
1384 LOGFOCUS((" requesting toplevel activation [%p]\n", (void *)this));
1385 NS_ASSERTION(owningWindow
->mWindowType
!= eWindowType_popup
1387 "Presenting an override-redirect window");
1388 gtk_window_present_with_time(GTK_WINDOW(owningWindow
->mShell
), timestamp
);
1391 GTKToolkit
->SetFocusTimestamp(0);
1397 // aRaise == false means that keyboard events should be dispatched
1398 // from this widget.
1400 // Ensure owningWidget is the focused GtkWidget within its toplevel window.
1402 // For eWindowType_popup, this GtkWidget may not actually be the one that
1403 // receives the key events as it may be the parent window that is active.
1404 if (!gtk_widget_is_focus(owningWidget
)) {
1405 // This is synchronous. It takes focus from a plugin or from a widget
1406 // in an embedder. The focus manager already knows that this window
1407 // is active so gBlockActivateEvent avoids another (unnecessary)
1408 // activate notification.
1409 gBlockActivateEvent
= true;
1410 gtk_widget_grab_focus(owningWidget
);
1411 gBlockActivateEvent
= false;
1414 // If this is the widget that already has focus, return.
1415 if (gFocusWindow
== this) {
1416 LOGFOCUS((" already have focus [%p]\n", (void *)this));
1420 // Set this window to be the focused child window
1421 gFocusWindow
= this;
1424 mIMModule
->OnFocusWindow(this);
1427 LOGFOCUS((" widget now has focus in SetFocus() [%p]\n",
1434 nsWindow::GetScreenBounds(nsIntRect
&aRect
)
1436 if (mIsTopLevel
&& mContainer
) {
1437 // use the point including window decorations
1439 gdk_window_get_root_origin(gtk_widget_get_window(GTK_WIDGET(mContainer
)), &x
, &y
);
1443 aRect
.MoveTo(WidgetToScreenOffset());
1445 // mBounds.Size() is the window bounds, not the window-manager frame
1446 // bounds (bug 581863). gdk_window_get_frame_extents would give the
1447 // frame bounds, but mBounds.Size() is returned here for consistency
1449 aRect
.SizeTo(mBounds
.Size());
1450 LOG(("GetScreenBounds %d,%d | %dx%d\n",
1451 aRect
.x
, aRect
.y
, aRect
.width
, aRect
.height
));
1456 nsWindow::GetClientBounds(nsIntRect
&aRect
)
1458 // GetBounds returns a rect whose top left represents the top left of the
1459 // outer bounds, but whose width/height represent the size of the inner
1460 // bounds (which is messed up).
1462 aRect
.MoveBy(GetClientOffset());
1468 nsWindow::GetClientOffset()
1471 return nsIntPoint(0, 0);
1474 GdkAtom cardinal_atom
= gdk_x11_xatom_to_atom(XA_CARDINAL
);
1476 GdkAtom type_returned
;
1477 int format_returned
;
1478 int length_returned
;
1479 long *frame_extents
;
1482 if (!mShell
|| !(window
= gtk_widget_get_window(mShell
)) ||
1483 !gdk_property_get(window
,
1484 gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE
),
1492 (guchar
**) &frame_extents
) ||
1493 length_returned
/sizeof(glong
) != 4) {
1495 return nsIntPoint(0, 0);
1498 // data returned is in the order left, right, top, bottom
1499 int32_t left
= int32_t(frame_extents
[0]);
1500 int32_t top
= int32_t(frame_extents
[2]);
1502 g_free(frame_extents
);
1504 return nsIntPoint(left
, top
);
1508 nsWindow::SetCursor(nsCursor aCursor
)
1510 // if we're not the toplevel window pass up the cursor request to
1511 // the toplevel window to handle it.
1512 if (!mContainer
&& mGdkWindow
) {
1513 nsWindow
*window
= GetContainerWindow();
1515 return NS_ERROR_FAILURE
;
1517 return window
->SetCursor(aCursor
);
1520 // Only change cursor if it's actually been changed
1521 if (aCursor
!= mCursor
|| mUpdateCursor
) {
1522 GdkCursor
*newCursor
= nullptr;
1523 mUpdateCursor
= false;
1525 newCursor
= get_gtk_cursor(aCursor
);
1527 if (nullptr != newCursor
) {
1533 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer
)), newCursor
);
1541 nsWindow::SetCursor(imgIContainer
* aCursor
,
1542 uint32_t aHotspotX
, uint32_t aHotspotY
)
1544 // if we're not the toplevel window pass up the cursor request to
1545 // the toplevel window to handle it.
1546 if (!mContainer
&& mGdkWindow
) {
1547 nsWindow
*window
= GetContainerWindow();
1549 return NS_ERROR_FAILURE
;
1551 return window
->SetCursor(aCursor
, aHotspotX
, aHotspotY
);
1554 mCursor
= nsCursor(-1);
1556 // Get the image's current frame
1557 GdkPixbuf
* pixbuf
= nsImageToPixbuf::ImageToPixbuf(aCursor
);
1559 return NS_ERROR_NOT_AVAILABLE
;
1561 int width
= gdk_pixbuf_get_width(pixbuf
);
1562 int height
= gdk_pixbuf_get_height(pixbuf
);
1563 // Reject cursors greater than 128 pixels in some direction, to prevent
1565 // XXX ideally we should rescale. Also, we could modify the API to
1566 // allow trusted content to set larger cursors.
1567 if (width
> 128 || height
> 128) {
1568 g_object_unref(pixbuf
);
1569 return NS_ERROR_NOT_AVAILABLE
;
1572 // Looks like all cursors need an alpha channel (tested on Gtk 2.4.4). This
1573 // is of course not documented anywhere...
1574 // So add one if there isn't one yet
1575 if (!gdk_pixbuf_get_has_alpha(pixbuf
)) {
1576 GdkPixbuf
* alphaBuf
= gdk_pixbuf_add_alpha(pixbuf
, FALSE
, 0, 0, 0);
1577 g_object_unref(pixbuf
);
1579 return NS_ERROR_OUT_OF_MEMORY
;
1584 GdkCursor
* cursor
= gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
1586 aHotspotX
, aHotspotY
);
1587 g_object_unref(pixbuf
);
1588 nsresult rv
= NS_ERROR_OUT_OF_MEMORY
;
1591 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer
)), cursor
);
1594 #if (MOZ_WIDGET_GTK == 3)
1595 g_object_unref(cursor
);
1597 gdk_cursor_unref(cursor
);
1605 nsWindow::Invalidate(const nsIntRect
&aRect
)
1613 rect
.width
= aRect
.width
;
1614 rect
.height
= aRect
.height
;
1616 LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
1617 rect
.x
, rect
.y
, rect
.width
, rect
.height
));
1619 gdk_window_invalidate_rect(mGdkWindow
, &rect
, FALSE
);
1625 nsWindow::GetNativeData(uint32_t aDataType
)
1627 switch (aDataType
) {
1628 case NS_NATIVE_WINDOW
:
1629 case NS_NATIVE_WIDGET
: {
1637 case NS_NATIVE_PLUGIN_PORT
:
1638 return SetupPluginPort();
1641 case NS_NATIVE_DISPLAY
:
1643 return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1646 #endif /* MOZ_X11 */
1649 case NS_NATIVE_SHELLWIDGET
:
1650 return GetToplevelWidget();
1652 case NS_NATIVE_SHAREABLE_WINDOW
:
1653 return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow
));
1656 NS_WARNING("nsWindow::GetNativeData called with bad value");
1662 nsWindow::SetTitle(const nsAString
& aTitle
)
1667 // convert the string into utf8 and set the title.
1668 #define UTF8_FOLLOWBYTE(ch) (((ch) & 0xC0) == 0x80)
1669 NS_ConvertUTF16toUTF8
titleUTF8(aTitle
);
1670 if (titleUTF8
.Length() > NS_WINDOW_TITLE_MAX_LENGTH
) {
1671 // Truncate overlong titles (bug 167315). Make sure we chop after a
1672 // complete sequence by making sure the next char isn't a follow-byte.
1673 uint32_t len
= NS_WINDOW_TITLE_MAX_LENGTH
;
1674 while(UTF8_FOLLOWBYTE(titleUTF8
[len
]))
1676 titleUTF8
.Truncate(len
);
1678 gtk_window_set_title(GTK_WINDOW(mShell
), (const char *)titleUTF8
.get());
1684 nsWindow::SetIcon(const nsAString
& aIconSpec
)
1689 nsAutoCString iconName
;
1691 if (aIconSpec
.EqualsLiteral("default")) {
1692 nsXPIDLString brandName
;
1693 GetBrandName(brandName
);
1694 AppendUTF16toUTF8(brandName
, iconName
);
1695 ToLowerCase(iconName
);
1697 AppendUTF16toUTF8(aIconSpec
, iconName
);
1700 nsCOMPtr
<nsIFile
> iconFile
;
1704 gtk_icon_theme_get_icon_sizes(gtk_icon_theme_get_default(),
1706 bool foundIcon
= (iconSizes
[0] != 0);
1710 // Look for icons with the following suffixes appended to the base name
1711 // The last two entries (for the old XPM format) will be ignored unless
1712 // no icons are found using other suffixes. XPM icons are deprecated.
1714 const char extensions
[6][7] = { ".png", "16.png", "32.png", "48.png",
1717 for (uint32_t i
= 0; i
< ArrayLength(extensions
); i
++) {
1718 // Don't bother looking for XPM versions if we found a PNG.
1719 if (i
== ArrayLength(extensions
) - 2 && foundIcon
)
1722 nsAutoString extension
;
1723 extension
.AppendASCII(extensions
[i
]);
1725 ResolveIconName(aIconSpec
, extension
, getter_AddRefs(iconFile
));
1727 iconFile
->GetNativePath(path
);
1728 GdkPixbuf
*icon
= gdk_pixbuf_new_from_file(path
.get(), nullptr);
1730 gtk_icon_theme_add_builtin_icon(iconName
.get(),
1731 gdk_pixbuf_get_height(icon
),
1733 g_object_unref(icon
);
1740 // leave the default icon intact if no matching icons were found
1742 gtk_window_set_icon_name(GTK_WINDOW(mShell
), iconName
.get());
1750 nsWindow::WidgetToScreenOffset()
1755 gdk_window_get_origin(mGdkWindow
, &x
, &y
);
1758 return nsIntPoint(x
, y
);
1762 nsWindow::EnableDragDrop(bool aEnable
)
1768 nsWindow::CaptureMouse(bool aCapture
)
1770 LOG(("CaptureMouse %p\n", (void *)this));
1776 return NS_ERROR_FAILURE
;
1779 gtk_grab_add(mShell
);
1780 GrabPointer(GetLastUserInputTime());
1784 gtk_grab_remove(mShell
);
1791 nsWindow::CaptureRollupEvents(nsIRollupListener
*aListener
,
1798 return NS_ERROR_FAILURE
;
1800 LOG(("CaptureRollupEvents %p %i\n", this, int(aDoCapture
)));
1803 gRollupListener
= aListener
;
1804 // real grab is only done when there is no dragging
1805 if (!nsWindow::DragInProgress()) {
1806 // This widget grab ensures that a Gecko GtkWidget receives mouse
1807 // events even when embedded in non-Gecko-owned GtkWidgets.
1808 // The grab is placed on the toplevel GtkWindow instead of the
1809 // MozContainer to avoid double dispatch of keyboard events
1811 gtk_grab_add(mShell
);
1812 GrabPointer(GetLastUserInputTime());
1816 if (!nsWindow::DragInProgress()) {
1819 // There may not have been a drag in process when aDoCapture was set,
1820 // so make sure to remove any added grab. This is a no-op if the grab
1821 // was not added to this widget.
1822 gtk_grab_remove(mShell
);
1823 gRollupListener
= nullptr;
1830 nsWindow::GetAttention(int32_t aCycleCount
)
1832 LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
1834 GtkWidget
* top_window
= GetToplevelWidget();
1835 GtkWidget
* top_focused_window
=
1836 gFocusWindow
? gFocusWindow
->GetToplevelWidget() : nullptr;
1838 // Don't get attention if the window is focused anyway.
1839 if (top_window
&& (gtk_widget_get_visible(top_window
)) &&
1840 top_window
!= top_focused_window
) {
1841 SetUrgencyHint(top_window
, true);
1848 nsWindow::HasPendingInputEvent()
1850 // This sucks, but gtk/gdk has no way to answer the question we want while
1851 // excluding paint events, and there's no X API that will let us peek
1852 // without blocking or removing. To prevent event reordering, peek
1853 // anything except expose events. Reordering expose and others should be
1858 Display
*display
= GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1860 XCheckMaskEvent(display
,
1861 KeyPressMask
| KeyReleaseMask
| ButtonPressMask
|
1862 ButtonReleaseMask
| EnterWindowMask
| LeaveWindowMask
|
1863 PointerMotionMask
| PointerMotionHintMask
|
1864 Button1MotionMask
| Button2MotionMask
|
1865 Button3MotionMask
| Button4MotionMask
|
1866 Button5MotionMask
| ButtonMotionMask
| KeymapStateMask
|
1867 VisibilityChangeMask
| StructureNotifyMask
|
1868 ResizeRedirectMask
| SubstructureNotifyMask
|
1869 SubstructureRedirectMask
| FocusChangeMask
|
1870 PropertyChangeMask
| ColormapChangeMask
|
1871 OwnerGrabButtonMask
, &ev
);
1873 XPutBackEvent(display
, &ev
);
1883 // Paint flashing code (disabled for cairo - see below)
1885 #define CAPS_LOCK_IS_ON \
1886 (KeymapWrapper::AreModifiersCurrentlyActive(KeymapWrapper::CAPS_LOCK))
1888 #define WANT_PAINT_FLASHING \
1889 (debug_WantPaintFlashing() && CAPS_LOCK_IS_ON)
1893 gdk_window_flash(GdkWindow
* aGdkWindow
,
1894 unsigned int aTimes
,
1895 unsigned int aInterval
, // Milliseconds
1896 GdkRegion
* aRegion
)
1906 #if (MOZ_WIDGET_GTK == 2)
1907 gdk_window_get_geometry(aGdkWindow
,nullptr,nullptr,&width
,&height
,nullptr);
1909 gdk_window_get_geometry(aGdkWindow
,nullptr,nullptr,&width
,&height
);
1912 gdk_window_get_origin (aGdkWindow
,
1916 gc
= gdk_gc_new(gdk_get_default_root_window());
1918 white
.pixel
= WhitePixel(gdk_display
,DefaultScreen(gdk_display
));
1920 gdk_gc_set_foreground(gc
,&white
);
1921 gdk_gc_set_function(gc
,GDK_XOR
);
1922 gdk_gc_set_subwindow(gc
,GDK_INCLUDE_INFERIORS
);
1924 gdk_region_offset(aRegion
, x
, y
);
1925 gdk_gc_set_clip_region(gc
, aRegion
);
1928 * Need to do this twice so that the XOR effect can replace
1929 * the original window contents.
1931 for (i
= 0; i
< aTimes
* 2; i
++)
1933 gdk_draw_rectangle(gdk_get_default_root_window(),
1943 PR_Sleep(PR_MillisecondsToInterval(aInterval
));
1948 gdk_region_offset(aRegion
, -x
, -y
);
1950 #endif /* MOZ_X11 */
1956 nsIntRegion mRegion
;
1958 #if (MOZ_WIDGET_GTK == 2)
1959 GdkRectangle
*mRects
;
1960 GdkRectangle
*mRectsEnd
;
1962 ExposeRegion() : mRects(nullptr)
1969 bool Init(GdkEventExpose
*aEvent
)
1972 gdk_region_get_rectangles(aEvent
->region
, &mRects
, &nrects
);
1974 if (nrects
> MAX_RECTS_IN_REGION
) {
1975 // Just use the bounding box
1976 mRects
[0] = aEvent
->area
;
1980 mRectsEnd
= mRects
+ nrects
;
1982 for (GdkRectangle
*r
= mRects
; r
< mRectsEnd
; r
++) {
1983 mRegion
.Or(mRegion
, nsIntRect(r
->x
, r
->y
, r
->width
, r
->height
));
1984 LOGDRAW(("\t%d %d %d %d\n", r
->x
, r
->y
, r
->width
, r
->height
));
1990 # ifdef cairo_copy_clip_rectangle_list
1991 # error "Looks like we're including Mozilla's cairo instead of system cairo"
1993 cairo_rectangle_list_t
*mRects
;
1995 ExposeRegion() : mRects(nullptr)
2000 cairo_rectangle_list_destroy(mRects
);
2002 bool Init(cairo_t
* cr
)
2004 mRects
= cairo_copy_clip_rectangle_list(cr
);
2005 if (mRects
->status
!= CAIRO_STATUS_SUCCESS
) {
2006 NS_WARNING("Failed to obtain cairo rectangle list.");
2010 for (int i
= 0; i
< mRects
->num_rectangles
; i
++) {
2011 const cairo_rectangle_t
& r
= mRects
->rectangles
[i
];
2012 mRegion
.Or(mRegion
, nsIntRect(r
.x
, r
.y
, r
.width
, r
.height
));
2013 LOGDRAW(("\t%d %d %d %d\n", r
.x
, r
.y
, r
.width
, r
.height
));
2020 #if (MOZ_WIDGET_GTK == 2)
2022 nsWindow::OnExposeEvent(GdkEventExpose
*aEvent
)
2025 nsWindow::OnExposeEvent(cairo_t
*cr
)
2032 // Windows that are not visible will be painted after they become visible.
2033 if (!mGdkWindow
|| mIsFullyObscured
|| !mHasMappedToplevel
)
2036 nsIWidgetListener
*listener
=
2037 mAttachedWidgetListener
? mAttachedWidgetListener
: mWidgetListener
;
2041 ExposeRegion exposeRegion
;
2042 #if (MOZ_WIDGET_GTK == 2)
2043 if (!exposeRegion
.Init(aEvent
)) {
2045 if (!exposeRegion
.Init(cr
)) {
2050 nsIntRegion
®ion
= exposeRegion
.mRegion
;
2052 ClientLayerManager
*clientLayers
=
2053 (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT
)
2054 ? static_cast<ClientLayerManager
*>(GetLayerManager())
2057 if (clientLayers
&& mCompositorParent
) {
2058 // We need to paint to the screen even if nothing changed, since if we
2059 // don't have a compositing window manager, our pixels could be stale.
2060 clientLayers
->SetNeedsComposite(true);
2061 clientLayers
->SendInvalidRegion(region
);
2064 // Dispatch WillPaintWindow notification to allow scripts etc. to run
2067 listener
->WillPaintWindow(this);
2069 // If the window has been destroyed during the will paint notification,
2070 // there is nothing left to do.
2074 // Re-get the listener since the will paint notification might have
2077 mAttachedWidgetListener
? mAttachedWidgetListener
: mWidgetListener
;
2082 if (clientLayers
&& mCompositorParent
&& clientLayers
->NeedsComposite()) {
2083 mCompositorParent
->ScheduleRenderOnCompositorThread();
2084 clientLayers
->SetNeedsComposite(false);
2087 LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
2088 (void *)this, (void *)mGdkWindow
,
2089 gdk_x11_window_get_xid(mGdkWindow
)));
2091 // Our bounds may have changed after calling WillPaintWindow. Clip
2092 // to the new bounds here. The region is relative to this
2094 region
.And(region
, nsIntRect(0, 0, mBounds
.width
, mBounds
.height
));
2096 bool shaped
= false;
2097 if (eTransparencyTransparent
== GetTransparencyMode()) {
2098 GdkScreen
*screen
= gdk_window_get_screen(mGdkWindow
);
2099 if (gdk_screen_is_composited(screen
) &&
2100 gdk_window_get_visual(mGdkWindow
) ==
2101 gdk_screen_get_rgba_visual(screen
)) {
2102 // Remove possible shape mask from when window manger was not
2103 // previously compositing.
2104 static_cast<nsWindow
*>(GetTopLevelWidget())->
2105 ClearTransparencyBitmap();
2113 gdk_window_peek_children(mGdkWindow
);
2115 GdkWindow
*gdkWin
= GDK_WINDOW(children
->data
);
2116 nsWindow
*kid
= get_window_for_gdk_window(gdkWin
);
2117 if (kid
&& gdk_window_is_visible(gdkWin
)) {
2118 nsAutoTArray
<nsIntRect
,1> clipRects
;
2119 kid
->GetWindowClipRegion(&clipRects
);
2121 kid
->GetBounds(bounds
);
2122 for (uint32_t i
= 0; i
< clipRects
.Length(); ++i
) {
2123 nsIntRect r
= clipRects
[i
] + bounds
.TopLeft();
2124 region
.Sub(region
, r
);
2127 children
= children
->next
;
2131 if (region
.IsEmpty()) {
2135 // If this widget uses OMTC...
2136 if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT
) {
2137 listener
->PaintWindow(this, region
);
2138 listener
->DidPaintWindow();
2143 #if (MOZ_WIDGET_GTK == 2)
2144 surf
= GetThebesSurface();
2146 surf
= GetThebesSurface(cr
);
2149 nsRefPtr
<gfxContext
> ctx
;
2150 if (gfxPlatform::GetPlatform()->
2151 SupportsAzureContentForType(BackendType::CAIRO
)) {
2152 IntSize
intSize(surf
->GetSize().width
, surf
->GetSize().height
);
2153 RefPtr
<DrawTarget
> dt
=
2154 gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf
, intSize
);
2155 ctx
= new gfxContext(dt
);
2156 } else if (gfxPlatform::GetPlatform()->
2157 SupportsAzureContentForType(BackendType::SKIA
) &&
2158 surf
->GetType() == gfxSurfaceType::Image
) {
2159 gfxImageSurface
* imgSurf
= static_cast<gfxImageSurface
*>(surf
);
2160 SurfaceFormat format
= ImageFormatToSurfaceFormat(imgSurf
->Format());
2161 IntSize
intSize(surf
->GetSize().width
, surf
->GetSize().height
);
2162 RefPtr
<DrawTarget
> dt
=
2163 gfxPlatform::GetPlatform()->CreateDrawTargetForData(
2164 imgSurf
->Data(), intSize
, imgSurf
->Stride(), format
);
2165 ctx
= new gfxContext(dt
);
2167 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected content type");
2171 nsIntRect boundsRect
; // for shaped only
2175 // Collapse update area to the bounding box. This is so we only have to
2176 // call UpdateTranslucentWindowAlpha once. After we have dropped
2177 // support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
2178 // our private interface so we can rework things to avoid this.
2179 boundsRect
= region
.GetBounds();
2180 ctx
->Rectangle(gfxRect(boundsRect
.x
, boundsRect
.y
,
2181 boundsRect
.width
, boundsRect
.height
));
2183 gfxUtils::PathFromRegion(ctx
, region
);
2187 BufferMode layerBuffering
;
2189 // The double buffering is done here to extract the shape mask.
2190 // (The shape mask won't be necessary when a visual with an alpha
2191 // channel is used on compositing window managers.)
2192 layerBuffering
= mozilla::layers::BufferMode::BUFFER_NONE
;
2193 ctx
->PushGroup(gfxContentType::COLOR_ALPHA
);
2194 #ifdef MOZ_HAVE_SHMIMAGE
2195 } else if (nsShmImage::UseShm()) {
2196 // We're using an xshm mapping as a back buffer.
2197 layerBuffering
= mozilla::layers::BufferMode::BUFFER_NONE
;
2198 #endif // MOZ_HAVE_SHMIMAGE
2200 // Get the layer manager to do double buffering (if necessary).
2201 layerBuffering
= mozilla::layers::BufferMode::BUFFERED
;
2205 // NOTE: Paint flashing region would be wrong for cairo, since
2206 // cairo inflates the update region, etc. So don't paint flash
2209 // XXX aEvent->region may refer to a newly-invalid area. FIXME
2210 if (0 && WANT_PAINT_FLASHING
&& gtk_widget_get_window(aEvent
))
2211 gdk_window_flash(mGdkWindow
, 1, 100, aEvent
->region
);
2217 bool painted
= false;
2219 if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC
) {
2220 AutoLayerManagerSetup
setupLayerManager(this, ctx
, layerBuffering
);
2221 painted
= listener
->PaintWindow(this, region
);
2226 // PaintWindow can Destroy us (bug 378273), avoid doing any paint
2227 // operations below if that happened - it will lead to XError and exit().
2229 if (MOZ_LIKELY(!mIsDestroyed
)) {
2231 nsRefPtr
<gfxPattern
> pattern
= ctx
->PopGroup();
2233 UpdateAlpha(pattern
, boundsRect
);
2235 ctx
->SetOperator(gfxContext::OPERATOR_SOURCE
);
2236 ctx
->SetPattern(pattern
);
2241 # ifdef MOZ_HAVE_SHMIMAGE
2242 if (mShmImage
&& MOZ_LIKELY(!mIsDestroyed
)) {
2243 #if (MOZ_WIDGET_GTK == 2)
2244 mShmImage
->Put(mGdkWindow
, exposeRegion
.mRects
, exposeRegion
.mRectsEnd
);
2246 mShmImage
->Put(mGdkWindow
, exposeRegion
.mRects
);
2249 # endif // MOZ_HAVE_SHMIMAGE
2252 listener
->DidPaintWindow();
2254 // Synchronously flush any new dirty areas
2255 #if (MOZ_WIDGET_GTK == 2)
2256 GdkRegion
* dirtyArea
= gdk_window_get_update_area(mGdkWindow
);
2258 cairo_region_t
* dirtyArea
= gdk_window_get_update_area(mGdkWindow
);
2262 gdk_window_invalidate_region(mGdkWindow
, dirtyArea
, false);
2263 #if (MOZ_WIDGET_GTK == 2)
2264 gdk_region_destroy(dirtyArea
);
2266 cairo_region_destroy(dirtyArea
);
2268 gdk_window_process_updates(mGdkWindow
, false);
2271 // check the return value!
2276 nsWindow::UpdateAlpha(gfxPattern
* aPattern
, nsIntRect aBoundsRect
)
2278 // We need to create our own buffer to force the stride to match the
2280 int32_t stride
= GetAlignedStride
<4>(BytesPerPixel(SurfaceFormat::A8
) *
2282 int32_t bufferSize
= stride
* aBoundsRect
.height
;
2283 nsAutoArrayPtr
<uint8_t> imageBuffer(new (std::nothrow
) uint8_t[bufferSize
]);
2284 RefPtr
<DrawTarget
> drawTarget
= gfxPlatform::GetPlatform()->
2285 CreateDrawTargetForData(imageBuffer
, ToIntSize(aBoundsRect
.Size()),
2286 stride
, SurfaceFormat::A8
);
2289 Matrix transform
= Matrix::Translation(-aBoundsRect
.x
, -aBoundsRect
.y
);
2290 drawTarget
->SetTransform(transform
);
2292 drawTarget
->FillRect(Rect(aBoundsRect
.x
, aBoundsRect
.y
, aBoundsRect
.width
, aBoundsRect
.height
),
2293 *aPattern
->GetPattern(drawTarget
),
2294 DrawOptions(1.0, CompositionOp::OP_SOURCE
));
2296 UpdateTranslucentWindowAlphaInternal(aBoundsRect
, imageBuffer
, stride
);
2300 nsWindow::OnConfigureEvent(GtkWidget
*aWidget
, GdkEventConfigure
*aEvent
)
2302 // These events are only received on toplevel windows.
2304 // GDK ensures that the coordinates are the client window top-left wrt the
2307 // GDK calculates the cordinates for real ConfigureNotify events on
2308 // managed windows (that would normally be relative to the parent
2311 // Synthetic ConfigureNotify events are from the window manager and
2312 // already relative to the root window. GDK creates all X windows with
2313 // border_width = 0, so synthetic events also indicate the top-left of
2314 // the client window.
2316 // Override-redirect windows are children of the root window so parent
2317 // coordinates are root coordinates.
2319 LOG(("configure event [%p] %d %d %d %d\n", (void *)this,
2320 aEvent
->x
, aEvent
->y
, aEvent
->width
, aEvent
->height
));
2322 nsIntRect screenBounds
;
2323 GetScreenBounds(screenBounds
);
2325 if (mWindowType
== eWindowType_toplevel
|| mWindowType
== eWindowType_dialog
) {
2326 // This check avoids unwanted rollup on spurious configure events from
2327 // Cygwin/X (bug 672103).
2328 if (mBounds
.x
!= screenBounds
.x
||
2329 mBounds
.y
!= screenBounds
.y
) {
2330 CheckForRollup(0, 0, false, true);
2334 // This event indicates that the window position may have changed.
2335 // mBounds.Size() is updated in OnSizeAllocate().
2337 // (The gtk_window_get_window_type() function is only available from
2339 NS_ASSERTION(GTK_IS_WINDOW(aWidget
),
2340 "Configure event on widget that is not a GtkWindow");
2342 g_object_get(aWidget
, "type", &type
, nullptr);
2343 if (type
== GTK_WINDOW_POPUP
) {
2344 // Override-redirect window
2346 // These windows should not be moved by the window manager, and so any
2347 // change in position is a result of our direction. mBounds has
2348 // already been set in Move() or Resize(), and that is more
2349 // up-to-date than the position in the ConfigureNotify event if the
2350 // event is from an earlier window move.
2352 // Skipping the WindowMoved call saves context menus from an infinite
2353 // loop when nsXULPopupManager::PopupMoved moves the window to the new
2354 // position and nsMenuPopupFrame::SetPopupPosition adds
2355 // offsetForContextMenu on each iteration.
2359 mBounds
.MoveTo(screenBounds
.TopLeft());
2361 // XXX mozilla will invalidate the entire window after this move
2363 NotifyWindowMoved(mBounds
.x
, mBounds
.y
);
2369 nsWindow::OnContainerUnrealize()
2371 // The GdkWindows are about to be destroyed (but not deleted), so remove
2372 // their references back to their container widget while the GdkWindow
2373 // hierarchy is still available.
2376 DestroyChildWindows();
2378 g_object_set_data(G_OBJECT(mGdkWindow
), "nsWindow", nullptr);
2379 mGdkWindow
= nullptr;
2384 nsWindow::OnSizeAllocate(GtkAllocation
*aAllocation
)
2386 LOG(("size_allocate [%p] %d %d %d %d\n",
2387 (void *)this, aAllocation
->x
, aAllocation
->y
,
2388 aAllocation
->width
, aAllocation
->height
));
2390 nsIntSize
size(aAllocation
->width
, aAllocation
->height
);
2391 if (mBounds
.Size() == size
)
2394 // Invalidate the new part of the window now for the pending paint to
2395 // minimize background flashes (GDK does not do this for external resizes
2397 if (mBounds
.width
< size
.width
) {
2399 { mBounds
.width
, 0, size
.width
- mBounds
.width
, size
.height
};
2400 gdk_window_invalidate_rect(mGdkWindow
, &rect
, FALSE
);
2402 if (mBounds
.height
< size
.height
) {
2404 { 0, mBounds
.height
, size
.width
, size
.height
- mBounds
.height
};
2405 gdk_window_invalidate_rect(mGdkWindow
, &rect
, FALSE
);
2408 mBounds
.SizeTo(size
);
2413 DispatchResized(size
.width
, size
.height
);
2417 nsWindow::OnDeleteEvent()
2419 if (mWidgetListener
)
2420 mWidgetListener
->RequestWindowClose(this);
2424 nsWindow::OnEnterNotifyEvent(GdkEventCrossing
*aEvent
)
2426 // This skips NotifyVirtual and NotifyNonlinearVirtual enter notify events
2427 // when the pointer enters a child window. If the destination window is a
2428 // Gecko window then we'll catch the corresponding event on that window,
2429 // but we won't notice when the pointer directly enters a foreign (plugin)
2430 // child window without passing over a visible portion of a Gecko window.
2431 if (aEvent
->subwindow
!= nullptr)
2434 // Check before is_parent_ungrab_enter() as the button state may have
2435 // changed while a non-Gecko ancestor window had a pointer grab.
2436 DispatchMissedButtonReleases(aEvent
);
2438 if (is_parent_ungrab_enter(aEvent
))
2441 WidgetMouseEvent
event(true, NS_MOUSE_ENTER
, this, WidgetMouseEvent::eReal
);
2443 event
.refPoint
.x
= nscoord(aEvent
->x
);
2444 event
.refPoint
.y
= nscoord(aEvent
->y
);
2446 event
.time
= aEvent
->time
;
2448 LOG(("OnEnterNotify: %p\n", (void *)this));
2450 nsEventStatus status
;
2451 DispatchEvent(&event
, status
);
2454 // XXX Is this the right test for embedding cases?
2456 is_top_level_mouse_exit(GdkWindow
* aWindow
, GdkEventCrossing
*aEvent
)
2458 gint x
= gint(aEvent
->x_root
);
2459 gint y
= gint(aEvent
->y_root
);
2460 GdkDisplay
* display
= gdk_window_get_display(aWindow
);
2461 GdkWindow
* winAtPt
= gdk_display_get_window_at_pointer(display
, &x
, &y
);
2464 GdkWindow
* topLevelAtPt
= gdk_window_get_toplevel(winAtPt
);
2465 GdkWindow
* topLevelWidget
= gdk_window_get_toplevel(aWindow
);
2466 return topLevelAtPt
!= topLevelWidget
;
2470 nsWindow::OnLeaveNotifyEvent(GdkEventCrossing
*aEvent
)
2472 // This ignores NotifyVirtual and NotifyNonlinearVirtual leave notify
2473 // events when the pointer leaves a child window. If the destination
2474 // window is a Gecko window then we'll catch the corresponding event on
2477 // XXXkt However, we will miss toplevel exits when the pointer directly
2478 // leaves a foreign (plugin) child window without passing over a visible
2479 // portion of a Gecko window.
2480 if (aEvent
->subwindow
!= nullptr)
2483 WidgetMouseEvent
event(true, NS_MOUSE_EXIT
, this, WidgetMouseEvent::eReal
);
2485 event
.refPoint
.x
= nscoord(aEvent
->x
);
2486 event
.refPoint
.y
= nscoord(aEvent
->y
);
2488 event
.time
= aEvent
->time
;
2490 event
.exit
= is_top_level_mouse_exit(mGdkWindow
, aEvent
)
2491 ? WidgetMouseEvent::eTopLevel
: WidgetMouseEvent::eChild
;
2493 LOG(("OnLeaveNotify: %p\n", (void *)this));
2495 nsEventStatus status
;
2496 DispatchEvent(&event
, status
);
2500 nsWindow::OnMotionNotifyEvent(GdkEventMotion
*aEvent
)
2502 // see if we can compress this event
2503 // XXXldb Why skip every other motion event when we have multiple,
2504 // but not more than that?
2505 bool synthEvent
= false;
2509 while (XPending (GDK_WINDOW_XDISPLAY(aEvent
->window
))) {
2511 XPeekEvent (GDK_WINDOW_XDISPLAY(aEvent
->window
), &peeked
);
2512 if (peeked
.xany
.window
!= gdk_x11_window_get_xid(aEvent
->window
)
2513 || peeked
.type
!= MotionNotify
)
2517 XNextEvent (GDK_WINDOW_XDISPLAY(aEvent
->window
), &xevent
);
2519 #if (MOZ_WIDGET_GTK == 2)
2520 // if plugins still keeps the focus, get it back
2521 if (gPluginFocusWindow
&& gPluginFocusWindow
!= this) {
2522 nsRefPtr
<nsWindow
> kungFuDeathGrip
= gPluginFocusWindow
;
2523 gPluginFocusWindow
->LoseNonXEmbedPluginFocus();
2525 #endif /* MOZ_WIDGET_GTK2 */
2526 #endif /* MOZ_X11 */
2528 WidgetMouseEvent
event(true, NS_MOUSE_MOVE
, this, WidgetMouseEvent::eReal
);
2530 gdouble pressure
= 0;
2531 gdk_event_get_axis ((GdkEvent
*)aEvent
, GDK_AXIS_PRESSURE
, &pressure
);
2532 // Sometime gdk generate 0 pressure value between normal values
2533 // We have to ignore that and use last valid value
2535 mLastMotionPressure
= pressure
;
2536 event
.pressure
= mLastMotionPressure
;
2538 guint modifierState
;
2541 event
.refPoint
.x
= nscoord(xevent
.xmotion
.x
);
2542 event
.refPoint
.y
= nscoord(xevent
.xmotion
.y
);
2544 modifierState
= xevent
.xmotion
.state
;
2546 event
.time
= xevent
.xmotion
.time
;
2548 event
.refPoint
.x
= nscoord(aEvent
->x
);
2549 event
.refPoint
.y
= nscoord(aEvent
->y
);
2551 modifierState
= aEvent
->state
;
2553 event
.time
= aEvent
->time
;
2554 #endif /* MOZ_X11 */
2557 // XXX see OnScrollEvent()
2558 if (aEvent
->window
== mGdkWindow
) {
2559 event
.refPoint
.x
= nscoord(aEvent
->x
);
2560 event
.refPoint
.y
= nscoord(aEvent
->y
);
2562 LayoutDeviceIntPoint
point(NSToIntFloor(aEvent
->x_root
),
2563 NSToIntFloor(aEvent
->y_root
));
2564 event
.refPoint
= point
-
2565 LayoutDeviceIntPoint::FromUntyped(WidgetToScreenOffset());
2568 modifierState
= aEvent
->state
;
2570 event
.time
= aEvent
->time
;
2573 KeymapWrapper::InitInputEvent(event
, modifierState
);
2575 nsEventStatus status
;
2576 DispatchEvent(&event
, status
);
2579 // If the automatic pointer grab on ButtonPress has deactivated before
2580 // ButtonRelease, and the mouse button is released while the pointer is not
2581 // over any a Gecko window, then the ButtonRelease event will not be received.
2582 // (A similar situation exists when the pointer is grabbed with owner_events
2583 // True as the ButtonRelease may be received on a foreign [plugin] window).
2584 // Use this method to check for released buttons when the pointer returns to a
2587 nsWindow::DispatchMissedButtonReleases(GdkEventCrossing
*aGdkEvent
)
2589 guint changed
= aGdkEvent
->state
^ gButtonState
;
2590 // Only consider button releases.
2591 // (Ignore button presses that occurred outside Gecko.)
2592 guint released
= changed
& gButtonState
;
2593 gButtonState
= aGdkEvent
->state
;
2595 // Loop over each button, excluding mouse wheel buttons 4 and 5 for which
2596 // GDK ignores releases.
2597 for (guint buttonMask
= GDK_BUTTON1_MASK
;
2598 buttonMask
<= GDK_BUTTON3_MASK
;
2601 if (released
& buttonMask
) {
2603 switch (buttonMask
) {
2604 case GDK_BUTTON1_MASK
:
2605 buttonType
= WidgetMouseEvent::eLeftButton
;
2607 case GDK_BUTTON2_MASK
:
2608 buttonType
= WidgetMouseEvent::eMiddleButton
;
2611 NS_ASSERTION(buttonMask
== GDK_BUTTON3_MASK
,
2612 "Unexpected button mask");
2613 buttonType
= WidgetMouseEvent::eRightButton
;
2616 LOG(("Synthesized button %u release on %p\n",
2617 guint(buttonType
+ 1), (void *)this));
2619 // Dispatch a synthesized button up event to tell Gecko about the
2620 // change in state. This event is marked as synthesized so that
2621 // it is not dispatched as a DOM event, because we don't know the
2622 // position, widget, modifiers, or time/order.
2623 WidgetMouseEvent
synthEvent(true, NS_MOUSE_BUTTON_UP
, this,
2624 WidgetMouseEvent::eSynthesized
);
2625 synthEvent
.button
= buttonType
;
2626 nsEventStatus status
;
2627 DispatchEvent(&synthEvent
, status
);
2633 nsWindow::InitButtonEvent(WidgetMouseEvent
& aEvent
,
2634 GdkEventButton
* aGdkEvent
)
2636 // XXX see OnScrollEvent()
2637 if (aGdkEvent
->window
== mGdkWindow
) {
2638 aEvent
.refPoint
.x
= nscoord(aGdkEvent
->x
);
2639 aEvent
.refPoint
.y
= nscoord(aGdkEvent
->y
);
2641 LayoutDeviceIntPoint
point(NSToIntFloor(aGdkEvent
->x_root
),
2642 NSToIntFloor(aGdkEvent
->y_root
));
2643 aEvent
.refPoint
= point
-
2644 LayoutDeviceIntPoint::FromUntyped(WidgetToScreenOffset());
2647 guint modifierState
= aGdkEvent
->state
;
2648 // aEvent's state doesn't include this event's information. Therefore,
2649 // if aEvent is mouse button down event, we need to set it manually.
2650 // Note that we cannot do same thing for NS_MOUSE_BUTTON_UP because
2651 // system may have two or more mice and same button of another mouse
2652 // may be still pressed.
2653 if (aGdkEvent
->type
!= GDK_BUTTON_RELEASE
) {
2654 switch (aGdkEvent
->button
) {
2656 modifierState
|= GDK_BUTTON1_MASK
;
2659 modifierState
|= GDK_BUTTON2_MASK
;
2662 modifierState
|= GDK_BUTTON3_MASK
;
2667 KeymapWrapper::InitInputEvent(aEvent
, modifierState
);
2669 aEvent
.time
= aGdkEvent
->time
;
2671 switch (aGdkEvent
->type
) {
2672 case GDK_2BUTTON_PRESS
:
2673 aEvent
.clickCount
= 2;
2675 case GDK_3BUTTON_PRESS
:
2676 aEvent
.clickCount
= 3;
2678 // default is one click
2680 aEvent
.clickCount
= 1;
2684 static guint
ButtonMaskFromGDKButton(guint button
)
2686 return GDK_BUTTON1_MASK
<< (button
- 1);
2690 nsWindow::OnButtonPressEvent(GdkEventButton
*aEvent
)
2692 LOG(("Button %u press on %p\n", aEvent
->button
, (void *)this));
2694 nsEventStatus status
;
2696 // If you double click in GDK, it will actually generate a second
2697 // GDK_BUTTON_PRESS before sending the GDK_2BUTTON_PRESS, and this is
2698 // different than the DOM spec. GDK puts this in the queue
2699 // programatically, so it's safe to assume that if there's a
2700 // double click in the queue, it was generated so we can just drop
2702 GdkEvent
*peekedEvent
= gdk_event_peek();
2704 GdkEventType type
= peekedEvent
->any
.type
;
2705 gdk_event_free(peekedEvent
);
2706 if (type
== GDK_2BUTTON_PRESS
|| type
== GDK_3BUTTON_PRESS
)
2710 nsWindow
*containerWindow
= GetContainerWindow();
2711 if (!gFocusWindow
&& containerWindow
) {
2712 containerWindow
->DispatchActivateEvent();
2715 // check to see if we should rollup
2716 if (CheckForRollup(aEvent
->x_root
, aEvent
->y_root
, false, false))
2719 gdouble pressure
= 0;
2720 gdk_event_get_axis ((GdkEvent
*)aEvent
, GDK_AXIS_PRESSURE
, &pressure
);
2721 mLastMotionPressure
= pressure
;
2724 switch (aEvent
->button
) {
2726 domButton
= WidgetMouseEvent::eLeftButton
;
2729 domButton
= WidgetMouseEvent::eMiddleButton
;
2732 domButton
= WidgetMouseEvent::eRightButton
;
2734 // These are mapped to horizontal scroll
2737 NS_WARNING("We're not supporting legacy horizontal scroll event");
2739 // Map buttons 8-9 to back/forward
2741 DispatchCommandEvent(nsGkAtoms::Back
);
2744 DispatchCommandEvent(nsGkAtoms::Forward
);
2750 gButtonState
|= ButtonMaskFromGDKButton(aEvent
->button
);
2752 WidgetMouseEvent
event(true, NS_MOUSE_BUTTON_DOWN
, this,
2753 WidgetMouseEvent::eReal
);
2754 event
.button
= domButton
;
2755 InitButtonEvent(event
, aEvent
);
2756 event
.pressure
= mLastMotionPressure
;
2758 DispatchEvent(&event
, status
);
2760 // right menu click on linux should also pop up a context menu
2761 if (domButton
== WidgetMouseEvent::eRightButton
&&
2762 MOZ_LIKELY(!mIsDestroyed
)) {
2763 WidgetMouseEvent
contextMenuEvent(true, NS_CONTEXTMENU
, this,
2764 WidgetMouseEvent::eReal
);
2765 InitButtonEvent(contextMenuEvent
, aEvent
);
2766 contextMenuEvent
.pressure
= mLastMotionPressure
;
2767 DispatchEvent(&contextMenuEvent
, status
);
2772 nsWindow::OnButtonReleaseEvent(GdkEventButton
*aEvent
)
2774 LOG(("Button %u release on %p\n", aEvent
->button
, (void *)this));
2777 switch (aEvent
->button
) {
2779 domButton
= WidgetMouseEvent::eLeftButton
;
2782 domButton
= WidgetMouseEvent::eMiddleButton
;
2785 domButton
= WidgetMouseEvent::eRightButton
;
2791 gButtonState
&= ~ButtonMaskFromGDKButton(aEvent
->button
);
2793 WidgetMouseEvent
event(true, NS_MOUSE_BUTTON_UP
, this,
2794 WidgetMouseEvent::eReal
);
2795 event
.button
= domButton
;
2796 InitButtonEvent(event
, aEvent
);
2797 gdouble pressure
= 0;
2798 gdk_event_get_axis ((GdkEvent
*)aEvent
, GDK_AXIS_PRESSURE
, &pressure
);
2799 event
.pressure
= pressure
? pressure
: mLastMotionPressure
;
2801 nsEventStatus status
;
2802 DispatchEvent(&event
, status
);
2803 mLastMotionPressure
= pressure
;
2807 nsWindow::OnContainerFocusInEvent(GdkEventFocus
*aEvent
)
2809 LOGFOCUS(("OnContainerFocusInEvent [%p]\n", (void *)this));
2811 // Unset the urgency hint, if possible
2812 GtkWidget
* top_window
= GetToplevelWidget();
2813 if (top_window
&& (gtk_widget_get_visible(top_window
)))
2814 SetUrgencyHint(top_window
, false);
2816 // Return if being called within SetFocus because the focus manager
2817 // already knows that the window is active.
2818 if (gBlockActivateEvent
) {
2819 LOGFOCUS(("activated notification is blocked [%p]\n", (void *)this));
2823 // If keyboard input will be accepted, the focus manager will call
2824 // SetFocus to set the correct window.
2825 gFocusWindow
= nullptr;
2827 DispatchActivateEvent();
2829 if (!gFocusWindow
) {
2830 // We don't really have a window for dispatching key events, but
2831 // setting a non-nullptr value here prevents OnButtonPressEvent() from
2832 // dispatching an activation notification if the widget is already
2834 gFocusWindow
= this;
2837 LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
2841 nsWindow::OnContainerFocusOutEvent(GdkEventFocus
*aEvent
)
2843 LOGFOCUS(("OnContainerFocusOutEvent [%p]\n", (void *)this));
2845 if (mWindowType
== eWindowType_toplevel
|| mWindowType
== eWindowType_dialog
) {
2846 nsCOMPtr
<nsIDragService
> dragService
= do_GetService(kCDragServiceCID
);
2847 nsCOMPtr
<nsIDragSession
> dragSession
;
2848 dragService
->GetCurrentSession(getter_AddRefs(dragSession
));
2850 // Rollup popups when a window is focused out unless a drag is occurring.
2851 // This check is because drags grab the keyboard and cause a focus out on
2852 // versions of GTK before 2.18.
2853 bool shouldRollup
= !dragSession
;
2854 if (!shouldRollup
) {
2855 // we also roll up when a drag is from a different application
2856 nsCOMPtr
<nsIDOMNode
> sourceNode
;
2857 dragSession
->GetSourceNode(getter_AddRefs(sourceNode
));
2858 shouldRollup
= (sourceNode
== nullptr);
2862 CheckForRollup(0, 0, false, true);
2866 #if (MOZ_WIDGET_GTK == 2) && defined(MOZ_X11)
2867 // plugin lose focus
2868 if (gPluginFocusWindow
) {
2869 nsRefPtr
<nsWindow
> kungFuDeathGrip
= gPluginFocusWindow
;
2870 gPluginFocusWindow
->LoseNonXEmbedPluginFocus();
2872 #endif /* MOZ_X11 && MOZ_WIDGET_GTK2 */
2875 nsRefPtr
<nsWindow
> kungFuDeathGrip
= gFocusWindow
;
2876 if (gFocusWindow
->mIMModule
) {
2877 gFocusWindow
->mIMModule
->OnBlurWindow(gFocusWindow
);
2879 gFocusWindow
= nullptr;
2882 DispatchDeactivateEvent();
2884 LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
2888 nsWindow::DispatchCommandEvent(nsIAtom
* aCommand
)
2890 nsEventStatus status
;
2891 WidgetCommandEvent
event(true, nsGkAtoms::onAppCommand
, aCommand
, this);
2892 DispatchEvent(&event
, status
);
2897 nsWindow::DispatchContentCommandEvent(int32_t aMsg
)
2899 nsEventStatus status
;
2900 WidgetContentCommandEvent
event(true, aMsg
, this);
2901 DispatchEvent(&event
, status
);
2906 IsCtrlAltTab(GdkEventKey
*aEvent
)
2908 return aEvent
->keyval
== GDK_Tab
&&
2909 KeymapWrapper::AreModifiersActive(
2910 KeymapWrapper::CTRL
| KeymapWrapper::ALT
, aEvent
->state
);
2914 nsWindow::DispatchKeyDownEvent(GdkEventKey
*aEvent
, bool *aCancelled
)
2916 NS_PRECONDITION(aCancelled
, "aCancelled must not be null");
2918 *aCancelled
= false;
2920 if (IsCtrlAltTab(aEvent
)) {
2924 // send the key down event
2925 nsEventStatus status
;
2926 WidgetKeyboardEvent
downEvent(true, NS_KEY_DOWN
, this);
2927 KeymapWrapper::InitKeyEvent(downEvent
, aEvent
);
2928 DispatchEvent(&downEvent
, status
);
2929 *aCancelled
= (status
== nsEventStatus_eConsumeNoDefault
);
2934 nsWindow::OnKeyPressEvent(GdkEventKey
*aEvent
)
2936 LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
2938 // if we are in the middle of composing text, XIM gets to see it
2939 // before mozilla does.
2940 bool IMEWasEnabled
= false;
2942 IMEWasEnabled
= mIMModule
->IsEnabled();
2943 if (mIMModule
->OnKeyEvent(this, aEvent
)) {
2948 nsEventStatus status
;
2950 // work around for annoying things.
2951 if (IsCtrlAltTab(aEvent
)) {
2955 nsCOMPtr
<nsIWidget
> kungFuDeathGrip
= this;
2957 // Dispatch keydown event always. At auto repeating, we should send
2958 // KEYDOWN -> KEYPRESS -> KEYDOWN -> KEYPRESS ... -> KEYUP
2959 // However, old distributions (e.g., Ubuntu 9.10) sent native key
2960 // release event, so, on such platform, the DOM events will be:
2961 // KEYDOWN -> KEYPRESS -> KEYUP -> KEYDOWN -> KEYPRESS -> KEYUP...
2963 bool isKeyDownCancelled
= false;
2964 if (DispatchKeyDownEvent(aEvent
, &isKeyDownCancelled
) &&
2965 (MOZ_UNLIKELY(mIsDestroyed
) || isKeyDownCancelled
)) {
2969 // If a keydown event handler causes to enable IME, i.e., it moves
2970 // focus from IME unusable content to IME usable editor, we should
2971 // send the native key event to IME for the first input on the editor.
2972 if (!IMEWasEnabled
&& mIMModule
&& mIMModule
->IsEnabled()) {
2973 // Notice our keydown event was already dispatched. This prevents
2974 // unnecessary DOM keydown event in the editor.
2975 if (mIMModule
->OnKeyEvent(this, aEvent
, true)) {
2980 // Don't pass modifiers as NS_KEY_PRESS events.
2981 // TODO: Instead of selectively excluding some keys from NS_KEY_PRESS events,
2982 // we should instead selectively include (as per MSDN spec; no official
2983 // spec covers KeyPress events).
2984 if (!KeymapWrapper::IsKeyPressEventNecessary(aEvent
)) {
2989 #if ! defined AIX // no XFree86 on AIX 5L
2990 // Look for specialized app-command keys
2991 switch (aEvent
->keyval
) {
2993 return DispatchCommandEvent(nsGkAtoms::Back
);
2994 case XF86XK_Forward
:
2995 return DispatchCommandEvent(nsGkAtoms::Forward
);
2996 case XF86XK_Refresh
:
2997 return DispatchCommandEvent(nsGkAtoms::Reload
);
2999 return DispatchCommandEvent(nsGkAtoms::Stop
);
3001 return DispatchCommandEvent(nsGkAtoms::Search
);
3002 case XF86XK_Favorites
:
3003 return DispatchCommandEvent(nsGkAtoms::Bookmarks
);
3004 case XF86XK_HomePage
:
3005 return DispatchCommandEvent(nsGkAtoms::Home
);
3007 case GDK_F16
: // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo
3008 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY
);
3011 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT
);
3014 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE
);
3016 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO
);
3019 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO
);
3022 #endif /* MOZ_X11 */
3024 WidgetKeyboardEvent
event(true, NS_KEY_PRESS
, this);
3025 KeymapWrapper::InitKeyEvent(event
, aEvent
);
3027 // before we dispatch a key, check if it's the context menu key.
3028 // If so, send a context menu key event instead.
3029 if (is_context_menu_key(event
)) {
3030 WidgetMouseEvent
contextMenuEvent(true, NS_CONTEXTMENU
, this,
3031 WidgetMouseEvent::eReal
,
3032 WidgetMouseEvent::eContextMenuKey
);
3034 contextMenuEvent
.refPoint
= LayoutDeviceIntPoint(0, 0);
3035 contextMenuEvent
.time
= aEvent
->time
;
3036 contextMenuEvent
.clickCount
= 1;
3037 KeymapWrapper::InitInputEvent(contextMenuEvent
, aEvent
->state
);
3038 DispatchEvent(&contextMenuEvent
, status
);
3041 // If the character code is in the BMP, send the key press event.
3042 // Otherwise, send a text event with the equivalent UTF-16 string.
3043 if (IS_IN_BMP(event
.charCode
)) {
3044 DispatchEvent(&event
, status
);
3047 WidgetTextEvent
textEvent(true, NS_TEXT_TEXT
, this);
3048 char16_t textString
[3];
3049 textString
[0] = H_SURROGATE(event
.charCode
);
3050 textString
[1] = L_SURROGATE(event
.charCode
);
3052 textEvent
.theText
= textString
;
3053 textEvent
.time
= event
.time
;
3054 DispatchEvent(&textEvent
, status
);
3058 // If the event was consumed, return.
3059 if (status
== nsEventStatus_eConsumeNoDefault
) {
3067 nsWindow::OnKeyReleaseEvent(GdkEventKey
*aEvent
)
3069 LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
3071 if (mIMModule
&& mIMModule
->OnKeyEvent(this, aEvent
)) {
3075 // send the key event as a key up event
3076 WidgetKeyboardEvent
event(true, NS_KEY_UP
, this);
3077 KeymapWrapper::InitKeyEvent(event
, aEvent
);
3079 nsEventStatus status
;
3080 DispatchEvent(&event
, status
);
3082 // If the event was consumed, return.
3083 if (status
== nsEventStatus_eConsumeNoDefault
) {
3091 nsWindow::OnScrollEvent(GdkEventScroll
*aEvent
)
3093 // check to see if we should rollup
3094 if (CheckForRollup(aEvent
->x_root
, aEvent
->y_root
, true, false))
3096 #if GTK_CHECK_VERSION(3,4,0)
3097 // check for duplicate legacy scroll event, see GNOME bug 726878
3098 if (mLastScrollEventTime
== aEvent
->time
)
3101 WidgetWheelEvent
wheelEvent(true, NS_WHEEL_WHEEL
, this);
3102 wheelEvent
.deltaMode
= nsIDOMWheelEvent::DOM_DELTA_LINE
;
3103 switch (aEvent
->direction
) {
3104 #if GTK_CHECK_VERSION(3,4,0)
3105 case GDK_SCROLL_SMOOTH
:
3107 // As of GTK 3.4, all directional scroll events are provided by
3108 // the GDK_SCROLL_SMOOTH direction on XInput2 devices.
3109 mLastScrollEventTime
= aEvent
->time
;
3110 // TODO - use a more appropriate scrolling unit than lines.
3111 // Multiply event deltas by 3 to emulate legacy behaviour.
3112 wheelEvent
.deltaX
= aEvent
->delta_x
* 3;
3113 wheelEvent
.deltaY
= aEvent
->delta_y
* 3;
3114 wheelEvent
.mIsNoLineOrPageDelta
= true;
3115 // This next step manually unsets smooth scrolling for touch devices
3116 // that trigger GDK_SCROLL_SMOOTH. We use the slave device, which
3117 // represents the actual input.
3118 GdkDevice
*device
= gdk_event_get_source_device((GdkEvent
*)aEvent
);
3119 GdkInputSource source
= gdk_device_get_source(device
);
3120 if (source
== GDK_SOURCE_TOUCHSCREEN
||
3121 source
== GDK_SOURCE_TOUCHPAD
) {
3122 wheelEvent
.scrollType
= WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY
;
3128 wheelEvent
.deltaY
= wheelEvent
.lineOrPageDeltaY
= -3;
3130 case GDK_SCROLL_DOWN
:
3131 wheelEvent
.deltaY
= wheelEvent
.lineOrPageDeltaY
= 3;
3133 case GDK_SCROLL_LEFT
:
3134 wheelEvent
.deltaX
= wheelEvent
.lineOrPageDeltaX
= -1;
3136 case GDK_SCROLL_RIGHT
:
3137 wheelEvent
.deltaX
= wheelEvent
.lineOrPageDeltaX
= 1;
3141 NS_ASSERTION(wheelEvent
.deltaX
|| wheelEvent
.deltaY
,
3142 "deltaX or deltaY must be non-zero");
3144 if (aEvent
->window
== mGdkWindow
) {
3145 // we are the window that the event happened on so no need for expensive WidgetToScreenOffset
3146 wheelEvent
.refPoint
.x
= nscoord(aEvent
->x
);
3147 wheelEvent
.refPoint
.y
= nscoord(aEvent
->y
);
3149 // XXX we're never quite sure which GdkWindow the event came from due to our custom bubbling
3150 // in scroll_event_cb(), so use ScreenToWidget to translate the screen root coordinates into
3151 // coordinates relative to this widget.
3152 LayoutDeviceIntPoint
point(NSToIntFloor(aEvent
->x_root
),
3153 NSToIntFloor(aEvent
->y_root
));
3154 wheelEvent
.refPoint
= point
-
3155 LayoutDeviceIntPoint::FromUntyped(WidgetToScreenOffset());
3158 KeymapWrapper::InitInputEvent(wheelEvent
, aEvent
->state
);
3160 wheelEvent
.time
= aEvent
->time
;
3162 nsEventStatus status
;
3163 DispatchEvent(&wheelEvent
, status
);
3167 nsWindow::OnVisibilityNotifyEvent(GdkEventVisibility
*aEvent
)
3169 LOGDRAW(("Visibility event %i on [%p] %p\n",
3170 aEvent
->state
, this, aEvent
->window
));
3175 switch (aEvent
->state
) {
3176 case GDK_VISIBILITY_UNOBSCURED
:
3177 case GDK_VISIBILITY_PARTIAL
:
3178 if (mIsFullyObscured
&& mHasMappedToplevel
) {
3179 // GDK_EXPOSE events have been ignored, so make sure GDK
3180 // doesn't think that the window has already been painted.
3181 gdk_window_invalidate_rect(mGdkWindow
, nullptr, FALSE
);
3184 mIsFullyObscured
= false;
3186 if (!nsGtkIMModule::IsVirtualKeyboardOpened()) {
3187 // if we have to retry the grab, retry it.
3191 default: // includes GDK_VISIBILITY_FULLY_OBSCURED
3192 mIsFullyObscured
= true;
3198 nsWindow::OnWindowStateEvent(GtkWidget
*aWidget
, GdkEventWindowState
*aEvent
)
3200 LOG(("nsWindow::OnWindowStateEvent [%p] changed %d new_window_state %d\n",
3201 (void *)this, aEvent
->changed_mask
, aEvent
->new_window_state
));
3203 if (IS_MOZ_CONTAINER(aWidget
)) {
3204 // This event is notifying the container widget of changes to the
3205 // toplevel window. Just detect changes affecting whether windows are
3208 // (A visibility notify event is sent to each window that becomes
3209 // viewable when the toplevel is mapped, but we can't rely on that for
3210 // setting mHasMappedToplevel because these toplevel window state
3211 // events are asynchronous. The windows in the hierarchy now may not
3212 // be the same windows as when the toplevel was mapped, so they may
3213 // not get VisibilityNotify events.)
3215 !(aEvent
->new_window_state
&
3216 (GDK_WINDOW_STATE_ICONIFIED
|GDK_WINDOW_STATE_WITHDRAWN
));
3217 if (mHasMappedToplevel
!= mapped
) {
3218 SetHasMappedToplevel(mapped
);
3222 // else the widget is a shell widget.
3224 // We don't care about anything but changes in the maximized/icon/fullscreen
3226 if ((aEvent
->changed_mask
3227 & (GDK_WINDOW_STATE_ICONIFIED
|
3228 GDK_WINDOW_STATE_MAXIMIZED
|
3229 GDK_WINDOW_STATE_FULLSCREEN
)) == 0) {
3233 if (aEvent
->new_window_state
& GDK_WINDOW_STATE_ICONIFIED
) {
3234 LOG(("\tIconified\n"));
3235 mSizeState
= nsSizeMode_Minimized
;
3236 #ifdef ACCESSIBILITY
3237 DispatchMinimizeEventAccessible();
3238 #endif //ACCESSIBILITY
3240 else if (aEvent
->new_window_state
& GDK_WINDOW_STATE_FULLSCREEN
) {
3241 LOG(("\tFullscreen\n"));
3242 mSizeState
= nsSizeMode_Fullscreen
;
3244 else if (aEvent
->new_window_state
& GDK_WINDOW_STATE_MAXIMIZED
) {
3245 LOG(("\tMaximized\n"));
3246 mSizeState
= nsSizeMode_Maximized
;
3247 #ifdef ACCESSIBILITY
3248 DispatchMaximizeEventAccessible();
3249 #endif //ACCESSIBILITY
3252 LOG(("\tNormal\n"));
3253 mSizeState
= nsSizeMode_Normal
;
3254 #ifdef ACCESSIBILITY
3255 DispatchRestoreEventAccessible();
3256 #endif //ACCESSIBILITY
3259 if (mWidgetListener
)
3260 mWidgetListener
->SizeModeChanged(mSizeState
);
3264 nsWindow::ThemeChanged()
3266 NotifyThemeChanged();
3268 if (!mGdkWindow
|| MOZ_UNLIKELY(mIsDestroyed
))
3271 // Dispatch theme change notification to all child windows
3273 gdk_window_peek_children(mGdkWindow
);
3275 GdkWindow
*gdkWin
= GDK_WINDOW(children
->data
);
3277 nsWindow
*win
= (nsWindow
*) g_object_get_data(G_OBJECT(gdkWin
),
3280 if (win
&& win
!= this) { // guard against infinite recursion
3281 nsRefPtr
<nsWindow
> kungFuDeathGrip
= win
;
3282 win
->ThemeChanged();
3285 children
= children
->next
;
3290 nsWindow::DispatchDragEvent(uint32_t aMsg
, const nsIntPoint
& aRefPoint
,
3293 WidgetDragEvent
event(true, aMsg
, this);
3295 if (aMsg
== NS_DRAGDROP_OVER
) {
3296 InitDragEvent(event
);
3299 event
.refPoint
= LayoutDeviceIntPoint::FromUntyped(aRefPoint
);
3302 nsEventStatus status
;
3303 DispatchEvent(&event
, status
);
3307 nsWindow::OnDragDataReceivedEvent(GtkWidget
*aWidget
,
3308 GdkDragContext
*aDragContext
,
3311 GtkSelectionData
*aSelectionData
,
3316 LOGDRAG(("nsWindow::OnDragDataReceived(%p)\n", (void*)this));
3318 nsDragService::GetInstance()->
3319 TargetDataReceived(aWidget
, aDragContext
, aX
, aY
,
3320 aSelectionData
, aInfo
, aTime
);
3324 GetBrandName(nsXPIDLString
& brandName
)
3326 nsCOMPtr
<nsIStringBundleService
> bundleService
=
3327 do_GetService(NS_STRINGBUNDLE_CONTRACTID
);
3329 nsCOMPtr
<nsIStringBundle
> bundle
;
3331 bundleService
->CreateBundle(
3332 "chrome://branding/locale/brand.properties",
3333 getter_AddRefs(bundle
));
3336 bundle
->GetStringFromName(
3337 MOZ_UTF16("brandShortName"),
3338 getter_Copies(brandName
));
3340 if (brandName
.IsEmpty())
3341 brandName
.AssignLiteral(MOZ_UTF16("Mozilla"));
3345 CreateGdkWindow(GdkWindow
*parent
, GtkWidget
*widget
)
3347 GdkWindowAttr attributes
;
3348 gint attributes_mask
= GDK_WA_VISUAL
;
3350 attributes
.event_mask
= kEvents
;
3352 attributes
.width
= 1;
3353 attributes
.height
= 1;
3354 attributes
.wclass
= GDK_INPUT_OUTPUT
;
3355 attributes
.visual
= gtk_widget_get_visual(widget
);
3356 attributes
.window_type
= GDK_WINDOW_CHILD
;
3358 #if (MOZ_WIDGET_GTK == 2)
3359 attributes_mask
|= GDK_WA_COLORMAP
;
3360 attributes
.colormap
= gtk_widget_get_colormap(widget
);
3363 GdkWindow
*window
= gdk_window_new(parent
, &attributes
, attributes_mask
);
3364 gdk_window_set_user_data(window
, widget
);
3367 #if (MOZ_WIDGET_GTK == 2)
3368 /* set the default pixmap to None so that you don't end up with the
3369 gtk default which is BlackPixel. */
3370 gdk_window_set_back_pixmap(window
, nullptr, FALSE
);
3377 nsWindow::Create(nsIWidget
*aParent
,
3378 nsNativeWidget aNativeParent
,
3379 const nsIntRect
&aRect
,
3380 nsDeviceContext
*aContext
,
3381 nsWidgetInitData
*aInitData
)
3383 // only set the base parent if we're going to be a dialog or a
3385 nsIWidget
*baseParent
= aInitData
&&
3386 (aInitData
->mWindowType
== eWindowType_dialog
||
3387 aInitData
->mWindowType
== eWindowType_toplevel
||
3388 aInitData
->mWindowType
== eWindowType_invisible
) ?
3391 #ifdef ACCESSIBILITY
3392 // Send a DBus message to check whether a11y is enabled
3396 // Ensure that the toolkit is created.
3397 nsGTKToolkit::GetToolkit();
3399 // initialize all the common bits of this class
3400 BaseCreate(baseParent
, aRect
, aContext
, aInitData
);
3402 // Do we need to listen for resizes?
3403 bool listenForResizes
= false;;
3404 if (aNativeParent
|| (aInitData
&& aInitData
->mListenForResizes
))
3405 listenForResizes
= true;
3407 // and do our common creation
3408 CommonCreate(aParent
, listenForResizes
);
3412 ConstrainSize(&mBounds
.width
, &mBounds
.height
);
3414 // figure out our parent window
3415 GtkWidget
*parentMozContainer
= nullptr;
3416 GtkContainer
*parentGtkContainer
= nullptr;
3417 GdkWindow
*parentGdkWindow
= nullptr;
3418 GtkWindow
*topLevelParent
= nullptr;
3419 nsWindow
*parentnsWindow
= nullptr;
3420 GtkWidget
*eventWidget
= nullptr;
3423 parentnsWindow
= static_cast<nsWindow
*>(aParent
);
3424 parentGdkWindow
= parentnsWindow
->mGdkWindow
;
3425 } else if (aNativeParent
&& GDK_IS_WINDOW(aNativeParent
)) {
3426 parentGdkWindow
= GDK_WINDOW(aNativeParent
);
3427 parentnsWindow
= get_window_for_gdk_window(parentGdkWindow
);
3428 if (!parentnsWindow
)
3429 return NS_ERROR_FAILURE
;
3431 } else if (aNativeParent
&& GTK_IS_CONTAINER(aNativeParent
)) {
3432 parentGtkContainer
= GTK_CONTAINER(aNativeParent
);
3435 if (parentGdkWindow
) {
3436 // get the widget for the window - it should be a moz container
3437 parentMozContainer
= parentnsWindow
->GetMozContainerWidget();
3438 if (!parentMozContainer
)
3439 return NS_ERROR_FAILURE
;
3441 // get the toplevel window just in case someone needs to use it
3442 // for setting transients or whatever.
3444 GTK_WINDOW(gtk_widget_get_toplevel(parentMozContainer
));
3447 // ok, create our windows
3448 switch (mWindowType
) {
3449 case eWindowType_dialog
:
3450 case eWindowType_popup
:
3451 case eWindowType_toplevel
:
3452 case eWindowType_invisible
: {
3455 // We only move a general managed toplevel window if someone has
3456 // actually placed the window somewhere. If no placement has taken
3457 // place, we just let the window manager Do The Right Thing.
3459 // Indicate that if we're shown, we at least need to have our size set.
3460 // If we get explicitly moved, the position will also be set.
3461 mNeedsResize
= true;
3463 if (mWindowType
== eWindowType_dialog
) {
3464 mShell
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
3466 gtk_window_set_wmclass(GTK_WINDOW(mShell
), "Dialog",
3467 gdk_get_program_class());
3468 gtk_window_set_type_hint(GTK_WINDOW(mShell
),
3469 GDK_WINDOW_TYPE_HINT_DIALOG
);
3470 gtk_window_set_transient_for(GTK_WINDOW(mShell
),
3473 else if (mWindowType
== eWindowType_popup
) {
3474 // With popup windows, we want to control their position, so don't
3475 // wait for the window manager to place them (which wouldn't
3476 // happen with override-redirect windows anyway).
3479 // Popups that are not noautohide are only temporary. The are used
3480 // for menus and the like and disappear when another window is used.
3481 // For most popups, use the standard GtkWindowType GTK_WINDOW_POPUP,
3482 // which will use a Window with the override-redirect attribute
3483 // (for temporary windows).
3484 // For long-lived windows, their stacking order is managed by the
3485 // window manager, as indicated by GTK_WINDOW_TOPLEVEL ...
3486 GtkWindowType type
= aInitData
->mNoAutoHide
?
3487 GTK_WINDOW_TOPLEVEL
: GTK_WINDOW_POPUP
;
3488 mShell
= gtk_window_new(type
);
3489 gtk_window_set_wmclass(GTK_WINDOW(mShell
), "Popup",
3490 gdk_get_program_class());
3492 if (aInitData
->mSupportTranslucency
) {
3493 // We need to select an ARGB visual here instead of in
3494 // SetTransparencyMode() because it has to be done before the
3495 // widget is realized. An ARGB visual is only useful if we
3496 // are on a compositing window manager.
3497 GdkScreen
*screen
= gtk_widget_get_screen(mShell
);
3498 if (gdk_screen_is_composited(screen
)) {
3499 #if (MOZ_WIDGET_GTK == 2)
3500 GdkColormap
*colormap
=
3501 gdk_screen_get_rgba_colormap(screen
);
3502 gtk_widget_set_colormap(mShell
, colormap
);
3504 GdkVisual
*visual
= gdk_screen_get_rgba_visual(screen
);
3505 gtk_widget_set_visual(mShell
, visual
);
3509 if (aInitData
->mNoAutoHide
) {
3510 // ... but the window manager does not decorate this window,
3511 // nor provide a separate taskbar icon.
3512 if (mBorderStyle
== eBorderStyle_default
) {
3513 gtk_window_set_decorated(GTK_WINDOW(mShell
), FALSE
);
3516 bool decorate
= mBorderStyle
& eBorderStyle_title
;
3517 gtk_window_set_decorated(GTK_WINDOW(mShell
), decorate
);
3519 gtk_window_set_deletable(GTK_WINDOW(mShell
), mBorderStyle
& eBorderStyle_close
);
3522 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell
), TRUE
);
3523 // Element focus is managed by the parent window so the
3524 // WM_HINTS input field is set to False to tell the window
3525 // manager not to set input focus to this window ...
3526 gtk_window_set_accept_focus(GTK_WINDOW(mShell
), FALSE
);
3528 // ... but when the window manager offers focus through
3529 // WM_TAKE_FOCUS, focus is requested on the parent window.
3530 gtk_widget_realize(mShell
);
3531 gdk_window_add_filter(gtk_widget_get_window(mShell
),
3532 popup_take_focus_filter
, nullptr);
3536 GdkWindowTypeHint gtkTypeHint
;
3537 if (aInitData
->mIsDragPopup
) {
3538 gtkTypeHint
= GDK_WINDOW_TYPE_HINT_DND
;
3541 switch (aInitData
->mPopupHint
) {
3542 case ePopupTypeMenu
:
3543 gtkTypeHint
= GDK_WINDOW_TYPE_HINT_POPUP_MENU
;
3545 case ePopupTypeTooltip
:
3546 gtkTypeHint
= GDK_WINDOW_TYPE_HINT_TOOLTIP
;
3549 gtkTypeHint
= GDK_WINDOW_TYPE_HINT_UTILITY
;
3553 gtk_window_set_type_hint(GTK_WINDOW(mShell
), gtkTypeHint
);
3555 if (topLevelParent
) {
3556 gtk_window_set_transient_for(GTK_WINDOW(mShell
),
3560 else { // must be eWindowType_toplevel
3561 mShell
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
3563 gtk_window_set_wmclass(GTK_WINDOW(mShell
), "Toplevel",
3564 gdk_get_program_class());
3566 // each toplevel window gets its own window group
3567 GtkWindowGroup
*group
= gtk_window_group_new();
3568 gtk_window_group_add_window(group
, GTK_WINDOW(mShell
));
3569 g_object_unref(group
);
3572 // Prevent GtkWindow from painting a background to flicker.
3573 gtk_widget_set_app_paintable(mShell
, TRUE
);
3575 // Create a container to hold child windows and child GtkWidgets.
3576 GtkWidget
*container
= moz_container_new();
3577 mContainer
= MOZ_CONTAINER(container
);
3578 // Use mShell's window for drawing and events.
3579 gtk_widget_set_has_window(container
, FALSE
);
3580 eventWidget
= mShell
;
3581 gtk_widget_add_events(eventWidget
, kEvents
);
3582 gtk_container_add(GTK_CONTAINER(mShell
), container
);
3583 gtk_widget_realize(container
);
3585 // make sure this is the focus widget in the container
3586 gtk_widget_show(container
);
3587 gtk_widget_grab_focus(container
);
3589 // the drawing window
3590 mGdkWindow
= gtk_widget_get_window(mShell
);
3592 if (mWindowType
== eWindowType_popup
) {
3593 // gdk does not automatically set the cursor for "temporary"
3594 // windows, which are what gtk uses for popups.
3596 mCursor
= eCursor_wait
; // force SetCursor to actually set the
3597 // cursor, even though our internal state
3598 // indicates that we already have the
3600 SetCursor(eCursor_standard
);
3602 if (aInitData
->mNoAutoHide
) {
3603 gint wmd
= ConvertBorderStyles(mBorderStyle
);
3605 gdk_window_set_decorations(gtk_widget_get_window(mShell
), (GdkWMDecoration
) wmd
);
3608 // If the popup ignores mouse events, set an empty input shape.
3609 if (aInitData
->mMouseTransparent
) {
3610 #if (MOZ_WIDGET_GTK == 2)
3611 GdkRectangle rect
= { 0, 0, 0, 0 };
3612 GdkRegion
*region
= gdk_region_rectangle(&rect
);
3614 gdk_window_input_shape_combine_region(mGdkWindow
, region
, 0, 0);
3615 gdk_region_destroy(region
);
3617 cairo_rectangle_int_t rect
= { 0, 0, 0, 0 };
3618 cairo_region_t
*region
= cairo_region_create_rectangle(&rect
);
3620 gdk_window_input_shape_combine_region(mGdkWindow
, region
, 0, 0);
3621 cairo_region_destroy(region
);
3627 case eWindowType_plugin
:
3628 case eWindowType_child
: {
3629 if (parentMozContainer
) {
3630 mGdkWindow
= CreateGdkWindow(parentGdkWindow
, parentMozContainer
);
3631 mHasMappedToplevel
= parentnsWindow
->mHasMappedToplevel
;
3633 else if (parentGtkContainer
) {
3634 // This MozContainer has its own window for drawing and receives
3635 // events because there is no mShell widget (corresponding to this
3637 GtkWidget
*container
= moz_container_new();
3638 mContainer
= MOZ_CONTAINER(container
);
3639 eventWidget
= container
;
3640 gtk_widget_add_events(eventWidget
, kEvents
);
3641 gtk_container_add(parentGtkContainer
, container
);
3642 gtk_widget_realize(container
);
3644 mGdkWindow
= gtk_widget_get_window(container
);
3647 NS_WARNING("Warning: tried to create a new child widget with no parent!");
3648 return NS_ERROR_FAILURE
;
3656 // label the drawing window with this object so we can find our way home
3657 g_object_set_data(G_OBJECT(mGdkWindow
), "nsWindow", this);
3660 g_object_set_data(G_OBJECT(mContainer
), "nsWindow", this);
3663 g_object_set_data(G_OBJECT(mShell
), "nsWindow", this);
3665 // attach listeners for events
3667 g_signal_connect(mShell
, "configure_event",
3668 G_CALLBACK(configure_event_cb
), nullptr);
3669 g_signal_connect(mShell
, "delete_event",
3670 G_CALLBACK(delete_event_cb
), nullptr);
3671 g_signal_connect(mShell
, "window_state_event",
3672 G_CALLBACK(window_state_event_cb
), nullptr);
3674 GtkSettings
* default_settings
= gtk_settings_get_default();
3675 g_signal_connect_after(default_settings
,
3676 "notify::gtk-theme-name",
3677 G_CALLBACK(theme_changed_cb
), this);
3678 g_signal_connect_after(default_settings
,
3679 "notify::gtk-font-name",
3680 G_CALLBACK(theme_changed_cb
), this);
3685 g_signal_connect(mContainer
, "unrealize",
3686 G_CALLBACK(container_unrealize_cb
), nullptr);
3687 g_signal_connect_after(mContainer
, "size_allocate",
3688 G_CALLBACK(size_allocate_cb
), nullptr);
3689 g_signal_connect(mContainer
, "hierarchy-changed",
3690 G_CALLBACK(hierarchy_changed_cb
), nullptr);
3691 // Initialize mHasMappedToplevel.
3692 hierarchy_changed_cb(GTK_WIDGET(mContainer
), nullptr);
3693 // Expose, focus, key, and drag events are sent even to GTK_NO_WINDOW
3695 #if (MOZ_WIDGET_GTK == 2)
3696 g_signal_connect(mContainer
, "expose_event",
3697 G_CALLBACK(expose_event_cb
), nullptr);
3699 g_signal_connect(G_OBJECT(mContainer
), "draw",
3700 G_CALLBACK(expose_event_cb
), nullptr);
3702 g_signal_connect(mContainer
, "focus_in_event",
3703 G_CALLBACK(focus_in_event_cb
), nullptr);
3704 g_signal_connect(mContainer
, "focus_out_event",
3705 G_CALLBACK(focus_out_event_cb
), nullptr);
3706 g_signal_connect(mContainer
, "key_press_event",
3707 G_CALLBACK(key_press_event_cb
), nullptr);
3708 g_signal_connect(mContainer
, "key_release_event",
3709 G_CALLBACK(key_release_event_cb
), nullptr);
3711 gtk_drag_dest_set((GtkWidget
*)mContainer
,
3717 g_signal_connect(mContainer
, "drag_motion",
3718 G_CALLBACK(drag_motion_event_cb
), nullptr);
3719 g_signal_connect(mContainer
, "drag_leave",
3720 G_CALLBACK(drag_leave_event_cb
), nullptr);
3721 g_signal_connect(mContainer
, "drag_drop",
3722 G_CALLBACK(drag_drop_event_cb
), nullptr);
3723 g_signal_connect(mContainer
, "drag_data_received",
3724 G_CALLBACK(drag_data_received_event_cb
), nullptr);
3726 GtkWidget
*widgets
[] = { GTK_WIDGET(mContainer
), mShell
};
3727 for (size_t i
= 0; i
< ArrayLength(widgets
) && widgets
[i
]; ++i
) {
3728 // Visibility events are sent to the owning widget of the relevant
3729 // window but do not propagate to parent widgets so connect on
3730 // mShell (if it exists) as well as mContainer.
3731 g_signal_connect(widgets
[i
], "visibility-notify-event",
3732 G_CALLBACK(visibility_notify_event_cb
), nullptr);
3733 // Similarly double buffering is controlled by the window's owning
3734 // widget. Disable double buffering for painting directly to the
3736 gtk_widget_set_double_buffered(widgets
[i
], FALSE
);
3739 // We create input contexts for all containers, except for
3740 // toplevel popup windows
3741 if (mWindowType
!= eWindowType_popup
) {
3742 mIMModule
= new nsGtkIMModule(this);
3744 } else if (!mIMModule
) {
3745 nsWindow
*container
= GetContainerWindow();
3747 mIMModule
= container
->mIMModule
;
3752 #if (MOZ_WIDGET_GTK == 2)
3753 // Don't let GTK mess with the shapes of our GdkWindows
3754 GTK_PRIVATE_SET_FLAG(eventWidget
, GTK_HAS_SHAPE_MASK
);
3757 // These events are sent to the owning widget of the relevant window
3758 // and propagate up to the first widget that handles the events, so we
3759 // need only connect on mShell, if it exists, to catch events on its
3760 // window and windows of mContainer.
3761 g_signal_connect(eventWidget
, "enter-notify-event",
3762 G_CALLBACK(enter_notify_event_cb
), nullptr);
3763 g_signal_connect(eventWidget
, "leave-notify-event",
3764 G_CALLBACK(leave_notify_event_cb
), nullptr);
3765 g_signal_connect(eventWidget
, "motion-notify-event",
3766 G_CALLBACK(motion_notify_event_cb
), nullptr);
3767 g_signal_connect(eventWidget
, "button-press-event",
3768 G_CALLBACK(button_press_event_cb
), nullptr);
3769 g_signal_connect(eventWidget
, "button-release-event",
3770 G_CALLBACK(button_release_event_cb
), nullptr);
3771 g_signal_connect(eventWidget
, "scroll-event",
3772 G_CALLBACK(scroll_event_cb
), nullptr);
3775 LOG(("nsWindow [%p]\n", (void *)this));
3777 LOG(("\tmShell %p mContainer %p mGdkWindow %p 0x%lx\n",
3778 mShell
, mContainer
, mGdkWindow
,
3779 gdk_x11_window_get_xid(mGdkWindow
)));
3780 } else if (mContainer
) {
3781 LOG(("\tmContainer %p mGdkWindow %p\n", mContainer
, mGdkWindow
));
3783 else if (mGdkWindow
) {
3784 LOG(("\tmGdkWindow %p parent %p\n",
3785 mGdkWindow
, gdk_window_get_parent(mGdkWindow
)));
3788 // resize so that everything is set to the right dimensions
3790 Resize(mBounds
.x
, mBounds
.y
, mBounds
.width
, mBounds
.height
, false);
3796 nsWindow::SetWindowClass(const nsAString
&xulWinType
)
3799 return NS_ERROR_FAILURE
;
3801 const char *res_class
= gdk_get_program_class();
3803 return NS_ERROR_FAILURE
;
3805 char *res_name
= ToNewCString(xulWinType
);
3807 return NS_ERROR_OUT_OF_MEMORY
;
3809 const char *role
= nullptr;
3811 // Parse res_name into a name and role. Characters other than
3812 // [A-Za-z0-9_-] are converted to '_'. Anything after the first
3813 // colon is assigned to role; if there's no colon, assign the
3814 // whole thing to both role and res_name.
3815 for (char *c
= res_name
; *c
; c
++) {
3820 else if (!isascii(*c
) || (!isalnum(*c
) && ('_' != *c
) && ('-' != *c
)))
3823 res_name
[0] = toupper(res_name
[0]);
3824 if (!role
) role
= res_name
;
3826 GdkWindow
*shellWindow
= gtk_widget_get_window(GTK_WIDGET(mShell
));
3827 gdk_window_set_role(shellWindow
, role
);
3830 XClassHint
*class_hint
= XAllocClassHint();
3832 nsMemory::Free(res_name
);
3833 return NS_ERROR_OUT_OF_MEMORY
;
3835 class_hint
->res_name
= res_name
;
3836 class_hint
->res_class
= const_cast<char*>(res_class
);
3838 // Can't use gtk_window_set_wmclass() for this; it prints
3839 // a warning & refuses to make the change.
3840 XSetClassHint(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
3841 gdk_x11_window_get_xid(shellWindow
),
3844 #endif /* MOZ_X11 */
3846 nsMemory::Free(res_name
);
3852 nsWindow::NativeResize(int32_t aWidth
, int32_t aHeight
, bool aRepaint
)
3854 LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
3857 // clear our resize flag
3858 mNeedsResize
= false;
3861 gtk_window_resize(GTK_WINDOW(mShell
), aWidth
, aHeight
);
3863 else if (mContainer
) {
3864 GtkWidget
*widget
= GTK_WIDGET(mContainer
);
3865 GtkAllocation allocation
, prev_allocation
;
3866 gtk_widget_get_allocation(widget
, &prev_allocation
);
3867 allocation
.x
= prev_allocation
.x
;
3868 allocation
.y
= prev_allocation
.y
;
3869 allocation
.width
= aWidth
;
3870 allocation
.height
= aHeight
;
3871 gtk_widget_size_allocate(widget
, &allocation
);
3873 else if (mGdkWindow
) {
3874 gdk_window_resize(mGdkWindow
, aWidth
, aHeight
);
3879 nsWindow::NativeResize(int32_t aX
, int32_t aY
,
3880 int32_t aWidth
, int32_t aHeight
,
3883 mNeedsResize
= false;
3886 LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
3887 aX
, aY
, aWidth
, aHeight
));
3890 // aX and aY give the position of the window manager frame top-left.
3891 gtk_window_move(GTK_WINDOW(mShell
), aX
, aY
);
3892 // This sets the client window size.
3893 gtk_window_resize(GTK_WINDOW(mShell
), aWidth
, aHeight
);
3895 else if (mContainer
) {
3896 GtkAllocation allocation
;
3899 allocation
.width
= aWidth
;
3900 allocation
.height
= aHeight
;
3901 gtk_widget_size_allocate(GTK_WIDGET(mContainer
), &allocation
);
3903 else if (mGdkWindow
) {
3904 gdk_window_move_resize(mGdkWindow
, aX
, aY
, aWidth
, aHeight
);
3909 nsWindow::NativeShow(bool aAction
)
3912 // unset our flag now that our window has been shown
3916 // Set up usertime/startupID metadata for the created window.
3917 if (mWindowType
!= eWindowType_invisible
) {
3918 SetUserTimeAndStartupIDForActivatedWindow(mShell
);
3921 gtk_widget_show(mShell
);
3923 else if (mContainer
) {
3924 gtk_widget_show(GTK_WIDGET(mContainer
));
3926 else if (mGdkWindow
) {
3927 gdk_window_show_unraised(mGdkWindow
);
3932 gtk_widget_hide(GTK_WIDGET(mShell
));
3934 ClearTransparencyBitmap(); // Release some resources
3936 else if (mContainer
) {
3937 gtk_widget_hide(GTK_WIDGET(mContainer
));
3939 else if (mGdkWindow
) {
3940 gdk_window_hide(mGdkWindow
);
3946 nsWindow::SetHasMappedToplevel(bool aState
)
3948 // Even when aState == mHasMappedToplevel (as when this method is called
3949 // from Show()), child windows need to have their state checked, so don't
3951 bool oldState
= mHasMappedToplevel
;
3952 mHasMappedToplevel
= aState
;
3954 // mHasMappedToplevel is not updated for children of windows that are
3955 // hidden; GDK knows not to send expose events for these windows. The
3956 // state is recorded on the hidden window itself, but, for child trees of
3957 // hidden windows, their state essentially becomes disconnected from their
3958 // hidden parent. When the hidden parent gets shown, the child trees are
3959 // reconnected, and the state of the window being shown can be easily
3961 if (!mIsShown
|| !mGdkWindow
)
3964 if (aState
&& !oldState
&& !mIsFullyObscured
) {
3965 // GDK_EXPOSE events have been ignored but the window is now visible,
3966 // so make sure GDK doesn't think that the window has already been
3968 gdk_window_invalidate_rect(mGdkWindow
, nullptr, FALSE
);
3970 // Check that a grab didn't fail due to the window not being
3975 for (GList
*children
= gdk_window_peek_children(mGdkWindow
);
3977 children
= children
->next
) {
3978 GdkWindow
*gdkWin
= GDK_WINDOW(children
->data
);
3979 nsWindow
*child
= get_window_for_gdk_window(gdkWin
);
3981 if (child
&& child
->mHasMappedToplevel
!= aState
) {
3982 child
->SetHasMappedToplevel(aState
);
3988 nsWindow::GetSafeWindowSize(nsIntSize aSize
)
3990 // The X protocol uses CARD32 for window sizes, but the server (1.11.3)
3991 // reads it as CARD16. Sizes of pixmaps, used for drawing, are (unsigned)
3992 // CARD16 in the protocol, but the server's ProcCreatePixmap returns
3993 // BadAlloc if dimensions cannot be represented by signed shorts.
3994 nsIntSize result
= aSize
;
3995 const int32_t kInt16Max
= 32767;
3996 if (result
.width
> kInt16Max
) {
3997 result
.width
= kInt16Max
;
3999 if (result
.height
> kInt16Max
) {
4000 result
.height
= kInt16Max
;
4006 nsWindow::EnsureGrabs(void)
4008 if (mRetryPointerGrab
)
4009 GrabPointer(sRetryGrabTime
);
4013 nsWindow::CleanLayerManagerRecursive(void) {
4014 if (mLayerManager
) {
4015 mLayerManager
->Destroy();
4016 mLayerManager
= nullptr;
4019 DestroyCompositor();
4021 GList
* children
= gdk_window_peek_children(mGdkWindow
);
4022 for (GList
* list
= children
; list
; list
= list
->next
) {
4023 nsWindow
* window
= get_window_for_gdk_window(GDK_WINDOW(list
->data
));
4025 window
->CleanLayerManagerRecursive();
4031 nsWindow::SetTransparencyMode(nsTransparencyMode aMode
)
4034 // Pass the request to the toplevel window
4035 GtkWidget
*topWidget
= GetToplevelWidget();
4039 nsWindow
*topWindow
= get_window_for_gtk_widget(topWidget
);
4043 topWindow
->SetTransparencyMode(aMode
);
4046 bool isTransparent
= aMode
== eTransparencyTransparent
;
4048 if (mIsTransparent
== isTransparent
)
4051 if (!isTransparent
) {
4052 ClearTransparencyBitmap();
4053 } // else the new default alpha values are "all 1", so we don't
4054 // need to change anything yet
4056 mIsTransparent
= isTransparent
;
4058 // Need to clean our LayerManager up while still alive because
4059 // we don't want to use layers acceleration on shaped windows
4060 CleanLayerManagerRecursive();
4064 nsWindow::GetTransparencyMode()
4067 // Pass the request to the toplevel window
4068 GtkWidget
*topWidget
= GetToplevelWidget();
4070 return eTransparencyOpaque
;
4073 nsWindow
*topWindow
= get_window_for_gtk_widget(topWidget
);
4075 return eTransparencyOpaque
;
4078 return topWindow
->GetTransparencyMode();
4081 return mIsTransparent
? eTransparencyTransparent
: eTransparencyOpaque
;
4085 nsWindow::ConfigureChildren(const nsTArray
<Configuration
>& aConfigurations
)
4087 for (uint32_t i
= 0; i
< aConfigurations
.Length(); ++i
) {
4088 const Configuration
& configuration
= aConfigurations
[i
];
4089 nsWindow
* w
= static_cast<nsWindow
*>(configuration
.mChild
);
4090 NS_ASSERTION(w
->GetParent() == this,
4091 "Configured widget is not a child");
4092 w
->SetWindowClipRegion(configuration
.mClipRegion
, true);
4093 if (w
->mBounds
.Size() != configuration
.mBounds
.Size()) {
4094 w
->Resize(configuration
.mBounds
.x
, configuration
.mBounds
.y
,
4095 configuration
.mBounds
.width
, configuration
.mBounds
.height
,
4097 } else if (w
->mBounds
.TopLeft() != configuration
.mBounds
.TopLeft()) {
4098 w
->Move(configuration
.mBounds
.x
, configuration
.mBounds
.y
);
4100 w
->SetWindowClipRegion(configuration
.mClipRegion
, false);
4106 ToPixmanBox(const nsIntRect
& aRect
)
4108 pixman_box32_t result
;
4109 result
.x1
= aRect
.x
;
4110 result
.y1
= aRect
.y
;
4111 result
.x2
= aRect
.XMost();
4112 result
.y2
= aRect
.YMost();
4117 ToIntRect(const pixman_box32
& aBox
)
4122 result
.width
= aBox
.x2
- aBox
.x1
;
4123 result
.height
= aBox
.y2
- aBox
.y1
;
4128 InitRegion(pixman_region32
* aRegion
,
4129 const nsTArray
<nsIntRect
>& aRects
)
4131 nsAutoTArray
<pixman_box32
,10> rects
;
4132 rects
.SetCapacity(aRects
.Length());
4133 for (uint32_t i
= 0; i
< aRects
.Length (); ++i
) {
4134 if (!aRects
[i
].IsEmpty()) {
4135 rects
.AppendElement(ToPixmanBox(aRects
[i
]));
4139 pixman_region32_init_rects(aRegion
,
4140 rects
.Elements(), rects
.Length());
4144 GetIntRects(pixman_region32
& aRegion
, nsTArray
<nsIntRect
>* aRects
)
4147 pixman_box32
* boxes
= pixman_region32_rectangles(&aRegion
, &nRects
);
4148 aRects
->SetCapacity(aRects
->Length() + nRects
);
4149 for (int i
= 0; i
< nRects
; ++i
) {
4150 aRects
->AppendElement(ToIntRect(boxes
[i
]));
4155 nsWindow::SetWindowClipRegion(const nsTArray
<nsIntRect
>& aRects
,
4156 bool aIntersectWithExisting
)
4158 const nsTArray
<nsIntRect
>* newRects
= &aRects
;
4160 nsAutoTArray
<nsIntRect
,1> intersectRects
;
4161 if (aIntersectWithExisting
) {
4162 nsAutoTArray
<nsIntRect
,1> existingRects
;
4163 GetWindowClipRegion(&existingRects
);
4165 nsAutoRef
<pixman_region32
> existingRegion
;
4166 InitRegion(&existingRegion
, existingRects
);
4167 nsAutoRef
<pixman_region32
> newRegion
;
4168 InitRegion(&newRegion
, aRects
);
4169 nsAutoRef
<pixman_region32
> intersectRegion
;
4170 pixman_region32_init(&intersectRegion
);
4171 pixman_region32_intersect(&intersectRegion
,
4172 &newRegion
, &existingRegion
);
4174 // If mClipRects is null we haven't set a clip rect yet, so we
4175 // need to set the clip even if it is equal.
4177 pixman_region32_equal(&intersectRegion
, &existingRegion
)) {
4181 if (!pixman_region32_equal(&intersectRegion
, &newRegion
)) {
4182 GetIntRects(intersectRegion
, &intersectRects
);
4183 newRects
= &intersectRects
;
4187 if (!StoreWindowClipRegion(*newRects
))
4193 #if (MOZ_WIDGET_GTK == 2)
4194 GdkRegion
*region
= gdk_region_new(); // aborts on OOM
4195 for (uint32_t i
= 0; i
< newRects
->Length(); ++i
) {
4196 const nsIntRect
& r
= newRects
->ElementAt(i
);
4197 GdkRectangle rect
= { r
.x
, r
.y
, r
.width
, r
.height
};
4198 gdk_region_union_with_rect(region
, &rect
);
4201 gdk_window_shape_combine_region(mGdkWindow
, region
, 0, 0);
4202 gdk_region_destroy(region
);
4204 cairo_region_t
*region
= cairo_region_create();
4205 for (uint32_t i
= 0; i
< newRects
->Length(); ++i
) {
4206 const nsIntRect
& r
= newRects
->ElementAt(i
);
4207 cairo_rectangle_int_t rect
= { r
.x
, r
.y
, r
.width
, r
.height
};
4208 cairo_region_union_rectangle(region
, &rect
);
4211 gdk_window_shape_combine_region(mGdkWindow
, region
, 0, 0);
4212 cairo_region_destroy(region
);
4219 nsWindow::ResizeTransparencyBitmap()
4221 if (!mTransparencyBitmap
)
4224 if (mBounds
.width
== mTransparencyBitmapWidth
&&
4225 mBounds
.height
== mTransparencyBitmapHeight
)
4228 int32_t newRowBytes
= GetBitmapStride(mBounds
.width
);
4229 int32_t newSize
= newRowBytes
* mBounds
.height
;
4230 gchar
* newBits
= new gchar
[newSize
];
4231 // fill new mask with "transparent", first
4232 memset(newBits
, 0, newSize
);
4234 // Now copy the intersection of the old and new areas into the new mask
4235 int32_t copyWidth
= std::min(mBounds
.width
, mTransparencyBitmapWidth
);
4236 int32_t copyHeight
= std::min(mBounds
.height
, mTransparencyBitmapHeight
);
4237 int32_t oldRowBytes
= GetBitmapStride(mTransparencyBitmapWidth
);
4238 int32_t copyBytes
= GetBitmapStride(copyWidth
);
4241 gchar
* fromPtr
= mTransparencyBitmap
;
4242 gchar
* toPtr
= newBits
;
4243 for (i
= 0; i
< copyHeight
; i
++) {
4244 memcpy(toPtr
, fromPtr
, copyBytes
);
4245 fromPtr
+= oldRowBytes
;
4246 toPtr
+= newRowBytes
;
4249 delete[] mTransparencyBitmap
;
4250 mTransparencyBitmap
= newBits
;
4251 mTransparencyBitmapWidth
= mBounds
.width
;
4252 mTransparencyBitmapHeight
= mBounds
.height
;
4256 ChangedMaskBits(gchar
* aMaskBits
, int32_t aMaskWidth
, int32_t aMaskHeight
,
4257 const nsIntRect
& aRect
, uint8_t* aAlphas
, int32_t aStride
)
4259 int32_t x
, y
, xMax
= aRect
.XMost(), yMax
= aRect
.YMost();
4260 int32_t maskBytesPerRow
= GetBitmapStride(aMaskWidth
);
4261 for (y
= aRect
.y
; y
< yMax
; y
++) {
4262 gchar
* maskBytes
= aMaskBits
+ y
*maskBytesPerRow
;
4263 uint8_t* alphas
= aAlphas
;
4264 for (x
= aRect
.x
; x
< xMax
; x
++) {
4265 bool newBit
= *alphas
> 0x7f;
4268 gchar maskByte
= maskBytes
[x
>> 3];
4269 bool maskBit
= (maskByte
& (1 << (x
& 7))) != 0;
4271 if (maskBit
!= newBit
) {
4282 void UpdateMaskBits(gchar
* aMaskBits
, int32_t aMaskWidth
, int32_t aMaskHeight
,
4283 const nsIntRect
& aRect
, uint8_t* aAlphas
, int32_t aStride
)
4285 int32_t x
, y
, xMax
= aRect
.XMost(), yMax
= aRect
.YMost();
4286 int32_t maskBytesPerRow
= GetBitmapStride(aMaskWidth
);
4287 for (y
= aRect
.y
; y
< yMax
; y
++) {
4288 gchar
* maskBytes
= aMaskBits
+ y
*maskBytesPerRow
;
4289 uint8_t* alphas
= aAlphas
;
4290 for (x
= aRect
.x
; x
< xMax
; x
++) {
4291 bool newBit
= *alphas
> 0x7f;
4294 gchar mask
= 1 << (x
& 7);
4295 gchar maskByte
= maskBytes
[x
>> 3];
4296 // Note: '-newBit' turns 0 into 00...00 and 1 into 11...11
4297 maskBytes
[x
>> 3] = (maskByte
& ~mask
) | (-newBit
& mask
);
4304 nsWindow::ApplyTransparencyBitmap()
4307 // We use X11 calls where possible, because GDK handles expose events
4308 // for shaped windows in a way that's incompatible with us (Bug 635903).
4309 // It doesn't occur when the shapes are set through X.
4310 GdkWindow
*shellWindow
= gtk_widget_get_window(mShell
);
4311 Display
* xDisplay
= GDK_WINDOW_XDISPLAY(shellWindow
);
4312 Window xDrawable
= GDK_WINDOW_XID(shellWindow
);
4313 Pixmap maskPixmap
= XCreateBitmapFromData(xDisplay
,
4315 mTransparencyBitmap
,
4316 mTransparencyBitmapWidth
,
4317 mTransparencyBitmapHeight
);
4318 XShapeCombineMask(xDisplay
, xDrawable
,
4319 ShapeBounding
, 0, 0,
4320 maskPixmap
, ShapeSet
);
4321 XFreePixmap(xDisplay
, maskPixmap
);
4323 #if (MOZ_WIDGET_GTK == 2)
4324 gtk_widget_reset_shapes(mShell
);
4325 GdkBitmap
* maskBitmap
= gdk_bitmap_create_from_data(gtk_widget_get_window(mShell
),
4326 mTransparencyBitmap
,
4327 mTransparencyBitmapWidth
, mTransparencyBitmapHeight
);
4331 gtk_widget_shape_combine_mask(mShell
, maskBitmap
, 0, 0);
4332 g_object_unref(maskBitmap
);
4334 cairo_surface_t
*maskBitmap
;
4335 maskBitmap
= cairo_image_surface_create_for_data((unsigned char*)mTransparencyBitmap
,
4337 mTransparencyBitmapWidth
,
4338 mTransparencyBitmapHeight
,
4339 GetBitmapStride(mTransparencyBitmapWidth
));
4343 cairo_region_t
* maskRegion
= gdk_cairo_region_create_from_surface(maskBitmap
);
4344 gtk_widget_shape_combine_region(mShell
, maskRegion
);
4345 cairo_region_destroy(maskRegion
);
4346 cairo_surface_destroy(maskBitmap
);
4347 #endif // MOZ_WIDGET_GTK2
4352 nsWindow::ClearTransparencyBitmap()
4354 if (!mTransparencyBitmap
)
4357 delete[] mTransparencyBitmap
;
4358 mTransparencyBitmap
= nullptr;
4359 mTransparencyBitmapWidth
= 0;
4360 mTransparencyBitmapHeight
= 0;
4366 GdkWindow
*window
= gtk_widget_get_window(mShell
);
4370 Display
* xDisplay
= GDK_WINDOW_XDISPLAY(window
);
4371 Window xWindow
= gdk_x11_window_get_xid(window
);
4373 XShapeCombineMask(xDisplay
, xWindow
, ShapeBounding
, 0, 0, None
, ShapeSet
);
4378 nsWindow::UpdateTranslucentWindowAlphaInternal(const nsIntRect
& aRect
,
4379 uint8_t* aAlphas
, int32_t aStride
)
4382 // Pass the request to the toplevel window
4383 GtkWidget
*topWidget
= GetToplevelWidget();
4385 return NS_ERROR_FAILURE
;
4387 nsWindow
*topWindow
= get_window_for_gtk_widget(topWidget
);
4389 return NS_ERROR_FAILURE
;
4391 return topWindow
->UpdateTranslucentWindowAlphaInternal(aRect
, aAlphas
, aStride
);
4394 NS_ASSERTION(mIsTransparent
, "Window is not transparent");
4396 if (mTransparencyBitmap
== nullptr) {
4397 int32_t size
= GetBitmapStride(mBounds
.width
)*mBounds
.height
;
4398 mTransparencyBitmap
= new gchar
[size
];
4399 memset(mTransparencyBitmap
, 255, size
);
4400 mTransparencyBitmapWidth
= mBounds
.width
;
4401 mTransparencyBitmapHeight
= mBounds
.height
;
4403 ResizeTransparencyBitmap();
4407 rect
.IntersectRect(aRect
, nsIntRect(0, 0, mBounds
.width
, mBounds
.height
));
4409 if (!ChangedMaskBits(mTransparencyBitmap
, mBounds
.width
, mBounds
.height
,
4410 rect
, aAlphas
, aStride
))
4411 // skip the expensive stuff if the mask bits haven't changed; hopefully
4412 // this is the common case
4415 UpdateMaskBits(mTransparencyBitmap
, mBounds
.width
, mBounds
.height
,
4416 rect
, aAlphas
, aStride
);
4419 ApplyTransparencyBitmap();
4425 nsWindow::GrabPointer(guint32 aTime
)
4427 LOG(("GrabPointer time=0x%08x retry=%d\n",
4428 (unsigned int)aTime
, mRetryPointerGrab
));
4430 mRetryPointerGrab
= false;
4431 sRetryGrabTime
= aTime
;
4433 // If the window isn't visible, just set the flag to retry the
4434 // grab. When this window becomes visible, the grab will be
4436 if (!mHasMappedToplevel
|| mIsFullyObscured
) {
4437 LOG(("GrabPointer: window not visible\n"));
4438 mRetryPointerGrab
= true;
4446 retval
= gdk_pointer_grab(mGdkWindow
, TRUE
,
4447 (GdkEventMask
)(GDK_BUTTON_PRESS_MASK
|
4448 GDK_BUTTON_RELEASE_MASK
|
4449 GDK_ENTER_NOTIFY_MASK
|
4450 GDK_LEAVE_NOTIFY_MASK
|
4451 GDK_POINTER_MOTION_MASK
),
4452 (GdkWindow
*)nullptr, nullptr, aTime
);
4454 if (retval
== GDK_GRAB_NOT_VIEWABLE
) {
4455 LOG(("GrabPointer: window not viewable; will retry\n"));
4456 mRetryPointerGrab
= true;
4457 } else if (retval
!= GDK_GRAB_SUCCESS
) {
4458 LOG(("GrabPointer: pointer grab failed: %i\n", retval
));
4459 // A failed grab indicates that another app has grabbed the pointer.
4460 // Check for rollup now, because, without the grab, we likely won't
4461 // get subsequent button press events.
4462 CheckForRollup(0, 0, false, true);
4467 nsWindow::ReleaseGrabs(void)
4469 LOG(("ReleaseGrabs\n"));
4471 mRetryPointerGrab
= false;
4472 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
4476 nsWindow::GetToplevelWidget()
4482 GtkWidget
*widget
= GetMozContainerWidget();
4486 return gtk_widget_get_toplevel(widget
);
4490 nsWindow::GetMozContainerWidget()
4496 return GTK_WIDGET(mContainer
);
4498 GtkWidget
*owningWidget
=
4499 get_gtk_widget_for_gdk_window(mGdkWindow
);
4500 return owningWidget
;
4504 nsWindow::GetContainerWindow()
4506 GtkWidget
*owningWidget
= GetMozContainerWidget();
4510 nsWindow
*window
= get_window_for_gtk_widget(owningWidget
);
4511 NS_ASSERTION(window
, "No nsWindow for container widget");
4516 nsWindow::SetUrgencyHint(GtkWidget
*top_window
, bool state
)
4521 gdk_window_set_urgency_hint(gtk_widget_get_window(top_window
), state
);
4525 nsWindow::SetupPluginPort(void)
4530 if (gdk_window_is_destroyed(mGdkWindow
) == TRUE
)
4533 Window window
= gdk_x11_window_get_xid(mGdkWindow
);
4535 // we have to flush the X queue here so that any plugins that
4536 // might be running on separate X connections will be able to use
4537 // this window in case it was just created
4539 XWindowAttributes xattrs
;
4540 Display
*display
= GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
4541 XGetWindowAttributes(display
, window
, &xattrs
);
4542 XSelectInput (display
, window
,
4543 xattrs
.your_event_mask
|
4544 SubstructureNotifyMask
);
4546 gdk_window_add_filter(mGdkWindow
, plugin_window_filter_func
, this);
4548 XSync(display
, False
);
4549 #endif /* MOZ_X11 */
4551 return (void *)window
;
4555 nsWindow::SetDefaultIcon(void)
4557 SetIcon(NS_LITERAL_STRING("default"));
4561 nsWindow::SetPluginType(PluginType aPluginType
)
4563 mPluginType
= aPluginType
;
4568 nsWindow::SetNonXEmbedPluginFocus()
4570 if (gPluginFocusWindow
== this || mPluginType
!=PluginType_NONXEMBED
) {
4574 if (gPluginFocusWindow
) {
4575 nsRefPtr
<nsWindow
> kungFuDeathGrip
= gPluginFocusWindow
;
4576 gPluginFocusWindow
->LoseNonXEmbedPluginFocus();
4579 LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus\n"));
4581 Window curFocusWindow
;
4584 GdkDisplay
*gdkDisplay
= gdk_window_get_display(mGdkWindow
);
4585 XGetInputFocus(gdk_x11_display_get_xdisplay(gdkDisplay
),
4589 LOGFOCUS(("\t curFocusWindow=%p\n", curFocusWindow
));
4591 GdkWindow
* toplevel
= gdk_window_get_toplevel(mGdkWindow
);
4592 #if (MOZ_WIDGET_GTK == 2)
4593 GdkWindow
*gdkfocuswin
= gdk_window_lookup(curFocusWindow
);
4595 GdkWindow
*gdkfocuswin
= gdk_x11_window_lookup_for_display(gdkDisplay
,
4599 // lookup with the focus proxy window is supposed to get the
4600 // same GdkWindow as toplevel. If the current focused window
4601 // is not the focus proxy, we return without any change.
4602 if (gdkfocuswin
!= toplevel
) {
4606 // switch the focus from the focus proxy to the plugin window
4607 mOldFocusWindow
= curFocusWindow
;
4608 XRaiseWindow(GDK_WINDOW_XDISPLAY(mGdkWindow
),
4609 gdk_x11_window_get_xid(mGdkWindow
));
4610 gdk_error_trap_push();
4611 XSetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow
),
4612 gdk_x11_window_get_xid(mGdkWindow
),
4616 #if (MOZ_WIDGET_GTK == 3)
4617 gdk_error_trap_pop_ignored();
4619 gdk_error_trap_pop();
4621 gPluginFocusWindow
= this;
4622 gdk_window_add_filter(nullptr, plugin_client_message_filter
, this);
4624 LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus oldfocus=%p new=%p\n",
4625 mOldFocusWindow
, gdk_x11_window_get_xid(mGdkWindow
)));
4629 nsWindow::LoseNonXEmbedPluginFocus()
4631 LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus\n"));
4633 // This method is only for the nsWindow which contains a
4634 // Non-XEmbed plugin, for example, JAVA plugin.
4635 if (gPluginFocusWindow
!= this || mPluginType
!=PluginType_NONXEMBED
) {
4639 Window curFocusWindow
;
4642 XGetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow
),
4646 // we only switch focus between plugin window and focus proxy. If the
4647 // current focused window is not the plugin window, just removing the
4648 // event filter that blocks the WM_TAKE_FOCUS is enough. WM and gtk2
4649 // will take care of the focus later.
4650 if (!curFocusWindow
||
4651 curFocusWindow
== gdk_x11_window_get_xid(mGdkWindow
)) {
4653 gdk_error_trap_push();
4654 XRaiseWindow(GDK_WINDOW_XDISPLAY(mGdkWindow
),
4656 XSetInputFocus(GDK_WINDOW_XDISPLAY(mGdkWindow
),
4661 #if (MOZ_WIDGET_GTK == 3)
4662 gdk_error_trap_pop_ignored();
4664 gdk_error_trap_pop();
4667 gPluginFocusWindow
= nullptr;
4668 mOldFocusWindow
= 0;
4669 gdk_window_remove_filter(nullptr, plugin_client_message_filter
, this);
4671 LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus end\n"));
4673 #endif /* MOZ_X11 */
4676 nsWindow::ConvertBorderStyles(nsBorderStyle aStyle
)
4680 if (aStyle
== eBorderStyle_default
)
4683 // note that we don't handle eBorderStyle_close yet
4684 if (aStyle
& eBorderStyle_all
)
4686 if (aStyle
& eBorderStyle_border
)
4687 w
|= GDK_DECOR_BORDER
;
4688 if (aStyle
& eBorderStyle_resizeh
)
4689 w
|= GDK_DECOR_RESIZEH
;
4690 if (aStyle
& eBorderStyle_title
)
4691 w
|= GDK_DECOR_TITLE
;
4692 if (aStyle
& eBorderStyle_menu
)
4693 w
|= GDK_DECOR_MENU
;
4694 if (aStyle
& eBorderStyle_minimize
)
4695 w
|= GDK_DECOR_MINIMIZE
;
4696 if (aStyle
& eBorderStyle_maximize
)
4697 w
|= GDK_DECOR_MAXIMIZE
;
4703 nsWindow::MakeFullScreen(bool aFullScreen
)
4705 LOG(("nsWindow::MakeFullScreen [%p] aFullScreen %d\n",
4706 (void *)this, aFullScreen
));
4709 if (mSizeMode
!= nsSizeMode_Fullscreen
)
4710 mLastSizeMode
= mSizeMode
;
4712 mSizeMode
= nsSizeMode_Fullscreen
;
4713 gtk_window_fullscreen(GTK_WINDOW(mShell
));
4716 mSizeMode
= mLastSizeMode
;
4717 gtk_window_unfullscreen(GTK_WINDOW(mShell
));
4720 NS_ASSERTION(mLastSizeMode
!= nsSizeMode_Fullscreen
,
4721 "mLastSizeMode should never be fullscreen");
4726 nsWindow::HideWindowChrome(bool aShouldHide
)
4729 // Pass the request to the toplevel window
4730 GtkWidget
*topWidget
= GetToplevelWidget();
4732 return NS_ERROR_FAILURE
;
4734 nsWindow
*topWindow
= get_window_for_gtk_widget(topWidget
);
4736 return NS_ERROR_FAILURE
;
4738 return topWindow
->HideWindowChrome(aShouldHide
);
4741 // Sawfish, metacity, and presumably other window managers get
4742 // confused if we change the window decorations while the window
4744 bool wasVisible
= false;
4745 GdkWindow
*shellWindow
= gtk_widget_get_window(mShell
);
4746 if (gdk_window_is_visible(shellWindow
)) {
4747 gdk_window_hide(shellWindow
);
4755 wmd
= ConvertBorderStyles(mBorderStyle
);
4758 gdk_window_set_decorations(shellWindow
, (GdkWMDecoration
) wmd
);
4761 gdk_window_show(shellWindow
);
4763 // For some window managers, adding or removing window decorations
4764 // requires unmapping and remapping our toplevel window. Go ahead
4765 // and flush the queue here so that we don't end up with a BadWindow
4766 // error later when this happens (when the persistence timer fires
4767 // and GetWindowPos is called)
4769 XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) , False
);
4772 #endif /* MOZ_X11 */
4778 nsWindow::CheckForRollup(gdouble aMouseX
, gdouble aMouseY
,
4779 bool aIsWheel
, bool aAlwaysRollup
)
4781 nsIRollupListener
* rollupListener
= GetActiveRollupListener();
4782 nsCOMPtr
<nsIWidget
> rollupWidget
;
4783 if (rollupListener
) {
4784 rollupWidget
= rollupListener
->GetRollupWidget();
4786 if (!rollupWidget
) {
4787 nsBaseWidget::gRollupListener
= nullptr;
4791 bool retVal
= false;
4792 GdkWindow
*currentPopup
=
4793 (GdkWindow
*)rollupWidget
->GetNativeData(NS_NATIVE_WINDOW
);
4794 if (aAlwaysRollup
|| !is_mouse_in_window(currentPopup
, aMouseX
, aMouseY
)) {
4797 rollup
= rollupListener
->ShouldRollupOnMouseWheelEvent();
4798 retVal
= rollupListener
->ShouldConsumeOnMouseWheelEvent();
4800 // if we're dealing with menus, we probably have submenus and
4801 // we don't want to rollup if the click is in a parent menu of
4802 // the current submenu
4803 uint32_t popupsToRollup
= UINT32_MAX
;
4804 if (!aAlwaysRollup
) {
4805 nsAutoTArray
<nsIWidget
*, 5> widgetChain
;
4806 uint32_t sameTypeCount
= rollupListener
->GetSubmenuWidgetChain(&widgetChain
);
4807 for (uint32_t i
=0; i
<widgetChain
.Length(); ++i
) {
4808 nsIWidget
* widget
= widgetChain
[i
];
4809 GdkWindow
* currWindow
=
4810 (GdkWindow
*) widget
->GetNativeData(NS_NATIVE_WINDOW
);
4811 if (is_mouse_in_window(currWindow
, aMouseX
, aMouseY
)) {
4812 // don't roll up if the mouse event occurred within a
4813 // menu of the same type. If the mouse event occurred
4814 // in a menu higher than that, roll up, but pass the
4815 // number of popups to Rollup so that only those of the
4816 // same type close up.
4817 if (i
< sameTypeCount
) {
4821 popupsToRollup
= sameTypeCount
;
4825 } // foreach parent menu widget
4826 } // if rollup listener knows about menus
4828 // if we've determined that we should still rollup, do it.
4829 bool usePoint
= !aIsWheel
&& !aAlwaysRollup
;
4830 nsIntPoint
point(aMouseX
, aMouseY
);
4831 if (rollup
&& rollupListener
->Rollup(popupsToRollup
, usePoint
? &point
: nullptr, nullptr)) {
4840 nsWindow::DragInProgress(void)
4842 nsCOMPtr
<nsIDragService
> dragService
= do_GetService(kCDragServiceCID
);
4847 nsCOMPtr
<nsIDragSession
> currentDragSession
;
4848 dragService
->GetCurrentSession(getter_AddRefs(currentDragSession
));
4850 return currentDragSession
!= nullptr;
4854 is_mouse_in_window (GdkWindow
* aWindow
, gdouble aMouseX
, gdouble aMouseY
)
4863 GdkWindow
*window
= aWindow
;
4869 gdk_window_get_position(window
, &tmpX
, &tmpY
);
4870 GtkWidget
*widget
= get_gtk_widget_for_gdk_window(window
);
4872 // if this is a window, compute x and y given its origin and our
4874 if (GTK_IS_WINDOW(widget
)) {
4882 window
= gdk_window_get_parent(window
);
4885 #if (MOZ_WIDGET_GTK == 2)
4886 gdk_drawable_get_size(aWindow
, &w
, &h
);
4888 w
= gdk_window_get_width(aWindow
);
4889 h
= gdk_window_get_height(aWindow
);
4892 if (aMouseX
> x
&& aMouseX
< x
+ w
&&
4893 aMouseY
> y
&& aMouseY
< y
+ h
)
4900 get_window_for_gtk_widget(GtkWidget
*widget
)
4902 gpointer user_data
= g_object_get_data(G_OBJECT(widget
), "nsWindow");
4904 return static_cast<nsWindow
*>(user_data
);
4908 get_window_for_gdk_window(GdkWindow
*window
)
4910 gpointer user_data
= g_object_get_data(G_OBJECT(window
), "nsWindow");
4912 return static_cast<nsWindow
*>(user_data
);
4916 get_gtk_widget_for_gdk_window(GdkWindow
*window
)
4918 gpointer user_data
= nullptr;
4919 gdk_window_get_user_data(window
, &user_data
);
4921 return GTK_WIDGET(user_data
);
4925 get_gtk_cursor(nsCursor aCursor
)
4927 GdkCursor
*gdkcursor
= nullptr;
4928 uint8_t newType
= 0xff;
4930 if ((gdkcursor
= gCursorCache
[aCursor
])) {
4934 GdkDisplay
*defaultDisplay
= gdk_display_get_default();
4936 // The strategy here is to use standard GDK cursors, and, if not available,
4937 // load by standard name with gdk_cursor_new_from_name.
4938 // Spec is here: http://www.freedesktop.org/wiki/Specifications/cursor-spec/
4940 case eCursor_standard
:
4941 gdkcursor
= gdk_cursor_new(GDK_LEFT_PTR
);
4944 gdkcursor
= gdk_cursor_new(GDK_WATCH
);
4946 case eCursor_select
:
4947 gdkcursor
= gdk_cursor_new(GDK_XTERM
);
4949 case eCursor_hyperlink
:
4950 gdkcursor
= gdk_cursor_new(GDK_HAND2
);
4952 case eCursor_n_resize
:
4953 gdkcursor
= gdk_cursor_new(GDK_TOP_SIDE
);
4955 case eCursor_s_resize
:
4956 gdkcursor
= gdk_cursor_new(GDK_BOTTOM_SIDE
);
4958 case eCursor_w_resize
:
4959 gdkcursor
= gdk_cursor_new(GDK_LEFT_SIDE
);
4961 case eCursor_e_resize
:
4962 gdkcursor
= gdk_cursor_new(GDK_RIGHT_SIDE
);
4964 case eCursor_nw_resize
:
4965 gdkcursor
= gdk_cursor_new(GDK_TOP_LEFT_CORNER
);
4967 case eCursor_se_resize
:
4968 gdkcursor
= gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER
);
4970 case eCursor_ne_resize
:
4971 gdkcursor
= gdk_cursor_new(GDK_TOP_RIGHT_CORNER
);
4973 case eCursor_sw_resize
:
4974 gdkcursor
= gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER
);
4976 case eCursor_crosshair
:
4977 gdkcursor
= gdk_cursor_new(GDK_CROSSHAIR
);
4980 gdkcursor
= gdk_cursor_new(GDK_FLEUR
);
4983 gdkcursor
= gdk_cursor_new(GDK_QUESTION_ARROW
);
4985 case eCursor_copy
: // CSS3
4986 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "copy");
4988 newType
= MOZ_CURSOR_COPY
;
4991 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "alias");
4993 newType
= MOZ_CURSOR_ALIAS
;
4995 case eCursor_context_menu
:
4996 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "context-menu");
4998 newType
= MOZ_CURSOR_CONTEXT_MENU
;
5001 gdkcursor
= gdk_cursor_new(GDK_PLUS
);
5003 // Those two aren’t standardized. Trying both KDE’s and GNOME’s names
5005 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "openhand");
5007 newType
= MOZ_CURSOR_HAND_GRAB
;
5009 case eCursor_grabbing
:
5010 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "closedhand");
5012 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "grabbing");
5014 newType
= MOZ_CURSOR_HAND_GRABBING
;
5016 case eCursor_spinning
:
5017 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "progress");
5019 newType
= MOZ_CURSOR_SPINNING
;
5021 case eCursor_zoom_in
:
5022 newType
= MOZ_CURSOR_ZOOM_IN
;
5024 case eCursor_zoom_out
:
5025 newType
= MOZ_CURSOR_ZOOM_OUT
;
5027 case eCursor_not_allowed
:
5028 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "not-allowed");
5029 if (!gdkcursor
) // nonstandard, yet common
5030 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "crossed_circle");
5032 newType
= MOZ_CURSOR_NOT_ALLOWED
;
5034 case eCursor_no_drop
:
5035 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "no-drop");
5036 if (!gdkcursor
) // this nonstandard sequence makes it work on KDE and GNOME
5037 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "forbidden");
5039 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "circle");
5041 newType
= MOZ_CURSOR_NOT_ALLOWED
;
5043 case eCursor_vertical_text
:
5044 newType
= MOZ_CURSOR_VERTICAL_TEXT
;
5046 case eCursor_all_scroll
:
5047 gdkcursor
= gdk_cursor_new(GDK_FLEUR
);
5049 case eCursor_nesw_resize
:
5050 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "size_bdiag");
5052 newType
= MOZ_CURSOR_NESW_RESIZE
;
5054 case eCursor_nwse_resize
:
5055 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "size_fdiag");
5057 newType
= MOZ_CURSOR_NWSE_RESIZE
;
5059 case eCursor_ns_resize
:
5060 gdkcursor
= gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW
);
5062 case eCursor_ew_resize
:
5063 gdkcursor
= gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW
);
5065 // Here, two better fitting cursors exist in some cursor themes. Try those first
5066 case eCursor_row_resize
:
5067 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "split_v");
5069 gdkcursor
= gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW
);
5071 case eCursor_col_resize
:
5072 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, "split_h");
5074 gdkcursor
= gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW
);
5077 newType
= MOZ_CURSOR_NONE
;
5080 NS_ASSERTION(aCursor
, "Invalid cursor type");
5081 gdkcursor
= gdk_cursor_new(GDK_LEFT_PTR
);
5085 // If by now we don't have a xcursor, this means we have to make a custom
5086 // one. First, we try creating a named cursor based on the hash of our
5087 // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
5088 // to themed cursors
5089 if (newType
!= 0xFF && GtkCursors
[newType
].hash
) {
5090 gdkcursor
= gdk_cursor_new_from_name(defaultDisplay
, GtkCursors
[newType
].hash
);
5093 // If we still don't have a xcursor, we now really create a bitmap cursor
5094 if (newType
!= 0xff && !gdkcursor
) {
5095 GdkPixbuf
* cursor_pixbuf
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, 32, 32);
5099 guchar
*data
= gdk_pixbuf_get_pixels(cursor_pixbuf
);
5101 // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and mask
5102 // GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for each pixel)
5103 // so it's 128 byte array (4 bytes for are one bitmap row and there are 32 rows here).
5104 const unsigned char *bits
= GtkCursors
[newType
].bits
;
5105 const unsigned char *mask_bits
= GtkCursors
[newType
].mask_bits
;
5107 for (int i
= 0; i
< 128; i
++) {
5109 char mask
= *mask_bits
++;
5110 for (int j
= 0; j
< 8; j
++) {
5111 unsigned char pix
= ~(((bit
>> j
) & 0x01) * 0xff);
5115 *data
++ = (((mask
>> j
) & 0x01) * 0xff);
5119 gdkcursor
= gdk_cursor_new_from_pixbuf(gdk_display_get_default(), cursor_pixbuf
,
5120 GtkCursors
[newType
].hot_x
,
5121 GtkCursors
[newType
].hot_y
);
5123 g_object_unref(cursor_pixbuf
);
5126 gCursorCache
[aCursor
] = gdkcursor
;
5133 #if (MOZ_WIDGET_GTK == 2)
5135 expose_event_cb(GtkWidget
*widget
, GdkEventExpose
*event
)
5137 nsRefPtr
<nsWindow
> window
= get_window_for_gdk_window(event
->window
);
5141 window
->OnExposeEvent(event
);
5146 draw_window_of_widget(GtkWidget
*widget
, GdkWindow
*aWindow
, cairo_t
*cr
)
5148 if (gtk_cairo_should_draw_window(cr
, aWindow
)) {
5149 nsRefPtr
<nsWindow
> window
= get_window_for_gdk_window(aWindow
);
5151 NS_WARNING("Cannot get nsWindow from GtkWidget");
5155 gtk_cairo_transform_to_window(cr
, widget
, aWindow
);
5156 // TODO - window->OnExposeEvent() can destroy this or other windows,
5157 // do we need to handle it somehow?
5158 window
->OnExposeEvent(cr
);
5163 GList
*children
= gdk_window_get_children(aWindow
);
5164 GList
*child
= children
;
5166 GdkWindow
*window
= GDK_WINDOW(child
->data
);
5167 gpointer windowWidget
;
5168 gdk_window_get_user_data(window
, &windowWidget
);
5169 if (windowWidget
== widget
) {
5170 draw_window_of_widget(widget
, window
, cr
);
5172 child
= g_list_next(child
);
5174 g_list_free(children
);
5179 expose_event_cb(GtkWidget
*widget
, cairo_t
*cr
)
5181 draw_window_of_widget(widget
, gtk_widget_get_window(widget
), cr
);
5184 #endif //MOZ_WIDGET_GTK2
5187 configure_event_cb(GtkWidget
*widget
,
5188 GdkEventConfigure
*event
)
5190 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(widget
);
5194 return window
->OnConfigureEvent(widget
, event
);
5198 container_unrealize_cb (GtkWidget
*widget
)
5200 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(widget
);
5204 window
->OnContainerUnrealize();
5208 size_allocate_cb (GtkWidget
*widget
, GtkAllocation
*allocation
)
5210 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(widget
);
5214 window
->OnSizeAllocate(allocation
);
5218 delete_event_cb(GtkWidget
*widget
, GdkEventAny
*event
)
5220 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(widget
);
5224 window
->OnDeleteEvent();
5230 enter_notify_event_cb(GtkWidget
*widget
,
5231 GdkEventCrossing
*event
)
5233 nsRefPtr
<nsWindow
> window
= get_window_for_gdk_window(event
->window
);
5237 window
->OnEnterNotifyEvent(event
);
5243 leave_notify_event_cb(GtkWidget
*widget
,
5244 GdkEventCrossing
*event
)
5246 if (is_parent_grab_leave(event
)) {
5250 // bug 369599: Suppress LeaveNotify events caused by pointer grabs to
5251 // avoid generating spurious mouse exit events.
5252 gint x
= gint(event
->x_root
);
5253 gint y
= gint(event
->y_root
);
5254 GdkDisplay
* display
= gtk_widget_get_display(widget
);
5255 GdkWindow
* winAtPt
= gdk_display_get_window_at_pointer(display
, &x
, &y
);
5256 if (winAtPt
== event
->window
) {
5260 nsRefPtr
<nsWindow
> window
= get_window_for_gdk_window(event
->window
);
5264 window
->OnLeaveNotifyEvent(event
);
5270 GetFirstNSWindowForGDKWindow(GdkWindow
*aGdkWindow
)
5273 while (!(window
= get_window_for_gdk_window(aGdkWindow
))) {
5274 // The event has bubbled to the moz_container widget as passed into each caller's *widget parameter,
5275 // but its corresponding nsWindow is an ancestor of the window that we need. Instead, look at
5276 // event->window and find the first ancestor nsWindow of it because event->window may be in a plugin.
5277 aGdkWindow
= gdk_window_get_parent(aGdkWindow
);
5287 motion_notify_event_cb(GtkWidget
*widget
, GdkEventMotion
*event
)
5289 UpdateLastInputEventTime(event
);
5291 nsWindow
*window
= GetFirstNSWindowForGDKWindow(event
->window
);
5295 window
->OnMotionNotifyEvent(event
);
5301 button_press_event_cb(GtkWidget
*widget
, GdkEventButton
*event
)
5303 UpdateLastInputEventTime(event
);
5305 nsWindow
*window
= GetFirstNSWindowForGDKWindow(event
->window
);
5309 window
->OnButtonPressEvent(event
);
5315 button_release_event_cb(GtkWidget
*widget
, GdkEventButton
*event
)
5317 UpdateLastInputEventTime(event
);
5319 nsWindow
*window
= GetFirstNSWindowForGDKWindow(event
->window
);
5323 window
->OnButtonReleaseEvent(event
);
5329 focus_in_event_cb(GtkWidget
*widget
, GdkEventFocus
*event
)
5331 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(widget
);
5335 window
->OnContainerFocusInEvent(event
);
5341 focus_out_event_cb(GtkWidget
*widget
, GdkEventFocus
*event
)
5343 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(widget
);
5347 window
->OnContainerFocusOutEvent(event
);
5353 // For long-lived popup windows that don't really take focus themselves but
5354 // may have elements that accept keyboard input when the parent window is
5355 // active, focus is handled specially. These windows include noautohide
5356 // panels. (This special handling is not necessary for temporary popups where
5357 // the keyboard is grabbed.)
5359 // Mousing over or clicking on these windows should not cause them to steal
5360 // focus from their parent windows, so, the input field of WM_HINTS is set to
5361 // False to request that the window manager not set the input focus to this
5362 // window. http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7
5364 // However, these windows can still receive WM_TAKE_FOCUS messages from the
5365 // window manager, so they can still detect when the user has indicated that
5366 // they wish to direct keyboard input at these windows. When the window
5367 // manager offers focus to these windows (after a mouse over or click, for
5368 // example), a request to make the parent window active is issued. When the
5369 // parent window becomes active, keyboard events will be received.
5371 static GdkFilterReturn
5372 popup_take_focus_filter(GdkXEvent
*gdk_xevent
,
5376 XEvent
* xevent
= static_cast<XEvent
*>(gdk_xevent
);
5377 if (xevent
->type
!= ClientMessage
)
5378 return GDK_FILTER_CONTINUE
;
5380 XClientMessageEvent
& xclient
= xevent
->xclient
;
5381 if (xclient
.message_type
!= gdk_x11_get_xatom_by_name("WM_PROTOCOLS"))
5382 return GDK_FILTER_CONTINUE
;
5384 Atom atom
= xclient
.data
.l
[0];
5385 if (atom
!= gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS"))
5386 return GDK_FILTER_CONTINUE
;
5388 guint32 timestamp
= xclient
.data
.l
[1];
5390 GtkWidget
* widget
= get_gtk_widget_for_gdk_window(event
->any
.window
);
5392 return GDK_FILTER_CONTINUE
;
5394 GtkWindow
* parent
= gtk_window_get_transient_for(GTK_WINDOW(widget
));
5396 return GDK_FILTER_CONTINUE
;
5398 if (gtk_window_is_active(parent
))
5399 return GDK_FILTER_REMOVE
; // leave input focus on the parent
5401 GdkWindow
* parent_window
= gtk_widget_get_window(GTK_WIDGET(parent
));
5403 return GDK_FILTER_CONTINUE
;
5405 // In case the parent has not been deconified.
5406 gdk_window_show_unraised(parent_window
);
5408 // Request focus on the parent window.
5409 // Use gdk_window_focus rather than gtk_window_present to avoid
5410 // raising the parent window.
5411 gdk_window_focus(parent_window
, timestamp
);
5412 return GDK_FILTER_REMOVE
;
5415 static GdkFilterReturn
5416 plugin_window_filter_func(GdkXEvent
*gdk_xevent
, GdkEvent
*event
, gpointer data
)
5418 GdkWindow
*plugin_window
;
5420 Window xeventWindow
;
5422 nsRefPtr
<nsWindow
> nswindow
= (nsWindow
*)data
;
5423 GdkFilterReturn return_val
;
5425 xevent
= (XEvent
*)gdk_xevent
;
5426 return_val
= GDK_FILTER_CONTINUE
;
5428 switch (xevent
->type
)
5431 case ReparentNotify
:
5432 if (xevent
->type
==CreateNotify
) {
5433 xeventWindow
= xevent
->xcreatewindow
.window
;
5436 if (xevent
->xreparent
.event
!= xevent
->xreparent
.parent
)
5438 xeventWindow
= xevent
->xreparent
.window
;
5440 #if (MOZ_WIDGET_GTK == 2)
5441 plugin_window
= gdk_window_lookup(xeventWindow
);
5443 plugin_window
= gdk_x11_window_lookup_for_display(
5444 gdk_x11_lookup_xdisplay(xevent
->xcreatewindow
.display
), xeventWindow
);
5446 if (plugin_window
) {
5448 get_gtk_widget_for_gdk_window(plugin_window
);
5451 #if (MOZ_WIDGET_GTK == 2)
5452 if (GTK_IS_XTBIN(widget
)) {
5453 nswindow
->SetPluginType(nsWindow::PluginType_NONXEMBED
);
5458 if(GTK_IS_SOCKET(widget
)) {
5459 if (!g_object_get_data(G_OBJECT(widget
), "enable-xt-focus")) {
5460 nswindow
->SetPluginType(nsWindow::PluginType_XEMBED
);
5465 nswindow
->SetPluginType(nsWindow::PluginType_NONXEMBED
);
5466 return_val
= GDK_FILTER_REMOVE
;
5469 nswindow
->SetNonXEmbedPluginFocus();
5472 gdk_window_remove_filter
5473 ((GdkWindow
*)(nswindow
->GetNativeData(NS_NATIVE_WINDOW
)),
5474 plugin_window_filter_func
,
5476 // Currently we consider all plugins are non-xembed and calls
5477 // LoseNonXEmbedPluginFocus without any checking.
5478 nswindow
->LoseNonXEmbedPluginFocus();
5486 static GdkFilterReturn
5487 plugin_client_message_filter(GdkXEvent
*gdk_xevent
,
5492 xevent
= (XEvent
*)gdk_xevent
;
5494 GdkFilterReturn return_val
;
5495 return_val
= GDK_FILTER_CONTINUE
;
5497 if (!gPluginFocusWindow
|| xevent
->type
!=ClientMessage
) {
5501 // When WM sends out WM_TAKE_FOCUS, gtk2 will use XSetInputFocus
5502 // to set the focus to the focus proxy. To prevent this happen
5503 // while the focus is on the plugin, we filter the WM_TAKE_FOCUS
5505 if (gdk_x11_get_xatom_by_name("WM_PROTOCOLS")
5506 != xevent
->xclient
.message_type
) {
5510 if ((Atom
) xevent
->xclient
.data
.l
[0] ==
5511 gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS")) {
5512 // block it from gtk2.0 focus proxy
5513 return_val
= GDK_FILTER_REMOVE
;
5518 #endif /* MOZ_X11 */
5521 key_press_event_cb(GtkWidget
*widget
, GdkEventKey
*event
)
5523 LOG(("key_press_event_cb\n"));
5525 UpdateLastInputEventTime(event
);
5527 // find the window with focus and dispatch this event to that widget
5528 nsWindow
*window
= get_window_for_gtk_widget(widget
);
5532 nsRefPtr
<nsWindow
> focusWindow
= gFocusWindow
? gFocusWindow
: window
;
5535 // Keyboard repeat can cause key press events to queue up when there are
5536 // slow event handlers (bug 301029). Throttle these events by removing
5537 // consecutive pending duplicate KeyPress events to the same window.
5538 // We use the event time of the last one.
5539 // Note: GDK calls XkbSetDetectableAutorepeat so that KeyRelease events
5540 // are generated only when the key is physically released.
5541 #define NS_GDKEVENT_MATCH_MASK 0x1FFF /* GDK_SHIFT_MASK .. GDK_BUTTON5_MASK */
5542 GdkDisplay
* gdkDisplay
= gtk_widget_get_display(widget
);
5543 Display
* dpy
= GDK_DISPLAY_XDISPLAY(gdkDisplay
);
5544 while (XPending(dpy
)) {
5546 XPeekEvent(dpy
, &next_event
);
5547 GdkWindow
* nextGdkWindow
=
5548 gdk_x11_window_lookup_for_display(gdkDisplay
, next_event
.xany
.window
);
5549 if (nextGdkWindow
!= event
->window
||
5550 next_event
.type
!= KeyPress
||
5551 next_event
.xkey
.keycode
!= event
->hardware_keycode
||
5552 next_event
.xkey
.state
!= (event
->state
& NS_GDKEVENT_MATCH_MASK
)) {
5555 XNextEvent(dpy
, &next_event
);
5556 event
->time
= next_event
.xkey
.time
;
5560 return focusWindow
->OnKeyPressEvent(event
);
5564 key_release_event_cb(GtkWidget
*widget
, GdkEventKey
*event
)
5566 LOG(("key_release_event_cb\n"));
5568 UpdateLastInputEventTime(event
);
5570 // find the window with focus and dispatch this event to that widget
5571 nsWindow
*window
= get_window_for_gtk_widget(widget
);
5575 nsRefPtr
<nsWindow
> focusWindow
= gFocusWindow
? gFocusWindow
: window
;
5577 return focusWindow
->OnKeyReleaseEvent(event
);
5581 scroll_event_cb(GtkWidget
*widget
, GdkEventScroll
*event
)
5583 nsWindow
*window
= GetFirstNSWindowForGDKWindow(event
->window
);
5587 window
->OnScrollEvent(event
);
5593 visibility_notify_event_cb (GtkWidget
*widget
, GdkEventVisibility
*event
)
5595 nsRefPtr
<nsWindow
> window
= get_window_for_gdk_window(event
->window
);
5599 window
->OnVisibilityNotifyEvent(event
);
5605 hierarchy_changed_cb (GtkWidget
*widget
,
5606 GtkWidget
*previous_toplevel
)
5608 GtkWidget
*toplevel
= gtk_widget_get_toplevel(widget
);
5609 GdkWindowState old_window_state
= GDK_WINDOW_STATE_WITHDRAWN
;
5610 GdkEventWindowState event
;
5612 event
.new_window_state
= GDK_WINDOW_STATE_WITHDRAWN
;
5614 if (GTK_IS_WINDOW(previous_toplevel
)) {
5615 g_signal_handlers_disconnect_by_func(previous_toplevel
,
5616 FuncToGpointer(window_state_event_cb
),
5618 GdkWindow
*win
= gtk_widget_get_window(previous_toplevel
);
5620 old_window_state
= gdk_window_get_state(win
);
5624 if (GTK_IS_WINDOW(toplevel
)) {
5625 g_signal_connect_swapped(toplevel
, "window-state-event",
5626 G_CALLBACK(window_state_event_cb
), widget
);
5627 GdkWindow
*win
= gtk_widget_get_window(toplevel
);
5629 event
.new_window_state
= gdk_window_get_state(win
);
5633 event
.changed_mask
= static_cast<GdkWindowState
>
5634 (old_window_state
^ event
.new_window_state
);
5636 if (event
.changed_mask
) {
5637 event
.type
= GDK_WINDOW_STATE
;
5638 event
.window
= nullptr;
5639 event
.send_event
= TRUE
;
5640 window_state_event_cb(widget
, &event
);
5645 window_state_event_cb (GtkWidget
*widget
, GdkEventWindowState
*event
)
5647 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(widget
);
5651 window
->OnWindowStateEvent(widget
, event
);
5657 theme_changed_cb (GtkSettings
*settings
, GParamSpec
*pspec
, nsWindow
*data
)
5659 nsRefPtr
<nsWindow
> window
= data
;
5660 window
->ThemeChanged();
5663 //////////////////////////////////////////////////////////////////////
5664 // These are all of our drag and drop operations
5667 nsWindow::InitDragEvent(WidgetDragEvent
&aEvent
)
5669 // set the keyboard modifiers
5670 guint modifierState
= KeymapWrapper::GetCurrentModifierState();
5671 KeymapWrapper::InitInputEvent(aEvent
, modifierState
);
5675 drag_motion_event_cb(GtkWidget
*aWidget
,
5676 GdkDragContext
*aDragContext
,
5682 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(aWidget
);
5686 // figure out which internal widget this drag motion actually happened on
5690 GdkWindow
*innerWindow
=
5691 get_inner_gdk_window(gtk_widget_get_window(aWidget
), aX
, aY
,
5693 nsRefPtr
<nsWindow
> innerMostWindow
= get_window_for_gdk_window(innerWindow
);
5695 if (!innerMostWindow
) {
5696 innerMostWindow
= window
;
5699 LOGDRAG(("nsWindow drag-motion signal for %p\n", (void*)innerMostWindow
));
5701 return nsDragService::GetInstance()->
5702 ScheduleMotionEvent(innerMostWindow
, aDragContext
,
5703 nsIntPoint(retx
, rety
), aTime
);
5707 drag_leave_event_cb(GtkWidget
*aWidget
,
5708 GdkDragContext
*aDragContext
,
5712 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(aWidget
);
5716 nsDragService
*dragService
= nsDragService::GetInstance();
5718 nsWindow
*mostRecentDragWindow
= dragService
->GetMostRecentDestWindow();
5719 if (!mostRecentDragWindow
) {
5720 // This can happen when the target will not accept a drop. A GTK drag
5721 // source sends the leave message to the destination before the
5722 // drag-failed signal on the source widget, but the leave message goes
5723 // via the X server, and so doesn't get processed at least until the
5724 // event loop runs again.
5728 GtkWidget
*mozContainer
= mostRecentDragWindow
->GetMozContainerWidget();
5729 if (aWidget
!= mozContainer
)
5731 // When the drag moves between widgets, GTK can send leave signal for
5732 // the old widget after the motion or drop signal for the new widget.
5733 // We'll send the leave event when the motion or drop event is run.
5737 LOGDRAG(("nsWindow drag-leave signal for %p\n",
5738 (void*)mostRecentDragWindow
));
5740 dragService
->ScheduleLeaveEvent();
5745 drag_drop_event_cb(GtkWidget
*aWidget
,
5746 GdkDragContext
*aDragContext
,
5752 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(aWidget
);
5756 // figure out which internal widget this drag motion actually happened on
5760 GdkWindow
*innerWindow
=
5761 get_inner_gdk_window(gtk_widget_get_window(aWidget
), aX
, aY
,
5763 nsRefPtr
<nsWindow
> innerMostWindow
= get_window_for_gdk_window(innerWindow
);
5765 if (!innerMostWindow
) {
5766 innerMostWindow
= window
;
5769 LOGDRAG(("nsWindow drag-drop signal for %p\n", (void*)innerMostWindow
));
5771 return nsDragService::GetInstance()->
5772 ScheduleDropEvent(innerMostWindow
, aDragContext
,
5773 nsIntPoint(retx
, rety
), aTime
);
5777 drag_data_received_event_cb(GtkWidget
*aWidget
,
5778 GdkDragContext
*aDragContext
,
5781 GtkSelectionData
*aSelectionData
,
5786 nsRefPtr
<nsWindow
> window
= get_window_for_gtk_widget(aWidget
);
5790 window
->OnDragDataReceivedEvent(aWidget
,
5794 aInfo
, aTime
, aData
);
5798 initialize_prefs(void)
5801 Preferences::GetBool("mozilla.widget.raise-on-setfocus", true);
5807 get_inner_gdk_window (GdkWindow
*aWindow
,
5809 gint
*retx
, gint
*rety
)
5811 gint cx
, cy
, cw
, ch
;
5812 GList
*children
= gdk_window_peek_children(aWindow
);
5813 for (GList
*child
= g_list_last(children
);
5815 child
= g_list_previous(child
)) {
5816 GdkWindow
*childWindow
= (GdkWindow
*) child
->data
;
5817 if (get_window_for_gdk_window(childWindow
)) {
5818 #if (MOZ_WIDGET_GTK == 2)
5819 gdk_window_get_geometry(childWindow
, &cx
, &cy
, &cw
, &ch
, nullptr);
5821 gdk_window_get_geometry(childWindow
, &cx
, &cy
, &cw
, &ch
);
5823 if ((cx
< x
) && (x
< (cx
+ cw
)) &&
5824 (cy
< y
) && (y
< (cy
+ ch
)) &&
5825 gdk_window_is_visible(childWindow
)) {
5826 return get_inner_gdk_window(childWindow
,
5838 is_context_menu_key(const WidgetKeyboardEvent
& aKeyEvent
)
5840 return ((aKeyEvent
.keyCode
== NS_VK_F10
&& aKeyEvent
.IsShift() &&
5841 !aKeyEvent
.IsControl() && !aKeyEvent
.IsMeta() &&
5842 !aKeyEvent
.IsAlt()) ||
5843 (aKeyEvent
.keyCode
== NS_VK_CONTEXT_MENU
&& !aKeyEvent
.IsShift() &&
5844 !aKeyEvent
.IsControl() && !aKeyEvent
.IsMeta() &&
5845 !aKeyEvent
.IsAlt()));
5849 is_parent_ungrab_enter(GdkEventCrossing
*aEvent
)
5851 return (GDK_CROSSING_UNGRAB
== aEvent
->mode
) &&
5852 ((GDK_NOTIFY_ANCESTOR
== aEvent
->detail
) ||
5853 (GDK_NOTIFY_VIRTUAL
== aEvent
->detail
));
5858 is_parent_grab_leave(GdkEventCrossing
*aEvent
)
5860 return (GDK_CROSSING_GRAB
== aEvent
->mode
) &&
5861 ((GDK_NOTIFY_ANCESTOR
== aEvent
->detail
) ||
5862 (GDK_NOTIFY_VIRTUAL
== aEvent
->detail
));
5865 #ifdef ACCESSIBILITY
5867 nsWindow::CreateRootAccessible()
5869 if (mIsTopLevel
&& !mRootAccessible
) {
5870 LOG(("nsWindow:: Create Toplevel Accessibility\n"));
5871 mRootAccessible
= GetRootAccessible();
5876 nsWindow::DispatchEventToRootAccessible(uint32_t aEventType
)
5878 if (!a11y::ShouldA11yBeEnabled()) {
5882 nsCOMPtr
<nsIAccessibilityService
> accService
=
5883 services::GetAccessibilityService();
5888 // Get the root document accessible and fire event to it.
5889 a11y::Accessible
* acc
= GetRootAccessible();
5891 accService
->FireAccessibleEvent(aEventType
, acc
);
5896 nsWindow::DispatchActivateEventAccessible(void)
5898 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE
);
5902 nsWindow::DispatchDeactivateEventAccessible(void)
5904 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE
);
5908 nsWindow::DispatchMaximizeEventAccessible(void)
5910 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE
);
5914 nsWindow::DispatchMinimizeEventAccessible(void)
5916 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE
);
5920 nsWindow::DispatchRestoreEventAccessible(void)
5922 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_RESTORE
);
5925 #endif /* #ifdef ACCESSIBILITY */
5927 // nsChildWindow class
5929 nsChildWindow::nsChildWindow()
5933 nsChildWindow::~nsChildWindow()
5938 nsWindow::NotifyIME(const IMENotification
& aIMENotification
)
5940 if (MOZ_UNLIKELY(!mIMModule
)) {
5941 switch (aIMENotification
.mMessage
) {
5942 case NOTIFY_IME_OF_CURSOR_POS_CHANGED
:
5943 case REQUEST_TO_COMMIT_COMPOSITION
:
5944 case REQUEST_TO_CANCEL_COMPOSITION
:
5945 case NOTIFY_IME_OF_FOCUS
:
5946 case NOTIFY_IME_OF_BLUR
:
5947 return NS_ERROR_NOT_AVAILABLE
;
5952 switch (aIMENotification
.mMessage
) {
5953 // TODO: We should replace NOTIFY_IME_OF_CURSOR_POS_CHANGED with
5954 // NOTIFY_IME_OF_SELECTION_CHANGE. The required behavior is
5955 // really different from committing composition.
5956 case NOTIFY_IME_OF_CURSOR_POS_CHANGED
:
5957 case REQUEST_TO_COMMIT_COMPOSITION
:
5958 return mIMModule
->CommitIMEComposition(this);
5959 case REQUEST_TO_CANCEL_COMPOSITION
:
5960 return mIMModule
->CancelIMEComposition(this);
5961 case NOTIFY_IME_OF_FOCUS
:
5962 mIMModule
->OnFocusChangeInGecko(true);
5964 case NOTIFY_IME_OF_BLUR
:
5965 mIMModule
->OnFocusChangeInGecko(false);
5967 case NOTIFY_IME_OF_COMPOSITION_UPDATE
:
5968 mIMModule
->OnUpdateComposition();
5971 return NS_ERROR_NOT_IMPLEMENTED
;
5975 NS_IMETHODIMP_(void)
5976 nsWindow::SetInputContext(const InputContext
& aContext
,
5977 const InputContextAction
& aAction
)
5982 mIMModule
->SetInputContext(this, &aContext
, &aAction
);
5985 NS_IMETHODIMP_(InputContext
)
5986 nsWindow::GetInputContext()
5988 InputContext context
;
5990 context
.mIMEState
.mEnabled
= IMEState::DISABLED
;
5991 context
.mIMEState
.mOpen
= IMEState::OPEN_STATE_NOT_SUPPORTED
;
5992 // If IME context isn't available on this widget, we should set |this|
5993 // instead of nullptr since nullptr means that the platform has only one
5994 // context per process.
5995 context
.mNativeIMEContext
= this;
5997 context
= mIMModule
->GetInputContext();
5998 context
.mNativeIMEContext
= mIMModule
;
6003 NS_IMETHODIMP_(bool)
6004 nsWindow::ExecuteNativeKeyBinding(NativeKeyBindingsType aType
,
6005 const WidgetKeyboardEvent
& aEvent
,
6006 DoCommandCallback aCallback
,
6007 void* aCallbackData
)
6009 NativeKeyBindings
* keyBindings
= NativeKeyBindings::GetInstance(aType
);
6010 return keyBindings
->Execute(aEvent
, aCallback
, aCallbackData
);
6014 nsWindow::GetToggledKeyState(uint32_t aKeyCode
, bool* aLEDState
)
6016 NS_ENSURE_ARG_POINTER(aLEDState
);
6018 KeymapWrapper::Modifiers modifier
;
6020 case NS_VK_CAPS_LOCK
: modifier
= KeymapWrapper::CAPS_LOCK
; break;
6021 case NS_VK_NUM_LOCK
: modifier
= KeymapWrapper::NUM_LOCK
; break;
6022 case NS_VK_SCROLL_LOCK
: modifier
= KeymapWrapper::SCROLL_LOCK
; break;
6023 default: return NS_ERROR_INVALID_ARG
;
6027 KeymapWrapper::AreModifiersCurrentlyActive(modifier
);
6031 #if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
6032 /* static */ already_AddRefed
<gfxASurface
>
6033 nsWindow::GetSurfaceForGdkDrawable(GdkDrawable
* aDrawable
,
6034 const nsIntSize
& aSize
)
6036 GdkVisual
* visual
= gdk_drawable_get_visual(aDrawable
);
6038 gdk_x11_screen_get_xscreen(gdk_drawable_get_screen(aDrawable
));
6039 Display
* xDisplay
= DisplayOfScreen(xScreen
);
6040 Drawable xDrawable
= gdk_x11_drawable_get_xid(aDrawable
);
6042 nsRefPtr
<gfxASurface
> result
;
6045 Visual
* xVisual
= gdk_x11_visual_get_xvisual(visual
);
6047 result
= new gfxXlibSurface(xDisplay
, xDrawable
, xVisual
,
6048 gfxIntSize(aSize
.width
, aSize
.height
));
6050 // no visual? we must be using an xrender format. Find a format
6052 XRenderPictFormat
*pf
= nullptr;
6053 switch (gdk_drawable_get_depth(aDrawable
)) {
6055 pf
= XRenderFindStandardFormat(xDisplay
, PictStandardARGB32
);
6058 pf
= XRenderFindStandardFormat(xDisplay
, PictStandardRGB24
);
6061 NS_ERROR("Don't know how to handle the given depth!");
6065 result
= new gfxXlibSurface(xScreen
, xDrawable
, pf
,
6066 gfxIntSize(aSize
.width
, aSize
.height
));
6069 return result
.forget();
6073 TemporaryRef
<DrawTarget
>
6074 nsWindow::StartRemoteDrawing()
6076 gfxASurface
*surf
= GetThebesSurface();
6081 IntSize
size(surf
->GetSize().width
, surf
->GetSize().height
);
6082 if (size
.width
<= 0 || size
.height
<= 0) {
6086 return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf
, size
);
6089 // return the gfxASurface for rendering to this widget
6091 nsWindow::GetThebesSurface()
6092 #if (MOZ_WIDGET_GTK == 3)
6094 return GetThebesSurface(nullptr);
6097 nsWindow::GetThebesSurface(cairo_t
*cr
)
6106 #if (MOZ_WIDGET_GTK == 2)
6107 gdk_drawable_get_size(GDK_DRAWABLE(mGdkWindow
), &width
, &height
);
6109 width
= gdk_window_get_width(mGdkWindow
);
6110 height
= gdk_window_get_height(mGdkWindow
);
6113 // Owen Taylor says this is the right thing to do!
6114 width
= std::min(32767, width
);
6115 height
= std::min(32767, height
);
6116 gfxIntSize
size(width
, height
);
6118 GdkVisual
*gdkVisual
= gdk_window_get_visual(mGdkWindow
);
6119 Visual
* visual
= gdk_x11_visual_get_xvisual(gdkVisual
);
6121 # ifdef MOZ_HAVE_SHMIMAGE
6122 bool usingShm
= false;
6123 if (nsShmImage::UseShm()) {
6124 // EnsureShmImage() is a dangerous interface, but we guarantee
6125 // that the thebes surface and the shmimage have the same
6128 nsShmImage::EnsureShmImage(size
,
6129 visual
, gdk_visual_get_depth(gdkVisual
),
6131 usingShm
= mThebesSurface
!= nullptr;
6134 # endif // MOZ_HAVE_SHMIMAGE
6136 #if (MOZ_WIDGET_GTK == 3)
6138 #error "cairo-gtk3 target must be built with --enable-system-cairo"
6141 cairo_surface_t
*surf
= cairo_get_target(cr
);
6142 if (cairo_surface_status(surf
) != CAIRO_STATUS_SUCCESS
) {
6143 NS_NOTREACHED("Missing cairo target?");
6146 mThebesSurface
= gfxASurface::Wrap(surf
);
6149 #endif // (MOZ_WIDGET_GTK == 3)
6150 mThebesSurface
= new gfxXlibSurface
6151 (GDK_WINDOW_XDISPLAY(mGdkWindow
),
6152 gdk_x11_window_get_xid(mGdkWindow
),
6158 // if the surface creation is reporting an error, then
6159 // we don't have a surface to give back
6160 if (mThebesSurface
&& mThebesSurface
->CairoStatus() != 0) {
6161 mThebesSurface
= nullptr;
6164 return mThebesSurface
;
6167 // Code shared begin BeginMoveDrag and BeginResizeDrag
6169 nsWindow::GetDragInfo(WidgetMouseEvent
* aMouseEvent
,
6170 GdkWindow
** aWindow
, gint
* aButton
,
6171 gint
* aRootX
, gint
* aRootY
)
6173 if (aMouseEvent
->button
!= WidgetMouseEvent::eLeftButton
) {
6174 // we can only begin a move drag with the left mouse button
6179 // get the gdk window for this widget
6180 GdkWindow
* gdk_window
= mGdkWindow
;
6184 NS_ABORT_IF_FALSE(GDK_IS_WINDOW(gdk_window
), "must really be window");
6186 // find the top-level window
6187 gdk_window
= gdk_window_get_toplevel(gdk_window
);
6188 NS_ABORT_IF_FALSE(gdk_window
,
6189 "gdk_window_get_toplevel should not return null");
6190 *aWindow
= gdk_window
;
6192 if (!aMouseEvent
->widget
) {
6196 // FIXME: It would be nice to have the widget position at the time
6197 // of the event, but it's relatively unlikely that the widget has
6198 // moved since the mousedown. (On the other hand, it's quite likely
6199 // that the mouse has moved, which is why we use the mouse position
6201 nsIntPoint offset
= aMouseEvent
->widget
->WidgetToScreenOffset();
6202 *aRootX
= aMouseEvent
->refPoint
.x
+ offset
.x
;
6203 *aRootY
= aMouseEvent
->refPoint
.y
+ offset
.y
;
6209 nsWindow::BeginMoveDrag(WidgetMouseEvent
* aEvent
)
6211 NS_ABORT_IF_FALSE(aEvent
, "must have event");
6212 NS_ABORT_IF_FALSE(aEvent
->mClass
== eMouseEventClass
,
6213 "event must have correct struct type");
6215 GdkWindow
*gdk_window
;
6216 gint button
, screenX
, screenY
;
6217 if (!GetDragInfo(aEvent
, &gdk_window
, &button
, &screenX
, &screenY
)) {
6218 return NS_ERROR_FAILURE
;
6221 // tell the window manager to start the move
6222 gdk_window_begin_move_drag(gdk_window
, button
, screenX
, screenY
,
6229 nsWindow::BeginResizeDrag(WidgetGUIEvent
* aEvent
,
6230 int32_t aHorizontal
,
6233 NS_ENSURE_ARG_POINTER(aEvent
);
6235 if (aEvent
->mClass
!= eMouseEventClass
) {
6236 // you can only begin a resize drag with a mouse event
6237 return NS_ERROR_INVALID_ARG
;
6240 GdkWindow
*gdk_window
;
6241 gint button
, screenX
, screenY
;
6242 if (!GetDragInfo(aEvent
->AsMouseEvent(), &gdk_window
, &button
,
6243 &screenX
, &screenY
)) {
6244 return NS_ERROR_FAILURE
;
6247 // work out what GdkWindowEdge we're talking about
6248 GdkWindowEdge window_edge
;
6249 if (aVertical
< 0) {
6250 if (aHorizontal
< 0) {
6251 window_edge
= GDK_WINDOW_EDGE_NORTH_WEST
;
6252 } else if (aHorizontal
== 0) {
6253 window_edge
= GDK_WINDOW_EDGE_NORTH
;
6255 window_edge
= GDK_WINDOW_EDGE_NORTH_EAST
;
6257 } else if (aVertical
== 0) {
6258 if (aHorizontal
< 0) {
6259 window_edge
= GDK_WINDOW_EDGE_WEST
;
6260 } else if (aHorizontal
== 0) {
6261 return NS_ERROR_INVALID_ARG
;
6263 window_edge
= GDK_WINDOW_EDGE_EAST
;
6266 if (aHorizontal
< 0) {
6267 window_edge
= GDK_WINDOW_EDGE_SOUTH_WEST
;
6268 } else if (aHorizontal
== 0) {
6269 window_edge
= GDK_WINDOW_EDGE_SOUTH
;
6271 window_edge
= GDK_WINDOW_EDGE_SOUTH_EAST
;
6275 // tell the window manager to start the resize
6276 gdk_window_begin_resize_drag(gdk_window
, window_edge
, button
,
6277 screenX
, screenY
, aEvent
->time
);
6282 nsIWidget::LayerManager
*
6283 nsWindow::GetLayerManager(PLayerTransactionChild
* aShadowManager
,
6284 LayersBackend aBackendHint
,
6285 LayerManagerPersistence aPersistence
,
6286 bool* aAllowRetaining
)
6288 if (!mLayerManager
&& eTransparencyTransparent
== GetTransparencyMode()) {
6289 mLayerManager
= CreateBasicLayerManager();
6292 return nsBaseWidget::GetLayerManager(aShadowManager
, aBackendHint
,
6293 aPersistence
, aAllowRetaining
);
6297 nsWindow::ClearCachedResources()
6299 if (mLayerManager
&&
6300 mLayerManager
->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC
) {
6301 mLayerManager
->ClearCachedResources();
6304 GList
* children
= gdk_window_peek_children(mGdkWindow
);
6305 for (GList
* list
= children
; list
; list
= list
->next
) {
6306 nsWindow
* window
= get_window_for_gdk_window(GDK_WINDOW(list
->data
));
6308 window
->ClearCachedResources();
6314 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint
,
6315 uint32_t aNativeMessage
,
6316 uint32_t aModifierFlags
)
6322 GdkDisplay
* display
= gdk_window_get_display(mGdkWindow
);
6324 // When a button-release event is requested, create it here and put it in the
6325 // event queue. This will not emit a motion event - this needs to be done
6326 // explicitly *before* requesting a button-release. You will also need to wait
6327 // for the motion event to be dispatched before requesting a button-release
6328 // event to maintain the desired event order.
6329 if (aNativeMessage
== GDK_BUTTON_RELEASE
) {
6331 memset(&event
, 0, sizeof(GdkEvent
));
6332 event
.type
= (GdkEventType
)aNativeMessage
;
6333 event
.button
.button
= 1;
6334 event
.button
.window
= mGdkWindow
;
6335 event
.button
.time
= GDK_CURRENT_TIME
;
6337 #if (MOZ_WIDGET_GTK == 3)
6338 // Get device for event source
6339 GdkDeviceManager
*device_manager
= gdk_display_get_device_manager(display
);
6340 event
.button
.device
= gdk_device_manager_get_client_pointer(device_manager
);
6343 gdk_event_put(&event
);
6345 // We don't support specific events other than button-release. In case
6346 // aNativeMessage != GDK_BUTTON_RELEASE we'll synthesize a motion event
6347 // that will be emitted by gdk_display_warp_pointer().
6348 GdkScreen
* screen
= gdk_window_get_screen(mGdkWindow
);
6349 gdk_display_warp_pointer(display
, screen
, aPoint
.x
, aPoint
.y
);