Files
Mozilla/mozilla/widget/src/os2/nsAppShell.cpp
dbaron%fas.harvard.edu 3485888237 Replace uses of deprecated NS_IMPL_ISUPPORTS and NS_IMPL_QUERYINTERFACE macros with NS_IMPL_{ISUPPORTS,QUERYINTERFACE}{1,0}. r=jag rs=brendan b=45797
git-svn-id: svn://10.0.0.236/trunk@101462 18797224-902f-48f8-a5cc-f745e15eee43
2001-08-21 01:48:11 +00:00

319 lines
8.2 KiB
C++

/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Mozilla OS/2 libraries.
*
* The Initial Developer of the Original Code is John Fairhurst,
* <john_fairhurst@iname.com>. Portions created by John Fairhurst are
* Copyright (C) 1999 John Fairhurst. All Rights Reserved.
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
*
*/
#include "nsAppShell.h"
#include "nsToolkit.h"
#include "nsIWidget.h"
#include "nsHashtable.h"
#include "nsIEventQueueService.h"
#include "nsIServiceManager.h"
#include "nsWidgetsCID.h"
#include "nsITimer.h"
#include "nsITimerQueue.h"
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kTimerManagerCID, NS_TIMERMANAGER_CID);
// Appshell manager. Same threads must get the same appshell object,
// or else the message queue will be taken over by the second (nested)
// appshell and subsequently killed when it does. This is bad because
// the main (first) appshell should still be running.
TID QueryCurrentTID();
class nsAppshellManager
{
HMTX mLock;
nsHashtable *mTable;
struct ThreadKey : public nsVoidKey
{
ThreadKey() : nsVoidKey( (void*) QueryCurrentTID()) {}
};
public:
nsAppshellManager()
{
mTable = new nsHashtable;
DosCreateMutexSem( 0, &mLock, 0, FALSE /*unowned*/);
}
~nsAppshellManager()
{
DosCloseMutexSem( mLock);
delete mTable;
}
nsIAppShell *GetAppshell()
{
ThreadKey key;
DosRequestMutexSem( mLock, SEM_INDEFINITE_WAIT);
nsIAppShell *pShell = (nsIAppShell*) mTable->Get( &key);
if( nsnull == pShell)
{
pShell = new nsAppShell;
mTable->Put( &key, (void*) pShell);
}
DosReleaseMutexSem( mLock);
return pShell;
}
void RemoveAppshell( nsIAppShell *aShell)
{
ThreadKey key;
DosRequestMutexSem( mLock, SEM_INDEFINITE_WAIT);
nsIAppShell *pShell = (nsIAppShell*) mTable->Get( &key);
if( pShell == aShell)
mTable->Remove( &key);
#ifdef DEBUG
else
printf( "Appshell object dying in a foreign thread\n");
#endif
DosReleaseMutexSem( mLock);
}
};
static nsAppshellManager *pManager = nsnull;
NS_IMPL_ISUPPORTS1(nsAppShell, nsIAppShell)
// nsAppShell constructor
nsAppShell::nsAppShell()
{
NS_INIT_REFCNT();
mDispatchListener = 0;
mHab = 0; mHmq = 0;
mQuitNow = FALSE;
memset( &mQmsg, 0, sizeof mQmsg);
}
nsresult nsAppShell::SetDispatchListener( nsDispatchListener *aDispatchListener)
{
mDispatchListener = aDispatchListener;
return NS_OK;
}
// Create the application shell
nsresult nsAppShell::Create( int */*argc*/, char **/*argv*/)
{
// It is possible that there already is a HAB/HMQ for this thread.
// This condition arises when an event queue (underlying, PLEvent) is
// created before the appshell.
// When this happens, we must take over ownership of these existing
// objects (and so destroy them when we go, too).
if( FALSE == WinQueryQueueInfo( HMQ_CURRENT, 0, 0))
{
mHab = WinInitialize( 0);
mHmq = WinCreateMsgQueue( mHab, 0);
}
else
{
mHab = 0; // HABs don't actually seem to be checked, ever.
// But 0 == (current pid,current tid)
mHmq = HMQ_CURRENT;
}
return NS_OK;
}
// Enter a message handler loop
nsresult nsAppShell::Run()
{
if( !mHmq) return NS_ERROR_FAILURE; // (mHab = 0 is okay)
NS_ADDREF_THIS();
int keepGoing = 1;
#if 0
nsresult rv;
nsCOMPtr<nsITimerQueue> queue(do_GetService(kTimerManagerCID, &rv));
if (NS_FAILED(rv)) return rv;
#endif
// Process messages
do {
// Give priority to system messages (in particular keyboard, mouse,
// timer, and paint messages).
if (WinPeekMsg((HAB)0, &mQmsg, NULL, WM_CHAR, WM_VIOCHAR, PM_REMOVE) ||
WinPeekMsg((HAB)0, &mQmsg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) ||
WinPeekMsg((HAB)0, &mQmsg, NULL, 0, WM_USER-1, PM_REMOVE) ||
WinPeekMsg((HAB)0, &mQmsg, NULL, 0, 0, PM_REMOVE)) {
if (mQmsg.msg != WM_QUIT) {
WinDispatchMsg((HAB)0, &mQmsg);
if (mDispatchListener)
mDispatchListener->AfterDispatch();
} else {
if( mQmsg.hwnd) {
// send WM_SYSCOMMAND, SC_CLOSE to window (tasklist close)
WinSendMsg( mQmsg.hwnd, WM_SYSCOMMAND, MPFROMSHORT(SC_CLOSE), 0);
} else {
if( mQuitNow) // Don't want to close the app when a window
keepGoing = 0; // is closed, just when our `Exit' is called.
}
}
#if 0
// process timer queue.
} else if (queue->HasReadyTimers(NS_PRIORITY_LOWEST)) {
do {
queue->FireNextReadyTimer(NS_PRIORITY_LOWEST);
} while (queue->HasReadyTimers(NS_PRIORITY_LOWEST) &&
!WinPeekMsg((HAB)0, &mQmsg, NULL, 0, 0, PM_NOREMOVE));
#endif
} else {
// Block and wait for any posted application message
WinWaitMsg((HAB)0, 0, 0);
}
} while (keepGoing != 0);
// reset mQuitNow flag for re-entrant appshells
mQuitNow = FALSE;
Release();
return NS_OK;
}
// GetNativeData - return the HMQ for NS_NATIVE_SHELL
void *nsAppShell::GetNativeData( PRUint32 aDataType)
{
void *rc = 0;
switch( aDataType)
{
case NS_NATIVE_SHELL: rc = (void*) mHmq; break;
}
return rc;
}
// Exit a message handler loop
nsresult nsAppShell::Exit()
{
NS_ASSERTION( mQuitNow == FALSE, "Double AppShell::Exit");
mQuitNow = TRUE;
WinPostQueueMsg( mHmq, WM_QUIT, 0, 0);
return NS_OK;
}
// nsAppShell destructor
nsAppShell::~nsAppShell()
{
WinDestroyMsgQueue( mHmq);
WinTerminate( mHab);
}
// These are for modal dialogs and also tres weird.
//
// XXX must handle WM_QUIT sensibly (close window)
// -- dependency on xptoolkit dialogs being close by other means.
//
nsresult nsAppShell::GetNativeEvent( PRBool &aRealEvent, void *&aEvent)
{
PRBool gotMessage = PR_FALSE;
#if 0
nsresult rv;
nsCOMPtr<nsITimerQueue> queue(do_GetService(kTimerManagerCID, &rv));
if (NS_FAILED(rv)) return rv;
#endif
do {
// Give priority to system messages (in particular keyboard, mouse,
// timer, and paint messages).
if (WinPeekMsg((HAB)0, &mQmsg, NULL, WM_CHAR, WM_VIOCHAR, PM_REMOVE) ||
WinPeekMsg((HAB)0, &mQmsg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) ||
WinPeekMsg((HAB)0, &mQmsg, NULL, 0, WM_USER-1, PM_REMOVE) ||
WinPeekMsg((HAB)0, &mQmsg, NULL, 0, 0, PM_REMOVE)) {
gotMessage = PR_TRUE;
#if 0
// process timer queue.
} else if (queue->HasReadyTimers(NS_PRIORITY_LOWEST)) {
do {
queue->FireNextReadyTimer(NS_PRIORITY_LOWEST);
} while (queue->HasReadyTimers(NS_PRIORITY_LOWEST) &&
!WinPeekMsg((HAB)0, &mQmsg, NULL, 0, 0, PM_NOREMOVE));
#endif
} else {
// Block and wait for any posted application message
WinWaitMsg((HAB)0, 0, 0);
}
} while (gotMessage == PR_FALSE);
aEvent = &mQmsg;
aRealEvent = PR_TRUE;
return NS_OK;
}
nsresult nsAppShell::DispatchNativeEvent( PRBool /*aRealEvent*/, void */*aEvent*/)
{
WinDispatchMsg( mHab, &mQmsg);
return NS_OK;
}
extern "C" nsresult NS_CreateAppshell( nsIAppShell **aAppShell)
{
if( !aAppShell)
return NS_ERROR_NULL_POINTER;
if( !pManager)
{
pManager = new nsAppshellManager;
}
*aAppShell = pManager->GetAppshell();
// only do this the very first time
if (gWidgetModuleData == nsnull)
{
gWidgetModuleData = new nsWidgetModuleData();
gWidgetModuleData->Init(*aAppShell);
}
return NS_OK;
}
// Get the current TID [vacpp doesn't have gettid()]
TID QueryCurrentTID()
{
PTIB pTib = 0;
PPIB pPib = 0;
DosGetInfoBlocks( &pTib, &pPib);
return pTib->tib_ptib2->tib2_ultid;
}