Back to index

lightning-sunbird  0.9+nobinonly
nsWindow.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is Christopher Blizzard
00020  * <blizzard@mozilla.org>.  Portions created by the Initial Developer
00021  * are Copyright (C) 2001 the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Mats Palmgren <mats.palmgren@bredband.net>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "prlink.h"
00041 
00042 #include "nsWindow.h"
00043 #include "nsToolkit.h"
00044 #include "nsIRenderingContext.h"
00045 #include "nsIRegion.h"
00046 #include "nsIRollupListener.h"
00047 #include "nsIMenuRollup.h"
00048 #include "nsIDOMNode.h"
00049 
00050 #include "nsWidgetsCID.h"
00051 #include "nsIDragService.h"
00052 #include "nsIDragSessionGTK.h"
00053 
00054 #include "nsGtkKeyUtils.h"
00055 #include "nsGtkCursors.h"
00056 
00057 #include <gtk/gtkwindow.h>
00058 #include <gdk/gdkx.h>
00059 #include <gdk/gdkkeysyms.h>
00060 
00061 #include "gtk2xtbin.h"
00062 
00063 #include "nsIPrefService.h"
00064 #include "nsIPrefBranch.h"
00065 #include "nsIServiceManager.h"
00066 #include "nsGfxCIID.h"
00067 
00068 #ifdef ACCESSIBILITY
00069 #include "nsPIAccessNode.h"
00070 #include "nsPIAccessible.h"
00071 #include "nsIAccessibleEvent.h"
00072 #include "prenv.h"
00073 #include "stdlib.h"
00074 static PRBool sAccessibilityChecked = PR_FALSE;
00075 static PRBool sAccessibilityEnabled = PR_FALSE;
00076 static const char sSysPrefService [] = "@mozilla.org/system-preference-service;1";
00077 static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
00078 static const char sAccessibilityKey [] = "config.use_system_prefs.accessibility";
00079 #endif
00080 
00081 /* For SetIcon */
00082 #include "nsAppDirectoryServiceDefs.h"
00083 #include "nsXPIDLString.h"
00084 #include "nsIFile.h"
00085 #include "nsILocalFile.h"
00086 
00087 /* SetCursor(imgIContainer*) */
00088 #include <gdk/gdk.h>
00089 #include "imgIContainer.h"
00090 #include "gfxIImageFrame.h"
00091 #include "nsIImage.h"
00092 #include "nsIGdkPixbufImage.h"
00093 #include "nsIInterfaceRequestorUtils.h"
00094 
00095 /* utility functions */
00096 static PRBool     check_for_rollup(GdkWindow *aWindow,
00097                                    gdouble aMouseX, gdouble aMouseY,
00098                                    PRBool aIsWheel);
00099 static PRBool     is_mouse_in_window(GdkWindow* aWindow,
00100                                      gdouble aMouseX, gdouble aMouseY);
00101 static nsWindow  *get_window_for_gtk_widget(GtkWidget *widget);
00102 static nsWindow  *get_window_for_gdk_window(GdkWindow *window);
00103 static nsWindow  *get_owning_window_for_gdk_window(GdkWindow *window);
00104 static GtkWidget *get_gtk_widget_for_gdk_window(GdkWindow *window);
00105 static GdkCursor *get_gtk_cursor(nsCursor aCursor);
00106 
00107 static GdkWindow *get_inner_gdk_window (GdkWindow *aWindow,
00108                                         gint x, gint y,
00109                                         gint *retx, gint *rety);
00110 
00111 static inline PRBool is_context_menu_key(const nsKeyEvent& inKeyEvent);
00112 static void   key_event_to_context_menu_event(const nsKeyEvent* inKeyEvent,
00113                                               nsMouseEvent* outCMEvent);
00114 
00115 static int    is_parent_ungrab_enter(GdkEventCrossing *aEvent);
00116 static int    is_parent_grab_leave(GdkEventCrossing *aEvent);
00117 
00118 /* callbacks from widgets */
00119 static gboolean expose_event_cb           (GtkWidget *widget,
00120                                            GdkEventExpose *event);
00121 static gboolean configure_event_cb        (GtkWidget *widget,
00122                                            GdkEventConfigure *event);
00123 static void     size_allocate_cb          (GtkWidget *widget,
00124                                            GtkAllocation *allocation);
00125 static gboolean delete_event_cb           (GtkWidget *widget,
00126                                            GdkEventAny *event);
00127 static gboolean enter_notify_event_cb     (GtkWidget *widget,
00128                                            GdkEventCrossing *event);
00129 static gboolean leave_notify_event_cb     (GtkWidget *widget,
00130                                            GdkEventCrossing *event);
00131 static gboolean motion_notify_event_cb    (GtkWidget *widget,
00132                                            GdkEventMotion *event);
00133 static gboolean button_press_event_cb     (GtkWidget *widget,
00134                                            GdkEventButton *event);
00135 static gboolean button_release_event_cb   (GtkWidget *widget,
00136                                            GdkEventButton *event);
00137 static gboolean focus_in_event_cb         (GtkWidget *widget,
00138                                            GdkEventFocus *event);
00139 static gboolean focus_out_event_cb        (GtkWidget *widget,
00140                                            GdkEventFocus *event);
00141 static gboolean key_press_event_cb        (GtkWidget *widget,
00142                                            GdkEventKey *event);
00143 static gboolean key_release_event_cb      (GtkWidget *widget,
00144                                            GdkEventKey *event);
00145 static gboolean scroll_event_cb           (GtkWidget *widget,
00146                                            GdkEventScroll *event);
00147 static gboolean visibility_notify_event_cb(GtkWidget *widget,
00148                                            GdkEventVisibility *event);
00149 static gboolean window_state_event_cb     (GtkWidget *widget,
00150                                            GdkEventWindowState *event);
00151 static void     theme_changed_cb          (GtkSettings *settings,
00152                                            GParamSpec *pspec,
00153                                            nsWindow *data);
00154 #ifdef __cplusplus
00155 extern "C" {
00156 #endif /* __cplusplus */
00157 static GdkFilterReturn plugin_window_filter_func (GdkXEvent *gdk_xevent,
00158                                                   GdkEvent *event,
00159                                                   gpointer data);
00160 static GdkFilterReturn plugin_client_message_filter (GdkXEvent *xevent,
00161                                                      GdkEvent *event,
00162                                                      gpointer data);
00163 #ifdef __cplusplus
00164 }
00165 #endif /* __cplusplus */
00166 
00167 static gboolean drag_motion_event_cb      (GtkWidget *aWidget,
00168                                            GdkDragContext *aDragContext,
00169                                            gint aX,
00170                                            gint aY,
00171                                            guint aTime,
00172                                            gpointer aData);
00173 static void     drag_leave_event_cb       (GtkWidget *aWidget,
00174                                            GdkDragContext *aDragContext,
00175                                            guint aTime,
00176                                            gpointer aData);
00177 static gboolean drag_drop_event_cb        (GtkWidget *aWidget,
00178                                            GdkDragContext *aDragContext,
00179                                            gint aX,
00180                                            gint aY,
00181                                            guint aTime,
00182                                            gpointer *aData);
00183 static void    drag_data_received_event_cb(GtkWidget *aWidget,
00184                                            GdkDragContext *aDragContext,
00185                                            gint aX,
00186                                            gint aY,
00187                                            GtkSelectionData  *aSelectionData,
00188                                            guint aInfo,
00189                                            guint32 aTime,
00190                                            gpointer aData);
00191 
00192 /* initialization static functions */
00193 static nsresult    initialize_prefs        (void);
00194 
00195 // this is the last window that had a drag event happen on it.
00196 nsWindow *nsWindow::mLastDragMotionWindow = NULL;
00197 PRBool nsWindow::sIsDraggingOutOf = PR_FALSE;
00198 
00199 // This is the time of the last button press event.  The drag service
00200 // uses it as the time to start drags.
00201 guint32   nsWindow::mLastButtonPressTime = 0;
00202 // Time of the last button release event. We use it to detect when the
00203 // drag ended before we could properly setup drag and drop.
00204 guint32   nsWindow::mLastButtonReleaseTime = 0;
00205 
00206 static NS_DEFINE_IID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
00207 
00208 // the current focus window
00209 static nsWindow         *gFocusWindow          = NULL;
00210 static PRBool            gGlobalsInitialized   = PR_FALSE;
00211 static PRBool            gRaiseWindows         = PR_TRUE;
00212 static nsWindow         *gPluginFocusWindow    = NULL;
00213 
00214 nsCOMPtr  <nsIRollupListener> gRollupListener;
00215 nsWeakPtr                     gRollupWindow;
00216 
00217 #define NS_WINDOW_TITLE_MAX_LENGTH 4095
00218 
00219 #ifdef USE_XIM
00220 
00221 static nsWindow    *gIMEFocusWindow = NULL;
00222 static GdkEventKey *gKeyEvent = NULL;
00223 static PRBool       gKeyEventCommitted = PR_FALSE;
00224 static PRBool       gKeyEventChanged = PR_FALSE;
00225 
00226 static void IM_commit_cb              (GtkIMContext *aContext,
00227                                        const gchar *aString,
00228                                        nsWindow *aWindow);
00229 static void IM_preedit_changed_cb     (GtkIMContext *aContext,
00230                                        nsWindow *aWindow);
00231 static void IM_set_text_range         (const PRInt32 aLen,
00232                                        const gchar *aPreeditString,
00233                                        const gint aCursorPos,
00234                                        const PangoAttrList *aFeedback,
00235                                        PRUint32 *aTextRangeListLengthResult,
00236                                        nsTextRangeArray *aTextRangeListResult);
00237 
00238 static GtkIMContext *IM_get_input_context(MozDrawingarea *aArea);
00239 
00240 // If after selecting profile window, the startup fail, please refer to
00241 // http://bugzilla.gnome.org/show_bug.cgi?id=88940
00242 #endif
00243 
00244 // needed for imgIContainer cursors
00245 // GdkDisplay* was added in 2.2
00246 typedef struct _GdkDisplay GdkDisplay;
00247 typedef GdkDisplay* (*_gdk_display_get_default_fn)(void);
00248 
00249 typedef GdkCursor*  (*_gdk_cursor_new_from_pixbuf_fn)(GdkDisplay *display,
00250                                                       GdkPixbuf *pixbuf,
00251                                                       gint x,
00252                                                       gint y);
00253 static _gdk_display_get_default_fn    _gdk_display_get_default;
00254 static _gdk_cursor_new_from_pixbuf_fn _gdk_cursor_new_from_pixbuf;
00255 static PRBool sPixbufCursorChecked;
00256 
00257 // needed for GetAttention calls
00258 // gdk_window_set_urgency_hint was added in 2.8
00259 typedef void (*_gdk_window_set_urgency_hint_fn)(GdkWindow *window,
00260                                                 gboolean urgency);
00261 
00262 #define kWindowPositionSlop 20
00263 
00264 // cursor cache
00265 static GdkCursor *gCursorCache[eCursorCount];
00266 
00267 #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
00268 
00269 nsWindow::nsWindow()
00270 {
00271     mContainer           = nsnull;
00272     mDrawingarea         = nsnull;
00273     mShell               = nsnull;
00274     mWindowGroup         = nsnull;
00275     mContainerGotFocus   = PR_FALSE;
00276     mContainerLostFocus  = PR_FALSE;
00277     mContainerBlockFocus = PR_FALSE;
00278     mInKeyRepeat         = PR_FALSE;
00279     mIsVisible           = PR_FALSE;
00280     mRetryPointerGrab    = PR_FALSE;
00281     mRetryKeyboardGrab   = PR_FALSE;
00282     mActivatePending     = PR_FALSE;
00283     mTransientParent     = nsnull;
00284     mWindowType          = eWindowType_child;
00285     mSizeState           = nsSizeMode_Normal;
00286     mOldFocusWindow      = 0;
00287     mPluginType          = PluginType_NONE;
00288 
00289     if (!gGlobalsInitialized) {
00290         gGlobalsInitialized = PR_TRUE;
00291 
00292         // It's OK if either of these fail, but it may not be one day.
00293         initialize_prefs();
00294     }
00295 
00296     if (mLastDragMotionWindow == this)
00297         mLastDragMotionWindow = NULL;
00298     mDragMotionWidget = 0;
00299     mDragMotionContext = 0;
00300     mDragMotionX = 0;
00301     mDragMotionY = 0;
00302     mDragMotionTime = 0;
00303     mDragMotionTimerID = 0;
00304 
00305 #ifdef USE_XIM
00306     mIMContext = nsnull;
00307     mComposingText = PR_FALSE;
00308 #endif
00309 
00310 #ifdef ACCESSIBILITY
00311     mRootAccessible  = nsnull;
00312 #endif
00313 
00314     mIsTranslucent = PR_FALSE;
00315     mTransparencyBitmap = nsnull;
00316 }
00317 
00318 nsWindow::~nsWindow()
00319 {
00320     LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
00321     if (mLastDragMotionWindow == this) {
00322         mLastDragMotionWindow = NULL;
00323     }
00324 
00325     delete[] mTransparencyBitmap;
00326     mTransparencyBitmap = nsnull;
00327 
00328     Destroy();
00329 }
00330 
00331 /* static */ void
00332 nsWindow::ReleaseGlobals()
00333 {
00334   for (PRUint32 i = 0; i < ARRAY_LENGTH(gCursorCache); ++i) {
00335     if (gCursorCache[i]) {
00336       gdk_cursor_unref(gCursorCache[i]);
00337       gCursorCache[i] = nsnull;
00338     }
00339   }
00340 }
00341 
00342 NS_IMPL_ISUPPORTS_INHERITED1(nsWindow, nsCommonWidget,
00343                              nsISupportsWeakReference)
00344 
00345 NS_IMETHODIMP
00346 nsWindow::Create(nsIWidget        *aParent,
00347                  const nsRect     &aRect,
00348                  EVENT_CALLBACK   aHandleEventFunction,
00349                  nsIDeviceContext *aContext,
00350                  nsIAppShell      *aAppShell,
00351                  nsIToolkit       *aToolkit,
00352                  nsWidgetInitData *aInitData)
00353 {
00354     nsresult rv = NativeCreate(aParent, nsnull, aRect, aHandleEventFunction,
00355                                aContext, aAppShell, aToolkit, aInitData);
00356     return rv;
00357 }
00358 
00359 NS_IMETHODIMP
00360 nsWindow::Create(nsNativeWidget aParent,
00361                  const nsRect     &aRect,
00362                  EVENT_CALLBACK   aHandleEventFunction,
00363                  nsIDeviceContext *aContext,
00364                  nsIAppShell      *aAppShell,
00365                  nsIToolkit       *aToolkit,
00366                  nsWidgetInitData *aInitData)
00367 {
00368     nsresult rv = NativeCreate(nsnull, aParent, aRect, aHandleEventFunction,
00369                                aContext, aAppShell, aToolkit, aInitData);
00370     return rv;
00371 }
00372 
00373 NS_IMETHODIMP
00374 nsWindow::Destroy(void)
00375 {
00376     if (mIsDestroyed || !mCreated)
00377         return NS_OK;
00378 
00379     LOG(("nsWindow::Destroy [%p]\n", (void *)this));
00380     mIsDestroyed = PR_TRUE;
00381     mCreated = PR_FALSE;
00382 
00383     g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
00384                                          (gpointer)G_CALLBACK(theme_changed_cb),
00385                                          this);
00386 
00387     // ungrab if required
00388     nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
00389     if (NS_STATIC_CAST(nsIWidget *, this) == rollupWidget.get()) {
00390         if (gRollupListener)
00391             gRollupListener->Rollup();
00392         gRollupWindow = nsnull;
00393         gRollupListener = nsnull;
00394     }
00395 
00396     NativeShow(PR_FALSE);
00397 
00398     // walk the list of children and call destroy on them.  Have to be
00399     // careful, though -- calling destroy on a kid may actually remove
00400     // it from our child list, losing its sibling links.
00401     for (nsIWidget* kid = mFirstChild; kid; ) {
00402         nsIWidget* next = kid->GetNextSibling();
00403         kid->Destroy();
00404         kid = next;
00405     }
00406 
00407 #ifdef USE_XIM
00408     IMEDestroyContext();
00409 #endif
00410 
00411     // make sure that we remove ourself as the focus window
00412     if (gFocusWindow == this) {
00413         LOGFOCUS(("automatically losing focus...\n"));
00414         gFocusWindow = nsnull;
00415     }
00416 
00417     // make sure that we remove ourself as the plugin focus window
00418     if (gPluginFocusWindow == this) {
00419         gPluginFocusWindow->LoseNonXEmbedPluginFocus();
00420     }
00421 
00422     // Remove our reference to the window group.  If there was a window
00423     // group destroying the widget will have automatically unreferenced
00424     // the group, destroying it if necessary.  And, if we're a child
00425     // window this isn't going to harm anything.
00426     mWindowGroup = nsnull;
00427 
00428     if (mDragMotionTimerID) {
00429         gtk_timeout_remove(mDragMotionTimerID);
00430         mDragMotionTimerID = 0;
00431     }
00432 
00433     if (mShell) {
00434         gtk_widget_destroy(mShell);
00435         mShell = nsnull;
00436         mContainer = nsnull;
00437     }
00438     else if (mContainer) {
00439         gtk_widget_destroy(GTK_WIDGET(mContainer));
00440         mContainer = nsnull;
00441     }
00442 
00443     if (mDrawingarea) {
00444         g_object_unref(mDrawingarea);
00445         mDrawingarea = nsnull;
00446     }
00447 
00448     OnDestroy();
00449 
00450 #ifdef ACCESSIBILITY
00451     if (mRootAccessible) {
00452         mRootAccessible = nsnull;
00453     }
00454 #endif
00455 
00456     return NS_OK;
00457 }
00458 
00459 NS_IMETHODIMP
00460 nsWindow::SetParent(nsIWidget *aNewParent)
00461 {
00462     NS_ENSURE_ARG_POINTER(aNewParent);
00463 
00464     GdkWindow* newParentWindow =
00465         NS_STATIC_CAST(GdkWindow*, aNewParent->GetNativeData(NS_NATIVE_WINDOW));
00466     NS_ASSERTION(newParentWindow, "Parent widget has a null native window handle");
00467 
00468     if (!mShell && mDrawingarea) {
00469         moz_drawingarea_reparent(mDrawingarea, newParentWindow);
00470     } else {
00471         NS_NOTREACHED("nsWindow::SetParent - reparenting a non-child window");
00472     }
00473     return NS_OK;
00474 }
00475 
00476 NS_IMETHODIMP
00477 nsWindow::SetModal(PRBool aModal)
00478 {
00479     LOG(("nsWindow::SetModal [%p] %d\n", (void *)this, aModal));
00480 
00481     // find the toplevel window and add it to the grab list
00482     GtkWidget *grabWidget = nsnull;
00483 
00484     GetToplevelWidget(&grabWidget);
00485 
00486     if (!grabWidget)
00487         return NS_ERROR_FAILURE;
00488 
00489     if (aModal)
00490         gtk_grab_add(grabWidget);
00491     else
00492         gtk_grab_remove(grabWidget);
00493 
00494     return NS_OK;
00495 }
00496 
00497 NS_IMETHODIMP
00498 nsWindow::IsVisible(PRBool & aState)
00499 {
00500     aState = mIsVisible;
00501     if (mIsTopLevel && mShell) {
00502         aState = GTK_WIDGET_VISIBLE(mShell);
00503     }
00504     return NS_OK;
00505 }
00506 
00507 NS_IMETHODIMP
00508 nsWindow::ConstrainPosition(PRBool aAllowSlop, PRInt32 *aX, PRInt32 *aY)
00509 {
00510     if (mIsTopLevel && mShell) {
00511         PRInt32 screenWidth = gdk_screen_width();
00512         PRInt32 screenHeight = gdk_screen_height();
00513         if (aAllowSlop) {
00514             if (*aX < (kWindowPositionSlop - mBounds.width))
00515                 *aX = kWindowPositionSlop - mBounds.width;
00516             if (*aX > (screenWidth - kWindowPositionSlop))
00517                 *aX = screenWidth - kWindowPositionSlop;
00518             if (*aY < (kWindowPositionSlop - mBounds.height))
00519                 *aY = kWindowPositionSlop - mBounds.height;
00520             if (*aY > (screenHeight - kWindowPositionSlop))
00521                 *aY = screenHeight - kWindowPositionSlop;
00522         } else {
00523             if (*aX < 0)
00524                 *aX = 0;
00525             if (*aX > (screenWidth - mBounds.width))
00526                 *aX = screenWidth - mBounds.width;
00527             if (*aY < 0)
00528                 *aY = 0;
00529             if (*aY > (screenHeight - mBounds.height))
00530                 *aY = screenHeight - mBounds.height;
00531         }
00532     }
00533     return NS_OK;
00534 }
00535 
00536 NS_IMETHODIMP
00537 nsWindow::Move(PRInt32 aX, PRInt32 aY)
00538 {
00539     LOG(("nsWindow::Move [%p] %d %d\n", (void *)this,
00540          aX, aY));
00541 
00542     mPlaced = PR_TRUE;
00543 
00544     // Since a popup window's x/y coordinates are in relation to to
00545     // the parent, the parent might have moved so we always move a
00546     // popup window.
00547     if (aX == mBounds.x && aY == mBounds.y &&
00548         mWindowType != eWindowType_popup)
00549         return NS_OK;
00550 
00551     mBounds.x = aX;
00552     mBounds.y = aY;
00553 
00554     if (!mCreated)
00555         return NS_OK;
00556 
00557     if (mIsTopLevel) {
00558         if (mParent && mWindowType == eWindowType_popup) {
00559             nsRect oldrect, newrect;
00560             oldrect.x = aX;
00561             oldrect.y = aY;
00562             mParent->WidgetToScreen(oldrect, newrect);
00563             gtk_window_move(GTK_WINDOW(mShell), newrect.x, newrect.y);
00564         }
00565         else {
00566             // We only move the toplevel window if someone has
00567             // actually placed the window somewhere.  If no placement
00568             // has taken place, we just let the window manager Do The
00569             // Right Thing.
00570             if (mPlaced)
00571                 gtk_window_move(GTK_WINDOW(mShell), aX, aY);
00572         }
00573     }
00574     else if (mDrawingarea) {
00575         moz_drawingarea_move(mDrawingarea, aX, aY);
00576     }
00577 
00578     return NS_OK;
00579 }
00580 
00581 NS_IMETHODIMP
00582 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement  aPlacement,
00583                       nsIWidget                  *aWidget,
00584                       PRBool                      aActivate)
00585 {
00586     return NS_ERROR_NOT_IMPLEMENTED;
00587 }
00588 
00589 NS_IMETHODIMP
00590 nsWindow::SetZIndex(PRInt32 aZIndex)
00591 {
00592     nsIWidget* oldPrev = GetPrevSibling();
00593 
00594     nsBaseWidget::SetZIndex(aZIndex);
00595 
00596     if (GetPrevSibling() == oldPrev) {
00597         return NS_OK;
00598     }
00599 
00600     NS_ASSERTION(!mContainer, "Expected Mozilla child widget");
00601 
00602     // We skip the nsWindows that don't have mDrawingareas.
00603     // These are probably in the process of being destroyed.
00604 
00605     if (!GetNextSibling()) {
00606         // We're to be on top.
00607         if (mDrawingarea)
00608             gdk_window_raise(mDrawingarea->clip_window);
00609     } else {
00610         // All the siblings before us need to be below our widget. 
00611         for (nsWindow* w = this; w;
00612              w = NS_STATIC_CAST(nsWindow*, w->GetPrevSibling())) {
00613             if (w->mDrawingarea)
00614                 gdk_window_lower(w->mDrawingarea->clip_window);
00615         }
00616     }
00617     return NS_OK;
00618 }
00619 
00620 NS_IMETHODIMP
00621 nsWindow::SetSizeMode(PRInt32 aMode)
00622 {
00623     nsresult rv;
00624 
00625     LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode));
00626 
00627     // Save the requested state.
00628     rv = nsBaseWidget::SetSizeMode(aMode);
00629 
00630     // return if there's no shell or our current state is the same as
00631     // the mode we were just set to.
00632     if (!mShell || mSizeState == mSizeMode) {
00633         return rv;
00634     }
00635 
00636     switch (aMode) {
00637     case nsSizeMode_Maximized:
00638         gtk_window_maximize(GTK_WINDOW(mShell));
00639         break;
00640     case nsSizeMode_Minimized:
00641         gtk_window_iconify(GTK_WINDOW(mShell));
00642         break;
00643     default:
00644         // nsSizeMode_Normal, really.
00645         if (mSizeState == nsSizeMode_Minimized)
00646             gtk_window_deiconify(GTK_WINDOW(mShell));
00647         else if (mSizeState == nsSizeMode_Maximized)
00648             gtk_window_unmaximize(GTK_WINDOW(mShell));
00649         break;
00650     }
00651 
00652     mSizeState = mSizeMode;
00653 
00654     return rv;
00655 }
00656 
00657 NS_IMETHODIMP
00658 nsWindow::Enable(PRBool aState)
00659 {
00660     return NS_ERROR_NOT_IMPLEMENTED;
00661 }
00662 
00663 NS_IMETHODIMP
00664 nsWindow::SetFocus(PRBool aRaise)
00665 {
00666     // Make sure that our owning widget has focus.  If it doesn't try to
00667     // grab it.  Note that we don't set our focus flag in this case.
00668 
00669     LOGFOCUS(("  SetFocus [%p]\n", (void *)this));
00670 
00671     if (!mDrawingarea)
00672         return NS_ERROR_FAILURE;
00673 
00674     GtkWidget *owningWidget =
00675         get_gtk_widget_for_gdk_window(mDrawingarea->inner_window);
00676     if (!owningWidget)
00677         return NS_ERROR_FAILURE;
00678 
00679     // Raise the window if someone passed in PR_TRUE and the prefs are
00680     // set properly.
00681     GtkWidget *toplevelWidget = gtk_widget_get_toplevel(owningWidget);
00682 
00683     if (gRaiseWindows && aRaise && toplevelWidget &&
00684         !GTK_WIDGET_HAS_FOCUS(owningWidget) &&
00685         !GTK_WIDGET_HAS_FOCUS(toplevelWidget)) {
00686         GtkWidget* top_window = nsnull;
00687         GetToplevelWidget(&top_window);
00688         if (top_window && (GTK_WIDGET_VISIBLE(top_window)))
00689         {
00690             gdk_window_show(top_window->window);
00691             // Unset the urgency hint if possible.
00692             SetUrgencyHint(top_window, PR_FALSE);
00693         }
00694     }
00695 
00696     nsWindow  *owningWindow = get_window_for_gtk_widget(owningWidget);
00697     if (!owningWindow)
00698         return NS_ERROR_FAILURE;
00699 
00700     if (!GTK_WIDGET_HAS_FOCUS(owningWidget)) {
00701         LOGFOCUS(("  grabbing focus for the toplevel [%p]\n", (void *)this));
00702         owningWindow->mContainerBlockFocus = PR_TRUE;
00703         gtk_widget_grab_focus(owningWidget);
00704         owningWindow->mContainerBlockFocus = PR_FALSE;
00705 
00706         DispatchGotFocusEvent();
00707 
00708         // unset the activate flag
00709         if (owningWindow->mActivatePending) {
00710             owningWindow->mActivatePending = PR_FALSE;
00711             DispatchActivateEvent();
00712         }
00713 
00714         return NS_OK;
00715     }
00716 
00717     // If this is the widget that already has focus, return.
00718     if (gFocusWindow == this) {
00719         LOGFOCUS(("  already have focus [%p]\n", (void *)this));
00720         return NS_OK;
00721     }
00722 
00723     // If there is already a focused child window, dispatch a LOSTFOCUS
00724     // event from that widget and unset its got focus flag.
00725     if (gFocusWindow) {
00726 #ifdef USE_XIM
00727         // If the focus window and this window share the same input
00728         // context we don't have to change the focus of the IME
00729         // context
00730         if (IM_get_input_context(this->mDrawingarea) !=
00731             IM_get_input_context(gFocusWindow->mDrawingarea))
00732             gFocusWindow->IMELoseFocus();
00733 #endif
00734         gFocusWindow->LoseFocus();
00735     }
00736 
00737     // Set this window to be the focused child window, update our has
00738     // focus flag and dispatch a GOTFOCUS event.
00739     gFocusWindow = this;
00740 
00741 #ifdef USE_XIM
00742     IMESetFocus();
00743 #endif
00744 
00745     LOGFOCUS(("  widget now has focus - dispatching events [%p]\n",
00746               (void *)this));
00747 
00748     DispatchGotFocusEvent();
00749 
00750     // unset the activate flag
00751     if (owningWindow->mActivatePending) {
00752         owningWindow->mActivatePending = PR_FALSE;
00753         DispatchActivateEvent();
00754     }
00755 
00756     LOGFOCUS(("  done dispatching events in SetFocus() [%p]\n",
00757               (void *)this));
00758 
00759     return NS_OK;
00760 }
00761 
00762 NS_IMETHODIMP
00763 nsWindow::GetScreenBounds(nsRect &aRect)
00764 {
00765     nsRect origin(0, 0, mBounds.width, mBounds.height);
00766     WidgetToScreen(origin, aRect);
00767     LOG(("GetScreenBounds %d %d | %d %d | %d %d\n",
00768          aRect.x, aRect.y,
00769          mBounds.width, mBounds.height,
00770          aRect.width, aRect.height));
00771     return NS_OK;
00772 }
00773 
00774 NS_IMETHODIMP
00775 nsWindow::SetForegroundColor(const nscolor &aColor)
00776 {
00777     return NS_ERROR_NOT_IMPLEMENTED;
00778 }
00779 
00780 NS_IMETHODIMP
00781 nsWindow::SetBackgroundColor(const nscolor &aColor)
00782 {
00783     return NS_ERROR_NOT_IMPLEMENTED;
00784 }
00785 
00786 nsIFontMetrics*
00787 nsWindow::GetFont(void)
00788 {
00789     return nsnull;
00790 }
00791 
00792 NS_IMETHODIMP
00793 nsWindow::SetFont(const nsFont &aFont)
00794 {
00795     return NS_ERROR_NOT_IMPLEMENTED;
00796 }
00797 
00798 NS_IMETHODIMP
00799 nsWindow::SetCursor(nsCursor aCursor)
00800 {
00801     // if we're not the toplevel window pass up the cursor request to
00802     // the toplevel window to handle it.
00803     if (!mContainer && mDrawingarea) {
00804         GtkWidget *widget =
00805             get_gtk_widget_for_gdk_window(mDrawingarea->inner_window);
00806         nsWindow *window = get_window_for_gtk_widget(widget);
00807         return window->SetCursor(aCursor);
00808     }
00809 
00810     // Only change cursor if it's actually been changed
00811     if (aCursor != mCursor) {
00812         GdkCursor *newCursor = NULL;
00813 
00814         newCursor = get_gtk_cursor(aCursor);
00815 
00816         if (nsnull != newCursor) {
00817             mCursor = aCursor;
00818 
00819             if (!mContainer)
00820                 return NS_OK;
00821 
00822             gdk_window_set_cursor(GTK_WIDGET(mContainer)->window, newCursor);
00823 
00824             XFlush(GDK_DISPLAY());
00825         }
00826     }
00827 
00828     return NS_OK;
00829 }
00830 
00831 
00832 static
00833 PRUint8* Data32BitTo1Bit(PRUint8* aImageData,
00834                          PRUint32 aImageBytesPerRow,
00835                          PRUint32 aWidth, PRUint32 aHeight)
00836 {
00837   PRUint32 outBpr = (aWidth + 7) / 8;
00838   
00839   PRUint8* outData = new PRUint8[outBpr * aHeight];
00840   if (!outData)
00841       return NULL;
00842 
00843   PRUint8 *outRow = outData,
00844           *imageRow = aImageData;
00845 
00846   for (PRUint32 curRow = 0; curRow < aHeight; curRow++) {
00847       PRUint8 *irow = imageRow;
00848       PRUint8 *orow = outRow;
00849       PRUint8 imagePixels = 0;
00850       PRUint8 offset = 0;
00851 
00852       for (PRUint32 curCol = 0; curCol < aWidth; curCol++) {
00853           PRUint8 r = *imageRow++,
00854                   g = *imageRow++,
00855                   b = *imageRow++;
00856                /* a = * */imageRow++;
00857 
00858           if ((r + b + g) < 3 * 128)
00859               imagePixels |= (1 << offset);
00860 
00861           if (offset == 7) {
00862               *outRow++ = imagePixels;
00863               offset = 0;
00864               imagePixels = 0;
00865           } else {
00866               offset++;
00867           }
00868       }
00869       if (offset != 0)
00870           *outRow++ = imagePixels;
00871 
00872       imageRow = irow + aImageBytesPerRow;
00873       outRow = orow + outBpr;
00874   }
00875 
00876   return outData;
00877 }
00878 
00879 
00880 
00881 NS_IMETHODIMP
00882 nsWindow::SetCursor(imgIContainer* aCursor,
00883                     PRUint32 aHotspotX, PRUint32 aHotspotY)
00884 {
00885     // if we're not the toplevel window pass up the cursor request to
00886     // the toplevel window to handle it.
00887     if (!mContainer && mDrawingarea) {
00888         GtkWidget *widget =
00889             get_gtk_widget_for_gdk_window(mDrawingarea->inner_window);
00890         nsWindow *window = get_window_for_gtk_widget(widget);
00891         return window->SetCursor(aCursor, aHotspotX, aHotspotY);
00892     }
00893 
00894     if (!sPixbufCursorChecked) {
00895         PRLibrary* lib;
00896         _gdk_cursor_new_from_pixbuf = (_gdk_cursor_new_from_pixbuf_fn)
00897             PR_FindFunctionSymbolAndLibrary("gdk_cursor_new_from_pixbuf", &lib);
00898         _gdk_display_get_default = (_gdk_display_get_default_fn)
00899             PR_FindFunctionSymbolAndLibrary("gdk_display_get_default", &lib);
00900         sPixbufCursorChecked = PR_TRUE;
00901     }
00902     mCursor = nsCursor(-1);
00903 
00904     // Get first image frame
00905     nsCOMPtr<gfxIImageFrame> frame;
00906     aCursor->GetFrameAt(0, getter_AddRefs(frame));
00907     if (!frame)
00908         return NS_ERROR_NOT_AVAILABLE;
00909 
00910     nsCOMPtr<nsIImage> img(do_GetInterface(frame));
00911     if (!img)
00912         return NS_ERROR_NOT_AVAILABLE;
00913 
00914     nsCOMPtr<nsIGdkPixbufImage> pixImg(do_QueryInterface(img));
00915     if (!pixImg)
00916         return NS_ERROR_NOT_AVAILABLE;
00917 
00918     GdkPixbuf* pixbuf = pixImg->GetGdkPixbuf();
00919     if (!pixbuf)
00920         return NS_ERROR_NOT_AVAILABLE;
00921 
00922     int width = gdk_pixbuf_get_width(pixbuf);
00923     int height = gdk_pixbuf_get_height(pixbuf);
00924     // Reject cursors greater than 128 pixels in some direction, to prevent
00925     // spoofing.
00926     // XXX ideally we should rescale. Also, we could modify the API to
00927     // allow trusted content to set larger cursors.
00928     if (width > 128 || height > 128) {
00929         gdk_pixbuf_unref(pixbuf);
00930         return NS_ERROR_NOT_AVAILABLE;
00931     }
00932 
00933     // Looks like all cursors need an alpha channel (tested on Gtk 2.4.4). This
00934     // is of course not documented anywhere...
00935     // So add one if there isn't one yet
00936     if (!gdk_pixbuf_get_has_alpha(pixbuf)) {
00937         GdkPixbuf* alphaBuf = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
00938         gdk_pixbuf_unref(pixbuf);
00939         if (!alphaBuf) {
00940             return NS_ERROR_OUT_OF_MEMORY;
00941         }
00942         pixbuf = alphaBuf;
00943     }
00944 
00945     GdkCursor* cursor;
00946     if (!_gdk_cursor_new_from_pixbuf || !_gdk_display_get_default) {
00947         // Fallback to a monochrome cursor
00948         GdkPixmap* mask = gdk_pixmap_new(NULL, width, height, 1);
00949         if (!mask) {
00950             gdk_pixbuf_unref(pixbuf);
00951             return NS_ERROR_OUT_OF_MEMORY;
00952         }
00953 
00954         PRUint8* data = Data32BitTo1Bit(gdk_pixbuf_get_pixels(pixbuf),
00955                                         gdk_pixbuf_get_rowstride(pixbuf),
00956                                         width, height);
00957         if (!data) {
00958             g_object_unref(mask);
00959             gdk_pixbuf_unref(pixbuf);
00960             return NS_ERROR_OUT_OF_MEMORY;
00961         }
00962 
00963         GdkPixmap* image = gdk_bitmap_create_from_data(NULL, (const gchar*)data, width,
00964                                                        height);
00965         delete[] data;
00966         if (!image) {
00967             g_object_unref(mask);
00968             gdk_pixbuf_unref(pixbuf);
00969             return NS_ERROR_OUT_OF_MEMORY;
00970         }
00971 
00972         gdk_pixbuf_render_threshold_alpha(pixbuf, mask, 0, 0, 0, 0, width,
00973                                           height, 1);
00974 
00975         GdkColor fg = { 0, 0, 0, 0 }; // Black
00976         GdkColor bg = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; // White
00977 
00978         cursor = gdk_cursor_new_from_pixmap(image, mask, &fg, &bg, aHotspotX,
00979                                             aHotspotY);
00980         g_object_unref(image);
00981         g_object_unref(mask);
00982     } else {
00983         // Now create the cursor
00984         cursor = _gdk_cursor_new_from_pixbuf(_gdk_display_get_default(),
00985                                              pixbuf,
00986                                              aHotspotX, aHotspotY);
00987     }
00988     gdk_pixbuf_unref(pixbuf);
00989     nsresult rv = NS_ERROR_OUT_OF_MEMORY;
00990     if (cursor) {
00991         if (mContainer) {
00992             gdk_window_set_cursor(GTK_WIDGET(mContainer)->window, cursor);
00993             XFlush(GDK_DISPLAY());
00994             rv = NS_OK;
00995         }
00996         gdk_cursor_unref(cursor);
00997     }
00998 
00999     return rv;
01000 }
01001 
01002 
01003 NS_IMETHODIMP
01004 nsWindow::Validate()
01005 {
01006     // Get the update for this window and, well, just drop it on the
01007     // floor.
01008     if (!mDrawingarea)
01009         return NS_OK;
01010 
01011     GdkRegion *region = gdk_window_get_update_area(mDrawingarea->inner_window);
01012 
01013     if (region)
01014         gdk_region_destroy(region);
01015 
01016     return NS_OK;
01017 }
01018 
01019 NS_IMETHODIMP
01020 nsWindow::Invalidate(PRBool aIsSynchronous)
01021 {
01022     GdkRectangle rect;
01023 
01024     rect.x = mBounds.x;
01025     rect.y = mBounds.y;
01026     rect.width = mBounds.width;
01027     rect.height = mBounds.height;
01028 
01029     LOGDRAW(("Invalidate (all) [%p]: %d %d %d %d\n", (void *)this,
01030              rect.x, rect.y, rect.width, rect.height));
01031 
01032     if (!mDrawingarea)
01033         return NS_OK;
01034 
01035     gdk_window_invalidate_rect(mDrawingarea->inner_window,
01036                                &rect, FALSE);
01037     if (aIsSynchronous)
01038         gdk_window_process_updates(mDrawingarea->inner_window, FALSE);
01039 
01040     return NS_OK;
01041 }
01042 
01043 NS_IMETHODIMP
01044 nsWindow::Invalidate(const nsRect &aRect,
01045                      PRBool        aIsSynchronous)
01046 {
01047     GdkRectangle rect;
01048 
01049     rect.x = aRect.x;
01050     rect.y = aRect.y;
01051     rect.width = aRect.width;
01052     rect.height = aRect.height;
01053 
01054     LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d (sync: %d)\n", (void *)this,
01055              rect.x, rect.y, rect.width, rect.height, aIsSynchronous));
01056 
01057     if (!mDrawingarea)
01058         return NS_OK;
01059 
01060     gdk_window_invalidate_rect(mDrawingarea->inner_window,
01061                                &rect, FALSE);
01062     if (aIsSynchronous)
01063         gdk_window_process_updates(mDrawingarea->inner_window, FALSE);
01064 
01065     return NS_OK;
01066 }
01067 
01068 NS_IMETHODIMP
01069 nsWindow::InvalidateRegion(const nsIRegion* aRegion,
01070                            PRBool           aIsSynchronous)
01071 {
01072     GdkRegion *region = nsnull;
01073     aRegion->GetNativeRegion((void *&)region);
01074 
01075     if (region && mDrawingarea) {
01076         GdkRectangle rect;
01077         gdk_region_get_clipbox(region, &rect);
01078 
01079         LOGDRAW(("Invalidate (region) [%p]: %d %d %d %d (sync: %d)\n",
01080                  (void *)this,
01081                  rect.x, rect.y, rect.width, rect.height, aIsSynchronous));
01082 
01083         gdk_window_invalidate_region(mDrawingarea->inner_window,
01084                                      region, FALSE);
01085     }
01086     else {
01087         LOGDRAW(("Invalidate (region) [%p] with empty region\n",
01088                  (void *)this));
01089     }
01090 
01091     return NS_OK;
01092 }
01093 
01094 NS_IMETHODIMP
01095 nsWindow::Update()
01096 {
01097     if (!mDrawingarea)
01098         return NS_OK;
01099 
01100     gdk_window_process_updates(mDrawingarea->inner_window, FALSE);
01101     return NS_OK;
01102 }
01103 
01104 NS_IMETHODIMP
01105 nsWindow::SetColorMap(nsColorMap *aColorMap)
01106 {
01107     return NS_ERROR_NOT_IMPLEMENTED;
01108 }
01109 
01110 NS_IMETHODIMP
01111 nsWindow::Scroll(PRInt32  aDx,
01112                  PRInt32  aDy,
01113                  nsRect  *aClipRect)
01114 {
01115     if (!mDrawingarea)
01116         return NS_OK;
01117 
01118     moz_drawingarea_scroll(mDrawingarea, aDx, aDy);
01119 
01120     // Update bounds on our child windows
01121     for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
01122         nsRect bounds;
01123         kid->GetBounds(bounds);
01124         bounds.x += aDx;
01125         bounds.y += aDy;
01126         NS_STATIC_CAST(nsBaseWidget*, kid)->SetBounds(bounds);
01127     }
01128 
01129     // Process all updates so that everything is drawn.
01130     gdk_window_process_all_updates();
01131     return NS_OK;
01132 }
01133 
01134 NS_IMETHODIMP
01135 nsWindow::ScrollWidgets(PRInt32 aDx,
01136                         PRInt32 aDy)
01137 {
01138     if (!mDrawingarea)
01139         return NS_OK;
01140 
01141     moz_drawingarea_scroll(mDrawingarea, aDx, aDy);
01142     return NS_OK;
01143 }
01144 
01145 NS_IMETHODIMP
01146 nsWindow::ScrollRect(nsRect  &aSrcRect,
01147                      PRInt32  aDx,
01148                      PRInt32  aDy)
01149 {
01150     return NS_ERROR_NOT_IMPLEMENTED;
01151 }
01152 
01153 void*
01154 nsWindow::GetNativeData(PRUint32 aDataType)
01155 {
01156     switch (aDataType) {
01157     case NS_NATIVE_WINDOW:
01158     case NS_NATIVE_WIDGET: {
01159         if (!mDrawingarea)
01160             return nsnull;
01161 
01162         return mDrawingarea->inner_window;
01163         break;
01164     }
01165 
01166     case NS_NATIVE_PLUGIN_PORT:
01167         return SetupPluginPort();
01168         break;
01169 
01170     case NS_NATIVE_DISPLAY:
01171         return GDK_DISPLAY();
01172         break;
01173 
01174     case NS_NATIVE_GRAPHIC: {
01175         NS_ASSERTION(nsnull != mToolkit, "NULL toolkit, unable to get a GC");
01176         return (void *)NS_STATIC_CAST(nsToolkit *, mToolkit)->GetSharedGC();
01177         break;
01178     }
01179 
01180     case NS_NATIVE_SHELLWIDGET:
01181         return (void *) mShell;
01182 
01183     default:
01184         NS_WARNING("nsWindow::GetNativeData called with bad value");
01185         return nsnull;
01186     }
01187 }
01188 
01189 NS_IMETHODIMP
01190 nsWindow::SetBorderStyle(nsBorderStyle aBorderStyle)
01191 {
01192     return NS_ERROR_NOT_IMPLEMENTED;
01193 }
01194 
01195 NS_IMETHODIMP
01196 nsWindow::SetTitle(const nsAString& aTitle)
01197 {
01198     if (!mShell)
01199         return NS_OK;
01200 
01201     // convert the string into utf8 and set the title.
01202 #define UTF8_FOLLOWBYTE(ch) (((ch) & 0xC0) == 0x80)
01203     NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
01204     if (titleUTF8.Length() > NS_WINDOW_TITLE_MAX_LENGTH) {
01205         // Truncate overlong titles (bug 167315). Make sure we chop after a
01206         // complete sequence by making sure the next char isn't a follow-byte.
01207         PRUint32 len = NS_WINDOW_TITLE_MAX_LENGTH;
01208         while(UTF8_FOLLOWBYTE(titleUTF8[len]))
01209             --len;
01210         titleUTF8.Truncate(len);
01211     }
01212     gtk_window_set_title(GTK_WINDOW(mShell), (const char *)titleUTF8.get());
01213 
01214     return NS_OK;
01215 }
01216 
01217 NS_IMETHODIMP
01218 nsWindow::SetIcon(const nsAString& aIconSpec)
01219 {
01220     if (!mShell)
01221         return NS_OK;
01222 
01223     nsCOMPtr<nsILocalFile> iconFile;
01224     nsCAutoString path;
01225     nsCStringArray iconList;
01226 
01227     // Assume the given string is a local identifier for an icon file.
01228 
01229     ResolveIconName(aIconSpec, NS_LITERAL_STRING(".xpm"),
01230                     getter_AddRefs(iconFile));
01231     if (iconFile) {
01232         iconFile->GetNativePath(path);
01233         iconList.AppendCString(path);
01234     }
01235 
01236     // Get the 16px icon path as well
01237     ResolveIconName(aIconSpec, NS_LITERAL_STRING("16.xpm"),
01238                     getter_AddRefs(iconFile));
01239     if (iconFile) {
01240         iconFile->GetNativePath(path);
01241         iconList.AppendCString(path);
01242     }
01243 
01244     // leave the default icon intact if no matching icons were found
01245     if (iconList.Count() == 0)
01246         return NS_OK;
01247 
01248     return SetWindowIconList(iconList);
01249 }
01250 
01251 NS_IMETHODIMP
01252 nsWindow::SetMenuBar(nsIMenuBar * aMenuBar)
01253 {
01254     return NS_ERROR_NOT_IMPLEMENTED;
01255 }
01256 
01257 NS_IMETHODIMP
01258 nsWindow::ShowMenuBar(PRBool aShow)
01259 {
01260     return NS_ERROR_NOT_IMPLEMENTED;
01261 }
01262 
01263 NS_IMETHODIMP
01264 nsWindow::WidgetToScreen(const nsRect& aOldRect, nsRect& aNewRect)
01265 {
01266     gint x, y = 0;
01267 
01268     if (mContainer) {
01269         gdk_window_get_root_origin(GTK_WIDGET(mContainer)->window,
01270                                    &x, &y);
01271         LOG(("WidgetToScreen (container) %d %d\n", x, y));
01272     }
01273     else if (mDrawingarea) {
01274         gdk_window_get_origin(mDrawingarea->inner_window, &x, &y);
01275         LOG(("WidgetToScreen (drawing) %d %d\n", x, y));
01276     }
01277 
01278     aNewRect.x = x + aOldRect.x;
01279     aNewRect.y = y + aOldRect.y;
01280     aNewRect.width = aOldRect.width;
01281     aNewRect.height = aOldRect.height;
01282 
01283     return NS_OK;
01284 }
01285 
01286 NS_IMETHODIMP
01287 nsWindow::ScreenToWidget(const nsRect& aOldRect, nsRect& aNewRect)
01288 {
01289     return NS_ERROR_NOT_IMPLEMENTED;
01290 }
01291 
01292 NS_IMETHODIMP
01293 nsWindow::BeginResizingChildren(void)
01294 {
01295     return NS_ERROR_NOT_IMPLEMENTED;
01296 }
01297 
01298 NS_IMETHODIMP
01299 nsWindow::EndResizingChildren(void)
01300 {
01301     return NS_ERROR_NOT_IMPLEMENTED;
01302 }
01303 
01304 NS_IMETHODIMP
01305 nsWindow::EnableDragDrop(PRBool aEnable)
01306 {
01307     return NS_OK;
01308 }
01309 
01310 void
01311 nsWindow::ConvertToDeviceCoordinates(nscoord &aX,
01312                                      nscoord &aY)
01313 {
01314 }
01315 
01316 NS_IMETHODIMP
01317 nsWindow::PreCreateWidget(nsWidgetInitData *aWidgetInitData)
01318 {
01319     if (nsnull != aWidgetInitData) {
01320         mWindowType = aWidgetInitData->mWindowType;
01321         mBorderStyle = aWidgetInitData->mBorderStyle;
01322         return NS_OK;
01323     }
01324     return NS_ERROR_FAILURE;
01325 }
01326 
01327 NS_IMETHODIMP
01328 nsWindow::CaptureMouse(PRBool aCapture)
01329 {
01330     LOG(("CaptureMouse %p\n", (void *)this));
01331 
01332     if (!mDrawingarea)
01333         return NS_OK;
01334 
01335     GtkWidget *widget =
01336         get_gtk_widget_for_gdk_window(mDrawingarea->inner_window);
01337 
01338     if (aCapture) {
01339         gtk_grab_add(widget);
01340         GrabPointer();
01341     }
01342     else {
01343         ReleaseGrabs();
01344         gtk_grab_remove(widget);
01345     }
01346 
01347     return NS_OK;
01348 }
01349 
01350 NS_IMETHODIMP
01351 nsWindow::CaptureRollupEvents(nsIRollupListener *aListener,
01352                               PRBool             aDoCapture,
01353                               PRBool             aConsumeRollupEvent)
01354 {
01355     if (!mDrawingarea)
01356         return NS_OK;
01357 
01358     GtkWidget *widget =
01359         get_gtk_widget_for_gdk_window(mDrawingarea->inner_window);
01360 
01361     LOG(("CaptureRollupEvents %p\n", (void *)this));
01362 
01363     if (aDoCapture) {
01364         gRollupListener = aListener;
01365         gRollupWindow = do_GetWeakReference(NS_STATIC_CAST(nsIWidget*,
01366                                                            this));
01367         // real grab is only done when there is no dragging
01368         if (!nsWindow::DragInProgress()) {
01369             gtk_grab_add(widget);
01370             GrabPointer();
01371             GrabKeyboard();
01372         }
01373     }
01374     else {
01375         if (!nsWindow::DragInProgress()) {
01376             ReleaseGrabs();
01377             gtk_grab_remove(widget);
01378         }
01379         gRollupListener = nsnull;
01380         gRollupWindow = nsnull;
01381     }
01382 
01383     return NS_OK;
01384 }
01385 
01386 NS_IMETHODIMP
01387 nsWindow::GetAttention(PRInt32 aCycleCount)
01388 {
01389     LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
01390 
01391     GtkWidget* top_window = nsnull;
01392     GtkWidget* top_focused_window = nsnull;
01393     GetToplevelWidget(&top_window);
01394     if (gFocusWindow)
01395         gFocusWindow->GetToplevelWidget(&top_focused_window);
01396 
01397     // Don't get attention if the window is focused anyway.
01398     if (top_window && (GTK_WIDGET_VISIBLE(top_window)) &&
01399         top_window != top_focused_window) {
01400         SetUrgencyHint(top_window, PR_TRUE);
01401     }
01402 
01403     return NS_OK;
01404 }
01405 
01406 void
01407 nsWindow::LoseFocus(void)
01408 {
01409     // make sure that we reset our repeat counter so the next keypress
01410     // for this widget will get the down event
01411     mInKeyRepeat = PR_FALSE;
01412 
01413     // Dispatch a lostfocus event
01414     DispatchLostFocusEvent();
01415 
01416     LOGFOCUS(("  widget lost focus [%p]\n", (void *)this));
01417 }
01418 
01419 gboolean
01420 nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
01421 {
01422     if (mIsDestroyed) {
01423         LOG(("Expose event on destroyed window [%p] window %p\n",
01424              (void *)this, (void *)aEvent->window));
01425         return NS_OK;
01426     }
01427 
01428     if (!mDrawingarea)
01429         return FALSE;
01430 
01431     // handle exposes for the inner window only
01432     if (aEvent->window != mDrawingarea->inner_window)
01433         return FALSE;
01434 
01435     nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
01436 
01437     static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
01438 
01439     nsCOMPtr<nsIRegion> updateRegion = do_CreateInstance(kRegionCID);
01440     if (!updateRegion)
01441         return FALSE;
01442 
01443     updateRegion->Init();
01444 
01445     GdkRectangle *rects;
01446     gint nrects;
01447     gdk_region_get_rectangles(aEvent->region, &rects, &nrects);
01448     LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
01449              (void *)this, (void *)aEvent->window,
01450              GDK_WINDOW_XWINDOW(aEvent->window)));
01451 
01452     for (GdkRectangle *r = rects, *r_end = rects + nrects; r < r_end; ++r) {
01453         updateRegion->Union(r->x, r->y, r->width, r->height);
01454         LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
01455     }
01456 
01457     nsPaintEvent event(PR_TRUE, NS_PAINT, this);
01458     event.point.x = aEvent->area.x;
01459     event.point.y = aEvent->area.y;
01460     event.rect = nsnull;
01461     event.region = updateRegion;
01462     event.renderingContext = rc;
01463 
01464     nsEventStatus status;
01465     DispatchEvent(&event, status);
01466 
01467     g_free(rects);
01468 
01469     // check the return value!
01470     return TRUE;
01471 }
01472 
01473 gboolean
01474 nsWindow::OnConfigureEvent(GtkWidget *aWidget, GdkEventConfigure *aEvent)
01475 {
01476     LOG(("configure event [%p] %d %d %d %d\n", (void *)this,
01477          aEvent->x, aEvent->y, aEvent->width, aEvent->height));
01478 
01479     // can we shortcut?
01480     if (mBounds.x == aEvent->x &&
01481         mBounds.y == aEvent->y)
01482         return FALSE;
01483 
01484     // Toplevel windows need to have their bounds set so that we can
01485     // keep track of our location.  It's not often that the x,y is set
01486     // by the layout engine.  Width and height are set elsewhere.
01487     if (mIsTopLevel) {
01488         mPlaced = PR_TRUE;
01489         // Need to translate this into the right coordinates
01490         nsRect oldrect, newrect;
01491         WidgetToScreen(oldrect, newrect);
01492         mBounds.x = newrect.x;
01493         mBounds.y = newrect.y;
01494     }
01495 
01496     nsGUIEvent event(PR_TRUE, NS_MOVE, this);
01497 
01498     event.point.x = aEvent->x;
01499     event.point.y = aEvent->y;
01500 
01501     // XXX mozilla will invalidate the entire window after this move
01502     // complete.  wtf?
01503     nsEventStatus status;
01504     DispatchEvent(&event, status);
01505 
01506     return FALSE;
01507 }
01508 
01509 void
01510 nsWindow::OnSizeAllocate(GtkWidget *aWidget, GtkAllocation *aAllocation)
01511 {
01512     LOG(("size_allocate [%p] %d %d %d %d\n",
01513          (void *)this, aAllocation->x, aAllocation->y,
01514          aAllocation->width, aAllocation->height));
01515 
01516     nsRect rect(aAllocation->x, aAllocation->y,
01517                 aAllocation->width, aAllocation->height);
01518 
01519     ResizeTransparencyBitmap(rect.width, rect.height);
01520 
01521     mBounds.width = rect.width;
01522     mBounds.height = rect.height;
01523 
01524     if (!mDrawingarea)
01525         return;
01526 
01527     moz_drawingarea_resize (mDrawingarea, rect.width, rect.height);
01528 
01529     nsEventStatus status;
01530     DispatchResizeEvent (rect, status);
01531 }
01532 
01533 void
01534 nsWindow::OnDeleteEvent(GtkWidget *aWidget, GdkEventAny *aEvent)
01535 {
01536     nsGUIEvent event(PR_TRUE, NS_XUL_CLOSE, this);
01537 
01538     event.point.x = 0;
01539     event.point.y = 0;
01540 
01541     nsEventStatus status;
01542     DispatchEvent(&event, status);
01543 }
01544 
01545 void
01546 nsWindow::OnEnterNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
01547 {
01548     // XXXldb Is this the right test for embedding cases?
01549     if (aEvent->subwindow != NULL)
01550         return;
01551 
01552     nsMouseEvent event(PR_TRUE, NS_MOUSE_ENTER, this, nsMouseEvent::eReal);
01553 
01554     event.point.x = nscoord(aEvent->x);
01555     event.point.y = nscoord(aEvent->y);
01556 
01557     LOG(("OnEnterNotify: %p\n", (void *)this));
01558 
01559     nsEventStatus status;
01560     DispatchEvent(&event, status);
01561 }
01562 
01563 void
01564 nsWindow::OnLeaveNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
01565 {
01566     // XXXldb Is this the right test for embedding cases?
01567     if (aEvent->subwindow != NULL)
01568         return;
01569 
01570     nsMouseEvent event(PR_TRUE, NS_MOUSE_EXIT, this, nsMouseEvent::eReal);
01571 
01572     event.point.x = nscoord(aEvent->x);
01573     event.point.y = nscoord(aEvent->y);
01574 
01575     LOG(("OnLeaveNotify: %p\n", (void *)this));
01576 
01577     nsEventStatus status;
01578     DispatchEvent(&event, status);
01579 }
01580 
01581 void
01582 nsWindow::OnMotionNotifyEvent(GtkWidget *aWidget, GdkEventMotion *aEvent)
01583 {
01584     // when we receive this, it must be that the gtk dragging is over,
01585     // it is dropped either in or out of mozilla, clear the flag
01586     sIsDraggingOutOf = PR_FALSE;
01587 
01588     // see if we can compress this event
01589     XEvent xevent;
01590     PRPackedBool synthEvent = PR_FALSE;
01591     while (XCheckWindowEvent(GDK_WINDOW_XDISPLAY(aEvent->window),
01592                              GDK_WINDOW_XWINDOW(aEvent->window),
01593                              ButtonMotionMask, &xevent)) {
01594         synthEvent = PR_TRUE;
01595     }
01596 
01597     // if plugins still keeps the focus, get it back
01598     if (gPluginFocusWindow && gPluginFocusWindow != this) {
01599         gPluginFocusWindow->LoseNonXEmbedPluginFocus();
01600     }
01601 
01602     nsMouseEvent event(PR_TRUE, NS_MOUSE_MOVE, this, nsMouseEvent::eReal);
01603 
01604     if (synthEvent) {
01605         event.point.x = nscoord(xevent.xmotion.x);
01606         event.point.y = nscoord(xevent.xmotion.y);
01607 
01608         event.isShift   = (xevent.xmotion.state & GDK_SHIFT_MASK)
01609             ? PR_TRUE : PR_FALSE;
01610         event.isControl = (xevent.xmotion.state & GDK_CONTROL_MASK)
01611             ? PR_TRUE : PR_FALSE;
01612         event.isAlt     = (xevent.xmotion.state & GDK_MOD1_MASK)
01613             ? PR_TRUE : PR_FALSE;
01614     }
01615     else {
01616         event.point.x = nscoord(aEvent->x);
01617         event.point.y = nscoord(aEvent->y);
01618 
01619         event.isShift   = (aEvent->state & GDK_SHIFT_MASK)
01620             ? PR_TRUE : PR_FALSE;
01621         event.isControl = (aEvent->state & GDK_CONTROL_MASK)
01622             ? PR_TRUE : PR_FALSE;
01623         event.isAlt     = (aEvent->state & GDK_MOD1_MASK)
01624             ? PR_TRUE : PR_FALSE;
01625     }
01626 
01627     nsEventStatus status;
01628     DispatchEvent(&event, status);
01629 }
01630 
01631 void
01632 nsWindow::OnButtonPressEvent(GtkWidget *aWidget, GdkEventButton *aEvent)
01633 {
01634     PRUint32      eventType;
01635     nsEventStatus status;
01636 
01637     // If you double click in GDK, it will actually generate a single
01638     // click event before sending the double click event, and this is
01639     // different than the DOM spec.  GDK puts this in the queue
01640     // programatically, so it's safe to assume that if there's a
01641     // double click in the queue, it was generated so we can just drop
01642     // this click.
01643     GdkEvent *peekedEvent = gdk_event_peek();
01644     if (peekedEvent) {
01645         GdkEventType type = peekedEvent->any.type;
01646         gdk_event_free(peekedEvent);
01647         if (type == GDK_2BUTTON_PRESS || type == GDK_3BUTTON_PRESS)
01648             return;
01649     }
01650 
01651     // Always save the time of this event
01652     mLastButtonPressTime = aEvent->time;
01653     mLastButtonReleaseTime = 0;
01654 
01655     // check to see if we should rollup
01656     nsWindow *containerWindow;
01657     GetContainerWindow(&containerWindow);
01658 
01659     if (!gFocusWindow) {
01660         containerWindow->mActivatePending = PR_FALSE;
01661         DispatchActivateEvent();
01662     }
01663     if (check_for_rollup(aEvent->window, aEvent->x_root, aEvent->y_root,
01664                          PR_FALSE))
01665         return;
01666 
01667     switch (aEvent->button) {
01668     case 2:
01669         eventType = NS_MOUSE_MIDDLE_BUTTON_DOWN;
01670         break;
01671     case 3:
01672         eventType = NS_MOUSE_RIGHT_BUTTON_DOWN;
01673         break;
01674     default:
01675         eventType = NS_MOUSE_LEFT_BUTTON_DOWN;
01676         break;
01677     }
01678 
01679     nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
01680 
01681     nsMouseEvent event(PR_TRUE, eventType, this, nsMouseEvent::eReal);
01682     InitButtonEvent(event, aEvent);
01683 
01684     DispatchEvent(&event, status);
01685 
01686     // right menu click on linux should also pop up a context menu
01687     if (eventType == NS_MOUSE_RIGHT_BUTTON_DOWN) {
01688         nsMouseEvent contextMenuEvent(PR_TRUE, NS_CONTEXTMENU, this,
01689                                       nsMouseEvent::eReal);
01690         InitButtonEvent(contextMenuEvent, aEvent);
01691         DispatchEvent(&contextMenuEvent, status);
01692     }
01693 }
01694 
01695 void
01696 nsWindow::OnButtonReleaseEvent(GtkWidget *aWidget, GdkEventButton *aEvent)
01697 {
01698     PRUint32      eventType;
01699 
01700     mLastButtonReleaseTime = aEvent->time;
01701 
01702     switch (aEvent->button) {
01703     case 2:
01704         eventType = NS_MOUSE_MIDDLE_BUTTON_UP;
01705         break;
01706     case 3:
01707         eventType = NS_MOUSE_RIGHT_BUTTON_UP;
01708         break;
01709         // don't send events for these types
01710     case 4:
01711     case 5:
01712         return;
01713         break;
01714         // default including button 1 is left button up
01715     default:
01716         eventType = NS_MOUSE_LEFT_BUTTON_UP;
01717         break;
01718     }
01719 
01720     nsMouseEvent  event(PR_TRUE, eventType, this, nsMouseEvent::eReal);
01721     InitButtonEvent(event, aEvent);
01722 
01723     nsEventStatus status;
01724     DispatchEvent(&event, status);
01725 }
01726 
01727 void
01728 nsWindow::OnContainerFocusInEvent(GtkWidget *aWidget, GdkEventFocus *aEvent)
01729 {
01730     LOGFOCUS(("OnContainerFocusInEvent [%p]\n", (void *)this));
01731     // Return if someone has blocked events for this widget.  This will
01732     // happen if someone has called gtk_widget_grab_focus() from
01733     // nsWindow::SetFocus() and will prevent recursion.
01734     if (mContainerBlockFocus) {
01735         LOGFOCUS(("Container focus is blocked [%p]\n", (void *)this));
01736         return;
01737     }
01738 
01739     if (mIsTopLevel)
01740         mActivatePending = PR_TRUE;
01741 
01742     // Unset the urgency hint, if possible
01743     GtkWidget* top_window = nsnull;
01744     GetToplevelWidget(&top_window);
01745     if (top_window && (GTK_WIDGET_VISIBLE(top_window)))
01746         SetUrgencyHint(top_window, PR_FALSE);
01747 
01748     // dispatch a got focus event
01749     DispatchGotFocusEvent();
01750 
01751     // send the activate event if it wasn't already sent via any
01752     // SetFocus() calls that were the result of the GOTFOCUS event
01753     // above.
01754     if (mActivatePending) {
01755         mActivatePending = PR_FALSE;
01756         DispatchActivateEvent();
01757     }
01758 
01759     LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
01760 }
01761 
01762 void
01763 nsWindow::OnContainerFocusOutEvent(GtkWidget *aWidget, GdkEventFocus *aEvent)
01764 {
01765     LOGFOCUS(("OnContainerFocusOutEvent [%p]\n", (void *)this));
01766 
01767     // plugin lose focus
01768     if (gPluginFocusWindow) {
01769         gPluginFocusWindow->LoseNonXEmbedPluginFocus();
01770     }
01771 
01772     // Figure out if the focus widget is the child of this window.  If
01773     // it is, send a focus out and deactivate event for it.
01774     if (!gFocusWindow)
01775         return;
01776 
01777     GdkWindow *tmpWindow;
01778     tmpWindow = (GdkWindow *)gFocusWindow->GetNativeData(NS_NATIVE_WINDOW);
01779     nsWindow *tmpnsWindow = get_window_for_gdk_window(tmpWindow);
01780 
01781     while (tmpWindow && tmpnsWindow) {
01782         // found it!
01783         if (tmpnsWindow == this)
01784             goto foundit;
01785 
01786         tmpWindow = gdk_window_get_parent(tmpWindow);
01787         if (!tmpWindow)
01788             break;
01789 
01790         tmpnsWindow = get_owning_window_for_gdk_window(tmpWindow);
01791     }
01792 
01793     LOGFOCUS(("The focus widget was not a child of this window [%p]\n",
01794               (void *)this));
01795 
01796     return;
01797 
01798  foundit:
01799 
01800 #ifdef USE_XIM
01801     gFocusWindow->IMELoseFocus();
01802 #endif
01803 
01804     gFocusWindow->LoseFocus();
01805 
01806     // We only dispatch a deactivate event if we are a toplevel
01807     // window, otherwise the embedding code takes care of it.
01808     if (mIsTopLevel)
01809         gFocusWindow->DispatchDeactivateEvent();
01810 
01811     gFocusWindow = nsnull;
01812 
01813     mActivatePending = PR_FALSE;
01814 
01815     LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
01816 }
01817 
01818 gboolean
01819 nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
01820 {
01821     LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
01822 
01823 #ifdef USE_XIM
01824     // if we are in the middle of composing text, XIM gets to see it
01825     // before mozilla does.
01826    LOGIM(("key press [%p]: composing %d val %d\n",
01827            (void *)this, mComposingText, aEvent->keyval));
01828    if (IMEFilterEvent(aEvent))
01829        return TRUE;
01830    LOGIM(("sending as regular key press event\n"));
01831 #endif
01832 
01833     nsEventStatus status;
01834 
01835     // work around for annoying things.
01836     if (aEvent->keyval == GDK_Tab && aEvent->state & GDK_CONTROL_MASK &&
01837         aEvent->state & GDK_MOD1_MASK) {
01838         return TRUE;
01839     }
01840 
01841     nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
01842 
01843     // If the key repeat flag isn't set then set it so we don't send
01844     // another key down event on the next key press -- DOM events are
01845     // key down, key press and key up.  X only has key press and key
01846     // release.  gtk2 already filters the extra key release events for
01847     // us.
01848 
01849     PRBool isKeyDownCancelled = PR_FALSE;
01850     if (!mInKeyRepeat) {
01851         mInKeyRepeat = PR_TRUE;
01852 
01853         // send the key down event
01854         nsKeyEvent downEvent(PR_TRUE, NS_KEY_DOWN, this);
01855         InitKeyEvent(downEvent, aEvent);
01856         DispatchEvent(&downEvent, status);
01857         isKeyDownCancelled = (status == nsEventStatus_eConsumeNoDefault);
01858     }
01859 
01860     // Don't pass modifiers as NS_KEY_PRESS events.
01861     // TODO: Instead of selectively excluding some keys from NS_KEY_PRESS events,
01862     //       we should instead selectively include (as per MSDN spec; no official
01863     //       spec covers KeyPress events).
01864     if (aEvent->keyval == GDK_Shift_L
01865         || aEvent->keyval == GDK_Shift_R
01866         || aEvent->keyval == GDK_Control_L
01867         || aEvent->keyval == GDK_Control_R
01868         || aEvent->keyval == GDK_Alt_L
01869         || aEvent->keyval == GDK_Alt_R
01870         || aEvent->keyval == GDK_Meta_L
01871         || aEvent->keyval == GDK_Meta_R) {
01872         // reset the key repeat flag so that the next keypress gets the
01873         // key down event
01874         mInKeyRepeat = PR_FALSE;
01875         return TRUE;
01876     }
01877     nsKeyEvent event(PR_TRUE, NS_KEY_PRESS, this);
01878     InitKeyEvent(event, aEvent);
01879     if (isKeyDownCancelled) {
01880       // If prevent default set for onkeydown, do the same for onkeypress
01881       event.flags |= NS_EVENT_FLAG_NO_DEFAULT;
01882     }
01883     event.charCode = nsConvertCharCodeToUnicode(aEvent);
01884     if (event.charCode) {
01885         event.keyCode = 0;
01886         // if the control, meta, or alt key is down, then we should leave
01887         // the isShift flag alone (probably not a printable character)
01888         // if none of the other modifier keys are pressed then we need to
01889         // clear isShift so the character can be inserted in the editor
01890 
01891         if (event.isControl || event.isAlt || event.isMeta) {
01892            // make Ctrl+uppercase functional as same as Ctrl+lowercase
01893            // when Ctrl+uppercase(eg.Ctrl+C) is pressed,convert the charCode
01894            // from uppercase to lowercase(eg.Ctrl+c),so do Alt and Meta Key
01895            // It is hack code for bug 61355, there is same code snip for
01896            // Windows platform in widget/src/windows/nsWindow.cpp: See bug 16486
01897            // Note: if Shift is pressed at the same time, do not to_lower()
01898            // Because Ctrl+Shift has different function with Ctrl
01899            if (!event.isShift &&
01900                event.charCode >= GDK_A &&
01901                event.charCode <= GDK_Z)
01902             event.charCode = gdk_keyval_to_lower(event.charCode);
01903 
01904            // Keep the characters unshifted for shortcuts and accesskeys and
01905            // make sure that numbers are always passed as such (among others:
01906            // bugs 50255 and 351310)
01907            if (!event.isControl && event.isShift &&
01908                (event.charCode < GDK_0 || event.charCode > GDK_9)) {
01909                GdkKeymapKey k = { aEvent->hardware_keycode, aEvent->group, 0 };
01910                guint savedKeyval = aEvent->keyval;
01911                aEvent->keyval = gdk_keymap_lookup_key(gdk_keymap_get_default(), &k);
01912                PRUint32 unshiftedCharCode = nsConvertCharCodeToUnicode(aEvent);
01913                if (unshiftedCharCode)
01914                    event.charCode = unshiftedCharCode;
01915                else
01916                    aEvent->keyval = savedKeyval;
01917            }
01918         }
01919     }
01920 
01921     // before we dispatch a key, check if it's the context menu key.
01922     // If so, send a context menu key event instead.
01923     if (is_context_menu_key(event)) {
01924         nsMouseEvent contextMenuEvent(PR_TRUE, 0, nsnull, nsMouseEvent::eReal);
01925         key_event_to_context_menu_event(&event, &contextMenuEvent);
01926         DispatchEvent(&contextMenuEvent, status);
01927     }
01928     else {
01929         // send the key press event
01930         DispatchEvent(&event, status);
01931     }
01932 
01933     // If the event was consumed, return.
01934     LOGIM(("status %d\n", status));
01935     if (status == nsEventStatus_eConsumeNoDefault) {
01936         LOGIM(("key press consumed\n"));
01937         return TRUE;
01938     }
01939 
01940     return FALSE;
01941 }
01942 
01943 gboolean
01944 nsWindow::OnKeyReleaseEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
01945 {
01946     LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
01947 
01948 #ifdef USE_XIM
01949     if (IMEFilterEvent(aEvent))
01950         return TRUE;
01951 #endif
01952 
01953     nsEventStatus status;
01954 
01955     // unset the repeat flag
01956     mInKeyRepeat = PR_FALSE;
01957 
01958     // send the key event as a key up event
01959     nsKeyEvent event(PR_TRUE, NS_KEY_UP, this);
01960     InitKeyEvent(event, aEvent);
01961 
01962     DispatchEvent(&event, status);
01963 
01964     // If the event was consumed, return.
01965     if (status == nsEventStatus_eConsumeNoDefault) {
01966         LOGIM(("key release consumed\n"));
01967         return TRUE;
01968     }
01969 
01970     return FALSE;
01971 }
01972 
01973 void
01974 nsWindow::OnScrollEvent(GtkWidget *aWidget, GdkEventScroll *aEvent)
01975 {
01976     nsMouseScrollEvent event(PR_TRUE, NS_MOUSE_SCROLL, this);
01977     InitMouseScrollEvent(event, aEvent);
01978 
01979     // check to see if we should rollup
01980     if (check_for_rollup(aEvent->window, aEvent->x_root, aEvent->y_root,
01981                          PR_TRUE)) {
01982         return;
01983     }
01984 
01985     nsEventStatus status;
01986     DispatchEvent(&event, status);
01987 }
01988 
01989 void
01990 nsWindow::OnVisibilityNotifyEvent(GtkWidget *aWidget,
01991                                   GdkEventVisibility *aEvent)
01992 {
01993     switch (aEvent->state) {
01994     case GDK_VISIBILITY_UNOBSCURED:
01995     case GDK_VISIBILITY_PARTIAL:
01996         mIsVisible = PR_TRUE;
01997         // if we have to retry the grab, retry it.
01998         EnsureGrabs();
01999         break;
02000     default: // includes GDK_VISIBILITY_FULLY_OBSCURED
02001         mIsVisible = PR_FALSE;
02002         break;
02003     }
02004 }
02005 
02006 void
02007 nsWindow::OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent)
02008 {
02009     LOG(("nsWindow::OnWindowStateEvent [%p] changed %d new_window_state %d\n",
02010          (void *)this, aEvent->changed_mask, aEvent->new_window_state));
02011 
02012     nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, this);
02013 
02014     // We don't care about anything but changes in the maximized/icon
02015     // states
02016     if (aEvent->changed_mask &
02017         (GDK_WINDOW_STATE_ICONIFIED|GDK_WINDOW_STATE_MAXIMIZED) == 0) {
02018         return;
02019     }
02020 
02021     if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) {
02022         LOG(("\tIconified\n"));
02023         event.mSizeMode = nsSizeMode_Minimized;
02024         mSizeState = nsSizeMode_Minimized;
02025     }
02026     else if (aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
02027         LOG(("\tMaximized\n"));
02028         event.mSizeMode = nsSizeMode_Maximized;
02029         mSizeState = nsSizeMode_Maximized;
02030     }
02031     else {
02032         LOG(("\tNormal\n"));
02033         event.mSizeMode = nsSizeMode_Normal;
02034         mSizeState = nsSizeMode_Normal;
02035     }
02036 
02037     nsEventStatus status;
02038     DispatchEvent(&event, status);
02039 }
02040 
02041 void
02042 nsWindow::ThemeChanged()
02043 {
02044     nsGUIEvent event(PR_TRUE, NS_THEMECHANGED, this);
02045     nsEventStatus status = nsEventStatus_eIgnore;
02046     DispatchEvent(&event, status);
02047 
02048     if (!mDrawingarea)
02049         return;
02050 
02051     // Dispatch NS_THEMECHANGED to all child windows
02052     GList *children =
02053         gdk_window_peek_children(mDrawingarea->inner_window);
02054     while (children) {
02055         GdkWindow *gdkWin = GDK_WINDOW(children->data);
02056 
02057         nsWindow *win = (nsWindow*) g_object_get_data(G_OBJECT(gdkWin),
02058                                                       "nsWindow");
02059 
02060         if (win && win != this)   // guard against infinite recursion
02061             win->ThemeChanged();
02062 
02063         children = children->next;
02064     }
02065 }
02066 
02067 gboolean
02068 nsWindow::OnDragMotionEvent(GtkWidget *aWidget,
02069                             GdkDragContext *aDragContext,
02070                             gint aX,
02071                             gint aY,
02072                             guint aTime,
02073                             gpointer aData)
02074 {
02075     LOG(("nsWindow::OnDragMotionSignal\n"));
02076 
02077     if (mLastButtonReleaseTime) {
02078       // The drag ended before it was even setup to handle the end of the drag
02079       // So, we fake the button getting released again to release the drag
02080       GtkWidget *widget = gtk_grab_get_current();
02081       GdkEvent event;
02082       gboolean retval;
02083       memset(&event, 0, sizeof(event));
02084       event.type = GDK_BUTTON_RELEASE;
02085       event.button.time = mLastButtonReleaseTime;
02086       event.button.button = 1;
02087       mLastButtonReleaseTime = 0;
02088       if (widget) {
02089         g_signal_emit_by_name(widget, "button_release_event", &event, &retval);
02090         return TRUE;
02091       }
02092     }
02093 
02094     sIsDraggingOutOf = PR_FALSE;
02095 
02096     // Reset out drag motion timer
02097     ResetDragMotionTimer(aWidget, aDragContext, aX, aY, aTime);
02098 
02099     // get our drag context
02100     nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
02101     nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
02102 
02103     // first, figure out which internal widget this drag motion actually
02104     // happened on
02105     nscoord retx = 0;
02106     nscoord rety = 0;
02107 
02108     GdkWindow *thisWindow = aWidget->window;
02109     GdkWindow *returnWindow = NULL;
02110     returnWindow = get_inner_gdk_window(thisWindow, aX, aY,
02111                                         &retx, &rety);
02112     nsWindow *innerMostWidget = NULL;
02113     innerMostWidget = get_window_for_gdk_window(returnWindow);
02114 
02115     if (!innerMostWidget)
02116         innerMostWidget = this;
02117 
02118     // check to see if there was a drag motion window already in place
02119     if (mLastDragMotionWindow) {
02120         // if it wasn't this
02121         if (mLastDragMotionWindow != innerMostWidget) {
02122             // send a drag event to the last window that got a motion event
02123             mLastDragMotionWindow->OnDragLeave();
02124             // and enter on the new one
02125             innerMostWidget->OnDragEnter(retx, rety);
02126         }
02127     }
02128     else {
02129         // if there was no other motion window, then we're starting a
02130         // drag. Send an enter event to initiate the drag.
02131 
02132         innerMostWidget->OnDragEnter(retx, rety);
02133     }
02134 
02135     // set the last window to the innerMostWidget
02136     mLastDragMotionWindow = innerMostWidget;
02137 
02138     // update the drag context
02139     dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
02140 
02141     // notify the drag service that we are starting a drag motion.
02142     dragSessionGTK->TargetStartDragMotion();
02143 
02144     nsMouseEvent event(PR_TRUE, NS_DRAGDROP_OVER, innerMostWidget,
02145                        nsMouseEvent::eReal);
02146 
02147     InitDragEvent(event);
02148 
02149     // now that we have initialized the event update our drag status
02150     UpdateDragStatus(event, aDragContext, dragService);
02151 
02152     event.point.x = retx;
02153     event.point.y = rety;
02154 
02155     innerMostWidget->AddRef();
02156 
02157     nsEventStatus status;
02158     innerMostWidget->DispatchEvent(&event, status);
02159 
02160     innerMostWidget->Release();
02161 
02162     // we're done with the drag motion event.  notify the drag service.
02163     dragSessionGTK->TargetEndDragMotion(aWidget, aDragContext, aTime);
02164 
02165     // and unset our context
02166     dragSessionGTK->TargetSetLastContext(0, 0, 0);
02167 
02168     return TRUE;
02169 }
02170 
02171 void
02172 nsWindow::OnDragLeaveEvent(GtkWidget *aWidget,
02173                            GdkDragContext *aDragContext,
02174                            guint aTime,
02175                            gpointer aData)
02176 {
02177     // XXX Do we want to pass this on only if the event's subwindow is null?
02178 
02179     LOG(("nsWindow::OnDragLeaveSignal(%p)\n", this));
02180 
02181     sIsDraggingOutOf = PR_TRUE;
02182 
02183     // make sure to unset any drag motion timers here.
02184     ResetDragMotionTimer(0, 0, 0, 0, 0);
02185 
02186     // create a fast timer - we're delaying the drag leave until the
02187     // next mainloop in hopes that we might be able to get a drag drop
02188     // signal
02189     mDragLeaveTimer = do_CreateInstance("@mozilla.org/timer;1");
02190     NS_ASSERTION(mDragLeaveTimer, "Failed to create drag leave timer!");
02191     // fire this baby asafp, but not too quickly... see bug 216800 ;-)
02192     mDragLeaveTimer->InitWithFuncCallback(DragLeaveTimerCallback,
02193                                           (void *)this,
02194                                           20, nsITimer::TYPE_ONE_SHOT);
02195 }
02196 
02197 gboolean
02198 nsWindow::OnDragDropEvent(GtkWidget *aWidget,
02199                           GdkDragContext *aDragContext,
02200                           gint aX,
02201                           gint aY,
02202                           guint aTime,
02203                           gpointer *aData)
02204 
02205 {
02206     LOG(("nsWindow::OnDragDropSignal\n"));
02207 
02208     // get our drag context
02209     nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
02210     nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
02211 
02212     nscoord retx = 0;
02213     nscoord rety = 0;
02214 
02215     GdkWindow *thisWindow = aWidget->window;
02216     GdkWindow *returnWindow = NULL;
02217     returnWindow = get_inner_gdk_window(thisWindow, aX, aY, &retx, &rety);
02218 
02219     nsWindow *innerMostWidget = NULL;
02220     innerMostWidget = get_window_for_gdk_window(returnWindow);
02221 
02222     // set this now before any of the drag enter or leave events happen
02223     dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
02224 
02225     if (!innerMostWidget)
02226         innerMostWidget = this;
02227 
02228     // check to see if there was a drag motion window already in place
02229     if (mLastDragMotionWindow) {
02230         // if it wasn't this
02231         if (mLastDragMotionWindow != innerMostWidget) {
02232             // send a drag event to the last window that got a motion event
02233             mLastDragMotionWindow->OnDragLeave();
02234             // and enter on the new one
02235             innerMostWidget->OnDragEnter(retx, rety);
02236         }
02237     }
02238     else {
02239         // if there was no other motion window, send an enter event to
02240         // initiate the drag session.
02241         innerMostWidget->OnDragEnter(retx, rety);
02242     }
02243 
02244     // clear any drag leave timer that might be pending so that it
02245     // doesn't get processed when we actually go out to get data.
02246     if (mDragLeaveTimer) {
02247         mDragLeaveTimer->Cancel();
02248         mDragLeaveTimer = 0;
02249     }
02250 
02251     // set the last window to this
02252     mLastDragMotionWindow = innerMostWidget;
02253 
02254     // What we do here is dispatch a new drag motion event to
02255     // re-validate the drag target and then we do the drop.  The events
02256     // look the same except for the type.
02257 
02258     innerMostWidget->AddRef();
02259 
02260     nsMouseEvent event(PR_TRUE, NS_DRAGDROP_OVER, innerMostWidget,
02261                        nsMouseEvent::eReal);
02262 
02263     InitDragEvent(event);
02264 
02265     // now that we have initialized the event update our drag status
02266     UpdateDragStatus(event, aDragContext, dragService);
02267 
02268     event.point.x = retx;
02269     event.point.y = rety;
02270 
02271     nsEventStatus status;
02272     innerMostWidget->DispatchEvent(&event, status);
02273 
02274     event.message = NS_DRAGDROP_DROP;
02275     event.widget = innerMostWidget;
02276     event.point.x = retx;
02277     event.point.y = rety;
02278 
02279     innerMostWidget->DispatchEvent(&event, status);
02280 
02281     innerMostWidget->Release();
02282 
02283     // before we unset the context we need to do a drop_finish
02284 
02285     gdk_drop_finish(aDragContext, TRUE, aTime);
02286 
02287     // after a drop takes place we need to make sure that the drag
02288     // service doesn't think that it still has a context.  if the other
02289     // way ( besides the drop ) to end a drag event is during the leave
02290     // event and and that case is handled in that handler.
02291     dragSessionGTK->TargetSetLastContext(0, 0, 0);
02292 
02293     // send our drag exit event
02294     innerMostWidget->OnDragLeave();
02295     // and clear the mLastDragMotion window
02296     mLastDragMotionWindow = 0;
02297 
02298     // Make sure to end the drag session. If this drag started in a
02299     // different app, we won't get a drag_end signal to end it from.
02300     dragService->EndDragSession();
02301 
02302     return TRUE;
02303 }
02304 
02305 void
02306 nsWindow::OnDragDataReceivedEvent(GtkWidget *aWidget,
02307                                   GdkDragContext *aDragContext,
02308                                   gint aX,
02309                                   gint aY,
02310                                   GtkSelectionData  *aSelectionData,
02311                                   guint aInfo,
02312                                   guint aTime,
02313                                   gpointer aData)
02314 {
02315     LOG(("nsWindow::OnDragDataReceived(%p)\n", this));
02316 
02317     // get our drag context
02318     nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
02319     nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
02320 
02321     dragSessionGTK->TargetDataReceived(aWidget, aDragContext, aX, aY,
02322                                        aSelectionData, aInfo, aTime);
02323 }
02324 
02325 void
02326 nsWindow::OnDragLeave(void)
02327 {
02328     LOG(("nsWindow::OnDragLeave(%p)\n", this));
02329 
02330     nsMouseEvent event(PR_TRUE, NS_DRAGDROP_EXIT, this, nsMouseEvent::eReal);
02331 
02332     AddRef();
02333 
02334     nsEventStatus status;
02335     DispatchEvent(&event, status);
02336 
02337     nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
02338 
02339     if (dragService) {
02340         nsCOMPtr<nsIDragSession> currentDragSession;
02341         dragService->GetCurrentSession(getter_AddRefs(currentDragSession));
02342 
02343         if (currentDragSession) {
02344             nsCOMPtr<nsIDOMNode> sourceNode;
02345             currentDragSession->GetSourceNode(getter_AddRefs(sourceNode));
02346 
02347             if (!sourceNode) {
02348                 // We're leaving a window while doing a drag that was
02349                 // initiated in a different app. End the drag session,
02350                 // since we're done with it for now (until the user
02351                 // drags back into mozilla).
02352                 dragService->EndDragSession();
02353             }
02354         }
02355     }
02356 
02357     Release();
02358 }
02359 
02360 void
02361 nsWindow::OnDragEnter(nscoord aX, nscoord aY)
02362 {
02363     // XXX Do we want to pass this on only if the event's subwindow is null?
02364 
02365     LOG(("nsWindow::OnDragEnter(%p)\n", this));
02366 
02367     nsMouseEvent event(PR_TRUE, NS_DRAGDROP_ENTER, this, nsMouseEvent::eReal);
02368 
02369     event.point.x = aX;
02370     event.point.y = aY;
02371 
02372     AddRef();
02373 
02374     nsEventStatus status;
02375     DispatchEvent(&event, status);
02376 
02377     nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
02378 
02379     if (dragService) {
02380         // Make sure that the drag service knows we're now dragging.
02381         dragService->StartDragSession();
02382     }
02383 
02384     Release();
02385 }
02386 
02387 nsresult
02388 nsWindow::NativeCreate(nsIWidget        *aParent,
02389                        nsNativeWidget    aNativeParent,
02390                        const nsRect     &aRect,
02391                        EVENT_CALLBACK    aHandleEventFunction,
02392                        nsIDeviceContext *aContext,
02393                        nsIAppShell      *aAppShell,
02394                        nsIToolkit       *aToolkit,
02395                        nsWidgetInitData *aInitData)
02396 {
02397     // only set the base parent if we're going to be a dialog or a
02398     // toplevel
02399     nsIWidget *baseParent = aInitData &&
02400         (aInitData->mWindowType == eWindowType_dialog ||
02401          aInitData->mWindowType == eWindowType_toplevel ||
02402          aInitData->mWindowType == eWindowType_invisible) ?
02403         nsnull : aParent;
02404 
02405     NS_ASSERTION(aInitData->mWindowType != eWindowType_popup ||
02406                  !aParent, "Popups should not be hooked into nsIWidget hierarchy");
02407 
02408     // initialize all the common bits of this class
02409     BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
02410                aAppShell, aToolkit, aInitData);
02411 
02412     // Do we need to listen for resizes?
02413     PRBool listenForResizes = PR_FALSE;;
02414     if (aNativeParent || (aInitData && aInitData->mListenForResizes))
02415         listenForResizes = PR_TRUE;
02416 
02417     // and do our common creation
02418     CommonCreate(aParent, listenForResizes);
02419 
02420     // save our bounds
02421     mBounds = aRect;
02422 
02423     // figure out our parent window
02424     MozDrawingarea *parentArea = nsnull;
02425     MozContainer   *parentMozContainer = nsnull;
02426     GtkContainer   *parentGtkContainer = nsnull;
02427     GdkWindow      *parentGdkWindow = nsnull;
02428     GtkWindow      *topLevelParent = nsnull;
02429 
02430     if (aParent)
02431         parentGdkWindow = GDK_WINDOW(aParent->GetNativeData(NS_NATIVE_WINDOW));
02432     else if (aNativeParent && GDK_IS_WINDOW(aNativeParent))
02433         parentGdkWindow = GDK_WINDOW(aNativeParent);
02434     else if (aNativeParent && GTK_IS_CONTAINER(aNativeParent))
02435         parentGtkContainer = GTK_CONTAINER(aNativeParent);
02436 
02437     if (parentGdkWindow) {
02438         // find the mozarea on that window
02439         gpointer user_data = nsnull;
02440         user_data = g_object_get_data(G_OBJECT(parentGdkWindow),
02441                                       "mozdrawingarea");
02442         parentArea = MOZ_DRAWINGAREA(user_data);
02443 
02444         NS_ASSERTION(parentArea, "no drawingarea for parent widget!\n");
02445         if (!parentArea)
02446             return NS_ERROR_FAILURE;
02447 
02448         // get the user data for the widget - it should be a container
02449         user_data = nsnull;
02450         gdk_window_get_user_data(parentArea->inner_window, &user_data);
02451         NS_ASSERTION(user_data, "no user data for parentArea\n");
02452         if (!user_data)
02453             return NS_ERROR_FAILURE;
02454 
02455         // Get the parent moz container
02456         parentMozContainer = MOZ_CONTAINER(user_data);
02457         NS_ASSERTION(parentMozContainer,
02458                      "owning widget is not a mozcontainer!\n");
02459         if (!parentMozContainer)
02460             return NS_ERROR_FAILURE;
02461 
02462         // get the toplevel window just in case someone needs to use it
02463         // for setting transients or whatever.
02464         topLevelParent =
02465             GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(parentMozContainer)));
02466     }
02467 
02468     // ok, create our windows
02469     switch (mWindowType) {
02470     case eWindowType_dialog:
02471     case eWindowType_popup:
02472     case eWindowType_toplevel:
02473     case eWindowType_invisible: {
02474         mIsTopLevel = PR_TRUE;
02475         if (mWindowType == eWindowType_dialog) {
02476             mShell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
02477             SetDefaultIcon();
02478             gtk_window_set_type_hint(GTK_WINDOW(mShell),
02479                                      GDK_WINDOW_TYPE_HINT_DIALOG);
02480             gtk_window_set_transient_for(GTK_WINDOW(mShell),
02481                                          topLevelParent);
02482             mTransientParent = topLevelParent;
02483             // add ourselves to the parent window's window group
02484             if (!topLevelParent) {
02485                 gtk_widget_realize(mShell);
02486                 GdkWindow* dialoglead = mShell->window;
02487                 gdk_window_set_group(dialoglead, dialoglead);
02488             }
02489             if (parentArea) {
02490                 nsWindow *parentnsWindow =
02491                     get_window_for_gdk_window(parentArea->inner_window);
02492                 NS_ASSERTION(parentnsWindow,
02493                              "no nsWindow for parentArea!");
02494                 if (parentnsWindow && parentnsWindow->mWindowGroup) {
02495                     gtk_window_group_add_window(parentnsWindow->mWindowGroup,
02496                                                 GTK_WINDOW(mShell));
02497                     // store this in case any children are created
02498                     mWindowGroup = parentnsWindow->mWindowGroup;
02499                     LOG(("adding window %p to group %p\n",
02500                          (void *)mShell, (void *)mWindowGroup));
02501                 }
02502             }
02503         }
02504         else if (mWindowType == eWindowType_popup) {
02505             mShell = gtk_window_new(GTK_WINDOW_POPUP);
02506             if (topLevelParent) {
02507                 gtk_window_set_transient_for(GTK_WINDOW(mShell),
02508                                             topLevelParent);
02509                 mTransientParent = topLevelParent;
02510 
02511                 if (topLevelParent->group) {
02512                     gtk_window_group_add_window(topLevelParent->group,
02513                                             GTK_WINDOW(mShell));
02514                     mWindowGroup = topLevelParent->group;
02515                 }
02516             }
02517         }
02518         else { // must be eWindowType_toplevel
02519             mShell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
02520             SetDefaultIcon();
02521 
02522             // each toplevel window gets its own window group
02523             mWindowGroup = gtk_window_group_new();
02524 
02525             // and add ourselves to the window group
02526             LOG(("adding window %p to new group %p\n",
02527                  (void *)mShell, (void *)mWindowGroup));
02528             gtk_window_group_add_window(mWindowGroup, GTK_WINDOW(mShell));
02529         }
02530 
02531         // create our container
02532         mContainer = MOZ_CONTAINER(moz_container_new());
02533         gtk_container_add(GTK_CONTAINER(mShell), GTK_WIDGET(mContainer));
02534         gtk_widget_realize(GTK_WIDGET(mContainer));
02535 
02536         // make sure this is the focus widget in the container
02537         gtk_window_set_focus(GTK_WINDOW(mShell), GTK_WIDGET(mContainer));
02538 
02539         // and the drawing area
02540         mDrawingarea = moz_drawingarea_new(nsnull, mContainer);
02541 
02542         if (mWindowType == eWindowType_popup) {
02543             // gdk does not automatically set the cursor for "temporary"
02544             // windows, which are what gtk uses for popups.
02545 
02546             mCursor = eCursor_wait; // force SetCursor to actually set the
02547                                     // cursor, even though our internal state
02548                                     // indicates that we already have the
02549                                     // standard cursor.
02550             SetCursor(eCursor_standard);
02551         }
02552     }
02553         break;
02554     case eWindowType_child: {
02555         if (parentMozContainer) {
02556             mDrawingarea = moz_drawingarea_new(parentArea, parentMozContainer);
02557         }
02558         else if (parentGtkContainer) {
02559             mContainer = MOZ_CONTAINER(moz_container_new());
02560             gtk_container_add(parentGtkContainer, GTK_WIDGET(mContainer));
02561             gtk_widget_realize(GTK_WIDGET(mContainer));
02562 
02563             mDrawingarea = moz_drawingarea_new(nsnull, mContainer);
02564         }
02565         else {
02566             NS_WARNING("Warning: tried to create a new child widget with no parent!");
02567             return NS_ERROR_FAILURE;
02568         }
02569     }
02570         break;
02571     default:
02572         break;
02573     }
02574     // Disable the double buffer because it will make the caret crazy
02575     // For bug#153805 (Gtk2 double buffer makes carets misbehave)
02576     if (mContainer)
02577         gtk_widget_set_double_buffered (GTK_WIDGET(mContainer),FALSE);
02578 
02579     // label the drawing area with this object so we can find our way
02580     // home
02581     g_object_set_data(G_OBJECT(mDrawingarea->clip_window), "nsWindow",
02582                       this);
02583     g_object_set_data(G_OBJECT(mDrawingarea->inner_window), "nsWindow",
02584                       this);
02585 
02586     g_object_set_data(G_OBJECT(mDrawingarea->clip_window), "mozdrawingarea",
02587                       mDrawingarea);
02588     g_object_set_data(G_OBJECT(mDrawingarea->inner_window), "mozdrawingarea",
02589                       mDrawingarea);
02590 
02591     if (mContainer)
02592         g_object_set_data(G_OBJECT(mContainer), "nsWindow", this);
02593 
02594     if (mShell)
02595         g_object_set_data(G_OBJECT(mShell), "nsWindow", this);
02596 
02597     // attach listeners for events
02598     if (mShell) {
02599         g_signal_connect(G_OBJECT(mShell), "configure_event",
02600                          G_CALLBACK(configure_event_cb), NULL);
02601         g_signal_connect(G_OBJECT(mShell), "delete_event",
02602                          G_CALLBACK(delete_event_cb), NULL);
02603         g_signal_connect(G_OBJECT(mShell), "window_state_event",
02604                          G_CALLBACK(window_state_event_cb), NULL);
02605 
02606         GtkSettings* default_settings = gtk_settings_get_default();
02607         g_signal_connect_after(default_settings,
02608                                "notify::gtk-theme-name",
02609                                G_CALLBACK(theme_changed_cb), this);
02610         g_signal_connect_after(default_settings,
02611                                "notify::gtk-font-name",
02612                                G_CALLBACK(theme_changed_cb), this);
02613     }
02614 
02615     if (mContainer) {
02616         g_signal_connect_after(G_OBJECT(mContainer), "size_allocate",
02617                                G_CALLBACK(size_allocate_cb), NULL);
02618         g_signal_connect(G_OBJECT(mContainer), "expose_event",
02619                          G_CALLBACK(expose_event_cb), NULL);
02620         g_signal_connect(G_OBJECT(mContainer), "enter_notify_event",
02621                          G_CALLBACK(enter_notify_event_cb), NULL);
02622         g_signal_connect(G_OBJECT(mContainer), "leave_notify_event",
02623                          G_CALLBACK(leave_notify_event_cb), NULL);
02624         g_signal_connect(G_OBJECT(mContainer), "motion_notify_event",
02625                          G_CALLBACK(motion_notify_event_cb), NULL);
02626         g_signal_connect(G_OBJECT(mContainer), "button_press_event",
02627                          G_CALLBACK(button_press_event_cb), NULL);
02628         g_signal_connect(G_OBJECT(mContainer), "button_release_event",
02629                          G_CALLBACK(button_release_event_cb), NULL);
02630         g_signal_connect(G_OBJECT(mContainer), "focus_in_event",
02631                          G_CALLBACK(focus_in_event_cb), NULL);
02632         g_signal_connect(G_OBJECT(mContainer), "focus_out_event",
02633                          G_CALLBACK(focus_out_event_cb), NULL);
02634         g_signal_connect(G_OBJECT(mContainer), "key_press_event",
02635                          G_CALLBACK(key_press_event_cb), NULL);
02636         g_signal_connect(G_OBJECT(mContainer), "key_release_event",
02637                          G_CALLBACK(key_release_event_cb), NULL);
02638         g_signal_connect(G_OBJECT(mContainer), "scroll_event",
02639                          G_CALLBACK(scroll_event_cb), NULL);
02640         g_signal_connect(G_OBJECT(mContainer), "visibility_notify_event",
02641                          G_CALLBACK(visibility_notify_event_cb), NULL);
02642 
02643         gtk_drag_dest_set((GtkWidget *)mContainer,
02644                           (GtkDestDefaults)0,
02645                           NULL,
02646                           0,
02647                           (GdkDragAction)0);
02648 
02649         g_signal_connect(G_OBJECT(mContainer), "drag_motion",
02650                          G_CALLBACK(drag_motion_event_cb), NULL);
02651         g_signal_connect(G_OBJECT(mContainer), "drag_leave",
02652                          G_CALLBACK(drag_leave_event_cb), NULL);
02653         g_signal_connect(G_OBJECT(mContainer), "drag_drop",
02654                          G_CALLBACK(drag_drop_event_cb), NULL);
02655         g_signal_connect(G_OBJECT(mContainer), "drag_data_received",
02656                          G_CALLBACK(drag_data_received_event_cb), NULL);
02657 
02658 #ifdef USE_XIM
02659         // We create input contexts for all containers, except for
02660         // toplevel popup windows
02661         if (mWindowType != eWindowType_popup)
02662             IMECreateContext();
02663 #endif
02664     }
02665 
02666     LOG(("nsWindow [%p]\n", (void *)this));
02667     if (mShell) {
02668         LOG(("\tmShell %p %p %lx\n", (void *)mShell, (void *)mShell->window,
02669              GDK_WINDOW_XWINDOW(mShell->window)));
02670     }
02671 
02672     if (mContainer) {
02673         LOG(("\tmContainer %p %p %lx\n", (void *)mContainer,
02674              (void *)GTK_WIDGET(mContainer)->window,
02675              GDK_WINDOW_XWINDOW(GTK_WIDGET(mContainer)->window)));
02676     }
02677 
02678     if (mDrawingarea) {
02679         LOG(("\tmDrawingarea %p %p %p %lx %lx\n", (void *)mDrawingarea,
02680              (void *)mDrawingarea->clip_window,
02681              (void *)mDrawingarea->inner_window,
02682              GDK_WINDOW_XWINDOW(mDrawingarea->clip_window),
02683              GDK_WINDOW_XWINDOW(mDrawingarea->inner_window)));
02684     }
02685 
02686     // resize so that everything is set to the right dimensions
02687     Resize(mBounds.width, mBounds.height, PR_FALSE);
02688 
02689 #ifdef ACCESSIBILITY
02690     nsresult rv;
02691     if (!sAccessibilityChecked) {
02692         sAccessibilityChecked = PR_TRUE;
02693 
02694         //check if accessibility enabled/disabled by environment variable
02695         const char *envValue = PR_GetEnv(sAccEnv);
02696         if (envValue) {
02697             sAccessibilityEnabled = atoi(envValue);
02698             LOG(("Accessibility Env %s=%s\n", sAccEnv, envValue));
02699         }
02700         //check gconf-2 setting
02701         else {
02702             nsCOMPtr<nsIPrefBranch> sysPrefService =
02703                 do_GetService(sSysPrefService, &rv);
02704             if (NS_SUCCEEDED(rv) && sysPrefService) {
02705 
02706                 // do the work to get gconf setting.
02707                 // will be done soon later.
02708                 sysPrefService->GetBoolPref(sAccessibilityKey,
02709                                             &sAccessibilityEnabled);
02710             }
02711 
02712         }
02713     }
02714     if (sAccessibilityEnabled) {
02715         LOG(("nsWindow:: Create Toplevel Accessibility\n"));
02716         CreateRootAccessible();
02717     }
02718 #endif
02719 
02720     return NS_OK;
02721 }
02722 
02723 void
02724 nsWindow::NativeResize(PRInt32 aWidth, PRInt32 aHeight, PRBool  aRepaint)
02725 {
02726     LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
02727          aWidth, aHeight));
02728 
02729     ResizeTransparencyBitmap(aWidth, aHeight);
02730 
02731     // clear our resize flag
02732     mNeedsResize = PR_FALSE;
02733 
02734     if (mIsTopLevel) {
02735         gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
02736     }
02737     else if (mContainer) {
02738         GtkAllocation allocation;
02739         allocation.x = 0;
02740         allocation.y = 0;
02741         allocation.width = aWidth;
02742         allocation.height = aHeight;
02743         gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
02744     }
02745 
02746     moz_drawingarea_resize (mDrawingarea, aWidth, aHeight);
02747 }
02748 
02749 void
02750 nsWindow::NativeResize(PRInt32 aX, PRInt32 aY,
02751                        PRInt32 aWidth, PRInt32 aHeight,
02752                        PRBool  aRepaint)
02753 {
02754     mNeedsResize = PR_FALSE;
02755     mNeedsMove = PR_FALSE;
02756 
02757     LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
02758          aX, aY, aWidth, aHeight));
02759 
02760     ResizeTransparencyBitmap(aWidth, aHeight);
02761 
02762     if (mIsTopLevel) {
02763         if (mParent && mWindowType == eWindowType_popup) {
02764             nsRect oldrect, newrect;
02765             oldrect.x = aX;
02766             oldrect.y = aY;
02767             mParent->WidgetToScreen(oldrect, newrect);
02768             moz_drawingarea_resize(mDrawingarea, aWidth, aHeight);
02769             gtk_window_move(GTK_WINDOW(mShell), newrect.x, newrect.y);
02770             gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
02771         }
02772         else {
02773             // We only move the toplevel window if someone has
02774             // actually placed the window somewhere.  If no placement
02775             // has taken place, we just let the window manager Do The
02776             // Right Thing.
02777             if (mPlaced)
02778                 gtk_window_move(GTK_WINDOW(mShell), aX, aY);
02779 
02780             gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
02781             moz_drawingarea_resize(mDrawingarea, aWidth, aHeight);
02782         }
02783     }
02784     else if (mContainer) {
02785         GtkAllocation allocation;
02786         allocation.x = 0;
02787         allocation.y = 0;
02788         allocation.width = aWidth;
02789         allocation.height = aHeight;
02790         gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
02791         moz_drawingarea_move_resize(mDrawingarea, aX, aY, aWidth, aHeight);
02792     }
02793     else if (mDrawingarea) {
02794         moz_drawingarea_move_resize(mDrawingarea, aX, aY, aWidth, aHeight);
02795     }
02796 }
02797 
02798 void
02799 nsWindow::NativeShow (PRBool  aAction)
02800 {
02801     if (aAction) {
02802         // GTK wants us to set the window mask before we show the window
02803         // for the first time, or setting the mask later won't work.
02804         // GTK also wants us to NOT set the window mask if we're not really
02805         // going to need it, because GTK won't let us unset the mask properly
02806         // later.
02807         // So, we delay setting the mask until the last moment: when the window
02808         // is shown.
02809         // XXX that may or may not be true for GTK+ 2.x
02810         if (mTransparencyBitmap) {
02811           ApplyTransparencyBitmap();
02812         }
02813 
02814         // unset our flag now that our window has been shown
02815         mNeedsShow = PR_FALSE;
02816 
02817         if (mIsTopLevel) {
02818             moz_drawingarea_set_visibility(mDrawingarea, aAction);
02819             gtk_widget_show(GTK_WIDGET(mContainer));
02820             gtk_widget_show(mShell);
02821         }
02822         else if (mContainer) {
02823             moz_drawingarea_set_visibility(mDrawingarea, TRUE);
02824             gtk_widget_show(GTK_WIDGET(mContainer));
02825         }
02826         else if (mDrawingarea) {
02827             moz_drawingarea_set_visibility(mDrawingarea, TRUE);
02828         }
02829     }
02830     else {
02831         if (mIsTopLevel) {
02832             gtk_widget_hide(GTK_WIDGET(mShell));
02833             gtk_widget_hide(GTK_WIDGET(mContainer));
02834         }
02835         else if (mContainer) {
02836             gtk_widget_hide(GTK_WIDGET(mContainer));
02837             moz_drawingarea_set_visibility(mDrawingarea, FALSE);
02838         }
02839         if (mDrawingarea) {
02840             moz_drawingarea_set_visibility(mDrawingarea, FALSE);
02841         }
02842     }
02843 }
02844 
02845 void
02846 nsWindow::EnsureGrabs(void)
02847 {
02848     if (mRetryPointerGrab)
02849         GrabPointer();
02850     if (mRetryKeyboardGrab)
02851         GrabKeyboard();
02852 }
02853 
02854 #ifndef MOZ_XUL
02855 void
02856 nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight)
02857 {
02858 }
02859 
02860 void
02861 nsWindow::ApplyTransparencyBitmap()
02862 {
02863 }
02864 #else
02865 NS_IMETHODIMP
02866 nsWindow::SetWindowTranslucency(PRBool aTranslucent)
02867 {
02868     if (!mShell) {
02869         // Pass the request to the toplevel window
02870         GtkWidget *topWidget = nsnull;
02871         GetToplevelWidget(&topWidget);
02872         if (!topWidget)
02873             return NS_ERROR_FAILURE;
02874 
02875         nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
02876         if (!topWindow)
02877             return NS_ERROR_FAILURE;
02878 
02879         return topWindow->SetWindowTranslucency(aTranslucent);
02880     }
02881 
02882     if (mIsTranslucent == aTranslucent)
02883         return NS_OK;
02884 
02885     if (!aTranslucent) {
02886         if (mTransparencyBitmap) {
02887             delete[] mTransparencyBitmap;
02888             mTransparencyBitmap = nsnull;
02889             gtk_widget_reset_shapes(mShell);
02890         }
02891     } // else the new default alpha values are "all 1", so we don't
02892     // need to change anything yet
02893 
02894     mIsTranslucent = aTranslucent;
02895     return NS_OK;
02896 }
02897 
02898 NS_IMETHODIMP
02899 nsWindow::GetWindowTranslucency(PRBool& aTranslucent)
02900 {
02901     if (!mShell) {
02902         // Pass the request to the toplevel window
02903         GtkWidget *topWidget = nsnull;
02904         GetToplevelWidget(&topWidget);
02905         if (!topWidget) {
02906             aTranslucent = PR_FALSE;
02907             return NS_ERROR_FAILURE;
02908         }
02909 
02910         nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
02911         if (!topWindow) {
02912             aTranslucent = PR_FALSE;
02913             return NS_ERROR_FAILURE;
02914         }
02915 
02916         return topWindow->GetWindowTranslucency(aTranslucent);
02917     }
02918 
02919     aTranslucent = mIsTranslucent;
02920     return NS_OK;
02921 }
02922 
02923 void
02924 nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight)
02925 {
02926     if (!mTransparencyBitmap)
02927         return;
02928 
02929     if (aNewWidth == mBounds.width && aNewHeight == mBounds.height)
02930         return;
02931 
02932     PRInt32 newSize = ((aNewWidth+7)/8)*aNewHeight;
02933     gchar* newBits = new gchar[newSize];
02934     if (!newBits) {
02935         delete[] mTransparencyBitmap;
02936         mTransparencyBitmap = nsnull;
02937         return;
02938     }
02939     // fill new mask with "opaque", first
02940     memset(newBits, 255, newSize);
02941 
02942     // Now copy the intersection of the old and new areas into the new mask
02943     PRInt32 copyWidth = PR_MIN(aNewWidth, mBounds.width);
02944     PRInt32 copyHeight = PR_MIN(aNewHeight, mBounds.height);
02945     PRInt32 oldRowBytes = (mBounds.width+7)/8;
02946     PRInt32 newRowBytes = (aNewWidth+7)/8;
02947     PRInt32 copyBytes = (copyWidth+7)/8;
02948 
02949     PRInt32 i;
02950     gchar* fromPtr = mTransparencyBitmap;
02951     gchar* toPtr = newBits;
02952     for (i = 0; i < copyHeight; i++) {
02953         memcpy(toPtr, fromPtr, copyBytes);
02954         fromPtr += oldRowBytes;
02955         toPtr += newRowBytes;
02956     }
02957 
02958     delete[] mTransparencyBitmap;
02959     mTransparencyBitmap = newBits;
02960 }
02961 
02962 static PRBool
02963 ChangedMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
02964         const nsRect& aRect, PRUint8* aAlphas)
02965 {
02966     PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
02967     PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8;
02968     for (y = aRect.y; y < yMax; y++) {
02969         gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
02970         for (x = aRect.x; x < xMax; x++) {
02971             PRBool newBit = *aAlphas > 0;
02972             aAlphas++;
02973 
02974             gchar maskByte = maskBytes[x >> 3];
02975             PRBool maskBit = (maskByte & (1 << (x & 7))) != 0;
02976 
02977             if (maskBit != newBit) {
02978                 return PR_TRUE;
02979             }
02980         }
02981     }
02982 
02983     return PR_FALSE;
02984 }
02985 
02986 static
02987 void UpdateMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
02988         const nsRect& aRect, PRUint8* aAlphas)
02989 {
02990     PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
02991     PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8;
02992     for (y = aRect.y; y < yMax; y++) {
02993         gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
02994         for (x = aRect.x; x < xMax; x++) {
02995             PRBool newBit = *aAlphas > 0;
02996             aAlphas++;
02997 
02998             gchar mask = 1 << (x & 7);
02999             gchar maskByte = maskBytes[x >> 3];
03000             // Note: '-newBit' turns 0 into 00...00 and 1 into 11...11
03001             maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask);
03002         }
03003     }
03004 }
03005 
03006 void
03007 nsWindow::ApplyTransparencyBitmap()
03008 {
03009     gtk_widget_reset_shapes(mShell);
03010     GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(mShell->window,
03011             mTransparencyBitmap,
03012             mBounds.width, mBounds.height);
03013     if (!maskBitmap)
03014         return;
03015 
03016     gtk_widget_shape_combine_mask(mShell, maskBitmap, 0, 0);
03017     gdk_bitmap_unref(maskBitmap);
03018 }
03019 
03020 NS_IMETHODIMP
03021 nsWindow::UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas)
03022 {
03023     if (!mShell) {
03024         // Pass the request to the toplevel window
03025         GtkWidget *topWidget = nsnull;
03026         GetToplevelWidget(&topWidget);
03027         if (!topWidget)
03028             return NS_ERROR_FAILURE;
03029 
03030         nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
03031         if (!topWindow)
03032             return NS_ERROR_FAILURE;
03033 
03034         return topWindow->UpdateTranslucentWindowAlpha(aRect, aAlphas);
03035     }
03036 
03037     NS_ASSERTION(mIsTranslucent, "Window is not transparent");
03038 
03039     if (mTransparencyBitmap == nsnull) {
03040         PRInt32 size = ((mBounds.width+7)/8)*mBounds.height;
03041         mTransparencyBitmap = new gchar[size];
03042         if (mTransparencyBitmap == nsnull)
03043             return NS_ERROR_FAILURE;
03044         memset(mTransparencyBitmap, 255, size);
03045     }
03046 
03047     NS_ASSERTION(aRect.x >= 0 && aRect.y >= 0
03048             && aRect.XMost() <= mBounds.width && aRect.YMost() <= mBounds.height,
03049             "Rect is out of window bounds");
03050 
03051     if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, aRect, aAlphas))
03052         // skip the expensive stuff if the mask bits haven't changed; hopefully
03053         // this is the common case
03054         return NS_OK;
03055 
03056     UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, aRect, aAlphas);
03057 
03058     if (!mNeedsShow) {
03059         ApplyTransparencyBitmap();
03060     }
03061 
03062     return NS_OK;
03063 }
03064 #endif
03065 
03066 void
03067 nsWindow::GrabPointer(void)
03068 {
03069     LOG(("GrabPointer %d\n", mRetryPointerGrab));
03070 
03071     mRetryPointerGrab = PR_FALSE;
03072 
03073     // If the window isn't visible, just set the flag to retry the
03074     // grab.  When this window becomes visible, the grab will be
03075     // retried.
03076     PRBool visibility = PR_TRUE;
03077     IsVisible(visibility);
03078     if (!visibility) {
03079         LOG(("GrabPointer: window not visible\n"));
03080         mRetryPointerGrab = PR_TRUE;
03081         return;
03082     }
03083 
03084     if (!mDrawingarea)
03085         return;
03086 
03087     gint retval;
03088     retval = gdk_pointer_grab(mDrawingarea->inner_window, TRUE,
03089                               (GdkEventMask)(GDK_BUTTON_PRESS_MASK |
03090                                              GDK_BUTTON_RELEASE_MASK |
03091                                              GDK_ENTER_NOTIFY_MASK |
03092                                              GDK_LEAVE_NOTIFY_MASK |
03093                                              GDK_POINTER_MOTION_MASK),
03094                               (GdkWindow *)NULL, NULL, GDK_CURRENT_TIME);
03095 
03096     if (retval != GDK_GRAB_SUCCESS) {
03097         LOG(("GrabPointer: pointer grab failed\n"));
03098         mRetryPointerGrab = PR_TRUE;
03099     }
03100 }
03101 
03102 void
03103 nsWindow::GrabKeyboard(void)
03104 {
03105     LOG(("GrabKeyboard %d\n", mRetryKeyboardGrab));
03106 
03107     mRetryKeyboardGrab = PR_FALSE;
03108 
03109     // If the window isn't visible, just set the flag to retry the
03110     // grab.  When this window becomes visible, the grab will be
03111     // retried.
03112     PRBool visibility = PR_TRUE;
03113     IsVisible(visibility);
03114     if (!visibility) {
03115         LOG(("GrabKeyboard: window not visible\n"));
03116         mRetryKeyboardGrab = PR_TRUE;
03117         return;
03118     }
03119 
03120     // we need to grab the keyboard on the transient parent so that we
03121     // don't end up with any focus events that end up on the parent
03122     // window that will cause the popup to go away
03123     GdkWindow *grabWindow;
03124 
03125     if (mTransientParent)
03126         grabWindow = GTK_WIDGET(mTransientParent)->window;
03127     else if (mDrawingarea)
03128         grabWindow = mDrawingarea->inner_window;
03129     else
03130         return;
03131 
03132     gint retval;
03133     retval = gdk_keyboard_grab(grabWindow, TRUE, GDK_CURRENT_TIME);
03134 
03135     if (retval != GDK_GRAB_SUCCESS) {
03136         LOG(("GrabKeyboard: keyboard grab failed %d\n", retval));
03137         gdk_pointer_ungrab(GDK_CURRENT_TIME);
03138         mRetryKeyboardGrab = PR_TRUE;
03139     }
03140 }
03141 
03142 void
03143 nsWindow::ReleaseGrabs(void)
03144 {
03145     LOG(("ReleaseGrabs\n"));
03146 
03147     mRetryPointerGrab = PR_FALSE;
03148     mRetryKeyboardGrab = PR_FALSE;
03149 
03150     gdk_pointer_ungrab(GDK_CURRENT_TIME);
03151     gdk_keyboard_ungrab(GDK_CURRENT_TIME);
03152 }
03153 
03154 void
03155 nsWindow::GetToplevelWidget(GtkWidget **aWidget)
03156 {
03157     *aWidget = nsnull;
03158 
03159     if (mShell) {
03160         *aWidget = mShell;
03161         return;
03162     }
03163 
03164     if (!mDrawingarea)
03165         return;
03166 
03167     GtkWidget *widget =
03168         get_gtk_widget_for_gdk_window(mDrawingarea->inner_window);
03169     if (!widget)
03170         return;
03171 
03172     *aWidget = gtk_widget_get_toplevel(widget);
03173 }
03174 
03175 void
03176 nsWindow::GetContainerWindow(nsWindow **aWindow)
03177 {
03178     if (!mDrawingarea)
03179         return;
03180 
03181     GtkWidget *owningWidget =
03182         get_gtk_widget_for_gdk_window(mDrawingarea->inner_window);
03183 
03184     *aWindow = get_window_for_gtk_widget(owningWidget);
03185 }
03186 
03187 void
03188 nsWindow::SetUrgencyHint(GtkWidget *top_window, PRBool state)
03189 {
03190     if (!top_window)
03191         return;
03192 
03193     // Try to get a pointer to gdk_window_set_urgency_hint
03194     PRLibrary* lib;
03195     _gdk_window_set_urgency_hint_fn _gdk_window_set_urgency_hint = nsnull;
03196     _gdk_window_set_urgency_hint = (_gdk_window_set_urgency_hint_fn)
03197            PR_FindFunctionSymbolAndLibrary("gdk_window_set_urgency_hint", &lib);
03198 
03199     if (_gdk_window_set_urgency_hint) {
03200         _gdk_window_set_urgency_hint(top_window->window, state);
03201         PR_UnloadLibrary(lib);
03202     }
03203     else if (state) {
03204         gdk_window_show(top_window->window);
03205     }
03206 }
03207 
03208 void *
03209 nsWindow::SetupPluginPort(void)
03210 {
03211     if (!mDrawingarea)
03212         return nsnull;
03213 
03214     if (GDK_WINDOW_OBJECT(mDrawingarea->inner_window)->destroyed == TRUE)
03215         return nsnull;
03216 
03217     // we have to flush the X queue here so that any plugins that
03218     // might be running on separate X connections will be able to use
03219     // this window in case it was just created
03220     XWindowAttributes xattrs;
03221     XGetWindowAttributes(GDK_DISPLAY (),
03222                          GDK_WINDOW_XWINDOW(mDrawingarea->inner_window),
03223                          &xattrs);
03224     XSelectInput (GDK_DISPLAY (),
03225                   GDK_WINDOW_XWINDOW(mDrawingarea->inner_window),
03226                   xattrs.your_event_mask |
03227                   SubstructureNotifyMask);
03228 
03229     gdk_window_add_filter(mDrawingarea->inner_window,
03230                           plugin_window_filter_func,
03231                           this);
03232 
03233     XSync(GDK_DISPLAY(), False);
03234 
03235     return (void *)GDK_WINDOW_XWINDOW(mDrawingarea->inner_window);
03236 }
03237 
03238 nsresult
03239 nsWindow::SetWindowIconList(const nsCStringArray &aIconList)
03240 {
03241     GList *list = NULL;
03242 
03243     for (int i = 0; i < aIconList.Count(); ++i) {
03244         const char *path = aIconList[i]->get();
03245         LOG(("window [%p] Loading icon from %s\n", (void *)this, path));
03246 
03247         GdkPixbuf *icon = gdk_pixbuf_new_from_file(path, NULL);
03248         if (!icon)
03249             continue;
03250 
03251         list = g_list_append(list, icon);
03252     }
03253 
03254     if (!list)
03255         return NS_ERROR_FAILURE;
03256 
03257     gtk_window_set_icon_list(GTK_WINDOW(mShell), list);
03258 
03259     g_list_foreach(list, (GFunc) g_object_unref, NULL);
03260     g_list_free(list);
03261 
03262     return NS_OK;
03263 }
03264 
03265 void
03266 nsWindow::SetDefaultIcon(void)
03267 {
03268     // Set up the default window icon
03269     nsCOMPtr<nsILocalFile> iconFile;
03270     ResolveIconName(NS_LITERAL_STRING("default"),
03271                     NS_LITERAL_STRING(".xpm"),
03272                     getter_AddRefs(iconFile));
03273     if (!iconFile) {
03274         NS_WARNING("default.xpm not found");
03275         return;
03276     }
03277 
03278     nsCAutoString path;
03279     iconFile->GetNativePath(path);
03280 
03281     nsCStringArray iconList;
03282     iconList.AppendCString(path);
03283 
03284     SetWindowIconList(iconList);
03285 }
03286 
03287 void
03288 nsWindow::SetPluginType(PluginType aPluginType)
03289 {
03290     mPluginType = aPluginType;
03291 }
03292 
03293 void
03294 nsWindow::SetNonXEmbedPluginFocus()
03295 {
03296     if (gPluginFocusWindow == this || mPluginType!=PluginType_NONXEMBED) {
03297         return;
03298     }
03299 
03300     if (gPluginFocusWindow) {
03301         gPluginFocusWindow->LoseNonXEmbedPluginFocus();
03302     }
03303 
03304     LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus\n"));
03305 
03306     Window curFocusWindow;
03307     int focusState;
03308 
03309     XGetInputFocus(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
03310                    &curFocusWindow,
03311                    &focusState);
03312 
03313     LOGFOCUS(("\t curFocusWindow=%p\n", curFocusWindow));
03314 
03315     GdkWindow* toplevel = gdk_window_get_toplevel
03316                                 (mDrawingarea->inner_window);
03317     GdkWindow *gdkfocuswin = gdk_window_lookup(curFocusWindow);
03318 
03319     // lookup with the focus proxy window is supposed to get the
03320     // same GdkWindow as toplevel. If the current focused window
03321     // is not the focus proxy, we return without any change.
03322     if (gdkfocuswin != toplevel) {
03323         return;
03324     }
03325 
03326     // switch the focus from the focus proxy to the plugin window
03327     mOldFocusWindow = curFocusWindow;
03328     XRaiseWindow(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
03329                  GDK_WINDOW_XWINDOW(mDrawingarea->inner_window));
03330     gdk_error_trap_push();
03331     XSetInputFocus(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
03332                    GDK_WINDOW_XWINDOW(mDrawingarea->inner_window),
03333                    RevertToNone,
03334                    CurrentTime);
03335     gdk_flush();
03336     gdk_error_trap_pop();
03337     gPluginFocusWindow = this;
03338     gdk_window_add_filter(NULL, plugin_client_message_filter, this);
03339 
03340     LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus oldfocus=%p new=%p\n",
03341                 mOldFocusWindow,
03342                 GDK_WINDOW_XWINDOW(mDrawingarea->inner_window)));
03343 }
03344 
03345 void
03346 nsWindow::LoseNonXEmbedPluginFocus()
03347 {
03348     LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus\n"));
03349 
03350     // This method is only for the nsWindow which contains a
03351     // Non-XEmbed plugin, for example, JAVA plugin.
03352     if (gPluginFocusWindow != this || mPluginType!=PluginType_NONXEMBED) {
03353         return;
03354     }
03355 
03356     Window curFocusWindow;
03357     int focusState;
03358 
03359     XGetInputFocus(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
03360                    &curFocusWindow,
03361                    &focusState);
03362 
03363     // we only switch focus between plugin window and focus proxy. If the
03364     // current focused window is not the plugin window, just removing the
03365     // event filter that blocks the WM_TAKE_FOCUS is enough. WM and gtk2
03366     // will take care of the focus later.
03367     if (!curFocusWindow ||
03368         curFocusWindow == GDK_WINDOW_XWINDOW(mDrawingarea->inner_window)) {
03369 
03370         gdk_error_trap_push();
03371         XRaiseWindow(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
03372                      mOldFocusWindow);
03373         XSetInputFocus(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
03374                        mOldFocusWindow,
03375                        RevertToParent,
03376                        CurrentTime);
03377         gdk_flush();
03378         gdk_error_trap_pop();
03379     }
03380     gPluginFocusWindow = NULL;
03381     mOldFocusWindow = 0;
03382     gdk_window_remove_filter(NULL, plugin_client_message_filter, this);
03383 
03384     LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus end\n"));
03385 }
03386 
03387 
03388 gint
03389 nsWindow::ConvertBorderStyles(nsBorderStyle aStyle)
03390 {
03391     gint w = 0;
03392 
03393     if (aStyle == eBorderStyle_default)
03394         return -1;
03395 
03396     if (aStyle & eBorderStyle_all)
03397         w |= GDK_DECOR_ALL;
03398     if (aStyle & eBorderStyle_border)
03399         w |= GDK_DECOR_BORDER;
03400     if (aStyle & eBorderStyle_resizeh)
03401         w |= GDK_DECOR_RESIZEH;
03402     if (aStyle & eBorderStyle_title)
03403         w |= GDK_DECOR_TITLE;
03404     if (aStyle & eBorderStyle_menu)
03405         w |= GDK_DECOR_MENU;
03406     if (aStyle & eBorderStyle_minimize)
03407         w |= GDK_DECOR_MINIMIZE;
03408     if (aStyle & eBorderStyle_maximize)
03409         w |= GDK_DECOR_MAXIMIZE;
03410     if (aStyle & eBorderStyle_close) {
03411 #ifdef DEBUG
03412         printf("we don't handle eBorderStyle_close yet... please fix me\n");
03413 #endif /* DEBUG */
03414     }
03415 
03416     return w;
03417 }
03418 
03419 NS_IMETHODIMP
03420 nsWindow::MakeFullScreen(PRBool aFullScreen)
03421 {
03422 #if GTK_CHECK_VERSION(2,2,0)
03423     if (aFullScreen)
03424         gdk_window_fullscreen (mShell->window);
03425     else
03426         gdk_window_unfullscreen (mShell->window);
03427 #else
03428     HideWindowChrome(aFullScreen);
03429 #endif
03430     return MakeFullScreenInternal(aFullScreen);
03431 }
03432 
03433 NS_IMETHODIMP
03434 nsWindow::HideWindowChrome(PRBool aShouldHide)
03435 {
03436     if (!mShell) {
03437         // Pass the request to the toplevel window
03438         GtkWidget *topWidget = nsnull;
03439         GetToplevelWidget(&topWidget);
03440         nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
03441         return topWindow->HideWindowChrome(aShouldHide);
03442     }
03443 
03444     // Sawfish, metacity, and presumably other window managers get
03445     // confused if we change the window decorations while the window
03446     // is visible.
03447     gdk_window_hide(mShell->window);
03448 
03449     gint wmd;
03450     if (aShouldHide)
03451         wmd = 0;
03452     else
03453         wmd = ConvertBorderStyles(mBorderStyle);
03454 
03455     gdk_window_set_decorations(mShell->window, (GdkWMDecoration) wmd);
03456 
03457     gdk_window_show(mShell->window);
03458 
03459     // For some window managers, adding or removing window decorations
03460     // requires unmapping and remapping our toplevel window.  Go ahead
03461     // and flush the queue here so that we don't end up with a BadWindow
03462     // error later when this happens (when the persistence timer fires
03463     // and GetWindowPos is called)
03464     XSync(GDK_DISPLAY(), False);
03465 
03466     return NS_OK;
03467 }
03468 
03469 PRBool
03470 check_for_rollup(GdkWindow *aWindow, gdouble aMouseX, gdouble aMouseY,
03471                  PRBool aIsWheel)
03472 {
03473     PRBool retVal = PR_FALSE;
03474     nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
03475 
03476     if (rollupWidget && gRollupListener) {
03477         GdkWindow *currentPopup =
03478             (GdkWindow *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
03479         if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
03480             PRBool rollup = PR_TRUE;
03481             if (aIsWheel) {
03482                 gRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
03483                 retVal = PR_TRUE;
03484             }
03485             // if we're dealing with menus, we probably have submenus and
03486             // we don't want to rollup if the clickis in a parent menu of
03487             // the current submenu
03488             nsCOMPtr<nsIMenuRollup> menuRollup;
03489             menuRollup = (do_QueryInterface(gRollupListener));
03490             if (menuRollup) {
03491                 nsCOMPtr<nsISupportsArray> widgetChain;
03492                 menuRollup->GetSubmenuWidgetChain(getter_AddRefs(widgetChain));
03493                 if (widgetChain) {
03494                     PRUint32 count = 0;
03495                     widgetChain->Count(&count);
03496                     for (PRUint32 i=0; i<count; ++i) {
03497                         nsCOMPtr<nsISupports> genericWidget;
03498                         widgetChain->GetElementAt(i,
03499                                                   getter_AddRefs(genericWidget));
03500                         nsCOMPtr<nsIWidget> widget(do_QueryInterface(genericWidget));
03501                         if (widget) {
03502                             GdkWindow* currWindow =
03503                                 (GdkWindow*) widget->GetNativeData(NS_NATIVE_WINDOW);
03504                             if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
03505                                 rollup = PR_FALSE;
03506                                 break;
03507                             }
03508                         }
03509                     } // foreach parent menu widget
03510                 }
03511             } // if rollup listener knows about menus
03512 
03513             // if we've determined that we should still rollup, do it.
03514             if (rollup) {
03515                 gRollupListener->Rollup();
03516                 retVal = PR_TRUE;
03517             }
03518         }
03519     } else {
03520         gRollupWindow = nsnull;
03521         gRollupListener = nsnull;
03522     }
03523 
03524     return retVal;
03525 }
03526 
03527 /* static */
03528 PRBool
03529 nsWindow::DragInProgress(void)
03530 {
03531     // mLastDragMotionWindow means the drag arrow is over mozilla
03532     // sIsDraggingOutOf means the drag arrow is out of mozilla
03533     // both cases mean the dragging is happenning.
03534     return (mLastDragMotionWindow || sIsDraggingOutOf);
03535 }
03536 
03537 /* static */
03538 PRBool
03539 is_mouse_in_window (GdkWindow* aWindow, gdouble aMouseX, gdouble aMouseY)
03540 {
03541     gint x = 0;
03542     gint y = 0;
03543     gint w, h;
03544 
03545     gint offsetX = 0;
03546     gint offsetY = 0;
03547 
03548     GtkWidget *widget;
03549     GdkWindow *window;
03550 
03551     window = aWindow;
03552 
03553     while (window) {
03554         gint tmpX = 0;
03555         gint tmpY = 0;
03556 
03557         gdk_window_get_position(window, &tmpX, &tmpY);
03558         widget = get_gtk_widget_for_gdk_window(window);
03559 
03560         // if this is a window, compute x and y given its origin and our
03561         // offset
03562         if (GTK_IS_WINDOW(widget)) {
03563             x = tmpX + offsetX;
03564             y = tmpY + offsetY;
03565             break;
03566         }
03567 
03568         offsetX += tmpX;
03569         offsetY += tmpY;
03570         window = gdk_window_get_parent(window);
03571     }
03572 
03573     gdk_window_get_size(aWindow, &w, &h);
03574 
03575     if (aMouseX > x && aMouseX < x + w &&
03576         aMouseY > y && aMouseY < y + h)
03577         return PR_TRUE;
03578 
03579     return PR_FALSE;
03580 }
03581 
03582 /* static */
03583 nsWindow *
03584 get_window_for_gtk_widget(GtkWidget *widget)
03585 {
03586     gpointer user_data;
03587     user_data = g_object_get_data(G_OBJECT(widget), "nsWindow");
03588 
03589     if (!user_data)
03590         return nsnull;
03591 
03592     return NS_STATIC_CAST(nsWindow *, user_data);
03593 }
03594 
03595 /* static */
03596 nsWindow *
03597 get_window_for_gdk_window(GdkWindow *window)
03598 {
03599     gpointer user_data;
03600     user_data = g_object_get_data(G_OBJECT(window), "nsWindow");
03601 
03602     if (!user_data)
03603         return nsnull;
03604 
03605     return NS_STATIC_CAST(nsWindow *, user_data);
03606 }
03607 
03608 /* static */
03609 nsWindow *
03610 get_owning_window_for_gdk_window(GdkWindow *window)
03611 {
03612     GtkWidget *owningWidget = get_gtk_widget_for_gdk_window(window);
03613     if (!owningWidget)
03614         return nsnull;
03615 
03616     gpointer user_data;
03617     user_data = g_object_get_data(G_OBJECT(owningWidget), "nsWindow");
03618 
03619     if (!user_data)
03620         return nsnull;
03621 
03622     return (nsWindow *)user_data;
03623 }
03624 
03625 /* static */
03626 GtkWidget *
03627 get_gtk_widget_for_gdk_window(GdkWindow *window)
03628 {
03629     gpointer user_data = NULL;
03630     gdk_window_get_user_data(window, &user_data);
03631     if (!user_data)
03632         return NULL;
03633 
03634     return GTK_WIDGET(user_data);
03635 }
03636 
03637 /* static */
03638 GdkCursor *
03639 get_gtk_cursor(nsCursor aCursor)
03640 {
03641     GdkPixmap *cursor;
03642     GdkPixmap *mask;
03643     GdkColor fg, bg;
03644     GdkCursor *gdkcursor = nsnull;
03645     PRUint8 newType = 0xff;
03646 
03647     if ((gdkcursor = gCursorCache[aCursor])) {
03648         return gdkcursor;
03649     }
03650 
03651     switch (aCursor) {
03652     case eCursor_standard:
03653         gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
03654         break;
03655     case eCursor_wait:
03656         gdkcursor = gdk_cursor_new(GDK_WATCH);
03657         break;
03658     case eCursor_select:
03659         gdkcursor = gdk_cursor_new(GDK_XTERM);
03660         break;
03661     case eCursor_hyperlink:
03662         gdkcursor = gdk_cursor_new(GDK_HAND2);
03663         break;
03664     case eCursor_n_resize:
03665         gdkcursor = gdk_cursor_new(GDK_TOP_SIDE);
03666         break;
03667     case eCursor_s_resize:
03668         gdkcursor = gdk_cursor_new(GDK_BOTTOM_SIDE);
03669         break;
03670     case eCursor_w_resize:
03671         gdkcursor = gdk_cursor_new(GDK_LEFT_SIDE);
03672         break;
03673     case eCursor_e_resize:
03674         gdkcursor = gdk_cursor_new(GDK_RIGHT_SIDE);
03675         break;
03676     case eCursor_nw_resize:
03677         gdkcursor = gdk_cursor_new(GDK_TOP_LEFT_CORNER);
03678         break;
03679     case eCursor_se_resize:
03680         gdkcursor = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
03681         break;
03682     case eCursor_ne_resize:
03683         gdkcursor = gdk_cursor_new(GDK_TOP_RIGHT_CORNER);
03684         break;
03685     case eCursor_sw_resize:
03686         gdkcursor = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER);
03687         break;
03688     case eCursor_crosshair:
03689         gdkcursor = gdk_cursor_new(GDK_CROSSHAIR);
03690         break;
03691     case eCursor_move:
03692         gdkcursor = gdk_cursor_new(GDK_FLEUR);
03693         break;
03694     case eCursor_help:
03695         newType = MOZ_CURSOR_QUESTION_ARROW;
03696         break;
03697     case eCursor_copy: // CSS3
03698         newType = MOZ_CURSOR_COPY;
03699         break;
03700     case eCursor_alias:
03701         newType = MOZ_CURSOR_ALIAS;
03702         break;
03703     case eCursor_context_menu:
03704         newType = MOZ_CURSOR_CONTEXT_MENU;
03705         break;
03706     case eCursor_cell:
03707         gdkcursor = gdk_cursor_new(GDK_PLUS);
03708         break;
03709     case eCursor_grab:
03710         newType = MOZ_CURSOR_HAND_GRAB;
03711         break;
03712     case eCursor_grabbing:
03713         newType = MOZ_CURSOR_HAND_GRABBING;
03714         break;
03715     case eCursor_spinning:
03716         newType = MOZ_CURSOR_SPINNING;
03717         break;
03718     case eCursor_zoom_in:
03719         newType = MOZ_CURSOR_ZOOM_IN;
03720         break;
03721     case eCursor_zoom_out:
03722         newType = MOZ_CURSOR_ZOOM_OUT;
03723         break;
03724     case eCursor_not_allowed:
03725     case eCursor_no_drop:
03726         newType = MOZ_CURSOR_NOT_ALLOWED;
03727         break;
03728     case eCursor_col_resize:
03729         newType = MOZ_CURSOR_COL_RESIZE;
03730         break;
03731     case eCursor_row_resize:
03732         newType = MOZ_CURSOR_ROW_RESIZE;
03733         break;
03734     case eCursor_vertical_text:
03735         newType = MOZ_CURSOR_VERTICAL_TEXT;
03736         break;
03737     case eCursor_all_scroll:
03738         gdkcursor = gdk_cursor_new(GDK_FLEUR);
03739         break;
03740     case eCursor_nesw_resize:
03741         newType = MOZ_CURSOR_NESW_RESIZE;
03742         break;
03743     case eCursor_nwse_resize:
03744         newType = MOZ_CURSOR_NWSE_RESIZE;
03745         break;
03746     case eCursor_ns_resize:
03747         gdkcursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
03748         break;
03749     case eCursor_ew_resize:
03750         gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
03751         break;
03752     default:
03753         NS_ASSERTION(aCursor, "Invalid cursor type");
03754         gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
03755         break;
03756     }
03757 
03758     // if by now we dont have a xcursor, this means we have to make a
03759     // custom one
03760     if (newType != 0xff) {
03761         gdk_color_parse("#000000", &fg);
03762         gdk_color_parse("#ffffff", &bg);
03763 
03764         cursor = gdk_bitmap_create_from_data(NULL,
03765                                              (char *)GtkCursors[newType].bits,
03766                                              32, 32);
03767         if (!cursor)
03768             return NULL;
03769 
03770         mask =
03771             gdk_bitmap_create_from_data(NULL,
03772                                         (char *)GtkCursors[newType].mask_bits,
03773                                         32, 32);
03774         if (!mask) {
03775             gdk_bitmap_unref(cursor);
03776             return NULL;
03777         }
03778 
03779         gdkcursor = gdk_cursor_new_from_pixmap(cursor, mask, &fg, &bg,
03780                                                GtkCursors[newType].hot_x,
03781                                                GtkCursors[newType].hot_y);
03782 
03783         gdk_bitmap_unref(mask);
03784         gdk_bitmap_unref(cursor);
03785     }
03786 
03787     gCursorCache[aCursor] = gdkcursor;
03788 
03789     return gdkcursor;
03790 }
03791 
03792 // gtk callbacks
03793 
03794 /* static */
03795 gboolean
03796 expose_event_cb(GtkWidget *widget, GdkEventExpose *event)
03797 {
03798     nsWindow *window = get_window_for_gdk_window(event->window);
03799     if (!window)
03800         return FALSE;
03801 
03802     // XXX We are so getting lucky here.  We are doing all of
03803     // mozilla's painting and then allowing default processing to occur.
03804     // This means that Mozilla paints in all of it's stuff and then
03805     // NO_WINDOW widgets (like scrollbars, for example) are painted by
03806     // Gtk on top of what we painted.
03807 
03808     // This return window->OnExposeEvent(widget, event); */
03809 
03810     window->OnExposeEvent(widget, event);
03811     return FALSE;
03812 }
03813 
03814 /* static */
03815 gboolean
03816 configure_event_cb(GtkWidget *widget,
03817                    GdkEventConfigure *event)
03818 {
03819     nsWindow *window = get_window_for_gtk_widget(widget);
03820     if (!window)
03821         return FALSE;
03822 
03823     return window->OnConfigureEvent(widget, event);
03824 }
03825 
03826 /* static */
03827 void
03828 size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation)
03829 {
03830     nsWindow *window = get_window_for_gtk_widget(widget);
03831     if (!window)
03832         return;
03833 
03834     window->OnSizeAllocate(widget, allocation);
03835 }
03836 
03837 /* static */
03838 gboolean
03839 delete_event_cb(GtkWidget *widget, GdkEventAny *event)
03840 {
03841     nsWindow *window = get_window_for_gtk_widget(widget);
03842     if (!window)
03843         return FALSE;
03844 
03845     window->OnDeleteEvent(widget, event);
03846 
03847     return TRUE;
03848 }
03849 
03850 /* static */
03851 gboolean
03852 enter_notify_event_cb (GtkWidget *widget,
03853                        GdkEventCrossing *event)
03854 {
03855     if (is_parent_ungrab_enter(event)) {
03856         return TRUE;
03857     }
03858 
03859     nsWindow *window = get_window_for_gdk_window(event->window);
03860     if (!window)
03861         return TRUE;
03862 
03863     window->OnEnterNotifyEvent(widget, event);
03864 
03865     return TRUE;
03866 }
03867 
03868 /* static */
03869 gboolean
03870 leave_notify_event_cb (GtkWidget *widget,
03871                        GdkEventCrossing *event)
03872 {
03873     if (is_parent_grab_leave(event)) {
03874         return TRUE;
03875     }
03876 
03877     nsWindow *window = get_window_for_gdk_window(event->window);
03878     if (!window)
03879         return TRUE;
03880 
03881     window->OnLeaveNotifyEvent(widget, event);
03882 
03883     return TRUE;
03884 }
03885 
03886 /* static */
03887 gboolean
03888 motion_notify_event_cb (GtkWidget *widget, GdkEventMotion *event)
03889 {
03890     nsWindow *window = get_window_for_gdk_window(event->window);
03891     if (!window)
03892         return TRUE;
03893 
03894     window->OnMotionNotifyEvent(widget, event);
03895 
03896     return TRUE;
03897 }
03898 
03899 /* static */
03900 gboolean
03901 button_press_event_cb   (GtkWidget *widget, GdkEventButton *event)
03902 {
03903     LOG(("button_press_event_cb\n"));
03904     nsWindow *window = get_window_for_gdk_window(event->window);
03905     if (!window)
03906         return TRUE;
03907 
03908     window->OnButtonPressEvent(widget, event);
03909 
03910     return TRUE;
03911 }
03912 
03913 /* static */
03914 gboolean
03915 button_release_event_cb (GtkWidget *widget, GdkEventButton *event)
03916 {
03917     nsWindow *window = get_window_for_gdk_window(event->window);
03918     if (!window)
03919         return TRUE;
03920 
03921     window->OnButtonReleaseEvent(widget, event);
03922 
03923     return TRUE;
03924 }
03925 
03926 /* static */
03927 gboolean
03928 focus_in_event_cb (GtkWidget *widget, GdkEventFocus *event)
03929 {
03930     nsWindow *window = get_window_for_gtk_widget(widget);
03931     if (!window)
03932         return FALSE;
03933 
03934     window->OnContainerFocusInEvent(widget, event);
03935 
03936     return FALSE;
03937 }
03938 
03939 /* static */
03940 gboolean
03941 focus_out_event_cb (GtkWidget *widget, GdkEventFocus *event)
03942 {
03943     nsWindow *window = get_window_for_gtk_widget(widget);
03944     if (!window)
03945         return FALSE;
03946 
03947     window->OnContainerFocusOutEvent(widget, event);
03948 
03949     return FALSE;
03950 }
03951 
03952 /* static */
03953 GdkFilterReturn
03954 plugin_window_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
03955 {
03956     GtkWidget *widget;
03957     GdkWindow *plugin_window;
03958     gpointer  user_data;
03959     XEvent    *xevent;
03960 
03961     nsWindow  *nswindow = (nsWindow*)data;
03962     GdkFilterReturn return_val;
03963 
03964     xevent = (XEvent *)gdk_xevent;
03965     return_val = GDK_FILTER_CONTINUE;
03966 
03967     switch (xevent->type)
03968     {
03969         case CreateNotify:
03970         case ReparentNotify:
03971             if (xevent->type==CreateNotify) {
03972                 plugin_window = gdk_window_lookup(xevent->xcreatewindow.window);
03973             }
03974             else {
03975                 if (xevent->xreparent.event != xevent->xreparent.parent)
03976                     break;
03977                 plugin_window = gdk_window_lookup (xevent->xreparent.window);
03978             }
03979             if (plugin_window) {
03980                 user_data = nsnull;
03981                 gdk_window_get_user_data(plugin_window, &user_data);
03982                 widget = GTK_WIDGET(user_data);
03983 
03984                 if (GTK_IS_XTBIN(widget)) {
03985                     nswindow->SetPluginType(nsWindow::PluginType_NONXEMBED);
03986                     break;
03987                 }
03988                 else if(GTK_IS_SOCKET(widget)) {
03989                     nswindow->SetPluginType(nsWindow::PluginType_XEMBED);
03990                     break;
03991                 }
03992             }
03993             nswindow->SetPluginType(nsWindow::PluginType_NONXEMBED);
03994             return_val = GDK_FILTER_REMOVE;
03995             break;
03996         case EnterNotify:
03997             nswindow->SetNonXEmbedPluginFocus();
03998             break;
03999         case DestroyNotify:
04000             gdk_window_remove_filter
04001                 ((GdkWindow*)(nswindow->GetNativeData(NS_NATIVE_WINDOW)),
04002                  plugin_window_filter_func,
04003                  nswindow);
04004             // Currently we consider all plugins are non-xembed and calls
04005             // LoseNonXEmbedPluginFocus without any checking.
04006             nswindow->LoseNonXEmbedPluginFocus();
04007             break;
04008         default:
04009             break;
04010     }
04011     return return_val;
04012 }
04013 
04014 /* static */
04015 GdkFilterReturn
04016 plugin_client_message_filter (GdkXEvent *gdk_xevent,
04017                               GdkEvent *event,
04018                               gpointer data)
04019 {
04020     XEvent    *xevent;
04021     xevent = (XEvent *)gdk_xevent;
04022 
04023     GdkFilterReturn return_val;
04024     return_val = GDK_FILTER_CONTINUE;
04025 
04026     if (!gPluginFocusWindow || xevent->type!=ClientMessage) {
04027         return return_val;
04028     }
04029 
04030     // When WM sends out WM_TAKE_FOCUS, gtk2 will use XSetInputFocus
04031     // to set the focus to the focus proxy. To prevent this happen
04032     // while the focus is on the plugin, we filter the WM_TAKE_FOCUS
04033     // out.
04034     Display *dpy ;
04035     dpy = GDK_WINDOW_XDISPLAY((GdkWindow*)(gPluginFocusWindow->
04036                 GetNativeData(NS_NATIVE_WINDOW)));
04037     if (gdk_x11_get_xatom_by_name("WM_PROTOCOLS")
04038             != xevent->xclient.message_type) {
04039         return return_val;
04040     }
04041 
04042     if ((Atom) xevent->xclient.data.l[0] ==
04043             gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS")) {
04044         // block it from gtk2.0 focus proxy
04045         return_val = GDK_FILTER_REMOVE;
04046     }
04047 
04048     return return_val;
04049 }
04050 
04051 /* static */
04052 gboolean
04053 key_press_event_cb (GtkWidget *widget, GdkEventKey *event)
04054 {
04055     LOG(("key_press_event_cb\n"));
04056     // find the window with focus and dispatch this event to that widget
04057     nsWindow *window = get_window_for_gtk_widget(widget);
04058     if (!window)
04059         return FALSE;
04060 
04061     nsWindow *focusWindow = gFocusWindow ? gFocusWindow : window;
04062 
04063     return focusWindow->OnKeyPressEvent(widget, event);
04064 }
04065 
04066 gboolean
04067 key_release_event_cb (GtkWidget *widget, GdkEventKey *event)
04068 {
04069     LOG(("key_release_event_cb\n"));
04070     // find the window with focus and dispatch this event to that widget
04071     nsWindow *window = get_window_for_gtk_widget(widget);
04072     if (!window)
04073         return FALSE;
04074 
04075     nsWindow *focusWindow = gFocusWindow ? gFocusWindow : window;
04076 
04077     return focusWindow->OnKeyReleaseEvent(widget, event);
04078 }
04079 
04080 /* static */
04081 gboolean
04082 scroll_event_cb (GtkWidget *widget, GdkEventScroll *event)
04083 {
04084     nsWindow *window = get_window_for_gdk_window(event->window);
04085     if (!window)
04086         return FALSE;
04087 
04088     window->OnScrollEvent(widget, event);
04089 
04090     return TRUE;
04091 }
04092 
04093 /* static */
04094 gboolean
04095 visibility_notify_event_cb (GtkWidget *widget, GdkEventVisibility *event)
04096 {
04097     nsWindow *window = get_window_for_gdk_window(event->window);
04098     if (!window)
04099         return FALSE;
04100 
04101     window->OnVisibilityNotifyEvent(widget, event);
04102 
04103     return TRUE;
04104 }
04105 
04106 /* static */
04107 gboolean
04108 window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event)
04109 {
04110     nsWindow *window = get_window_for_gtk_widget(widget);
04111     if (!window)
04112         return FALSE;
04113 
04114     window->OnWindowStateEvent(widget, event);
04115 
04116     return FALSE;
04117 }
04118 
04119 /* static */
04120 void
04121 theme_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data)
04122 {
04123     data->ThemeChanged();
04124 }
04125 
04127 // These are all of our drag and drop operations
04128 
04129 void
04130 nsWindow::InitDragEvent(nsMouseEvent &aEvent)
04131 {
04132     // set the keyboard modifiers
04133     gint x, y;
04134     GdkModifierType state = (GdkModifierType)0;
04135     gdk_window_get_pointer(NULL, &x, &y, &state);
04136     aEvent.isShift = (state & GDK_SHIFT_MASK) ? PR_TRUE : PR_FALSE;
04137     aEvent.isControl = (state & GDK_CONTROL_MASK) ? PR_TRUE : PR_FALSE;
04138     aEvent.isAlt = (state & GDK_MOD1_MASK) ? PR_TRUE : PR_FALSE;
04139     aEvent.isMeta = PR_FALSE; // GTK+ doesn't support the meta key
04140 }
04141 
04142 // This will update the drag action based on the information in the
04143 // drag context.  Gtk gets this from a combination of the key settings
04144 // and what the source is offering.
04145 
04146 void
04147 nsWindow::UpdateDragStatus(nsMouseEvent   &aEvent,
04148                            GdkDragContext *aDragContext,
04149                            nsIDragService *aDragService)
04150 {
04151     // default is to do nothing
04152     int action = nsIDragService::DRAGDROP_ACTION_NONE;
04153 
04154     // set the default just in case nothing matches below
04155     if (aDragContext->actions & GDK_ACTION_DEFAULT)
04156         action = nsIDragService::DRAGDROP_ACTION_MOVE;
04157 
04158     // first check to see if move is set
04159     if (aDragContext->actions & GDK_ACTION_MOVE)
04160         action = nsIDragService::DRAGDROP_ACTION_MOVE;
04161 
04162     // then fall to the others
04163     else if (aDragContext->actions & GDK_ACTION_LINK)
04164         action = nsIDragService::DRAGDROP_ACTION_LINK;
04165 
04166     // copy is ctrl
04167     else if (aDragContext->actions & GDK_ACTION_COPY)
04168         action = nsIDragService::DRAGDROP_ACTION_COPY;
04169 
04170     // update the drag information
04171     nsCOMPtr<nsIDragSession> session;
04172     aDragService->GetCurrentSession(getter_AddRefs(session));
04173 
04174     if (session)
04175         session->SetDragAction(action);
04176 }
04177 
04178 
04179 /* static */
04180 gboolean
04181 drag_motion_event_cb(GtkWidget *aWidget,
04182                      GdkDragContext *aDragContext,
04183                      gint aX,
04184                      gint aY,
04185                      guint aTime,
04186                      gpointer aData)
04187 {
04188     nsWindow *window = get_window_for_gtk_widget(aWidget);
04189     if (!window)
04190         return FALSE;
04191 
04192     return window->OnDragMotionEvent(aWidget,
04193                                      aDragContext,
04194                                      aX, aY, aTime, aData);
04195 }
04196 /* static */
04197 void
04198 drag_leave_event_cb(GtkWidget *aWidget,
04199                     GdkDragContext *aDragContext,
04200                     guint aTime,
04201                     gpointer aData)
04202 {
04203     nsWindow *window = get_window_for_gtk_widget(aWidget);
04204     if (!window)
04205         return;
04206 
04207     window->OnDragLeaveEvent(aWidget, aDragContext, aTime, aData);
04208 }
04209 
04210 
04211 /* static */
04212 gboolean
04213 drag_drop_event_cb(GtkWidget *aWidget,
04214                    GdkDragContext *aDragContext,
04215                    gint aX,
04216                    gint aY,
04217                    guint aTime,
04218                    gpointer *aData)
04219 {
04220     nsWindow *window = get_window_for_gtk_widget(aWidget);
04221 
04222     if (!window)
04223         return FALSE;
04224 
04225     return window->OnDragDropEvent(aWidget,
04226                                    aDragContext,
04227                                    aX, aY, aTime, aData);
04228 
04229 }
04230 
04231 /* static */
04232 void
04233 drag_data_received_event_cb (GtkWidget *aWidget,
04234                              GdkDragContext *aDragContext,
04235                              gint aX,
04236                              gint aY,
04237                              GtkSelectionData  *aSelectionData,
04238                              guint aInfo,
04239                              guint aTime,
04240                              gpointer aData)
04241 {
04242     nsWindow *window = get_window_for_gtk_widget(aWidget);
04243     if (!window)
04244         return;
04245 
04246     window->OnDragDataReceivedEvent(aWidget,
04247                                     aDragContext,
04248                                     aX, aY,
04249                                     aSelectionData,
04250                                     aInfo, aTime, aData);
04251 }
04252 
04253 /* static */
04254 nsresult
04255 initialize_prefs(void)
04256 {
04257     // check to see if we should set our raise pref
04258     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
04259     if (prefs) {
04260         PRBool val = PR_TRUE;
04261         nsresult rv;
04262         rv = prefs->GetBoolPref("mozilla.widget.raise-on-setfocus", &val);
04263         if (NS_SUCCEEDED(rv))
04264             gRaiseWindows = val;
04265     }
04266 
04267     return NS_OK;
04268 }
04269 
04270 void
04271 nsWindow::ResetDragMotionTimer(GtkWidget *aWidget,
04272                                GdkDragContext *aDragContext,
04273                                gint aX, gint aY, guint aTime)
04274 {
04275 
04276     // We have to be careful about ref ordering here.  if aWidget ==
04277     // mDraMotionWidget be careful not to let the refcnt drop to zero.
04278     // Same with the drag context.
04279     if (aWidget)
04280         gtk_widget_ref(aWidget);
04281     if (mDragMotionWidget)
04282         gtk_widget_unref(mDragMotionWidget);
04283     mDragMotionWidget = aWidget;
04284 
04285     if (aDragContext)
04286         gdk_drag_context_ref(aDragContext);
04287     if (mDragMotionContext)
04288         gdk_drag_context_unref(mDragMotionContext);
04289     mDragMotionContext = aDragContext;
04290 
04291     mDragMotionX = aX;
04292     mDragMotionY = aY;
04293     mDragMotionTime = aTime;
04294 
04295     // always clear the timer
04296     if (mDragMotionTimerID) {
04297         gtk_timeout_remove(mDragMotionTimerID);
04298         mDragMotionTimerID = 0;
04299         LOG(("*** canceled motion timer\n"));
04300     }
04301 
04302     // if no widget was passed in, just return instead of setting a new
04303     // timer
04304     if (!aWidget) {
04305         return;
04306     }
04307 
04308     // otherwise we create a new timer
04309     mDragMotionTimerID = gtk_timeout_add(100,
04310                                          (GtkFunction)DragMotionTimerCallback,
04311                                          this);
04312 }
04313 
04314 void
04315 nsWindow::FireDragMotionTimer(void)
04316 {
04317     LOG(("nsWindow::FireDragMotionTimer(%p)\n", this));
04318 
04319     OnDragMotionEvent(mDragMotionWidget, mDragMotionContext,
04320                       mDragMotionX, mDragMotionY, mDragMotionTime,
04321                       this);
04322 }
04323 
04324 void
04325 nsWindow::FireDragLeaveTimer(void)
04326 {
04327     LOG(("nsWindow::FireDragLeaveTimer(%p)\n", this));
04328 
04329     mDragLeaveTimer = 0;
04330 
04331     // clean up any pending drag motion window info
04332     if (mLastDragMotionWindow) {
04333         // send our leave signal
04334         mLastDragMotionWindow->OnDragLeave();
04335         mLastDragMotionWindow = 0;
04336     }
04337 }
04338 
04339 /* static */
04340 guint
04341 nsWindow::DragMotionTimerCallback(gpointer aClosure)
04342 {
04343     nsWindow *window = NS_STATIC_CAST(nsWindow *, aClosure);
04344     window->FireDragMotionTimer();
04345     return FALSE;
04346 }
04347 
04348 /* static */
04349 void
04350 nsWindow::DragLeaveTimerCallback(nsITimer *aTimer, void *aClosure)
04351 {
04352     nsWindow *window = NS_STATIC_CAST(nsWindow *, aClosure);
04353     window->FireDragLeaveTimer();
04354 }
04355 
04356 /* static */
04357 GdkWindow *
04358 get_inner_gdk_window (GdkWindow *aWindow,
04359                       gint x, gint y,
04360                       gint *retx, gint *rety)
04361 {
04362     gint cx, cy, cw, ch, cd;
04363     GList * children = gdk_window_peek_children(aWindow);
04364     guint num = g_list_length(children);
04365     for (int i = 0; i < (int)num; i++) {
04366         GList * child = g_list_nth(children, num - i - 1) ;
04367         if (child) {
04368             GdkWindow * childWindow = (GdkWindow *) child->data;
04369             gdk_window_get_geometry (childWindow, &cx, &cy, &cw, &ch, &cd);
04370             if ((cx < x) && (x < (cx + cw)) &&
04371                 (cy < y) && (y < (cy + ch)) &&
04372                 gdk_window_is_visible (childWindow)) {
04373                 return get_inner_gdk_window (childWindow,
04374                                              x - cx, y - cy,
04375                                              retx, rety);
04376             }
04377         }
04378     }
04379     *retx = x;
04380     *rety = y;
04381     return aWindow;
04382 }
04383 
04384 inline PRBool
04385 is_context_menu_key(const nsKeyEvent& aKeyEvent)
04386 {
04387     return ((aKeyEvent.keyCode == NS_VK_F10 && aKeyEvent.isShift &&
04388              !aKeyEvent.isControl && !aKeyEvent.isMeta && !aKeyEvent.isAlt) ||
04389             (aKeyEvent.keyCode == NS_VK_CONTEXT_MENU && !aKeyEvent.isShift &&
04390              !aKeyEvent.isControl && !aKeyEvent.isMeta && !aKeyEvent.isAlt));
04391 }
04392 
04393 void
04394 key_event_to_context_menu_event(const nsKeyEvent* aKeyEvent,
04395                                 nsMouseEvent* aCMEvent)
04396 {
04397     memcpy(aCMEvent, aKeyEvent, sizeof(nsInputEvent));
04398     aCMEvent->eventStructType = NS_MOUSE_EVENT;
04399     aCMEvent->message = NS_CONTEXTMENU_KEY;
04400     aCMEvent->isShift = aCMEvent->isControl = PR_FALSE;
04401     aCMEvent->isAlt = aCMEvent->isMeta = PR_FALSE;
04402     aCMEvent->clickCount = 0;
04403     aCMEvent->acceptActivation = PR_FALSE;
04404 }
04405 
04406 /* static */
04407 int
04408 is_parent_ungrab_enter(GdkEventCrossing *aEvent)
04409 {
04410     return (GDK_CROSSING_UNGRAB == aEvent->mode) &&
04411         ((GDK_NOTIFY_ANCESTOR == aEvent->detail) ||
04412          (GDK_NOTIFY_VIRTUAL == aEvent->detail));
04413 
04414 }
04415 
04416 /* static */
04417 int
04418 is_parent_grab_leave(GdkEventCrossing *aEvent)
04419 {
04420     return (GDK_CROSSING_GRAB == aEvent->mode) &&
04421         ((GDK_NOTIFY_ANCESTOR == aEvent->detail) ||
04422             (GDK_NOTIFY_VIRTUAL == aEvent->detail));
04423 }
04424 
04425 #ifdef ACCESSIBILITY
04426 
04432 void
04433 nsWindow::CreateRootAccessible()
04434 {
04435     if (mIsTopLevel && !mRootAccessible) {
04436         nsCOMPtr<nsIAccessible> acc;
04437         DispatchAccessibleEvent(getter_AddRefs(acc));
04438 
04439         if (acc) {
04440             mRootAccessible = acc;
04441         }
04442     }
04443 }
04444 
04445 void
04446 nsWindow::GetRootAccessible(nsIAccessible** aAccessible)
04447 {
04448     nsCOMPtr<nsIAccessible> docAcc, parentAcc;
04449     DispatchAccessibleEvent(getter_AddRefs(docAcc));
04450     PRUint32 role;
04451 
04452     while (docAcc) {
04453         docAcc->GetRole(&role);
04454         if (role == nsIAccessible::ROLE_FRAME) {
04455             *aAccessible = docAcc;
04456             NS_ADDREF(*aAccessible);
04457             break;
04458         }
04459         docAcc->GetParent(getter_AddRefs(parentAcc));
04460         docAcc = parentAcc;
04461     }
04462 }
04463 
04472 PRBool
04473 nsWindow::DispatchAccessibleEvent(nsIAccessible** aAccessible)
04474 {
04475     PRBool result = PR_FALSE;
04476     nsAccessibleEvent event(PR_TRUE, NS_GETACCESSIBLE, this);
04477 
04478     *aAccessible = nsnull;
04479 
04480     nsEventStatus status;
04481     DispatchEvent(&event, status);
04482     result = (nsEventStatus_eConsumeNoDefault == status) ? PR_TRUE : PR_FALSE;
04483 
04484     // if the event returned an accesssible get it.
04485     if (event.accessible)
04486         *aAccessible = event.accessible;
04487 
04488     return result;
04489 }
04490 
04491 void
04492 nsWindow::DispatchActivateEvent(void)
04493 {
04494     nsCommonWidget::DispatchActivateEvent();
04495 
04496     if (sAccessibilityEnabled) {
04497         nsCOMPtr<nsIAccessible> rootAcc;
04498         GetRootAccessible(getter_AddRefs(rootAcc));
04499         nsCOMPtr<nsPIAccessible> privAcc(do_QueryInterface(rootAcc));
04500         if (privAcc) {
04501             privAcc->FireToolkitEvent(
04502                          nsIAccessibleEvent::EVENT_ATK_WINDOW_ACTIVATE,
04503                          rootAcc, nsnull);
04504         }
04505     }
04506  }
04507 
04508 void
04509 nsWindow::DispatchDeactivateEvent(void)
04510 {
04511     nsCommonWidget::DispatchDeactivateEvent();
04512 
04513     if (sAccessibilityEnabled) {
04514         nsCOMPtr<nsIAccessible> rootAcc;
04515         GetRootAccessible(getter_AddRefs(rootAcc));
04516         nsCOMPtr<nsPIAccessible> privAcc(do_QueryInterface(rootAcc));
04517         if (privAcc) {
04518             privAcc->FireToolkitEvent(
04519                          nsIAccessibleEvent::EVENT_ATK_WINDOW_DEACTIVATE,
04520                          rootAcc, nsnull);
04521         }
04522     }
04523 }
04524 #endif /* #ifdef ACCESSIBILITY */
04525 
04526 // nsChildWindow class
04527 
04528 nsChildWindow::nsChildWindow()
04529 {
04530 }
04531 
04532 nsChildWindow::~nsChildWindow()
04533 {
04534 }
04535 
04536 #ifdef USE_XIM
04537 
04538 void
04539 nsWindow::IMEDestroyContext(void)
04540 {
04541     // If this is the focus window and we have an IM context we need
04542     // to unset the focus on this window before we destroy the window.
04543     if (gIMEFocusWindow == this) {
04544         gIMEFocusWindow->IMELoseFocus();
04545         gIMEFocusWindow = nsnull;
04546     }
04547 
04548     if (!mIMContext)
04549         return;
04550 
04551     gtk_im_context_set_client_window(mIMContext, NULL);
04552     g_object_unref(G_OBJECT(mIMContext));
04553     mIMContext = nsnull;
04554 }
04555 
04556 
04557 void
04558 nsWindow::IMESetFocus(void)
04559 {
04560     LOGIM(("IMESetFocus %p\n", (void *)this));
04561     GtkIMContext *im = IMEGetContext();
04562     if (!im)
04563         return;
04564 
04565     gtk_im_context_focus_in(im);
04566     gIMEFocusWindow = this;
04567 }
04568 
04569 void
04570 nsWindow::IMELoseFocus(void)
04571 {
04572     LOGIM(("IMELoseFocus %p\n", (void *)this));
04573     GtkIMContext *im = IMEGetContext();
04574     if (!im)
04575         return;
04576 
04577     gtk_im_context_focus_out(im);
04578 }
04579 
04580 void
04581 nsWindow::IMEComposeStart(void)
04582 {
04583     LOGIM(("IMEComposeStart [%p]\n", (void *)this));
04584 
04585     if (mComposingText) {
04586         NS_WARNING("tried to re-start text composition\n");
04587         return;
04588     }
04589 
04590     mComposingText = PR_TRUE;
04591 
04592     nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_START, this);
04593 
04594     nsEventStatus status;
04595     DispatchEvent(&compEvent, status);
04596 
04597     gint x1, y1, x2, y2;
04598     GtkWidget *widget =
04599         get_gtk_widget_for_gdk_window(this->mDrawingarea->inner_window);
04600 
04601     gdk_window_get_origin(widget->window, &x1, &y1);
04602     gdk_window_get_origin(this->mDrawingarea->inner_window, &x2, &y2);
04603 
04604     GdkRectangle area;
04605     area.x = compEvent.theReply.mCursorPosition.x + (x2 - x1);
04606     area.y = compEvent.theReply.mCursorPosition.y + (y2 - y1);
04607     area.width  = 0;
04608     area.height = compEvent.theReply.mCursorPosition.height;
04609 
04610     gtk_im_context_set_cursor_location(IMEGetContext(), &area);
04611 }
04612 
04613 void
04614 nsWindow::IMEComposeText (const PRUnichar *aText,
04615                           const PRInt32 aLen,
04616                           const gchar *aPreeditString,
04617                           const gint aCursorPos,
04618                           const PangoAttrList *aFeedback)
04619 {
04620     // Send our start composition event if we need to
04621     if (!mComposingText)
04622         IMEComposeStart();
04623 
04624     LOGIM(("IMEComposeText\n"));
04625     nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, this);
04626 
04627     if (aLen != 0) {
04628         textEvent.theText = (PRUnichar*)aText;
04629 
04630         if (aPreeditString && aFeedback && (aLen > 0)) {
04631             IM_set_text_range(aLen, aPreeditString, aCursorPos, aFeedback,
04632                               &(textEvent.rangeCount),
04633                               &(textEvent.rangeArray));
04634         }
04635     }
04636 
04637     nsEventStatus status;
04638     DispatchEvent(&textEvent, status);
04639 
04640     if (textEvent.rangeArray) {
04641         delete[] textEvent.rangeArray;
04642     }
04643 
04644     gint x1, y1, x2, y2;
04645     GtkWidget *widget =
04646         get_gtk_widget_for_gdk_window(this->mDrawingarea->inner_window);
04647 
04648     gdk_window_get_origin(widget->window, &x1, &y1);
04649     gdk_window_get_origin(this->mDrawingarea->inner_window, &x2, &y2);
04650 
04651     GdkRectangle area;
04652     area.x = textEvent.theReply.mCursorPosition.x + (x2 - x1);
04653     area.y = textEvent.theReply.mCursorPosition.y + (y2 - y1);
04654     area.width  = 0;
04655     area.height = textEvent.theReply.mCursorPosition.height;
04656 
04657     gtk_im_context_set_cursor_location(IMEGetContext(), &area);
04658 }
04659 
04660 void
04661 nsWindow::IMEComposeEnd(void)
04662 {
04663     LOGIM(("IMEComposeEnd [%p]\n", (void *)this));
04664 
04665     if (!mComposingText) {
04666         NS_WARNING("tried to end text composition before it was started");
04667         return;
04668     }
04669 
04670     mComposingText = PR_FALSE;
04671 
04672     nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_END, this);
04673 
04674     nsEventStatus status;
04675     DispatchEvent(&compEvent, status);
04676 }
04677 
04678 GtkIMContext*
04679 nsWindow::IMEGetContext()
04680 {
04681     return IM_get_input_context(this->mDrawingarea);
04682 }
04683 
04684 void
04685 nsWindow::IMECreateContext(void)
04686 {
04687     GtkIMContext *im = gtk_im_multicontext_new();
04688     if (!im)
04689         return;
04690 
04691     gtk_im_context_set_client_window(im, GTK_WIDGET(mContainer)->window);
04692 
04693     g_signal_connect(G_OBJECT(im), "preedit_changed",
04694                      G_CALLBACK(IM_preedit_changed_cb), this);
04695     g_signal_connect(G_OBJECT(im), "commit",
04696                      G_CALLBACK(IM_commit_cb), this);
04697 
04698     mIMContext = im;
04699 }
04700 
04701 PRBool
04702 nsWindow::IMEFilterEvent(GdkEventKey *aEvent)
04703 {
04704     GtkIMContext *im = IMEGetContext();
04705     if (!im)
04706         return FALSE;
04707 
04708     gKeyEvent = aEvent;
04709     gboolean filtered = gtk_im_context_filter_keypress(im, aEvent);
04710     gKeyEvent = NULL;
04711 
04712     LOGIM(("key filtered: %d committed: %d changed: %d\n",
04713            filtered, gKeyEventCommitted, gKeyEventChanged));
04714 
04715     // We filter the key event if the event was not committed (because
04716     // it's probably part of a composition) or if the key event was
04717     // committed _and_ changed.  This way we still let key press
04718     // events go through as simple key press events instead of
04719     // composed characters.
04720 
04721     PRBool retval = PR_FALSE;
04722     if (filtered &&
04723         (!gKeyEventCommitted || (gKeyEventCommitted && gKeyEventChanged)))
04724         retval = PR_TRUE;
04725 
04726     gKeyEventChanged = PR_FALSE;
04727     gKeyEventCommitted = PR_FALSE;
04728     gKeyEventChanged = PR_FALSE;
04729 
04730     return retval;
04731 }
04732 
04733 /* static */
04734 void
04735 IM_preedit_changed_cb(GtkIMContext *aContext,
04736                       nsWindow     *aWindow)
04737 {
04738     gchar *preedit_string;
04739     gint cursor_pos;
04740     PangoAttrList *feedback_list;
04741 
04742     // if gFocusWindow is null, use the last focused gIMEFocusWindow
04743     nsWindow *window = gFocusWindow ? gFocusWindow : gIMEFocusWindow;
04744     if (!window)
04745         return;
04746 
04747     // Should use cursor_pos ?
04748     // Of course!!!
04749     gtk_im_context_get_preedit_string(aContext, &preedit_string,
04750                                       &feedback_list, &cursor_pos);
04751 
04752     LOGIM(("preedit string is: %s   length is: %d\n",
04753            preedit_string, strlen(preedit_string)));
04754 
04755     if (!preedit_string || !*preedit_string) {
04756         LOGIM(("preedit ended\n"));
04757         window->IMEComposeText(NULL, 0, NULL, 0, NULL);
04758         window->IMEComposeEnd();
04759         return;
04760     }
04761 
04762     LOGIM(("preedit len %d\n", strlen(preedit_string)));
04763 
04764     gunichar2 * uniStr;
04765     glong uniStrLen;
04766 
04767     uniStr = NULL;
04768     uniStrLen = 0;
04769     uniStr = g_utf8_to_utf16(preedit_string, -1, NULL, &uniStrLen, NULL);
04770 
04771     if (!uniStr) {
04772         g_free(preedit_string);
04773         LOG(("utf8-utf16 string tranfer failed!\n"));
04774         if (feedback_list)
04775             pango_attr_list_unref(feedback_list);
04776         return;
04777     }
04778 
04779     if (uniStrLen) {
04780         window->IMEComposeText(NS_STATIC_CAST(const PRUnichar *, uniStr),
04781                                uniStrLen, preedit_string, cursor_pos, feedback_list);
04782     }
04783 
04784     g_free(preedit_string);
04785     g_free(uniStr);
04786 
04787     if (feedback_list)
04788         pango_attr_list_unref(feedback_list);
04789 }
04790 
04791 /* static */
04792 void
04793 IM_commit_cb (GtkIMContext *aContext,
04794               const gchar  *aUtf8_str,
04795               nsWindow     *aWindow)
04796 {
04797     gunichar2 *uniStr;
04798     glong uniStrLen;
04799 
04800     LOGIM(("IM_commit_cb\n"));
04801 
04802     gKeyEventCommitted = PR_TRUE;
04803 
04804     // if gFocusWindow is null, use the last focused gIMEFocusWindow
04805     nsWindow *window = gFocusWindow ? gFocusWindow : gIMEFocusWindow;
04806 
04807     if (!window)
04808         return;
04809 
04810     /* If IME doesn't change they keyevent that generated this commit,
04811        don't send it through XIM - just send it as a normal key press
04812        event. */
04813 
04814     if (gKeyEvent) {
04815         char keyval_utf8[8]; /* should have at least 6 bytes of space */
04816         gint keyval_utf8_len;
04817         guint32 keyval_unicode;
04818 
04819         keyval_unicode = gdk_keyval_to_unicode(gKeyEvent->keyval);
04820         keyval_utf8_len = g_unichar_to_utf8(keyval_unicode, keyval_utf8);
04821         keyval_utf8[keyval_utf8_len] = '\0';
04822 
04823         if (!strcmp(aUtf8_str, keyval_utf8)) {
04824             gKeyEventChanged = PR_FALSE;
04825             return;
04826         }
04827     }
04828 
04829     gKeyEventChanged = PR_TRUE;
04830 
04831     uniStr = NULL;
04832     uniStrLen = 0;
04833     uniStr = g_utf8_to_utf16(aUtf8_str, -1, NULL, &uniStrLen, NULL);
04834 
04835     if (!uniStr) {
04836         LOGIM(("utf80utf16 string tranfer failed!\n"));
04837         return;
04838     }
04839 
04840     if (uniStrLen) {
04841         window->IMEComposeText((const PRUnichar *)uniStr,
04842                                (PRInt32)uniStrLen, NULL, 0, NULL);
04843         window->IMEComposeEnd();
04844     }
04845 
04846     g_free(uniStr);
04847 }
04848 
04849 #define       START_OFFSET(I)      \
04850     (*aTextRangeListResult)[I].mStartOffset
04851 
04852 #define       END_OFFSET(I) \
04853     (*aTextRangeListResult)[I].mEndOffset
04854 
04855 #define       SET_FEEDBACKTYPE(I,T) (*aTextRangeListResult)[I].mRangeType = T
04856 
04857 /* static */
04858 void
04859 IM_set_text_range(const PRInt32 aLen,
04860                   const gchar *aPreeditString,
04861                   const gint aCursorPos,
04862                   const PangoAttrList *aFeedback,
04863                   PRUint32 *aTextRangeListLengthResult,
04864                   nsTextRangeArray *aTextRangeListResult)
04865 {
04866     if (aLen == 0) {
04867         aTextRangeListLengthResult = 0;
04868         aTextRangeListResult = NULL;
04869         return;
04870     }
04871 
04872     PangoAttrIterator * aFeedbackIterator;
04873     aFeedbackIterator = pango_attr_list_get_iterator((PangoAttrList*)aFeedback);
04874     //(NS_REINTERPRET_CAST(PangoAttrList*, aFeedback));
04875     // Since some compilers don't permit this casting -- from const to un-const
04876     if (aFeedbackIterator == NULL) return;
04877 
04878     /*
04879      * Don't use pango_attr_iterator_range, it'll mislead you.
04880      * As for going through the list to get the attribute number,
04881      * it take much time for performance.
04882      * Now it's simple and enough, although maybe waste a little space.
04883     */
04884     PRInt32 aMaxLenOfTextRange;
04885     aMaxLenOfTextRange = 2*aLen + 1;
04886     *aTextRangeListResult = new nsTextRange[aMaxLenOfTextRange];
04887     NS_ASSERTION(*aTextRangeListResult, "No enough memory.");
04888 
04889     // Set caret's postion
04890     SET_FEEDBACKTYPE(0, NS_TEXTRANGE_CARETPOSITION);
04891     START_OFFSET(0) = aCursorPos;
04892     END_OFFSET(0) = aCursorPos;
04893 
04894     int count = 0;
04895     PangoAttribute * aPangoAttr;
04896     PangoAttribute * aPangoAttrReverse, * aPangoAttrUnderline;
04897     /*
04898      * Depend on gtk2's implementation on XIM support.
04899      * In aFeedback got from gtk2, there are only three types of data:
04900      * PANGO_ATTR_UNDERLINE, PANGO_ATTR_FOREGROUND, PANGO_ATTR_BACKGROUND.
04901      * Corresponding to XIMUnderline, XIMReverse.
04902      * Don't take PANGO_ATTR_BACKGROUND into account, since
04903      * PANGO_ATTR_BACKGROUND and PANGO_ATTR_FOREGROUND are always
04904      * a couple.
04905      */
04906     gint start, end;
04907     gunichar2 * uniStr;
04908     glong uniStrLen;
04909     do {
04910         aPangoAttrUnderline = pango_attr_iterator_get(aFeedbackIterator,
04911                                                       PANGO_ATTR_UNDERLINE);
04912         aPangoAttrReverse = pango_attr_iterator_get(aFeedbackIterator,
04913                                                     PANGO_ATTR_FOREGROUND);
04914         if (!aPangoAttrUnderline && !aPangoAttrReverse)
04915             continue;
04916 
04917         // Get the range of the current attribute(s)
04918         pango_attr_iterator_range(aFeedbackIterator, &start, &end);
04919 
04920         PRUint32 feedbackType = 0;
04921         // XIMReverse | XIMUnderline
04922         if (aPangoAttrUnderline && aPangoAttrReverse) {
04923             feedbackType = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT;
04924             // Doesn't matter which attribute we use here since we
04925             // are using pango_attr_iterator_range to determine the
04926             // range of the attributes.
04927             aPangoAttr = aPangoAttrUnderline;
04928         }
04929         // XIMUnderline
04930         else if (aPangoAttrUnderline) {
04931             feedbackType = NS_TEXTRANGE_CONVERTEDTEXT;
04932             aPangoAttr = aPangoAttrUnderline;
04933         }
04934         // XIMReverse
04935         else if (aPangoAttrReverse) {
04936             feedbackType = NS_TEXTRANGE_SELECTEDRAWTEXT;
04937             aPangoAttr = aPangoAttrReverse;
04938         }
04939 
04940         count++;
04941         START_OFFSET(count) = 0;
04942         END_OFFSET(count) = 0;
04943 
04944         uniStr = NULL;
04945         if (start > 0) {
04946             uniStr = g_utf8_to_utf16(aPreeditString, start,
04947                                      NULL, &uniStrLen, NULL);
04948         }
04949         if (uniStr) {
04950             START_OFFSET(count) = uniStrLen;
04951             g_free(uniStr);
04952         }
04953 
04954         uniStr = NULL;
04955         uniStr = g_utf8_to_utf16(aPreeditString + start, end - start,
04956                                  NULL, &uniStrLen, NULL);
04957         if (uniStr) {
04958             END_OFFSET(count) = START_OFFSET(count) + uniStrLen;
04959             SET_FEEDBACKTYPE(count, feedbackType);
04960             g_free(uniStr);
04961         }
04962 
04963     } while ((count < aMaxLenOfTextRange - 1) &&
04964              (pango_attr_iterator_next(aFeedbackIterator)));
04965 
04966    *aTextRangeListLengthResult = count + 1;
04967 
04968    pango_attr_iterator_destroy(aFeedbackIterator);
04969 }
04970 
04971 /* static */
04972 GtkIMContext *
04973 IM_get_input_context(MozDrawingarea *aArea)
04974 {
04975     if (!aArea)
04976         return nsnull;
04977     GtkWidget *owningWidget =
04978         get_gtk_widget_for_gdk_window(aArea->inner_window);
04979 
04980     nsWindow *owningWindow = get_window_for_gtk_widget(owningWidget);
04981 
04982     return owningWindow ? owningWindow->mIMContext : nsnull;
04983 }
04984 
04985 #endif