mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 15:15:23 +00:00
553 lines
15 KiB
C++
553 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||
*
|
||
* The contents of this file are subject to the Netscape Public License
|
||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
* http://www.mozilla.org/NPL/
|
||
*
|
||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
* for the specific language governing rights and limitations under the
|
||
* NPL.
|
||
*
|
||
* The Initial Developer of this code under the NPL is Netscape
|
||
* Communications Corporation. Portions created by Netscape are
|
||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
* Reserved.
|
||
*/
|
||
|
||
// errmgr.cp, Mac front end ErrorManager
|
||
|
||
// Editorial comments:
|
||
//
|
||
// Viewing some of this code may make you scream in panic
|
||
// Don't try this at home
|
||
// Use only under medical supervision
|
||
|
||
#include "uerrmgr.h"
|
||
|
||
#include <UDesktop.h>
|
||
#include "uapp.h"
|
||
#include "PascalString.h"
|
||
#include "xpassert.h"
|
||
#include "macutil.h"
|
||
#include "resgui.h"
|
||
#include "xp_error.h"
|
||
#include "UTextBox.h"
|
||
#include "resdef.h"
|
||
#include "macfeprefs.h"
|
||
// Apple
|
||
#include <Notification.h>
|
||
#include <Resources.h>
|
||
#include <AppleEvents.h>
|
||
#include <Dialogs.h>
|
||
|
||
#include <Icons.h>
|
||
|
||
#include "libi18n.h"
|
||
|
||
static void InitializeStrings(); // Need proto to use before declaration
|
||
|
||
OSType ErrorManager::sAlertApp = emSignature;
|
||
|
||
// Converts an OSErr to appropriate string.
|
||
// Just prints the number for now, might do something more
|
||
// useful in the future
|
||
void ErrorManager::OSNumToStr(OSErr err, CStr255 &outString)
|
||
{
|
||
NumToString((long)err, outString);
|
||
}
|
||
|
||
// PrepareToInteract makes sure that this is the frontmost application.
|
||
// If Netscape is not in the foreground, it blinks the small icon in
|
||
// the menu bar until the user brings us to front
|
||
void ErrorManager::PrepareToInteract()
|
||
{
|
||
TryToInteract(10000000);
|
||
}
|
||
|
||
// TryToInteract tries to bring Netscape to foreground (like PrepareToInteract)
|
||
// If user does not bring Netscape to foreground in 900 seconds,
|
||
// it returns FALSE;
|
||
Boolean ErrorManager::TryToInteract(long wait)
|
||
{
|
||
ProcessSerialNumber netscapeProcess, frontProcess;
|
||
OSErr err = ::GetCurrentProcess(&netscapeProcess);
|
||
Boolean inFront = IsFrontApplication();
|
||
if (!inFront)
|
||
{
|
||
unsigned long start, currentTime;
|
||
::GetDateTime(&start);
|
||
currentTime = start;
|
||
NMRec nmRec;
|
||
Handle iconSuite;
|
||
err = ::GetIconSuite (&iconSuite, 128,svAllSmallData);
|
||
nmRec.qLink = 0;
|
||
nmRec.qType = nmType;
|
||
nmRec.nmMark = true;
|
||
nmRec.nmIcon = iconSuite;
|
||
nmRec.nmStr = NULL;
|
||
nmRec.nmSound = (Handle)-1;
|
||
nmRec.nmResp = NULL;
|
||
err = ::NMInstall(&nmRec); // Remove the call automatically
|
||
if (err == noErr)
|
||
{
|
||
while (!inFront && ((currentTime - start) < wait))
|
||
{
|
||
EventRecord event;
|
||
::WaitNextEvent(0, &event, 30, NULL);
|
||
::GetFrontProcess(&frontProcess);
|
||
::GetDateTime(¤tTime);
|
||
::SameProcess(&frontProcess, &netscapeProcess, &inFront);
|
||
}
|
||
::NMRemove(&nmRec);
|
||
}
|
||
#if defined(DEBUG) && defined(ALEKS)
|
||
XP_Abort();
|
||
#endif
|
||
UDesktop::Resume(); // Because the resume event gets eaten up by dialog box
|
||
// Now, process any update events, so that our windows get refreshed properly
|
||
EventRecord event;
|
||
while (::WaitNextEvent(updateEvt, &event, 1, NULL))
|
||
(CFrontApp::GetApplication())->DispatchEvent(event);
|
||
}
|
||
return inFront;
|
||
}
|
||
|
||
// Class that resizes the alert dialog
|
||
|
||
// Resizes
|
||
void ShrinkToFitAlertDialog(cstring & temp);
|
||
void ShrinkToFitAlertDialog(cstring & temp)
|
||
{
|
||
Handle ditl = ::GetResource('DITL', ALRT_PlainAlert);
|
||
StHandleLocker lock(ditl);
|
||
Handle alrt = ::GetResource('ALRT', ALRT_PlainAlert);
|
||
StHandleLocker lock2(alrt);
|
||
|
||
// <20><><EFBFBD> WARNING <20><><EFBFBD> <ftang>
|
||
// You need to consider the PAD byte after each string
|
||
#define IncludePadByte(a) (((a) & 1) ? ((a) +1) : (a))
|
||
|
||
// This ugliness happens because my pointer arithmetic was messed up otherwise
|
||
UInt32 tmp = (UInt32)*ditl;
|
||
Rect * okRect = (Rect*)(tmp + 0x6);
|
||
// Offset + length of the OK string
|
||
Rect * editRect = (Rect*)(tmp + 0x14 + IncludePadByte(*(uint8*)(tmp + 0xF)));
|
||
StTextState textState;
|
||
TextFont(0);
|
||
TextSize(12);
|
||
short height = UTextBox::TextBoxDialogHeight((char*)temp, temp.length(), editRect,
|
||
teForceLeft, 0);
|
||
if (height < 50) // Need to make place for the icon
|
||
height = 50;
|
||
editRect->bottom = editRect->top + height;
|
||
okRect->top = editRect->bottom + 8;
|
||
okRect->bottom = okRect->top + 20;
|
||
// Get the window resource
|
||
// Strange thing here: after ALRT is called for the first time,
|
||
// altrRect gets altered. Its top/left are strange (>30000)
|
||
// So I reset them, and everything seems to work
|
||
// I bet that the toolbox guys are storing alert state in these
|
||
Rect * alrtRect = (Rect*)*alrt;
|
||
alrtRect->top = 100;
|
||
alrtRect->bottom = alrtRect->top+ okRect->bottom + 8;
|
||
alrtRect->left = 185;
|
||
alrtRect->right = 577;
|
||
}
|
||
|
||
void ShrinkToFitYorNDialog(cstring & temp);
|
||
void ShrinkToFitYorNDialog(cstring & temp)
|
||
{
|
||
Handle ditl = ::GetResource('DITL', ALRT_YorNAlert);
|
||
StHandleLocker lock(ditl);
|
||
Handle alrt = ::GetResource('ALRT', ALRT_YorNAlert);
|
||
StHandleLocker lock2(alrt);
|
||
// This ugliness happens because my pointer arithmetic was messed up otherwise
|
||
UInt32 base = (UInt32)*ditl;
|
||
|
||
// <20><><EFBFBD> WARNING <20><><EFBFBD> <ftang>
|
||
// You need to consider the PAD byte after each string
|
||
|
||
Rect * yesRect = (Rect*)(base + 0x6);
|
||
UInt8 * yesLen = (UInt8 *)(base + 0xF);
|
||
|
||
Rect * noRect = (Rect*)(base + 0x14 + IncludePadByte(*yesLen));
|
||
UInt8 * noLen = (UInt8 *)(base + 0x1D + IncludePadByte(*yesLen));
|
||
Rect * editRect = (Rect*)(base + 0x22 + IncludePadByte(*yesLen) + IncludePadByte(*noLen));
|
||
StTextState textState;
|
||
TextFont(0);
|
||
TextSize(12);
|
||
short height = UTextBox::TextBoxDialogHeight((char*)temp, temp.length(), editRect,
|
||
teForceLeft, 0);
|
||
if (height < 50) // Need to make place for the icon
|
||
height = 50;
|
||
editRect->bottom = editRect->top + height;
|
||
yesRect->top = editRect->bottom + 8;
|
||
yesRect->bottom = yesRect->top + 20;
|
||
noRect->top = editRect->bottom + 8;
|
||
noRect->bottom = noRect->top + 20;
|
||
// Get the window resource
|
||
// Strange thing here: after ALRT is called for the first time,
|
||
// altrRect gets altered. Its top/left are strange (>30000)
|
||
// So I reset them, and everything seems to work
|
||
// I bet that the toolbox guys are storing alert state in these
|
||
Rect * alrtRect = (Rect*)*alrt;
|
||
alrtRect->top = 185;
|
||
alrtRect->bottom = alrtRect->top+ yesRect->bottom + 8;
|
||
alrtRect->left = 185;
|
||
alrtRect->right = 590;
|
||
}
|
||
|
||
// Displays a vanilla alert. All strings inside the alert are
|
||
// supplied by caller
|
||
void ErrorManager::PlainAlert(const CStr255& s1, const char * s2, const char * s3, const char * s4)
|
||
{
|
||
if (sAlertApp != emSignature)
|
||
return;
|
||
if (!TryToInteract(900)) // If we time out, go away
|
||
return;
|
||
CStr255 S1(s1);
|
||
CStr255 S2(s2);
|
||
CStr255 S3(s3);
|
||
CStr255 S4(s4);
|
||
ConvertCRtoLF(S1);
|
||
ConvertCRtoLF(S2);
|
||
ConvertCRtoLF(S3);
|
||
ConvertCRtoLF(S4);
|
||
ParamText(S1, S2, S3, S4);
|
||
cstring temp;
|
||
temp += s1;
|
||
temp += s2;
|
||
temp += s3;
|
||
temp += s4;
|
||
ShrinkToFitAlertDialog(temp);
|
||
UDesktop::Deactivate();
|
||
::CautionAlert(ALRT_PlainAlert, NULL);
|
||
UDesktop::Activate();
|
||
}
|
||
|
||
void ErrorManager::PlainAlert( short resID )
|
||
{
|
||
InitializeStrings();
|
||
|
||
if (sAlertApp != emSignature)
|
||
return;
|
||
|
||
CStr255 cstr[ 4 ];
|
||
StringHandle strings[ 4 ];
|
||
|
||
if ( !TryToInteract(900))
|
||
return;
|
||
|
||
for ( short i = 0; i <= 3; i++ )
|
||
{
|
||
strings[ i ] = GetString( resID + i );
|
||
if ( strings[ i ] )
|
||
cstr[ i ] = **( (CStr255**)strings[ i ] );
|
||
}
|
||
|
||
ParamText( cstr[ 0 ], cstr[ 1 ], cstr[ 2 ], cstr[ 3 ] );
|
||
cstring temp;
|
||
temp += cstr[ 0 ];
|
||
temp += cstr[ 1 ];
|
||
temp += cstr[ 2 ];
|
||
temp += cstr[ 3 ];
|
||
ShrinkToFitAlertDialog(temp); // Size the dalog
|
||
UDesktop::Deactivate();
|
||
::CautionAlert( ALRT_PlainAlert, NULL );
|
||
UDesktop::Activate();
|
||
}
|
||
|
||
// Displays a yes or no alert. All strings inside the alert are
|
||
// supplied by caller
|
||
Boolean ErrorManager::PlainConfirm(const char * s1, const char * s2, const char * s3, const char * s4)
|
||
{
|
||
if (sAlertApp != emSignature)
|
||
return FALSE;
|
||
|
||
if (!TryToInteract(900)) // If we time out, go away
|
||
return false;
|
||
CStr255 S1(s1);
|
||
CStr255 S2(s2);
|
||
CStr255 S3(s3);
|
||
CStr255 S4(s4);
|
||
ConvertCRtoLF(S1);
|
||
ConvertCRtoLF(S2);
|
||
ConvertCRtoLF(S3);
|
||
ConvertCRtoLF(S4);
|
||
|
||
// pkc (6/6/96) Hack to stuff s1 into CStr255's if it's the
|
||
// only string passed in.
|
||
if( S1.Length() < strlen(s1) && s2 == NULL )
|
||
{
|
||
int storedLength = S1.Length();
|
||
S2 += (s1 + storedLength);
|
||
ConvertCRtoLF(S2);
|
||
storedLength += S2.Length();
|
||
if( storedLength < strlen(s1) )
|
||
{
|
||
S3 += (s1 + storedLength);
|
||
ConvertCRtoLF(S3);
|
||
storedLength += S3.Length();
|
||
if( storedLength < strlen(s1) )
|
||
{
|
||
S4 += (s1 + storedLength);
|
||
ConvertCRtoLF(S4);
|
||
}
|
||
}
|
||
}
|
||
|
||
cstring temp;
|
||
temp += s1;
|
||
temp += s2;
|
||
temp += s3;
|
||
temp += s4;
|
||
ParamText(S1, S2, S3, S4);
|
||
ShrinkToFitYorNDialog(temp);
|
||
UDesktop::Deactivate();
|
||
int confirm = ::CautionAlert(ALRT_YorNAlert, NULL);
|
||
UDesktop::Activate();
|
||
return (confirm == 1);
|
||
}
|
||
|
||
void ErrorManager::ErrorNotify(OSErr err, const CStr255& message)
|
||
{
|
||
if (sAlertApp != emSignature)
|
||
return;
|
||
CStr255 errNum;
|
||
|
||
OSNumToStr(err, errNum);
|
||
PlainAlert(message, errNum);
|
||
}
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
static void XPStringsNotFoundAlert()
|
||
//----------------------------------------------------------------------------------------
|
||
{
|
||
Str255 stringsFileName;
|
||
|
||
GetIndString(stringsFileName, 14000, 2); // From Bootstrap.rsrc.
|
||
ParamText(stringsFileName, NULL, NULL, NULL);
|
||
Alert (14003, NULL);
|
||
ExitToShell();
|
||
}
|
||
|
||
char * XP_GetBuiltinString(long i);
|
||
|
||
//----------------------------------------------------------------------------------------
|
||
char * XP_GetString( int xpStringID )
|
||
//----------------------------------------------------------------------------------------
|
||
{
|
||
/*
|
||
// Add the offset (the one added by the perl script) but leave it as 32 bits, so
|
||
// we can check the range.
|
||
int32 resID = xpStringID + RES_OFFSET;
|
||
// Check for wraparound. If this happens, some xp person has started to use some
|
||
// range of values that we can't handle. See also my comment at the top of
|
||
// allxpstr.h - jrm 98/04/01.
|
||
if (resID < 128 || resID > SHRT_MAX )
|
||
{
|
||
XPStringsNotFoundAlert();
|
||
}
|
||
// BEWARE! This calls CString::operator char*() const,
|
||
// which uses a stack of 8 static strings into which the
|
||
// C string is copied, and you are returned a pointer to
|
||
// one of these buffers. This result is volatile; 8 more
|
||
// calls of this operator will overwrite the string pointed
|
||
// to by the char* returned.
|
||
// You should call XP_STRDUP or otherwise store the string if you
|
||
// want it to persist
|
||
return GetCString(resID);
|
||
*/
|
||
|
||
static char buf[128];
|
||
static char strclass[128];
|
||
char *ret;
|
||
char *type;
|
||
//XrmValue value;
|
||
|
||
/*
|
||
(void) PR_snprintf(buf, sizeof (buf),
|
||
"%s.strings.%d", fe_progclass, xpStringID + RES_OFFSET);
|
||
(void) PR_snprintf(strclass, sizeof (strclass),
|
||
"%s.Strings.Number", fe_progclass);
|
||
if (fe_display && ((database = XtDatabase(fe_display))) &&
|
||
XrmGetResource(database, buf, strclass, &type, &value))
|
||
{
|
||
return value.addr;
|
||
}
|
||
|
||
if ((ret = mcom_cmd_xfe_xfe_err_h_strings (i + RES_OFFSET)))
|
||
{
|
||
return ret;
|
||
}
|
||
*/
|
||
return XP_GetBuiltinString((long)xpStringID);
|
||
|
||
}
|
||
|
||
extern "C" char * mcom_include_merrors_i_strings (long);
|
||
extern "C" char * mcom_include_secerr_i_strings (long);
|
||
extern "C" char * mcom_include_sec_dialog_strings(long);
|
||
extern "C" char * mcom_include_sslerr_i_strings (long);
|
||
extern "C" char * mcom_include_xp_error_i_strings(long);
|
||
extern "C" char * mcom_include_xp_msg_i_strings (long);
|
||
|
||
char * XP_GetBuiltinString(long i);
|
||
//----------------------------------------------------------------------------------------
|
||
char *
|
||
XP_GetBuiltinString(long i)
|
||
//----------------------------------------------------------------------------------------
|
||
{
|
||
static char buf[128];
|
||
char *ret;
|
||
|
||
i += RES_OFFSET;
|
||
if
|
||
(
|
||
((ret = (mcom_include_merrors_i_strings (i)) )) ||
|
||
((ret = (mcom_include_secerr_i_strings (i)) )) ||
|
||
((ret = (mcom_include_sec_dialog_strings(i)) )) ||
|
||
((ret = (mcom_include_sslerr_i_strings (i)) )) ||
|
||
((ret = (mcom_include_xp_error_i_strings(i)) )) ||
|
||
((ret = (mcom_include_xp_msg_i_strings (i)) ))
|
||
)
|
||
{
|
||
return ret;
|
||
}
|
||
(void) sprintf(buf, "XP_GetBuiltinString: %d not found", i);
|
||
|
||
return buf;
|
||
}
|
||
|
||
//-----------------------------------
|
||
static void InitializeStrings()
|
||
//-----------------------------------
|
||
{
|
||
/*
|
||
static Boolean initialized = false;
|
||
if (initialized)
|
||
return;
|
||
|
||
initialized = true;
|
||
|
||
// Locate and load all the XP string resources
|
||
// in the "Netscape Resources" file
|
||
// inside the "Essential Files" folder.
|
||
|
||
FSSpec stringsFolderSpec;
|
||
|
||
if (FindGutsFolder(&stringsFolderSpec) != noErr)
|
||
XPStringsNotFoundAlert();
|
||
|
||
CInfoPBRec pb;
|
||
|
||
pb.dirInfo.ioNamePtr = stringsFolderSpec.name;
|
||
pb.dirInfo.ioVRefNum = stringsFolderSpec.vRefNum;
|
||
pb.dirInfo.ioFDirIndex = 0;
|
||
pb.dirInfo.ioDrDirID = stringsFolderSpec.parID;
|
||
|
||
if (PBGetCatInfoSync(&pb) != noErr)
|
||
XPStringsNotFoundAlert();
|
||
|
||
Str255 stringFileName;
|
||
GetIndString(stringFileName, 14000, 2);
|
||
|
||
FSSpec stringsFileSpec;
|
||
if (FSMakeFSSpec(pb.dirInfo.ioVRefNum, pb.dirInfo.ioDrDirID,
|
||
stringFileName, &stringsFileSpec) != noErr)
|
||
XPStringsNotFoundAlert();
|
||
|
||
short currentFileRefNum = CurResFile();
|
||
short stringsFileRefNum = FSpOpenResFile(&stringsFileSpec, fsCurPerm);
|
||
|
||
if (ResError() != noErr)
|
||
XPStringsNotFoundAlert();
|
||
|
||
MoveResourceMapBelowApp();
|
||
|
||
UseResFile(currentFileRefNum);
|
||
*/
|
||
} // InitializeStrings
|
||
|
||
void MoveResourceMapBelowApp()
|
||
{
|
||
#if PRAGMA_ALIGN_SUPPORTED
|
||
#pragma options align=mac68k
|
||
#else
|
||
#error "There'll probably be a bug here."
|
||
#endif
|
||
|
||
// Partial definition of "private" Resource Manager structure.
|
||
struct ResourceMap
|
||
{
|
||
char header[16];
|
||
ResourceMap **next;
|
||
short fileRefNum;
|
||
};
|
||
|
||
#if PRAGMA_ALIGN_SUPPORTED
|
||
#pragma options align=reset
|
||
#endif
|
||
|
||
short applicationRefNum = LMGetCurApRefNum();
|
||
ResourceMap **stringsFileMap = (ResourceMap **)LMGetTopMapHndl();
|
||
|
||
// Find the application's resource map.
|
||
for (ResourceMap **map = stringsFileMap; map; map = (*map)->next)
|
||
{
|
||
if ((*map)->fileRefNum == applicationRefNum)
|
||
{
|
||
// Move the strings file below the application
|
||
// in the current resource chain.
|
||
// (Kids, don't do this at home!)
|
||
ResourceMap **top = (*stringsFileMap)->next;
|
||
LMSetTopMapHndl((Handle)top);
|
||
LMSetCurMap((*top)->fileRefNum);
|
||
(*stringsFileMap)->next = (*map)->next;
|
||
(*map)->next = stringsFileMap;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//-----------------------------------
|
||
char* GetCString( short resID )
|
||
//-----------------------------------
|
||
{
|
||
CStr255 pstring = GetPString(resID);
|
||
return (char*)pstring; // BEWARE! This calls CString::operator char*() const,
|
||
// which uses a stack of 8 static strings into which the
|
||
// C string is copied, and you are returned a pointer to
|
||
// one of these buffers. This result is volatile; 8 more
|
||
// calls of this operator will overwrite the strings pointed
|
||
// to by the char* returned.
|
||
} // GetCString
|
||
|
||
//-----------------------------------
|
||
CStr255 GetPString( ResIDT resID )
|
||
//-----------------------------------
|
||
{
|
||
InitializeStrings();
|
||
StringHandle sh = GetString( resID );
|
||
if (sh && *sh)
|
||
{
|
||
//StHandleLocker aLock((Handle)sh); // (probably) not necessary, hence removed
|
||
CStr255 fullResult(*sh);
|
||
return fullResult;
|
||
}
|
||
|
||
CStr255 emptyResult; // initialized to empty by constructor.
|
||
return emptyResult; // This copies the string to the caller's string.
|
||
} // GetPString
|
||
|
||
char * INTL_ResourceCharSet(void)
|
||
{
|
||
char *cbuf;
|
||
cbuf = (char *)GetCString(CHARSET_RESID);
|
||
if (cbuf[0] == '\0')
|
||
return "x-mac-roman";
|
||
return cbuf;
|
||
}
|