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  *   Peter Hartshorn <peter@igelaus.com.au>
00024  *   Ken Faulkner <faulkner@igelaus.com.au>
00025  *   B.J. Rossiter <bj@igelaus.com.au>
00026  *   Tony Tsui <tony@igelaus.com.au>
00027  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00028  *   Mats Palmgren <mats.palmgren@bredband.net>
00029  *
00030  * Alternatively, the contents of this file may be used under the terms of
00031  * either the GNU General Public License Version 2 or later (the "GPL"), or
00032  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00033  * in which case the provisions of the GPL or the LGPL are applicable instead
00034  * of those above. If you wish to allow use of your version of this file only
00035  * under the terms of either the GPL or the LGPL, and not to allow others to
00036  * use your version of this file under the terms of the MPL, indicate your
00037  * decision by deleting the provisions above and replace them with the notice
00038  * and other provisions required by the GPL or the LGPL. If you do not delete
00039  * the provisions above, a recipient may use your version of this file under
00040  * the terms of any one of the MPL, the GPL or the LGPL.
00041  *
00042  * ***** END LICENSE BLOCK ***** */
00043 
00044 #include "nsWindow.h"
00045 #include "xlibrgb.h"
00046 
00047 #include "nsIRenderingContext.h"
00048 
00049 /* for window title unicode->locale conversion */
00050 #include "nsICharsetConverterManager.h"
00051 #include "nsIPlatformCharset.h"
00052 #include "nsIServiceManager.h"
00053 
00054 #define NS_WINDOW_TITLE_MAX_LENGTH 4095
00055 
00056 // Variables for grabbing
00057 PRBool   nsWindow::sIsGrabbing = PR_FALSE;
00058 nsWindow *nsWindow::sGrabWindow = nsnull;
00059 
00060 // Routines implementing an update queue.
00061 // We keep a single queue for all widgets because it is 
00062 // (most likely) more efficient and better looking to handle
00063 // all the updates in one shot. Actually, this queue should
00064 // be at most per-toplevel. FIXME.
00065 //
00066 
00067 nsListItem::nsListItem(void *aData, nsListItem *aPrev)
00068 {
00069   next = nsnull;
00070   prev = aPrev;
00071   data = aData;
00072 }
00073 
00074 nsList::nsList()
00075 {
00076   head = nsnull;
00077   tail = nsnull;
00078 }
00079 
00080 nsList::~nsList()
00081 {
00082   reset();
00083 }
00084 
00085 void nsList::add(void *aData)
00086 {
00087   if (head == nsnull) {           // We have an empty list, create the head
00088     head = new nsListItem(aData, nsnull);
00089     tail = head;
00090   } else {                        // Append to the end of the list
00091     tail->setNext(new nsListItem(aData, tail));
00092     tail = tail->getNext();       // Reset the tail
00093     tail->setNext(nsnull);
00094   }
00095 }
00096 
00097 void nsList::remove(void *aData)
00098 {
00099   if (head == nsnull) {           // Removing from a null list
00100     return;
00101   } else {                        // find the data
00102     nsListItem *aItem = head;
00103     while ((aItem != nsnull) && (aItem->getData() != aData)) {
00104       aItem = aItem->getNext();
00105     }
00106     if (aItem == nsnull) {        // we didn't find it
00107       return;
00108     } else
00109     if (aItem == head) {          // we have to remove the head
00110       head = aItem->getNext();
00111       delete aItem;
00112       if (head == nsnull)         // we have emptied the list
00113         tail = nsnull;
00114       else
00115         head->setPrev(nsnull);
00116     } else
00117     if (aItem == tail) {          // we have to remove the tail
00118       tail = aItem->getPrev();
00119       delete aItem;
00120       if (tail == nsnull)         // we have emptied the list
00121         head = nsnull;
00122       else
00123         tail->setNext(nsnull);
00124     } else {                      // we remove from the middle
00125       nsListItem *prev = aItem->getPrev();
00126       nsListItem *next = aItem->getNext();
00127       delete aItem;
00128       prev->setNext(next);
00129       next->setPrev(prev);
00130     }
00131   }
00132 }
00133 
00134 void nsList::reset()
00135 {
00136   while (head != nsnull) {
00137     void *aData = head->getData();
00138     remove(aData);
00139   }
00140 }
00141 
00142 static nsList *update_queue = nsnull;
00143 
00144 void 
00145 nsWindow::UpdateIdle (void *data)
00146 {
00147   if (update_queue != nsnull) {
00148     nsList     *old_queue;
00149     nsListItem *tmp_list;
00150 
00151     old_queue    = update_queue;
00152     update_queue = nsnull;
00153     
00154     for( tmp_list = old_queue->getHead() ; tmp_list != nsnull ; tmp_list = tmp_list->getNext() )
00155     {
00156       nsWindow *window = NS_STATIC_CAST(nsWindow*,(tmp_list->getData()));       
00157 
00158       window->mIsUpdating = PR_FALSE;
00159     }
00160     
00161     for( tmp_list = old_queue->getHead() ; tmp_list != nsnull ; tmp_list = tmp_list->getNext() )
00162     {
00163       nsWindow *window = NS_STATIC_CAST(nsWindow*,(tmp_list->getData()));
00164        
00165       window->Update();
00166     }    
00167 
00168     delete old_queue;
00169   }
00170 }
00171 
00172 // Just raises the window.
00173 // There should probably be checks on this.
00174 // FIXME KenF
00175 NS_IMETHODIMP nsWindow::GetAttention(PRInt32 aCycleCount)
00176 {
00177   XRaiseWindow(mDisplay, mBaseWindow);
00178   return NS_OK;
00179 }
00180 
00181 void
00182 nsWindow::QueueDraw ()
00183 {
00184   if (!mIsUpdating)
00185   {
00186     if (update_queue == nsnull)
00187       update_queue = new nsList();
00188     update_queue->add((void *)this);
00189     mIsUpdating = PR_TRUE;
00190   }
00191 }
00192 
00193 void
00194 nsWindow::UnqueueDraw ()
00195 {
00196   if (mIsUpdating)
00197   {
00198     if (update_queue != nsnull)
00199       update_queue->remove((void *)this);
00200     mIsUpdating = PR_FALSE;
00201   }
00202 }
00203 
00205 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsWidget)
00207 
00208 nsWindow::nsWindow() : nsWidget()
00209 {
00210   mName.AssignLiteral("nsWindow");
00211   mBackground = NS_RGB(255, 255, 255);
00212   mBackgroundPixel = xxlib_rgb_xpixel_from_rgb(mXlibRgbHandle, mBackground);
00213   mBorderRGB = NS_RGB(255,255,255);
00214   mBorderPixel = xxlib_rgb_xpixel_from_rgb(mXlibRgbHandle, mBorderRGB);
00215 
00216   // FIXME KenF
00217   mIsUpdating = PR_FALSE;
00218   mBlockFocusEvents = PR_FALSE;
00219   mLastGrabFailed = PR_TRUE;
00220   mIsTooSmall = PR_FALSE;
00221 
00222   // FIXME New on M17 merge.
00223   mWindowType = eWindowType_child;
00224   mBorderStyle = eBorderStyle_default;
00225   mIsToplevel = PR_FALSE;
00226   
00227   mScrollGC = nsnull;
00228 }
00229 
00230 
00231 nsWindow::~nsWindow()
00232 {
00233   if (mScrollGC)
00234     XFreeGC(mDisplay, mScrollGC);
00235   
00236   // Release grab
00237   if (sGrabWindow == this)
00238   {
00239     sIsGrabbing = PR_FALSE;
00240     sGrabWindow = nsnull;
00241   }
00242  
00243   // Should get called from ~nsWidget() anyway. KenF
00244   // if (mBaseWindow)
00245   //Destroy();
00246   if (mIsUpdating)
00247     UnqueueDraw();
00248 }
00249 
00250 PRBool nsWindow::OnExpose(nsPaintEvent &event)
00251 {
00252   nsresult result = PR_TRUE;
00253 
00254   // call the event callback
00255   if (mEventCallback) 
00256   {
00257     event.renderingContext = nsnull;
00258 
00259     //    printf("nsWindow::OnExpose\n");
00260 
00261     // expose.. we didn't get an Invalidate, so we should up the count here
00262     //    mBounds.UnionRect(mBounds, event.rect);
00263 
00264     //    SendExposeEvent();
00265   }
00266 
00267   return result;
00268 }
00269 
00270 NS_IMETHODIMP nsWindow::Show(PRBool bState)
00271 {
00272   // don't show if we are too small
00273   if (mIsTooSmall)
00274     return NS_OK;
00275 
00276   if (bState) {
00277     if (mIsToplevel) {
00278       PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Someone just used the show method on the toplevel window.\n"));
00279     }
00280 
00281     if (mParentWidget) {
00282       ((nsWidget *)mParentWidget)->WidgetShow(this);
00283       // Fix Popups appearing behind mozilla window. TonyT
00284       XRaiseWindow(mDisplay, mBaseWindow);
00285     } else {
00286       if (mBaseWindow) {
00287         PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Mapping window 0x%lx...\n", mBaseWindow));
00288         Map();
00289       }
00290     }
00291 
00292     mIsShown = PR_TRUE;
00293     if (sGrabWindow == this && mLastGrabFailed) {
00294       /* re-grab things like popup menus - the window isn't mapped when
00295        * the first grab occurs */
00296       NativeGrab(PR_TRUE);
00297     }
00298   } else {
00299     if (mBaseWindow) {
00300       PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Unmapping window 0x%lx...\n", mBaseWindow));
00301       Unmap();
00302     }
00303     mIsShown = PR_FALSE;
00304   }
00305   return NS_OK;
00306 }
00307 
00308 // Function that does native grab.
00309 void nsWindow::NativeGrab(PRBool aGrab)
00310 {
00311   mLastGrabFailed = PR_FALSE;
00312 
00313   if (aGrab)
00314   {
00315     int retval;
00316 
00317     Cursor newCursor = XCreateFontCursor(mDisplay, XC_right_ptr);
00318     retval = XGrabPointer(mDisplay, mBaseWindow, PR_TRUE, (ButtonPressMask |
00319                           ButtonReleaseMask | EnterWindowMask | LeaveWindowMask 
00320                           | PointerMotionMask), GrabModeAsync, GrabModeAsync, 
00321                           (Window)0, newCursor, CurrentTime);
00322     XFreeCursor(mDisplay, newCursor);
00323 
00324     if (retval != GrabSuccess)
00325       mLastGrabFailed = PR_TRUE;
00326 
00327     retval = XGrabKeyboard(mDisplay, mBaseWindow, PR_TRUE, GrabModeAsync,
00328                            GrabModeAsync, CurrentTime);
00329 
00330     if (retval != GrabSuccess)
00331       mLastGrabFailed = PR_TRUE;
00332 
00333   } else {
00334     XUngrabPointer(mDisplay, CurrentTime);
00335     XUngrabKeyboard(mDisplay, CurrentTime);
00336   }
00337 }
00338 
00339 /* This called when a popup is generated so that if a mouse down event occurs,
00340  * the passed listener can be informed (see nsWidget::HandlePopup). It is also
00341  * called with aDoCapture == PR_FALSE when a popup is no longer visible
00342  */
00343 NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener,
00344                                             PRBool aDoCapture,
00345                                             PRBool aConsumeRollupEvent)
00346   {
00347   if (aDoCapture) {
00348     NativeGrab(PR_TRUE);
00349 
00350     sIsGrabbing = PR_TRUE;
00351     sGrabWindow = this;
00352 
00353     gRollupConsumeRollupEvent = PR_TRUE;
00354     gRollupListener = aListener;
00355     gRollupWidget = do_GetWeakReference(NS_STATIC_CAST(nsIWidget*, this));
00356   }else{
00357     // Release Grab
00358     if (sGrabWindow == this)
00359       sGrabWindow = nsnull;
00360 
00361     sIsGrabbing = PR_FALSE;
00362 
00363     NativeGrab(PR_FALSE);
00364 
00365     gRollupListener = nsnull;
00366     gRollupWidget = nsnull;
00367   }
00368   return NS_OK;
00369 }
00370 
00371 NS_IMETHODIMP nsWindow::InvalidateRegion(const nsIRegion* aRegion, PRBool aIsSynchronous)
00372 {
00373   mUpdateArea->Union(*aRegion);
00374 
00375   if (aIsSynchronous)
00376     Update();
00377   else
00378     QueueDraw();
00379   
00380   return NS_OK;
00381 }
00382 
00383 
00384 NS_IMETHODIMP nsWindow::SetFocus(PRBool aRaise)
00385 {
00386   nsEventStatus status;
00387   nsFocusEvent event(PR_TRUE, NS_GOTFOCUS, this);
00388   //  nsGUIEvent eventActivate;
00389 
00390   if (mBaseWindow)
00391     mFocusWindow = mBaseWindow;
00392    
00393   if (mBlockFocusEvents)
00394     return NS_OK;
00395    
00396   mBlockFocusEvents = PR_TRUE;
00397  
00398   AddRef();
00399   DispatchEvent(&event, status);
00400   Release();
00401   
00402   nsGUIEvent actEvent(PR_TRUE, NS_ACTIVATE, this);
00403   
00404   AddRef();
00405   DispatchWindowEvent(actEvent);
00406   Release();
00407   
00408   mBlockFocusEvents = PR_FALSE;
00409   
00410   return NS_OK;
00411 }
00412 
00413 /* NOTE: Originally, nsWindow just uses Resize from nsWidget. 
00414  * Changed so it will first use the nsWidget resizing routine, then
00415  * send out a NS_SIZE event. This makes sure that the resizing is known
00416  * by all parts that NEED to know about it.
00417  * event bit is common for both resizes, yes, could make it a function,
00418  * but haven't yet....
00419  */
00420 NS_IMETHODIMP nsWindow::Resize(PRInt32 aWidth,
00421                                PRInt32 aHeight,
00422                                PRBool   aRepaint)
00423 {
00424   //printf("nsWindow::Resize aWidth=%i aHeight=%i\n", aWidth,aHeight);
00425   PRBool NeedToShow = PR_FALSE;
00426   /* PRInt32 sizeHeight = aHeight;
00427   PRInt32 sizeWidth = aWidth; */
00428 
00429   mBounds.width  = aWidth;
00430   mBounds.height = aHeight;
00431 
00432   // code to keep the window from showing before it has been moved or resized
00433 
00434   // if we are resized to 1x1 or less, we will hide the window.  Show(TRUE) will be ignored until a
00435   // larger resize has happened
00436   if (aWidth <= 1 || aHeight <= 1)
00437   {
00438     aWidth = 1;
00439     aHeight = 1;
00440     mIsTooSmall = PR_TRUE;
00441     Show(PR_FALSE);
00442   }
00443   else
00444   {
00445     if (mIsTooSmall)
00446     {
00447       // if we are not shown, we don't want to force a show here, so check and see if Show(TRUE) has been called
00448       NeedToShow = mIsShown;
00449       mIsTooSmall = PR_FALSE;
00450     }
00451   }
00452   nsWidget::Resize(aWidth, aHeight, aRepaint);
00453 
00454   nsSizeEvent sevent(PR_TRUE, NS_SIZE, this);
00455   nsRect sevent_windowSize(0, 0, aWidth, aHeight);
00456   sevent.windowSize = &sevent_windowSize;
00457   sevent.mWinWidth = aWidth;
00458   sevent.mWinHeight = aHeight;
00459   AddRef();
00460   OnResize(sevent);
00461   Release();
00462 
00463   if (NeedToShow)
00464     Show(PR_TRUE);
00465 
00466   if (aRepaint)
00467     Invalidate(PR_FALSE);
00468 
00469   return NS_OK;
00470 }
00471 
00472 /* NOTE: Originally, nsWindow just uses Resize from nsWidget. 
00473  * Changed so it will first use the nsWidget resizing routine, then
00474  * send out a NS_SIZE event. This makes sure that the resizing is known
00475  * by all parts that NEED to know about it.
00476  */
00477 NS_IMETHODIMP nsWindow::Resize(PRInt32 aX,
00478                                PRInt32 aY,
00479                                PRInt32 aWidth,
00480                                PRInt32 aHeight,
00481                                PRBool   aRepaint)
00482 {
00483   //printf("nsWindow::Resize aX=%i, aY=%i, aWidth=%i, aHeight=%i\n", aX,aY,aWidth,aHeight);
00484 
00485   nsWidget::Resize(aX, aY, aWidth, aHeight, aRepaint);
00486 
00487   nsSizeEvent sevent(PR_TRUE, NS_SIZE, this);
00488   nsRect sevent_windowSize(0, 0, aWidth, aHeight);
00489   sevent.windowSize = &sevent_windowSize;
00490   sevent.mWinWidth = aWidth;
00491   sevent.mWinHeight = aHeight;
00492   AddRef();
00493   OnResize(sevent);
00494   Release();
00495   return NS_OK;
00496 }
00497 
00498 /* virtual */ long
00499 nsWindow::GetEventMask()
00500 {
00501   long event_mask;
00502 
00503   event_mask = 
00504     ButtonMotionMask |
00505     ButtonPressMask | 
00506     ButtonReleaseMask | 
00507     EnterWindowMask |
00508     ExposureMask | 
00509     KeyPressMask | 
00510     KeyReleaseMask | 
00511     LeaveWindowMask |
00512     PointerMotionMask |
00513     StructureNotifyMask | 
00514     VisibilityChangeMask |
00515     FocusChangeMask |
00516     OwnerGrabButtonMask;
00517   return event_mask;
00518 }
00519 
00520 #undef TRACE_INVALIDATE
00521 
00522 #ifdef TRACE_INVALIDATE
00523 static PRInt32 sInvalidatePrintCount = 0;
00524 #endif
00525 
00526 NS_IMETHODIMP nsWindow::Invalidate(PRBool aIsSynchronous)
00527 {
00528   mUpdateArea->SetTo(mBounds.x, mBounds.y, mBounds.width, mBounds.height);
00529 
00530   if (aIsSynchronous)
00531     Update();
00532   else
00533     QueueDraw();
00534 
00535   return NS_OK;
00536 }
00537 
00538 NS_IMETHODIMP nsWindow::Invalidate(const nsRect & aRect, PRBool aIsSynchronous)
00539 {
00540   mUpdateArea->Union(aRect.x, aRect.y, aRect.width, aRect.height);
00541   if (aIsSynchronous)
00542     Update();
00543   else
00544     QueueDraw();
00545   
00546   return NS_OK;
00547 }
00548 
00549 void 
00550 nsWindow::DoPaint (PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
00551                    nsIRegion *aClipRegion)
00552 {
00553   if (mEventCallback) {
00554     nsPaintEvent event(PR_TRUE, NS_PAINT, this);
00555     nsRect rect(aX, aY, aWidth, aHeight);
00556     event.point.x = aX;
00557     event.point.y = aY; 
00558     event.time = PR_Now(); /* No time in EXPOSE events */
00559     event.rect = &rect;
00560     
00561     event.renderingContext = GetRenderingContext();
00562     if (event.renderingContext) {
00563       DispatchWindowEvent(event);
00564       NS_RELEASE(event.renderingContext);
00565     }
00566   }
00567 }
00568 
00569 NS_IMETHODIMP nsWindow::Update(void)
00570 {
00571   if (mIsUpdating)
00572     UnqueueDraw();
00573 
00574   if (!mUpdateArea->IsEmpty()) {
00575     PRUint32 numRects;
00576     mUpdateArea->GetNumRects(&numRects);
00577 
00578     /* We paint the rects by themselves if we have 2 to 15 rects,
00579      * otherwise we will just paint the bounding box. */
00580     if (numRects != 1 && numRects < 16) {
00581       nsRegionRectSet *regionRectSet = nsnull;
00582 
00583       if (NS_FAILED(mUpdateArea->GetRects(&regionRectSet)))
00584         return NS_ERROR_FAILURE;
00585 
00586       PRUint32 len;
00587       PRUint32 i;
00588       
00589       len = regionRectSet->mRectsLen;
00590 
00591       for (i=0;i<len;++i) {
00592         nsRegionRect *r = &(regionRectSet->mRects[i]);
00593         DoPaint (r->x, r->y, r->width, r->height, mUpdateArea);
00594       }
00595       
00596       mUpdateArea->FreeRects(regionRectSet);
00597       
00598       mUpdateArea->SetTo(0, 0, 0, 0);
00599       return NS_OK;
00600     } else {
00601       PRInt32 x, y, w, h;
00602       mUpdateArea->GetBoundingBox(&x, &y, &w, &h);
00603       DoPaint (x, y, w, h, mUpdateArea);
00604       mUpdateArea->SetTo(0, 0, 0, 0);
00605     }
00606   } 
00607 
00608   // While I'd think you should NS_RELEASE(aPaintEvent.widget) here,
00609   // if you do, it is a NULL pointer.  Not sure where it is getting
00610   // released.
00611   return NS_OK;
00612 }
00613 
00614 NS_IMETHODIMP nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
00615 {
00616   PR_LOG(XlibScrollingLM, PR_LOG_DEBUG, ("nsWindow::Scroll()\n"));
00617   
00618   if (mIsUpdating)
00619     UnqueueDraw();
00620 
00621   PRInt32 srcX = 0, srcY = 0, destX = 0, destY = 0, width = 0, height = 0;
00622   nsRect aRect;
00623  
00624   /* only create GC for scolling once ... */
00625   if (!mScrollGC)
00626     mScrollGC = XCreateGC(mDisplay, mBaseWindow, 0, nsnull);   
00627  
00628   if (aDx < 0 || aDy < 0)
00629   {
00630     srcX   = mBounds.x + PR_ABS(aDx);
00631     srcY   = mBounds.y + PR_ABS(aDy);
00632     destX  = mBounds.x;
00633     destY  = mBounds.y;
00634     width  = mBounds.width  - PR_ABS(aDx);
00635     height = mBounds.height - PR_ABS(aDy);
00636   } 
00637   else if (aDx > 0 || aDy > 0)
00638   {
00639     srcX   = mBounds.x;
00640     srcY   = mBounds.y;
00641     destX  = mBounds.x + PR_ABS(aDx);
00642     destY  = mBounds.y + PR_ABS(aDy);
00643     width  = mBounds.width  - PR_ABS(aDx);
00644     height = mBounds.height - PR_ABS(aDy);
00645   }
00646 
00647   XCopyArea(mDisplay, mBaseWindow, mBaseWindow, mScrollGC,
00648             srcX, srcY, width, height, destX, destY);
00649 
00650   width = mBounds.width;
00651   height = mBounds.height;
00652 
00653   if (aDx != 0 || aDy != 0) {
00654     if (aDx < 0) {
00655       aRect.SetRect(width + aDx, 0,
00656                     -aDx, height);
00657     }
00658     else if (aDx > 0) {
00659       aRect.SetRect(0,0, aDx, height);
00660     }
00661 
00662     if (aDy < 0) {
00663       aRect.SetRect(0, height + aDy,
00664                     width, -aDy);
00665     }
00666     else if (aDy > 0) {
00667       aRect.SetRect(0,0, width, aDy);
00668     }
00669 
00670     mUpdateArea->Offset(aDx, aDy);
00671     Invalidate(aRect, PR_TRUE);
00672   }
00673 
00674   //--------
00675   // Scroll the children
00676   for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
00677     nsWindow* childWindow = NS_STATIC_CAST(nsWindow*, kid);
00678     nsRect bounds;
00679     childWindow->GetRequestedBounds(bounds);
00680     childWindow->Move(bounds.x + aDx, bounds.y + aDy);
00681     Invalidate(bounds, PR_TRUE);
00682   }
00683 
00684   // If we are obscurred by another window we have to update those areas
00685   // which were not copied with the XCopyArea function.
00686 
00687   if (mVisibility == VisibilityPartiallyObscured)
00688   {
00689     XEvent event;
00690     PRBool needToUpdate = PR_FALSE;
00691     mUpdateArea->SetTo(0,0,0,0);
00692     while(XCheckWindowEvent(mDisplay, mBaseWindow, 0xffffffff, &event))
00693     {
00694       if (event.type == GraphicsExpose) {
00695         nsRect rect;
00696         rect.SetRect(event.xgraphicsexpose.x,
00697                      event.xgraphicsexpose.y,
00698                      event.xgraphicsexpose.width,
00699                      event.xgraphicsexpose.height);
00700         mUpdateArea->Union(rect.x, rect.y, rect.width, rect.height);
00701         needToUpdate = PR_TRUE;
00702         if (event.xgraphicsexpose.count == 0) {
00703           continue;
00704         }
00705       }
00706     }
00707     if (needToUpdate)
00708       Update();
00709   }
00710   return NS_OK;
00711 }
00712 
00713 NS_IMETHODIMP nsWindow::ScrollWidgets(PRInt32 aDx, PRInt32 aDy)
00714 {
00715   return Scroll(aDx, aDy, nsnull);
00716 }
00717 
00718 NS_IMETHODIMP nsWindow::ScrollRect(nsRect &aSrcRect, PRInt32 aDx, PRInt32 aDy)
00719 {
00720   return Scroll(aDx, aDy, nsnull);
00721 }
00722 
00723 NS_IMETHODIMP nsWindow::SetTitle(const nsAString& aTitle)
00724 {
00725   if(!mBaseWindow)
00726     return NS_ERROR_FAILURE;
00727 
00728   nsresult rv;
00729   char *platformText;
00730   PRInt32 platformLen;
00731 
00732   nsCOMPtr<nsIUnicodeEncoder> encoder;
00733   /* get the charset */
00734   nsCAutoString platformCharset;
00735   nsCOMPtr <nsIPlatformCharset> platformCharsetService = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
00736   if (NS_SUCCEEDED(rv))
00737     rv = platformCharsetService->GetCharset(kPlatformCharsetSel_Menu, platformCharset);
00738   
00739   if (NS_FAILED(rv))
00740     platformCharset.AssignLiteral("ISO-8859-1");
00741 
00742   /* get the encoder */
00743   nsCOMPtr<nsICharsetConverterManager> ccm = 
00744            do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);  
00745   rv = ccm->GetUnicodeEncoderRaw(platformCharset.get(), getter_AddRefs(encoder));
00746   NS_ASSERTION(NS_SUCCEEDED(rv), "GetUnicodeEncoderRaw failed.");
00747   if (NS_FAILED(rv))
00748     return NS_ERROR_FAILURE;
00749 
00750   /* Estimate out length and allocate the buffer based on a worst-case estimate, then do
00751      the conversion. */
00752   nsAString::const_iterator begin;
00753   const PRUnichar *title = aTitle.BeginReading(begin).get();
00754   PRInt32 len = (PRInt32)aTitle.Length();
00755   encoder->GetMaxLength(title, len, &platformLen);
00756   if (platformLen) {
00757     // Truncate overlong titles (bug 167315).
00758     if (platformLen > NS_WINDOW_TITLE_MAX_LENGTH) {
00759       platformLen = NS_WINDOW_TITLE_MAX_LENGTH;
00760     }
00761     platformText = NS_REINTERPRET_CAST(char*, nsMemory::Alloc(platformLen + sizeof(char)));
00762     if (platformText) {
00763       rv = encoder->Convert(title, &len, platformText, &platformLen);
00764       (platformText)[platformLen] = '\0';  // null terminate. Convert() doesn't do it for us
00765     }
00766   } // if valid length
00767 
00768   if (platformLen > 0) {
00769     int status = 0;
00770     XTextProperty prop;
00771 
00772     /* Use XStdICCTextStyle for 41786(a.k.a TWM sucks) and 43108(JA text title) */
00773     prop.value = 0;
00774     status = XmbTextListToTextProperty(mDisplay, &platformText, 1,
00775         XStdICCTextStyle, &prop);
00776 
00777     if (status == Success) {
00778       XSetWMProperties(mDisplay, mBaseWindow,
00779                        &prop, &prop, nsnull, 0, nsnull, nsnull, nsnull);
00780       if (prop.value)
00781         XFree(prop.value);
00782 
00783       nsMemory::Free(platformText);
00784       return NS_OK;
00785     } else {                    // status != Success
00786       if (prop.value)
00787         XFree(prop.value);
00788       nsMemory::Free(platformText);
00789     }
00790   }
00791 
00792   /* if the stuff above failed, replace multibyte with .... */
00793   XStoreName(mDisplay, mBaseWindow, NS_LossyConvertUCS2toASCII(aTitle).get());
00794 
00795   return NS_OK;
00796 }
00797 
00798 ChildWindow::ChildWindow(): nsWindow()
00799 {
00800   mName.AssignLiteral("nsChildWindow");
00801 }
00802 
00803