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