Back to index

lightning-sunbird  0.9+nobinonly
nsWindow.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Ilya Konstantinov <future@galanet.net>
00024  *   tim copperfield <timecop@network.email.ne.jp>
00025  *   Mats Palmgren <mats.palmgren@bredband.net>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #undef DEBUG_CURSORCACHE
00042 
00043 #include <stdio.h>
00044 
00045 #include <gtk/gtk.h>
00046 
00047 #include <gdk/gdkx.h>
00048 #include <gtk/gtkprivate.h>
00049 // XXX FTSO nsWebShell
00050 #include <gdk/gdkprivate.h>
00051 
00052 #include <X11/Xatom.h>   // For XA_STRING
00053 
00054 #include "nsWindow.h"
00055 #include "nsWidgetsCID.h"
00056 #include "nsIFontMetrics.h"
00057 #include "nsFont.h"
00058 #include "nsGUIEvent.h"
00059 #include "nsIRenderingContext.h"
00060 #include "nsIDOMNode.h"
00061 #include "nsRect.h"
00062 #include "nsTransform2D.h"
00063 #include "nsGfxCIID.h"
00064 #include "nsGtkEventHandler.h"
00065 #include "nsIAppShell.h"
00066 #include "nsClipboard.h"
00067 #include "nsIRollupListener.h"
00068 
00069 #include "nsIPref.h"
00070 
00071 #include "nsICharsetConverterManager.h"
00072 #include "nsIPlatformCharset.h"
00073 #include "nsIServiceManager.h"
00074 #include "nsIIOService.h"
00075 #include "nsIProtocolHandler.h"
00076 #include "nsIURI.h"
00077 #include "nsNetUtil.h"
00078 #include "nsIResProtocolHandler.h"
00079 #include "nsIFileURL.h"
00080 
00081 #include "nsGtkUtils.h" // for nsGtkUtils::gdk_window_flash()
00082 
00083 #include "nsIDragService.h"
00084 #include "nsIDragSessionGTK.h"
00085 
00086 #include "nsGtkIMEHelper.h"
00087 #include "nsKeyboardUtils.h"
00088 
00089 #include "nsGtkCursors.h" // for custom cursors
00090 
00091 #include "nspr.h"
00092 
00093 #include <unistd.h>
00094 
00095 #ifdef NEED_USLEEP_PROTOTYPE
00096 extern "C" int usleep(unsigned int);
00097 #endif
00098 #if defined(__QNX__)
00099 #define usleep(s)    sleep(s)
00100 #endif
00101 
00102 #undef DEBUG_DND_XLATE
00103 #undef DEBUG_DND_EVENTS
00104 #undef DEBUG_FOCUS
00105 #undef DEBUG_GRAB
00106 #undef DEBUG_ICONS
00107 #define MODAL_TIMERS_BROKEN
00108 
00109 #define NS_TO_GDK_RGB(ns) (ns & 0xff) << 16 | (ns & 0xff00) | ((ns >> 16) & 0xff)
00110 
00111 #define CAPS_LOCK_IS_ON \
00112 (nsGtkUtils::gdk_keyboard_get_modifiers() & GDK_LOCK_MASK)
00113 
00114 #define WANT_PAINT_FLASHING \
00115 (debug_WantPaintFlashing() && CAPS_LOCK_IS_ON)
00116 
00117 #define kWindowPositionSlop 20
00118 
00119 static NS_DEFINE_IID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
00120 
00121 static PRBool gGlobalsInitialized   = PR_FALSE;
00122 static PRBool gRaiseWindows         = PR_TRUE;
00123 /* cursors cache */
00124 GdkCursor *nsWindow::gsGtkCursorCache[eCursorCount];
00125 
00126 /* window icon cache */
00127 struct IconEntry : public PLDHashEntryHdr {
00128   const char* string;
00129   GdkPixmap* w_pixmap;
00130   GdkBitmap* w_mask;
00131   GdkPixmap* w_minipixmap;
00132   GdkBitmap* w_minimask;
00133 };
00134 
00135 static PLDHashTableOps iconHashOps = {
00136   PL_DHashAllocTable,
00137   PL_DHashFreeTable,
00138   PL_DHashGetKeyStub,
00139   PL_DHashStringKey,
00140   PL_DHashMatchStringKey,
00141   PL_DHashMoveEntryStub,
00142   nsWindow::ClearIconEntry,
00143   PL_DHashFinalizeStub,
00144   NULL
00145 };
00146 
00147 gint handle_mozarea_focus_in (
00148     GtkWidget *      aWidget, 
00149     GdkEventFocus *  aGdkFocusEvent, 
00150     gpointer         aData);
00151     
00152 gint handle_mozarea_focus_out (
00153     GtkWidget *      aWidget, 
00154     GdkEventFocus *  aGdkFocusEvent, 
00155     gpointer         aData);
00156 
00157 void handle_toplevel_configure (
00158     GtkMozArea *      aArea,
00159     nsWindow   *      aWindow);
00160 
00161 // are we grabbing?
00162 PRBool      nsWindow::sIsGrabbing = PR_FALSE;
00163 nsWindow   *nsWindow::sGrabWindow = NULL;
00164 PRBool      nsWindow::sIsDraggingOutOf = PR_FALSE;
00165 
00166 // this is a hash table that contains a list of the
00167 // shell_window -> nsWindow * lookups
00168 GHashTable *nsWindow::mWindowLookupTable = NULL;
00169 
00170 // this is the last window that had a drag event happen on it.
00171 nsWindow *nsWindow::mLastDragMotionWindow = NULL;
00172 
00173 PLDHashTable* nsWindow::sIconCache;
00174 
00175 PRBool gJustGotDeactivate = PR_FALSE;
00176 PRBool gJustGotActivate   = PR_FALSE;
00177 
00178 #define NS_WINDOW_TITLE_MAX_LENGTH 4095
00179 
00180 #ifdef USE_XIM
00181 
00182 struct nsXICLookupEntry : public PLDHashEntryHdr {
00183   nsWindow*   mShellWindow;
00184   nsIMEGtkIC* mXIC;
00185 };
00186 
00187 PLDHashTable nsWindow::gXICLookupTable;
00188 GdkFont *nsWindow::gPreeditFontset = nsnull;
00189 GdkFont *nsWindow::gStatusFontset = nsnull;
00190 
00191 #define XIC_FONTSET "-*-*-medium-r-*-*-%d-*-*-*-*-*-*-*,-*-*-*-r-*-*-%d-*-*-*-*-*-*-*,-*-*-*-*-*-*-%d-*-*-*-*-*-*-*"
00192 #endif // USE_XIM
00193 
00194 #ifdef DEBUG_DND_XLATE
00195 static void printDepth(int depth) {
00196   int i;
00197   for (i=0; i < depth; i++)
00198   {
00199     g_print(" ");
00200   }
00201 }
00202 #endif
00203 
00204 static int is_parent_ungrab_enter(GdkEventCrossing *aEvent);
00205 static int is_parent_grab_leave(GdkEventCrossing *aEvent);
00206 
00207 NS_IMETHODIMP nsWindow::SetParent(nsIWidget* aNewParent)
00208 {
00209   NS_ENSURE_ARG_POINTER(aNewParent);
00210 
00211   GdkWindow* newParentWindow =
00212     NS_STATIC_CAST(GdkWindow*, aNewParent->GetNativeData(NS_NATIVE_WINDOW));
00213   NS_ASSERTION(newParentWindow, "Parent widget has a null native window handle");
00214 
00215   if (!mShell && mSuperWin) {
00216     gdk_superwin_reparent(mSuperWin, newParentWindow);
00217   } else {
00218     NS_NOTREACHED("nsWindow::SetParent - reparenting a non-child window");
00219   }
00220   return NS_OK;
00221 }
00222 
00223 
00224 // This function will check if a button event falls inside of a
00225 // window's bounds.
00226 static PRBool
00227 ButtonEventInsideWindow (GdkWindow *window, GdkEventButton *aGdkButtonEvent)
00228 {
00229   gint x, y;
00230   gint width, height;
00231   gdk_window_get_position(window, &x, &y);
00232   gdk_window_get_size(window, &width, &height);
00233 
00234   // This event is measured from the origin of the window itself, not
00235   // from the origin of the screen.
00236   if (aGdkButtonEvent->x >= x && aGdkButtonEvent->y >= y &&
00237       aGdkButtonEvent->x <= width + x && aGdkButtonEvent->y <= height + y)
00238     return TRUE;
00239 
00240   return FALSE;
00241 }
00242 
00243 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsWidget)
00244 
00245 //-------------------------------------------------------------------------
00246 //
00247 // nsWindow constructor
00248 //
00249 //-------------------------------------------------------------------------
00250 nsWindow::nsWindow() 
00251 {
00252   mShell = nsnull;
00253   mWindowType = eWindowType_child;
00254   mBorderStyle = eBorderStyle_default;
00255   mSuperWin = 0;
00256   mMozArea = 0;
00257   mMozAreaClosestParent = 0;
00258   mCachedX = mCachedY = -1;
00259 
00260   mIsTooSmall = PR_FALSE;
00261   mIsUpdating = PR_FALSE;
00262   mTransientParent = nsnull;
00263   // init the hash table if it hasn't happened already
00264   if (mWindowLookupTable == NULL) {
00265     mWindowLookupTable = g_hash_table_new(g_direct_hash, g_direct_equal);
00266   }
00267   if (mLastDragMotionWindow == this)
00268     mLastDragMotionWindow = NULL;
00269   mBlockMozAreaFocusIn = PR_FALSE;
00270   mLastGrabFailed = PR_TRUE;
00271   mHasAnonymousChildren = PR_FALSE;
00272   mDragMotionWidget = 0;
00273   mDragMotionContext = 0;
00274   mDragMotionX = 0;
00275   mDragMotionY = 0;
00276   mDragMotionTime = 0;
00277   mDragMotionTimerID = 0;
00278 
00279   // for commit character
00280   mIMECompositionUniString = nsnull;
00281   mIMECompositionUniStringSize = 0;
00282 
00283   mIsTranslucent = PR_FALSE;
00284   mTransparencyBitmap = nsnull;
00285 
00286 #ifdef USE_XIM
00287   mIMEEnable = PR_TRUE; //currently will not be used
00288   mIMEShellWindow = 0;
00289   mIMECallComposeStart = PR_FALSE;
00290   mIMECallComposeEnd = PR_TRUE;
00291   mIMEIsBeingActivate = PR_FALSE;
00292   mICSpotTimer = nsnull;
00293   mXICFontSize = 16;
00294   if (gXICLookupTable.ops == NULL) {
00295     PL_DHashTableInit(&gXICLookupTable, PL_DHashGetStubOps(), nsnull,
00296                       sizeof(nsXICLookupEntry), PL_DHASH_MIN_SIZE);
00297   }
00298 #endif // USE_XIM
00299 
00300   mLeavePending = PR_FALSE;
00301   mRestoreFocus = PR_FALSE;
00302 
00303   // initialize globals
00304   if (!gGlobalsInitialized) {
00305     gGlobalsInitialized = PR_TRUE;
00306 
00307     // check to see if we should set our raise pref
00308     nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID);
00309     if (prefs) {
00310       PRBool val = PR_TRUE;
00311       nsresult rv;
00312       rv = prefs->GetBoolPref("mozilla.widget.raise-on-setfocus",
00313                               &val);
00314       if (NS_SUCCEEDED(rv))
00315         gRaiseWindows = val;
00316 
00317       //
00318       // control the "keyboard Mode_switch during XGrabKeyboard"
00319       //
00320       PRBool grab_during_popup = PR_TRUE;
00321       PRBool ungrab_during_mode_switch = PR_TRUE;
00322       prefs->GetBoolPref("autocomplete.grab_during_popup",
00323                               &grab_during_popup);
00324       prefs->GetBoolPref("autocomplete.ungrab_during_mode_switch",
00325                               &ungrab_during_mode_switch);
00326       nsXKBModeSwitch::ControlWorkaround(grab_during_popup,
00327                            ungrab_during_mode_switch);
00328     }
00329 
00330     sIconCache = PL_NewDHashTable(&iconHashOps, nsnull, sizeof(IconEntry), 28);
00331   }
00332 }
00333 
00334 //-------------------------------------------------------------------------
00335 //
00336 // nsWindow destructor
00337 //
00338 //-------------------------------------------------------------------------
00339 nsWindow::~nsWindow()
00340 {
00341 #ifdef USE_XIM
00342   KillICSpotTimer();
00343 #endif // USE_XIM
00344 
00345   if (mIMECompositionUniString) {
00346     delete[] mIMECompositionUniString;
00347     mIMECompositionUniString = nsnull;
00348   }
00349 
00350   // make sure to unset any drag motion timers here.
00351   ResetDragMotionTimer(0, 0, 0, 0, 0);
00352 
00353   //  printf("%p nsWindow::~nsWindow\n", this);
00354   // make sure that we release the grab indicator here
00355   if (sGrabWindow == this) {
00356     sIsGrabbing = PR_FALSE;
00357     sGrabWindow = NULL;
00358   }
00359   // make sure that we unset the lastDragMotionWindow if
00360   // we are it.
00361   if (mLastDragMotionWindow == this) {
00362     mLastDragMotionWindow = NULL;
00363   }
00364   // make sure to release our focus window
00365   if (mHasFocus == PR_TRUE) {
00366     sFocusWindow = NULL;
00367   }
00368 
00369   // always call destroy.  if it's already been called, there's no harm
00370   // since it keeps track of when it's already been called.
00371 
00372   Destroy();
00373 
00374   delete[] mTransparencyBitmap;
00375   mTransparencyBitmap = nsnull;
00376 
00377   if (mIsUpdating)
00378     UnqueueDraw();
00379 }
00380 
00381 /* static */ void
00382 nsWindow::ReleaseGlobals()
00383 {
00384   if (mWindowLookupTable) {
00385     g_hash_table_destroy(mWindowLookupTable);
00386     mWindowLookupTable = nsnull;
00387   }
00388   if (gXICLookupTable.ops) {
00389     PL_DHashTableFinish(&gXICLookupTable);
00390     gXICLookupTable.ops = nsnull;
00391   }
00392   if (sIconCache) {
00393     PL_DHashTableDestroy(sIconCache);
00394     sIconCache = nsnull;
00395   }
00396   if (gPreeditFontset) {
00397     gdk_font_unref(gPreeditFontset);
00398     gPreeditFontset = nsnull;
00399   }
00400   if (gStatusFontset) {
00401     gdk_font_unref(gStatusFontset);
00402     gStatusFontset = nsnull;
00403   }
00404   for (int i = 0, n = NS_ARRAY_LENGTH(gsGtkCursorCache); i < n; ++i) {
00405     if (gsGtkCursorCache[i]) {
00406       gdk_cursor_destroy(gsGtkCursorCache[i]);
00407       gsGtkCursorCache[i] = nsnull;
00408     }
00409   }
00410   gGlobalsInitialized = PR_FALSE;
00411 }
00412 
00413 NS_IMETHODIMP nsWindow::Destroy(void)
00414 {
00415   // remove our pointer from the object so that we event handlers don't send us events
00416   // after we are gone or in the process of going away
00417 
00418   if (mSuperWin)
00419     gtk_object_remove_data(GTK_OBJECT(mSuperWin), "nsWindow");
00420   if (mShell)
00421     gtk_object_remove_data(GTK_OBJECT(mShell), "nsWindow");
00422   if (mMozArea)
00423     gtk_object_remove_data(GTK_OBJECT(mMozArea), "nsWindow");
00424 
00425   return nsWidget::Destroy();
00426 }
00427 
00428 
00429 void nsWindow::InvalidateWindowPos(void)
00430 {
00431   mCachedX = mCachedY = -1;
00432 
00433   for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
00434     // Force kid to invalidate its window position if necessary.
00435     nsRect kidBounds;
00436     kid->GetBounds(kidBounds);
00437     kid->Move(kidBounds.x, kidBounds.y);
00438   }
00439 
00440   // The following code was shamelessly copied from nsWindow::DestroyNativeChildren
00441   // If this wasn't GTK1, I'd refactor it to share code with that function
00442   if (mSuperWin && mHasAnonymousChildren) {
00443     Display *display = GDK_DISPLAY();
00444     Window  window = GDK_WINDOW_XWINDOW(mSuperWin->bin_window);
00445     if (window && !((GdkWindowPrivate *)mSuperWin->bin_window)->destroyed)
00446     {
00447       Window       root_return;
00448       Window       parent_return;
00449       Window      *children_return = NULL;
00450       unsigned int nchildren_return = 0;
00451       // get a list of children for this window
00452       XQueryTree(display, window, &root_return, &parent_return,
00453                  &children_return, &nchildren_return);
00454       // walk the list of children
00455       for (unsigned int i=0; i < nchildren_return; i++)
00456       {
00457         Window child_window = children_return[i];
00458         nsWindow *thisWindow = GetnsWindowFromXWindow(child_window);
00459         if (thisWindow)
00460         {
00461           nsRect kidBounds;
00462           thisWindow->GetBounds(kidBounds);
00463           thisWindow->Move(kidBounds.x, kidBounds.y);
00464         }
00465       }      
00466     }
00467   }
00468 }
00469 
00470 void
00471 handle_invalidate_pos(GtkMozArea *aArea, gpointer p)
00472 {
00473   nsWindow *widget = (nsWindow *)p;
00474   widget->InvalidateWindowPos();
00475 }
00476 
00477 PRBool nsWindow::GetWindowPos(nscoord &x, nscoord &y)
00478 {
00479   if ((mCachedX==-1) && (mCachedY==-1)) { /* Not cached */
00480     gint xpos, ypos;
00481 
00482     if (mMozArea)
00483       {
00484         if (mMozArea->window)
00485           {
00486             if (!GTK_WIDGET_MAPPED(mMozArea) || !GTK_WIDGET_REALIZED(mMozArea)) {
00487               // get_root_origin will do Bad Things
00488               return PR_FALSE;
00489             }
00490             gdk_window_get_root_origin(mMozArea->window, &xpos, &ypos);
00491           }
00492         else
00493           return PR_FALSE;
00494       }
00495     else if (mSuperWin)
00496       {
00497         if (mSuperWin->bin_window)
00498           {
00499             gdk_window_get_origin(mSuperWin->bin_window, &xpos, &ypos);
00500           }
00501         else
00502           return PR_FALSE;
00503       }
00504     else
00505       return PR_FALSE;
00506 
00507     mCachedX = xpos;
00508     mCachedY = ypos;
00509   }
00510 
00511   x = mCachedX;
00512   y = mCachedY;
00513 
00514   return PR_TRUE;
00515 }
00516 
00517 NS_IMETHODIMP nsWindow::WidgetToScreen(const nsRect& aOldRect, nsRect& aNewRect)
00518 {
00519   nscoord x;
00520   nscoord y;
00521 
00522   aNewRect.width = aOldRect.width;
00523   aNewRect.height = aOldRect.height;
00524 
00525   if (!GetWindowPos(x, y))
00526     return NS_ERROR_FAILURE;
00527  
00528   aNewRect.x = x + aOldRect.x;
00529   aNewRect.y = y + aOldRect.y;
00530 
00531   return NS_OK;
00532 }
00533 
00534 // this is the function that will destroy the native windows for this widget.
00535  
00536 /* virtual */
00537 void
00538 nsWindow::DestroyNative(void)
00539 {
00540   // destroy all of the children that are nsWindow() classes
00541   // preempting the gdk destroy system.
00542   DestroyNativeChildren();
00543 
00544 #ifdef USE_XIM
00545   IMEDestroyIC();
00546 #endif // USE_XIM 
00547 
00548   if (mSuperWin) {
00549     // remove the key from the hash table for the shell_window
00550     g_hash_table_remove(mWindowLookupTable, mSuperWin->shell_window);
00551   }
00552 
00553   if (mShell) {
00554     gtk_widget_destroy(mShell);
00555     mShell = nsnull;
00556     // the moz area and superwin will have been destroyed when we destroyed the shell
00557     mMozArea = nsnull;
00558     mSuperWin = nsnull;
00559   }
00560   else if(mMozArea) {
00561     // We will get here if the widget was created as the child of a
00562     // GtkContainer.
00563     gtk_widget_destroy(mMozArea);
00564     mMozArea = nsnull;
00565     mSuperWin = nsnull;
00566   }
00567   else if(mSuperWin) {
00568     gtk_object_unref(GTK_OBJECT(mSuperWin));
00569     mSuperWin = NULL;
00570   }
00571 }
00572 
00573 // this function will walk the list of children and destroy them.
00574 // the reason why this is here is that because of the superwin code
00575 // it's very likely that we will never get notification of the
00576 // the destruction of the child windows.  so, we have to beat the
00577 // layout engine to the punch.  CB 
00578 
00579 void
00580 nsWindow::DestroyNativeChildren(void)
00581 {
00582 
00583   Display     *display;
00584   Window       window;
00585   Window       root_return;
00586   Window       parent_return;
00587   Window      *children_return = NULL;
00588   unsigned int nchildren_return = 0;
00589   unsigned int i = 0;
00590 
00591   if (mSuperWin)
00592   {
00593     display = GDK_DISPLAY();
00594     window = GDK_WINDOW_XWINDOW(mSuperWin->bin_window);
00595     if (window && !((GdkWindowPrivate *)mSuperWin->bin_window)->destroyed)
00596     {
00597       // get a list of children for this window
00598       XQueryTree(display, window, &root_return, &parent_return,
00599                  &children_return, &nchildren_return);
00600       // walk the list of children
00601       for (i=0; i < nchildren_return; i++)
00602       {
00603         Window child_window = children_return[i];
00604         nsWindow *thisWindow = GetnsWindowFromXWindow(child_window);
00605         if (thisWindow)
00606         {
00607           thisWindow->Destroy();
00608         }
00609       }      
00610     }
00611   }
00612 
00613   // free up this struct
00614   if (children_return)
00615     XFree(children_return);
00616 }
00617 
00618 // This function will try to take a given native X window and try 
00619 // to find the nsWindow * class that has it corresponds to.
00620 
00621 /* static */
00622 nsWindow *
00623 nsWindow::GetnsWindowFromXWindow(Window aWindow)
00624 {
00625   GdkWindow *thisWindow = NULL;
00626 
00627   thisWindow = gdk_window_lookup(aWindow);
00628 
00629   if (!thisWindow)
00630   {
00631     return NULL;
00632   }
00633   gpointer data = NULL;
00634   // see if this is a real widget
00635   gdk_window_get_user_data(thisWindow, &data);
00636   if (data)
00637   {
00638     if (GTK_IS_OBJECT(data))
00639     {
00640       return (nsWindow *)gtk_object_get_data(GTK_OBJECT(data), "nsWindow");
00641     }
00642     else
00643     {
00644       return NULL;
00645     }
00646   }
00647   else
00648   {
00649     // ok, see if it's a shell window
00650     nsWindow *childWindow = (nsWindow *)g_hash_table_lookup(nsWindow::mWindowLookupTable,
00651                                                             thisWindow);
00652     if (childWindow)
00653     {
00654       return childWindow;
00655     }
00656   }
00657   // shouldn't ever get here but just to make the compiler happy...
00658   return NULL;
00659 }
00660 
00661 // given an origin window and inner window ( can be the same ) 
00662 // this function will find the innermost window in the 
00663 // window tree that fits inside of the coordinates
00664 // the depth is how deep we are in the tree and really
00665 // is for debugging...
00666 
00667 /* static */
00668 Window
00669 nsWindow::GetInnerMostWindow(Window aOriginWindow,
00670                              Window aWindow,
00671                              nscoord x, nscoord y,
00672                              nscoord *retx, nscoord *rety,
00673                              int depth)
00674 {
00675 
00676   Display     *display;
00677   Window       window;
00678   Window       root_return;
00679   Window       parent_return;
00680   Window      *children_return = NULL;
00681   unsigned int nchildren_return;
00682   unsigned int i;
00683   Window       returnWindow = None;
00684   
00685   display = GDK_DISPLAY();
00686   window = aWindow;
00687 
00688 #ifdef DEBUG_DND_XLATE
00689   printDepth(depth);
00690   g_print("Finding children for 0x%lx\n", aWindow);
00691 #endif
00692 
00693   // get a list of children for this window
00694   XQueryTree(display, window, &root_return, &parent_return,
00695              &children_return, &nchildren_return);
00696   
00697 #ifdef DEBUG_DND_XLATE
00698   printDepth(depth);
00699   g_print("Found %d children\n", nchildren_return);
00700 #endif
00701 
00702   // walk the list looking for someone who matches the coords
00703 
00704   for (i=0; i < nchildren_return; i++)
00705   {
00706     Window src_w = aOriginWindow;
00707     Window dest_w = children_return[i];
00708     int  src_x = x;
00709     int  src_y = y;
00710     int  dest_x_return, dest_y_return;
00711     Window child_return;
00712     
00713 #ifdef DEBUG_DND_XLATE
00714     printDepth(depth);
00715     g_print("Checking window 0x%lx with coords %d %d\n", dest_w,
00716             src_x, src_y);
00717 #endif
00718     if (XTranslateCoordinates(display, src_w, dest_w,
00719                               src_x, src_y,
00720                               &dest_x_return, &dest_y_return,
00721                               &child_return))
00722     {
00723       int x_return, y_return;
00724       unsigned int width_return, height_return;
00725       unsigned int border_width_return;
00726       unsigned int depth_return;
00727 
00728       // get the parent window's geometry
00729       XGetGeometry(display, src_w, &root_return, &x_return, &y_return,
00730                    &width_return, &height_return, &border_width_return,
00731                    &depth_return);
00732 
00733 #ifdef DEBUG_DND_XLATE
00734       printDepth(depth);
00735       g_print("parent has geo %d %d %d %d\n",
00736               x_return, y_return, width_return, height_return);
00737 #endif
00738 
00739       // get the child window's geometry
00740       XGetGeometry(display, dest_w, &root_return, &x_return, &y_return,
00741                    &width_return, &height_return, &border_width_return,
00742                    &depth_return);
00743 
00744 #ifdef DEBUG_DND_XLATE
00745       printDepth(depth);
00746       g_print("child has geo %d %d %d %d\n",
00747               x_return, y_return, width_return, height_return);
00748       printDepth(depth);
00749       g_print("coords are %d %d in child window's geo\n",
00750               dest_x_return, dest_y_return);
00751 #endif
00752 
00753       int x_offset = width_return;
00754       int y_offset = height_return;
00755       x_offset -= dest_x_return;
00756       y_offset -= dest_y_return;
00757 #ifdef DEBUG_DND_XLATE
00758       printDepth(depth);
00759       g_print("offsets are %d %d\n", x_offset, y_offset);
00760 #endif
00761       // does this child exist within the x,y coords?
00762       if ((dest_x_return > 0) && (dest_y_return > 0) &&
00763           (y_offset > 0) && (x_offset > 0))
00764       {
00765         // set our return window to this dest
00766         returnWindow = dest_w;
00767         // set the coords that we are going to return to the coords that we got above.
00768         *retx = dest_x_return;
00769         *rety = dest_y_return;
00770         // check to see if there's a more inner window that is
00771         // also within these coords
00772         Window tempWindow = None;
00773         tempWindow = GetInnerMostWindow(aOriginWindow, dest_w, x, y, retx, rety, (depth + 1));
00774         if (tempWindow != None)
00775           returnWindow = tempWindow;
00776         goto finishedWalk;
00777       }
00778       
00779     }
00780     else
00781     {
00782       g_assert("XTranslateCoordinates failed!\n");
00783     }
00784   }
00785   
00786  finishedWalk:
00787 
00788   // free up the list of children
00789   if (children_return)
00790     XFree(children_return);
00791 
00792   return returnWindow;
00793 }
00794 
00795 // Routines implementing an update queue.
00796 // We keep a single queue for all widgets because it is 
00797 // (most likely) more efficient and better looking to handle
00798 // all the updates in one shot. Actually, this queue should
00799 // be at most per-toplevel. FIXME.
00800 //
00801 
00802 static GSList *update_queue = NULL;
00803 static guint update_idle = 0;
00804 
00805 gboolean 
00806 nsWindow::UpdateIdle (gpointer data)
00807 {
00808   GSList *old_queue = update_queue;
00809   GSList *it;
00810   
00811   update_idle = 0;
00812   update_queue = nsnull;
00813   
00814   for (it = old_queue; it; it = it->next)
00815   {
00816     nsWindow *window = (nsWindow *)it->data;
00817     window->mIsUpdating = PR_FALSE;
00818   }
00819   
00820   for (it = old_queue; it; it = it->next)
00821   {
00822     nsWindow *window = (nsWindow *)it->data;
00823     window->Update();
00824   }
00825   
00826   g_slist_free (old_queue);
00827   
00828   return PR_FALSE;
00829 }
00830 
00831 void
00832 nsWindow::QueueDraw ()
00833 {
00834   if (!mIsUpdating)
00835   {
00836     update_queue = g_slist_prepend (update_queue, (gpointer)this);
00837     if (!update_idle)
00838       update_idle = g_idle_add_full (G_PRIORITY_HIGH_IDLE, 
00839                                      UpdateIdle,
00840                                      NULL, (GDestroyNotify)NULL);
00841     mIsUpdating = PR_TRUE;
00842   }
00843 }
00844 
00845 void
00846 nsWindow::UnqueueDraw ()
00847 {
00848   if (mIsUpdating)
00849   {
00850     update_queue = g_slist_remove (update_queue, (gpointer)this);
00851     mIsUpdating = PR_FALSE;
00852   }
00853 }
00854 
00855 void 
00856 nsWindow::DoPaint (nsIRegion *aClipRegion)
00857 {
00858   if (!mEventCallback)
00859     return;
00860 
00861   // Don't paint anything if our window isn't visible.
00862   if (!mSuperWin)
00863     return;
00864 
00865   if (mSuperWin->visibility == GDK_VISIBILITY_FULLY_OBSCURED) {
00866     // if our window has translucent pixels, then we can't trust the obscured
00867     // check; it's possible that no pixels of the window are *currently* showing,
00868     // but maybe after the paint new non-transparent pixels will appear in visible
00869     // positions.
00870     PRBool isTranslucent;
00871     GetWindowTranslucency(isTranslucent);
00872     if (!isTranslucent)
00873       return;
00874   }
00875 
00876   nsCOMPtr<nsIRenderingContext> rc = getter_AddRefs(GetRenderingContext());
00877   if (!rc)
00878     return;
00879 
00880 // defining NS_PAINT_SEPARATELY is useful for debugging invalidation
00881 // problems since it limits repainting to the rects that were actually
00882 // invalidated.
00883 #undef  NS_PAINT_SEPARATELY
00884 
00885 #ifdef NS_PAINT_SEPARATELY
00886   nsRegionRectSet *regionRectSet = nsnull;
00887   aClipRegion->GetRects(&regionRectSet);
00888   for (nsRegionRect *r = regionRectSet->mRects,
00889                 *r_end = r + regionRectSet->mNumRects; r < r_end; ++r) {
00890   nsRect boundsRect(r->x, r->y, r->width, r->height);
00891 #else
00892   nsRect boundsRect;
00893   aClipRegion->GetBoundingBox(&boundsRect.x, &boundsRect.y, &boundsRect.width, &boundsRect.height);
00894 #endif
00895 
00896   nsPaintEvent event(PR_TRUE, NS_PAINT, this);
00897   event.renderingContext = rc;
00898   event.time = GDK_CURRENT_TIME; // No time in EXPOSE events
00899   event.rect = &boundsRect;
00900   
00901 #ifdef DEBUG
00902   GdkWindow *gw = GetRenderWindow(GTK_OBJECT(mSuperWin));
00903   if (WANT_PAINT_FLASHING && gw)
00904     {
00905       GdkRegion *region;
00906       aClipRegion->GetNativeRegion(*(void**)&region);
00907       nsGtkUtils::gdk_window_flash(gw,1,100000,region);
00908     }
00909 
00910   // Check the pref _before_ checking caps lock, because checking
00911   // caps lock requires a server round-trip.
00912   if (debug_GetCachedBoolPref("nglayout.debug.paint_dumping") && CAPS_LOCK_IS_ON)
00913     debug_DumpPaintEvent(stdout, this, &event, 
00914                          debug_GetName(GTK_OBJECT(mSuperWin)),
00915                          (PRInt32) debug_GetRenderXID(GTK_OBJECT(mSuperWin)));
00916 #endif // DEBUG
00917 
00918   DispatchWindowEvent(&event);
00919 #ifdef NS_PAINT_SEPARATELY
00920   }
00921 #endif
00922 }
00923 
00924 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
00925 
00926 NS_IMETHODIMP nsWindow::Update(void)
00927 {
00928   if (!mSuperWin)               // XXX ???
00929     return NS_OK;
00930 
00931   if (mIsUpdating)
00932     UnqueueDraw();
00933 
00934   if (!mUpdateArea->IsEmpty()) {
00935     // Watch out for updates occuring during DoPaint. We must clear
00936     // mUpdateArea before we go into DoPaint.
00937     nsCOMPtr<nsIRegion> updateArea = mUpdateArea;
00938     mUpdateArea = do_CreateInstance(kRegionCID);
00939     if (mUpdateArea) {
00940       mUpdateArea->Init();
00941       mUpdateArea->SetTo(0, 0, 0, 0);
00942     }
00943     
00944     DoPaint(updateArea);
00945   } else {
00946     //  g_print("nsWidget::Update(this=%p): avoided update of empty area\n", this);
00947   }
00948 
00949   // While I'd think you should NS_RELEASE(aPaintEvent.widget) here,
00950   // if you do, it is a NULL pointer.  Not sure where it is getting
00951   // released.
00952   return NS_OK;
00953 }
00954 
00955 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
00956                                             PRBool aDoCapture,
00957                                             PRBool aConsumeRollupEvent)
00958 {
00959   GtkWidget *grabWidget;
00960 
00961   grabWidget = mWidget;
00962   // XXX we need a visible widget!!
00963 
00964   if (aDoCapture) {
00965 
00966     if (mSuperWin) {
00967 
00968       // real grab is only done when there is no dragging
00969       if (!nsWindow::DragInProgress()) {
00970         NativeGrab(PR_TRUE);
00971 
00972         sIsGrabbing = PR_TRUE;
00973         sGrabWindow = this;
00974       }
00975     }
00976 
00977     gRollupListener = aListener;
00978     gRollupWidget = do_GetWeakReference(NS_STATIC_CAST(nsIWidget*,this));
00979   } else {
00980     // make sure that the grab window is marked as released
00981     if (sGrabWindow == this) {
00982       sGrabWindow = NULL;
00983     }
00984     sIsGrabbing = PR_FALSE;
00985 
00986     if (!nsWindow::DragInProgress())
00987       NativeGrab(PR_FALSE);
00988     gRollupListener = nsnull;
00989     gRollupWidget = nsnull;
00990   }
00991   
00992   return NS_OK;
00993 }
00994 
00995 // this function is the function that actually does the native window
00996 // grab passing in PR_TRUE will activate the grab, PR_FALSE will
00997 // release the grab
00998 
00999 void nsWindow::NativeGrab(PRBool aGrab)
01000 {
01001   // unconditionally reset our state
01002   mLastGrabFailed = PR_FALSE;
01003 
01004   if (aGrab) {
01005     DropMotionTarget();
01006     gint retval;
01007     retval = gdk_pointer_grab (GDK_SUPERWIN(mSuperWin)->bin_window, PR_TRUE, (GdkEventMask)
01008                                (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
01009                                 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
01010                                 GDK_POINTER_MOTION_MASK),
01011                                (GdkWindow*)NULL, NULL, GDK_CURRENT_TIME);
01012 #ifdef DEBUG_GRAB
01013     printf("nsWindow::NativeGrab %p pointer_grab %d\n", this, retval);
01014 #endif
01015     // check and set our flag if the grab failed
01016     if (retval != 0)
01017       mLastGrabFailed = PR_TRUE;
01018 
01019     if (mTransientParent)
01020       retval = nsXKBModeSwitch::GrabKeyboard(GTK_WIDGET(mTransientParent)->window,
01021                                  PR_TRUE, GDK_CURRENT_TIME);
01022     else
01023       retval = nsXKBModeSwitch::GrabKeyboard(mSuperWin->bin_window,
01024                                  PR_TRUE, GDK_CURRENT_TIME);
01025 #ifdef DEBUG_GRAB
01026     printf("nsWindow::NativeGrab %p keyboard_grab %d\n", this, retval);
01027 #endif
01028     // check and set our flag if the grab failed
01029     if (retval != 0)
01030       mLastGrabFailed = PR_TRUE;
01031 
01032     // make sure to add outselves as the grab window
01033     gtk_grab_add(GetOwningWidget());
01034   } else {
01035 #ifdef DEBUG_GRAB
01036     printf("nsWindow::NativeGrab %p ungrab\n", this);
01037 #endif
01038     nsXKBModeSwitch::UnGrabKeyboard(GDK_CURRENT_TIME);
01039     gtk_grab_remove(GetOwningWidget());
01040     DropMotionTarget();
01041     gdk_pointer_ungrab(GDK_CURRENT_TIME);
01042     
01043     // Unlock CDE if something is deadlock
01044     gdk_flush();
01045   }
01046 }
01047 
01048 NS_IMETHODIMP nsWindow::Validate()
01049 {
01050   if (mIsUpdating) {
01051     mUpdateArea->SetTo(0, 0, 0, 0);
01052     UnqueueDraw();
01053   }
01054   return NS_OK;
01055 }
01056 
01057 NS_IMETHODIMP nsWindow::Invalidate(PRBool aIsSynchronous)
01058 {
01059 
01060   if (!mSuperWin)
01061     return NS_OK;
01062   
01063   mUpdateArea->SetTo(0, 0, mBounds.width, mBounds.height);
01064   
01065   if (aIsSynchronous)
01066     Update();
01067   else
01068     QueueDraw();
01069   
01070   return NS_OK;
01071 }
01072 
01073 NS_IMETHODIMP nsWindow::Invalidate(const nsRect &aRect, PRBool aIsSynchronous)
01074 {
01075 
01076   if (!mSuperWin)
01077     return NS_OK;
01078 
01079   mUpdateArea->Union(aRect.x, aRect.y, aRect.width, aRect.height);
01080 
01081   if (aIsSynchronous)
01082     Update();
01083   else
01084     QueueDraw();
01085   
01086   return NS_OK;
01087 }
01088 
01089 NS_IMETHODIMP nsWindow::InvalidateRegion(const nsIRegion* aRegion, PRBool aIsSynchronous)
01090 {
01091 
01092   if (!mSuperWin)
01093     return NS_OK;
01094   
01095   mUpdateArea->Union(*aRegion);
01096 
01097   if (aIsSynchronous)
01098     Update();
01099   else
01100     QueueDraw();
01101   
01102   return NS_OK;
01103 }
01104 
01105 NS_IMETHODIMP nsWindow::SetBackgroundColor(const nscolor &aColor)
01106 {
01107   nsBaseWidget::SetBackgroundColor(aColor);
01108 
01109   if (nsnull != mSuperWin) {
01110     GdkColor back_color;
01111 
01112     back_color.pixel = ::gdk_rgb_xpixel_from_rgb(NS_TO_GDK_RGB(aColor));
01113 
01114     gdk_window_set_background(mSuperWin->bin_window, &back_color); 
01115   }
01116 
01117   return NS_OK;
01118 }
01119 
01120 //-------------------------------------------------------------------------
01121 //
01122 // Set this component cursor
01123 //
01124 //-------------------------------------------------------------------------
01125 NS_IMETHODIMP nsWindow::SetCursor(nsCursor aCursor)
01126 {
01127   if (!mSuperWin) 
01128     /* These cases should agree with enum nsCursor in nsIWidget.h
01129      * We're limited to those cursors available with XCreateFontCursor()
01130      * If you change these, change them in gtk/nsWidget, too. */
01131     return NS_ERROR_FAILURE;
01132 
01133   // if we're not the toplevel window pass up the cursor request to
01134   // the toplevel window to handle it.
01135   if (!mMozArea)
01136     return GetOwningWindow()->SetCursor(aCursor);
01137 
01138   // Only change cursor if it's changing
01139   if (aCursor != mCursor) {
01140     GdkCursor *newCursor = 0;
01141 
01142     newCursor = GtkCreateCursor(aCursor);
01143 
01144     if (nsnull != newCursor) {
01145       mCursor = aCursor;
01146       ::gdk_window_set_cursor(mSuperWin->shell_window, newCursor);
01147       XFlush(GDK_DISPLAY());
01148     }
01149   }
01150   return NS_OK;
01151 }
01152 
01153 GdkCursor *nsWindow::GtkCreateCursor(nsCursor aCursorType)
01154 {
01155   GdkPixmap *cursor;
01156   GdkPixmap *mask;
01157   GdkColor fg, bg;
01158   GdkCursor *gdkcursor = nsnull;
01159   PRUint8 newType = 0xff;
01160 
01161   if ((gdkcursor = gsGtkCursorCache[aCursorType])) {
01162 #ifdef DEBUG_CURSORCACHE
01163     printf("cached cursor found: %p\n", gdkcursor);
01164 #endif
01165     return gdkcursor;
01166   }
01167 
01168   switch (aCursorType) {
01169     case eCursor_standard:
01170       gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
01171       break;
01172     case eCursor_wait:
01173       gdkcursor = gdk_cursor_new(GDK_WATCH);
01174       break;
01175     case eCursor_select:
01176       gdkcursor = gdk_cursor_new(GDK_XTERM);
01177       break;
01178     case eCursor_hyperlink:
01179       gdkcursor = gdk_cursor_new(GDK_HAND2);
01180       break;
01181     case eCursor_n_resize:
01182       gdkcursor = gdk_cursor_new(GDK_TOP_SIDE);
01183       break;
01184     case eCursor_s_resize:
01185       gdkcursor = gdk_cursor_new(GDK_BOTTOM_SIDE);
01186       break;
01187     case eCursor_w_resize:
01188       gdkcursor = gdk_cursor_new(GDK_LEFT_SIDE);
01189       break;
01190     case eCursor_e_resize:
01191       gdkcursor = gdk_cursor_new(GDK_RIGHT_SIDE);
01192       break;
01193     case eCursor_nw_resize:
01194       gdkcursor = gdk_cursor_new(GDK_TOP_LEFT_CORNER);
01195       break;
01196     case eCursor_se_resize:
01197       gdkcursor = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER);
01198       break;
01199     case eCursor_ne_resize:
01200       gdkcursor = gdk_cursor_new(GDK_TOP_RIGHT_CORNER);
01201       break;
01202     case eCursor_sw_resize:
01203       gdkcursor = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER);
01204       break;
01205     case eCursor_crosshair:
01206       gdkcursor = gdk_cursor_new(GDK_CROSSHAIR);
01207       break;
01208     case eCursor_move:
01209       gdkcursor = gdk_cursor_new(GDK_FLEUR);
01210       break;
01211     case eCursor_help:
01212       newType = MOZ_CURSOR_QUESTION_ARROW;
01213       break;
01214     case eCursor_copy: // CSS3
01215       newType = MOZ_CURSOR_COPY;
01216       break;
01217     case eCursor_alias:
01218       newType = MOZ_CURSOR_ALIAS;
01219       break;
01220     case eCursor_context_menu:
01221       newType = MOZ_CURSOR_CONTEXT_MENU;
01222       break;
01223     case eCursor_cell:
01224       gdkcursor = gdk_cursor_new(GDK_PLUS);
01225       break;
01226     case eCursor_grab:
01227       newType = MOZ_CURSOR_HAND_GRAB;
01228       break;
01229     case eCursor_grabbing:
01230       newType = MOZ_CURSOR_HAND_GRABBING;
01231       break;
01232     case eCursor_spinning:
01233       newType = MOZ_CURSOR_SPINNING;
01234       break;
01235     case eCursor_zoom_in:
01236       newType = MOZ_CURSOR_ZOOM_IN;
01237       break;
01238     case eCursor_zoom_out:
01239       newType = MOZ_CURSOR_ZOOM_OUT;
01240       break;
01241     case eCursor_not_allowed:
01242     case eCursor_no_drop:
01243       newType = MOZ_CURSOR_NOT_ALLOWED;
01244       break;
01245     case eCursor_col_resize:
01246       newType = MOZ_CURSOR_COL_RESIZE;
01247       break;
01248     case eCursor_row_resize:
01249       newType = MOZ_CURSOR_ROW_RESIZE;
01250       break;
01251     case eCursor_vertical_text:
01252       newType = MOZ_CURSOR_VERTICAL_TEXT;
01253       break;
01254     case eCursor_all_scroll:
01255       gdkcursor = gdk_cursor_new(GDK_FLEUR);
01256       break;
01257     case eCursor_nesw_resize:
01258       newType = MOZ_CURSOR_NESW_RESIZE;
01259       break;
01260     case eCursor_nwse_resize:
01261       newType = MOZ_CURSOR_NWSE_RESIZE;
01262       break;
01263     case eCursor_ns_resize:
01264       gdkcursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW);
01265       break;
01266     case eCursor_ew_resize:
01267       gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW);
01268       break;
01269     default:
01270       NS_ASSERTION(aCursorType, "Invalid cursor type");
01271       gdkcursor = gdk_cursor_new(GDK_LEFT_PTR);
01272       break;
01273   }
01274 
01275   /* if by now we dont have a xcursor, this means we have to make a custom one */
01276   if (newType != 0xff) {
01277     gdk_color_parse("#000000", &fg);
01278     gdk_color_parse("#ffffff", &bg);
01279 
01280     cursor = gdk_bitmap_create_from_data(NULL,
01281                                          (char *)GtkCursors[newType].bits,
01282                                          32, 32);
01283     mask   = gdk_bitmap_create_from_data(NULL,
01284                                          (char *)GtkCursors[newType].mask_bits,
01285                                          32, 32);
01286 
01287     gdkcursor = gdk_cursor_new_from_pixmap(cursor, mask, &fg, &bg,
01288                                            GtkCursors[newType].hot_x,
01289                                            GtkCursors[newType].hot_y);
01290 
01291     gdk_bitmap_unref(mask);
01292     gdk_bitmap_unref(cursor);
01293   }
01294 
01295 #ifdef DEBUG_CURSORCACHE
01296   printf("inserting cursor into the cache: %p\n", gdkcursor);
01297 #endif
01298   gsGtkCursorCache[aCursorType] = gdkcursor;
01299 
01300   return gdkcursor;
01301 }
01302 
01303 NS_IMETHODIMP
01304 nsWindow::Enable(PRBool aState)
01305 {
01306   GtkWidget *top_mozarea = GetOwningWidget();
01307   GtkWindow *top_window = GTK_WINDOW(gtk_widget_get_toplevel(top_mozarea));
01308 
01309   if (aState) {
01310     gtk_widget_set_sensitive(top_mozarea, TRUE);
01311     // See if now that we're sensitive again check to see if we need
01312     // to reset ourselves the default focus widget for the toplevel
01313     // window.  We should only do that if there is no focus widget
01314     // since someone else might have taken the focus while we were
01315     // disabled, and stealing focus is rude!
01316     if (mRestoreFocus && !top_window->focus_widget) {
01317       gtk_window_set_focus(top_window, top_mozarea);
01318     }
01319     mRestoreFocus = PR_FALSE;
01320   }
01321   else {
01322     // Setting the window insensitive below will remove the window
01323     // focus widget so we will have to restore it when we are
01324     // reenabled.  Of course, because of embedding, we might not
01325     // actually _be_ the widget with focus, so keep that in mind.
01326     if (top_window->focus_widget == top_mozarea) {
01327       mRestoreFocus = PR_TRUE;
01328     }
01329     gtk_widget_set_sensitive(top_mozarea, FALSE);
01330   }
01331 
01332   return NS_OK;
01333 }
01334 
01335 NS_IMETHODIMP
01336 nsWindow::IsEnabled(PRBool *aState)
01337 {
01338   NS_ENSURE_ARG_POINTER(aState);
01339 
01340   *aState = !mMozArea || GTK_WIDGET_IS_SENSITIVE(mMozArea);
01341 
01342   return NS_OK;
01343 }
01344 
01345 NS_IMETHODIMP
01346 nsWindow::SetFocus(PRBool aRaise)
01347 {
01348 #ifdef DEBUG_FOCUS
01349   printf("nsWindow::SetFocus %p\n", NS_STATIC_CAST(void *, this));
01350 #endif /* DEBUG_FOCUS */
01351 
01352   GtkWidget *top_mozarea = GetOwningWidget();
01353   GtkWidget *toplevel = nsnull;
01354 
01355   if (top_mozarea)
01356     toplevel = gtk_widget_get_toplevel(top_mozarea);
01357 
01358   // map the window if the pref says to and neither the mozarea or its
01359   // toplevel window has focus
01360   if (gRaiseWindows && aRaise && toplevel && top_mozarea &&
01361       (!GTK_WIDGET_HAS_FOCUS(top_mozarea) && !GTK_WIDGET_HAS_FOCUS(toplevel)))
01362     GetAttention(-1);
01363 
01364 #ifdef DEBUG_FOCUS
01365   printf("top moz area is %p\n", NS_STATIC_CAST(void *, top_mozarea));
01366 #endif
01367 
01368   // see if the toplevel window has focus
01369   gboolean toplevel_focus =
01370     gtk_mozarea_get_toplevel_focus(GTK_MOZAREA(top_mozarea));
01371 
01372   // we need to grab focus or make sure that we get focus the next
01373   // time that the toplevel gets focus.
01374   if (top_mozarea && !GTK_WIDGET_HAS_FOCUS(top_mozarea)) {
01375 
01376     gpointer data = gtk_object_get_data(GTK_OBJECT(top_mozarea), "nsWindow");
01377     nsWindow *mozAreaWindow = NS_STATIC_CAST(nsWindow *, data);
01378     mozAreaWindow->mBlockMozAreaFocusIn = PR_TRUE;
01379     gtk_widget_grab_focus(top_mozarea);
01380     mozAreaWindow->mBlockMozAreaFocusIn = PR_FALSE;
01381 
01382     // !!hack alert!!  This works around bugs in version of gtk older
01383     // than 1.2.9, which is what most people use.  If the toplevel
01384     // window doesn't have focus then we have to unset the focus flag
01385     // on this widget since it was probably just set incorrectly.
01386     if (!toplevel_focus)
01387       GTK_WIDGET_UNSET_FLAGS(top_mozarea, GTK_HAS_FOCUS);
01388     
01389     // always dispatch a set focus event
01390     DispatchSetFocusEvent();
01391     return NS_OK;
01392   }
01393 
01394   if (mHasFocus)
01395   {
01396 #ifdef DEBUG_FOCUS
01397     printf("Returning: Already have focus.\n");
01398 #endif /* DEBUG_FOCUS */
01399     return NS_OK;
01400   }
01401 
01402   // check to see if we need to send a focus out event for the old window
01403   if (sFocusWindow)
01404   {
01405     // let the current window loose its focus
01406     sFocusWindow->DispatchLostFocusEvent();
01407     sFocusWindow->LoseFocus();
01408   }
01409 
01410   // set the focus window to this window
01411 
01412   sFocusWindow = this;
01413   mHasFocus = PR_TRUE;
01414 
01415 #ifdef USE_XIM
01416   IMESetFocusWindow();
01417 #endif // USE_XIM 
01418 
01419   DispatchSetFocusEvent();
01420 
01421 #ifdef DEBUG_FOCUS
01422   printf("Returning:\n");
01423 #endif
01424 
01425   return NS_OK;
01426 }
01427 
01428 /* virtual */ void
01429 nsWindow::LoseFocus(void)
01430 {
01431   // doesn't do anything.  needed for nsWindow housekeeping, really.
01432   if (mHasFocus == PR_FALSE)
01433     return;
01434 
01435 #ifdef USE_XIM
01436   IMEUnsetFocusWindow();
01437 #endif // USE_XIM
01438   
01439   sFocusWindow = 0;
01440   mHasFocus = PR_FALSE;
01441 
01442 }
01443 
01444 void nsWindow::DispatchSetFocusEvent(void)
01445 {
01446 #ifdef DEBUG_FOCUS
01447   printf("nsWindow::DispatchSetFocusEvent %p\n", NS_STATIC_CAST(void *, this));
01448 #endif /* DEBUG_FOCUS */
01449 
01450   nsGUIEvent event(PR_TRUE, NS_GOTFOCUS, this);
01451 
01452   NS_ADDREF_THIS();
01453   DispatchFocus(event);
01454 
01455   if (gJustGotActivate) {
01456     gJustGotActivate = PR_FALSE;
01457     DispatchActivateEvent();
01458   }
01459 
01460   NS_RELEASE_THIS();
01461 }
01462 
01463 void nsWindow::DispatchLostFocusEvent(void)
01464 {
01465 
01466 #ifdef DEBUG_FOCUS
01467   printf("nsWindow::DispatchLostFocusEvent %p\n", NS_STATIC_CAST(void *, this));
01468 #endif /* DEBUG_FOCUS */
01469 
01470   nsGUIEvent event(PR_TRUE, NS_LOSTFOCUS, this);
01471 
01472   NS_ADDREF_THIS();
01473   
01474   DispatchFocus(event);
01475   
01476   NS_RELEASE_THIS();
01477 }
01478 
01479 void nsWindow::DispatchActivateEvent(void)
01480 {
01481 #ifdef DEBUG_FOCUS
01482   printf("nsWindow::DispatchActivateEvent %p\n", NS_STATIC_CAST(void *, this));
01483 #endif
01484 
01485 #ifdef USE_XIM
01486   IMEBeingActivate(PR_TRUE);
01487 #endif // USE_XIM
01488 
01489   gJustGotDeactivate = PR_FALSE;
01490 
01491   nsGUIEvent event(PR_TRUE, NS_ACTIVATE, this);
01492 
01493   NS_ADDREF_THIS();  
01494   DispatchFocus(event);
01495   NS_RELEASE_THIS();
01496 
01497 #ifdef USE_XIM
01498   IMEBeingActivate(PR_FALSE);
01499 #endif // USE_XIM
01500 }
01501 
01502 void nsWindow::DispatchDeactivateEvent(void)
01503 {
01504 #ifdef DEBUG_FOCUS
01505   printf("nsWindow::DispatchDeactivateEvent %p\n", 
01506          NS_STATIC_CAST(void *, this));
01507 #endif
01508 #ifdef USE_XIM
01509   IMEBeingActivate(PR_TRUE);
01510 #endif // USE_XIM
01511 
01512   nsGUIEvent event(PR_TRUE, NS_DEACTIVATE, this);
01513 
01514   NS_ADDREF_THIS();
01515   DispatchFocus(event);
01516   NS_RELEASE_THIS();
01517 
01518 #ifdef USE_XIM
01519   IMEBeingActivate(PR_FALSE);
01520 #endif // USE_XIM
01521 }
01522 
01523 // this function is called whenever there's a focus in event on the
01524 // mozarea.
01525 
01526 void nsWindow::HandleMozAreaFocusIn(void)
01527 {
01528   // If we're getting this focus in as a result of a child superwin
01529   // getting called with SetFocus() this flag will be set.  We don't
01530   // want to generate extra focus in events so just return.
01531   if (mBlockMozAreaFocusIn)
01532     return;
01533 
01534   // otherwise, dispatch our focus events
01535 #ifdef DEBUG_FOCUS
01536   printf("nsWindow::HandleMozAreaFocusIn %p\n", NS_STATIC_CAST(void *, this));
01537 #endif
01538   // we only set the gJustGotActivate signal if we're the toplevel
01539   // window.  embedding handles activate semantics for us.
01540   if (mIsToplevel)
01541     gJustGotActivate = PR_TRUE;
01542 
01543 #ifdef USE_XIM
01544   IMESetFocusWindow();
01545 #endif // USE_XIM 
01546 
01547   DispatchSetFocusEvent();
01548 }
01549 
01550 // this function is called whenever there's a focus out event on the
01551 // mozarea.
01552 
01553 void nsWindow::HandleMozAreaFocusOut(void)
01554 {
01555   // otherwise handle our focus out here.
01556 #ifdef DEBUG_FOCUS
01557   printf("nsWindow::HandleMozAreaFocusOut %p\n", NS_STATIC_CAST(void *, this));
01558 #endif
01559   // if there's a window with focus, send a focus out event for that
01560   // window.
01561   if (sFocusWindow)
01562   {
01563     // Figure out of the focus widget is the child of this widget.  If
01564     // it isn't then we don't send the event since it was already sent
01565     // earlier.
01566     PRBool isChild = PR_FALSE;
01567     GdkWindow *window;
01568     window = (GdkWindow *)sFocusWindow->GetNativeData(NS_NATIVE_WINDOW);
01569     while (window)
01570     {
01571       gpointer data = NULL;
01572       gdk_window_get_user_data(window, &data);
01573       if (GTK_IS_MOZAREA(data)) 
01574       {
01575         GtkWidget *tmpMozArea = GTK_WIDGET(data);
01576         if (tmpMozArea == mMozArea)
01577         {
01578           isChild = PR_TRUE;
01579           break;
01580         }
01581       }
01582       window = gdk_window_get_parent(window);
01583     }
01584 
01585     if (isChild)
01586     {
01587       nsWidget *focusWidget = sFocusWindow;
01588       nsCOMPtr<nsIWidget> focusWidgetGuard(focusWidget);
01589 
01590       focusWidget->DispatchLostFocusEvent();
01591       // we only send activate/deactivate events for toplevel windows.
01592       // activation and deactivation is handled by embedders.
01593       if (mIsToplevel)
01594         focusWidget->DispatchDeactivateEvent();
01595       focusWidget->LoseFocus();
01596     }
01597   }
01598 }
01599 
01601 /* virtual */ void
01602 nsWindow::OnMotionNotifySignal(GdkEventMotion *aGdkMotionEvent)
01603 {
01604   XEvent xevent;
01605   GdkEvent gdk_event;
01606   PRBool synthEvent = PR_FALSE;
01607   while (XCheckWindowEvent(GDK_DISPLAY(),
01608                            GDK_WINDOW_XWINDOW(mSuperWin->bin_window),
01609                            ButtonMotionMask, &xevent)) {
01610     synthEvent = PR_TRUE;
01611   }
01612   if (synthEvent) {
01613     gdk_event.type = GDK_MOTION_NOTIFY;
01614     gdk_event.motion.window = aGdkMotionEvent->window;
01615     gdk_event.motion.send_event = aGdkMotionEvent->send_event;
01616     gdk_event.motion.time = xevent.xmotion.time;
01617     gdk_event.motion.x = xevent.xmotion.x;
01618     gdk_event.motion.y = xevent.xmotion.y;
01619     gdk_event.motion.pressure = aGdkMotionEvent->pressure;
01620     gdk_event.motion.xtilt = aGdkMotionEvent->xtilt;
01621     gdk_event.motion.ytilt = aGdkMotionEvent->ytilt;
01622     gdk_event.motion.state = aGdkMotionEvent->state;
01623     gdk_event.motion.is_hint = xevent.xmotion.is_hint;
01624     gdk_event.motion.source = aGdkMotionEvent->source;
01625     gdk_event.motion.deviceid = aGdkMotionEvent->deviceid;
01626     gdk_event.motion.x_root = xevent.xmotion.x_root;
01627     gdk_event.motion.y_root = xevent.xmotion.y_root;
01628     nsWidget::OnMotionNotifySignal(&gdk_event.motion);
01629   }
01630   else {
01631     nsWidget::OnMotionNotifySignal(aGdkMotionEvent);
01632   }
01633 }
01634 
01636 /* virtual */ void
01637 nsWindow::OnEnterNotifySignal(GdkEventCrossing *aGdkCrossingEvent)
01638 {
01639   if (GTK_WIDGET_SENSITIVE(GetOwningWidget())) {
01640     nsWidget::OnEnterNotifySignal(aGdkCrossingEvent);
01641     if (mMozArea) {
01642       GTK_PRIVATE_SET_FLAG(mMozArea, GTK_LEAVE_PENDING);
01643       mLeavePending = PR_TRUE;
01644     }
01645   }
01646 }
01647 
01649 /* virtual */ void
01650 nsWindow::OnLeaveNotifySignal(GdkEventCrossing *aGdkCrossingEvent)
01651 {
01652   if (mMozArea) {
01653     if (mLeavePending) {
01654       GTK_PRIVATE_UNSET_FLAG(mMozArea, GTK_LEAVE_PENDING);
01655       mLeavePending = PR_FALSE;
01656       nsWidget::OnLeaveNotifySignal(aGdkCrossingEvent);
01657     }
01658   } else
01659     nsWidget::OnLeaveNotifySignal(aGdkCrossingEvent);
01660 }
01661 
01663 /* virtual */ void
01664 nsWindow::OnButtonPressSignal(GdkEventButton *aGdkButtonEvent)
01665 {
01666   // This widget has gotten a button press event.  If there's a rollup
01667   // widget and we're not inside of a popup window we should pop up
01668   // the rollup widget.  Also, if the event is our event but it
01669   // happens outside of the bounds of the window we should roll up as
01670   // well.
01671   if (gRollupWidget && ((GetOwningWindowType() != eWindowType_popup) ||
01672                         (mSuperWin->bin_window == aGdkButtonEvent->window &&
01673                          !ButtonEventInsideWindow(aGdkButtonEvent->window,
01674                                                   aGdkButtonEvent)))) {
01675     gRollupListener->Rollup();
01676     gRollupWidget = nsnull;
01677     gRollupListener = nsnull;
01678     return;
01679   }
01680 
01681   nsWidget::OnButtonPressSignal(aGdkButtonEvent);
01682 }
01683 
01685 /* virtual */ void
01686 nsWindow::OnButtonReleaseSignal(GdkEventButton *aGdkButtonEvent)
01687 {
01688   // we only dispatch this event if there's a button motion target or
01689   // if it's happening inside of a popup window while there is a
01690   // rollup widget
01691   if (!sButtonMotionTarget &&
01692       (gRollupWidget && GetOwningWindowType() != eWindowType_popup)) {
01693     return;
01694   }
01695   nsWidget::OnButtonReleaseSignal(aGdkButtonEvent);
01696 }
01697 
01699 /* virtual */ void
01700 nsWindow::OnFocusInSignal(GdkEventFocus * aGdkFocusEvent)
01701 {
01702   
01703   GTK_WIDGET_SET_FLAGS(mMozArea, GTK_HAS_FOCUS);
01704 
01705   nsFocusEvent event(PR_TRUE, NS_GOTFOCUS, this);
01706 #ifdef DEBUG  
01707   printf("send NS_GOTFOCUS from nsWindow::OnFocusInSignal\n");
01708 #endif
01709 
01710 //  event.time = aGdkFocusEvent->time;;
01711 //  event.time = PR_Now();
01712 
01713   AddRef();
01714   
01715   DispatchFocus(event);
01716   
01717   Release();
01718 }
01720 /* virtual */ void
01721 nsWindow::OnFocusOutSignal(GdkEventFocus * aGdkFocusEvent)
01722 {
01723 
01724   GTK_WIDGET_UNSET_FLAGS(mMozArea, GTK_HAS_FOCUS);
01725 
01726   nsFocusEvent event(PR_TRUE, NS_LOSTFOCUS, this);
01727   
01728 //  event.time = aGdkFocusEvent->time;;
01729 //  event.time = PR_Now();
01730 
01731   AddRef();
01732   
01733   DispatchFocus(event);
01734   
01735   Release();
01736 }
01737 
01739 void 
01740 nsWindow::InstallFocusInSignal(GtkWidget * aWidget)
01741 {
01742   NS_ASSERTION( nsnull != aWidget, "widget is null");
01743 
01744   InstallSignal(aWidget,
01745                             (gchar *)"focus_in_event",
01746                             GTK_SIGNAL_FUNC(nsWindow::FocusInSignal));
01747 }
01749 void 
01750 nsWindow::InstallFocusOutSignal(GtkWidget * aWidget)
01751 {
01752   NS_ASSERTION( nsnull != aWidget, "widget is null");
01753 
01754   InstallSignal(aWidget,
01755                             (gchar *)"focus_out_event",
01756                             GTK_SIGNAL_FUNC(nsWindow::FocusOutSignal));
01757 }
01758 
01759 
01760 void 
01761 nsWindow::HandleGDKEvent(GdkEvent *event)
01762 {
01763   if (mIsDestroying)
01764     return;
01765 
01766   switch (event->any.type)
01767   {
01768   case GDK_MOTION_NOTIFY:
01769     // when we receive this, it must be that the gtk dragging is over,
01770     // it is dropped either in or out of mozilla, clear the flag
01771     sIsDraggingOutOf = PR_FALSE;
01772     OnMotionNotifySignal (&event->motion);
01773     break;
01774   case GDK_BUTTON_PRESS:
01775   case GDK_2BUTTON_PRESS:
01776   case GDK_3BUTTON_PRESS:
01777     OnButtonPressSignal (&event->button);
01778     break;
01779   case GDK_BUTTON_RELEASE:
01780     OnButtonReleaseSignal (&event->button);
01781     break;
01782   case GDK_ENTER_NOTIFY:
01783     if(is_parent_ungrab_enter(&event->crossing))
01784       return;
01785 
01786     OnEnterNotifySignal (&event->crossing);
01787     break;
01788   case GDK_LEAVE_NOTIFY:
01789     if(is_parent_grab_leave(&event->crossing))
01790       return;
01791 
01792     OnLeaveNotifySignal (&event->crossing);
01793     break;
01794 
01795   default:
01796     break;
01797   }
01798 }
01799 
01800 void
01801 nsWindow::OnDestroySignal(GtkWidget* aGtkWidget)
01802 {
01803   nsWidget::OnDestroySignal(aGtkWidget);
01804   if (aGtkWidget == mShell) {
01805     mShell = nsnull;
01806   }
01807 }
01808 
01809 gint handle_delete_event(GtkWidget *w, GdkEventAny *e, nsWindow *win)
01810 {
01811 
01812   PRBool isEnabled;
01813   // If this window is disabled, don't dispatch the delete event
01814   win->IsEnabled(&isEnabled);
01815   if (!isEnabled)
01816     return TRUE;
01817 
01818   NS_ADDREF(win);
01819 
01820   // dispatch an "onclose" event. to delete immediately, call win->Destroy()
01821   nsGUIEvent event(PR_TRUE, NS_XUL_CLOSE, win);
01822   nsEventStatus status;
01823   
01824   win->DispatchEvent(&event, status);
01825 
01826   NS_RELEASE(win);
01827   return TRUE;
01828 }
01829 
01830 
01831 
01832 NS_IMETHODIMP nsWindow::PreCreateWidget(nsWidgetInitData *aInitData)
01833 {
01834   if (nsnull != aInitData) {
01835     SetWindowType(aInitData->mWindowType);
01836     SetBorderStyle(aInitData->mBorderStyle);
01837 
01838     return NS_OK;
01839   }
01840   return NS_ERROR_FAILURE;
01841 }
01842 
01843 
01844 gint nsWindow::ConvertBorderStyles(nsBorderStyle bs)
01845 {
01846   gint w = 0;
01847 
01848   if (bs == eBorderStyle_default)
01849     return -1;
01850 
01851   if (bs & eBorderStyle_all)
01852     w |= GDK_DECOR_ALL;
01853   if (bs & eBorderStyle_border)
01854     w |= GDK_DECOR_BORDER;
01855   if (bs & eBorderStyle_resizeh)
01856     w |= GDK_DECOR_RESIZEH;
01857   if (bs & eBorderStyle_title)
01858     w |= GDK_DECOR_TITLE;
01859   if (bs & eBorderStyle_menu)
01860     w |= GDK_DECOR_MENU;
01861   if (bs & eBorderStyle_minimize)
01862     w |= GDK_DECOR_MINIMIZE;
01863   if (bs & eBorderStyle_maximize)
01864     w |= GDK_DECOR_MAXIMIZE;
01865   if (bs & eBorderStyle_close) {
01866 #ifdef DEBUG
01867     printf("we don't handle eBorderStyle_close yet... please fix me\n");
01868 #endif /* DEBUG */
01869   }
01870 
01871   return w;
01872 }
01873 
01874 
01875 //-------------------------------------------------------------------------
01876 //
01877 // Create the native widget
01878 //
01879 //-------------------------------------------------------------------------
01880 
01881 NS_METHOD nsWindow::CreateNative(GtkObject *parentWidget)
01882 {
01883   GdkSuperWin  *superwin = 0;
01884   GdkEventMask  mask;
01885   PRBool        parentIsContainer = PR_FALSE;
01886   GtkContainer *parentContainer = NULL;
01887   GtkWindow    *topLevelParent  = NULL;
01888 
01889   if (parentWidget) {
01890     if (GDK_IS_SUPERWIN(parentWidget)) {
01891       superwin = GDK_SUPERWIN(parentWidget);
01892       GdkWindow *topGDKWindow =
01893         gdk_window_get_toplevel(GDK_SUPERWIN(parentWidget)->shell_window);
01894       gpointer data;
01895       gdk_window_get_user_data(topGDKWindow, &data);
01896       if (GTK_IS_WINDOW(data)) {
01897         topLevelParent = GTK_WINDOW(data);
01898       }
01899     }
01900     else if (GTK_IS_CONTAINER(parentWidget)) {
01901       parentContainer = GTK_CONTAINER(parentWidget);
01902       parentIsContainer = PR_TRUE;
01903       topLevelParent =
01904         GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(parentWidget)));
01905     }
01906     else {
01907       NS_WARNING("Unknown parent widget type");
01908     }
01909   }
01910 
01911   switch(mWindowType)
01912   {
01913   case eWindowType_dialog:
01914     mIsToplevel = PR_TRUE;
01915     mShell = gtk_window_new(GTK_WINDOW_DIALOG);
01916     if (topLevelParent) {
01917       gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent);
01918       mTransientParent = topLevelParent;
01919     }
01920     gtk_window_set_policy(GTK_WINDOW(mShell), PR_TRUE, PR_TRUE, PR_FALSE);
01921     //    gtk_widget_set_app_paintable(mShell, PR_TRUE);
01922     InstallRealizeSignal(mShell);
01923 
01924     // create the mozarea.  this will be the single child of the
01925     // toplevel window
01926     mMozArea = gtk_mozarea_new();
01927     gtk_container_add(GTK_CONTAINER(mShell), mMozArea);
01928     gtk_widget_realize(GTK_WIDGET(mMozArea));
01929     SetIcon(NS_LITERAL_STRING("default"));
01930     mSuperWin = GTK_MOZAREA(mMozArea)->superwin;
01931     // set the back pixmap to None so that we don't get a flash of
01932     // black
01933     gdk_window_set_back_pixmap(mShell->window, NULL, FALSE);
01934 
01935     gtk_signal_connect(GTK_OBJECT(mShell),
01936                        "delete_event",
01937                        GTK_SIGNAL_FUNC(handle_delete_event),
01938                        this);
01939     break;
01940 
01941   case eWindowType_popup:
01942     mIsToplevel = PR_TRUE;
01943     mShell = gtk_window_new(GTK_WINDOW_POPUP);
01944     if (topLevelParent) {
01945       gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent);
01946       mTransientParent = topLevelParent;
01947     }
01948     // create the mozarea.  this will be the single child of the
01949     // toplevel window
01950     mMozArea = gtk_mozarea_new();
01951     gtk_container_add(GTK_CONTAINER(mShell), mMozArea);
01952     gtk_widget_realize(GTK_WIDGET(mMozArea));
01953     mSuperWin = GTK_MOZAREA(mMozArea)->superwin;
01954     // set the back pixmap to None so that we don't get a flash of
01955     // black
01956     gdk_window_set_back_pixmap(mShell->window, NULL, FALSE);
01957 
01958     // gdk does not automatically set the cursor for "temporary"
01959     // windows, which are what gtk uses for popups.
01960 
01961     mCursor = eCursor_wait; // force SetCursor to actually set the cursor,
01962                             // even though our internal state indicates
01963                             // that we already have the standard cursor.
01964     SetCursor(eCursor_standard);
01965 
01966     break;
01967 
01968   case eWindowType_toplevel:
01969   case eWindowType_invisible:
01970     mIsToplevel = PR_TRUE;
01971     mShell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
01972     //    gtk_widget_set_app_paintable(mShell, PR_TRUE);
01973     gtk_window_set_policy(GTK_WINDOW(mShell), PR_TRUE, PR_TRUE, PR_FALSE);
01974     InstallRealizeSignal(mShell);
01975     // create the mozarea.  this will be the single child of the
01976     // toplevel window
01977     mMozArea = gtk_mozarea_new();
01978     gtk_container_add(GTK_CONTAINER(mShell), mMozArea);
01979     gtk_widget_realize(GTK_WIDGET(mMozArea));
01980     SetIcon(NS_LITERAL_STRING("default"));
01981     mSuperWin = GTK_MOZAREA(mMozArea)->superwin;
01982     // set the back pixmap to None so that we don't get a flash of
01983     // black
01984     gdk_window_set_back_pixmap(mShell->window, NULL, FALSE);
01985 
01986     if (!topLevelParent) {
01987       GdkWindow* dialoglead = mShell->window;
01988       gdk_window_set_group(dialoglead, dialoglead);
01989     }
01990     gtk_signal_connect(GTK_OBJECT(mShell),
01991                        "delete_event",
01992                        GTK_SIGNAL_FUNC(handle_delete_event),
01993                        this);
01994     gtk_signal_connect_after(GTK_OBJECT(mShell),
01995                              "size_allocate",
01996                              GTK_SIGNAL_FUNC(handle_size_allocate),
01997                              this);
01998     break;
01999 
02000   case eWindowType_child:
02001     // check to see if we need to create a mozarea for this widget
02002     
02003     if (parentIsContainer) {
02004       // check to make sure that the widget is realized
02005       if (!GTK_WIDGET_REALIZED(parentContainer))
02006         g_print("Warning: The parent container of this widget is not realized.  I'm going to crash very, very soon.\n");
02007       else {
02008         //  create a containg mozarea for the superwin since we've got
02009         //  play nice with the gtk widget system.
02010         mMozArea = gtk_mozarea_new();
02011         gtk_container_add(parentContainer, mMozArea);
02012         gtk_widget_realize(GTK_WIDGET(mMozArea));
02013         mSuperWin = GTK_MOZAREA(mMozArea)->superwin;
02014       }
02015     }
02016     else {
02017       if (superwin) {
02018         mSuperWin = gdk_superwin_new(superwin->bin_window,
02019                                      mBounds.x, mBounds.y,
02020                                      mBounds.width, mBounds.height);
02021         nsWindow* realParent =
02022           NS_STATIC_CAST(nsWindow*, gtk_object_get_data(GTK_OBJECT(superwin), "nsWindow"));
02023         if (realParent && !mParent) {
02024           realParent->mHasAnonymousChildren = PR_TRUE;
02025         }
02026       }
02027     }
02028     break;
02029 
02030   default:
02031     break;
02032   }
02033 
02034   // set up all the focus handling
02035 
02036   if (mShell) {
02037     mask = (GdkEventMask) (GDK_KEY_PRESS_MASK |
02038                            GDK_KEY_RELEASE_MASK |
02039                            GDK_FOCUS_CHANGE_MASK );
02040     gdk_window_set_events(mShell->window, 
02041                           mask);
02042 
02043   }
02044 
02045   if (mMozArea) {
02046     // make sure that the mozarea widget can take the focus
02047     GTK_WIDGET_SET_FLAGS(mMozArea, GTK_CAN_FOCUS);
02048     // If there's a shell too make sure that this widget is the
02049     // default for that window.  We do this here because it has to
02050     // happen after the GTK_CAN_FOCUS flag is set on the widget but
02051     // before we hook up to the signals otherwise we will get spurious
02052     // events.
02053     if (mShell)
02054       gtk_window_set_focus(GTK_WINDOW(mShell), mMozArea);
02055 
02056     // track focus events for the moz area
02057     gtk_signal_connect(GTK_OBJECT(mMozArea),
02058                        "focus_in_event",
02059                        GTK_SIGNAL_FUNC(handle_mozarea_focus_in),
02060                        this);
02061     gtk_signal_connect(GTK_OBJECT(mMozArea),
02062                        "focus_out_event",
02063                        GTK_SIGNAL_FUNC(handle_mozarea_focus_out),
02064                        this);
02065     // Install button press and release signals so in the grab case we
02066     // get the events.
02067     InstallButtonPressSignal(mMozArea);
02068     InstallButtonReleaseSignal(mMozArea);
02069   }
02070 
02071   // end of settup up focus handling
02072 
02073   mask = (GdkEventMask)(GDK_BUTTON_PRESS_MASK |
02074                         GDK_BUTTON_RELEASE_MASK |
02075                         GDK_ENTER_NOTIFY_MASK |
02076                         GDK_LEAVE_NOTIFY_MASK |
02077                         GDK_EXPOSURE_MASK |
02078                         GDK_FOCUS_CHANGE_MASK |
02079                         GDK_KEY_PRESS_MASK |
02080                         GDK_KEY_RELEASE_MASK |
02081                         GDK_POINTER_MOTION_MASK);
02082 
02083 
02084   NS_ASSERTION(mSuperWin,"no super window!");
02085   if (!mSuperWin) return NS_ERROR_FAILURE;
02086 
02087   gdk_window_set_events(mSuperWin->bin_window, 
02088                         mask);
02089 
02090   // set our object data so that we can find the class for this window
02091   gtk_object_set_data (GTK_OBJECT (mSuperWin), "nsWindow", this);
02092   // we want to set this on our moz area and shell too so we can
02093   // always find the nsWindow given a specific GtkWidget *
02094   if (mShell)
02095     gtk_object_set_data(GTK_OBJECT(mShell), "nsWindow", this);
02096   if (mMozArea) {
02097     gtk_object_set_data(GTK_OBJECT(mMozArea), "nsWindow", this);
02098   }
02099   // set user data on the bin_window so we can find the superwin for it.
02100   gdk_window_set_user_data (mSuperWin->bin_window, (gpointer)mSuperWin);
02101 
02102   // unset the back pixmap on this window.
02103   gdk_window_set_back_pixmap(mSuperWin->bin_window, NULL, 0);
02104 
02105   if (mShell) {
02106     // set up our drag and drop for the shell
02107     gtk_drag_dest_set(mShell,
02108                       (GtkDestDefaults)0,
02109                       NULL,
02110                       0,
02111                       (GdkDragAction)0);
02112 
02113     gtk_signal_connect(GTK_OBJECT(mShell),
02114                        "drag_motion",
02115                        GTK_SIGNAL_FUNC(nsWindow::DragMotionSignal),
02116                        this);
02117     gtk_signal_connect(GTK_OBJECT(mShell),
02118                        "drag_leave",
02119                        GTK_SIGNAL_FUNC(nsWindow::DragLeaveSignal),
02120                        this);
02121     gtk_signal_connect(GTK_OBJECT(mShell),
02122                        "drag_drop",
02123                        GTK_SIGNAL_FUNC(nsWindow::DragDropSignal),
02124                        this);
02125     gtk_signal_connect(GTK_OBJECT(mShell),
02126                        "drag_data_received",
02127                        GTK_SIGNAL_FUNC(nsWindow::DragDataReceived),
02128                        this);
02129 
02130     // Also set up client_event handling for theme change notifications
02131     gtk_signal_connect(GTK_OBJECT(mShell),
02132                        "client_event",
02133                        GTK_SIGNAL_FUNC(nsWindow::ClientEventSignal),
02134                        this);
02135   }
02136 
02137   if (mMozArea) {
02138 
02139     // add our key event masks so that we can pass events to the inner
02140     // windows.
02141     mask = (GdkEventMask) ( GDK_EXPOSURE_MASK |
02142                            GDK_KEY_PRESS_MASK |
02143                            GDK_KEY_RELEASE_MASK |
02144                            GDK_ENTER_NOTIFY_MASK |
02145                            GDK_LEAVE_NOTIFY_MASK |
02146                            GDK_STRUCTURE_MASK | 
02147                            GDK_FOCUS_CHANGE_MASK );
02148     gdk_window_set_events(mMozArea->window, 
02149                           mask);
02150     gtk_signal_connect(GTK_OBJECT(mMozArea),
02151                        "key_press_event",
02152                        GTK_SIGNAL_FUNC(handle_key_press_event),
02153                        this);
02154     gtk_signal_connect(GTK_OBJECT(mMozArea),
02155                        "key_release_event",
02156                        GTK_SIGNAL_FUNC(handle_key_release_event),
02157                        this);
02158 
02159     // Connect to the configure event from the mozarea.  This will
02160     // notify us when the toplevel window that contains the mozarea
02161     // changes size so that we can update our size caches.  It handles
02162     // the plug/socket case, too.
02163     gtk_signal_connect(GTK_OBJECT(mMozArea),
02164                        "toplevel_configure",
02165                        GTK_SIGNAL_FUNC(handle_toplevel_configure),
02166                        this);
02167   }
02168 
02169   if (mSuperWin) {
02170     // add the shell_window for this window to the table lookup
02171     // this is so that as part of destruction we can find the superwin
02172     // associated with the window.
02173     g_hash_table_insert(mWindowLookupTable, mSuperWin->shell_window, this);
02174   }
02175 
02176   // Any time the toplevel window invalidates mark ourselves as dirty
02177   // with respect to caching window positions.
02178   GtkWidget *top_mozarea = GetOwningWidget();
02179   if (top_mozarea) {
02180     gtk_signal_connect_while_alive(GTK_OBJECT(top_mozarea),
02181                                    "toplevel_configure",
02182                                    GTK_SIGNAL_FUNC(handle_invalidate_pos),
02183                                    this,
02184                                    GTK_OBJECT(mSuperWin));
02185   }
02186 
02187   return NS_OK;
02188 }
02189 
02190 //-------------------------------------------------------------------------
02191 //
02192 // Initialize all the Callbacks
02193 //
02194 //-------------------------------------------------------------------------
02195 void nsWindow::InitCallbacks(char * aName)
02196 {
02197   NS_ASSERTION(mSuperWin,"no superwin, can't init callbacks");
02198   if (mSuperWin) {
02199     gdk_superwin_set_event_funcs(mSuperWin,
02200                                  handle_xlib_shell_event,
02201                                  handle_superwin_paint,
02202                                  handle_superwin_flush,
02203                                  nsXKBModeSwitch::HandleKeyPress,
02204                                  nsXKBModeSwitch::HandleKeyRelease,
02205                                  this, NULL);
02206   }
02207 }
02208 
02209 //-------------------------------------------------------------------------
02210 //
02211 // Return some native data according to aDataType
02212 //
02213 //-------------------------------------------------------------------------
02214 void * nsWindow::GetNativeData(PRUint32 aDataType)
02215 {
02216 
02217   if (aDataType == NS_NATIVE_WINDOW)
02218   {
02219     if (mSuperWin) {
02220       GdkWindowPrivate *private_window = (GdkWindowPrivate *)mSuperWin->bin_window;
02221       if (private_window->destroyed == PR_TRUE) {
02222         return NULL;
02223       }
02224       return (void *)mSuperWin->bin_window;
02225     }
02226   }
02227   else if (aDataType == NS_NATIVE_WIDGET) {
02228     if (mSuperWin) {
02229       GdkWindowPrivate *private_window = (GdkWindowPrivate *)mSuperWin->bin_window;
02230       if (private_window->destroyed == PR_TRUE) {
02231         return NULL;
02232       }
02233     }
02234     return (void *)mSuperWin;
02235   }
02236   else if (aDataType == NS_NATIVE_PLUGIN_PORT) {
02237     if (mSuperWin) {
02238       GdkWindowPrivate *private_window = (GdkWindowPrivate *)mSuperWin->bin_window;
02239       if (private_window->destroyed == PR_TRUE) {
02240         return NULL;
02241       }
02242 
02243       // we have to flush the X queue here so that any plugins that
02244       // might be running on separate X connections will be able to use
02245       // this window in case it was just created
02246       XSync(GDK_DISPLAY(), False);
02247       return (void *)GDK_WINDOW_XWINDOW(mSuperWin->bin_window);
02248     }
02249     return NULL;
02250   }
02251   else if (aDataType == NS_NATIVE_SHELLWIDGET) {
02252     return (void *) mShell;
02253   }
02254 
02255   return nsWidget::GetNativeData(aDataType);
02256 }
02257 
02258 //-------------------------------------------------------------------------
02259 //
02260 // Scroll the bits of a window
02261 //
02262 //-------------------------------------------------------------------------
02263 
02264 NS_IMETHODIMP nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
02265 {
02266   NS_ASSERTION(mIsDestroying != PR_TRUE, "Trying to scroll a destroyed widget\n");
02267   UnqueueDraw();
02268   mUpdateArea->Offset(aDx, aDy);
02269 
02270   if (mSuperWin) {
02271     // scroll baby, scroll!
02272     gdk_superwin_scroll(mSuperWin, aDx, aDy);
02273   }
02274 
02275   // Update bounds on our child windows
02276   for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
02277     nsRect bounds;
02278     kid->GetBounds(bounds);
02279     bounds.x += aDx;
02280     bounds.y += aDy;
02281     nsWidget* childWidget = NS_STATIC_CAST(nsWidget*, kid);
02282     childWidget->SetBounds(bounds);
02283     childWidget->ResetInternalVisibility();
02284   }
02285 
02286   // Now invalidate the screen position cache, since things moved around.
02287   InvalidateWindowPos();
02288 
02289   return NS_OK;
02290 }
02291 //-------------------------------------------------------------------------
02292 //
02293 // Scroll the bits of a window
02294 //
02295 //-------------------------------------------------------------------------
02296 
02297 NS_IMETHODIMP nsWindow::ScrollWidgets(PRInt32 aDx, PRInt32 aDy)
02298 {
02299   UnqueueDraw();
02300   mUpdateArea->Offset(aDx, aDy);
02301 
02302   if (mSuperWin) {
02303     // scroll baby, scroll!
02304     gdk_superwin_scroll(mSuperWin, aDx, aDy);
02305   }
02306   return NS_OK;
02307 }
02308 
02309 NS_IMETHODIMP nsWindow::ScrollRect(nsRect &aSrcRect, PRInt32 aDx, PRInt32 aDy)
02310 {
02311   return NS_OK;
02312 }
02313 
02314 NS_IMETHODIMP nsWindow::SetTitle(const nsAString& aTitle)
02315 {
02316   if (!mShell)
02317     return NS_ERROR_FAILURE;
02318 
02319   nsresult rv;
02320   char *platformText = nsnull;
02321   PRInt32 platformLen;
02322 
02323   // Set UTF8_STRING title for NET_WM-supporting window managers
02324 #define UTF8_FOLLOWBYTE(ch) (((ch) & 0xC0) == 0x80)
02325   NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
02326   if (titleUTF8.Length() > NS_WINDOW_TITLE_MAX_LENGTH) {
02327     // Truncate overlong titles (bug 167315). Make sure we chop after a
02328     // complete sequence by making sure the next char isn't a follow-byte.
02329     PRUint32 len = NS_WINDOW_TITLE_MAX_LENGTH;
02330     while(UTF8_FOLLOWBYTE(titleUTF8[len]))
02331       --len;
02332     titleUTF8.Truncate(len);
02333   }
02334 
02335   XChangeProperty(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(mShell->window),
02336                 XInternAtom(GDK_DISPLAY(), "_NET_WM_NAME", False),
02337                 XInternAtom(GDK_DISPLAY(), "UTF8_STRING", False),
02338                 8, PropModeReplace, (unsigned char *) titleUTF8.get(),
02339                 titleUTF8.Length());
02340 
02341   // Set UTF8_STRING title for _NET_WM_ICON_NAME as well
02342   XChangeProperty(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(mShell->window),
02343                 XInternAtom(GDK_DISPLAY(), "_NET_WM_ICON_NAME", False),
02344                 XInternAtom(GDK_DISPLAY(), "UTF8_STRING", False),
02345                 8, PropModeReplace, (unsigned char *) titleUTF8.get(),
02346                 titleUTF8.Length());
02347 
02348   nsCOMPtr<nsIUnicodeEncoder> encoder;
02349   // get the charset
02350   nsCAutoString platformCharset;
02351   nsCOMPtr <nsIPlatformCharset> platformCharsetService = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
02352   if (NS_SUCCEEDED(rv))
02353     rv = platformCharsetService->GetCharset(kPlatformCharsetSel_Menu, platformCharset);
02354 
02355   // This is broken, it's just a random guess
02356   if (NS_FAILED(rv))
02357     platformCharset.AssignLiteral("ISO-8859-1");
02358 
02359   // get the encoder
02360   nsCOMPtr<nsICharsetConverterManager> ccm = 
02361            do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);  
02362   rv = ccm->GetUnicodeEncoderRaw(platformCharset.get(), getter_AddRefs(encoder));
02363   NS_ASSERTION(NS_SUCCEEDED(rv), "GetUnicodeEncoderRaw failed.");
02364   if (NS_FAILED(rv))
02365     return NS_ERROR_FAILURE;
02366 
02367   // Estimate out length and allocate the buffer based on a worst-case estimate, then do
02368   // the conversion.
02369   nsAString::const_iterator begin;
02370   const PRUnichar *title = aTitle.BeginReading(begin).get();
02371   PRInt32 len = (PRInt32)aTitle.Length();
02372   encoder->GetMaxLength(title, len, &platformLen);
02373   if (platformLen) {
02374     // Truncate overlong titles (bug 167315).
02375     if (platformLen > NS_WINDOW_TITLE_MAX_LENGTH) {
02376       platformLen = NS_WINDOW_TITLE_MAX_LENGTH;
02377     }
02378     platformText = NS_REINTERPRET_CAST(char*, nsMemory::Alloc(platformLen + sizeof(char)));
02379     if (platformText) {
02380       rv = encoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, nsnull, '?');
02381       if (NS_SUCCEEDED(rv))
02382         rv = encoder->Convert(title, &len, platformText, &platformLen);
02383       (platformText)[platformLen] = '\0';  // null terminate. Convert() doesn't do it for us
02384     }
02385   } // if valid length
02386 
02387   if (platformLen > 0 && platformText) {
02388     gtk_window_set_title(GTK_WINDOW(mShell), platformText);
02389   }
02390   else {
02391     gtk_window_set_title(GTK_WINDOW(mShell), "");
02392   }
02393 
02394   if (platformText)
02395     nsMemory::Free(platformText);
02396 
02397   return NS_OK;
02398 }
02399 
02400 NS_IMETHODIMP
02401 nsWindow::SetIcon(const nsAString& aIconSpec)
02402 {
02403   // See if we have a cached icon set for this window type.
02404   // Note that icon specs must be UTF8.
02405   NS_ConvertUTF16toUTF8 iconKey(aIconSpec);
02406   IconEntry* entry = NS_STATIC_CAST(IconEntry*,
02407                                     PL_DHashTableOperate(sIconCache,
02408                                                          iconKey.get(),
02409                                                          PL_DHASH_ADD));
02410   if (!entry)
02411       return NS_ERROR_OUT_OF_MEMORY;
02412 
02413   if (!entry->string) {
02414     // We'll need to create the pixmaps.
02415 #ifdef NS_DEBUG
02416     PRUint32 generation = sIconCache->generation;
02417 #endif
02418 
02419     GtkStyle* w_style;
02420     GdkPixmap* w_pixmap = NULL, *w_minipixmap = NULL;
02421     GdkBitmap* w_mask = NULL, *w_minimask = NULL;
02422 
02423     w_style = gtk_widget_get_style(mShell);
02424 
02425     nsCOMPtr<nsILocalFile> iconFile;
02426     ResolveIconName(aIconSpec, NS_LITERAL_STRING(".xpm"),
02427                     getter_AddRefs(iconFile));
02428     if (iconFile) {
02429       nsCAutoString path;
02430       iconFile->GetNativePath(path);
02431 
02432       w_pixmap =
02433         gdk_pixmap_colormap_create_from_xpm(mShell->window,
02434                                             gdk_colormap_get_system(),
02435                                             &w_mask,
02436                                             &w_style->bg[GTK_STATE_NORMAL],
02437                                             path.get());
02438 #ifdef DEBUG_ICONS
02439       printf("Loaded large icon file: %s\n", path.get());
02440 #endif
02441     }
02442 
02443     ResolveIconName(aIconSpec, NS_LITERAL_STRING("16.xpm"),
02444                     getter_AddRefs(iconFile));
02445     if (iconFile) {
02446       nsCAutoString path;
02447       iconFile->GetNativePath(path);
02448 
02449       w_minipixmap =
02450         gdk_pixmap_colormap_create_from_xpm(mShell->window,
02451                                             gdk_colormap_get_system(),
02452                                             &w_minimask,
02453                                             &w_style->bg[GTK_STATE_NORMAL],
02454                                             path.get());
02455 #ifdef DEBUG_ICONS
02456       printf("Loaded small icon file: %s\n", path.get());
02457 #endif
02458     }
02459 
02460     NS_ASSERTION(sIconCache->generation == generation, "sIconCache changed!");
02461     entry->string = strdup(iconKey.get());
02462     entry->w_pixmap = w_pixmap;
02463     entry->w_mask = w_mask;
02464     entry->w_minipixmap = w_minipixmap;
02465     entry->w_minimask = w_minimask;
02466   }
02467 #ifdef DEBUG_ICONS
02468   else
02469     printf("Loaded icon set for %s from cache\n", iconKey.get());
02470 #endif
02471 
02472   if (entry->w_pixmap && SetIcon(entry->w_pixmap, entry->w_mask) != NS_OK)
02473     return NS_ERROR_FAILURE;
02474 
02475   /* Now set the mini icon */
02476   if (entry->w_minipixmap)
02477     return SetMiniIcon (entry->w_minipixmap, entry->w_minimask);
02478   return NS_OK;
02479 }
02480 
02481 nsresult nsWindow::SetMiniIcon(GdkPixmap *pixmap,
02482                                GdkBitmap *mask)
02483 {
02484    GdkAtom icon_atom;
02485    glong data[2];
02486 
02487    if (!mShell)
02488       return NS_ERROR_FAILURE;
02489    
02490    data[0] = ((GdkPixmapPrivate *)pixmap)->xwindow;
02491    data[1] = ((GdkPixmapPrivate *)mask)->xwindow;
02492 
02493    icon_atom = gdk_atom_intern ("KWM_WIN_ICON", FALSE);
02494    gdk_property_change (mShell->window, icon_atom, icon_atom,
02495                         32, GDK_PROP_MODE_REPLACE,
02496                         (guchar *)data, 2);
02497    return NS_OK;
02498 }
02499 
02500 // Set the iconify icon for the window.
02501 nsresult nsWindow::SetIcon(GdkPixmap *pixmap, 
02502                            GdkBitmap *mask)
02503 {
02504   if (!mShell)
02505     return NS_ERROR_FAILURE;
02506 
02507   gdk_window_set_icon(mShell->window, (GdkWindow*)nsnull, pixmap, mask);
02508 
02509   return NS_OK;
02510 }
02511 
02512 NS_IMETHODIMP nsWindow::BeginResizingChildren(void)
02513 {
02514   //  gtk_layout_freeze(GTK_LAYOUT(mWidget));
02515   return NS_OK;
02516 }
02517 
02518 NS_IMETHODIMP nsWindow::EndResizingChildren(void)
02519 {
02520   //  gtk_layout_thaw(GTK_LAYOUT(mWidget));
02521   return NS_OK;
02522 }
02523 
02524 NS_IMETHODIMP nsWindow::GetScreenBounds(nsRect &aRect)
02525 {
02526   nsRect origin(0,0,mBounds.width,mBounds.height);
02527   WidgetToScreen(origin, aRect);
02528   return NS_OK;
02529 }
02530 
02531 
02532 //-------------------------------------------------------------------------
02533 //
02534 // Hide or show this component
02535 //
02536 //-------------------------------------------------------------------------
02537 
02538 NS_IMETHODIMP nsWindow::Show(PRBool bState)
02539 {
02540   if (!mSuperWin)
02541     return NS_OK; // Will be null durring printing
02542 
02543   mShown = bState;
02544 
02545   // show
02546   ResetInternalVisibility();
02547 
02548   return NS_OK;
02549 }
02550 
02551 void nsWindow::ResetInternalVisibility()
02552 {
02553   if (mShell)
02554   { // top level, always set the visibility regardless of parent geometry
02555     SetInternalVisibility(mShown);
02556   }
02557   else
02558   {
02559     nsWidget::ResetInternalVisibility();
02560   }
02561 }
02562 
02563 void nsWindow::SetInternalVisibility(PRBool aVisible)
02564 {
02565   // don't show if we are too small
02566   if (mIsTooSmall)
02567   {
02568     aVisible = PR_FALSE;
02569   }
02570 
02571   // Bail out now if we have nothing to do
02572   if (aVisible == mInternalShown)
02573   {
02574     return;
02575   }
02576 
02577   mInternalShown = aVisible;
02578 
02579   if (aVisible)
02580   {
02581     // GTK wants us to set the window mask before we show the window
02582     // for the first time, or setting the mask later won't work.
02583     // GTK also wants us to NOT set the window mask if we're not really
02584     // going to need it, because GTK won't let us unset the mask properly
02585     // later.
02586     // So, we delay setting the mask until the last moment: when the window
02587     // is shown.
02588     if (mIsTranslucent) {
02589       ApplyTransparencyBitmap();
02590     }
02591 
02592     // show mSuperWin
02593     gdk_window_show(mSuperWin->bin_window);
02594     gdk_window_show(mSuperWin->shell_window);
02595 
02596     if (mMozArea)
02597     {
02598       gtk_widget_show(mMozArea);
02599       // if we're a toplevel window, show that too
02600       if (mShell)
02601         gtk_widget_show(mShell);
02602     }
02603 
02604     // We just brought ourselves to the top. If we're not supposed to
02605     // be at the top, put us back where we belong.
02606     if (GetNextSibling()) {
02607       ResetZOrder();
02608     }
02609 
02610     // and if we've been grabbed, grab for good measure.
02611     if (sGrabWindow == this && mLastGrabFailed && !nsWindow::DragInProgress())
02612       NativeGrab(PR_TRUE);
02613   }
02614   // hide
02615   else
02616   {
02617     gdk_window_hide(mSuperWin->bin_window);
02618     gdk_window_hide(mSuperWin->shell_window);
02619     // hide toplevel first so that things don't disapear from the screen one by one
02620 
02621     // are we a toplevel window?
02622     if (mMozArea)
02623     {
02624       // if we're a toplevel window hide that too
02625       if (mShell)
02626         gtk_widget_hide(mShell);
02627       gtk_widget_hide(mMozArea);
02628     } 
02629 
02630   }
02631 }
02632 
02633 //-------------------------------------------------------------------------
02634 //
02635 // grab mouse events for this widget
02636 //
02637 //-------------------------------------------------------------------------
02638 NS_IMETHODIMP nsWindow::CaptureMouse(PRBool aCapture)
02639 {
02640   GtkWidget *grabWidget;
02641 
02642   if (mIsToplevel && mMozArea)
02643     grabWidget = mMozArea;
02644   else
02645     grabWidget = mWidget;
02646 
02647   if (aCapture)
02648   {
02649     if (!grabWidget) {
02650 #ifdef DEBUG
02651       g_print("nsWindow::CaptureMouse on NULL grabWidget\n");
02652 #endif
02653       return NS_ERROR_FAILURE;
02654     }
02655 
02656     GdkCursor *cursor = gdk_cursor_new (GDK_ARROW);
02657     DropMotionTarget();
02658     gdk_pointer_grab (GTK_WIDGET(grabWidget)->window, PR_TRUE, (GdkEventMask)
02659                       (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
02660                        GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
02661                        GDK_POINTER_MOTION_MASK),
02662                       (GdkWindow*) NULL, cursor, GDK_CURRENT_TIME);
02663     gdk_cursor_destroy(cursor);
02664     gtk_grab_add(grabWidget);
02665   }
02666   else
02667   {
02668     DropMotionTarget();
02669     gdk_pointer_ungrab(GDK_CURRENT_TIME);
02670     if (grabWidget) gtk_grab_remove(grabWidget);
02671   }
02672 
02673   return NS_OK;
02674 }
02675 
02676 NS_IMETHODIMP nsWindow::ConstrainPosition(PRBool aAllowSlop, PRInt32 *aX, PRInt32 *aY)
02677 {
02678   if (mIsToplevel && mShell)
02679   {
02680     PRInt32 screenWidth = gdk_screen_width();
02681     PRInt32 screenHeight = gdk_screen_height();
02682     if (aAllowSlop) {
02683       if (*aX < kWindowPositionSlop - mBounds.width)
02684         *aX = kWindowPositionSlop - mBounds.width;
02685       if (*aX > screenWidth - kWindowPositionSlop)
02686         *aX = screenWidth - kWindowPositionSlop;
02687       if (*aY < kWindowPositionSlop - mBounds.height)
02688         *aY = kWindowPositionSlop - mBounds.height;
02689       if (*aY > screenHeight - kWindowPositionSlop)
02690         *aY = screenHeight - kWindowPositionSlop;
02691     } else {
02692       if (*aX < 0)
02693         *aX = 0;
02694       if (*aX > screenWidth - mBounds.width)
02695         *aX = screenWidth - mBounds.width;
02696       if (*aY < 0)
02697         *aY = 0;
02698       if (*aY > screenHeight - mBounds.height)
02699         *aY = screenHeight - mBounds.height;
02700     }
02701   }
02702   return NS_OK;
02703 }
02704 
02705 NS_IMETHODIMP nsWindow::Move(PRInt32 aX, PRInt32 aY)
02706 {
02707   InvalidateWindowPos();        
02708   // check if we are at right place already
02709   if((aX == mBounds.x) && (aY == mBounds.y) && !mIsToplevel) {
02710      return NS_OK;
02711   }
02712 
02713   mBounds.x = aX;
02714   mBounds.y = aY;
02715 
02716   if (mIsToplevel && mShell)
02717   {
02718 #ifdef DEBUG
02719     /* complain if a top-level window is moved offscreen
02720        (legal, but potentially worrisome) */
02721     if (!mParent) {
02722       PRInt32 screenWidth = gdk_screen_width();
02723       PRInt32 screenHeight = gdk_screen_height();
02724       // no annoying assertions. just mention the issue.
02725       if (aX < 0 || aX >= screenWidth || aY < 0 || aY >= screenHeight)
02726         printf("window moved to offscreen position\n");
02727     }
02728 #endif
02729 
02730     // do it the way it should be done period.
02731     if (mParent && mWindowType == eWindowType_popup) {
02732       // *VERY* stupid hack to make gfx combo boxes work
02733       nsRect oldrect, newrect;
02734       oldrect.x = aX;
02735       oldrect.y = aY;
02736       mParent->WidgetToScreen(oldrect, newrect);
02737       gtk_widget_set_uposition(mShell, newrect.x, newrect.y);
02738     } else {
02739       gtk_widget_set_uposition(mShell, aX, aY);
02740     }
02741   }
02742   else if (mSuperWin) {
02743     gdk_window_move(mSuperWin->shell_window, aX, aY);
02744   }
02745 
02746   ResetInternalVisibility();
02747 
02748   return NS_OK;
02749 }
02750 
02751 NS_IMETHODIMP nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
02752 {
02753   PRInt32 sizeHeight = aHeight;
02754   PRInt32 sizeWidth = aWidth;
02755 
02756 #if 0
02757   printf("nsWindow::Resize %s (%p) to %d %d\n",
02758          (const char *) debug_GetName(mWidget),
02759          this,
02760          aWidth, aHeight);
02761 #endif
02762   
02763   ResizeTransparencyBitmap(aWidth, aHeight);
02764 
02765   mBounds.width  = aWidth;
02766   mBounds.height = aHeight;
02767 
02768   // code to keep the window from showing before it has been moved or
02769   // resized
02770   // if we are resized to 1x1 or less, we will hide the window.
02771   // Show(TRUE) will be ignored until a larger resize has happened
02772   if (aWidth <= 1 || aHeight <= 1)
02773   {
02774     mIsTooSmall = PR_TRUE;
02775   }
02776   else
02777   {
02778     mIsTooSmall = PR_FALSE;
02779   }
02780 
02781   if (mSuperWin) {
02782     // toplevel window?  if so, we should resize it as well.
02783     if (mIsToplevel && mShell)
02784     {
02785       // set_default_size won't make a window smaller after it is visible
02786       if (GTK_WIDGET_VISIBLE(mShell) && GTK_WIDGET_REALIZED(mShell))  
02787         gdk_window_resize(mShell->window, aWidth, aHeight);
02788 
02789       gtk_window_set_default_size(GTK_WINDOW(mShell), aWidth, aHeight);
02790     }
02791     // we could be a mozarea resizing.
02792     else if (mMozArea)
02793       gdk_window_resize(mMozArea->window, aWidth, aHeight);
02794     // in any case we always resize our mSuperWin window.
02795     gdk_superwin_resize(mSuperWin, aWidth, aHeight);
02796   }
02797   if (mIsToplevel || mListenForResizes) {
02798     //g_print("sending resize event\n");
02799     nsSizeEvent sevent(PR_TRUE, NS_SIZE, this);
02800     sevent.windowSize = new nsRect (0, 0, sizeWidth, sizeHeight);
02801     sevent.mWinWidth = sizeWidth;
02802     sevent.mWinHeight = sizeHeight;
02803     // XXX fix sevent.time
02804     AddRef();
02805     OnResize(&sevent);
02806     Release();
02807     delete sevent.windowSize;
02808   }
02809   else {
02810     //g_print("not sending resize event\n");
02811   }
02812 
02813   if (aRepaint)
02814     Invalidate(PR_FALSE);
02815 
02816   // Do the actual work of showing or hiding the window as necessary
02817   ResetInternalVisibility();
02818   for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
02819     NS_STATIC_CAST(nsWidget*, kid)->ResetInternalVisibility();
02820   }
02821 
02822   return NS_OK;
02823 }
02824 
02825 NS_IMETHODIMP nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth,
02826                                PRInt32 aHeight, PRBool aRepaint)
02827 {
02828   Move(aX,aY);
02829   // resize can cause a show to happen, so do this last
02830   Resize(aWidth,aHeight,aRepaint);
02831   return NS_OK;
02832 }
02833 
02834 NS_IMETHODIMP nsWindow::GetAttention(PRInt32 aCycleCount)
02835 {
02836   // get the next up moz area
02837   GtkWidget *top_mozarea = GetOwningWidget();
02838   if (top_mozarea) {
02839     GtkWidget *top_window = gtk_widget_get_toplevel(top_mozarea);
02840     if (top_window && GTK_WIDGET_VISIBLE(top_window)) {
02841       // this will raise the toplevel window
02842       gdk_window_show(top_window->window);
02843     }
02844   }
02845   return NS_OK;
02846 }
02847 
02848 /* virtual */ void
02849 nsWindow::OnRealize(GtkWidget *aWidget)
02850 {
02851   if (aWidget == mShell) {
02852     gint wmd = ConvertBorderStyles(mBorderStyle);
02853     if (wmd != -1)
02854       gdk_window_set_decorations(mShell->window, (GdkWMDecoration)wmd);
02855   }
02856 }
02857 
02858 gint handle_mozarea_focus_in(GtkWidget *      aWidget, 
02859                              GdkEventFocus *  aGdkFocusEvent, 
02860                              gpointer         aData)
02861 {
02862   if (!aWidget)
02863     return FALSE;
02864 
02865   if (!aGdkFocusEvent)
02866     return FALSE;
02867 
02868   nsWindow *widget = (nsWindow *)aData;
02869 
02870   if (!widget)
02871     return FALSE;
02872 
02873 #ifdef DEBUG_FOCUS
02874   printf("handle_mozarea_focus_in\n");
02875 #endif
02876 
02877 #ifdef DEBUG_FOCUS
02878   printf("aWidget is %p\n", NS_STATIC_CAST(void *, aWidget));
02879 #endif
02880 
02881   // set the flag since got a focus in event
02882   GTK_WIDGET_SET_FLAGS(aWidget, GTK_HAS_FOCUS);
02883 
02884   widget->HandleMozAreaFocusIn();
02885 
02886   return FALSE;
02887 }
02888 
02889 gint handle_mozarea_focus_out(GtkWidget *      aWidget, 
02890                               GdkEventFocus *  aGdkFocusEvent, 
02891                               gpointer         aData)
02892 {
02893 #ifdef DEBUG_FOCUS
02894   printf("handle_mozarea_focus_out\n");
02895 #endif
02896 
02897   if (!aWidget) {
02898     return FALSE;
02899   }
02900   
02901   if (!aGdkFocusEvent) {
02902     return FALSE;
02903   }
02904 
02905   nsWindow *widget = (nsWindow *) aData;
02906 
02907   if (!widget) {
02908     return FALSE;
02909   }
02910 
02911   // make sure that we unset our focus flag
02912   GTK_WIDGET_UNSET_FLAGS(aWidget, GTK_HAS_FOCUS);
02913 
02914   widget->HandleMozAreaFocusOut();
02915 
02916   return FALSE;
02917 }
02918 
02919 void handle_toplevel_configure (
02920     GtkMozArea *      aArea,
02921     nsWindow   *      aWindow)
02922 {
02923   // This event handler is only installed on toplevel windows
02924 
02925   // Find out if the window position has changed
02926   nsRect oldBounds;
02927   aWindow->GetBounds(oldBounds);
02928 
02929   // this is really supposed to be get_origin, not get_root_origin
02930   // - bryner
02931   nscoord x,y;
02932   gdk_window_get_origin(GTK_WIDGET(aArea)->window, &x, &y);
02933 
02934   if ((oldBounds.x == x) && (oldBounds.y == y)) {
02935     return;
02936   }
02937 
02938   aWindow->OnMove(x, y);
02939 }
02940 
02941 void
02942 nsWindow::HandleXlibConfigureNotifyEvent(XEvent *event)
02943 {
02944 #if 0
02945   XEvent    config_event;
02946 
02947   while (XCheckTypedWindowEvent(event->xany.display, 
02948                                 event->xany.window, 
02949                                 ConfigureNotify,
02950                                 &config_event) == True) {
02951     // make sure that we don't get other types of events.  
02952     // StructureNotifyMask includes other kinds of events, too.
02953     // g_print("clearing xlate queue from widget handler, serial is %ld\n", event->xany.serial);
02954     //    gdk_superwin_clear_translate_queue(mSuperWin, event->xany.serial);
02955     *event = config_event;
02956     // make sure that if we remove a configure event from the queue
02957     // that it gets pulled out of the superwin tranlate queue,
02958     // too.
02959 #if 0
02960     g_print("Extra ConfigureNotify event for window 0x%lx %d %d %d %d\n",
02961             event->xconfigure.window,
02962             event->xconfigure.x, 
02963             event->xconfigure.y,
02964             event->xconfigure.width, 
02965             event->xconfigure.height);
02966 #endif
02967   }
02968 
02969   // gdk_superwin_clear_translate_queue(mSuperWin, event->xany.serial);
02970 
02971 #endif
02972 
02973   if (mIsToplevel) {
02974     nsSizeEvent sevent(PR_TRUE, NS_SIZE, this);
02975     sevent.windowSize = new nsRect (event->xconfigure.x, event->xconfigure.y,
02976                                     event->xconfigure.width, event->xconfigure.height);
02977     sevent.point.x = event->xconfigure.x;
02978     sevent.point.y = event->xconfigure.y;
02979     sevent.mWinWidth = event->xconfigure.width;
02980     sevent.mWinHeight = event->xconfigure.height;
02981     // XXX fix sevent.time
02982     AddRef();
02983     OnResize(&sevent);
02984     Release();
02985     delete sevent.windowSize;
02986   }
02987 }
02988 
02989 // Return the GtkMozArea that is the nearest parent of this widget
02990 GtkWidget *
02991 nsWindow::GetOwningWidget()
02992 {
02993   GdkWindow *parent = nsnull;
02994   GtkWidget *widget;
02995 
02996   if (mMozAreaClosestParent)
02997   {
02998     return (GtkWidget *)mMozAreaClosestParent;
02999   }
03000   if ((mMozAreaClosestParent == nsnull) && mMozArea)
03001   {
03002     mMozAreaClosestParent = mMozArea;
03003     return (GtkWidget *)mMozAreaClosestParent;
03004   }
03005   
03006   if (mSuperWin)
03007   {
03008     parent = mSuperWin->shell_window;
03009   }
03010 
03011   while (parent)
03012   {
03013     gdk_window_get_user_data (parent, (void **)&widget);
03014     if (widget != nsnull && GTK_IS_MOZAREA (widget))
03015     {
03016       mMozAreaClosestParent = widget;
03017       break;
03018     }
03019     parent = gdk_window_get_parent (parent);
03020     parent = gdk_window_get_parent (parent);
03021   }
03022   
03023   return (GtkWidget *)mMozAreaClosestParent;
03024 }
03025 
03026 nsWindow *
03027 nsWindow::GetOwningWindow(void) 
03028 {
03029   GtkWidget *widget = GetOwningWidget();
03030 
03031   return NS_STATIC_CAST(nsWindow *, gtk_object_get_data(GTK_OBJECT(widget),
03032                                                         "nsWindow"));
03033 }
03034 
03035 nsWindowType
03036 nsWindow::GetOwningWindowType(void)
03037 {
03038   nsWindow *owningWindow;
03039   owningWindow = GetOwningWindow();
03040 
03041   nsWindowType retval;
03042   owningWindow->GetWindowType(retval);
03043 
03044   return retval;
03045 }
03046 
03047 PRBool
03048 nsWindow::GrabInProgress(void)
03049 {
03050   return nsWindow::sIsGrabbing;
03051 }
03052 
03053 /* static */
03054 PRBool
03055 nsWindow::DragInProgress(void)
03056 {
03057   // mLastDragMotionWindow means the drag arrow is over mozilla
03058   // sIsDraggingOutOf means the drag arrow is out of mozilla
03059   // both cases mean the dragging is happenning.
03060   if (mLastDragMotionWindow || sIsDraggingOutOf)
03061     return PR_TRUE;
03062   else
03063     return PR_FALSE;
03064 }
03065 
03066 
03067 /* static */
03068 nsWindow *
03069 nsWindow::GetGrabWindow(void)
03070 {
03071   if (nsWindow::sIsGrabbing)
03072     return sGrabWindow;
03073   else
03074     return nsnull;
03075 }
03076 
03077 GdkWindow *
03078 nsWindow::GetGdkGrabWindow(void)
03079 {
03080   if (!nsWindow::sIsGrabbing)
03081   {
03082     return nsnull;
03083   }
03084   if (mTransientParent)
03085     return GTK_WIDGET(mTransientParent)->window;
03086   else
03087     return mSuperWin->bin_window;
03088 
03089 }
03090 
03091 GdkWindow *
03092 nsWindow::GetLayeringWindow()
03093 {
03094   return mSuperWin->shell_window;
03095 }
03096 
03097 /* virtual */ GdkWindow *
03098 nsWindow::GetRenderWindow(GtkObject * aGtkObject)
03099 {
03100   GdkWindow * renderWindow = nsnull;
03101 
03102   if (aGtkObject)
03103   {
03104     if (GDK_IS_SUPERWIN(aGtkObject))
03105     {
03106       renderWindow = GDK_SUPERWIN(aGtkObject)->bin_window;
03107     }
03108   }
03109   return renderWindow;
03110 }
03111 
03112 /* virtual */
03113 GtkWindow *nsWindow::GetTopLevelWindow(void)
03114 {
03115   GtkWidget *moz_area;
03116 
03117   if (!mSuperWin)
03118     return NULL;
03119   moz_area = GetOwningWidget();
03120   return GTK_WINDOW(gtk_widget_get_toplevel(moz_area));
03121 }
03122 
03124 // These are all of our drag and drop operations
03125 
03126 void
03127 nsWindow::InitDragEvent(nsMouseEvent &aEvent)
03128 {
03129   // set the keyboard modifiers
03130   gint x, y;
03131   GdkModifierType state = (GdkModifierType)0;
03132   gdk_window_get_pointer(NULL, &x, &y, &state);
03133   aEvent.isShift = (state & GDK_SHIFT_MASK) ? PR_TRUE : PR_FALSE;
03134   aEvent.isControl = (state & GDK_CONTROL_MASK) ? PR_TRUE : PR_FALSE;
03135   aEvent.isAlt = (state & GDK_MOD1_MASK) ? PR_TRUE : PR_FALSE;
03136   aEvent.isMeta = PR_FALSE; // GTK+ doesn't support the meta key
03137 }
03138 
03139 // This will update the drag action based on the information in the
03140 // drag context.  Gtk gets this from a combination of the key settings
03141 // and what the source is offering.
03142 
03143 void
03144 nsWindow::UpdateDragStatus(nsMouseEvent   &aEvent,
03145                            GdkDragContext *aDragContext,
03146                            nsIDragService *aDragService)
03147 {
03148   // default is to do nothing
03149   int action = nsIDragService::DRAGDROP_ACTION_NONE;
03150   
03151   // set the default just in case nothing matches below
03152   if (aDragContext->actions & GDK_ACTION_DEFAULT) {
03153     action = nsIDragService::DRAGDROP_ACTION_MOVE;
03154   }
03155 
03156   // first check to see if move is set
03157   if (aDragContext->actions & GDK_ACTION_MOVE)
03158     action = nsIDragService::DRAGDROP_ACTION_MOVE;
03159 
03160   // then fall to the others
03161   else if (aDragContext->actions & GDK_ACTION_LINK)
03162     action = nsIDragService::DRAGDROP_ACTION_LINK;
03163  
03164   // copy is ctrl
03165   else if (aDragContext->actions & GDK_ACTION_COPY)
03166     action = nsIDragService::DRAGDROP_ACTION_COPY;
03167 
03168   // update the drag information
03169   nsCOMPtr<nsIDragSession> session;
03170   aDragService->GetCurrentSession(getter_AddRefs(session));
03171 
03172   if (session)
03173     session->SetDragAction(action);
03174 }
03175 
03176 /* static */
03177 gint
03178 nsWindow::DragMotionSignal (GtkWidget *      aWidget,
03179                             GdkDragContext   *aDragContext,
03180                             gint             aX,
03181                             gint             aY,
03182                             guint            aTime,
03183                             void             *aData)
03184 {
03185   nsWindow *window = (nsWindow *)aData;
03186   return window->OnDragMotionSignal(aWidget, aDragContext, aX, aY, aTime, aData);
03187 }
03188 
03189 gint nsWindow::OnDragMotionSignal      (GtkWidget *      aWidget,
03190                                         GdkDragContext   *aDragContext,
03191                                         gint             aX,
03192                                         gint             aY,
03193                                         guint            aTime,
03194                                         void             *aData)
03195 {
03196 #ifdef DEBUG_DND_EVENTS
03197   g_print("nsWindow::OnDragMotionSignal\n");
03198 #endif /* DEBUG_DND_EVENTS */
03199 
03200   sIsDraggingOutOf = PR_FALSE;
03201 
03202   // Reset out drag motion timer
03203   ResetDragMotionTimer(aWidget, aDragContext, aX, aY, aTime);
03204 
03205   // get our drag context
03206   nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
03207   nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
03208 
03209   // first, figure out which internal widget this drag motion actually
03210   // happened on
03211   nscoord retx = 0;
03212   nscoord rety = 0;
03213 
03214   Window thisWindow = GDK_WINDOW_XWINDOW(aWidget->window);
03215   Window returnWindow = None;
03216   returnWindow = GetInnerMostWindow(thisWindow, thisWindow, aX, aY,
03217                                     &retx, &rety, 0);
03218 
03219   nsWindow *innerMostWidget = NULL;
03220   innerMostWidget = GetnsWindowFromXWindow(returnWindow);
03221 
03222   if (!innerMostWidget)
03223     innerMostWidget = this;
03224 
03225   // check to see if there was a drag motion window already in place
03226   if (mLastDragMotionWindow) {
03227     // if it wasn't this
03228     if (mLastDragMotionWindow != innerMostWidget) {
03229       // send a drag event to the last window that got a motion event
03230       mLastDragMotionWindow->OnDragLeave();
03231       // and enter on the new one
03232       innerMostWidget->OnDragEnter(retx, rety);
03233       
03234     }
03235   }
03236   else {
03237     // if there was no other motion window, then we're starting a
03238     // drag. Send an enter event to initiate the drag.
03239 
03240     innerMostWidget->OnDragEnter(retx, rety);
03241   }
03242 
03243   // set the last window to the innerMostWidget
03244   mLastDragMotionWindow = innerMostWidget;
03245 
03246   // update the drag context
03247   dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
03248 
03249   // notify the drag service that we are starting a drag motion.
03250   dragSessionGTK->TargetStartDragMotion();
03251 
03252   nsMouseEvent event(PR_TRUE, NS_DRAGDROP_OVER, innerMostWidget,
03253                      nsMouseEvent::eReal);
03254 
03255   InitDragEvent(event);
03256 
03257   // now that we have initialized the event update our drag status
03258   UpdateDragStatus(event, aDragContext, dragService);
03259 
03260   event.point.x = retx;
03261   event.point.y = rety;
03262 
03263   innerMostWidget->AddRef();
03264 
03265   innerMostWidget->DispatchMouseEvent(event);
03266 
03267   innerMostWidget->Release();
03268 
03269   // we're done with the drag motion event.  notify the drag service.
03270   dragSessionGTK->TargetEndDragMotion(aWidget, aDragContext, aTime);
03271   
03272   // and unset our context
03273   dragSessionGTK->TargetSetLastContext(0, 0, 0);
03274 
03275   return TRUE;
03276 }
03277 
03278 /* static */
03279 void
03280 nsWindow::DragLeaveSignal  (GtkWidget *      aWidget,
03281                             GdkDragContext   *aDragContext,
03282                             guint            aTime,
03283                             gpointer         aData)
03284 {
03285   nsWindow *window = (nsWindow *)aData;
03286   window->OnDragLeaveSignal(aWidget, aDragContext, aTime, aData);
03287 }
03288 
03289 void 
03290 nsWindow::OnDragLeaveSignal       (GtkWidget *      aWidget,
03291                                    GdkDragContext   *aDragContext,
03292                                    guint            aTime,
03293                                    gpointer         aData)
03294 {
03295 #ifdef DEBUG_DND_EVENTS
03296   g_print("nsWindow::OnDragLeaveSignal\n");
03297 #endif /* DEBUG_DND_EVENTS */
03298 
03299   sIsDraggingOutOf = PR_TRUE;
03300 
03301   // make sure to unset any drag motion timers here.
03302   ResetDragMotionTimer(0, 0, 0, 0, 0);
03303 
03304   // create a fast timer - we're delaying the drag leave until the
03305   // next mainloop in hopes that we might be able to get a drag drop
03306   // signal
03307   mDragLeaveTimer = do_CreateInstance("@mozilla.org/timer;1");
03308   NS_ASSERTION(mDragLeaveTimer, "Failed to create drag leave timer!");
03309   // fire this baby asafp
03310   mDragLeaveTimer->InitWithFuncCallback(DragLeaveTimerCallback, this, 0,
03311                                         nsITimer::TYPE_ONE_SHOT);
03312 }
03313 
03314 /* static */
03315 gint
03316 nsWindow::DragDropSignal   (GtkWidget        *aWidget,
03317                             GdkDragContext   *aDragContext,
03318                             gint             aX,
03319                             gint             aY,
03320                             guint            aTime,
03321                             void             *aData)
03322 {
03323   nsWindow *window = (nsWindow *)aData;
03324   return window->OnDragDropSignal(aWidget, aDragContext, aX, aY, aTime, aData);
03325 }
03326 
03327 gint
03328 nsWindow::OnDragDropSignal        (GtkWidget        *aWidget,
03329                                    GdkDragContext   *aDragContext,
03330                                    gint             aX,
03331                                    gint             aY,
03332                                    guint            aTime,
03333                                    void             *aData)
03334 {
03335 #ifdef DEBUG_DND_EVENTS
03336   g_print("nsWindow::OnDragDropSignal\n");
03337 #endif /* DEBUG_DND_EVENTS */
03338 
03339   // get our drag context
03340   nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
03341   nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
03342 
03343   nscoord retx = 0;
03344   nscoord rety = 0;
03345   
03346   Window thisWindow = GDK_WINDOW_XWINDOW(aWidget->window);
03347   Window returnWindow = None;
03348   returnWindow = GetInnerMostWindow(thisWindow, thisWindow, aX, aY, 
03349                                     &retx, &rety, 0);
03350 
03351   nsWindow *innerMostWidget = NULL;
03352   innerMostWidget = GetnsWindowFromXWindow(returnWindow);
03353 
03354   // set this now before any of the drag enter or leave events happen
03355   dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
03356 
03357   if (!innerMostWidget)
03358     innerMostWidget = this;
03359 
03360   // check to see if there was a drag motion window already in place
03361   if (mLastDragMotionWindow) {
03362     // if it wasn't this
03363     if (mLastDragMotionWindow != innerMostWidget) {
03364       // send a drag event to the last window that got a motion event
03365       mLastDragMotionWindow->OnDragLeave();
03366       // and enter on the new one
03367       innerMostWidget->OnDragEnter(retx, rety);
03368     }
03369   }
03370   else {
03371     // if there was no other motion window, send an enter event to
03372     // initiate the drag session.
03373     innerMostWidget->OnDragEnter(retx, rety);
03374   }
03375 
03376   // clear any drag leave timer that might be pending so that it
03377   // doesn't get processed when we actually go out to get data.
03378   if (mDragLeaveTimer) {
03379     mDragLeaveTimer->Cancel();
03380     mDragLeaveTimer = 0;
03381   }
03382 
03383   // set the last window to this 
03384   mLastDragMotionWindow = innerMostWidget;
03385 
03386   // What we do here is dispatch a new drag motion event to
03387   // re-validate the drag target and then we do the drop.  The events
03388   // look the same except for the type.
03389 
03390   innerMostWidget->AddRef();
03391 
03392   nsMouseEvent event(PR_TRUE, NS_DRAGDROP_OVER, innerMostWidget,
03393                      nsMouseEvent::eReal);
03394 
03395   InitDragEvent(event);
03396 
03397   // now that we have initialized the event update our drag status
03398   UpdateDragStatus(event, aDragContext, dragService);
03399 
03400   event.point.x = retx;
03401   event.point.y = rety;
03402 
03403   innerMostWidget->DispatchMouseEvent(event);
03404 
03405   InitDragEvent(event);
03406 
03407   event.message = NS_DRAGDROP_DROP;
03408   event.widget = innerMostWidget;
03409   event.point.x = retx;
03410   event.point.y = rety;
03411 
03412   innerMostWidget->DispatchMouseEvent(event);
03413 
03414   innerMostWidget->Release();
03415 
03416   // before we unset the context we need to do a drop_finish
03417 
03418   gdk_drop_finish(aDragContext, TRUE, aTime);
03419 
03420   // after a drop takes place we need to make sure that the drag
03421   // service doesn't think that it still has a context.  if the other
03422   // way ( besides the drop ) to end a drag event is during the leave
03423   // event and and that case is handled in that handler.
03424   dragSessionGTK->TargetSetLastContext(0, 0, 0);
03425 
03426   // send our drag exit event
03427   innerMostWidget->OnDragLeave();
03428   // and clear the mLastDragMotion window
03429   mLastDragMotionWindow = 0;
03430 
03431   // Make sure to end the drag session. If this drag started in a
03432   // different app, we won't get a drag_end signal to end it from.
03433   dragService->EndDragSession();
03434 
03435   return TRUE;
03436 }
03437 
03438 // when the data has been received
03439 /* static */
03440 void
03441 nsWindow::DragDataReceived (GtkWidget         *aWidget,
03442                             GdkDragContext    *aDragContext,
03443                             gint               aX,
03444                             gint               aY,
03445                             GtkSelectionData  *aSelectionData,
03446                             guint              aInfo,
03447                             guint32            aTime,
03448                             gpointer           aData)
03449 {
03450   nsWindow *window = (nsWindow *)aData;
03451   window->OnDragDataReceived(aWidget, aDragContext, aX, aY,
03452                              aSelectionData, aInfo, aTime, aData);
03453 }
03454 
03455 void
03456 nsWindow::OnDragDataReceived      (GtkWidget         *aWidget,
03457                                    GdkDragContext    *aDragContext,
03458                                    gint               aX,
03459                                    gint               aY,
03460                                    GtkSelectionData  *aSelectionData,
03461                                    guint              aInfo,
03462                                    guint32            aTime,
03463                                    gpointer           aData)
03464 {
03465 #ifdef DEBUG_DND_EVENTS
03466   g_print("nsWindow::OnDragDataReceived\n");
03467 #endif /* DEBUG_DND_EVENTS */
03468   // get our drag context
03469   nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
03470   nsCOMPtr<nsIDragSessionGTK> dragSessionGTK = do_QueryInterface(dragService);
03471 
03472   dragSessionGTK->TargetDataReceived(aWidget, aDragContext, aX, aY,
03473                                      aSelectionData, aInfo, aTime);
03474 }
03475  
03476 void
03477 nsWindow::OnDragLeave(void)
03478 {
03479 #ifdef DEBUG_DND_EVENTS
03480   g_print("nsWindow::OnDragLeave\n");
03481 #endif /* DEBUG_DND_EVENTS */
03482 
03483   nsMouseEvent event(PR_TRUE, NS_DRAGDROP_EXIT, this, nsMouseEvent::eReal);
03484 
03485   AddRef();
03486 
03487   DispatchMouseEvent(event);
03488 
03489   nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
03490 
03491   if (dragService) {
03492     nsCOMPtr<nsIDragSession> currentDragSession;
03493     dragService->GetCurrentSession(getter_AddRefs(currentDragSession));
03494 
03495     if (currentDragSession) {
03496       nsCOMPtr<nsIDOMNode> sourceNode;
03497       currentDragSession->GetSourceNode(getter_AddRefs(sourceNode));
03498 
03499       if (!sourceNode) {
03500         // We're leaving a window while doing a drag that was
03501         // initiated in a different app. End the drag session, since
03502         // we're done with it for now (until the user drags back into
03503         // mozilla).
03504         dragService->EndDragSession();
03505       }
03506     }
03507   }
03508 
03509   Release();
03510 }
03511 
03512 void
03513 nsWindow::OnDragEnter(nscoord aX, nscoord aY)
03514 {
03515 #ifdef DEBUG_DND_EVENTS
03516   g_print("nsWindow::OnDragEnter\n");
03517 #endif /* DEBUG_DND_EVENTS */
03518   
03519   nsMouseEvent event(PR_TRUE, NS_DRAGDROP_ENTER, this, nsMouseEvent::eReal);
03520 
03521   event.point.x = aX;
03522   event.point.y = aY;
03523 
03524   AddRef();
03525 
03526   DispatchMouseEvent(event);
03527 
03528   nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
03529 
03530   if (dragService) {
03531     // Make sure that the drag service knows we're now dragging.
03532     dragService->StartDragSession();
03533   }
03534 
03535   Release();
03536 }
03537 
03538 void
03539 nsWindow::ResetDragMotionTimer(GtkWidget *aWidget,
03540                                GdkDragContext *aDragContext,
03541                                gint aX, gint aY, guint aTime)
03542 {
03543   
03544   // We have to be careful about ref ordering here.  if aWidget ==
03545   // mDraMotionWidget be careful not to let the refcnt drop to zero.
03546   // Same with the drag context.
03547   if (aWidget)
03548     gtk_widget_ref(aWidget);
03549   if (mDragMotionWidget)
03550     gtk_widget_unref(mDragMotionWidget);
03551   mDragMotionWidget = aWidget;
03552 
03553   if (aDragContext)
03554     gdk_drag_context_ref(aDragContext);
03555   if (mDragMotionContext)
03556     gdk_drag_context_unref(mDragMotionContext);
03557   mDragMotionContext = aDragContext;
03558 
03559   mDragMotionX = aX;
03560   mDragMotionY = aY;
03561   mDragMotionTime = aTime;
03562 
03563   // always clear the timer
03564   if (mDragMotionTimerID) {
03565       gtk_timeout_remove(mDragMotionTimerID);
03566       mDragMotionTimerID = 0;
03567 #ifdef DEBUG_DND_EVENTS
03568       g_print("*** canceled motion timer\n");
03569 #endif
03570   }
03571 
03572   // if no widget was passed in, just return instead of setting a new
03573   // timer
03574   if (!aWidget) {
03575     return;
03576   }
03577   
03578   // otherwise we create a new timer
03579   mDragMotionTimerID = gtk_timeout_add(100,
03580                                        (GtkFunction)DragMotionTimerCallback,
03581                                        this);
03582 }
03583 
03584 void
03585 nsWindow::FireDragMotionTimer(void)
03586 {
03587 #ifdef DEBUG_DND_EVENTS
03588   g_print("nsWindow::FireDragMotionTimer\n");
03589 #endif
03590   OnDragMotionSignal(mDragMotionWidget, mDragMotionContext,
03591                      mDragMotionX, mDragMotionY, mDragMotionTime, 
03592                      this);
03593 }
03594 
03595 void
03596 nsWindow::FireDragLeaveTimer(void)
03597 {
03598 #ifdef DEBUG_DND_EVENTS
03599   g_print("nsWindow::FireDragLeaveTimer\n");
03600 #endif
03601   mDragLeaveTimer = 0;
03602 
03603   // clean up any pending drag motion window info
03604   if (mLastDragMotionWindow) {
03605     // send our leave signal
03606     mLastDragMotionWindow->OnDragLeave();
03607     mLastDragMotionWindow = 0;
03608   }
03609 
03610 }
03611 
03612 /* static */
03613 guint
03614 nsWindow::DragMotionTimerCallback(gpointer aClosure)
03615 {
03616   nsWindow *window = NS_STATIC_CAST(nsWindow *, aClosure);
03617   window->FireDragMotionTimer();
03618   return FALSE;
03619 }
03620 
03621 /* static */
03622 void
03623 nsWindow::DragLeaveTimerCallback(nsITimer *aTimer, void *aClosure)
03624 {
03625   nsWindow *window = NS_STATIC_CAST(nsWindow *, aClosure);
03626   window->FireDragLeaveTimer();
03627 }
03628 
03629 /* static */
03630 gint
03631 nsWindow::ClientEventSignal(GtkWidget* widget, GdkEventClient* event, void* data)
03632 {
03633   static GdkAtom atom_rcfiles = GDK_NONE;
03634   if (!atom_rcfiles)
03635     atom_rcfiles = gdk_atom_intern("_GTK_READ_RCFILES", FALSE);
03636 
03637   if (event->message_type == atom_rcfiles) {
03638     nsWidget* targetWindow = (nsWidget*) data;
03639     targetWindow->ThemeChanged();
03640   }
03641 
03642   return FALSE;
03643 }
03644 
03645 void
03646 nsWindow::ThemeChanged()
03647 {
03648   Display     *display;
03649   Window       window;
03650   Window       root_return;
03651   Window       parent_return;
03652   Window      *children_return = NULL;
03653   unsigned int nchildren_return = 0;
03654   unsigned int i = 0;
03655 
03656   if (mSuperWin)
03657   {
03658     display = GDK_DISPLAY();
03659     window = GDK_WINDOW_XWINDOW(mSuperWin->bin_window);
03660     if (window && !((GdkWindowPrivate *)mSuperWin->bin_window)->destroyed)
03661     {
03662       // get a list of children for this window
03663       XQueryTree(display, window, &root_return, &parent_return,
03664                  &children_return, &nchildren_return);
03665       // walk the list of children
03666       for (i=0; i < nchildren_return; i++)
03667       {
03668         Window child_window = children_return[i];
03669         nsWindow *thisWindow = GetnsWindowFromXWindow(child_window);
03670         if (thisWindow)
03671         {
03672           thisWindow->ThemeChanged();
03673         }
03674       }
03675 
03676       // free up the list of children
03677       if (children_return)
03678         XFree(children_return);
03679     }
03680   }
03681 
03682   DispatchStandardEvent(NS_THEMECHANGED);
03683   Invalidate(PR_FALSE);
03684 }
03685 
03686 ChildWindow::ChildWindow()
03687 {
03688 }
03689 
03690 ChildWindow::~ChildWindow()
03691 {
03692 #ifdef NOISY_DESTROY
03693   IndentByDepth(stdout);
03694   printf("ChildWindow::~ChildWindow:%p\n", this);
03695 #endif
03696 }
03697 
03698 #ifdef USE_XIM
03699 nsresult nsWindow::KillICSpotTimer ()
03700 {
03701    if(mICSpotTimer)
03702    {
03703      mICSpotTimer->Cancel();
03704      mICSpotTimer = nsnull;
03705    }
03706    return NS_OK;
03707 }
03708 
03709 nsresult nsWindow::PrimeICSpotTimer ()
03710 {
03711    KillICSpotTimer();
03712    nsresult err;
03713    mICSpotTimer = do_CreateInstance("@mozilla.org/timer;1", &err);
03714    if (NS_FAILED(err))
03715      return err;
03716    mICSpotTimer->InitWithFuncCallback(ICSpotCallback, this, 1000,
03717                                       nsITimer::TYPE_ONE_SHOT);
03718    return NS_OK;
03719 }
03720 
03721 void nsWindow::ICSpotCallback(nsITimer * aTimer, void * aClosure)
03722 {
03723    nsWindow *window= NS_REINTERPRET_CAST(nsWindow*, aClosure);
03724    if( ! window) return;
03725    nsresult res = NS_ERROR_FAILURE;
03726 
03727    nsIMEGtkIC *xic = window->IMEGetInputContext(PR_FALSE);
03728    if (xic) {
03729      res = window->UpdateICSpot(xic);
03730    }
03731    if(NS_SUCCEEDED(res))
03732    {
03733       window->PrimeICSpotTimer();
03734    }
03735 }
03736 
03737 nsresult nsWindow::UpdateICSpot(nsIMEGtkIC *aXIC)
03738 {
03739   // set spot location
03740   nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_QUERY, this);
03741   static gint oldx =0;
03742   static gint oldy =0;
03743   static gint oldw =0;
03744   static gint oldh =0;
03745   compEvent.theReply.mCursorPosition.x=-1;
03746   compEvent.theReply.mCursorPosition.y=-1;
03747   this->OnComposition(compEvent);
03748   // set SpotLocation
03749   if((compEvent.theReply.mCursorPosition.x < 0) &&
03750      (compEvent.theReply.mCursorPosition.y < 0))
03751     return NS_ERROR_FAILURE;
03752 
03753   // In over-the-spot style, pre-edit can not be drawn properly when
03754   // IMESetFocusWindow() is called at height=1 and width=1
03755   // After resizing, we need to call SetPreeditArea() again
03756   if((oldw != mBounds.width) || (oldh != mBounds.height)) {
03757     GdkWindow *gdkWindow = (GdkWindow*)this->GetNativeData(NS_NATIVE_WINDOW);
03758     if (gdkWindow) {
03759       aXIC->SetPreeditArea(0, 0,
03760                            (int)((GdkWindowPrivate*)gdkWindow)->width,
03761                            (int)((GdkWindowPrivate*)gdkWindow)->height);
03762     }
03763     oldw = mBounds.width;
03764     oldh = mBounds.height;
03765   }
03766 
03767   if((compEvent.theReply.mCursorPosition.x != oldx)||
03768      (compEvent.theReply.mCursorPosition.y != oldy))
03769   {
03770     nsPoint spot;
03771     spot.x = compEvent.theReply.mCursorPosition.x;
03772     spot.y = compEvent.theReply.mCursorPosition.y + 
03773       compEvent.theReply.mCursorPosition.height;
03774     SetXICBaseFontSize(aXIC, compEvent.theReply.mCursorPosition.height - 1);
03775     SetXICSpotLocation(aXIC, spot);
03776     oldx = compEvent.theReply.mCursorPosition.x;
03777     oldy = compEvent.theReply.mCursorPosition.y;
03778   } 
03779   return NS_OK;
03780 }
03781 
03782 void
03783 nsWindow::SetXICBaseFontSize(nsIMEGtkIC* aXIC, int height)
03784 {
03785   if (height%2) {
03786     height-=1;
03787   }
03788   if (height<2) return;
03789   if (height == mXICFontSize) return;
03790   if (gPreeditFontset) {
03791     gdk_font_unref(gPreeditFontset);
03792   }
03793   char *xlfdbase = PR_smprintf(XIC_FONTSET, height, height, height);
03794   gPreeditFontset = gdk_fontset_load(xlfdbase);
03795   if (gPreeditFontset) {
03796     aXIC->SetPreeditFont(gPreeditFontset);
03797   }
03798   mXICFontSize = height;
03799   PR_smprintf_free(xlfdbase);
03800 }
03801 
03802 void
03803 nsWindow::SetXICSpotLocation(nsIMEGtkIC* aXIC, nsPoint aPoint)
03804 {
03805   if (gPreeditFontset) {
03806     unsigned long x, y;
03807     x = aPoint.x, y = aPoint.y;
03808     y -= gPreeditFontset->descent;
03809     aXIC->SetPreeditSpotLocation(x, y);
03810   }
03811 }
03812 
03813 void
03814 nsWindow::ime_preedit_start() {
03815 }
03816 
03817 void
03818 nsWindow::ime_preedit_draw(nsIMEGtkIC *aXIC) {
03819   IMEComposeStart(nsnull);
03820   nsIMEPreedit *preedit = aXIC->GetPreedit();
03821   IMEComposeText(nsnull,
03822                  preedit->GetPreeditString(),
03823                  preedit->GetPreeditLength(),
03824                  preedit->GetPreeditFeedback());
03825   if (aXIC->IsPreeditComposing() == PR_FALSE) {
03826     IMEComposeEnd(nsnull);
03827   }
03828 }
03829 
03830 void
03831 nsWindow::ime_preedit_done() {
03832 #ifdef _AIX
03833   IMEComposeStart(nsnull);
03834   IMEComposeText(nsnull, nsnull, 0, nsnull);
03835 #endif
03836   IMEComposeEnd(nsnull);
03837 }
03838 
03839 void
03840 nsWindow::IMEUnsetFocusWindow()
03841 {
03842   KillICSpotTimer();
03843 }
03844 
03845 void
03846 nsWindow::IMESetFocusWindow()
03847 {
03848   // there is only one place to get ShellWindow
03849   IMEGetShellWindow();
03850 
03851   nsIMEGtkIC *xic = IMEGetInputContext(PR_TRUE);
03852 
03853   if (xic) {
03854     if (xic->IsPreeditComposing() == PR_FALSE) {
03855       IMEComposeEnd(nsnull);
03856     }
03857     xic->SetFocusWindow(this);
03858     if (xic->mInputStyle & GDK_IM_PREEDIT_POSITION) {
03859       UpdateICSpot(xic);
03860       PrimeICSpotTimer();
03861     }
03862   }
03863 }
03864 
03865 void
03866 nsWindow::IMEBeingActivate(PRBool aActive)
03867 {
03868   // mIMEShellWindow has been retrieved in IMESetFocusWindow()
03869   if (mIMEShellWindow) {
03870     mIMEShellWindow->mIMEIsBeingActivate = aActive;
03871   } else {
03872     NS_ASSERTION(0, "mIMEShellWindow should exist");
03873   }
03874 }
03875 
03876 void
03877 nsWindow::IMEGetShellWindow(void)
03878 {
03879   if (!mIMEShellWindow) {
03880     nsWindow *mozAreaWindow = nsnull;
03881     GtkWidget *top_mozarea = GetOwningWidget();
03882     if (top_mozarea) {
03883       mozAreaWindow = NS_STATIC_CAST(nsWindow *,
03884                     gtk_object_get_data(GTK_OBJECT(top_mozarea), "nsWindow"));
03885     }
03886     mIMEShellWindow = mozAreaWindow;
03887     NS_ASSERTION(mIMEShellWindow, "IMEGetShellWindow() fails");
03888   }
03889 }
03890 
03891 nsIMEGtkIC*
03892 nsWindow::IMEGetInputContext(PRBool aCreate)
03893 {
03894   if (!mIMEShellWindow) {
03895     return nsnull;
03896   }
03897 
03898   nsXICLookupEntry* entry =
03899     NS_STATIC_CAST(nsXICLookupEntry *,
03900                    PL_DHashTableOperate(&gXICLookupTable, mIMEShellWindow,
03901                                         aCreate ? PL_DHASH_ADD
03902                                                 : PL_DHASH_LOOKUP));
03903 
03904   if (!entry) {
03905     return nsnull;
03906   }
03907   if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mXIC) {
03908     return entry->mXIC;
03909   }
03910 
03911   // create new XIC
03912   if (aCreate) {
03913     // create XLFD, needs 3 arguments of height, see XIC_FONTSET definition
03914     char *xlfdbase = PR_smprintf(XIC_FONTSET, mXICFontSize, mXICFontSize,
03915                                  mXICFontSize);
03916     if (xlfdbase) {
03917       if (gPreeditFontset == nsnull) {
03918         gPreeditFontset = gdk_fontset_load(xlfdbase);
03919       }
03920       if (gStatusFontset == nsnull) {
03921         gStatusFontset = gdk_fontset_load(xlfdbase);
03922       }
03923       PR_smprintf_free(xlfdbase);
03924       nsIMEGtkIC *xic = nsnull;
03925       if (gPreeditFontset && gStatusFontset) {
03926         xic = nsIMEGtkIC::GetXIC(mIMEShellWindow, gPreeditFontset,
03927                                  gStatusFontset);
03928         if (xic) {
03929           xic->SetPreeditSpotLocation(0, 14);
03930           entry->mShellWindow = mIMEShellWindow;
03931           entry->mXIC = xic;
03932           mIMEShellWindow->mIMEShellWindow = mIMEShellWindow;
03933           return xic;
03934         }
03935       }
03936     }
03937 
03938     // ran out of memory somewhere in this block...
03939     PL_DHashTableRawRemove(&gXICLookupTable, entry);
03940   }
03941 
03942   return nsnull;
03943 }
03944 
03945 void
03946 nsWindow::IMEDestroyIC()
03947 {
03948   // do not call IMEGetShellWindow() here
03949   // user mIMEShellWindow to retrieve XIC
03950   nsIMEGtkIC *xic = IMEGetInputContext(PR_FALSE);
03951 
03952   // xic=null means mIMEShellWindow is destroyed before
03953   // or xic is never created for this widget
03954   if (!xic) {
03955     return;
03956   }
03957 
03958   // reset parent window for status window
03959   if (xic->mInputStyle & GDK_IM_STATUS_CALLBACKS) {
03960     xic->ResetStatusWindow(this);
03961   }
03962 
03963   if (mIMEShellWindow == this) {
03964     // shell widget is being destroyed
03965     // remove XIC from hashtable by mIMEShellWindow key
03966     PL_DHashTableOperate(&gXICLookupTable, mIMEShellWindow, PL_DHASH_REMOVE);
03967     delete xic;
03968   } else {
03969     // xic and mIMEShellWindow are valid
03970 
03971     nsWindow *gwin = xic->GetGlobalFocusWindow();
03972     nsWindow *fwin = xic->GetFocusWindow();
03973 
03974     // bug 53989
03975     // if the current focused widget in xic is being destroyed,
03976     // we need to change focused window to mIMEShellWindow
03977     if (fwin && fwin == this) {
03978       xic->SetFocusWindow(mIMEShellWindow);
03979       xic->UnsetFocusWindow();
03980 
03981       // bug 142873
03982       // if focus is already changed before, we need to change
03983       // focus window to the current focused window again for XIC
03984       if (gwin && gwin != this && sFocusWindow == gwin) {
03985         nsIMEGtkIC *focused_xic = gwin->IMEGetInputContext(PR_FALSE);
03986         if (focused_xic) {
03987           focused_xic->SetFocusWindow(gwin);
03988         }
03989       }
03990     }
03991   }
03992 }
03993 #endif // USE_XIM 
03994 
03995 void
03996 nsWindow::IMEComposeStart(guint aTime)
03997 {
03998 #ifdef USE_XIM
03999   if (mIMECallComposeStart == PR_TRUE) {
04000     return;
04001   }
04002 #endif // USE_XIM 
04003   nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_START, this);
04004   compEvent.time = aTime;
04005 
04006   OnComposition(compEvent);
04007 
04008 #ifdef USE_XIM
04009   mIMECallComposeStart = PR_TRUE;
04010   mIMECallComposeEnd = PR_FALSE;
04011 #endif // USE_XIM 
04012 }
04013 
04014 void
04015 nsWindow::IMECommitEvent(GdkEventKey *aEvent) {
04016   PRInt32 srcLen = aEvent->length;
04017 
04018   if (srcLen && aEvent->string && aEvent->string[0] &&
04019       nsGtkIMEHelper::GetSingleton()) {
04020 
04021     PRInt32 uniCharSize;
04022     uniCharSize = nsGtkIMEHelper::GetSingleton()->MultiByteToUnicode(
04023                                 aEvent->string,
04024                                 srcLen,
04025                                 &(mIMECompositionUniString),
04026                                 &(mIMECompositionUniStringSize));
04027 
04028     if (uniCharSize) {
04029 #ifdef USE_XIM
04030       nsIMEGtkIC *xic = IMEGetInputContext(PR_FALSE);
04031       mIMECompositionUniString[uniCharSize] = 0;
04032       if(sFocusWindow == 0 && xic != 0) {
04033         // Commit event happens when Mozilla window does not have
04034         // input focus but Lookup window (candidate) window has the focus
04035         // At the case, we have to call IME events with focused widget
04036         nsWindow *window = xic->GetFocusWindow();
04037         if (window) {
04038           window->IMEComposeStart(aEvent->time);
04039           window->IMEComposeText(aEvent,
04040                    mIMECompositionUniString,
04041                    uniCharSize,
04042                    nsnull);
04043           window->IMEComposeEnd(aEvent->time);
04044         }
04045       } else
04046 #endif // USE_XIM 
04047       {
04048         IMEComposeStart(aEvent->time);
04049         IMEComposeText(aEvent,
04050                    mIMECompositionUniString,
04051                    uniCharSize,
04052                    nsnull);
04053         IMEComposeEnd(aEvent->time);
04054       }
04055     }
04056   }
04057 
04058 #ifdef USE_XIM
04059   nsIMEGtkIC *xic = IMEGetInputContext(PR_FALSE);
04060   if (xic) {
04061     if (xic->mInputStyle & GDK_IM_PREEDIT_POSITION) {
04062       nsWindow *window = xic->GetFocusWindow();
04063       if (window) {
04064         window->UpdateICSpot(xic);
04065         window->PrimeICSpotTimer();
04066       }
04067     }
04068   }
04069 #endif // USE_XIM 
04070 }
04071 
04072 void
04073 nsWindow::IMEComposeText(GdkEventKey *aEvent,
04074                          const PRUnichar *aText, const PRInt32 aLen,
04075                          const char *aFeedback) {
04076   nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, this);
04077   if (aEvent) {
04078     textEvent.isShift = (aEvent->state & GDK_SHIFT_MASK) ? PR_TRUE : PR_FALSE;
04079     textEvent.isControl = (aEvent->state & GDK_CONTROL_MASK) ? PR_TRUE : PR_FALSE;
04080     textEvent.isAlt = (aEvent->state & GDK_MOD1_MASK) ? PR_TRUE : PR_FALSE;
04081     // XXX
04082     textEvent.isMeta = PR_FALSE; //(aEvent->state & GDK_MOD2_MASK) ? PR_TRUE : PR_FALSE;
04083     textEvent.time = aEvent->time;
04084   }
04085 
04086   if (aLen != 0) {
04087     textEvent.theText = (PRUnichar*)aText;
04088 #ifdef USE_XIM
04089     if (aFeedback) {
04090       nsIMEPreedit::IMSetTextRange(aLen,
04091                                    aFeedback,
04092                                    &(textEvent.rangeCount),
04093                                    &(textEvent.rangeArray));
04094     }
04095 #endif // USE_XIM 
04096   }
04097   OnText(textEvent);
04098 #ifdef USE_XIM
04099   if (textEvent.rangeArray) {
04100     delete[] textEvent.rangeArray;
04101   }
04102 #endif // USE_XIM 
04103 }
04104 
04105 void
04106 nsWindow::IMEComposeEnd(guint aTime)
04107 {
04108 #ifdef USE_XIM
04109   if (mIMECallComposeEnd == PR_TRUE) {
04110     return;
04111   }
04112 #endif // USE_XIM 
04113 
04114   nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_END, this);
04115   compEvent.time = aTime;
04116   OnComposition(compEvent);
04117 
04118 #ifdef USE_XIM
04119   mIMECallComposeStart = PR_FALSE;
04120   mIMECallComposeEnd = PR_TRUE;
04121 #endif // USE_XIM 
04122 }
04123 
04124 NS_IMETHODIMP nsWindow::ResetInputState()
04125 {
04126 #ifdef USE_XIM
04127   nsIMEGtkIC *xic = IMEGetInputContext(PR_FALSE);
04128   if (xic) {
04129     // while being called for NS_ACTIVE and NS_DEACTIVATE,
04130     // ignore ResetInputState() call
04131     if (mIMEShellWindow->mIMEIsBeingActivate == PR_TRUE) {
04132       return NS_OK;
04133     }
04134 
04135     // while no focus on this widget, reseting IM status 
04136     // should not be done
04137     if (mHasFocus == PR_FALSE) {
04138       return NS_OK;
04139     }
04140 
04141     // if no composed text, should just return
04142     if(xic->IsPreeditComposing() == PR_FALSE) {
04143       IMEComposeEnd(nsnull);
04144       return NS_OK;
04145     }
04146 
04147     // when composed text exists,
04148     PRInt32 uniCharSize = 
04149       xic->ResetIC(&(mIMECompositionUniString),
04150                     &(mIMECompositionUniStringSize));
04151 
04152     if (uniCharSize == 0) {
04153       // ResetIC() returns 0, need to erase existing composed text
04154       // in GDK_IM_PREEDIT_CALLBACKS style
04155       if (xic->mInputStyle & GDK_IM_PREEDIT_CALLBACKS) {
04156         IMEComposeStart(nsnull);
04157         IMEComposeText(nsnull, nsnull, 0, nsnull);
04158         IMEComposeEnd(nsnull);
04159       }
04160     } else {
04161       mIMECompositionUniString[uniCharSize] = 0;
04162       IMEComposeStart(nsnull);
04163       IMEComposeText(nsnull,
04164                    mIMECompositionUniString,
04165                    uniCharSize,
04166                    nsnull);
04167       IMEComposeEnd(nsnull);
04168     }
04169     if (xic->mInputStyle & GDK_IM_PREEDIT_POSITION) {
04170       UpdateICSpot(xic);
04171     }
04172   }
04173 #endif // USE_XIM 
04174   return NS_OK;
04175 }
04176 
04177 static void
04178 gdk_wmspec_change_state (gboolean   add,
04179                          GdkWindow *window,
04180                          GdkAtom    state1,
04181                          GdkAtom    state2)
04182 {
04183   XEvent xev;
04184 
04185 #define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
04186 #define _NET_WM_STATE_ADD           1    /* add/set property */
04187 #define _NET_WM_STATE_TOGGLE        2    /* toggle property  */
04188 
04189   xev.xclient.type = ClientMessage;
04190   xev.xclient.serial = 0;
04191   xev.xclient.send_event = True;
04192   xev.xclient.window = GDK_WINDOW_XWINDOW(window);
04193   xev.xclient.message_type = gdk_atom_intern("_NET_WM_STATE", FALSE);
04194   xev.xclient.format = 32;
04195   xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
04196   xev.xclient.data.l[1] = state1;
04197   xev.xclient.data.l[2] = state2;
04198 
04199   XSendEvent(gdk_display, GDK_ROOT_WINDOW(), False,
04200              SubstructureRedirectMask | SubstructureNotifyMask, &xev);
04201 }
04202 
04203 #ifndef MOZ_XUL
04204 void nsWindow::ApplyTransparencyBitmap() {}
04205 void nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight) {
04206 }
04207 #else
04208 NS_IMETHODIMP nsWindow::SetWindowTranslucency(PRBool aTranslucent) {
04209   if (!mMozArea)
04210     return GetOwningWindow()->SetWindowTranslucency(aTranslucent);
04211 
04212   if (!mShell) {
04213     // we must be embedded
04214     NS_WARNING("Trying to use transparent chrome in an embedded context");
04215     return NS_ERROR_FAILURE;
04216   }
04217 
04218   if (mIsTranslucent == aTranslucent)
04219     return NS_OK;
04220 
04221   if (!aTranslucent) {
04222     if (mTransparencyBitmap) {
04223       delete[] mTransparencyBitmap;
04224       mTransparencyBitmap = nsnull;
04225       gtk_widget_reset_shapes(mShell);
04226     }
04227   } // else the new default alpha values are "all 1", so we don't
04228     // need to change anything yet
04229 
04230   mIsTranslucent = aTranslucent;
04231   return NS_OK;
04232 }
04233 
04234 NS_IMETHODIMP nsWindow::GetWindowTranslucency(PRBool& aTranslucent) {
04235   if (!mMozArea)
04236     return GetOwningWindow()->GetWindowTranslucency(aTranslucent);
04237 
04238   aTranslucent = mIsTranslucent;
04239   return NS_OK;
04240 }
04241 
04242 static gchar* CreateDefaultTransparencyBitmap(PRInt32 aWidth, PRInt32 aHeight) {
04243   PRInt32 size = ((aWidth+7)/8)*aHeight;
04244   gchar* bits = new gchar[size];
04245   if (bits) {
04246     memset(bits, 255, size);
04247   }
04248   return bits;
04249 }
04250 
04251 void nsWindow::ResizeTransparencyBitmap(PRInt32 aNewWidth, PRInt32 aNewHeight) {
04252   if (!mTransparencyBitmap)
04253     return;
04254 
04255   gchar* newBits = CreateDefaultTransparencyBitmap(aNewWidth, aNewHeight);
04256   if (!newBits) {
04257     delete[] mTransparencyBitmap;
04258     mTransparencyBitmap = nsnull;
04259     return;
04260   }
04261 
04262   // Now copy the intersection of the old and new areas into the new mask
04263   PRInt32 copyWidth = PR_MIN(aNewWidth, mBounds.width);
04264   PRInt32 copyHeight = PR_MIN(aNewHeight, mBounds.height);
04265   PRInt32 oldRowBytes = (mBounds.width+7)/8;
04266   PRInt32 newRowBytes = (aNewWidth+7)/8;
04267   PRInt32 copyBytes = (copyWidth+7)/8;
04268   
04269   PRInt32 i;
04270   gchar* fromPtr = mTransparencyBitmap;
04271   gchar* toPtr = newBits;
04272   for (i = 0; i < copyHeight; i++) {
04273     memcpy(toPtr, fromPtr, copyBytes);
04274     fromPtr += oldRowBytes;
04275     toPtr += newRowBytes;
04276   }
04277 
04278   delete[] mTransparencyBitmap;
04279   mTransparencyBitmap = newBits;
04280 }
04281 
04282 static PRBool ChangedMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
04283                               const nsRect& aRect, PRUint8* aAlphas) {
04284   PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
04285   PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8;
04286   for (y = aRect.y; y < yMax; y++) {
04287     gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
04288     for (x = aRect.x; x < xMax; x++) {
04289       PRBool newBit = *aAlphas > 0;
04290       aAlphas++;
04291 
04292       gchar maskByte = maskBytes[x >> 3];
04293       PRBool maskBit = (maskByte & (1 << (x & 7))) != 0;
04294 
04295       if (maskBit != newBit) {
04296         return PR_TRUE;
04297       }
04298     }
04299   }
04300 
04301   return PR_FALSE;
04302 }
04303 
04304 static void UpdateMaskBits(gchar* aMaskBits, PRInt32 aMaskWidth, PRInt32 aMaskHeight,
04305                            const nsRect& aRect, PRUint8* aAlphas) {
04306   PRInt32 x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
04307   PRInt32 maskBytesPerRow = (aMaskWidth + 7)/8;
04308   for (y = aRect.y; y < yMax; y++) {
04309     gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
04310     for (x = aRect.x; x < xMax; x++) {
04311       PRBool newBit = *aAlphas > 0;
04312       aAlphas++;
04313 
04314       gchar mask = 1 << (x & 7);
04315       gchar maskByte = maskBytes[x >> 3];
04316       // Note: '-newBit' turns 0 into 00...00 and 1 into 11...11
04317       maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask);
04318     }
04319   }
04320 }
04321 
04322 void nsWindow::ApplyTransparencyBitmap() {
04323   if (!mTransparencyBitmap) {
04324     mTransparencyBitmap = CreateDefaultTransparencyBitmap(mBounds.width, mBounds.height);
04325     if (!mTransparencyBitmap)
04326       return;
04327   }
04328 
04329   gtk_widget_reset_shapes(mShell);
04330   GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(mShell->window,
04331                                                       mTransparencyBitmap,
04332                                                       mBounds.width, mBounds.height);
04333   if (!maskBitmap)
04334     return;
04335 
04336   gtk_widget_shape_combine_mask(mShell, maskBitmap, 0, 0);
04337   gdk_bitmap_unref(maskBitmap);
04338 }
04339 
04340 NS_IMETHODIMP nsWindow::UpdateTranslucentWindowAlpha(const nsRect& aRect,
04341                                                      PRUint8* aAlphas)
04342 {
04343   if (!mMozArea)
04344     return GetOwningWindow()->UpdateTranslucentWindowAlpha(aRect, aAlphas);
04345 
04346   NS_ASSERTION(mIsTranslucent, "Window is not transparent");
04347 
04348   if (!mTransparencyBitmap) {
04349     mTransparencyBitmap = CreateDefaultTransparencyBitmap(mBounds.width, mBounds.height);
04350     if (!mTransparencyBitmap)
04351       return NS_ERROR_FAILURE;
04352   }
04353 
04354   NS_ASSERTION(aRect.x >= 0 && aRect.y >= 0
04355                && aRect.XMost() <= mBounds.width && aRect.YMost() <= mBounds.height,
04356                "Rect is out of window bounds");
04357 
04358   if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, aRect, aAlphas))
04359     // skip the expensive stuff if the mask bits haven't changed; hopefully
04360     // this is the common case
04361     return NS_OK;
04362 
04363   UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, aRect, aAlphas);
04364 
04365   if (mShown) {
04366     ApplyTransparencyBitmap();
04367   }
04368 
04369   return NS_OK;
04370 }
04371 
04372 NS_IMETHODIMP
04373 nsWindow::HideWindowChrome(PRBool aShouldHide)
04374 {
04375   if (!mMozArea)
04376     return GetOwningWindow()->HideWindowChrome(aShouldHide);
04377 
04378   if (!mShell) {
04379     // we must be embedded
04380     NS_WARNING("Trying to hide window decorations in an embedded context");
04381     return NS_ERROR_FAILURE;
04382   }
04383 
04384   // Sawfish, metacity, and presumably other window managers get
04385   // confused if we change the window decorations while the window
04386   // is visible.
04387 
04388   if (mShown)
04389     gdk_window_hide(mShell->window);
04390 
04391   gint wmd;
04392   if (aShouldHide)
04393     wmd = 0;
04394   else
04395     wmd = ConvertBorderStyles(mBorderStyle);
04396 
04397   gdk_window_set_decorations(mShell->window, (GdkWMDecoration) wmd);
04398 
04399   if (mShown) 
04400     gdk_window_show(mShell->window);
04401   // XXX This brought the window to the front, which maybe isn't what
04402   // we wanted.
04403 
04404   // For some window managers, adding or removing window decorations
04405   // requires unmapping and remapping our toplevel window.  Go ahead
04406   // and flush the queue here so that we don't end up with a BadWindow
04407   // error later when this happens (when the persistence timer fires
04408   // and GetWindowPos is called).
04409   XSync(GDK_DISPLAY(), False);
04410 
04411   return NS_OK;
04412 }
04413 
04414 NS_IMETHODIMP
04415 nsWindow::MakeFullScreen(PRBool aFullScreen)
04416 {
04417   if (!mMozArea)
04418     return GetOwningWindow()->MakeFullScreen(aFullScreen);
04419 
04420   if (!mShell) {
04421     // we must be embedded
04422     NS_WARNING("Trying to go fullscreen in an embedded context");
04423     return NS_ERROR_FAILURE;
04424   }
04425 
04426   gdk_wmspec_change_state(aFullScreen, mShell->window,
04427                           gdk_atom_intern("_NET_WM_STATE_FULLSCREEN", False),
04428                           GDK_NONE);
04429   return NS_OK;
04430 }
04431 #endif
04432 
04433 void PR_CALLBACK
04434 nsWindow::ClearIconEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr)
04435 {
04436   IconEntry* entry = NS_STATIC_CAST(IconEntry*, aHdr);
04437   if (entry->w_pixmap) {
04438     gdk_pixmap_unref(entry->w_pixmap);
04439     gdk_bitmap_unref(entry->w_mask);
04440   }
04441   if (entry->w_minipixmap) {
04442     gdk_pixmap_unref(entry->w_minipixmap);
04443     gdk_bitmap_unref(entry->w_minimask);
04444   }
04445   if (entry->string)
04446     free((void*) entry->string);
04447   PL_DHashClearEntryStub(aTable, aHdr);
04448 }
04449 
04450 /* static */
04451 int
04452 is_parent_ungrab_enter(GdkEventCrossing *event)
04453 {
04454   return (GDK_CROSSING_UNGRAB == event->mode) &&
04455     ((GDK_NOTIFY_ANCESTOR == event->detail) ||
04456      (GDK_NOTIFY_VIRTUAL == event->detail));
04457 }
04458 
04459 /* static */
04460 int
04461 is_parent_grab_leave(GdkEventCrossing *event)
04462 {
04463   return (GDK_CROSSING_GRAB == event->mode) &&
04464     ((GDK_NOTIFY_ANCESTOR == event->detail) ||
04465      (GDK_NOTIFY_VIRTUAL == event->detail));
04466 }