зеркало из https://github.com/mozilla/gecko-dev.git
r=mkaply, a=brendan Bring nsToolkit up to par with the Windows code
This commit is contained in:
Родитель
5fa2999ab4
Коммит
428b8d9862
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef SWITCHTOUITHREAD_H
|
||||
#define SWITCHTOUITHREAD_H
|
||||
|
||||
|
||||
// foreward declaration
|
||||
struct MethodInfo;
|
||||
|
||||
/**
|
||||
* Switch thread to match the thread the widget was created in so messages will be dispatched.
|
||||
*/
|
||||
|
||||
class nsSwitchToUIThread {
|
||||
|
||||
public:
|
||||
virtual BOOL CallMethod(MethodInfo *info) = 0;
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// Structure used for passing the information necessary for synchronously
|
||||
// invoking a method on the GUI thread...
|
||||
//
|
||||
struct MethodInfo {
|
||||
nsSwitchToUIThread* target;
|
||||
UINT methodId;
|
||||
int nArgs;
|
||||
ULONG* args;
|
||||
|
||||
MethodInfo(nsSwitchToUIThread *obj, UINT id, int numArgs=0, ULONG *arguments = 0) {
|
||||
target = obj;
|
||||
methodId = id;
|
||||
nArgs = numArgs;
|
||||
args = arguments;
|
||||
}
|
||||
|
||||
BOOL Invoke() { return target->CallMethod(this); }
|
||||
};
|
||||
|
||||
#endif // TOUITHRD_H
|
||||
|
|
@ -1,257 +1,220 @@
|
|||
/*
|
||||
* 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/
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* The Original Code is the Mozilla OS/2 libraries.
|
||||
* 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 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.
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* John Fairhurst <john_fairhurst@iname.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* IBM Corp.
|
||||
*/
|
||||
|
||||
#include "nsToolkit.h"
|
||||
#include "nsSwitchToUIThread.h"
|
||||
|
||||
#include "nsIAppShell.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsIComponentManager.h"
|
||||
|
||||
static PRUintn gToolkitTLSIndex = 0;
|
||||
|
||||
// Bits to deal with the case where a new toolkit is initted with a null ----
|
||||
// thread. In this case it has to create a new thread to be the PM thread.
|
||||
// Hopefully this will never happen!
|
||||
|
||||
// struct passed to new thread
|
||||
struct ThreadInitInfo
|
||||
{
|
||||
PRMonitor *pMonitor;
|
||||
nsToolkit *toolkit;
|
||||
|
||||
ThreadInitInfo( nsToolkit *tk, PRMonitor *pMon)
|
||||
: pMonitor( pMon), toolkit( tk)
|
||||
{}
|
||||
};
|
||||
|
||||
// main for the message pump thread
|
||||
extern "C" void RunPump( void *arg)
|
||||
{
|
||||
ThreadInitInfo *info = (ThreadInitInfo *) arg;
|
||||
nsIAppShell *pShell = nsnull;
|
||||
nsresult res;
|
||||
|
||||
static NS_DEFINE_IID(kAppShellCID, NS_APPSHELL_CID);
|
||||
|
||||
res = nsComponentManager::CreateInstance( kAppShellCID, nsnull,
|
||||
NS_GET_IID(nsIAppShell),
|
||||
(void **) &pShell);
|
||||
NS_ASSERTION( res == NS_OK, "Couldn't create new shell");
|
||||
|
||||
pShell->Create( 0, 0);
|
||||
|
||||
// do registration and creation in this thread
|
||||
info->toolkit->CreateInternalWindow( PR_GetCurrentThread());
|
||||
|
||||
// let the main thread continue
|
||||
PR_EnterMonitor( info->pMonitor);
|
||||
PR_Notify( info->pMonitor);
|
||||
PR_ExitMonitor( info->pMonitor);
|
||||
|
||||
pShell->Run();
|
||||
NS_RELEASE( pShell);
|
||||
}
|
||||
|
||||
// toolkit method to create a new thread and process the msgq there
|
||||
void nsToolkit::CreatePMThread()
|
||||
{
|
||||
PR_EnterMonitor( mMonitor);
|
||||
|
||||
ThreadInitInfo ti( this, mMonitor);
|
||||
|
||||
// create a pm thread
|
||||
mPMThread = ::PR_CreateThread( PR_SYSTEM_THREAD,
|
||||
RunPump,
|
||||
&ti,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_LOCAL_THREAD,
|
||||
PR_UNJOINABLE_THREAD,
|
||||
0);
|
||||
// wait for it to start
|
||||
PR_Wait( mMonitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
PR_ExitMonitor( mMonitor);
|
||||
}
|
||||
|
||||
// 'Normal use' toolkit methods ---------------------------------------------
|
||||
nsToolkit::nsToolkit() : mDispatchWnd( 0), mPMThread( 0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mMonitor = PR_NewMonitor();
|
||||
}
|
||||
|
||||
nsToolkit::~nsToolkit()
|
||||
{
|
||||
// Destroy the Dispatch Window
|
||||
WinDestroyWindow( mDispatchWnd);
|
||||
|
||||
// Destroy monitor
|
||||
PR_DestroyMonitor( mMonitor);
|
||||
}
|
||||
|
||||
// nsISupports implementation macro
|
||||
NS_IMPL_ISUPPORTS(nsToolkit, NS_GET_IID(nsIToolkit))
|
||||
|
||||
static MRESULT EXPENTRY fnwpDispatch( HWND, ULONG, MPARAM, MPARAM);
|
||||
#define UWC_DISPATCH "DispatchWndClass"
|
||||
//
|
||||
// Static thread local storage index of the Toolkit
|
||||
// object associated with a given thread...
|
||||
//
|
||||
static PRUintn gToolkitTLSIndex = 0;
|
||||
|
||||
// Create the internal window - also sets the pm thread 'formally'
|
||||
void nsToolkit::CreateInternalWindow( PRThread *aThread)
|
||||
{
|
||||
NS_PRECONDITION(aThread, "null thread");
|
||||
mPMThread = aThread;
|
||||
//
|
||||
// main for the message pump thread
|
||||
//
|
||||
PRBool gThreadState = PR_FALSE;
|
||||
|
||||
BOOL rc = WinRegisterClass( 0/*hab*/, UWC_DISPATCH, fnwpDispatch, 0, 0);
|
||||
NS_ASSERTION( rc, "Couldn't register class");
|
||||
|
||||
// create the internal window - just use a static
|
||||
mDispatchWnd = WinCreateWindow( HWND_DESKTOP,
|
||||
UWC_DISPATCH,
|
||||
0, 0,
|
||||
0, 0, 0, 0,
|
||||
HWND_DESKTOP,
|
||||
HWND_BOTTOM,
|
||||
0, 0, 0);
|
||||
|
||||
NS_ASSERTION( mDispatchWnd, "Couldn't create toolkit internal window");
|
||||
|
||||
#if DEBUG_sobotka
|
||||
printf("\n+++++++++++nsToolkit created dispatch window 0x%lx\n", mDispatchWnd);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set up the toolkit - create window, check for thread.
|
||||
nsresult nsToolkit::Init( PRThread *aThread)
|
||||
{
|
||||
// Store the thread ID of the thread with the message queue.
|
||||
// If no thread is provided create one (!!)
|
||||
if( aThread)
|
||||
CreateInternalWindow( aThread);
|
||||
else
|
||||
// create a thread where the message pump will run
|
||||
CreatePMThread();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Bits to reflect events into the pm thread --------------------------------
|
||||
|
||||
// additional structure to provide synchronization & returncode
|
||||
// Unlike Windows, we cannot use WinSendMsg()
|
||||
struct RealMethodInfo
|
||||
{
|
||||
MethodInfo *pInfo;
|
||||
PRMonitor *pMonitor;
|
||||
nsresult rc;
|
||||
|
||||
RealMethodInfo( MethodInfo *info, PRMonitor *pMon)
|
||||
: pInfo( info), pMonitor( pMon), rc( NS_ERROR_FAILURE)
|
||||
{}
|
||||
struct ThreadInitInfo {
|
||||
PRMonitor *monitor;
|
||||
nsToolkit *toolkit;
|
||||
};
|
||||
|
||||
nsresult nsToolkit::CallMethod( MethodInfo *pInfo)
|
||||
void PR_CALLBACK RunPump(void* arg)
|
||||
{
|
||||
PR_EnterMonitor( mMonitor);
|
||||
ThreadInitInfo *info = (ThreadInitInfo*)arg;
|
||||
::PR_EnterMonitor(info->monitor);
|
||||
|
||||
RealMethodInfo rminfo( pInfo, mMonitor);
|
||||
// do registration and creation in this thread
|
||||
info->toolkit->CreateInternalWindow(PR_GetCurrentThread());
|
||||
|
||||
// post the message to the window
|
||||
WinPostMsg( mDispatchWnd, WMU_CALLMETHOD, MPFROMP(&rminfo), 0);
|
||||
gThreadState = PR_TRUE;
|
||||
|
||||
// wait for it to complete...
|
||||
PR_Wait( mMonitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
PR_ExitMonitor( mMonitor);
|
||||
::PR_Notify(info->monitor);
|
||||
::PR_ExitMonitor(info->monitor);
|
||||
|
||||
// cleanup & return
|
||||
return rminfo.rc;
|
||||
delete info;
|
||||
|
||||
// Process messages
|
||||
QMSG qmsg;
|
||||
while (WinGetMsg((HAB)0, &qmsg, 0, 0, 0)) {
|
||||
WinDispatchMsg((HAB)0, &qmsg);
|
||||
}
|
||||
}
|
||||
|
||||
struct SendMsgStruct
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// constructor
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
nsToolkit::nsToolkit()
|
||||
{
|
||||
HWND hwnd;
|
||||
ULONG msg;
|
||||
MPARAM mp1, mp2;
|
||||
MRESULT rc;
|
||||
|
||||
PRMonitor *pMonitor;
|
||||
|
||||
SendMsgStruct( HWND h, ULONG m, MPARAM p1, MPARAM p2, PRMonitor *pMon)
|
||||
: hwnd( h), msg( m), mp1( p1), mp2( p2), rc( 0), pMonitor( pMon)
|
||||
{}
|
||||
};
|
||||
|
||||
MRESULT nsToolkit::SendMsg( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
|
||||
{
|
||||
MRESULT rc = 0;
|
||||
|
||||
if( hwnd && IsPMThread())
|
||||
rc = WinSendMsg( hwnd, msg, mp1, mp2);
|
||||
else if( hwnd)
|
||||
{
|
||||
PR_EnterMonitor( mMonitor);
|
||||
|
||||
SendMsgStruct data( hwnd, msg, mp1, mp2, mMonitor);
|
||||
|
||||
// post a message to the window
|
||||
WinPostMsg( mDispatchWnd, WMU_SENDMSG, MPFROMP(&data), 0);
|
||||
|
||||
// wait for it to complete...
|
||||
PR_Wait( mMonitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
PR_ExitMonitor( mMonitor);
|
||||
|
||||
rc = data.rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
NS_INIT_REFCNT();
|
||||
mGuiThread = NULL;
|
||||
mDispatchWnd = 0;
|
||||
mMonitor = PR_NewMonitor();
|
||||
}
|
||||
|
||||
MRESULT EXPENTRY fnwpDispatch( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// destructor
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
nsToolkit::~nsToolkit()
|
||||
{
|
||||
MRESULT mRC = 0;
|
||||
NS_PRECONDITION(::WinIsWindow((HAB)0, mDispatchWnd), "Invalid window handle");
|
||||
|
||||
if( msg == WMU_CALLMETHOD)
|
||||
{
|
||||
RealMethodInfo *pInfo = (RealMethodInfo*) mp1;
|
||||
// call the method (indirection-fest :-)
|
||||
pInfo->rc = pInfo->pInfo->target->CallMethod( pInfo->pInfo);
|
||||
// signal the monitor to let the caller continue
|
||||
PR_EnterMonitor( pInfo->pMonitor);
|
||||
PR_Notify( pInfo->pMonitor);
|
||||
PR_ExitMonitor( pInfo->pMonitor);
|
||||
}
|
||||
else if( msg == WMU_SENDMSG)
|
||||
{
|
||||
SendMsgStruct *pData = (SendMsgStruct*) mp1;
|
||||
// send the message
|
||||
pData->rc = WinSendMsg( pData->hwnd, pData->msg, pData->mp1, pData->mp2);
|
||||
// signal the monitor to let the caller continue
|
||||
PR_EnterMonitor( pData->pMonitor);
|
||||
PR_Notify( pData->pMonitor);
|
||||
PR_ExitMonitor( pData->pMonitor);
|
||||
}
|
||||
else
|
||||
mRC = WinDefWindowProc( hwnd, msg, mp1, mp2);
|
||||
// Destroy the Dispatch Window
|
||||
::WinDestroyWindow(mDispatchWnd);
|
||||
mDispatchWnd = NULL;
|
||||
|
||||
return mRC;
|
||||
// Remove the TLS reference to the toolkit...
|
||||
PR_SetThreadPrivate(gToolkitTLSIndex, nsnull);
|
||||
PR_DestroyMonitor( mMonitor);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Register the window class for the internal window and create the window
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
void nsToolkit::CreateInternalWindow(PRThread *aThread)
|
||||
{
|
||||
|
||||
NS_PRECONDITION(aThread, "null thread");
|
||||
mGuiThread = aThread;
|
||||
|
||||
//
|
||||
// create the internal window
|
||||
//
|
||||
WinRegisterClass((HAB)0, "nsToolkitClass", nsToolkitWindowProc, NULL, 0);
|
||||
mDispatchWnd = ::WinCreateWindow(HWND_DESKTOP,
|
||||
"nsToolkitClass",
|
||||
"NetscapeDispatchWnd",
|
||||
WS_DISABLED,
|
||||
-50, -50,
|
||||
10, 10,
|
||||
HWND_DESKTOP,
|
||||
HWND_BOTTOM,
|
||||
0, 0, 0);
|
||||
VERIFY(mDispatchWnd);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Create a new thread and run the message pump in there
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
void nsToolkit::CreateUIThread()
|
||||
{
|
||||
PRMonitor *monitor = ::PR_NewMonitor();
|
||||
|
||||
::PR_EnterMonitor(monitor);
|
||||
|
||||
ThreadInitInfo *ti = new ThreadInitInfo();
|
||||
ti->monitor = monitor;
|
||||
ti->toolkit = this;
|
||||
|
||||
// create a gui thread
|
||||
mGuiThread = ::PR_CreateThread(PR_SYSTEM_THREAD,
|
||||
RunPump,
|
||||
(void*)ti,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_LOCAL_THREAD,
|
||||
PR_UNJOINABLE_THREAD,
|
||||
0);
|
||||
|
||||
// wait for the gui thread to start
|
||||
while(gThreadState == PR_FALSE) {
|
||||
::PR_Wait(monitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
// at this point the thread is running
|
||||
::PR_ExitMonitor(monitor);
|
||||
::PR_DestroyMonitor(monitor);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
NS_METHOD nsToolkit::Init(PRThread *aThread)
|
||||
{
|
||||
// Store the thread ID of the thread containing the message pump.
|
||||
// If no thread is provided create one
|
||||
if (NULL != aThread) {
|
||||
CreateInternalWindow(aThread);
|
||||
} else {
|
||||
// create a thread where the message pump will run
|
||||
CreateUIThread();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// nsToolkit WindowProc. Used to call methods on the "main GUI thread"...
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
MRESULT EXPENTRY nsToolkitWindowProc(HWND hWnd, ULONG msg, MPARAM mp1,
|
||||
MPARAM mp2)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_CALLMETHOD:
|
||||
{
|
||||
MethodInfo *info = (MethodInfo *)mp2;
|
||||
PRMonitor *monitor = (PRMonitor *)mp1;
|
||||
info->Invoke();
|
||||
PR_EnterMonitor(monitor);
|
||||
PR_Notify(monitor);
|
||||
PR_ExitMonitor(monitor);
|
||||
}
|
||||
case WM_SENDMSG:
|
||||
{
|
||||
SendMsgStruct *pData = (SendMsgStruct*) mp1;
|
||||
// send the message
|
||||
pData->rc = WinSendMsg( pData->hwnd, pData->msg, pData->mp1, pData->mp2);
|
||||
// signal the monitor to let the caller continue
|
||||
PR_EnterMonitor( pData->pMonitor);
|
||||
PR_Notify( pData->pMonitor);
|
||||
PR_ExitMonitor( pData->pMonitor);
|
||||
}
|
||||
default:
|
||||
return ::WinDefWindowProc(hWnd, msg, mp1, mp2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Return the nsIToolkit for the current thread. If a toolkit does not
|
||||
|
@ -300,3 +263,38 @@ NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult)
|
|||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsToolkit::CallMethod(MethodInfo *info)
|
||||
{
|
||||
PR_EnterMonitor(mMonitor);
|
||||
|
||||
::WinPostMsg(mDispatchWnd, WM_CALLMETHOD, MPFROMP(mMonitor), MPFROMP(info));
|
||||
|
||||
PR_Wait(mMonitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
PR_ExitMonitor( mMonitor);
|
||||
}
|
||||
|
||||
MRESULT nsToolkit::SendMsg( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
|
||||
{
|
||||
MRESULT rc = 0;
|
||||
|
||||
if( hwnd && IsGuiThread())
|
||||
rc = WinSendMsg( hwnd, msg, mp1, mp2);
|
||||
else if( hwnd)
|
||||
{
|
||||
PR_EnterMonitor( mMonitor);
|
||||
|
||||
SendMsgStruct data( hwnd, msg, mp1, mp2, mMonitor);
|
||||
|
||||
// post a message to the window
|
||||
WinPostMsg( mDispatchWnd, WM_SENDMSG, MPFROMP(&data), 0);
|
||||
|
||||
// wait for it to complete...
|
||||
PR_Wait( mMonitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
PR_ExitMonitor( mMonitor);
|
||||
|
||||
rc = data.rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,117 +1,91 @@
|
|||
/*
|
||||
* 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/
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* The Original Code is the Mozilla OS/2 libraries.
|
||||
* 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 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.
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* John Fairhurst <john_fairhurst@iname.com>
|
||||
* IBM Corp.
|
||||
*/
|
||||
|
||||
#ifndef _toolkit_h
|
||||
#define _toolkit_h
|
||||
#ifndef TOOLKIT_H
|
||||
#define TOOLKIT_H
|
||||
|
||||
#include "nsdefs.h"
|
||||
#include "nsIToolkit.h"
|
||||
#include "nsWidgetDefs.h"
|
||||
#include "prmon.h"
|
||||
|
||||
// This is a wrapper around the 'pm thread' which runs the message queue.
|
||||
// Need to do this to 1) ensure windows are always created/destroyed etc.
|
||||
// in the same thread, 2) because there's no guarantee that a calling
|
||||
// thread will have a message queue.
|
||||
//
|
||||
// In normal operation, a top level window will be created with a null
|
||||
// toolkit. This creates a new toolkit & init's with the current thread.
|
||||
// There is an assumption that there is an nsAppShell for that thread,
|
||||
// which becomes the 'PM thread'. A null thread can be passed in, in
|
||||
// which case a new thread is created & set to be the PM thread - this
|
||||
// shouldn't really happen because there's no condition for thread#1 to
|
||||
// exit!
|
||||
//
|
||||
// To allow non-pm threads to call pm functions, a slightly contorted
|
||||
// mechanism is used.
|
||||
//
|
||||
// The object which wishes to do tasks in the pm thread (eg. nsWindow) must
|
||||
// derive from the nsSwitchToPMThread class.
|
||||
// At task-time, create an instance of MethodInfo and call the 'CallMethod'
|
||||
// method in the widget's toolkit. This will call back into the object's
|
||||
// 'CallMethod' in the pm thread, and not return until it does.
|
||||
//
|
||||
// The good news is that you probably don't need to worry about this!
|
||||
//
|
||||
// What you may need to 'worry about' is the 'SendMsg' method. When you
|
||||
// want to call WinSendMsg & you're not certain you're in the PM thread,
|
||||
// use this one, and the right thing will happen.
|
||||
|
||||
struct MethodInfo;
|
||||
|
||||
/**
|
||||
* Wrapper around the thread running the message pump.
|
||||
* The toolkit abstraction is necessary because the message pump must
|
||||
* execute within the same thread that created the widget under Win32.
|
||||
*/
|
||||
|
||||
class nsToolkit : public nsIToolkit
|
||||
{
|
||||
public:
|
||||
nsToolkit();
|
||||
virtual ~nsToolkit();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
public:
|
||||
|
||||
NS_IMETHOD Init( PRThread *aThread);
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsresult CallMethod( MethodInfo *info);
|
||||
MRESULT SendMsg( HWND hwnd, ULONG msg, MPARAM mp1 = 0, MPARAM mp2 = 0);
|
||||
nsToolkit();
|
||||
NS_IMETHOD Init(PRThread *aThread);
|
||||
void CallMethod(MethodInfo *info);
|
||||
MRESULT SendMsg(HWND hwnd, ULONG msg, MPARAM mp1 = 0, MPARAM mp2 = 0);
|
||||
// Return whether the current thread is the application's Gui thread.
|
||||
PRBool IsGuiThread(void) { return (PRBool)(mGuiThread == PR_GetCurrentThread());}
|
||||
PRThread* GetGuiThread(void) { return mGuiThread; }
|
||||
HWND GetDispatchWindow(void) { return mDispatchWnd; }
|
||||
void CreateInternalWindow(PRThread *aThread);
|
||||
|
||||
// Return whether the current thread is the application's PM thread.
|
||||
PRBool IsPMThread() { return (PRBool)(mPMThread == PR_GetCurrentThread());}
|
||||
PRThread *GetPMThread() { return mPMThread; }
|
||||
HWND GetDispatchWindow() { return mDispatchWnd; }
|
||||
private:
|
||||
~nsToolkit();
|
||||
void CreateUIThread(void);
|
||||
|
||||
void CreateInternalWindow( PRThread *aThread);
|
||||
public:
|
||||
|
||||
private:
|
||||
void CreatePMThread();
|
||||
|
||||
protected:
|
||||
// Handle of the window used to receive dispatch messages.
|
||||
HWND mDispatchWnd;
|
||||
// Thread Id of the PM thread.
|
||||
PRThread *mPMThread;
|
||||
// Monitor used to coordinate dispatch
|
||||
PRMonitor *mMonitor;
|
||||
protected:
|
||||
// Handle of the window used to receive dispatch messages.
|
||||
HWND mDispatchWnd;
|
||||
// Thread Id of the "main" Gui thread.
|
||||
PRThread *mGuiThread;
|
||||
// Monitor used to coordinate dispatch
|
||||
PRMonitor *mMonitor;
|
||||
};
|
||||
|
||||
// Interface to derive things from
|
||||
class nsSwitchToPMThread
|
||||
// Window procedure for the internal window
|
||||
static MRESULT EXPENTRY nsToolkitWindowProc(HWND, ULONG, MPARAM, MPARAM);
|
||||
|
||||
#define WM_CALLMETHOD (WM_USER+1)
|
||||
#define WM_SENDMSG (WM_USER+2)
|
||||
|
||||
struct SendMsgStruct
|
||||
{
|
||||
public:
|
||||
// No return code: if this is a problem then
|
||||
virtual nsresult CallMethod( MethodInfo *info) = 0;
|
||||
HWND hwnd;
|
||||
ULONG msg;
|
||||
MPARAM mp1, mp2;
|
||||
MRESULT rc;
|
||||
|
||||
PRMonitor *pMonitor;
|
||||
|
||||
SendMsgStruct( HWND h, ULONG m, MPARAM p1, MPARAM p2, PRMonitor *pMon)
|
||||
: hwnd( h), msg( m), mp1( p1), mp2( p2), rc( 0), pMonitor( pMon)
|
||||
{}
|
||||
};
|
||||
|
||||
// Structure used for passing the information
|
||||
struct MethodInfo
|
||||
{
|
||||
nsSwitchToPMThread *target;
|
||||
UINT methodId;
|
||||
int nArgs;
|
||||
ULONG *args;
|
||||
|
||||
MethodInfo( nsSwitchToPMThread *obj, UINT id,
|
||||
int numArgs = 0, ULONG *arguments = 0)
|
||||
{
|
||||
target = obj;
|
||||
methodId = id;
|
||||
nArgs = numArgs;
|
||||
args = arguments;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // TOOLKIT_H
|
||||
|
|
|
@ -223,7 +223,7 @@ void nsWindow::DoCreate( HWND hwndP, nsWindow *aParent, const nsRect &aRect,
|
|||
}
|
||||
|
||||
// Switch to the PM thread if necessary...
|
||||
if( !mOS2Toolkit->IsPMThread())
|
||||
if( !mOS2Toolkit->IsGuiThread())
|
||||
{
|
||||
ULONG args[7] = { hwndP, (ULONG) aParent, (ULONG) &aRect,
|
||||
(ULONG) aHandleEventFunction,
|
||||
|
@ -394,7 +394,7 @@ nsWindow::~nsWindow()
|
|||
nsresult nsWindow::Destroy()
|
||||
{
|
||||
// Switch to the PM thread if necessary...
|
||||
if( mToolkit && !mOS2Toolkit->IsPMThread())
|
||||
if( mToolkit && !mOS2Toolkit->IsGuiThread())
|
||||
{
|
||||
MethodInfo info( this, nsWindow::W_DESTROY);
|
||||
mOS2Toolkit->CallMethod( &info);
|
||||
|
@ -1657,7 +1657,7 @@ nsresult nsWindow::Enable( PRBool bState)
|
|||
nsresult nsWindow::SetFocus()
|
||||
{
|
||||
// Switch to the PM thread if necessary...
|
||||
if( !mOS2Toolkit->IsPMThread())
|
||||
if( !mOS2Toolkit->IsGuiThread())
|
||||
{
|
||||
MethodInfo info(this, nsWindow::W_SET_FOCUS);
|
||||
mOS2Toolkit->CallMethod(&info);
|
||||
|
@ -2106,7 +2106,7 @@ nsresult nsWindow::InvalidateRegion(const nsIRegion *aRegion, PRBool aIsSynchron
|
|||
nsresult nsWindow::Update()
|
||||
{
|
||||
// Switch to the PM thread if necessary...
|
||||
if( !mOS2Toolkit->IsPMThread())
|
||||
if( !mOS2Toolkit->IsGuiThread())
|
||||
{
|
||||
MethodInfo info(this, nsWindow::W_UPDATE_WINDOW);
|
||||
mOS2Toolkit->CallMethod(&info);
|
||||
|
@ -2119,7 +2119,7 @@ nsresult nsWindow::Update()
|
|||
nsresult nsWindow::SetTitle( const nsString &aTitle)
|
||||
{
|
||||
// Switch to the PM thread if necessary...
|
||||
if( mOS2Toolkit && !mOS2Toolkit->IsPMThread())
|
||||
if( mOS2Toolkit && !mOS2Toolkit->IsGuiThread())
|
||||
{
|
||||
ULONG ulong = (ULONG) &aTitle;
|
||||
MethodInfo info( this, nsWindow::W_SET_TITLE, 1, &ulong);
|
||||
|
@ -2136,7 +2136,7 @@ nsresult nsWindow::SetTitle( const nsString &aTitle)
|
|||
nsresult nsWindow::GetWindowText( nsString &aStr, PRUint32 *rc)
|
||||
{
|
||||
// Switch to the PM thread if necessary...
|
||||
if( !mOS2Toolkit->IsPMThread())
|
||||
if( !mOS2Toolkit->IsGuiThread())
|
||||
{
|
||||
ULONG args[] = { (ULONG) &aStr, (ULONG) rc };
|
||||
MethodInfo info( this, nsWindow::W_GET_TITLE, 2, args);
|
||||
|
@ -2359,9 +2359,9 @@ void nsWindow::FreeNativeData( void *aDatum, PRUint32 aDataType)
|
|||
}
|
||||
|
||||
// Thread switch callback
|
||||
nsresult nsWindow::CallMethod(MethodInfo *info)
|
||||
BOOL nsWindow::CallMethod(MethodInfo *info)
|
||||
{
|
||||
nsresult rc = NS_ERROR_FAILURE;
|
||||
BOOL bRet = TRUE;
|
||||
|
||||
switch( info->methodId)
|
||||
{
|
||||
|
@ -2376,7 +2376,7 @@ nsresult nsWindow::CallMethod(MethodInfo *info)
|
|||
(nsIAppShell*) (info->args[5]),
|
||||
nsnull, /* toolkit */
|
||||
(nsWidgetInitData*) (info->args[6]));
|
||||
rc = NS_OK;
|
||||
bRet = TRUE;
|
||||
break;
|
||||
#if 0
|
||||
case nsWindow::W_CREATE:
|
||||
|
@ -2387,7 +2387,7 @@ nsresult nsWindow::CallMethod(MethodInfo *info)
|
|||
(nsIAppShell *)(info->args[4]),
|
||||
(nsIToolkit*)(info->args[5]),
|
||||
(nsWidgetInitData*)(info->args[6]));
|
||||
rc = NS_OK;
|
||||
bRet = TRUE;
|
||||
break;
|
||||
|
||||
case nsWindow::W_CREATE_NATIVE:
|
||||
|
@ -2398,44 +2398,46 @@ nsresult nsWindow::CallMethod(MethodInfo *info)
|
|||
(nsIAppShell *)(info->args[4]),
|
||||
(nsIToolkit*)(info->args[5]),
|
||||
(nsWidgetInitData*)(info->args[6]));
|
||||
rc = NS_OK;
|
||||
bRet = TRUE;
|
||||
break;
|
||||
#endif
|
||||
case nsWindow::W_DESTROY:
|
||||
NS_ASSERTION(info->nArgs == 0, "Bad args to Destroy");
|
||||
Destroy();
|
||||
rc = NS_OK;
|
||||
bRet = TRUE;
|
||||
break;
|
||||
|
||||
case nsWindow::W_SET_FOCUS:
|
||||
NS_ASSERTION(info->nArgs == 0, "Bad args to SetFocus");
|
||||
SetFocus();
|
||||
rc = NS_OK;
|
||||
bRet = TRUE;
|
||||
break;
|
||||
|
||||
case nsWindow::W_UPDATE_WINDOW:
|
||||
NS_ASSERTION(info->nArgs == 0, "Bad args to UpdateWindow");
|
||||
Update();
|
||||
rc = NS_OK;
|
||||
bRet = TRUE;
|
||||
break;
|
||||
|
||||
case nsWindow::W_SET_TITLE:
|
||||
NS_ASSERTION(info->nArgs == 1, "Bad args to SetTitle");
|
||||
SetTitle( (const nsString &) info->args[0]);
|
||||
rc = NS_OK;
|
||||
bRet = TRUE;
|
||||
break;
|
||||
|
||||
case nsWindow::W_GET_TITLE:
|
||||
NS_ASSERTION(info->nArgs == 2, "Bad args to GetTitle");
|
||||
rc = GetWindowText( *((nsString*) info->args[0]),
|
||||
(PRUint32*)info->args[1]);
|
||||
GetWindowText( *((nsString*) info->args[0]),
|
||||
(PRUint32*)info->args[1]);
|
||||
bRet = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
bRet = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return bRet;
|
||||
}
|
||||
|
||||
// function to translate from a WM_CHAR to an NS VK_ constant ---------------
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "nsWidgetDefs.h"
|
||||
#include "nsBaseWidget.h"
|
||||
#include "nsToolkit.h"
|
||||
#include "nsSwitchToUIThread.h"
|
||||
|
||||
class nsIMenuBar;
|
||||
//class nsContextMenu;
|
||||
|
@ -54,7 +55,7 @@ class nsIMenuBar;
|
|||
// there to decide whether methods apply to frame or client.
|
||||
|
||||
class nsWindow : public nsBaseWidget,
|
||||
public nsSwitchToPMThread
|
||||
public nsSwitchToUIThread
|
||||
{
|
||||
public:
|
||||
// Scaffolding
|
||||
|
@ -148,7 +149,7 @@ class nsWindow : public nsBaseWidget,
|
|||
virtual void FreeNativeData( void *aDatum, PRUint32 aDataType);
|
||||
|
||||
// nsSwitchToPMThread interface
|
||||
NS_IMETHOD CallMethod( MethodInfo *info);
|
||||
virtual BOOL CallMethod(MethodInfo *info);
|
||||
|
||||
// PM methods which need to be public (menus, etc)
|
||||
ULONG GetNextID() { return mNextID++; }
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/NPL/
|
||||
*
|
||||
* 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 mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef NSDEFS_H
|
||||
#define NSDEFS_H
|
||||
|
||||
#include <os2.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define BREAK_TO_DEBUGGER DebugBreak()
|
||||
#else
|
||||
#define BREAK_TO_DEBUGGER
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define VERIFY(exp) ((exp) ? 0: (WinGetLastError((HAB)0), BREAK_TO_DEBUGGER))
|
||||
#else // !_DEBUG
|
||||
#define VERIFY(exp) (exp)
|
||||
#endif // !_DEBUG
|
||||
|
||||
#endif // NSDEFS_H
|
||||
|
||||
|
Загрузка…
Ссылка в новой задаче