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