Back to index

lightning-sunbird  0.9+nobinonly
nsCommonWidget.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is Christopher Blizzard
00020  * <blizzard@mozilla.org>.  Portions created by the Initial Developer
00021  * are Copyright (C) 2001 the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsCommonWidget.h"
00040 #include "nsGtkKeyUtils.h"
00041 
00042 nsCommonWidget::nsCommonWidget()
00043 {
00044     mIsTopLevel       = PR_FALSE;
00045     mIsDestroyed      = PR_FALSE;
00046     mNeedsResize      = PR_FALSE;
00047     mNeedsMove        = PR_FALSE;
00048     mListenForResizes = PR_FALSE;
00049     mIsShown          = PR_FALSE;
00050     mNeedsShow        = PR_FALSE;
00051     mEnabled          = PR_TRUE;
00052     mCreated          = PR_FALSE;
00053     mPlaced           = PR_FALSE;
00054 
00055     mPreferredWidth   = 0;
00056     mPreferredHeight  = 0;
00057 }
00058 
00059 nsCommonWidget::~nsCommonWidget()
00060 {
00061 }
00062 
00063 nsIWidget *
00064 nsCommonWidget::GetParent(void)
00065 {
00066     nsIWidget *retval;
00067     retval = mParent;
00068     NS_IF_ADDREF(retval);
00069     return retval;
00070 }
00071 
00072 void
00073 nsCommonWidget::CommonCreate(nsIWidget *aParent, PRBool aListenForResizes)
00074 {
00075     mParent = aParent;
00076     mListenForResizes = aListenForResizes;
00077     mCreated = PR_TRUE;
00078 }
00079 
00080 void
00081 nsCommonWidget::InitButtonEvent(nsMouseEvent &aEvent,
00082                                 GdkEventButton *aGdkEvent)
00083 {
00084     aEvent.point.x = nscoord(aGdkEvent->x);
00085     aEvent.point.y = nscoord(aGdkEvent->y);
00086 
00087     aEvent.isShift   = (aGdkEvent->state & GDK_SHIFT_MASK)
00088         ? PR_TRUE : PR_FALSE;
00089     aEvent.isControl = (aGdkEvent->state & GDK_CONTROL_MASK)
00090         ? PR_TRUE : PR_FALSE;
00091     aEvent.isAlt     = (aGdkEvent->state & GDK_MOD1_MASK)
00092         ? PR_TRUE : PR_FALSE;
00093     aEvent.isMeta    = (aGdkEvent->state & GDK_MOD4_MASK)
00094         ? PR_TRUE : PR_FALSE;
00095 
00096     switch (aGdkEvent->type) {
00097     case GDK_2BUTTON_PRESS:
00098         aEvent.clickCount = 2;
00099         break;
00100     case GDK_3BUTTON_PRESS:
00101         aEvent.clickCount = 3;
00102         break;
00103         // default is one click
00104     default:
00105         aEvent.clickCount = 1;
00106     }
00107 }
00108 
00109 void
00110 nsCommonWidget::InitMouseScrollEvent(nsMouseScrollEvent &aEvent,
00111                                      GdkEventScroll *aGdkEvent)
00112 {
00113     switch (aGdkEvent->direction) {
00114     case GDK_SCROLL_UP:
00115         aEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
00116         aEvent.delta = -3;
00117         break;
00118     case GDK_SCROLL_DOWN:
00119         aEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
00120         aEvent.delta = 3;
00121         break;
00122     case GDK_SCROLL_LEFT:
00123         aEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
00124         aEvent.delta = -3;
00125         break;
00126     case GDK_SCROLL_RIGHT:
00127         aEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
00128         aEvent.delta = 3;
00129         break;
00130     }
00131 
00132     aEvent.point.x = nscoord(aGdkEvent->x);
00133     aEvent.point.y = nscoord(aGdkEvent->y);
00134 
00135     aEvent.isShift   = (aGdkEvent->state & GDK_SHIFT_MASK)
00136         ? PR_TRUE : PR_FALSE;
00137     aEvent.isControl = (aGdkEvent->state & GDK_CONTROL_MASK)
00138         ? PR_TRUE : PR_FALSE;
00139     aEvent.isAlt     = (aGdkEvent->state & GDK_MOD1_MASK)
00140         ? PR_TRUE : PR_FALSE;
00141     aEvent.isMeta    = (aGdkEvent->state & GDK_MOD4_MASK)
00142         ? PR_TRUE : PR_FALSE;
00143     
00144 }
00145 
00146 void
00147 nsCommonWidget::InitKeyEvent(nsKeyEvent &aEvent, GdkEventKey *aGdkEvent)
00148 {
00149     aEvent.keyCode   = GdkKeyCodeToDOMKeyCode(aGdkEvent->keyval);
00150     aEvent.isShift   = (aGdkEvent->state & GDK_SHIFT_MASK)
00151         ? PR_TRUE : PR_FALSE;
00152     aEvent.isControl = (aGdkEvent->state & GDK_CONTROL_MASK)
00153         ? PR_TRUE : PR_FALSE;
00154     aEvent.isAlt     = (aGdkEvent->state & GDK_MOD1_MASK)
00155         ? PR_TRUE : PR_FALSE;
00156     aEvent.isMeta    = (aGdkEvent->state & GDK_MOD4_MASK)
00157         ? PR_TRUE : PR_FALSE;
00158     aEvent.time      = aGdkEvent->time;
00159 }
00160 
00161 void
00162 nsCommonWidget::DispatchGotFocusEvent(void)
00163 {
00164     nsGUIEvent event(PR_TRUE, NS_GOTFOCUS, this);
00165     nsEventStatus status;
00166     DispatchEvent(&event, status);
00167 }
00168 
00169 void
00170 nsCommonWidget::DispatchLostFocusEvent(void)
00171 {
00172     nsGUIEvent event(PR_TRUE, NS_LOSTFOCUS, this);
00173     nsEventStatus status;
00174     DispatchEvent(&event, status);
00175 }
00176 
00177 void
00178 nsCommonWidget::DispatchActivateEvent(void)
00179 {
00180     nsGUIEvent event(PR_TRUE, NS_ACTIVATE, this);
00181     nsEventStatus status;
00182     DispatchEvent(&event, status);
00183 }
00184 
00185 void
00186 nsCommonWidget::DispatchDeactivateEvent(void)
00187 {
00188     nsGUIEvent event(PR_TRUE, NS_DEACTIVATE, this);
00189     nsEventStatus status;
00190     DispatchEvent(&event, status);
00191 }
00192 
00193 void
00194 nsCommonWidget::DispatchResizeEvent(nsRect &aRect, nsEventStatus &aStatus)
00195 {
00196     nsSizeEvent event(PR_TRUE, NS_SIZE, this);
00197 
00198     event.windowSize = &aRect;
00199     event.point.x = aRect.x;
00200     event.point.y = aRect.y;
00201     event.mWinWidth = aRect.width;
00202     event.mWinHeight = aRect.height;
00203 
00204     nsEventStatus status;
00205     DispatchEvent(&event, status); 
00206 }
00207 
00208 NS_IMETHODIMP
00209 nsCommonWidget::DispatchEvent(nsGUIEvent *aEvent,
00210                               nsEventStatus &aStatus)
00211 {
00212     aStatus = nsEventStatus_eIgnore;
00213 
00214     // hold a widget reference while we dispatch this event
00215     NS_ADDREF(aEvent->widget);
00216 
00217     // send it to the standard callback
00218     if (mEventCallback)
00219         aStatus = (* mEventCallback)(aEvent);
00220 
00221     // dispatch to event listener if event was not consumed
00222     if ((aStatus != nsEventStatus_eIgnore) && mEventListener)
00223         aStatus = mEventListener->ProcessEvent(*aEvent);
00224 
00225     NS_IF_RELEASE(aEvent->widget);
00226 
00227     return NS_OK;
00228 }
00229 
00230 NS_IMETHODIMP
00231 nsCommonWidget::Show(PRBool aState)
00232 {
00233     mIsShown = aState;
00234 
00235     LOG(("nsCommonWidget::Show [%p] state %d\n", (void *)this, aState));
00236 
00237     // Ok, someone called show on a window that isn't sized to a sane
00238     // value.  Mark this window as needing to have Show() called on it
00239     // and return.
00240     if ((aState && !AreBoundsSane()) || !mCreated) {
00241         LOG(("\tbounds are insane or window hasn't been created yet\n"));
00242         mNeedsShow = PR_TRUE;
00243         return NS_OK;
00244     }
00245 
00246     // If someone is hiding this widget, clear any needing show flag.
00247     if (!aState)
00248         mNeedsShow = PR_FALSE;
00249 
00250     // If someone is showing this window and it needs a resize then
00251     // resize the widget.
00252     if (aState) {
00253         if (mNeedsMove) {
00254             LOG(("\tresizing\n"));
00255             NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
00256                          PR_FALSE);
00257         } else if (mNeedsResize) {
00258             NativeResize(mBounds.width, mBounds.height, PR_FALSE);
00259         }
00260     }
00261 
00262     NativeShow(aState);
00263 
00264     return NS_OK;
00265 }
00266 
00267 NS_IMETHODIMP
00268 nsCommonWidget::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
00269 {
00270     mBounds.width = aWidth;
00271     mBounds.height = aHeight;
00272 
00273     if (!mCreated)
00274         return NS_OK;
00275 
00276     // There are several cases here that we need to handle, based on a
00277     // matrix of the visibility of the widget, the sanity of this resize
00278     // and whether or not the widget was previously sane.
00279 
00280     // Has this widget been set to visible?
00281     if (mIsShown) {
00282         // Are the bounds sane?
00283         if (AreBoundsSane()) {
00284             // Yep?  Resize the window
00285             //Maybe, the toplevel has moved
00286 
00287             // Note that if the widget needs to be shown because it
00288             // was previously insane in Resize(x,y,w,h), then we need
00289             // to set the x and y here too, because the widget wasn't
00290             // moved back then
00291             if (mIsTopLevel || mNeedsShow)
00292                 NativeResize(mBounds.x, mBounds.y,
00293                              mBounds.width, mBounds.height, aRepaint);
00294             else
00295                 NativeResize(mBounds.width, mBounds.height, aRepaint);
00296 
00297             // Does it need to be shown because it was previously insane?
00298             if (mNeedsShow)
00299                 NativeShow(PR_TRUE);
00300         }
00301         else {
00302             // If someone has set this so that the needs show flag is false
00303             // and it needs to be hidden, update the flag and hide the
00304             // window.  This flag will be cleared the next time someone
00305             // hides the window or shows it.  It also prevents us from
00306             // calling NativeShow(PR_FALSE) excessively on the window which
00307             // causes unneeded X traffic.
00308             if (!mNeedsShow) {
00309                 mNeedsShow = PR_TRUE;
00310                 NativeShow(PR_FALSE);
00311             }
00312         }
00313     }
00314     // If the widget hasn't been shown, mark the widget as needing to be
00315     // resized before it is shown.
00316     else {
00317         if (AreBoundsSane() && mListenForResizes) {
00318             // For widgets that we listen for resizes for (widgets created
00319             // with native parents) we apparently _always_ have to resize.  I
00320             // dunno why, but apparently we're lame like that.
00321             NativeResize(aWidth, aHeight, aRepaint);
00322         }
00323         else {
00324             mNeedsResize = PR_TRUE;
00325         }
00326     }
00327 
00328     // synthesize a resize event if this isn't a toplevel
00329     if (mIsTopLevel || mListenForResizes) {
00330         nsRect rect(mBounds.x, mBounds.y, aWidth, aHeight);
00331         nsEventStatus status;
00332         DispatchResizeEvent(rect, status);
00333     }
00334 
00335     return NS_OK;
00336 }
00337 
00338 NS_IMETHODIMP
00339 nsCommonWidget::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
00340                        PRBool aRepaint)
00341 {
00342     mBounds.x = aX;
00343     mBounds.y = aY;
00344     mBounds.width = aWidth;
00345     mBounds.height = aHeight;
00346 
00347     mPlaced = PR_TRUE;
00348 
00349     if (!mCreated)
00350         return NS_OK;
00351 
00352     // There are several cases here that we need to handle, based on a
00353     // matrix of the visibility of the widget, the sanity of this resize
00354     // and whether or not the widget was previously sane.
00355 
00356     // Has this widget been set to visible?
00357     if (mIsShown) {
00358         // Are the bounds sane?
00359         if (AreBoundsSane()) {
00360             // Yep?  Resize the window
00361             NativeResize(aX, aY, aWidth, aHeight, aRepaint);
00362             // Does it need to be shown because it was previously insane?
00363             if (mNeedsShow)
00364                 NativeShow(PR_TRUE);
00365         }
00366         else {
00367             // If someone has set this so that the needs show flag is false
00368             // and it needs to be hidden, update the flag and hide the
00369             // window.  This flag will be cleared the next time someone
00370             // hides the window or shows it.  It also prevents us from
00371             // calling NativeShow(PR_FALSE) excessively on the window which
00372             // causes unneeded X traffic.
00373             if (!mNeedsShow) {
00374                 mNeedsShow = PR_TRUE;
00375                 NativeShow(PR_FALSE);
00376             }
00377         }
00378     }
00379     // If the widget hasn't been shown, mark the widget as needing to be
00380     // resized before it is shown
00381     else {
00382         if (AreBoundsSane() && mListenForResizes){
00383             // For widgets that we listen for resizes for (widgets created
00384             // with native parents) we apparently _always_ have to resize.  I
00385             // dunno why, but apparently we're lame like that.
00386             NativeResize(aX, aY, aWidth, aHeight, aRepaint);
00387         }
00388         else {
00389             mNeedsResize = PR_TRUE;
00390             mNeedsMove = PR_TRUE;
00391         }
00392     }
00393 
00394     if (mIsTopLevel || mListenForResizes) {
00395         // synthesize a resize event
00396         nsRect rect(aX, aY, aWidth, aHeight);
00397         nsEventStatus status;
00398         DispatchResizeEvent(rect, status);
00399     }
00400 
00401     return NS_OK;
00402 }
00403 
00404 NS_IMETHODIMP
00405 nsCommonWidget::GetPreferredSize(PRInt32 &aWidth,
00406                                  PRInt32 &aHeight)
00407 {
00408     aWidth  = mPreferredWidth;
00409     aHeight = mPreferredHeight;
00410     return (mPreferredWidth != 0 && mPreferredHeight != 0) ? 
00411         NS_OK : NS_ERROR_FAILURE;
00412 }
00413 
00414 NS_IMETHODIMP
00415 nsCommonWidget::SetPreferredSize(PRInt32 aWidth,
00416                                  PRInt32 aHeight)
00417 {
00418     mPreferredWidth  = aWidth;
00419     mPreferredHeight = aHeight;
00420     return NS_OK;
00421 }
00422 
00423 NS_IMETHODIMP
00424 nsCommonWidget::Enable(PRBool aState)
00425 {
00426     mEnabled = aState;
00427 
00428     return NS_OK;
00429 }
00430 
00431 NS_IMETHODIMP
00432 nsCommonWidget::IsEnabled(PRBool *aState)
00433 {
00434     *aState = mEnabled;
00435 
00436     return NS_OK;
00437 }
00438 
00439 void
00440 nsCommonWidget::OnDestroy(void)
00441 {
00442     if (mOnDestroyCalled)
00443         return;
00444 
00445     mOnDestroyCalled = PR_TRUE;
00446 
00447     // release references to children, device context, toolkit + app shell
00448     nsBaseWidget::OnDestroy();
00449 
00450     // let go of our parent
00451     mParent = nsnull;
00452 
00453     nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
00454 
00455     nsGUIEvent event(PR_TRUE, NS_DESTROY, this);
00456     nsEventStatus status;
00457     DispatchEvent(&event, status);
00458 }
00459 
00460 PRBool
00461 nsCommonWidget::AreBoundsSane(void)
00462 {
00463     if (mBounds.width > 0 && mBounds.height > 0)
00464         return PR_TRUE;
00465 
00466     return PR_FALSE;
00467 }