Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

C Programming


MAY92: C PROGRAMMING

This article contains the following executables: DFLT12.ARC D12TXT.ARC

The APPLICATION window class is the foundation of any D-Flat application, which must create an application window before doing anything further. The application window hosts the menu bar, which hosts the pop-down menus, which react to the user's commands to make the program do its job. You learned about menus in an earlier "C Programming" column. The example Memopad program, which I described earlier as well, shows you how to create an application window and the command functions that its menu executes. This month, I'll explain how the application window itself works.

Window Class Messages

Listing One is applicat.c. the code that implements the APPLICATION window class. Its primary function is ApplicationProc, the window-processing module for the class. A typical D-Flat npplication will include its own application-window processing module, which intercepts the messages, processes the ones it wants, and then calls this module through the DefaultWndProc function. ApplicationProc uses a switch to interpret the messages. As with other D-Flat window-processing modules. ApplicationProc calls functions to process most of the messages. The names of the functions reflect the message name.

The CREATE_WINDOW message. The CREATE_WINDOW message begins by modifying the dialog box that lets the user change the characteristic of the display. Depending on the video system, the user had different options. A VGA can display 25, 43, or 50 lines, and that is how the dialog box is set up. If the user has a VGA, no changes are made. An EGA system can display 25 and 43 lines, so the program modifies the dialog box to include only those options. A CGA system can display only 25 lines, so the program modifies the dialog box so that no line-selection options appear. Next, the CREATE_WINDOW message checks the settings of the application's configuration-file variables that control how the application window displays. These settings control whether the window has a border, whether its data space is clear or textured, whether there are title and status bars, how many lines are on the screen, and whether the display is to be in color. monochrome. or reverse monochrome. The program sets the various check-box and radio-button controls on the dialog box to reflect the current settings. Then the program creates the menu- and status-bar windows as child windows of the parent application window. Next, the program calls a function to load the application's help database. Finally. it sends the SHOW_MOUSE message to show the mouse cursor.

The HIDE_WINDOW message. The HIDE_WINDOW message normally tries to change the focus if the window being hidden has the focus. If that window is the application window, there will not be a window that can get the focus, because a D-Flat application window is the ancestor of them all. Therefore, the application window intercepts the HIDE_WINDOW message to itself and sets the inFocus variable to NULL so that the program will not attempt to give the focus to another window.

The ADDSTATIIS message. D Flat applications send the ADDSTATUS message to the application window to write to or clear the text area of the status bar. The ADDSTATUS message sends SETTENT or CLEARTEXT messages to the status bar's window handle.

The SETFOCUS message. The APPLICATION window class has its own version of the SETFOCUS message. It does most of what the NORMAL window class does, but it does not do the repainting of overlapping and underlapping windows that document windows need.

The SIZE message. The SIZE message to the application window must do two things besides change the size of the application window itself. The menu- and status-bar windows are children of the application window, and their sizes depend on its size. Therefore, when the user changes the size of the application window, the program must automatically adjust the size of the menu and status bars. It does that by calling the functions that create those two windows. The functions close the windows if they already exist, and then create them with sizes that reflect the size of the application window.

The MINIMIZE message. D-Flat does not allow you to minimize the application window. Therefore, it intercepts the MINIMIZE message and simply returns without doing anything.

The KEYBOARD message. There are several keystroke values that the application window intercepts and processes. The AIt+F4 keystroke is the accelerator key for the Close conxti~nd on the application window s system menu. Therefore, the program sends the application window a CLOSE_WINDOW message when the window gets a KEY BOARD message with the Alt+F4 key stroke value. The user presses Alt+F6 to step from window to witidow. The pro gram calls the SetNextFocus and SkipSystemWindow functions when the application window gets Alt+F6 in a KEYBOARD message. Alt-Hyphen calls the BuildSystemMenu function to pop down the system menu for the application window. The application window passes all other keystrokes to the menu-bar window.

Keystroke events send KEYBOARD messages to the window that has the focus. If that window does not process the keystroke, it sends the message to its parent. The parent window does the same thing--it either processes the keystroke or passes the message to its parent. Eventually, an unprocessed KEYBOARD message will get to the application window because it is at the top of the family tree. If the application window does not process the message, it sends the message to the menu bar, which tests to see if the keystroke is a command-accelerator key or a menushortcut, Alt-key combination. This procedure guarantees that every window gets the KEYBOARD messages that it needs.

The SHIFT_CHANGED message. The D-Flat user interface allows the user to switch between a document window and the menu bar by pressing the F10 key or by pressing and releasing the Alt key without pressing another key. The window-processing module for the menu bar intercepts the F10 key and handles the switch between windows.

The SHIFT_CHANGED message is sent when the event collection routines in the message-processing code of DFlat senses that the user has pressed or released a Shift, Alt, or Ctrl key. As with unwanted KEYBOARD messages, all windows pass the SHIFT_CHANGED message to their parent window. The application program eventually intercepts this message to watch for changes in the Alt key. The program uses the AllDou'ii variable to indicate that the Alt key was seen to be pressed. When another SHIFT_CHANGED message occurs with the Alt key released, and when there has been no intervening keystroke while the Alt key was down. the program senses that the Alt key has been pressed and released by itself. The program then sends a KEYBOARD message with the F10 key value to the menu bar.

The PAINT message. When the application window gets the PAINT message, it simply clears its data space by calling the ClearWindow function. The cleaning character will be either a space or the value defined as APPLCHAR, depending on whether the user has selected a clear or textured application window.

The COMMAND message. The application window processes several of the COMMAND messages. A COMMAND message can originate from within the application program, or it can be the result of the user choosing a menu selection with which the command's identification is associated. All the commands that the application window processes come from menu selections.

In fact, all menu commands come to the application window first. The popdown menu sends the associated COMMAND message to its parent. the menu bar, when the user chooses a menu selection. The menu bar sends the message to its parent, the application window. If the application window does not process the COMMAND message, it sends the message to whatever document window has the focus. Otherwise, the application window processes the COMMAND messages discussed next. A COMMAND message is identified by a code in its first parameter.

There are several help commands associated with selections on the Help menu. Each of these calls the DisplayHelp function to display the associated help screen.

The ID_DOS command is associated with the DOS Shell command on the File menu. bus command calls the Shell DOS function which calls the DOS shell. First the function hides the D Flat application window and swaps the cursor and screen height configurations with what they were when the D Flat application program started. Then the function hides the mouse, displays a message telling the user how to get back into the D Flat application by typing the DOS EXIT command, then spawns a new copy of the DOS command processor. When the command processor retums. the program switches the screen and cursor back to their D-Flat context and shows the application window and the mouse cursor.

The ID_EMT and ID_SYSCLOSE cornmands both post the CLOSE_WINDOW message to the application. The ID EMT command is associated with the Exit selection on the File menu, and the ID_SYSCLOSE command is associated with the Close selection on the application window's system menu.

The ID_DISPLAY command is the result of the user choosing the Display selection on the Options menu. It executes the Display dialog box and then calls the various functions that affect how the application window is displayed.

The ID_SAVEOPTIONS command saves the user-selected options to a configuration file.

The ID_WINDOW command is sent when the user selects a document window from the Window menu. This menu is built dynamically when the user selects it on the menu baa It displa,ys the titles of the first nine document windows in the application window's data space. The Window menu provides one of the ways for the user to select a new document window to have the focus. The message finds the chosen document window from among those in the application window's list of child windows and sends the SETFOCUS message to the document window. If the document window is minimized, the program also sends it the RESTORE command.

The ID_CLOSEALL command is associated with the Close All selection on the Window menu. It sends every document window in the application window's list of children a CLOSE_WINDOW message.

The ID_MOREW1NDOWS command is associated with the More Windows selection on the Window menu. The menu includes that selection when there are more than nine document windows. The command displays a dialog box with a list-box control that has all the document-window titles. The dialog box serves as an extension to the Window menu listin all of the document windows instead of onl the first nine. The user can choose a window from the list box.

The CLOSE-WINDOW message. This message closes all the application window's document windows and posts the STOP message to the D-Flat message system. After the application window closes, the program resets the screen height to whatever it was when the program started and calls a function to unload the help database.

How to Get D-Flat Now

The D-Flat source code is on CompuServe in Library 0 of the DDJ Forum and on M&T Online. If you cannot use either online service. send a formatted 360K or 72OK diskelle and an addressed, stamped diskette mailer to me in care of Dr Dobb's Journal, 411 Borel Ave., San Mateo, CA 94402. I'll send you the latest version of D-Flat. The software is free, but if you'd care to. stuff a dollar bill in the mailer for the Brevard County Food Bank. They help the homeless and hungry. If you want to discuss DFlat with me, use CompuServe. My ID is 71101.1262, and I monitor the DDJ Forum daily.

D-Sharp?

We're almost to the end of the D-Flat project. There are three installments remaining that cover dialog boxes. message boxes, and the help system. Many of you have asked if I have a C++ version of D-Flat in the works. I had not considered such a project until recently. But now I think the time is right. Several major Ccompiler vendors now have C++ compilers integrated into their development environments. Microsoft's C++ compiler has been released. C++ is poised to dominate software development. Bjarne Stroustrup has been predicting that for years. Borland and Microsoft will make it happen.

The new project is in the planning stages, and it is forming into an interesting case study on how the event-driven, message-based architecture of DFlat maps onto the object-oriented class system of C++. No new ground is being broken here. There are a number of class libraries that implement the Windows user interface. They, however, must wrap the Windows message-based API into C++ classes. The next generation of D-Flat will implement the API with a class library. There are a number of design issues to address.

I do not expect the project to take as long as D-Flat has taken. Instead of publishing every line of code in monthly installments. I plan to address the problems and their solutions with extensive code examples along the way. Of course, the entire source-code package will be available, just as D-Flat is available now.

But what to call it? D-Flat++? Naw. If you increment the musical D-Flat note one whole tone, you get D-Sharp. Maybe. Any suggestions? No, I won't call it E

The Data Compression Book

Last year I published C programs in this column that implement the Huffman data-compression algorithms. D-Flat uses a variation on those programs to compress the help database. More recently, Dr. Dobb's ran the DDJ Data Compression Contest, where readers submitted their own data-compression programs. Mark Nelson refereed the contest and wrote about the results, and you can get the source code for the entrants from M&T Online and CompuServe. Now. Nelson has written a book about data compression called TheData Compression Book (M&T Books, 1991). M&T also publishes Dr. Dobb's, so I asked them to send me a free copy to review. They did, but would you believe that they sent me, their favorite C columnist, a rejected copy? It still had the reject sticker on it. The spine was crinkled a little bit from being at the hottom of the carton. I suspect. Didn't hurt the reading of it any, though. I'll bet they don't send Ray Duncan any damaged goods.

Data compression has always been a fascinating study for programmers and Nelson does justice to the subject. He covers many of the more popular compression algorithms and explains them well, including C code to implement them. The book includes a diskette with the code for the algorithms. He also provides a running history of data compression that adds dimension to the evolution of the technology.

I have often observed that those who write about Huffman, LZ77, LZ78, and LZW compression do not explain those algorithms well enough. You need to visualize what happens inside those processes to understand them, and nothing helps more than pictures. Many explanations try to do it with words alone. Nelson uses simple and effective graphs and C-code fragments to illustrate the compression and decompression steps for each of the algorithms. There is a delightful chapter on speech compression, and Nelson tops the book off with an archiving program in C that uses the LZSS algorithm and that you can integrate into your applications, extending it to add other compression algorithms if you want. This book is a good addition to your technical library, notwithstanding an odd acknowledgment of Robert X. Cringely, the pseudonym of an author that Ray Duncan generously associates with yellow journalism in the March "Programmer s Bookshelf."

There are three clues that Nelson wrote the book well before he published it. One is the use of the old-style K&R prototypes and function parameter blocks. He has included ANSI prototypes under the control of the

STDC__ compile-time variable, but the function declarations of some of the programs use the obsolete K&R style. Nelson attempts to justify this by implying that not everyone will be using ANSI compilers. but the book is inconsistent in this regard-other programs use ANSI function declarations. The second clue is his reference to Turbo C 1.0. The third clue is his use of the nod-eighties catch-phrase. "Where's the beef?" as a paragraph headed Come on, Mark. 23-Skidoo.



_C PROGRAMMING COLUMN_
by Al Stevens


[LISTING ONE]
<a name="0125_0009">

/* ------------- applicat.c ------------- */

#include "dflat.h"

static int ScreenHeight;
static BOOL AltDown = FALSE;

extern DBOX Display;
extern DBOX Windows;

#ifdef INCLUDE_LOGGING
extern DBOX Log;
#endif

#ifdef INCLUDE_SHELLDOS
static void ShellDOS(WINDOW);
#endif
static void CreateMenu(WINDOW);
static void CreateStatusBar(WINDOW);
static void SelectColors(WINDOW);
static void SetScreenHeight(int);
static void SelectLines(WINDOW);

#ifdef INCLUDE_WINDOWOPTIONS
static void SelectTexture(void);
static void SelectBorder(WINDOW);
static void SelectTitle(WINDOW);
static void SelectStatusBar(WINDOW);
#endif

#ifdef INCLUDE_MULTI_WINDOWS
static void CloseAll(WINDOW, int);
static void MoreWindows(WINDOW);
static void ChooseWindow(WINDOW, int);
static int WindowSel;
static WINDOW oldFocus;
static char *Menus[9] = {
    "~1.                      ",
    "~2.                      ",
    "~3.                      ",
    "~4.                      ",
    "~5.                      ",
    "~6.                      ",
    "~7.                      ",
    "~8.                      ",
    "~9.                      "
};
#endif

/* --------------- CREATE_WINDOW Message -------------- */
static int CreateWindowMsg(WINDOW wnd)
{
    int rtn;
    static BOOL DisplayModified = FALSE;
    ScreenHeight = SCREENHEIGHT;
    if (!isVGA() && !DisplayModified)    {
        /* ---- modify Display Dialog Box for EGA, CGA ---- */
        CTLWINDOW *ct, *ct1;
        int i;
        ct = FindCommand(&Display, ID_OK, BUTTON);
        if (isEGA())
            ct1 = FindCommand(&Display,ID_50LINES,RADIOBUTTON);
        else    {
            CTLWINDOW *ct2;
            ct2 = FindCommand(&Display,ID_COLOR,RADIOBUTTON)-1;
            ct2->dwnd.w++;
            for (i = 0; i < 7; i++)
                (ct2+i)->dwnd.x += 8;
            ct1 = FindCommand(&Display,ID_25LINES,RADIOBUTTON)-1;
        }
        for (i = 0; i < 4; i++)
            *ct1++ = *ct++;
        DisplayModified = TRUE;
    }
#ifdef INCLUDE_WINDOWOPTIONS
    if (cfg.Border)
        SetCheckBox(&Display, ID_BORDER);
    if (cfg.Title)
        SetCheckBox(&Display, ID_TITLE);
    if (cfg.StatusBar)
        SetCheckBox(&Display, ID_STATUSBAR);
    if (cfg.Texture)
        SetCheckBox(&Display, ID_TEXTURE);
#endif
    if (cfg.mono == 1)
        PushRadioButton(&Display, ID_MONO);
    else if (cfg.mono == 2)
        PushRadioButton(&Display, ID_REVERSE);
    else
        PushRadioButton(&Display, ID_COLOR);
    if (cfg.ScreenLines == 25)
        PushRadioButton(&Display, ID_25LINES);
    else if (cfg.ScreenLines == 43)
        PushRadioButton(&Display, ID_43LINES);
    else if (cfg.ScreenLines == 50)
        PushRadioButton(&Display, ID_50LINES);
    if (SCREENHEIGHT != cfg.ScreenLines)    {
        SetScreenHeight(cfg.ScreenLines);
        if (WindowHeight(wnd) == ScreenHeight ||
                SCREENHEIGHT-1 < GetBottom(wnd))    {
            WindowHeight(wnd) = SCREENHEIGHT-1;
            GetBottom(wnd) = GetTop(wnd)+WindowHeight(wnd)-1;
            wnd->RestoredRC = WindowRect(wnd);
        }
    }
    SelectColors(wnd);
#ifdef INCLUDE_WINDOWOPTIONS
    SelectBorder(wnd);
    SelectTitle(wnd);
    SelectStatusBar(wnd);
#endif
    rtn = BaseWndProc(APPLICATION, wnd, CREATE_WINDOW, 0, 0);
    if (wnd->extension != NULL)
        CreateMenu(wnd);
    CreateStatusBar(wnd);
    LoadHelpFile();
    SendMessage(NULL, SHOW_MOUSE, 0, 0);
    return rtn;
}

/* --------- ADDSTATUS Message ---------- */
static void AddStatusMsg(WINDOW wnd, PARAM p1)
{
    if (wnd->StatusBar != NULL)    {
        if (p1 && *(char *)p1)
            SendMessage(wnd->StatusBar, SETTEXT, p1, 0);
        else
            SendMessage(wnd->StatusBar, CLEARTEXT, 0, 0);
        SendMessage(wnd->StatusBar, PAINT, 0, 0);
    }
}

/* -------- SETFOCUS Message -------- */
static void SetFocusMsg(WINDOW wnd, BOOL p1)
{
    if (p1)
        SendMessage(inFocus, SETFOCUS, FALSE, 0);
    /* --- remove window from list --- */
    RemoveFocusWindow(wnd);
    /* --- move window to end/beginning of list --- */
    p1 ? AppendFocusWindow(wnd) : PrependFocusWindow(wnd);
    inFocus = p1 ? wnd : NULL;
    SendMessage(wnd, BORDER, 0, 0);
}

/* ------- SIZE Message -------- */
static void SizeMsg(WINDOW wnd, PARAM p1, PARAM p2)
{
    BOOL WasVisible;
    WasVisible = isVisible(wnd);
    if (WasVisible)
        SendMessage(wnd, HIDE_WINDOW, 0, 0);
    if (p1-GetLeft(wnd) < 30)
        p1 = GetLeft(wnd) + 30;
    BaseWndProc(APPLICATION, wnd, SIZE, p1, p2);
    CreateMenu(wnd);
    CreateStatusBar(wnd);
    if (WasVisible)
        SendMessage(wnd, SHOW_WINDOW, 0, 0);
}

/* ----------- KEYBOARD Message ------------ */
static int KeyboardMsg(WINDOW wnd, PARAM p1, PARAM p2)
{
    AltDown = FALSE;
    if (WindowMoving || WindowSizing || (int) p1 == F1)
        return BaseWndProc(APPLICATION, wnd, KEYBOARD, p1, p2);
    switch ((int) p1)    {
        case ALT_F4:
            PostMessage(wnd, CLOSE_WINDOW, 0, 0);
            return TRUE;
#ifdef INCLUDE_MULTI_WINDOWS
        case ALT_F6:
            SetNextFocus(inFocus);
            SkipSystemWindows(FALSE);
            return TRUE;
#endif
        case ALT_HYPHEN:
            BuildSystemMenu(wnd);
            return TRUE;
        default:
            break;
    }
    PostMessage(wnd->MenuBarWnd, KEYBOARD, p1, p2);
    return TRUE;
}

/* --------- SHIFT_CHANGED Message -------- */
static void ShiftChangedMsg(WINDOW wnd, PARAM p1)
{
    if ((int)p1 & ALTKEY)
        AltDown = TRUE;
    else if (AltDown)    {
        AltDown = FALSE;
        if (wnd->MenuBarWnd != inFocus)
            SendMessage(NULL, HIDE_CURSOR, 0, 0);
        SendMessage(wnd->MenuBarWnd, KEYBOARD, F10, 0);
    }
}

/* -------- COMMAND Message ------- */
static void CommandMsg(WINDOW wnd, PARAM p1, PARAM p2)
{
    switch ((int)p1)    {
        case ID_HELP:
            DisplayHelp(wnd, DFlatApplication);
            break;
        case ID_HELPHELP:
            DisplayHelp(wnd, "HelpHelp");
            break;
        case ID_EXTHELP:
            DisplayHelp(wnd, "ExtHelp");
            break;
        case ID_KEYSHELP:
            DisplayHelp(wnd, "KeysHelp");
            break;
        case ID_HELPINDEX:
            DisplayHelp(wnd, "HelpIndex");
            break;
#ifdef TESTING_DFLAT
        case ID_LOADHELP:
            LoadHelpFile();
            break;
#endif
#ifdef INCLUDE_LOGGING
        case ID_LOG:
            MessageLog(wnd);
            break;
#endif
#ifdef INCLUDE_SHELLDOS
        case ID_DOS:
            ShellDOS(wnd);
            break;
#endif
        case ID_EXIT:
        case ID_SYSCLOSE:
            PostMessage(wnd, CLOSE_WINDOW, 0, 0);
            break;
        case ID_DISPLAY:
            if (DialogBox(wnd, &Display, TRUE, NULL))    {
                SendMessage(wnd, HIDE_WINDOW, 0, 0);
                SelectColors(wnd);
                SelectLines(wnd);
#ifdef INCLUDE_WINDOWOPTIONS
                SelectBorder(wnd);
                SelectTitle(wnd);
                SelectStatusBar(wnd);
                SelectTexture();
#endif
                CreateMenu(wnd);
                CreateStatusBar(wnd);
                SendMessage(wnd, SHOW_WINDOW, 0, 0);
            }
            break;
        case ID_SAVEOPTIONS:
            SaveConfig();
            break;
#ifdef INCLUDE_MULTI_WINDOWS
        case ID_WINDOW:
            ChooseWindow(wnd, (int)p2-2);
            break;
        case ID_CLOSEALL:
            CloseAll(wnd, FALSE);
            break;
        case ID_MOREWINDOWS:
            MoreWindows(wnd);
            break;
#endif
#ifdef INCLUDE_RESTORE
        case ID_SYSRESTORE:
#endif
        case ID_SYSMOVE:
        case ID_SYSSIZE:
#ifdef INCLUDE_MINIMIZE
        case ID_SYSMINIMIZE:
#endif
#ifdef INCLUDE_MAXIMIZE
        case ID_SYSMAXIMIZE:
#endif
            BaseWndProc(APPLICATION, wnd, COMMAND, p1, p2);
            break;
        default:
            if (inFocus != wnd->MenuBarWnd && inFocus != wnd)
                PostMessage(inFocus, COMMAND, p1, p2);
            break;
    }
}

/* --------- CLOSE_WINDOW Message -------- */
static int CloseWindowMsg(WINDOW wnd)
{
    int rtn;
#ifdef INCLUDE_MULTI_WINDOWS
    CloseAll(wnd, TRUE);
#endif
    PostMessage(NULL, STOP, 0, 0);
    rtn = BaseWndProc(APPLICATION, wnd, CLOSE_WINDOW, 0, 0);
    if (ScreenHeight != SCREENHEIGHT)
        SetScreenHeight(ScreenHeight);
    UnLoadHelpFile();
    return rtn;
}

/* --- APPLICATION Window Class window processing module --- */
int ApplicationProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
{
    switch (msg)    {
        case CREATE_WINDOW:
            return CreateWindowMsg(wnd);
        case HIDE_WINDOW:
            if (wnd == inFocus)
                inFocus = NULL;
            break;
        case ADDSTATUS:
            AddStatusMsg(wnd, p1);
            return TRUE;
        case SETFOCUS:
            if ((int)p1 == (inFocus != wnd))    {
                SetFocusMsg(wnd, (BOOL) p1);
                return TRUE;
            }
            break;
        case SIZE:
            SizeMsg(wnd, p1, p2);
            return TRUE;
#ifdef INCLUDE_MINIMIZE
        case MINIMIZE:
            return TRUE;
#endif
        case KEYBOARD:
            return KeyboardMsg(wnd, p1, p2);
        case SHIFT_CHANGED:
            ShiftChangedMsg(wnd, p1);
            return TRUE;
        case PAINT:
            if (isVisible(wnd))    {
#ifdef INCLUDE_WINDOWOPTIONS
                int cl = cfg.Texture ? APPLCHAR : ' ';
#else
                int cl = APPLCHAR;
#endif
                ClearWindow(wnd, (RECT *)p1, cl);
            }
            return TRUE;
        case COMMAND:
            CommandMsg(wnd, p1, p2);
            return TRUE;
        case CLOSE_WINDOW:
            return CloseWindowMsg(wnd);
        default:
            break;
    }
    return BaseWndProc(APPLICATION, wnd, msg, p1, p2);
}

#ifdef INCLUDE_SHELLDOS
static void SwitchCursor(void)
{
    SendMessage(NULL, SAVE_CURSOR, 0, 0);
    SwapCursorStack();
    SendMessage(NULL, RESTORE_CURSOR, 0, 0);
}

/* ------- Shell out to DOS ---------- */
static void ShellDOS(WINDOW wnd)
{
    SendMessage(wnd, HIDE_WINDOW, 0, 0);
    SwitchCursor();
    if (ScreenHeight != SCREENHEIGHT)
        SetScreenHeight(ScreenHeight);
    SendMessage(NULL, HIDE_MOUSE, 0, 0);
    printf("To return to %s, execute the DOS exit command.",
                    DFlatApplication);
    fflush(stdout);
    spawnl(P_WAIT, getenv("COMSPEC"), NULL);
    if (SCREENHEIGHT != cfg.ScreenLines)
        SetScreenHeight(cfg.ScreenLines);
    SwitchCursor();
    SendMessage(wnd, SHOW_WINDOW, 0, 0);
    SendMessage(NULL, SHOW_MOUSE, 0, 0);
}
#endif

/* -------- Create the menu bar -------- */
static void CreateMenu(WINDOW wnd)
{
    AddAttribute(wnd, HASMENUBAR);
    if (wnd->MenuBarWnd != NULL)
        SendMessage(wnd->MenuBarWnd, CLOSE_WINDOW, 0, 0);
    wnd->MenuBarWnd = CreateWindow(MENUBAR,
                        NULL,
                        GetClientLeft(wnd),
                        GetClientTop(wnd)-1,
                        1,
                        ClientWidth(wnd),
                        NULL,
                        wnd,
                        NULL,
                        0);
    SendMessage(wnd->MenuBarWnd,BUILDMENU,
        (PARAM)wnd->extension,0);
    AddAttribute(wnd->MenuBarWnd, VISIBLE);
}

/* ----------- Create the status bar ------------- */
static void CreateStatusBar(WINDOW wnd)
{
    if (wnd->StatusBar != NULL)    {
        SendMessage(wnd->StatusBar, CLOSE_WINDOW, 0, 0);
        wnd->StatusBar = NULL;
    }
    if (TestAttribute(wnd, HASSTATUSBAR))    {
        wnd->StatusBar = CreateWindow(STATUSBAR,
                            NULL,
                            GetClientLeft(wnd),
                            GetBottom(wnd),
                            1,
                            ClientWidth(wnd),
                            NULL,
                            wnd,
                            NULL,
                            0);
        AddAttribute(wnd->StatusBar, VISIBLE);
    }
}

#ifdef INCLUDE_MULTI_WINDOWS
/* -------- return the name of a document window ------- */
static char *WindowName(WINDOW wnd)
{
    if (GetTitle(wnd) == NULL)    {
        if (GetClass(wnd) == DIALOG)
            return ((DBOX *)(wnd->extension))->HelpName;
        else
            return "Untitled";
    }
    else
        return GetTitle(wnd);
}

/* ----------- Prepare the Window menu ------------ */
void PrepWindowMenu(void *w, struct Menu *mnu)
{
    WINDOW wnd = w;
    struct PopDown *p0 = mnu->Selections;
    struct PopDown *pd = mnu->Selections + 2;
    struct PopDown *ca = mnu->Selections + 13;
    int MenuNo = 0;
    WINDOW cwnd;
    mnu->Selection = 0;
    oldFocus = NULL;
    if (GetClass(wnd) != APPLICATION)    {
        int i;
        oldFocus = wnd;
        /* ----- point to the APPLICATION window ----- */
        while (GetClass(wnd) != APPLICATION)
            if ((wnd = GetParent(wnd)) == NULL)
                return;
        /* ----- get the first 9 document windows ----- */
        for (i = 0; i < wnd->ChildCt && MenuNo < 9; i++)    {
            cwnd = *(wnd->Children + i);
            if (GetClass(cwnd) != MENUBAR &&
                    GetClass(cwnd) != STATUSBAR) {
                /* --- add the document window to the menu --- */
                strncpy(Menus[MenuNo]+4, WindowName(cwnd), 20);
                pd->SelectionTitle = Menus[MenuNo];
                if (cwnd == oldFocus)    {
                    /* -- mark the current document -- */
                    pd->Attrib |= CHECKED;
                    mnu->Selection = MenuNo+2;
                }
                else
                    pd->Attrib &= ~CHECKED;
                pd++;
                MenuNo++;
            }
        }
    }
    if (MenuNo)
        p0->SelectionTitle = "~Close all";
    else
        p0->SelectionTitle = NULL;
    if (MenuNo >= 9)    {
        *pd++ = *ca;
        if (mnu->Selection == 0)
            mnu->Selection = 11;
    }
    pd->SelectionTitle = NULL;
}

/* window processing module for the More Windows dialog box */
static int WindowPrep(WINDOW wnd,MESSAGE msg,PARAM p1,PARAM p2)
{
    switch (msg)    {
        case INITIATE_DIALOG:    {
            WINDOW wnd1;
            WINDOW cwnd = ControlWindow(&Windows,ID_WINDOWLIST);
            WINDOW pwnd = GetParent(wnd);
            int sel = 0, i;
            if (cwnd == NULL)
                return FALSE;
            for (i = 0; i < pwnd->ChildCt; i++)    {
                wnd1 = *(pwnd->Children + i);
                if (wnd1 != wnd && GetClass(wnd1) != MENUBAR &&
                        GetClass(wnd1) != STATUSBAR)    {
                    if (wnd1 == oldFocus)
                        WindowSel = sel;
                    SendMessage(cwnd, ADDTEXT,
                        (PARAM) WindowName(wnd1), 0);
                    sel++;
                }
            }
            SendMessage(cwnd, LB_SETSELECTION, WindowSel, 0);
            AddAttribute(cwnd, VSCROLLBAR);
            PostMessage(cwnd, SHOW_WINDOW, 0, 0);
            break;
        }
        case COMMAND:
            switch ((int) p1)    {
                case ID_OK:
                    if ((int)p2 == 0)
                        WindowSel = SendMessage(
                                    ControlWindow(&Windows,
                                    ID_WINDOWLIST),
                                    LB_CURRENTSELECTION, 0, 0);
                    break;
                case ID_WINDOWLIST:
                    if ((int) p2 == LB_CHOOSE)
                        SendMessage(wnd, COMMAND, ID_OK, 0);
                    break;
                default:
                    break;
            }
            break;
        default:
            break;
    }
    return DefaultWndProc(wnd, msg, p1, p2);
}

/* ---- the More Windows command on the Window menu ---- */
static void MoreWindows(WINDOW wnd)
{
    if (DialogBox(wnd, &Windows, TRUE, WindowPrep))
        ChooseWindow(wnd, WindowSel);
}

/* ----- user chose a window from the Window menu
        or the More Window dialog box ----- */
static void ChooseWindow(WINDOW wnd, int WindowNo)
{
    int i;
    WINDOW cwnd;
    for (i = 0; i < wnd->ChildCt; i++)    {
        cwnd = *(wnd->Children + i);
        if (GetClass(cwnd) != MENUBAR &&
                GetClass(cwnd) != STATUSBAR)
            if (WindowNo-- == 0)
                break;
    }
    if (wnd->ChildCt)    {
        SendMessage(cwnd, SETFOCUS, TRUE, 0);
        if (cwnd->condition == ISMINIMIZED)
            SendMessage(cwnd, RESTORE, 0, 0);
    }
}

/* ----- Close all document windows ----- */
static void CloseAll(WINDOW wnd, int closing)
{
    WINDOW wnd1;
    int i;
    SendMessage(wnd, SETFOCUS, TRUE, 0);
    for (i = wnd->ChildCt; i > 0; --i)    {
        wnd1 = *(wnd->Children + i - 1);
        if (GetClass(wnd1) != MENUBAR &&
                GetClass(wnd1) != STATUSBAR)    {
            ClearVisible(wnd1);
            SendMessage(wnd1, CLOSE_WINDOW, 0, 0);
        }
    }
    if (!closing)
        SendMessage(wnd, PAINT, 0, 0);
}

#endif    /* #ifdef INCLUDE_MULTI_WINDOWS */

static void DoWindowColors(WINDOW wnd)
{
    WINDOW cwnd;
    int i;
    InitWindowColors(wnd);
    for (i = 0; i < wnd->ChildCt; i++)    {
        cwnd = *(wnd->Children + i);
        InitWindowColors(cwnd);
        if (GetClass(cwnd) == TEXT && GetText(cwnd) != NULL)
            SendMessage(cwnd, CLEARTEXT, 0, 0);
    }
}

/* ----- set up colors for the application window ------ */
static void SelectColors(WINDOW wnd)
{
    if (RadioButtonSetting(&Display, ID_MONO))
        cfg.mono = 1;
    else if (RadioButtonSetting(&Display, ID_REVERSE))
        cfg.mono = 2;
    else
        cfg.mono = 0;
    if ((ismono() || video_mode == 2) && cfg.mono == 0)
        cfg.mono = 1;

    if (cfg.mono == 1)
        memcpy(cfg.clr, bw, sizeof bw);
    else if (cfg.mono == 2)
        memcpy(cfg.clr, reverse, sizeof reverse);
    else
        memcpy(cfg.clr, color, sizeof color);
    DoWindowColors(wnd);
}

/* ---- select screen lines ---- */
static void SelectLines(WINDOW wnd)
{
    cfg.ScreenLines = 25;
    if (isEGA() || isVGA())    {
        if (RadioButtonSetting(&Display, ID_43LINES))
            cfg.ScreenLines = 43;
        else if (RadioButtonSetting(&Display, ID_50LINES))
            cfg.ScreenLines = 50;
    }
    if (SCREENHEIGHT != cfg.ScreenLines)    {
        int FullScreen = WindowHeight(wnd) == SCREENHEIGHT;
        SetScreenHeight(cfg.ScreenLines);
        if (FullScreen || SCREENHEIGHT-1 < GetBottom(wnd))
            SendMessage(wnd, SIZE, (PARAM) GetRight(wnd),
                SCREENHEIGHT-1);
    }
}

/* ---- set the screen height in the video hardware ---- */
static void SetScreenHeight(int height)
{
    if (isEGA() || isVGA())    {
        SendMessage(NULL, SAVE_CURSOR, 0, 0);
        switch (height)    {
            case 25:
                Set25();
                break;
            case 43:
                Set43();
                break;
            case 50:
                Set50();
                break;
            default:
                break;
        }
        SendMessage(NULL, RESTORE_CURSOR, 0, 0);
        SendMessage(NULL, RESET_MOUSE, 0, 0);
        SendMessage(NULL, SHOW_MOUSE, 0, 0);
    }
}

#ifdef INCLUDE_WINDOWOPTIONS

/* ----- select the screen texture ----- */
static void SelectTexture(void)
{
    cfg.Texture = CheckBoxSetting(&Display, ID_TEXTURE);
}

/* -- select whether the application screen has a border -- */
static void SelectBorder(WINDOW wnd)
{
    cfg.Border = CheckBoxSetting(&Display, ID_BORDER);
    if (cfg.Border)
        AddAttribute(wnd, HASBORDER);
    else
        ClearAttribute(wnd, HASBORDER);
}

/* select whether the application screen has a status bar */
static void SelectStatusBar(WINDOW wnd)
{
    cfg.StatusBar = CheckBoxSetting(&Display, ID_STATUSBAR);
    if (cfg.StatusBar)
        AddAttribute(wnd, HASSTATUSBAR);
    else
        ClearAttribute(wnd, HASSTATUSBAR);
}

/* select whether the application screen has a title bar */
static void SelectTitle(WINDOW wnd)
{
    cfg.Title = CheckBoxSetting(&Display, ID_TITLE);
    if (cfg.Title)
        AddAttribute(wnd, HASTITLEBAR);
    else
        ClearAttribute(wnd, HASTITLEBAR);
}

#endif


Copyright © 1992, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.