![]() |
Analysis of PPBrowserLet's analyze PPBrowser!! On this section, I analyze the code of PPBrowser in practice.
|
int main()
{
SetDebugThrow_(PP_PowerPlant::debugAction_Alert); // Set Debugging options
SetDebugSignal_(PP_PowerPlant::debugAction_Alert);
PP_PowerPlant::InitializeHeap(3); // Initialize Memory Manager
// Parameter is number of Master Pointer
// blocks to allocate
PP_PowerPlant::UQDGlobals::InitializeToolbox(&qd); // Initialize standard Toolbox managers
#if DEBUG
::InitializeSIOUX(false);
#endif
::InitTSMAwareApplication();
new PP_PowerPlant::LGrowZone(20000); // Install a GrowZone function to catch low memory situations.
{
CBrowserApp theApp; // create instance of your application
theApp.Run();
}
::CloseTSMAwareApplication();
return 0;
}
|
In mozilla/lib/, there is InitializeMacToolbox() function that initializes Macintosh Toolbox related matters. But, PPBRowser uses PowerPlant and plain Macintosh functions to initialize Toolbox.
Most important process in this is to initialize EmbeddingAPI. This gets application's directory and by passing it to NS_InitEmbedding(), initializes it.
CBrowserApp::CBrowserApp()
{
.
.
nsresult rv;
ProcessSerialNumber psn;
ProcessInfoRec processInfo;
FSSpec appSpec;
nsCOMPtr<nsILocalFileMac> macDir;
nsCOMPtr<nsILocalFile> appDir; // If this ends up being NULL, default is used
if (!::GetCurrentProcess(&psn)) {
processInfo.processInfoLength = sizeof(processInfo);
processInfo.processName = NULL;
processInfo.processAppSpec = &appSpec;
if (!::GetProcessInformation(&psn, &processInfo)) {
// Turn the FSSpec of the app into an FSSpec of the app's directory
::FSMakeFSSpec(appSpec.vRefNum, appSpec.parID, "\p", &appSpec);
// Make an nsILocalFile out of it
rv = NS_NewLocalFileWithFSSpec(&appSpec, PR_TRUE, getter_AddRefs(macDir));
if (NS_SUCCEEDED(rv))
appDir = do_QueryInterface(macDir);
}
}
rv = NS_InitEmbedding(appDir, nsnull);
|
And this initializes the preference "PP Browser" in system's preferences folder and sets English font size to 12.
nsMPFileLocProvider *locationProvider = new nsMPFileLocProvider;
ThrowIfNil_(locationProvider);
nsCOMPtr<nsIFile> rootDir;
rv = NS_GetSpecialDirectory(NS_MAC_PREFS_DIR, getter_AddRefs(rootDir));
ThrowIfError_(rv);
rv = locationProvider->Initialize(rootDir, "PP Browser");
ThrowIfError_(rv);
NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv);
if (NS_SUCCEEDED(rv)) {
prefs->ResetPrefs(;) // Needed because things read default prefs during startup
prefs->ReadUserPrefs();
// HACK ALERT: Since we don't have prefs UI, reduce the font size here by hand
prefs->SetIntPref("font.size.variable.x-western", 12);
prefs->SetIntPref("font.size.fixed.x-western", 12);
}
else
NS_ASSERTION(PR_FALSE, "Could not get preferences service");
}
|
Most important process in this is to terminate EmbeddingAPI. In addition, to save preference, to clean up UMacUnicode.
CBrowserApp::~CBrowserApp()
{
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv);
if (NS_SUCCEEDED(rv))
prefs->SavePrefFile();
UMacUnicode::ReleaseUnit();
NS_TermEmbedding();
}
|
In PowerPlant specific way, show initial main window.
void
CBrowserApp::StartUp()
{
ObeyCommand(PP_PowerPlant::cmd_New, nil); // EXAMPLE, create a new window
}
|
To do event processing necessary to mozilla, this overrides ProcessNextEvent().
void
CBrowserApp::ProcessNextEvent()
{
EventRecord macEvent;
// When on duty (application is in the foreground), adjust the
// cursor shape before waiting for the next event. Except for the
// very first time, this is the same as adjusting the cursor
// after every event.
if (IsOnDuty()) {
// Calling OSEventAvail with a zero event mask will always
// pass back a null event. However, it fills the EventRecord
// with the information we need to set the cursor shape--
// the mouse location in global coordinates and the state
// of the modifier keys.
::OSEventAvail(0, &macEvent);
AdjustCursor(macEvent);
}
// Retrieve the next event. Context switch could happen here.
SetUpdateCommandStatus(false);
Boolean gotEvent = ::WaitNextEvent(everyEvent, &macEvent, mSleepTime,
mMouseRgn);
// Let Attachments process the event. Continue with normal
// event dispatching unless suppressed by an Attachment.
if (LAttachable::ExecuteAttachments(msg_Event, &macEvent)) {
if (gotEvent) {
#if DEBUG
if (!SIOUXHandleOneEvent(&macEvent))
#endif
DispatchEvent(macEvent);
} else {
UseIdleTime(macEvent);
Repeater::DoIdlers(macEvent);
// yield to other threads
::PR_Sleep(PR_INTERVAL_NO_WAIT);
}
}
// Repeaters get time after every event
LPeriodical::DevoteTimeToRepeaters(macEvent);
Repeater::DoRepeaters(macEvent);
// Update status of menu items
if (IsOnDuty() && GetUpdateCommandStatus()) {
UpdateMenus();
}
}
|
One of event processings unique to mozilla is to call static member of Repeater class to make background process such as net process worked. This calls Repeater::DoIdlers() at each null event and calls Repeater::DoRepeaters() at each event loop.
Besides, this does SIOUX event processing for debug console when Debug Building is in effect.
This does cmd_New processing. In a way specific to PowerPlant, this creates main window and load URL into it. Here, URL is fixed up on "http://www.mozilla.org".
Boolean
CBrowserApp::ObeyCommand(
PP_PowerPlant::CommandT inCommand,
void *ioParam)
{
Boolean cmdHandled = true;
switch (inCommand) {
case PP_PowerPlant::cmd_New:
{
CBrowserWindow *theWindow = dynamic_cast<CBrowserWindow*
(LWindow::CreateWindow(wind_BrowserWindow, this));
ThrowIfNil_(theWindow);
// LWindow is not initially visible in PPob resource
theWindow->Show();
// Just for demo sake, load a URL
LStr255 urlString("http://www.mozilla.org");
theWindow->GetBrowserShell()->LoadURL((Ptr)&urlString[1],
urlString.Length());
}
break;
// Any that you don't handle, such as cmd_About and cmd_Quit,
// will be passed up to LApplication
default:
cmdHandled = PP_PowerPlant::LApplication::ObeyCommand(inCommand, ioParam);
break;
}
return cmdHandled;
}
|
CBrowserWindow class 
Class definition of CBrowserWindow has, as member variable associated with mozilla, a pointer to window widget that is representation unique to mozilla of the main window, a pointer to each instance held as child control and a pointer to chrome instance.
class CBrowserWindow : public LWindow,
public LListener,
public LBroadcaster
{
private:
typedef LWindow Inherited;
friend class CWebBrowserChrome;
public:
enum { class_ID = FOUR_CHAR_CODE('BroW') };
CBrowserWindow();
CBrowserWindow(LStream* inStream);
virtual ~CBrowserWindow();
.
.
protected:
nsCOMPtr<nsIWidget> mWindow;
CBrowserShell* mBrowserShell;
CWebBrowserChrome* mBrowserChrome;
LEditText* mURLField;
LStaticText* mStatusBar;
CThrobber* mThrobber;
LBevelButton *mBackButton, *mForwardButton, *mStopButton;
LProgressBar* mProgressBar;
};
|
Constructor of CBrowserWindow class creates an instance of mozilla widget for main window. And this creates browser chrome and associates browser chrome with itself.
CBrowserWindow::CBrowserWindow(LStream* inStream)
: LWindow(inStream),
mBrowserShell(NULL), mBrowserChrome(NULL),
mURLField(NULL), mStatusBar(NULL), mThrobber(NULL),
mBackButton(NULL), mForwardButton(NULL), mStopButton(NULL),
mProgressBar(NULL)
{
nsresult rv = CommonConstruct();
if (NS_FAILED(rv))
Throw_(NS_ERROR_GET_CODE(rv));
}
NS_IMETHODIMP CBrowserWindow::CommonConstruct()
{
nsresult rv;
// Make the base widget
mWindow = do_CreateInstance(kWindowCID, &rv);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
// Make our CWebBrowserChrome
mBrowserChrome = new CWebBrowserChrome;
NS_ENSURE_TRUE(mBrowserChrome, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(mBrowserChrome);
mBrowserChrome->BrowserWindow() = this;
return NS_OK;
}
|
Initializing process of each visual parts in PowerPlant is called in the order shown below.
Destructor of CBrowserWindow class disposes of browser chrome.
CBrowserWindow::~CBrowserWindow()
{
if (mBrowserShell)
mBrowserShell->SetTopLevelWindow(nsnull);
if (mBrowserChrome)
{
mBrowserChrome->BrowserShell() = nsnull;
mBrowserChrome->BrowserWindow() = nsnull;
NS_RELEASE(mBrowserChrome);
}
}
|
By widget instance created in constructor, this creates an actual mozilla window.
void CBrowserWindow::FinishCreate()
{
// Initialize the top level widget
// This needs to be done AFTER the subviews are constructed
// but BEFORE the subviews do FinishCreateSelf.
Rect portRect = GetMacPort()->portRect;
nsRect r(0, 0, portRect.right - portRect.left, portRect.bottom - portRect.top);
nsresult rv = mWindow->Create((nsNativeWidget)GetMacPort()
r, nsnull, nsnull, nsnull, nsnull, nsnull);
if (NS_FAILED(rv))
Throw_(NS_ERROR_GET_CODE(rv));
Inherited::FinishCreate();
}
|
Mozilla specific process in this method is to set up and initialize CWebBrowserChrome, to associate CBrowserShell with CWebBrowserChrome and to set up each child control to member variables.
void CBrowserWindow::FinishCreateSelf()
{
mBrowserShell = dynamic_cast<CBrowserShell*>(FindPaneByID(paneID_WebShellView));
ThrowIfNULL_(mBrowserShell); // Curtains if we don't have this
// Tell our CBrowserShell about the chrome
mBrowserShell->SetTopLevelWindow(mBrowserChrome);
// Tell our chrome about the CBrowserShell
mBrowserChrome->BrowserShell() = mBrowserShell;
// Find our subviews - When we have a way of creating this
// window with various chrome flags, we may or may not have
// all of these subviews so don't fail if they don't exist
mURLField = dynamic_cast<LEditText*>(FindPaneByID(paneID_URLField));
if (mURLField)
SwitchTarget(mURLField);
mStatusBar = dynamic_cast<LStaticText*>(FindPaneByID(paneID_StatusBar));
mThrobber = dynamic_cast<CThrobber*>(FindPaneByID(paneID_Throbber));
mProgressBar = dynamic_cast<LProgressBar*>(FindPaneByID(paneID_ProgressBar));
if (mProgressBar)
mProgressBar->Hide();
mBackButton = dynamic_cast<LBevelButton*>(FindPaneByID(paneID_BackButton));
if (mBackButton)
mBackButton->Disable();
mForwardButton = dynamic_cast<LBevelButton*>(FindPaneByID(paneID_ForwardButton));
if (mForwardButton)
mForwardButton->Disable();
mStopButton = dynamic_cast<LBevelButton*>(FindPaneBy ID(paneID_StopButton));
if (mStopButton)
mStopButton->Disable();
UReanimator::LinkListenerToControls(this, this, mUserCon);
StartListening();
StartBroadcasting();
}
|
Main window's geometric manipuration such as showing/hiding or resizing are requested to mozilla widget by way of nsCOMPtr<nsIWidget> mWindow.
void CBrowserWindow::ResizeFrameBy(SInt16 inWidthDelta,
SInt16 inHeightDelta,
Boolean inRefresh)
{
// Resize the widget BEFORE subviews get resized
Rect portRect = GetMacPort()->portRect;
mWindow->Resize(portRect.right - portRect.left, portRect.bottom - portRect.top
inRefresh);
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
}
void CBrowserWindow::ShowSelf()
{
Inherited::ShowSelf();
mWindow->Show(PR_TRUE);
}
|
This procedure does menu related matters. Instructions to child controls held by main window and Find procedure. All of them are requested to CBrowserShell.
Boolean CBrowserWindow::ObeyCommand(CommandT inCommand,
voi *ioParam)
{
#pragma unused(ioParam)
Boolean cmdHandled = true;
switch (inCommand)
{
case paneID_BackButton:
mBrowserShell->Back();
break;
case paneID_ForwardButton:
mBrowserShell->Forward();
break;
case paneID_StopButton:
mBrowserShell->Stop();
break;
case paneID_URLField:
{
SInt32 urlTextLen;
mURLField->GetText(nil, 0, &urlTextLen);
StPointerBlock urlTextPtr(urlTextLen, true, false);
mURLField->GetText(urlTextPtr.Get(), urlTextLen, &urlTextLen);
mBrowserShell->LoadURL(urlTextPtr.Get(), urlTextLen);
}
break;
case CBrowserShell::cmd_Find:
mBrowserShell->Find();
break;
case CBrowserShell::cmd_FindNext:
mBrowserShell->FindNext();
break;
default:
cmdHandled = false;
break;
}
if (!cmdHandled)
cmdHandled = Inherited::ObeyCommand(inCommand, ioParam);
return cmdHandled;
}
|
Method called by CWebBrowserChrome (browser chrome). Character string is converted to Unicode -> nsString -> Str255 by using nsAutoString, UMacUnicode.
NS_METHOD CBrowserWindow::SetStatus(const PRUnichar* aStatus)
{
if (mStatusBar)
{
nsAutoString statusStr(aStatus);
Str255 aStr;
UMacUnicode::StringToStr255(statusStr, aStr);
mStatusBar->SetDescriptor(aStr);
}
return NS_OK;
}
NS_METHOD CBrowserWindow::SetLocation(const nsString& aLocation)
{
if (mURLField)
{
Str255 aStr;
UMacUnicode::StringToStr255(aLocation, aStr);
mURLField->SetDescriptor(aStr);
}
return NS_OK;
}
|
Method called by CWebBrowserChrome at the start time of net process. This starts progress bar and throbber and enables Stop button.
NS_METHOD CBrowserWindow::OnStatusNetStart(nsIWebProgress *progress, nsIRequest *request,
PRInt32 progressStateFlags, PRUint32 status)
{
if (mProgressBar) {
mProgressBar->Show();
mProgressBar->SetIndeterminateFlag(true, true);
}
if (mThrobber)
mThrobber->Start();
if (mStopButton)
mStopButton->Enable();
// Inform any other interested parties
// Actually, all of the above stuff should done through
// broadcasters and listeners. But for demo's sake this
// better shows what's happening.
LBroadcaster::BroadcastMessage(msg_OnStartLoadDocument, 0);
return NS_OK;
}
|
Method called by CWebBrowserChrome at the end of net process. This stops progress bar and throbber, sets up status of Back & Forward buttons and disables Stop button.
NS_METHOD CBrowserWindow::OnStatusNetStop(nsIWebProgress *progress,
nsIRequest *request, PRInt32 progressStateFlags, PRUint32 status)
{
if (mThrobber)
mThrobber->Stop();
if (mProgressBar) {
if (mProgressBar->IsIndeterminate())
mProgressBar->Stop();
mProgressBar->Hide();
}
// Enable back, forward, stop
if (mBackButton)
mBrowserShell->CanGoBack() ?
mBackButton->Enable() : mBackButton->Disable();
if (mForwardButton)
mBrowserShell->CanGoForward() ?
mForwardButton->Enable() : mForwardButton->Disable();
if (mStopButton)
mStopButton->Disable();
// Inform any other interested parties
// Actually, all of the above stuff should done through
// broadcasters and listeners. But for demo's sake this
// better shows what's happening.
LBroadcaster::BroadcastMessage(msg_OnEndLoadDocument, 0);
return NS_OK;
}
|
Method called by CWebBrowserChrome at the progress change of net process. This updates the value of progress bar.
NS_METHOD CBrowserWindow::OnProgressChange(nsIWebProgress *progress, nsIRequest *request,
PRInt32 curSelfProgress, PRInt32 maxSelfProgress,
PRInt32 curTotalProgress, PRInt32 maxTotalProgress)
{
if (mProgressBar) {
if (maxTotalProgress != -1 && mProgressBar->IsIndeterminate())
mProgressBar->SetIndeterminateFlag(false, false);
else if (maxTotalProgress == -1 && !mProgressBar->IsIndeterminate())
mProgressBar->SetIndeterminateFlag(true, true);
if (!mProgressBar->IsIndeterminate()) {
PRInt32 aMax = max(0, maxTotalProgress);
PRInt32 aVal = min(aMax, max(0, curTotalProgress));
mProgressBar->SetMaxValue(aMax);
mProgressBar->SetValue(aVal);
}
}
return NS_OK;
}
|
CBrowserShell class
Class definition of CBrowserShell has, as member variables associated with mozilla, initial URL character string, a pointer to interface associated with WebBrowser and a pointer to Find Component. And, this has, as a static member, message sink with which events are send to mozilla.
class CBrowserShell : public LView,
public LCommander,
public LPeriodical,
public LListener
{
private:
typedef LView Inherited;
public:
enum { class_ID = FOUR_CHAR_CODE('BroS') };
enum { cmd_Find = 'Find', cmd_FindNext = 'FNxt' };
CBrowserShell();
CBrowserShell(LStream* inStream);
virtual ~CBrowserShell();
.
.
protected:
static nsMacMessageSink mMessageSink;
LStr255 mInitURL;
nsCOMPtr<nsIWebBrowser> mWebBrowser; // The thing we actually create
nsCOMPtr<nsIBaseWindow> mWebBrowserAsBaseWin; // Convenience interface to above
nsCOMPtr<nsIWebNavigation> mWebBrowserAsWebNav; // Ditto
CFindComponent* mFinder;
};
yCBrowserShell.cpz
// CBrowserShell static variables
nsMacMessageSink CBrowserShell::mMessageSink;
|
Actual event processing code of mozilla exists in the widget module. In case of embedding, various events gotten at framework are sent to mozilla by way of nsMacMessageSink's mMessageSink.DispatchOSEvent().
As far as embedding, the XPCOM world is spread all over in CBrowserShell class and CWebBrowserChrome class. In XPCOM, one XPCOM instance holds multiple interfaces classified by their usage. When you want to request a XPCOM instance to do something, you should get the interface you hope via QueryInterface() and call the method through that interface pointer.
Constructor of CBrowserShell class creates XPCOM instance of browser (HTML part).
CBrowserShell::CBrowserShell(LStream* inStream) :
LView(inStream),
mFinder(nsnull)
{
*inStream >> (StringPtr) mInitURL;
nsresult rv = CommonConstruct();
if (rv != NS_OK)
// If this fails, there's no reason to live anymore :(
Throw_Err(NS_ERROR_GET_CODE(rv))
}
NS_IMETHODIMP CBrowserShell::CommonConstruct()
{
nsresult rv;
mWebBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mWebBrowser));
NS_ENSURE_TRUE(baseWin, NS_ERROR_FAILURE);
mWebBrowserAsBaseWin = baseWin;
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mWebBrowser));
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
mWebBrowserAsWebNav = webNav;
return NS_OK;
}
|
Browser is an instance of nsWebBrowser class. Its source code exists in the embedding module. nsWebBrowser is instanciated by do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &rv); and returns nsIWebBrower that is his typical interface. It is housed in mWebBrowser member variable.
In case that you manipulate nsWebBrowser, all you have to keep is this nsIWebBrower mWebBrowser and that's enough, and you can get whatever interfaces you want by QI()ing via nsIWebBrowser whenever other interfaces are necessary. But in this procedure, nsIBaseWindow, nsIWebNavigation are gotten and kept in member variables in this timing, 'cause afterwards they are referenced very often.
Destrutor of CBrowserShell class disposes of Find Component.
CBrowserShell::~CBrowserShell()
{
delete mFinder;
// nsCOMPtr destructors, do your thing
}
|
In this procedure, process specific to mozilla is to initialize the geometry of nsWebBrowser (position, size and so on). By InitWindow() and Create() of nsIBaseWindow mWebBrowserAsBaseWin, that is the interface associated with the geometry, initialization is done anyway. Then, by AdjustFrame() common method, the position and size are arranged precisely.
void CBrowserShell::FinishCreateSelf()
{
FocusDraw();
CBrowserWindow *ourWindow = dynamic_cast<CBrowserWindow*
>(LWindow::FetchWindowObject(GetMacPort()));
ThrowIfNil_(ourWindow);
ourWindow->AddListener(this);
nsCOMPtr<nsIWidget> aWidget;
ourWindow->GetWidget(getter_AddRefs(aWidget));
ThrowIfNil_(aWidget);
Rect portFrame;
CalcPortFrameRect(portFrame);
nsRect r(portFrame.left, portFrame.top
portFrame.right - portFrame.left, portFrame.bottom - portFrame.top);
mWebBrowserAsBaseWin->InitWindow(aWidget->GetNativeData(NS_NATIVE_WIDGET),
nsnull, r.x, r.y, r.width, r.height);
mWebBrowserAsBaseWin->Create();
AdjustFrame();
StartRepeating();
StartListening();
}
|
This is called by CBrowserWindow::FinishCreateSelf(). The final stage of browser initialization. By calling nsIWebBrowser::SetContainerWindow(), nsWebBrowser recognizes CWebBrowserChrome object as a chrome.
And, as the code comment says, if you want to initialize nsIDocShell related matters, it can be done here also.
NS_IMETHODIMP CBrowserShell::SetTopLevelWindow(nsIWebBrowserChrome *aTopLevelWindow)
{
mWebBrowser->SetContainerWindow(aTopLevelWindow);
/*
In case we needed to do something with the underlying docshell...
nsCOMPtr<nsIDocShell> ourDocShell(do_GetInterface(mWebBrowser));
NS_ENSURE_TRUE(ourDocShell, NS_ERROR_FAILURE);
*/
return NS_OK;
}
|
This is called when the geometry of nsWebBrowser (position, size and so on) changes. In addition to the processes specific to PowerPlant, after all, the position and size are adjusted correctly by AdjustFrame() common method. In AdjustFrame(), by nsIBaseWindow::SetPositionAndSize(), the browser is informed of new geometry.
void CBrowserShell::ResizeFrameBy(SInt16 inWidthDelta,
SInt16 inHeightDelta,
Boolean inRefresh)
{
LView::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
AdjustFrame();
}
void CBrowserShell::MoveBy(SInt32 inHorizDelta,
SInt32 inVertDelta,
Boolean inRefresh)
{
LView::MoveBy(inHorizDelta, inVertDelta, inRefresh);
AdjustFrame();
}
void CBrowserShell::AdjustFrame()
{
FocusDraw();
Rect portFrame;
CalcPortFrameRect(portFrame);
nsRect r(portFrame.left, portFrame.top
portFrame.right - portFrame.left, portFrame.bottom - portFrame.top);
mWebBrowserAsBaseWin->SetPositionAndSize(r.x, r.y, r.width, r.height, PR_TRUE);
}
|
nsIBaseWindow::SetVisibility() makes a browser shown.
void CBrowserShell::ShowSelf()
{
mWebBrowserAsBaseWin->SetVisibility(PR_TRUE);
}
|
These are event processings. nsMacMessageSink's DispatchOSEvent() send the event to the browser.
void CBrowserShell::ClickSelf(const SMouseDownEvent &inMouseDown)
{
if (!IsTarget())
SwitchTarget(this);
FocusDraw();
mMessageSink.DispatchOSEvent((EventRecord&)inMouseDown.macEvent, GetMacPort());
}
void CBrowserShell::EventMouseUp(const EventRecord &inMacEvent)
{
FocusDraw();
mMessageSink.DispatchOSEvent((EventRecord&)inMacEvent, GetMacPort());
LEventDispatcher *dispatcher = LEventDispatcher::GetCurrentEventDispatcher();
if (dispatcher)
dispatcher->UpdateMenus();
}
void CBrowserShell::AdjustCursorSelf(Point /* inPortPt */,
const EventRecord& inMacEvent)
{
static Point lastWhere = {0, 0};
if ((*(long*)&lastWhere != *(long*)&inMacEvent.where))
{
HandleMouseMoved(inMacEvent);
lastWhere = inMacEvent.where;
}
}
void CBrowserShell::HandleMouseMoved(const EventRecord& inMacEvent)
{
if (IsActive())
{
FocusDraw();
mMessageSink.DispatchOSEvent(const_cast<EventRecord&>(inMacEvent), GetMacPort());
}
}
Boolean CBrowserShell::HandleKeyPress(const EventRecord &inKeyEvent)
{
// set the QuickDraw origin
FocusDraw();
// dispatch the event
Boolean keyHandled = mMessageSink.DispatchOSEvent((EventRecord&)inKeyEvent, GetMacPort());
return keyHandled;
}
void CBrowserShell::SpendTime(const EventRecord& inMacEvent)
{
switch (inMacEvent.what)
{
case osEvt:
{
// The MacMessageSink will not set the cursor if we are in the backgroun
// d - which is right.
// We have to feed it suspendResumeMessages for it to know
unsigned char eventType = ((inMacEvent.message >> 24) & 0x00ff);
if (eventType == suspendResumeMessage)
mMessageSink.DispatchOSEvent(const_cast<EventRecord&>(inMacEvent), GetMacPort());
}
break;
}
}
|
Clipboard processes such as copy, paste and so on.
Boolean CBrowserShell::ObeyCommand(PP_PowerPlant::CommandT inCommand, void* ioParam)
{
Boolean cmdHandled = true;
nsresult rv;
nsCOMPtr<nsIClipboardCommands> clipCmd;
switch (inCommand)
{
case cmd_Cut:
rv = GetClipboardHandler(getter_AddRefs(clipCmd));
if (NS_SUCCEEDED(rv))
clipCmd->CutSelection();
break;
case cmd_Copy:
rv = GetClipboardHandler(getter_AddRefs(clipCmd));
if (NS_SUCCEEDED(rv))
clipCmd->CopySelection();
break;
case cmd_Paste:
rv = GetClipboardHandler(getter_AddRefs(clipCmd));
if (NS_SUCCEEDED(rv))
clipCmd->PasteSelection();
break;
case cmd_SelectAll:
rv = GetClipboardHandler(getter_AddRefs(clipCmd));
if (NS_SUCCEEDED(rv))
clipCmd->SelectAll();
break;
default:
cmdHandled = LCommander::ObeyCommand(inCommand, ioParam);
break;
}
return cmdHandled;
}
nsresult CBrowserShell::GetClipboardHandler(nsIClipboardCommands **aCommand)
{
NS_ENSURE_ARG_POINTER(aCommand);
nsCOMPtr<nsIDocShell> docShell(do_GetInterface(mWebBrowser));
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
nsCOMPtr<nsIClipboardCommands> clipCmd(do_QueryInterface(docShell));
NS_ENSURE_TRUE(clipCmd, NS_ERROR_FAILURE);
*aCommand = clipCmd;
NS_ADDREF(*aCommand);
return NS_OK;
}
|
In the above, nsIDocShell interface is gotten from nsIWebBrowser interface.
Because nsDocShell is held indirectly by nsWebBrowser, the interface is gotten not by do_QueryInterface() but by do_GetInterface().
All actual processes are requested to nsIWebNavigation interface.
Boolean CBrowserShell::CanGoBack()
{
PRBool canDo;
nsresult rv;
rv = mWebBrowserAsWebNav->GetCanGoBack(&canDo);
return (NS_SUCCEEDED(rv) && canDo);
}
Boolean CBrowserShell::CanGoForward()
{
PRBool canDo;
nsresult rv;
rv = mWebBrowserAsWebNav->GetCanGoForward(&canDo);
return (NS_SUCCEEDED(rv) && canDo);
}
void CBrowserShell::Back()
{
if (CanGoBack())
mWebBrowserAsWebNav->GoBack();
else
::SysBeep(5);
}
void CBrowserShell::Forward()
{
if (CanGoForward())
mWebBrowserAsWebNav->GoForward();
else
::SysBeep(5);
}
void CBrowserShell::Stop()
{
mWebBrowserAsWebNav->Stop();
}
|
This also requests nsIWebNavigation interface to do the process. Two methods are overloaded, one for plain character string, one for nsString.
void CBrowserShell::LoadURL(Ptr urlText, SInt32 urlTextLen)
{
nsAutoString urlString; urlString.AssignWithConversion(urlText, urlTextLen);
LoadURL(urlString);
}
void CBrowserShell::LoadURL(const nsString& urlText)
{
nsresult rv = mWebBrowserAsWebNav->LoadURI(urlText.GetUnicode(),
nsIWebNavigation::LOAD_FLAGS_NONE);
if (NS_FAILED(rv))
Throw_(NS_ERROR_GET_CODE(rv));
}
|
These are methods called by CWebBrowserChrome, and are getter & setter of a browser (nsIWebBrowser) used by the chrome class.
NS_METHOD CBrowserShell::GetWebBrowser(nsIWebBrowser** aBrowser)
{
NS_ENSURE_ARG_POINTER(aBrowser);
*aBrowser = mWebBrowser;
NS_IF_ADDREF(*aBrowser);
return NS_OK;
}
NS_METHOD CBrowserShell::SetWebBrowser(nsIWebBrowser* aBrowser)
{
NS_ENSURE_ARG(aBrowser);
FocusDraw();
CBrowserWindow *ourWindow = dynamic_cast<CBrowserWindow*
>(LWindow::FetchWindowObject(GetMacPort()));
NS_ENSURE_TRUE(ourWindow, NS_ERROR_FAILURE);
nsCOMPtr<nsIWidget> aWidget;
ourWindow->GetWidget(getter_AddRefs(aWidget));
NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE);
mWebBrowser = aBrowser;
nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mWebBrowser));
NS_ENSURE_TRUE(baseWin, NS_ERROR_FAILURE);
mWebBrowserAsBaseWin = baseWin;
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mWebBrowser));
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
mWebBrowserAsWebNav = webNav;
Rect portFrame;
CalcPortFrameRect(portFrame);
nsRect r(portFrame.left, portFrame.top,
portFrame.right - portFrame.left, portFrame.bottom - portFrame.top);
mWebBrowserAsBaseWin->InitWindow(aWidget->GetNativeData(NS_NATIVE_WIDGET),
nsnull, r.x, r.y, r.width, r.height);
mWebBrowserAsBaseWin->Create();
AdjustFrame();
return NS_OK;
}
|
CWebBrowserChrome class 
By implementing some pre-defined XPCOM interfaces and being associated with the browser class, this class manages all sorts of exchange with mozilla side. I show the interfaces actually implemented below.
nsIInterfaceRequestor interface is used when you want to implement some interfaces in a little different way from general XPCOM. In general XPCOM, if it is possible to do QI() on Interface A to get to Interface B, conversely, it also must be possible to do QI() on Interface B to get to Interface A. But, nsIInterfaceRequestor enables one-way getting. In this case, interfaces are gotton not by QI() but by GetInterface().
Above-mentioned nsIDocShell is held by nsWebBrowser via nsIInterfaceRequestor. Therefore, on nsIWebBrowser, nsIDocShell interface should be gotton to, not by QueryInterface() but by GetInterface().
Class definition of CWebBrowserChrome inherits from the interfaces it implements and defines these methods. These method definitions are expanded by the macro such as NS_DECL_ISUPPORTS, NS_DECL_NSIWEBBROWSERCHROME.
As member variables, this has a pointer to CBrowserWindow and CBrowserShell to keep association with them. And, as a static variable, this has the browser list (STL vector array of CWebBrowserChrom* type keeping all chrome instances it creates).
And, this class becoms "C++ friend" of CBrowserWindow class, and that makes it easier to access CBrowserWindow class members.
class CWebBrowserChrome : public nsIWebBrowserChrome,
public nsIWebProgressListener,
public nsIBaseWindow,
public nsIPrompt,
public nsIInterfaceRequestor
{
friend class CBrowserWindow;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBBROWSERCHROME
NS_DECL_NSIWEBPROGRESSLISTENER
NS_DECL_NSIBASEWINDOW
NS_DECL_NSIPROMPT
NS_DECL_NSIINTERFACEREQUESTOR
protected:
CWebBrowserChrome();
virtual ~CWebBrowserChrome();
CBrowserWindow*& BrowserWindow();
CBrowserShell*& BrowserShell();
protected:
CBrowserWindow* mBrowserWindow;
CBrowserShell* mBrowserShell;
static vector<CWebBrowserChrome*> mgBrowserList;
};
yCWebBrowserChrome.cpz
// Static Variables
vector<CWebBrowserChrome*> CWebBrowserChrome::mgBrowserList;
//*****************************************************************************
// CWebBrowserChrome::nsISupports
//*****************************************************************************
NS_IMPL_ADDREF(CWebBrowserChrome)
NS_IMPL_RELEASE(CWebBrowserChrome)
NS_INTERFACE_MAP_BEGIN(CWebBrowserChrome)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
NS_INTERFACE_MAP_ENTRY(nsIPrompt)
NS_INTERFACE_MAP_END
|
Moreover, by above-mentioned macro, this implements AddRef(), Release() and QueryInterface().
Constructor of CWebBrowserChrome class adds itself to the browser list.
CWebBrowserChrome::CWebBrowserChrome() :
mBrowserWindow(nsnull), mBrowserShell(nsnull)
{
NS_INIT_REFCNT();
mgBrowserList.push_back(this);
}
|
Destructor of CWebBrowserChrome class deletes itself from the browser list.
CWebBrowserChrome::~CWebBrowserChrome()
{
vector<CWebBrowserChrome*>::iterato iter = find(mgBrowserList.begin()
mgBrowserList.end(), this);
if (iter != mgBrowserList.end())
mgBrowserList.erase(iter);
}
|
Accessor methods to CBrowserWindow and CBrowserShell associated with this chrome instance. This code uses the reference to a pointer and can do both right side value reference and left side value assignment.
CBrowserWindow*& CWebBrowserChrome::BrowserWindow()
{
return mBrowserWindow;
}
CBrowserShell*& CWebBrowserChrome::BrowserShell()
{
return mBrowserShell;
}
|
This processes GetInterface() from the outside. In this code, all GetInterface() are processed as QueryInterface(), and nothing special.
NS_IMETHODIMP CWebBrowserChrome::GetInterface(const nsIID &aIID, void** aInstancePtr)
{
return QueryInterface(aIID, aInstancePtr);
}
|
This method is called when HTML document informs the chrome of status string.
NS_IMETHODIMP CWebBrowserChrome::SetStatus(PRUint32 statusType, const PRUnichar *status)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
if (statusType == STATUS_SCRIPT)
mBrowserWindow->SetStatus(status);
else if (statusType == STATUS_LINK)
mBrowserWindow->SetOverLink(status);
return NS_OK;
}
|
STATUS_SCRIPT is from Javascript and STATUS_LINK is href character string of a link on HTML document. Both request CBrowserWindow to show the status bar.
This is the information from mozilla side of getting and setting up a browser. Both actual processes are left to CBrowserShell.
NS_IMETHODIMP CWebBrowserChrome::GetWebBrowser(nsIWebBrowser** aWebBrowser)
{
NS_ENSURE_ARG_POINTER(aWebBrowser);
NS_ENSURE_TRUE(mBrowserShell, NS_ERROR_NOT_INITIALIZED);
mBrowserShell->GetWebBrowser(aWebBrowser);
return NS_OK;
}
NS_IMETHODIMP CWebBrowserChrome::SetWebBrowser(nsIWebBrowser* aWebBrowser)
{
NS_ENSURE_ARG(aWebBrowser); // Passing nsnull is NOT OK
NS_ENSURE_TRUE(mBrowserShell, NS_ERROR_NOT_INITIALIZED);
mBrowserShell->SetWebBrowser(aWebBrowser);
return NS_OK;
}
|
This is a request from mozilla side to create a browser window. This is called by mozilla when a new window is created by a link click in HTML document etc. In PPBrowser, PlainBrowserWindow of Layout = 130 is always created (a simple window owning only one browser). Ideally, according to the value of chromeMask, a window owning proper parts should be created.
NS_IMETHODIMP CWebBrowserChrome::CreateBrowserWindow(PRUint32 chromeMask,
PRInt32 aX, PRInt32 aY, PRInt32 aCX, PRInt32 aCY, nsIWebBrowser **aWebBrowser)
{
NS_ENSURE_ARG_POINTER(aWebBrowser);
*aWebBrowser = nsnull;
// Note: For now, until we can create a window with specific chrome flags, this will
// put up a plain window without navigation controls or location text. This is
// most likely being used to pop up an add.
CBrowserWindow *theWindow;
try
{
// CreateWindow can throw an we're being called from mozilla, so we need to catch
theWindow = dynamic_cast<CBrowserWindow*
>(LWindow::CreateWindow(wind_PlainBrowserWindow, LCommander::GetTopCommander()));
}
catch (...)
{
theWindow = nsnull;
}
NS_ENSURE_TRUE(theWindow, NS_ERROR_FAILURE);
CBrowserShell *aBrowserShell = theWindow->GetBrowserShell();
NS_ENSURE_TRUE(aBrowserShell, NS_ERROR_FAILURE);
return aBrowserShell->GetWebBrowser(aWebBrowser);
}
|
This searches a browser item corresponding to the given name and returns it.
NS_IMETHODIMP CWebBrowserChrome::FindNamedBrowserItem(const PRUnichar* aName,
nsIDocShellTreeItem ** aBrowserItem)
{
NS_ENSURE_ARG(aName);
NS_ENSURE_ARG_POINTER(aBrowserItem);
*aBrowserItem = nsnull;
vector<CWebBrowserChrome*>::iterator iter = mgBrowserList.begin();
while (iter < mgBrowserList.end())
{
CWebBrowserChrome* aChrome = *iter++;
if (aChrome == this)
continue; // Our tree has already been searched???
NS_ENSURE_TRUE(aChrome->BrowserShell(), NS_ERROR_FAILURE);
nsCOMPtr<nsIWebBrowser> webBrowser;
aChrome->BrowserShell()->GetWebBrowser(getter_AddRefs(webBrowser));
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(webBrowser));
NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
docShellAsItem->FindItemWithName(aName,
NS_STATIC_CAST(nsIWebBrowserChrome*, this), aBrowserItem);
if (*aBrowserItem)
break;
}
return NS_OK; // Return OK even if we didn't find it???
}
|
This iterates the browser list and seaches it by docShellAsItem::FindItemWithName().
This is the information of a change in size of the brower.
// Constants
const PRInt32 kGrowIconSize = 15;
NS_IMETHODIMP CWebBrowserChrome::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
{
mBrowserWindow->ResizeFrameTo(aCX, aCY + kGrowIconSize, true);
return NS_OK;
}
|
This calcurates size of client area of window from size of browser and requests CBrowserWindow to resize.
In PPBrowser, these implementations are empty.
This is called when the progress status of document load changes. This requests CBrowserWindow to do the process and updates progress bar etc.
NS_IMETHODIMP CWebBrowserChrome::OnProgressChange(nsIWebProgress *progress,
nsIRequest *request,
PRInt32 curSelfProgress, PRInt32 maxSelfProgress,
PRInt32 curTotalProgress, PRInt32 maxTotalProgress)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
return mBrowserWindow->OnProgressChange(progress, request,
curSelfProgress, maxSelfProgress,
curTotalProgress, maxTotalProgress);
}
|
This is called when the status of net process changes. This requests CBrowserWindow to do the process and updates progress bar, throbber, various buttons and so on.
NS_IMETHODIMP CWebBrowserChrome::OnStateChange(nsIWebProgress *progress,
nsIRequest *request,
PRInt32 progressStateFlags, PRUint32 status)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
if (progressStateFlags & STATE_IS_NETWORK) {
if (progressStateFlags & STATE_START)
mBrowserWindow->OnStatusNetStart(progress, request, progressStateFlags, status);
else if (progressStateFlags & STATE_STOP)
mBrowserWindow->OnStatusNetStop(progress, request, progressStateFlags, status);
}
return NS_OK;
}
|
This is called when a new page is loaded. This requests CBrowserWindow to do the process and shows resolved URL on location bar.
NS_IMETHODIMP CWebBrowserChrome::OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI *location)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
char *buf = nsnull;
if (location)
location->GetSpec(&buf);
nsAutoString tmp; tmp.AssignWithConversion(buf);
mBrowserWindow->SetLocation(tmp);
if (buf)
Recycle(buf);
return NS_OK;
}
|
In PPBrowser, these implementations are empty.
This initializes a window. By SetPositionAndSize() on the same interface, the position and size are set up.
NS_IMETHODIMP CWebBrowserChrome::InitWindow(nativeWindow aParentNativeWindow,
nsIWidget* parentWidget, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
{
// Ignore wigdet parents for now. Don't think those are a vaild thing to call.
NS_ENSURE_SUCCESS(SetPositionAndSize(x, y, cx, cy, PR_FALSE), NS_ERROR_FAILURE);
return NS_OK;
}
|
This sets up and gets the position and size of window. This requests CBrowserWindow to do each processes.
NS_IMETHODIMP CWebBrowserChrome::SetPosition(PRInt32 x, PRInt32 y)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
mBrowserWindow->MoveWindowTo(x, y);
return NS_OK;
}
NS_IMETHODIMP CWebBrowserChrome::GetPosition(PRInt32* x, PRInt32* y)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_ARG_POINTER(x && y);
Rect bounds;
mBrowserWindow->GetGlobalBounds(bounds);
*x = bounds.left;
*y = bounds.top;
return NS_OK;
}
NS_IMETHODIMP CWebBrowserChrome::SetSize(PRInt32 cx, PRInt32 cy, PRBool fRepaint)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
mBrowserWindow->ResizeFrameTo(cx, cy + kGrowIconSize, fRepaint);
return NS_OK;
}
NS_IMETHODIMP CWebBrowserChrome::GetSize(PRInt32* cx, PRInt32* cy)
{
NS_ENSURE_ARG_POINTER(cx && cy);
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
Rect bounds;
mBrowserWindow->GetGlobalBounds(bounds);
*cx = bounds.right - bounds.left;
*cy = bounds.bottom - bounds.top - kGrowIconSize;
return NS_OK;
}
NS_IMETHODIMP CWebBrowserChrome::SetPositionAndSize(PRInt32 x, PRInt32 y,
PRInt32 cx, PRInt32 cy, PRBool fRepaint)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
Rect bounds;
bounds.top = y;
bounds.left = x;
bounds.bottom = y + cy + kGrowIconSize;
bounds.right = x + cx;
mBrowserWindow->DoSetBounds(bounds);
return NS_OK;
}
NS_IMETHODIMP CWebBrowserChrome::GetPositionAndSize(PRInt32* x, PRInt32* y,
PRInt32* cx, PRInt32* cy)
{
NS_ENSURE_ARG_POINTER(x && y && cx && cy);
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
Rect bounds;
mBrowserWindow->GetGlobalBounds(bounds);
*x = bounds.left;
*y = bounds.top;
*cx = bounds.right - bounds.left;
*cy = bounds.bottom - bounds.top - kGrowIconSize;
return NS_OK;
}
|
This repaints window and requests CBrowserWindow to do the process. When aFource is false, by sending Update event, and when aFource is true, by direct painting, this repaints it.
NS_IMETHODIMP CWebBrowserChrome::Repaint(PRBool aForce)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
mBrowserWindow->Refresh();
if (aForce)
mBrowserWindow->UpdatePort();
return NS_OK;
}
|
This sets up/gets the window's show/hide property. This requests CBrowserWindow to do the process.
NS_IMETHODIMP CWebBrowserChrome::GetVisibility(PRBool* aVisibility)
{
NS_ENSURE_ARG_POINTER(aVisibility);
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
*aVisibility = mBrowserWindow->IsVisible();
return NS_OK;
}
NS_IMETHODIMP CWebBrowserChrome::SetVisibility(PRBool aVisibility)
{
NS_ENSURE_TRUE(mBrowserWindow, NS_ERROR_NOT_INITIALIZED);
if (aVisibility)
{
mBrowserWindow->Show();
mBrowserWindow->Select();
}
else
mBrowserWindow->Hide();
return NS_OK;
}
|
This sets up/gets a title of the window. This requests CBrowserWindow to do the process.
NS_IMETHODIMP CWebBrowserChrome::GetTitle(PRUnichar** aTitle)
{
NS_ENSURE_ARG_POINTER(aTitle);
NS_ENSURE_STATE(mBrowserWindow);
Str255 aStr;
nsAutoString titleStr;
mBrowserWindow->GetDescriptor(aStr);
UMacUnicode::Str255ToString(aStr, titleStr);
*aTitle = titleStr.ToNewUnicode();
return NS_OK;
}
NS_IMETHODIMP CWebBrowserChrome::SetTitle(const PRUnichar* aTitle)
{
NS_ENSURE_STATE(mBrowserWindow);
nsAutoString titleStr(aTitle);
Str255 aStr;
UMacUnicode::StringToStr255(titleStr, aStr);
mBrowserWindow->SetDescriptor(aStr);
return NS_OK;
}
|
In PPBrowser, these implementations are empty.
This is a request from mozilla side to show an alert dialog. In the way specific to PowerPlant, this shows the alert dialog from Layout resource.
NS_IMETHODIMP CWebBrowserChrome::Alert(const PRUnichar *dialogTitle, const PRUnichar *text)
{
RegisterClass_(LIconControl);
StDialogHandler theHandler(dlog_Alert, mBrowserWindow);
LWindow *theDialog = theHandler.GetDialog();
Str255 aStr;
UMacUnicode::StringToStr255(nsString(text), aStr);
LStaticText *msgText = dynamic_cast<LStaticText*>(theDialog->FindPaneByID('Msg '));
msgText->SetDescriptor(aStr);
theDialog->Show();
theDialog->Select();
while (true) // This is our modal dialog event loop
{
MessageT hitMessage = theHandler.DoDialog();
if (hitMessage == msg_OK)
break;
}
return NS_OK;
}
|
These are requests to show various dialogs. Basically the procedures are the same as Alert(), and the difference is only the U.I. parts displayed on the dialog. So, I omit these codes. Select() and UniversalDialog() are not implemented yet.
| c_o_n_t_a_c_t | Copyright (C) 2000-2002 Symphony, Inc. All Rights Reserved. |
Japanese |