home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
WINDOWS
/
UTILS
/
MEWIN10S.ZIP
/
MSWSYS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-10
|
32KB
|
1,034 lines
/* The routines in this file provide support for various OS-related
functions under the Microsoft Windows environment on an IBM-PC or
compatible computer.
Must be compiled with Borland C++ 2.0.
It should not be compiled if the WINDOW_MSWIN symbol is not set */
#include "estruct.h"
#include "elang.h"
#include <stdio.h>
#include <time.h>
#include "eproto.h"
#include "edef.h"
#define OEMRESOURCE 1 /* to have access to OBM_CLOSE from windows.h */
#include "mswin.h"
#define MAXPARAM 10 /* max command line parameters */
#define TXTSIZ NFILEN /* all purpose string length */
#define T_SLEEP 1 /* Sleep timer ID */
extern char *itoa (int value, char *string, int radix);
extern int putenv (const char *name);
/* message codes for EmacsBroadcast */
#define EMACS_BROADCAST 0x2000
#define EMACS_STARTING 0x2001
#define EMACS_ENDING 0x2010
/* variables */
static char *argv[MAXPARAM];
static int argc;
static CATCHBUF ExitCatchBuf;
static int Sleeping = 0; /* flag for TakeANap() */
static int TimeSlice;
static BOOL LongOperation = FALSE; /* for longop() and GetCharacter() */
static BOOL HourglassOn = FALSE; /* between SetHourglass & UpdateCursor */
static BOOL SystemModal = FALSE; /* indicates that the Yes/No message
box should be system-modal */
static int BroadcastVal; /* used by the EmacsBroadcast function */
static FARPROC MDIClientProc;
/* prototypes */
static void near pascal MessageLoop (BOOL WaitMode);
static BOOL near pascal UpdateCursor (HWND hWnd, WORD wParam, DWORD lParam);
static void near pascal SetHourglass (BOOL hg);
/* timeset: return a system-dependant time string */
/* ======= */
char * PASCAL timeset (void)
{
long Time;
struct tm *T;
static char section [] = "intl";
static int iDate, iTime;
static char sDate[2], sTime[2], sAMPM[2][5];
static char buf [TXTSIZ];
int day, month, year, hour;
time (&Time);
T = localtime (&Time);
iDate = GetProfileInt (section, "iDate", 0);
iTime = GetProfileInt (section, "iTime", 0);
GetProfileString (section, "sDate", "/", sDate, 2);
GetProfileString (section, "sTime", ":", sTime, 2);
GetProfileString (section, "s1159", "AM", sAMPM[0], 5);
GetProfileString (section, "s2359", "PM", sAMPM[1], 5);
day = T->tm_mday;
month = T->tm_mon + 1;
year = T->tm_year % 100;
hour = T->tm_hour;
wsprintf (buf, "%02d%s%02d%s%02d %02d%s%02d%s%02d %s",
iDate==1 ? day : iDate==2 ? year : month, sDate,
iDate==1 ? month : iDate==2 ? month : day, sDate,
iDate==1 ? year : iDate==2 ? day : year,
iTime==1 ? hour : (hour % 12) ? (hour % 12) : 12,
sTime, T->tm_min, sTime, T->tm_sec,
iTime==1 ? "" : sAMPM [hour / 12]);
return buf;
} /* timeset */
/* longop: to be called regularly while a long operation is in progress */
/* ======== */
PASCAL longop (int f)
/* f is TRUE to set long operation status and FALSE to reset that status */
/* when a long operation is signaled at least twice, the hourglass
cursor comes up */
/* While the long operation is in progress, this function runs the
message loop approximately every 100 ms to yield to other
applications and allow a reduced set of commands (among which quit)
to be input by the user */
{
static DWORD LastYield; /* time of last yield in milliseconds */
if (f) {
if (!LongOperation) {
LongOperation = TRUE;
LastYield = GetCurrentTime ();
}
else { /* 2nd (or more) call in a row, let's yield if enough
time has elapsed */
DWORD Time;
if ((Time = GetCurrentTime ()) - LastYield >= TimeSlice) {
SetHourglass (TRUE);
LastYield = Time;
MessageLoop (FALSE);
}
}
}
else {
if (LongOperation) {
LongOperation = FALSE;
SetHourglass (FALSE);
}
}
} /* longop */
/* mlyesno: ask a yes/no question */
/* ======= */
PASCAL mlyesno (char *prompt)
/* This function replaces the mlyesno from input.c. Instead of asking a
question on the message line, it pops up a message box */
{
if (MessageBox (hFrameWnd, prompt, ProgName,
MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION |
(SystemModal ? MB_SYSTEMMODAL : 0)) == IDYES) return TRUE;
return FALSE;
} /* mlyesno */
/* mlabort: display a serious error message (proposes abort) */
/* ======= */
PASCAL mlabort (char *s)
{
char text[NSTRING]; /* hopefully sufficient! */
while (*s == '%') s++; /* remove those strange % signs in some messages */
strcpy (text, s);
strcat (text, "\tAbort ");
strcat (text, ProgName);
strcat (text, " ?");
if (MessageBox (hFrameWnd, text, NULL,
MB_YESNO | MB_DEFBUTTON2 |
MB_ICONHAND | MB_APPLMODAL) == IDYES) {
eexitval = -1;
Throw (ExitCatchBuf, ABORT);
}
} /* mlabort */
/* WinInit: all the window initialization crap... */
/* ======= */
BOOL far pascal WinInit (LPSTR lpCmdLine, int nCmdShow)
/* returns FALSE if failed init */
{
WNDCLASS wc;
HMENU hSysMenu;
char FrameClassName [TXTSIZ];
char text [TXTSIZ];
POINT InitPos;
int Colors;
int i;
static char HomeDir [NFILEN] = "HOME=";
InitializeFarStorage ();
WinFlags = GetWinFlags ();
i = GetModuleFileName (hEmacsInstance, text, NFILEN);
for (; i >= 0; i--) {
if (text[i] == '\\') {
text[i] = '\0'; /* transform file name into dir name */
break;
}
}
if (i > 0) {
strcat (HomeDir, text);
putenv (HomeDir); /* set HOME environment var to point to
MicroEMACS executable directory */
}
HelpEngineFile[0] = '\0';
/*-read the profile */
TimeSlice = GetProfileInt (ProgName, "TimeSlice", 100);
Colors = GetProfileInt (ProgName, "Colors", 0);
GetProfileString (ProgName, "HelpFile", "mewin.hlp", text, TXTSIZ);
MainHelpFile = copystr (text);
MainHelpUsed = FALSE;
GetProfileString (ProgName, "InitialSize", "", text, TXTSIZ);
strlwr (text);
if (strstr (text, "optimize")) {
InitPos.x = InitPos.y = 0;
}
else {
InitPos.x = InitPos.y = CW_USEDEFAULT;
}
if (nCmdShow == SW_SHOWNORMAL) {
if (strstr (text, "maximize")) {
nCmdShow = SW_SHOWMAXIMIZED;
}
else if (strstr (text, "minimize") || strstr (text, "icon")) {
nCmdShow = SW_SHOWMINNOACTIVE;
}
}
/*-Register the frame window class */
strcpy (FrameClassName, ProgName);
strcat (FrameClassName, "_frame");
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = FrameWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = FRMWNDEXTRA;
wc.hInstance = hEmacsInstance;
wc.hIcon = LoadIcon (hEmacsInstance, "AppIcon");
wc.hCursor = NULL;
wc.hbrBackground= COLOR_WINDOW + 1;
wc.lpszMenuName = "Menu";
wc.lpszClassName= FrameClassName;
RegisterClass (&wc);
/*-Register the MDI child (screen) window class */
strcpy (text, ProgName);
strcat (text, "_screen");
ScreenClassName = copystr(text);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = ScrWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = SCRWNDEXTRA;
wc.hInstance = hEmacsInstance;
wc.hIcon = LoadIcon (hEmacsInstance, "ScreenIcon");
wc.hCursor = NULL;
wc.hbrBackground= COLOR_WINDOW + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName= ScreenClassName;
RegisterClass (&wc);
/*-Create the frame window */
hFrameWnd = CreateWindow (FrameClassName, /* class */
ProgName, /* title */
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
InitPos.x, /* positions */
InitPos.y,
CW_USEDEFAULT, /* dimensions */
CW_USEDEFAULT,
NULL, /* parent handle */
NULL, /* menu */
hEmacsInstance,
NULL);
if (hFrameWnd == 0) return FALSE;
if (Colors == 0) {
/* try to detect monochrome displays */
HDC hDC;
hDC = GetDC (hFrameWnd);
ColorDisplay = (GetDeviceCaps (hDC, NUMCOLORS) > 2);
ReleaseDC (hFrameWnd, hDC);
}
else {
ColorDisplay = (Colors > 2);
}
ShowWindow (hFrameWnd, nCmdShow);
hScreenCursor = LoadCursor (hEmacsInstance, "ScreenCursor");
hTrackCursor = hScreenCursor;
hNotQuiescentCursor = LoadCursor (hEmacsInstance,
"NotQuiescentCursor");
hHourglass = LoadCursor (NULL, IDC_WAIT);
in_init (); /* sets up the input stream */
argv [0] = ProgName; /* dummy program name */
{
register char *s;
argc = 1;
s = copystr (lpCmdLine);
while (*s != '\0') {
argv[argc] = s;
if (++argc >= MAXPARAM) goto ParsingDone;
while (*++s != ' ') if (*s == '\0') goto ParsingDone;
*s = '\0';
while (*++s == ' ');
}
}
ParsingDone:
return TRUE;
} /* WinInit */
/* SetFrameCaption: sets the frame window's text according to the app Id */
/* =============== */
static void pascal near SetFrameCaption (void)
{
char text[sizeof(PROGNAME)+19];
char *t;
int Id;
strcpy (text, ProgName);
Id = GetWindowWord (hFrameWnd, GWW_FRMID);
if (Id) {
for (t = text; *t != '\0'; t++) ; /* look for the end of text */
*t++ = ' ';
*t++ = '#';
itoa (Id, t, 10); /* append the App Id */
}
SetWindowText (hFrameWnd, text);
} /* SetFrameCaption */
/* BroadcastEnumProc: used by EmacsBroadcast */
/* ================= */
BOOL EXPORT far pascal BroadcastEnumProc (HWND hWnd, DWORD lParam)
{
if ((hWnd != LOWORD(lParam)) &&
(GetClassLong (hWnd, GCL_WNDPROC) == (DWORD)FrameWndProc)) {
if (HIWORD(lParam) != 0) {
PostMessage (hWnd, WM_COMMAND, EMACS_BROADCAST, lParam);
}
if (HIWORD(lParam) == EMACS_STARTING) {
/*-compute highest application Id */
int Id;
Id = GetWindowWord (hWnd, GWW_FRMID);
if (Id == 0) Id = 1;
++Id;
BroadcastVal = max(BroadcastVal, Id);
}
else {
/*-compute number of applications */
BroadcastVal++;
}
}
return TRUE;
} /* BroadcastEnumProc */
/* EmacsBroadcast: send a broadcast message to all Emacs applications */
/* ============== */
static int pascal near EmacsBroadcast (WORD MsgCode, HWND hWnd)
/* If MsgCode is not zero, the broadcast is sent as a WM_COMMAND to all
the Emacs frame windows, except the one specified by hWnd. The wParam
of that message is EMACS_BROADCAST, the HIWORD of lParam is set to
MsgCode and the LOWORD of lParam is set to hWnd.
The value returned by this function depends on MsgCode:
- If MsgCode is EMACS_STARTING, the function returns the Id assigned to
the calling Emacs instance: 0 if it is alone or 1 plus the highest Id
found, discounting the instance identified by hWnd (note that for
this purpose, an instance that has an Id of 0 is equivalent to a
"highest Id" of 1).
- If MsgCode is EMACS_ENDING or 0, the function returns the number of
emacs instances found, not counting the one identified by hWnd.
*/
{
FARPROC ProcInstance;
ProcInstance = MakeProcInstance ((FARPROC)BroadcastEnumProc,
hEmacsInstance);
BroadcastVal = 0;
EnumWindows (ProcInstance, MAKELONG(hWnd, MsgCode));
FreeProcInstance (ProcInstance);
return BroadcastVal;
} /* EmacsBroadcast */
/* MDIClientSubProc: Subclassing window proc for the MDI Client window */
/* ================ */
LONG EXPORT far pascal MDIClientSubProc (HWND hWnd, WORD wMsg, WORD wParam,
LONG lParam)
{
switch (wMsg) {
case WM_SETCURSOR:
if (UpdateCursor (hWnd, wParam, lParam)) return TRUE;
goto DefaultProc;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_CHAR:
case WM_SYSCHAR:
if (EatKey (wMsg, wParam, lParam)) break;
goto DefaultProc;
case WM_PARENTNOTIFY:
if (notquiescent) break; /* blocks mouse selection of an MDI
child (except on caption clicks!)
*/
goto DefaultProc;
default:
DefaultProc:
return CallWindowProc (MDIClientProc, hWnd, wMsg, wParam, lParam);
}
return 0L;
} /* MDIClientSubProc */
/* FrameInit: Frame window's WM_CREATE */
/* ========= */
void far pascal FrameInit (CREATESTRUCT *cs)
{
RECT Rect;
CLIENTCREATESTRUCT ccs;
HMENU hMenu;
/*-advertise our birth to other Emacs instances and set the frame's
caption with an Id if necessary */
SetWindowWord (hFrameWnd, GWW_FRMID,
EmacsBroadcast (EMACS_STARTING, hFrameWnd));
SetFrameCaption ();
/*-add "optimize" to system menu */
hMenu = GetSystemMenu (hFrameWnd, 0);
InsertMenu (hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED, SC_OPTIMIZE,
"&Optimize");
/*-initialize fonts and Cell Metrics */
FontInit ();
/*-Create the MDI Client window */
hMDIClientWnd = NULL; /* the NULL initial value allows
DefFrameProc to behave properly if
FrameInit fails */
ccs.hWindowMenu = GetScreenMenuHandle ();
ccs.idFirstChild = IDM_FIRSTCHILD;
GetClientRect (hFrameWnd, &Rect);
hMDIClientWnd = CreateWindow ("MDICLIENT", /* class */
NULL, /* title */
WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL |
WS_HSCROLL | WS_VISIBLE, /* style */
0, /* positions */
0,
Rect.right, /* dimensions */
Rect.bottom - EmacsCM.MLHeight,
hFrameWnd, /* parent handle */
NULL, /* menu */
hEmacsInstance,
(LPSTR) (LPCLIENTCREATESTRUCT) &ccs);
if (hMDIClientWnd) {
/* we subclass the MDIClient */
FARPROC ProcInstance;
MDIClientProc = (FARPROC)GetWindowLong (hMDIClientWnd, GWL_WNDPROC);
ProcInstance = MakeProcInstance ((FARPROC)MDIClientSubProc,
hEmacsInstance);
SetWindowLong (hMDIClientWnd, GWL_WNDPROC, ProcInstance);
}
} /* FrameInit */
/* CloseEmacs: handle WM_CLOSE of WM_QUERYENDSESSION messages */
/* ========== */
static BOOL near pascal CloseEmacs (WORD wMsg)
/* returns TRUE if emacs should exit */
{
if (eexitflag) return TRUE; /* emacs has already quited */
if (wMsg == WM_QUERYENDSESSION) SystemModal = TRUE;
if (fbusy != FWRITING) { /* no file write in progress */
quit (FALSE, 0); /* check if it's ok with emacs to terminate */
}
else { /* there is, indeed a file write in progress
MessageBeep (0); /* wake the user up! */
if (MessageBox (hFrameWnd, TEXT333,
/* "File write in progress. Quit later!" */
ProgName,
MB_OKCANCEL | MB_ICONSTOP |
(SystemModal ? MB_SYSTEMMODAL : 0)) == IDCANCEL) {
quit (TRUE, 0); /* give up! */
}
}
if (wMsg == WM_QUERYENDSESSION) SystemModal = FALSE;
if (eexitflag) { /* emacs agrees to quit */
ClipboardCleanup (); /* close clipboard if we had it open */
if (fbusy != FALSE) ffclose (); /* cleanup file IOs */
return TRUE;
}
update (TRUE); /* restore the caret that quit() moved into
the message line */
return FALSE; /* we refuse to die! */
} /* CloseEmacs */
/* ScrWndProc: MDI child (screen) window function */
/* ========== */
LONG EXPORT far pascal ScrWndProc (HWND hWnd, WORD wMsg, WORD wParam,
LONG lParam)
{
switch (wMsg) {
case WM_CREATE:
{ /*-init WindowWords for ScrReSize function */
RECT Rect;
GetClientRect (hWnd, &Rect);
SetWindowWord (hWnd, GWW_SCRCX, Rect.right);
SetWindowWord (hWnd, GWW_SCRCY, Rect.bottom);
}
{ /*-setup the stuff for display.c */
SCREEN *sp;
sp = (SCREEN*)(((MDICREATESTRUCT*)(((CREATESTRUCT*)lParam)->
lpCreateParams))->lParam);
SetWindowLong (hWnd, GWL_SCRPTR, (DWORD)sp);
sp->s_drvhandle = hWnd;
}
goto DefaultProc;
case WM_DESTROY:
vtfreescr ((SCREEN*)GetWindowLong (hWnd, GWL_SCRPTR));
break;
case WM_KILLFOCUS:
EmacsCaret (FALSE);
goto DefaultProc;
case WM_SETFOCUS:
EmacsCaret (TRUE);
goto DefaultProc;
case WM_ACTIVATE:
if (wParam) EmacsCaret (TRUE);
goto DefaultProc;
case WM_MDIACTIVATE:
if (wParam) { /* this one is becoming active */
if (!InternalRequest) {
InternalRequest = TRUE;
select_screen ((SCREEN *) GetWindowLong (hWnd, GWL_SCRPTR),
FALSE);
InternalRequest = FALSE;
}
else {
SCREEN *sp;
sp = (SCREEN*)GetWindowLong (hWnd, GWL_SCRPTR);
if (sp->s_virtual == NULL) {
/* this is initialization time! */
vtinitscr (sp, DisplayableRows (hWnd, 0, &EmacsCM),
DisplayableColumns (hWnd, 0, &EmacsCM));
}
}
}
goto DefaultProc;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_CHAR:
case WM_SYSCHAR:
if (EatKey (wMsg, wParam, lParam)) break;
goto DefaultProc;
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
MouseMessage (hWnd, wMsg, wParam, lParam);
break;
case WM_SETCURSOR:
if (UpdateCursor (hWnd, wParam, lParam)) return TRUE;
goto DefaultProc;
case WM_PAINT:
ScrPaint (hWnd);
break;
case WM_SIZE:
if (!IsIconic (hFrameWnd)) {
if (wParam == SIZEICONIC) EmacsCaret (FALSE);
ScrReSize (hWnd, wParam, LOWORD(lParam), HIWORD(lParam));
}
goto DefaultProc;
case WM_GETMINMAXINFO:
GetMinMaxInfo (hWnd, (LPPOINT)lParam);
goto DefaultProc;
case WM_MOUSEACTIVATE:
if (notquiescent) break; /* blocks mouse selection of an MDI
child's caption */
goto DefaultProc;
case WM_SYSCOMMAND:
switch (wParam & 0xFFF0) {
case SC_RESTORE:
case SC_SIZE:
case SC_MAXIMIZE:
case SC_MINIMIZE:
case SC_NEXTWINDOW:
case SC_PREVWINDOW:
if (notquiescent) break; /* sizing commands disabled */
goto DefaultProc;
case SC_CLOSE:
if (!notquiescent) {
SCREEN *sp;
/* this must be done here, before any MDI mumbo-jumbo */
sp = (SCREEN*)GetWindowLong (hWnd, GWL_SCRPTR);
if (sp == first_screen) {
cycle_screens (FALSE, 0);
}
if (sp != first_screen) {
unlist_screen (sp);
free_screen (sp);
}
update (TRUE); /* to restore the caret */
}
break;
case SC_MOVE:
if (notquiescent) {
/* prevent moving an MDI client other than the already
active one, since it would transfer the activation */
if (hWnd != LOWORD(SendMessage (hMDIClientWnd,
WM_MDIGETACTIVE,
0, 0L))) break;
}
goto DefaultProc;
default:
goto DefaultProc;
}
break;
default:
DefaultProc:
return DefMDIChildProc (hWnd, wMsg, wParam, lParam);
}
return 0L;
} /* ScrWndProc */
/* FrameWndProc: frame window function */
/* ============ */
LONG EXPORT far pascal FrameWndProc (HWND hWnd, WORD wMsg, WORD wParam,
LONG lParam)
{
switch (wMsg) {
case WM_INITMENUPOPUP:
InitMenuPopup (wParam, lParam);
goto DefaultProc;
case WM_MENUCHAR:
{
LONG Code;
Code = DefFrameProc (hWnd, hMDIClientWnd, wMsg, wParam, lParam);
if (HIWORD(Code) != 0) return Code; /* matches a menu command */
if (EatKey (wMsg, wParam, lParam)) return MAKELONG(0,1);
/* MicroEMACS ate that character, close the current menu! */
else return Code;
}
case WM_COMMAND:
if (wParam == EMACS_BROADCAST) {
int Id;
switch (HIWORD(lParam)) {
case EMACS_STARTING:
/* another instance of emacs is starting. If our ID was
0, it should now be 1 */
if (GetWindowWord (hFrameWnd, GWW_FRMID) == 0) {
SetWindowWord (hFrameWnd, GWW_FRMID, 1);
SetFrameCaption ();
}
break;
case EMACS_ENDING:
/* another instance of emacs is ending. If we are now
alone, let's switch our Id back to 0 */
Id = EmacsBroadcast (0, LOWORD(lParam));
/* Id here is the number of Emacs applications, except
the dying one */
if (Id == 1) {
SetWindowWord (hFrameWnd, GWW_FRMID, 0);
SetFrameCaption ();
}
break;
}
}
else {
if (!MenuCommand (wParam, lParam)) goto DefaultProc;
}
break;
case WM_SYSCOMMAND:
switch (wParam & 0xFFF0) {
case SC_RESTORE:
if (IsIconic (hFrameWnd)) goto DefaultProc;
case SC_SIZE:
case SC_MAXIMIZE:
if (notquiescent) break; /* sizing commands disabled */
goto DefaultProc;
case SC_OPTIMIZE:
if (notquiescent) break;
if (IsZoomed (hFrameWnd) || IsIconic (hFrameWnd)) {
/* must restore it first */
ShowWindow (hFrameWnd, SW_RESTORE);
}
MoveWindow (hFrameWnd, 0, 0,
GetSystemMetrics (SM_CXSCREEN),
GetSystemMetrics (SM_CYSCREEN)
- GetSystemMetrics (SM_CYICON)
- GetSystemMetrics (SM_CYCAPTION)
- GetSystemMetrics (SM_CYBORDER),
TRUE);
break;
default:
goto DefaultProc;
}
break;
case WM_SETCURSOR:
if (UpdateCursor (hWnd, wParam, lParam)) return TRUE;
goto DefaultProc;
case WM_TIMER:
if (wParam == T_SLEEP) {
--Sleeping; /* signal wake up to TakeANap() */
break;
}
goto DefaultProc;
case WM_PAINT: /* must be the message line */
MLPaint ();
break;
case WM_SIZE: /* must adjust the MDIClient's size to fit the
Message Line */
MoveWindow (hMDIClientWnd, 0, 0,
LOWORD(lParam), HIWORD(lParam) - EmacsCM.MLHeight, TRUE);
break;
case WM_NCLBUTTONDBLCLK:
{ /* This corrects a Windows 3.0 bug that prevents a maximized
child from being closed by double-clicking the close-box.
See "Windows 3: A Developer's Guide" by Jeffrey M.
Richter, page 480 */
RECT Rect;
HBITMAP hBmp;
BITMAP Bmp;
DWORD MDIGetActivateResult;
if (wParam != HTMENU) goto DefaultProc;
MDIGetActivateResult = SendMessage (hMDIClientWnd,
WM_MDIGETACTIVE, 0, 0);
if (!HIWORD(MDIGetActivateResult)) goto DefaultProc;
GetWindowRect (hWnd, &Rect);
Rect.top += GetSystemMetrics(SM_CYCAPTION) +
GetSystemMetrics (SM_CYFRAME);
Rect.left += GetSystemMetrics(SM_CXFRAME);
hBmp = LoadBitmap (NULL, MAKEINTRESOURCE(OBM_CLOSE));
GetObject (hBmp, sizeof(BITMAP), (LPSTR)(LPBITMAP)&Bmp);
Rect.bottom = Rect.top + Bmp.bmHeight;
Rect.right = Rect.left + Bmp.bmWidth / 2;
if (!PtInRect(&Rect, MAKEPOINT(lParam))) goto DefaultProc;
SendMessage(LOWORD(MDIGetActivateResult), WM_SYSCOMMAND,
SC_CLOSE, lParam);
}
break;
case WM_ACTIVATE:
EmacsCaret (wParam);
/* This call matters only when the active MDI Child is
iconic, in which case it never receives the focus and
thus fails to create the caret (that should still appear
if we are getting input on the message line) */
goto DefaultProc;
case WM_CREATE:
hFrameWnd = hWnd;
FrameInit ((CREATESTRUCT *)lParam);
goto DefaultProc;
case WM_QUERYENDSESSION:
if (CloseEmacs (wMsg)) return 1L;
break;
case WM_CLOSE:
if (CloseEmacs (wMsg)) goto DefaultProc;
break;
case WM_DESTROY:
if (MainHelpUsed) WinHelp (hFrameWnd, MainHelpFile, HELP_QUIT, NULL);
if (HelpEngineFile[0] != '\0') WinHelp (hFrameWnd, HelpEngineFile,
HELP_QUIT, NULL);
EmacsBroadcast (EMACS_ENDING, hFrameWnd);
PostQuitMessage (0);
break;
default:
DefaultProc:
return DefFrameProc (hWnd, hMDIClientWnd, wMsg, wParam, lParam);
}
return 0L;
} /* FrameWndProc */
/* WinMain: Application entry point */
/* ======= */
int pascal WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
hEmacsInstance = hInstance;
if (!WinInit (lpCmdLine, nCmdShow)) return -1;
switch (Catch (ExitCatchBuf)) {
case 0:
emacs (argc, argv);
/* If we exit through an emacs command, we pass here. Otherwise
(exit through a close in system menu or a windows session
termination), the application terminates from the call to
mswgetc that received the signal */
case ABORT:
eexitflag = TRUE;
longop (FALSE);
PostMessage (hFrameWnd, WM_CLOSE, 0, 0L);
for (;;) MessageLoop (TRUE);/* go into message loop until WM_QUIT */
/* case TRUE:
break; */
}
return eexitval;
} /* WinMain */
/* ModifyCursor: forces a WM_SETCURSOR */
/* ============ */
static void pascal near ModifyCursor (void)
{
POINT pt;
GetCursorPos (&pt);
SetCursorPos (pt.x, pt.y);
} /* ModifyCursor */
/* MessageLoop: Main message loop */
/* =========== */
static void near pascal MessageLoop (BOOL WaitMode)
/* If WaitMode is TRUE this function uses GetMessage the first time and
PeekMessage after that, until the input queue is empty and there is
something in the in_put pipe. Thus, WM_PAINTs are processed and the
input queue is emptied into the in_put pipe.
If WaitMode is FALSE, this function uses PeekMessage from the
beginning and returns only when the input queue is empty. In that
case, WM_PAINTs are not processed, but the processor still gets
relinquished. Note that while peeking for messages, this function
returns if the in_put pipe is about to overflow */
{
MSG Msg;
BOOL Peeking;
++notquiescent; /* this restrics some actions in nested calls */
ModifyCursor ();
do {
Peeking = !WaitMode;
for (;;) {
if(defferupdate) {
ShowEmacsCaret (FALSE);
update (TRUE);
ShowEmacsCaret (TRUE);
}
if (Peeking) {
if (!in_room (5)) break; /* input stream about to overflow */
if (!PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE)) break;
}
else {
longop (FALSE); /* we are going to wait for input */
GetMessage (&Msg, NULL, 0, 0);
Peeking = TRUE; /* from now on... */
}
if (Msg.message == WM_QUIT) { /* time to leave... */
JettisonFarStorage ();
if (hEmacsFont) DeleteObject (hEmacsFont);
Throw (ExitCatchBuf, TRUE);
/* we're gone out of business ! */
/* **************************** */
}
if (!TranslateMDISysAccel (hMDIClientWnd, &Msg)) {
TranslateMessage (&Msg);
DispatchMessage (&Msg);
}
}
} while (WaitMode && !in_check ()); /* keep waiting if pipe is empty */
--notquiescent;
ModifyCursor ();
return;
} /* MessageLoop */
/* GetInput: wait for user input (called by mswgetc from mswdrv.c) */
/* ======== */
/* The returned value is the next character from the input stream */
int far pascal GetInput (void)
{
if (!in_check ()) {
ShowEmacsCaret (TRUE);
MessageLoop (TRUE);
ShowEmacsCaret (FALSE);
}
return in_get (); /* return next character */
} /* GetInput */
/* TakeANap: put emacs to sleep for a few milliseconds */
/* ======== */
int far pascal TakeANap (int t)
/* this function is used by mswsleep(). It returns TRUE unless the timer
could not be created. Note that for a null time, it simply
relinquishes the processor */
{
if ((t == 0) ||
(!SetTimer (hFrameWnd, T_SLEEP, t, (FARPROC)NULL))) {
ShowEmacsCaret (TRUE);
MessageLoop (FALSE); /* let's do one relinquish anyway */
ShowEmacsCaret (FALSE);
if (t == 0) return TRUE;
else return FALSE;
}
ShowEmacsCaret (TRUE);
Sleeping = 1; /* this gets reset by WM_TIMER processing */
do {
MessageLoop (FALSE);
WaitMessage ();
} while (Sleeping > 0);
ShowEmacsCaret (FALSE);
KillTimer (hFrameWnd, T_SLEEP);
return TRUE;
} /* TakeANap */
/* UpdateCursor: sets the apropriate Emacs cursor shape */
/* ============ */
static BOOL near pascal UpdateCursor (HWND hWnd, WORD wParam, DWORD lParam)
/* this function should be called on each WM_SETCURSOR message, to
display the appropriate cursor. It returns TRUE if all processing has
been done (the calling window function should return TRUE). it
returns FALSE if the default window proc sould be called. */
{
HCURSOR hCursor;
switch (LOWORD(lParam)) { /* hit-test area code as in WM_NCHITTEST */
case HTCLIENT:
if (HourglassOn) hCursor = hHourglass;
else {
if (wParam == hFrameWnd) {
if (notquiescent) hCursor = hNotQuiescentCursor;
else hCursor = NULL;
}
else { /* a screen window or the MDIClient */
if (notquiescent) hCursor = hNotQuiescentCursor;
else if (wParam == hMDIClientWnd) {
hCursor = NULL;
}
else if (mouseflag) {
if (MouseTracking) hCursor = hTrackCursor;
else hCursor = hScreenCursor;
}
else hCursor = 0;
}
}
if (!hCursor) hCursor = LoadCursor (NULL, IDC_ARROW);
break;
case HTHSCROLL:
case HTVSCROLL:
case HTREDUCE:
if ((wParam == hMDIClientWnd) || (wParam == hFrameWnd)) return FALSE;
case HTBOTTOM:
case HTBOTTOMLEFT:
case HTBOTTOMRIGHT:
case HTLEFT:
case HTRIGHT:
case HTTOP:
case HTTOPLEFT:
case HTTOPRIGHT:
case HTSIZE:
case HTZOOM:
/* all those are unuseable when notquiescent */
if (notquiescent) {
if (HourglassOn) hCursor = hHourglass;
else hCursor = hNotQuiescentCursor;
}
else return FALSE;
break;
default:
return FALSE;
}
SetCursor (hCursor);
return TRUE;
} /* UpdateCursor */
/* SetHourglass: sets or removes the hourglass cursor */
/* ============ */
static void near pascal SetHourglass (BOOL hg)
/* hg = TRUE sets the hourglass, hg = FALSE removes it */
{
POINT Point;
HWND hWnd;
if (hg == HourglassOn) return; /* nothing to do */
HourglassOn = hg;
GetCursorPos (&Point);
hWnd = WindowFromPoint (Point);
if (hWnd && (GetWindowTask (hWnd) == GetCurrentTask ())) {
/* the cursor is above one of MicroEMACS's windows */
SetCursorPos (Point.x, Point.y);
/* this should cause a dummy cursor movement to be processed,
ending up in UpdateCursor being invoked */
}
} /* SetHourglass */