home *** CD-ROM | disk | FTP | other *** search
- /* @(#)winlib.c 1.1 8/27/96 */
-
- /******************************************************************************
- * WinLib: a simple Windows 95 GUI library *
- * (C) Copyright 1996 by Philip Stephens *
- * (C) Copyright 1996 by the IBM Corporation *
- * All Rights Reserved *
- * *
- * Permission to use, copy, modify, and distribute this software and its *
- * documentation without fee for any non-commerical purpose is hereby granted, *
- * provided that the above copyright notice appears on all copies and that *
- * both that copyright notice and this permission notice appear in all *
- * supporting documentation. *
- * *
- * NO REPRESENTATIONS ARE MADE ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY *
- * PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. *
- * NEITHER PHILIP STEPHENS OR IBM SHALL BE LIABLE FOR ANY DAMAGES SUFFERED BY *
- * THE USE OF THIS SOFTWARE. *
- ******************************************************************************/
-
- #define STRICT
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <windowsx.h>
- #include <commdlg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include "winlib.h"
-
- /*
- * I don't want to hear warnings about unused parameters or local variables in
- * functions.
- */
- #pragma warn -aus
- #pragma warn -par
-
- /*
- * Type definition of a window node.
- */
- typedef struct window_node {
- HWND window_handle;
- event_callbacks *callback_list;
- WNDPROC default_window_proc;
- struct window_node *next_window_node;
- } window_node;
-
- /*
- * Window list.
- */
- static window_node *window_list;
-
- /*
- * Application instance.
- */
- static HINSTANCE instance_handle;
-
- /***********************************************************************
- * Function to add a window and it's callback list to the window list. *
- ***********************************************************************/
-
- static BOOL
- AddWindowToList(HWND window_handle, event_callbacks *callback_list,
- WNDPROC default_window_proc)
- {
- window_node *window_node_ptr;
-
- if ((window_node_ptr = (window_node *)malloc(sizeof(window_node)))
- == NULL) {
- MessageBox(NULL, "Unable to add window to event handler list",
- "Fatal Error", MB_OK);
- return(FALSE);
- }
- window_node_ptr->window_handle = window_handle;
- window_node_ptr->callback_list = callback_list;
- window_node_ptr->default_window_proc = default_window_proc;
- window_node_ptr->next_window_node = window_list;
- window_list = window_node_ptr;
- return(TRUE);
- }
-
- /***************************************************
- * Function to locate a window in the window list. *
- ***************************************************/
-
- static window_node *
- FindWindowInList(HWND window_handle)
- {
- window_node *window_node_ptr;
-
- window_node_ptr = window_list;
- while (window_node_ptr) {
- if (window_node_ptr->window_handle == window_handle)
- return(window_node_ptr);
- window_node_ptr = window_node_ptr->next_window_node;
- }
- return(NULL);
- }
-
- /*************************************************************************
- * Function to handle events by looking up the window in the window list, *
- * and executing the approapiate callback function for that window. *
- **************************************************************************/
-
- /*
- * Macro to do what HANDLE_MSG does, except for adding a case
- * switch and asking for the window parameter.
- */
- #define MY_HANDLE_MSG(message, fn) \
- return(HANDLE_##message((window_handle), (wparam), (lparam), (fn)))
-
- /*
- * Macro to pass a button message to a handler along with the message type,
- * so that we can handle button events all in one function. Note that if
- * the application wishes to forward a button message, they'll need to
- * use a switch statement so that they can use the existing FORWARD macros in
- * windowsx.h
- */
- #define MY_HANDLE_WM_BUTTON(message, fn) \
- return(((fn)((window_handle), (message), (int)LOWORD(lparam), \
- (int)HIWORD(lparam), (UINT)(wparam)), 0L))
-
- LRESULT CALLBACK
- HandleEvent(HWND window_handle, UINT message, WPARAM wparam, LPARAM lparam)
- {
- window_node *window_node_ptr;
- WNDPROC default_window_proc;
- event_callbacks *callback_list;
-
- /*
- * The default window procedure is DefWindowProc().
- */
- default_window_proc = DefWindowProc;
-
- /*
- * Check if we can handle the event using a function in the window's
- * callback list. Note that we don't handle WM_CREATE messages
- * here because the window hasn't been added to the window list yet.
- * Instead, we explicitly call the window create function when the
- * window is being created.
- */
- if ((window_node_ptr = FindWindowInList(window_handle)) != NULL) {
- default_window_proc = window_node_ptr->default_window_proc;
- callback_list = window_node_ptr->callback_list;
- switch(message) {
- case WM_DESTROY:
- if (callback_list->destroy_fn)
- MY_HANDLE_MSG(WM_DESTROY,
- callback_list->destroy_fn);
- break;
- case WM_PAINT:
- if (callback_list->paint_fn)
- MY_HANDLE_MSG(WM_PAINT,
- callback_list->paint_fn);
- break;
- case WM_CHAR:
- if (callback_list->char_fn)
- MY_HANDLE_MSG(WM_CHAR, callback_list->char_fn);
- break;
- case WM_KEYUP:
- if (callback_list->key_fn)
- MY_HANDLE_MSG(WM_KEYUP, callback_list->key_fn);
- break;
- case WM_KEYDOWN:
- if (callback_list->key_fn)
- MY_HANDLE_MSG(WM_KEYDOWN,
- callback_list->key_fn);
- break;
- case WM_LBUTTONDOWN:
- case WM_MBUTTONDOWN:
- case WM_RBUTTONDOWN:
- case WM_LBUTTONUP:
- case WM_MBUTTONUP:
- case WM_RBUTTONUP:
- case WM_LBUTTONDBLCLK:
- case WM_MBUTTONDBLCLK:
- case WM_RBUTTONDBLCLK:
- if (callback_list->button_fn)
- MY_HANDLE_WM_BUTTON(message,
- callback_list->button_fn);
- break;
- case WM_MOUSEMOVE:
- if (callback_list->mouse_fn)
- MY_HANDLE_MSG(WM_MOUSEMOVE,
- callback_list->mouse_fn);
- break;
- case WM_QUERYNEWPALETTE:
- if (callback_list->focus_fn)
- MY_HANDLE_MSG(WM_QUERYNEWPALETTE,
- callback_list->focus_fn);
- break;
- case WM_COMMAND:
- if (callback_list->command_fn)
- MY_HANDLE_MSG(WM_COMMAND,
- callback_list->command_fn);
- break;
- }
- }
-
- /*
- * If all else fails, call the default window procedure.
- */
- return(CallWindowProc(default_window_proc, window_handle, message,
- wparam, lparam));
- }
-
- /***************************************
- * Function to initialise the library. *
- ***************************************/
-
- void
- WinLibInit(HINSTANCE instance)
- {
- WNDCLASS window_class;
-
- /*
- * Initialise the window list and instance handle.
- */
- window_list = NULL;
- instance_handle = instance;
-
- /*
- * Define the main window class.
- */
- window_class.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
- window_class.lpfnWndProc = DefWindowProc;
- window_class.cbClsExtra = 0;
- window_class.cbWndExtra = 0;
- window_class.hInstance = instance_handle;
- window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
- window_class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- window_class.lpszMenuName = NULL;
- window_class.lpszClassName = "MainWindow";
-
- /*
- * Register the main window class.
- */
- if (!RegisterClass(&window_class)) {
- MessageBox(NULL, "Unable to register main window class",
- "Fatal Error", MB_OK | MB_ICONEXCLAMATION);
- return;
- }
-
- /*
- * Define the child window class.
- */
- window_class.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
- window_class.lpfnWndProc = DefWindowProc;
- window_class.cbClsExtra = 0;
- window_class.cbWndExtra = 0;
- window_class.hInstance = instance_handle;
- window_class.hIcon = NULL;
- window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
- window_class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- window_class.lpszMenuName = NULL;
- window_class.lpszClassName = "ChildWindow";
-
- /*
- * Register the child window class.
- */
- if (!RegisterClass(&window_class)) {
- MessageBox(NULL, "Unable to register child window class",
- "Fatal Error", MB_OK | MB_ICONEXCLAMATION);
- return;
- }
- }
-
- /*****************************************************
- * Function to clean up the library data structures. *
- *****************************************************/
-
- void
- WinLibCleanUp(void)
- {
- window_node *window_node_ptr;
-
- while (window_list) {
- window_node_ptr = window_list->next_window_node;
- free(window_list);
- window_list = window_node_ptr;
- }
- }
-
- /********************************************
- * Function to create a window of any sort. *
- ********************************************/
-
- static HWND
- CreateNewWindow(LPCSTR window_class, LPCSTR window_title, UINT window_style,
- UINT x, UINT y, UINT window_width, UINT window_height,
- HWND parent_window_handle, HMENU menu_handle,
- event_callbacks *callback_list)
- {
- HWND window_handle;
-
- /*
- * Create the window.
- */
- window_handle = CreateWindow(window_class, window_title, window_style,
- x, y, window_width, window_height,
- parent_window_handle, menu_handle,
- instance_handle, NULL);
- if (!window_handle) {
- MessageBox(NULL, "Unable to create a window", "Fatal Error",
- MB_OK | MB_ICONEXCLAMATION);
- return(NULL);
- }
-
- /*
- * If a callback list was provided, override the default window procedure
- * with HandleEvent() and add the control to the window list, then call
- * the create callback function.
- */
- if (callback_list) {
- WNDPROC def_window_proc;
-
- def_window_proc = (WNDPROC)SetWindowLong(window_handle,
- GWL_WNDPROC,
- (LONG)HandleEvent);
- if (!AddWindowToList(window_handle, callback_list,
- def_window_proc)) {
- (void)SetWindowLong(window_handle, GWL_WNDPROC,
- (LONG)def_window_proc);
- return(NULL);
- }
- if (callback_list->create_fn)
- callback_list->create_fn(window_handle);
- }
-
- /*
- * Return the handle to the new window.
- */
- return(window_handle);
- }
-
- /****************************************************
- * Function to register and create the main window. *
- ****************************************************/
-
- HWND
- CreateMainWindow(LPCSTR window_title, UINT window_width, UINT window_height,
- UINT window_state, LPCSTR menu_name,
- event_callbacks *callback_list)
- {
- HWND window_handle;
- HMENU menu_handle;
-
- /*
- * Load the menu from the resource file if a menu name was given.
- */
- if (menu_name) {
- menu_handle = LoadMenu(instance_handle, menu_name);
- if (!menu_handle) {
- MessageBox(NULL, "Unable to load main window menu",
- "Fatal Error", MB_OK | MB_ICONEXCLAMATION);
- return(NULL);
- }
- } else
- menu_handle = NULL;
-
- /*
- * Create the main window.
- */
- window_handle = CreateNewWindow("MainWindow", window_title,
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, CW_USEDEFAULT,
- window_width, window_height, NULL,
- menu_handle, callback_list);
-
- /*
- * Make the main window visible and generate a WM_PAINT event.
- */
- ShowWindow(window_handle, window_state);
- UpdateWindow(window_handle);
- return(window_handle);
- }
-
- /**********************************************
- * Function to create a generic child window. *
- **********************************************/
-
- HWND
- CreateChildWindow(HWND parent_window_handle, UINT x, UINT y,
- UINT window_width, UINT window_height, UINT window_style,
- event_callbacks *callback_list)
- {
- HWND child_handle;
-
- /*
- * Create the child window.
- */
- child_handle = CreateNewWindow("ChildWindow", NULL,
- WS_CHILD | WS_VISIBLE | window_style,
- x, y, window_width, window_height,
- parent_window_handle, NULL,
- callback_list);
-
- /*
- * Return the handle to the child window.
- */
- return(child_handle);
- }
-
- /****************************************
- * Function to create a static control. *
- ****************************************/
-
- HWND
- CreateStaticControl(HWND parent_window_handle, UINT x, UINT y,
- UINT window_width, UINT window_height, UINT window_style,
- event_callbacks *callback_list)
- {
- HWND child_handle;
-
- /*
- * Create the static control.
- */
- child_handle = CreateNewWindow("static", NULL,
- WS_CHILD | WS_VISIBLE | window_style,
- x, y, window_width, window_height,
- parent_window_handle, NULL,
- callback_list);
-
- /*
- * Return the handle to the static control.
- */
- return(child_handle);
- }
-
- /***************************************
- * Function to create an edit control. *
- ***************************************/
-
- HWND
- CreateEditControl(HWND parent_window_handle, UINT x, UINT y,
- UINT window_width, UINT window_height, UINT window_style,
- event_callbacks *callback_list)
- {
- HWND child_handle;
-
- /*
- * Create the edit control window.
- */
- child_handle = CreateNewWindow("edit", NULL,
- WS_CHILD | WS_VISIBLE | WS_VSCROLL |
- ES_LEFT | ES_MULTILINE | window_style,
- x, y, window_width, window_height,
- parent_window_handle, NULL,
- callback_list);
-
- /*
- * Return the handle to the control window.
- */
- return(child_handle);
- }
-
- /*************************************************************************
- * Function to create a bitmap that can be displayed in a child window *
- * very quickly. Note that the window must be of class ChildWindow as *
- * it must have a style of CS_OWNDC, otherwise the chosen colour palette *
- * won't be correctly installed whenever the window gets input focus. *
- *************************************************************************/
-
- fast_bitmap *
- CreateFastBitmap(HWND window_handle, UINT width, UINT height, RGBQUAD *palette,
- UINT colours, UINT offset)
- {
- HDC dc = GetDC(window_handle);
- fast_bitmap *bitmap_ptr;
- BITMAPINFOHEADER *bitmap_header;
- RGBQUAD *bitmap_palette;
- PALETTEENTRY *window_palette;
- PALETTEENTRY system_palette[256];
- int index;
-
- /*
- * Allocate a fast bitmap structure.
- */
- bitmap_ptr = (fast_bitmap *)malloc(sizeof(fast_bitmap));
- bitmap_ptr->window_handle = window_handle;
- bitmap_ptr->bitmap_info = (BITMAPINFO *)malloc(sizeof(BITMAPINFO) +
- 255 * sizeof(RGBQUAD));
- bitmap_ptr->palette_info = (LOGPALETTE *)malloc(sizeof(LOGPALETTE) +
- 255 *
- sizeof(PALETTEENTRY));
-
- /*
- * Fill in the bitmap info header.
- */
- bitmap_header = &bitmap_ptr->bitmap_info->bmiHeader;
- bitmap_header->biSize = sizeof(BITMAPINFOHEADER);
- bitmap_header->biWidth = width;
- bitmap_header->biHeight = -height; /* top-down bitmap */
- bitmap_header->biPlanes = 1;
- bitmap_header->biBitCount = 8;
- bitmap_header->biCompression = BI_RGB;
- bitmap_header->biSizeImage = NULL;
- bitmap_header->biXPelsPerMeter = NULL;
- bitmap_header->biYPelsPerMeter = NULL;
- bitmap_header->biClrUsed = 256;
- bitmap_header->biClrImportant = 256;
-
- /*
- * Retrieve the palette entries from the system palette.
- */
- GetSystemPaletteEntries(dc, 0, 256, (PALETTEENTRY *)&system_palette);
-
- /*
- * Fill in the bitmap palette entries. The first and last 10 entries
- * are taken from the system palette, to ensure no colour remapping is
- * done by Windows or the BitBlt function.
- */
- bitmap_palette = (RGBQUAD *)&bitmap_ptr->bitmap_info->bmiColors;
- for (index = 0; index < 10; index++) {
- bitmap_palette[index].rgbRed = system_palette[index].peRed;
- bitmap_palette[index].rgbGreen = system_palette[index].peGreen;
- bitmap_palette[index].rgbBlue = system_palette[index].peBlue;
- }
- for (index = offset; index < offset + colours; index++)
- bitmap_palette[index] = palette[index];
- for (index = 246; index < 256; index++) {
- bitmap_palette[index].rgbRed = system_palette[index].peRed;
- bitmap_palette[index].rgbGreen = system_palette[index].peGreen;
- bitmap_palette[index].rgbBlue = system_palette[index].peBlue;
- }
-
- /*
- * Fill in the window palette entries. Once again, the first and last 10
- * entries come from the system palette, with the remaining 236 entries
- * from the requested palette. We set the PC_NOCOLLAPSE flag to ensure
- * Windows doesn't try to remap any of the requested colours.
- */
- bitmap_ptr->palette_info->palVersion = 0x300;
- bitmap_ptr->palette_info->palNumEntries = 256;
- window_palette = (PALETTEENTRY *)&bitmap_ptr->palette_info->palPalEntry;
- for (index = 0; index < 10; index++)
- window_palette[index] = system_palette[index];
- for (index = offset; index < offset + colours; index++) {
- window_palette[index].peRed = palette[index].rgbRed;
- window_palette[index].peGreen = palette[index].rgbGreen;
- window_palette[index].peBlue = palette[index].rgbBlue;
- window_palette[index].peFlags = PC_NOCOLLAPSE;
- }
- for (index = 246; index < 256; index++)
- window_palette[index] = system_palette[index];
-
- /*
- * Create the logical palette.
- */
- bitmap_ptr->palette_handle = CreatePalette(bitmap_ptr->palette_info);
-
- /*
- * Create the bitmap.
- */
- bitmap_ptr->bitmap_handle = CreateDIBSection(dc,
- bitmap_ptr->bitmap_info,
- DIB_RGB_COLORS,
- (void **)&bitmap_ptr->bits,
- NULL, NULL);
-
- /*
- * Release the window DC and return the fast bitmap pointer.
- */
- ReleaseDC(window_handle, dc);
- return(bitmap_ptr);
- }
-
- /**************************
- * Destroy a fast bitmap. *
- **************************/
-
- void
- DestroyFastBitmap(fast_bitmap *bitmap_ptr)
- {
- free(bitmap_ptr->bitmap_info);
- free(bitmap_ptr->palette_info);
- DeleteObject(bitmap_ptr->bitmap_handle);
- DeleteObject(bitmap_ptr->palette_handle);
- free(bitmap_ptr);
- }
-
- /**************************
- * Display a fast bitmap. *
- **************************/
-
- void
- DisplayFastBitmap(fast_bitmap *bitmap_ptr)
- {
- HDC dc = GetDC(bitmap_ptr->window_handle);
- HDC newdc = CreateCompatibleDC(NULL);
- RECT dest;
- HBITMAP prev_bitmap;
-
- GetClientRect(bitmap_ptr->window_handle, &dest);
- prev_bitmap = SelectBitmap(newdc, bitmap_ptr->bitmap_handle);
- BitBlt(dc, 0, 0, dest.right - dest.left, dest.bottom - dest.top, newdc,
- 0, 0, SRCCOPY);
- (void)SelectBitmap(newdc, prev_bitmap);
- DeleteDC(newdc);
- ReleaseDC(bitmap_ptr->window_handle, dc);
- }
-
- /******************************************************
- * Install the palette associated with a fast bitmap. *
- ******************************************************/
-
- BOOL
- InstallFastBitmapPalette(fast_bitmap *bitmap_ptr)
- {
- HDC dc;
- UINT entries_changed;
-
- /*
- * Realize the bitmap palette in the bitmap window.
- */
- dc = GetDC(bitmap_ptr->window_handle);
- (void)SelectPalette(dc, bitmap_ptr->palette_handle, FALSE);
- UnrealizeObject(bitmap_ptr->palette_handle);
- entries_changed = RealizePalette(dc);
- ReleaseDC(bitmap_ptr->window_handle, dc);
-
- /*
- * If any palette entries changed, repaint the bitmap window.
- */
- if (entries_changed > 0)
- InvalidateRect(bitmap_ptr->window_handle, NULL, TRUE);
- return(entries_changed);
- }
-
- /*****************************************************************************
- * Function to display text in an edit control. Normally used for read-only *
- * edit controls. *
- *****************************************************************************/
-
- void
- DisplayMessage(HWND edit_handle, char *format, ...)
- {
- va_list arg_ptr;
- char message[1024];
-
- va_start(arg_ptr, format);
- vsprintf(message, format, arg_ptr);
- va_end(arg_ptr);
-
- SendMessage(edit_handle, EM_REPLACESEL, 0, (LPARAM)message);
- }
-
- /**********************************************
- * Function to implement the main event loop. *
- **********************************************/
-
- void
- EnterEventLoop(void (*work_proc_ptr)(void))
- {
- MSG message;
-
- for (;;) {
- while (!PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE))
- (*work_proc_ptr)();
- if (!GetMessage(&message, NULL, 0, 0))
- break;
- TranslateMessage(&message);
- DispatchMessage(&message);
- }
- }
-
- /*************************************************************************
- * Display an Open File dialog box and return the user's file selection. *
- *************************************************************************/
-
- char *
- OpenFileDialog(char *title, char *filter)
- {
- OPENFILENAME file_struct;
- static char file_name[256];
-
- *file_name = '\0';
- memset(&file_struct, 0, sizeof(OPENFILENAME));
- file_struct.lStructSize = sizeof(OPENFILENAME);
- file_struct.hInstance = instance_handle;
- file_struct.lpstrFilter = filter;
- file_struct.lpstrFile = file_name;
- file_struct.nMaxFile = 256;
- file_struct.lpstrTitle = title;
- file_struct.Flags = OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON |
- OFN_HIDEREADONLY;
- if (GetOpenFileName(&file_struct))
- return((char *)file_name);
- return(NULL);
- }
-