Back to index

lightning-sunbird  0.9+nobinonly
nsAppShell.cpp
Go to the documentation of this file.
00001 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
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  *   Michael Lowe <michael.lowe@bigfoot.com>
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 "nsAppShell.h"
00040 #include "nsToolkit.h"
00041 #include "nsIWidget.h"
00042 #include "nsIEventQueueService.h"
00043 #include "nsIServiceManager.h"
00044 #include <windows.h>
00045 
00046 // unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
00047 #include <unknwn.h>
00048 
00049 #include "nsWidgetsCID.h"
00050 #include "aimm.h"
00051 
00052 
00053 NS_IMPL_ISUPPORTS1(nsAppShell, nsIAppShell) 
00054 
00055 static int gKeepGoing = 1;
00056 //-------------------------------------------------------------------------
00057 //
00058 // nsAppShell constructor
00059 //
00060 //-------------------------------------------------------------------------
00061 nsAppShell::nsAppShell()  
00062 { 
00063 }
00064 
00065 
00066 
00067 //-------------------------------------------------------------------------
00068 //
00069 // Create the application shell
00070 //
00071 //-------------------------------------------------------------------------
00072 
00073 NS_METHOD nsAppShell::Create(int* argc, char ** argv)
00074 {
00075   return NS_OK;
00076 }
00077 
00078 //-------------------------------------------------------------------------
00079 //
00080 // Enter a message handler loop
00081 //
00082 //-------------------------------------------------------------------------
00083 
00084 #include "nsITimerManager.h"
00085 
00086 BOOL PeekKeyAndIMEMessage(LPMSG msg, HWND hwnd)
00087 {
00088   MSG msg1, msg2, *lpMsg;
00089   BOOL b1, b2;
00090   b1 = nsToolkit::mPeekMessage(&msg1, NULL, WM_KEYFIRST, WM_IME_KEYLAST, PM_NOREMOVE);
00091   b2 = nsToolkit::mPeekMessage(&msg2, NULL, WM_IME_SETCONTEXT, WM_IME_KEYUP, PM_NOREMOVE);
00092   if (b1 || b2) {
00093     if (b1 && b2) {
00094       if (msg1.time < msg2.time)
00095         lpMsg = &msg1;
00096       else
00097         lpMsg = &msg2;
00098     } else if (b1)
00099       lpMsg = &msg1;
00100     else
00101       lpMsg = &msg2;
00102     return nsToolkit::mPeekMessage(msg, hwnd, lpMsg->message, lpMsg->message, PM_REMOVE);
00103   }
00104 
00105   return false;
00106 }
00107 
00108 
00109 NS_METHOD nsAppShell::Run(void)
00110 {
00111   NS_ADDREF_THIS();
00112   MSG  msg;
00113   int  keepGoing = 1;
00114 
00115   nsresult rv;
00116   nsCOMPtr<nsITimerManager> timerManager(do_GetService("@mozilla.org/timer/manager;1", &rv));
00117   if (NS_FAILED(rv)) return rv;
00118 
00119   timerManager->SetUseIdleTimers(PR_TRUE);
00120 
00121   gKeepGoing = 1;
00122   // Process messages
00123   do {
00124     // Give priority to system messages (in particular keyboard, mouse,
00125     // timer, and paint messages).
00126      if (PeekKeyAndIMEMessage(&msg, NULL) ||
00127          nsToolkit::mPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) || 
00128          nsToolkit::mPeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
00129       keepGoing = (msg.message != WM_QUIT);
00130 
00131       if (keepGoing != 0) {
00132         TranslateMessage(&msg);
00133         nsToolkit::mDispatchMessage(&msg);
00134       }
00135     } else {
00136 
00137       PRBool hasTimers;
00138       timerManager->HasIdleTimers(&hasTimers);
00139       if (hasTimers) {
00140         do {
00141           timerManager->FireNextIdleTimer();
00142           timerManager->HasIdleTimers(&hasTimers);
00143         } while (hasTimers && !nsToolkit::mPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE));
00144       } else {
00145 
00146         if (!gKeepGoing) {
00147           // In this situation, PostQuitMessage() was called, but the WM_QUIT
00148           // message was removed from the event queue by someone else -
00149           // (see bug #54725).  So, just exit the loop as if WM_QUIT had been
00150           // reeceived...
00151           keepGoing = 0;
00152         } else {
00153           // Block and wait for any posted application message
00154           ::WaitMessage();
00155         }
00156       }
00157     }
00158 
00159   } while (keepGoing != 0);
00160   Release();
00161   return msg.wParam;
00162 }
00163 
00164 inline NS_METHOD nsAppShell::Spinup(void)
00165 { return NS_OK; }
00166 
00167 inline NS_METHOD nsAppShell::Spindown(void)
00168 { return NS_OK; }
00169 
00170 inline NS_METHOD nsAppShell::ListenToEventQueue(nsIEventQueue * aQueue, PRBool aListen)
00171 { return NS_OK; }
00172 
00173 NS_METHOD
00174 nsAppShell::GetNativeEvent(PRBool &aRealEvent, void *&aEvent)
00175 {
00176   static MSG msg;
00177 
00178   BOOL gotMessage = false;
00179 
00180   nsresult rv;
00181   nsCOMPtr<nsITimerManager> timerManager(do_GetService("@mozilla.org/timer/manager;1", &rv));
00182   if (NS_FAILED(rv)) return rv;
00183 
00184   do {
00185     // Give priority to system messages (in particular keyboard, mouse,
00186     // timer, and paint messages).
00187      if (PeekKeyAndIMEMessage(&msg, NULL) ||
00188         nsToolkit::mPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) || 
00189         nsToolkit::mPeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
00190       gotMessage = true;
00191     } else {
00192       PRBool hasTimers;
00193       timerManager->HasIdleTimers(&hasTimers);
00194       if (hasTimers) {
00195         do {
00196           timerManager->FireNextIdleTimer();
00197           timerManager->HasIdleTimers(&hasTimers);
00198         } while (hasTimers && !nsToolkit::mPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE));
00199       } else {
00200         // Block and wait for any posted application message
00201         ::WaitMessage();
00202       }
00203     }
00204 
00205   } while (!gotMessage);
00206 
00207 #ifdef DEBUG_danm
00208   if (msg.message != WM_TIMER)
00209     printf("-> %d", msg.message);
00210 #endif
00211 
00212   TranslateMessage(&msg);
00213   aEvent = &msg;
00214   aRealEvent = PR_TRUE;
00215   return NS_OK;
00216 }
00217 
00218 nsresult nsAppShell::DispatchNativeEvent(PRBool aRealEvent, void *aEvent)
00219 {
00220   nsToolkit::mDispatchMessage((MSG *)aEvent);
00221   return NS_OK;
00222 }
00223 
00224 //-------------------------------------------------------------------------
00225 //
00226 // Exit a message handler loop
00227 //
00228 //-------------------------------------------------------------------------
00229 
00230 NS_METHOD nsAppShell::Exit(void)
00231 {
00232   PostQuitMessage(0);
00233   //
00234   // Also, set a global flag, just in case someone eats the WM_QUIT message.
00235   // see bug #54725.
00236   //
00237   gKeepGoing = 0;
00238   return NS_OK;
00239 }
00240 
00241 //-------------------------------------------------------------------------
00242 //
00243 // nsAppShell destructor
00244 //
00245 //-------------------------------------------------------------------------
00246 nsAppShell::~nsAppShell()
00247 {
00248 }
00249