mirror of
https://github.com/aaronsgiles/JPEGView.git
synced 2024-06-14 12:29:33 +00:00
92bdb55672
These are the sources for the final official release of JPEGView for the Mac, back in 1994.
1 line
15 KiB
C
1 line
15 KiB
C
/*********************************************************/
|
|
/* This source code copyright (c) 1991-2001, Aaron Giles */
|
|
/* See the Read Me file for licensing information. */
|
|
/* Contact email: mac@aarongiles.com */
|
|
/*********************************************************/
|
|
|
|
#if THINK_C
|
|
#include "THINK.Header"
|
|
#elif applec
|
|
#pragma load ":Headers:MPW.Header"
|
|
#elif __MWERKS__
|
|
//#include "MW.Header"
|
|
#else
|
|
#include "JPEGView.h"
|
|
#endif
|
|
|
|
/*
|
|
* MonitorInit()
|
|
*
|
|
* Purpose: Sets up the linked list of screen devices, and sets their inverse color
|
|
* table resolutions to 5 bits per component
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void MonitorInit(void)
|
|
{
|
|
DeviceLoopDrawingUPP addDevice = NewDeviceLoopDrawingProc((ProcPtr)AddDevice);
|
|
MonitorHandle theMonitor;
|
|
GDHandle theDevice;
|
|
|
|
if (!(theDevice = GetMainDevice())) FatalError(errNoDeviceInfo);
|
|
if (!(theMonitor = gMainMonitor = NewMonitor(theDevice))) FatalError(errNoMemory);
|
|
DeviceLoop(nil, addDevice, (long)&theMonitor, allDevices + singleDevices);
|
|
DisposeRoutineDescriptor((UniversalProcPtr)addDevice);
|
|
SetUpDevices();
|
|
KeepSpinning();
|
|
}
|
|
|
|
/*
|
|
* AddDevice(depth, deviceFlags, targetDevice, userData)
|
|
*
|
|
* Purpose: DeviceLoop routine to add the current device to the linked list
|
|
* Inputs: depth = depth of the device
|
|
* deviceFlags = device flags for the device
|
|
* targetDevice = handle to the target device
|
|
* userData = a refCon we can use
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
pascal void AddDevice(short depth, short deviceFlags, GDHandle targetDevice,
|
|
MonitorHandle *theMonitor)
|
|
{
|
|
#if applec
|
|
#pragma unused(depth, deviceFlags)
|
|
#endif
|
|
if (targetDevice != (*gMainMonitor)->device) {
|
|
if ((**theMonitor)->next = NewMonitor(targetDevice))
|
|
*theMonitor = (**theMonitor)->next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NewMonitor()
|
|
*
|
|
* Purpose: Allocates and initializes a new monitor record based on the given device
|
|
* Inputs: theDevice = handle to the new device
|
|
* Returns: a pointer to the new monitor record
|
|
*
|
|
*/
|
|
|
|
MonitorHandle NewMonitor(GDHandle theDevice)
|
|
{
|
|
MonitorHandle theMonitor;
|
|
Rect theRect;
|
|
|
|
if (theMonitor = (MonitorHandle)NewHandle(sizeof(MonitorItem))) {
|
|
if ((*theMonitor)->gray = NewRgn()) {
|
|
if ((*theMonitor)->screen = NewRgn()) {
|
|
(*theMonitor)->next = nil;
|
|
(*theMonitor)->device = theDevice;
|
|
(*theMonitor)->oldres = (*theDevice)->gdResPref;
|
|
(*theMonitor)->color = IsColorDevice(theDevice);
|
|
(*theMonitor)->depth = MonitorDepth(theMonitor);
|
|
(*theMonitor)->full = false;
|
|
theRect = (*theMonitor)->rect = (*theDevice)->gdRect;
|
|
RectRgn((*theMonitor)->screen, &theRect);
|
|
SectRgn((*theMonitor)->screen, GetGrayRgn(), (*theMonitor)->gray);
|
|
return theMonitor;
|
|
}
|
|
DisposeHandle((Handle)(*theMonitor)->gray);
|
|
}
|
|
DisposeHandle((Handle)theMonitor);
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
/*
|
|
* MonitorChanged()
|
|
*
|
|
* Purpose: Checks to see if any monitors have changed depth/greys
|
|
* Inputs: none
|
|
* Returns: a pointer to the changed monitor, or nil if everything is the same
|
|
*
|
|
*/
|
|
|
|
MonitorHandle MonitorChanged(void)
|
|
{
|
|
MonitorHandle theMonitor;
|
|
Boolean color;
|
|
short depth;
|
|
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
color = IsColorDevice((*theMonitor)->device);
|
|
depth = MonitorDepth(theMonitor);
|
|
if (((*theMonitor)->color != color) || ((*theMonitor)->depth != depth)) {
|
|
(*theMonitor)->color = color;
|
|
(*theMonitor)->depth = depth;
|
|
return theMonitor;
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
/*
|
|
* SetUpDevices()
|
|
*
|
|
* Purpose: Restores the new inverse table resolutions on the various devices
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void SetUpDevices(void)
|
|
{
|
|
MonitorHandle theMonitor;
|
|
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
/*(*(*theMonitor)->device)->gdResPref = 5;
|
|
if ((*(*theMonitor)->device)->gdITable)
|
|
(*(*(*theMonitor)->device)->gdITable)->iTabSeed = GetCTSeed();
|
|
GDeviceChanged((*theMonitor)->device);*/
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ResetDevices()
|
|
*
|
|
* Purpose: Restores the original inverse table resolutions on the various devices
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void ResetDevices(void)
|
|
{
|
|
MonitorHandle theMonitor;
|
|
|
|
if (!gMenuVisible && !(*gMainMonitor)->full) UnhideMenuBar();
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next)
|
|
if ((*theMonitor)->full) NormalScreen(theMonitor);
|
|
}
|
|
|
|
/*
|
|
* ResetColors()
|
|
*
|
|
* Purpose: Restores the colors of all active screens to their original CLUTs
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void ResetColors(void)
|
|
{
|
|
MonitorHandle theMonitor;
|
|
RgnHandle theRgn;
|
|
|
|
if (gInBackground) return;
|
|
if (theRgn = NewRgn()) {
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
if (!(*(*theMonitor)->device)->gdType) {
|
|
RestoreDeviceClut((*theMonitor)->device);
|
|
UnionRgn(theRgn, (*theMonitor)->gray, theRgn);
|
|
}
|
|
}
|
|
if (!EmptyRgn(theRgn)) {
|
|
LMSetPaintWhite(true);
|
|
PaintBehind((WindowPeek)GetFirstWindow(), theRgn);
|
|
LMSetPaintWhite(false);
|
|
PaintOne(nil, theRgn);
|
|
LMSetPaintWhite(true);
|
|
}
|
|
DisposeRgn(theRgn);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* FullScreen(theMonitor)
|
|
*
|
|
* Purpose: Fixes up theMonitor to allow full-screen windows
|
|
* Inputs: theMonitor = pointer to the monitor we're interested in, or nil for all
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void FullScreen(MonitorHandle theMonitor)
|
|
{
|
|
RgnHandle updateRgn;
|
|
|
|
if (!theMonitor) {
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next)
|
|
FullScreen(theMonitor);
|
|
return;
|
|
}
|
|
if ((*theMonitor)->full) return;
|
|
UnionRgn(GetGrayRgn(), (*theMonitor)->screen, GetGrayRgn());
|
|
if (theMonitor == gMainMonitor && gInBackground && (updateRgn = GetMenuRgn()))
|
|
DiffRgn(GetGrayRgn(), updateRgn, GetGrayRgn());
|
|
if (updateRgn = NewRgn()) {
|
|
DiffRgn((*theMonitor)->screen, (*theMonitor)->gray, updateRgn);
|
|
PaintOne((WindowPeek)FrontWindow(), updateRgn);
|
|
PaintBehind((WindowPeek)FrontWindow(), updateRgn);
|
|
CalcVis((WindowPeek)FrontWindow());
|
|
CalcVisBehind((WindowPeek)FrontWindow(), updateRgn);
|
|
DisposeRgn(updateRgn);
|
|
if (theMonitor == gMainMonitor && !gInBackground) {
|
|
LMSetMBarHeight(0);
|
|
gMenuVisible = false;
|
|
RestoreMenuArea();
|
|
}
|
|
(*theMonitor)->full = true;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* NormalScreen(theMonitor)
|
|
*
|
|
* Purpose: Fixes up theMonitor to remove the effects of FullScreen
|
|
* Inputs: theMonitor = pointer to the monitor we're interested in, or nil for all
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void NormalScreen(MonitorHandle theMonitor)
|
|
{
|
|
Boolean oldMenuVis = gMenuVisible;
|
|
RgnHandle updateRgn;
|
|
GrafPort tempPort;
|
|
|
|
if (!theMonitor) {
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next)
|
|
NormalScreen(theMonitor);
|
|
return;
|
|
}
|
|
if (!(*theMonitor)->full) return;
|
|
if (updateRgn = NewRgn()) {
|
|
if (theMonitor == gMainMonitor) SaveMenuArea();
|
|
DiffRgn((*theMonitor)->screen, (*theMonitor)->gray, updateRgn);
|
|
PushPort();
|
|
OpenPort(&tempPort);
|
|
CopyRgn(GetGrayRgn(), tempPort.visRgn);
|
|
MySetPort((CGrafPtr)&tempPort);
|
|
RGBForeColor(&gBlack);
|
|
PaintRgn(updateRgn);
|
|
ClosePort(&tempPort);
|
|
PopPort();
|
|
DiffRgn(GetGrayRgn(), updateRgn, GetGrayRgn());
|
|
CalcVis((WindowPeek)FrontWindow());
|
|
CalcVisBehind((WindowPeek)FrontWindow(), updateRgn);
|
|
DisposeRgn(updateRgn);
|
|
if (theMonitor == gMainMonitor) {
|
|
LMSetMBarHeight(gMenuHeight);
|
|
gMenuVisible = true;
|
|
AdjustMenus();
|
|
DrawMenuBar();
|
|
NudgeWindoids();
|
|
}
|
|
}
|
|
(*theMonitor)->full = false;
|
|
}
|
|
|
|
/*
|
|
* NudgeWindoids()
|
|
*
|
|
* Purpose: Check all windoids to be sure they're not under the menubar
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void NudgeWindoids(void)
|
|
{
|
|
WindowPtr theWindow = GetFirstWindow();
|
|
Rect theRect, menuRect, tempRect;
|
|
|
|
menuRect = (*gMainMonitor)->rect;
|
|
menuRect.bottom = menuRect.top + GetMBarHeight();
|
|
while (theWindow) {
|
|
if (WindowKind((WindowPtr)theWindow) == floatingWindowKind) {
|
|
theRect = theWindow->portRect;
|
|
theRect.top -= gTitleBarHeight * 2 / 3;
|
|
GlobalRect(&theRect, theWindow);
|
|
if (SectRect(&theRect, &menuRect, &tempRect)) {
|
|
theRect.top = GetMBarHeight() + gTitleBarHeight * 2 / 3;
|
|
MoveWindow(theWindow, theRect.left, theRect.top, false);
|
|
}
|
|
}
|
|
theWindow = NextWindow(theWindow);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* UnhideMenuBar()
|
|
*
|
|
* Purpose: Displays the menubar on the main screen, if it's currently full-screen
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void UnhideMenuBar(void)
|
|
{
|
|
Boolean oldMenuVis = gMenuVisible;
|
|
RgnHandle menuRgn = GetMenuRgn();
|
|
|
|
if (!(*gMainMonitor)->full || gMenuVisible) return;
|
|
SaveMenuArea();
|
|
DiffRgn(GetGrayRgn(), menuRgn, GetGrayRgn());
|
|
CalcVis((WindowPeek)FrontWindow());
|
|
CalcVisBehind((WindowPeek)FrontWindow(), menuRgn);
|
|
LMSetMBarHeight(gMenuHeight);
|
|
gMenuVisible = true;
|
|
if (oldMenuVis) MyInvalMenuBar();
|
|
else {
|
|
AdjustMenus();
|
|
DrawMenuBar();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* RehideMenuBar()
|
|
*
|
|
* Purpose: Removes the menu bar from the main screen, if it's currently full-screen
|
|
* Inputs: none
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void RehideMenuBar(void)
|
|
{
|
|
RgnHandle menuRgn = GetMenuRgn();
|
|
|
|
if (!(*gMainMonitor)->full || !gMenuVisible || gInBackground) return;
|
|
UnionRgn(GetGrayRgn(), menuRgn, GetGrayRgn());
|
|
PaintOne((WindowPeek)FrontWindow(), menuRgn);
|
|
PaintBehind((WindowPeek)FrontWindow(), menuRgn);
|
|
CalcVis((WindowPeek)FrontWindow());
|
|
CalcVisBehind((WindowPeek)FrontWindow(), menuRgn);
|
|
LMSetMBarHeight(0);
|
|
gMenuVisible = false;
|
|
RestoreMenuArea();
|
|
}
|
|
|
|
/*
|
|
* FrontWindowRgn(theRgn)
|
|
*
|
|
* Purpose: Finds the frontmost window that lies unobscured in theRgn
|
|
* Inputs: theRgn = the region of interest, in global coordinates
|
|
* Returns: a pointer to the window found, or nil if none qualify
|
|
*
|
|
*/
|
|
|
|
WindowPtr FrontWindowRgn(RgnHandle theRgn)
|
|
{
|
|
WindowPtr theWindow = FWFrontWindow();
|
|
WindowPtr theResult = nil;
|
|
RgnHandle testRgn;
|
|
|
|
if (testRgn = NewRgn()) {
|
|
for ( ; theWindow; theWindow = NextWindow(theWindow)) {
|
|
CopyRgn(theWindow->visRgn, testRgn);
|
|
GlobalRgn(testRgn, theWindow);
|
|
SectRgn(theRgn, testRgn, testRgn);
|
|
if (EqualRgn(theRgn, testRgn)) {
|
|
theResult = theWindow;
|
|
break;
|
|
} else if (!EmptyRgn(testRgn)) break;
|
|
}
|
|
DisposeRgn(testRgn);
|
|
}
|
|
return theResult;
|
|
}
|
|
|
|
/*
|
|
* GetMenuRgn()
|
|
*
|
|
* Purpose: Calculates the region occupied by the menubar
|
|
* Inputs: none
|
|
* Returns: a handle to the region of the menu bar
|
|
*
|
|
*/
|
|
|
|
RgnHandle GetMenuRgn(void)
|
|
{
|
|
static RgnHandle gMenuRgn = nil;
|
|
|
|
if (!gMenuRgn) {
|
|
gMenuRgn = NewRgn();
|
|
gMenuHeight = GetMBarHeight();
|
|
}
|
|
if (gMenuRgn) SetRectRgn(gMenuRgn, (*gMainMonitor)->rect.left, (*gMainMonitor)->rect.top,
|
|
(*gMainMonitor)->rect.right, (*gMainMonitor)->rect.top + gMenuHeight);
|
|
return gMenuRgn;
|
|
}
|
|
|
|
/*
|
|
* GetActiveRect(theMonitor, theRect)
|
|
*
|
|
* Purpose: Determines the active area of the monitor, with or without menu bar as
|
|
* appropriate
|
|
* Inputs: theMonitor = a handle to the monitor record
|
|
* theRect = a pointer to the destination rectangle
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void GetActiveRect(MonitorHandle theMonitor, Rect *theRect)
|
|
{
|
|
if ((theMonitor != gMainMonitor) || !gMenuVisible) *theRect = (*theMonitor)->rect;
|
|
else *theRect = (*(*theMonitor)->gray)->rgnBBox;
|
|
}
|
|
|
|
/*
|
|
* GetMinMaxMonitor(theImage)
|
|
*
|
|
* Purpose: Calculates the shallowest and deepest monitors intersecting the given
|
|
* image's window
|
|
* Inputs: theImage = a pointer to the image
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void GetMinMaxMonitor(ImageHandle theImage)
|
|
{
|
|
MonitorHandle theMonitor, deepMon = nil, shallowMon = nil;
|
|
ushort pass, depth, shallowest = 100, deepest = 0;
|
|
Rect winRect, tmpRect;
|
|
|
|
if (!WindowVisible((*theImage)->window)) {
|
|
if (!(*theImage)->dmon) (*theImage)->dmon = gMainMonitor;
|
|
if (!(*theImage)->smon) (*theImage)->smon = gMainMonitor;
|
|
return;
|
|
}
|
|
for (pass = 1; pass <= 2; pass++) {
|
|
winRect = (pass == 1) ? (*GetContRgn((*theImage)->window))->rgnBBox :
|
|
(*GetStrucRgn((*theImage)->window))->rgnBBox;
|
|
InsetRect(&winRect, 1, 1);
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
if (SectRect(&winRect, &(*theMonitor)->rect, &tmpRect)) {
|
|
depth = (*theMonitor)->depth;
|
|
if (depth > deepest) {
|
|
deepest = depth;
|
|
deepMon = theMonitor;
|
|
}
|
|
if (depth < shallowest) {
|
|
shallowest = depth;
|
|
shallowMon = theMonitor;
|
|
}
|
|
}
|
|
}
|
|
if (deepMon && shallowMon) break;
|
|
}
|
|
if (deepMon && shallowMon) {
|
|
(*theImage)->dmon = deepMon;
|
|
(*theImage)->smon = shallowMon;
|
|
} else if (deepMon) (*theImage)->dmon = (*theImage)->smon = deepMon;
|
|
else if (shallowMon) (*theImage)->dmon = (*theImage)->smon = shallowMon;
|
|
else (*theImage)->dmon = (*theImage)->smon = gMainMonitor;
|
|
}
|
|
|
|
/*
|
|
* GetDeepMonitor(pickColor)
|
|
*
|
|
* Purpose: Returns a pointer to the current deepest monitor
|
|
* Inputs: pickColor = flag: true to pick color monitors first
|
|
* Returns: a MonitorHandle pointing to the deepest monitor
|
|
*
|
|
*/
|
|
|
|
MonitorHandle GetDeepMonitor(Boolean pickColor)
|
|
{
|
|
ushort depth, deepest = 0, color = pickColor;
|
|
MonitorHandle theMonitor, deepMon = nil;
|
|
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
depth = (*theMonitor)->depth;
|
|
if ((depth > deepest) ||
|
|
((depth == deepest) && ((pickColor && !color) || (!pickColor && color)))) {
|
|
deepest = depth;
|
|
deepMon = theMonitor;
|
|
color = (*theMonitor)->color;
|
|
}
|
|
}
|
|
return deepMon;
|
|
}
|
|
|
|
/*
|
|
* GetBigMonitor(pickColor)
|
|
*
|
|
* Purpose: Returns a handle to the current biggest monitor
|
|
* Inputs: pickColor = flag: true to pick color monitors first
|
|
* Returns: a MonitorHandle pointing to the biggest monitor
|
|
*
|
|
*/
|
|
|
|
MonitorHandle GetBigMonitor(Boolean pickColor)
|
|
{
|
|
ulong biggest = 0, size, color = pickColor;
|
|
MonitorHandle theMonitor, bigMon = nil;
|
|
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
size = (long)Height(&(*theMonitor)->rect) * (long)Width(&(*theMonitor)->rect);
|
|
if ((size > biggest) ||
|
|
((size == biggest) && ((pickColor && !color) || (!pickColor && color)))) {
|
|
biggest = size;
|
|
bigMon = theMonitor;
|
|
color = (*theMonitor)->color;
|
|
}
|
|
}
|
|
return bigMon;
|
|
}
|
|
|
|
/*
|
|
* GetImageMonitor(theImage)
|
|
*
|
|
* Purpose: Returns a pointer to the deepest monitor intersected by the image window
|
|
* Inputs: theImage = pointer to the image we're interested in
|
|
* Returns: a MonitorHandle of the deepest intersecting monitor
|
|
*
|
|
*/
|
|
|
|
MonitorHandle GetImageMonitor(ImageHandle theImage)
|
|
{
|
|
MonitorHandle theMonitor, deepMon = nil;
|
|
ushort depth, deepest = 0;
|
|
Rect theRect, tmpRect;
|
|
|
|
if (!theImage || !(*theImage)->window) return nil;
|
|
theRect = (*theImage)->wrect;
|
|
GlobalRect(&theRect, (*theImage)->window);
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
if (SectRect(&theRect, &(*theMonitor)->rect, &tmpRect)) {
|
|
depth = (*theMonitor)->depth;
|
|
if (depth > deepest) {
|
|
deepest = depth;
|
|
deepMon = theMonitor;
|
|
}
|
|
}
|
|
}
|
|
return deepMon;
|
|
}
|
|
|
|
/*
|
|
* GetMostDevice(theRect)
|
|
*
|
|
* Purpose: Returns a pointer to the monitor containing the most area of the window
|
|
* Inputs: theRect = pointer to a global rectangle
|
|
* Returns: a MonitorHandle of the relevant intersecting monitor
|
|
*
|
|
*/
|
|
|
|
MonitorHandle GetMostDevice(Rect *theRect)
|
|
{
|
|
MonitorHandle theMonitor, mostMon = gMainMonitor;
|
|
long area, largest = 0;
|
|
Rect tmpRect;
|
|
|
|
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
|
|
SectRect(&(*theMonitor)->rect, theRect, &tmpRect);
|
|
area = (long)Width(&tmpRect) * (long)Height(&tmpRect);
|
|
if (area > largest) {
|
|
largest = area;
|
|
mostMon = theMonitor;
|
|
}
|
|
}
|
|
return mostMon;
|
|
}
|