//
// mxToolKit (c) 1999 by Mete Ciragan
//
// file: mx.cpp
// implementation: Win32 API
// last modified: Apr 18 1999, Mete Ciragan
// copyright: The programs and associated files contained in this
// distribution were developed by Mete Ciragan. The programs
// are not in the public domain, but they are freely
// distributable without licensing fees. These programs are
// provided without guarantee or warrantee expressed or
// implied.
//
#include <mx/mx.h>
#include <mx/mxWindow.h>
#include <mx/mxEvent.h>
#include <mx/mxLinkedList.h>
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tier1/UtlVector.h"
#define WM_MOUSEWHEEL 0x020A
//#include <ostream.h>
void mxTab_resizeChild (HWND hwnd);
mxWindow *g_mainWindow = 0;
static mxLinkedList *g_widgetList = 0;
static mxWindow *g_idleWindow = 0;
static MSG msg;
static HWND g_hwndToolTipControl = 0;
static bool isClosing = false;
static HACCEL g_hAcceleratorTable = NULL;
void mx::createAccleratorTable( int numentries, Accel_t *entries )
{
CUtlVector< ACCEL > accelentries;
for ( int i = 0; i < numentries; ++i )
{
const Accel_t& entry = entries[ i ];
ACCEL add;
add.key = entry.key;
add.cmd = entry.command;
add.fVirt = 0;
if ( entry.flags & ACCEL_ALT )
{
add.fVirt |= FALT;
}
if ( entry.flags & ACCEL_CONTROL )
{
add.fVirt |= FCONTROL;
}
if ( entry.flags & ACCEL_SHIFT )
{
add.fVirt |= FSHIFT;
}
if ( entry.flags & ACCEL_VIRTKEY )
{
add.fVirt |= FVIRTKEY;
}
accelentries.AddToTail( add );
}
g_hAcceleratorTable = ::CreateAcceleratorTable( accelentries.Base(), accelentries.Count() );
}
void
mx_addWidget (mxWidget *widget)
{
if (g_widgetList)
g_widgetList->add ((void *) widget);
}
void
mx_removeWidget (mxWidget *widget)
{
if (g_widgetList)
g_widgetList->remove ((void *) widget);
}
HWND
mx_CreateToolTipControl ()
{
if (!g_hwndToolTipControl)
{
if (g_mainWindow)
{
g_hwndToolTipControl = CreateWindowEx (0, TOOLTIPS_CLASS, "", WS_POPUP | WS_EX_TOPMOST,
0, 0, 0, 0, (HWND) g_mainWindow->getHandle (),
(HMENU) NULL, (HINSTANCE) GetModuleHandle (NULL), NULL);
}
}
return g_hwndToolTipControl;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *window -
// *event -
// Output : static void
//-----------------------------------------------------------------------------
static void RecursiveHandleEvent( mxWindow *window, mxEvent *event )
{
while ( window )
{
if ( window->handleEvent ( event ) )
break;
window = window->getParent();
}
}
char const *translatecode( int code )
{
switch ( code )
{
case NM_CLICK:
return "NM_CLICK";
case NM_CUSTOMDRAW:
return "NM_CUSTOMDRAW";
case NM_DBLCLK:
return "NM_DBLCLK";
case NM_KILLFOCUS:
return "NM_KILLFOCUS";
case NM_RCLICK:
return "NM_RCLICK";
case NM_RETURN:
return "NM_RETURN";
case NM_SETCURSOR:
return "NM_SETCURSOR";
case NM_SETFOCUS:
return "NM_SETFOCUS";
case TVN_BEGINDRAG:
return "TVN_BEGINDRAG";
case TVN_BEGINLABELEDIT:
return "TVN_BEGINLABELEDIT";
case TVN_BEGINRDRAG:
return "TVN_BEGINRDRAG";
case TVN_DELETEITEM:
return "TVN_DELETEITEM";
case TVN_ENDLABELEDIT:
return "TVN_ENDLABELEDIT";
case TVN_GETDISPINFO:
return "TVN_GETDISPINFO";
case TVN_GETINFOTIP:
return "TVN_GETINFOTIP";
case TVN_ITEMEXPANDED:
return "TVN_ITEMEXPANDED";
case TVN_ITEMEXPANDING:
return "TVN_ITEMEXPANDING";
case TVN_KEYDOWN :
return "TVN_KEYDOWN";
case TVN_SELCHANGED :
return "TVN_SELCHANGED";
case TVN_SELCHANGING :
return "TVN_SELCHANGING";
case TVN_SETDISPINFO :
return "TVN_SETDISPINFO";
case TVN_SINGLEEXPAND:
return "TVN_SINGLEEXPAND";
}
return "Unknown!!!";
}
static LRESULT CALLBACK WndProc (HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
static bool bDragging = FALSE;
switch (uMessage)
{
case WM_SETFOCUS:
case WM_KILLFOCUS:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if ( window )
{
mxEvent event;
event.event = mxEvent::Focus;
event.widget = NULL;
event.action = (uMessage == WM_SETFOCUS);
RecursiveHandleEvent( window, &event );
return 0;
}
}
break;
case WM_ACTIVATE:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if ( window )
{
mxEvent event;
event.event = mxEvent::Activate;
event.widget = NULL;
event.action = (LOWORD( wParam ) != WA_INACTIVE);
RecursiveHandleEvent( window, &event );
return 0;
}
}
break;
case WM_COMMAND:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (LOWORD (wParam) > 0 && window)
{
WORD wNotifyCode = (WORD) HIWORD (wParam);
HWND hwndCtrl = (HWND) lParam;
mxEvent event;
CHAR className[128];
GetClassName (hwndCtrl, className, 128);
if (!strcmpi (className, "edit"))
{
if (wNotifyCode != EN_CHANGE)
break;
}
else if (!strcmpi (className, "combobox"))
{
if (wNotifyCode != CBN_SELCHANGE)
break;
}
else if (!strcmpi (className, "listbox"))
{
if (wNotifyCode != LBN_SELCHANGE)
break;
}
event.event = mxEvent::Action;
event.widget = (mxWidget *) GetWindowLong ((HWND) lParam, GWL_USERDATA);
event.action = (int) LOWORD (wParam);
RecursiveHandleEvent( window, &event );
}
}
break;
case WM_NOTIFY:
{
if (isClosing)
break;
NMHDR *nmhdr = (NMHDR *) lParam;
mxEvent event;
#if 0
//if ( nmhdr->idFrom > 0 )
{
mxWidget *temp = (mxWidget *) GetWindowLong (nmhdr->hwndFrom, GWL_USERDATA);
if ( temp && temp->getType() == MX_TREEVIEW )
{
NMTREEVIEW *nmt = ( NMTREEVIEW * )nmhdr;
HTREEITEM hItem = TreeView_GetSelection (nmhdr->hwndFrom);
char sz[ 256 ];
sprintf( sz, "tree view receiving notify %i : %s action %i old %p new %p selection %p\n", nmhdr->code, translatecode( nmhdr->code ),
nmt->action, nmt->itemOld, nmt->itemNew, hItem );
OutputDebugString( sz );
}
}
#endif
if (nmhdr->code == TVN_SELCHANGED)
{
if (nmhdr->idFrom > 0)
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
event.event = mxEvent::Action;
event.widget = (mxWidget *) GetWindowLong (nmhdr->hwndFrom, GWL_USERDATA);
event.action = (int) nmhdr->idFrom;
RECT rc;
HTREEITEM hItem = TreeView_GetSelection (nmhdr->hwndFrom);
TreeView_GetItemRect (nmhdr->hwndFrom, hItem, &rc, TRUE);
event.x = (int) rc.left;
event.y = (int) rc.bottom;
RecursiveHandleEvent( window, &event );
}
}
else if (nmhdr->code == LVN_ITEMCHANGED)
{
if (nmhdr->idFrom > 0)
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
event.event = mxEvent::Action;
event.widget = (mxWidget *) GetWindowLong (nmhdr->hwndFrom, GWL_USERDATA);
event.action = (int) nmhdr->idFrom;
RecursiveHandleEvent( window, &event );
}
}
else if (nmhdr->code == NM_RCLICK)
{
if (nmhdr->idFrom > 0)
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
event.event = mxEvent::Action;
event.widget = (mxWidget *) GetWindowLong (nmhdr->hwndFrom, GWL_USERDATA);
event.action = (int) nmhdr->idFrom;
event.flags = mxEvent::RightClicked;
if ( event.widget )
{
if ( event.widget->getType () == MX_TREEVIEW )
{
RECT rc;
HTREEITEM hItem = TreeView_GetSelection (nmhdr->hwndFrom);
TreeView_GetItemRect (nmhdr->hwndFrom, hItem, &rc, TRUE);
event.x = (int) rc.left;
event.y = (int) rc.bottom;
}
}
RecursiveHandleEvent( window, &event );
}
}
else if (nmhdr->code == NM_DBLCLK)
{
if (nmhdr->idFrom > 0)
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
event.event = mxEvent::Action;
event.widget = (mxWidget *) GetWindowLong (nmhdr->hwndFrom, GWL_USERDATA);
event.action = (int) nmhdr->idFrom;
event.flags = mxEvent::DoubleClicked;
if (event.widget )
{
if ( event.widget->getType () == MX_TREEVIEW )
{
RECT rc;
HTREEITEM hItem = TreeView_GetSelection (nmhdr->hwndFrom);
TreeView_GetItemRect (nmhdr->hwndFrom, hItem, &rc, TRUE);
event.x = (int) rc.left;
event.y = (int) rc.bottom;
}
}
RecursiveHandleEvent( window, &event );
return TRUE;
}
}
else if (nmhdr->code == TCN_SELCHANGING)
{
TC_ITEM ti;
int index = TabCtrl_GetCurSel (nmhdr->hwndFrom);
if (index >= 0)
{
ti.mask = TCIF_PARAM;
TabCtrl_GetItem (nmhdr->hwndFrom, index, &ti);
mxWindow *window = (mxWindow *) ti.lParam;
if (window)
window->setVisible (false);
}
}
else if (nmhdr->code == TCN_SELCHANGE)
{
mxTab_resizeChild (nmhdr->hwndFrom);
if (nmhdr->idFrom > 0)
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
event.event = mxEvent::Action;
event.widget = (mxWidget *) GetWindowLong (nmhdr->hwndFrom, GWL_USERDATA);
event.action = (int) nmhdr->idFrom;
RecursiveHandleEvent( window, &event );
}
}
}
break;
case WM_SIZE:
{
mxEvent event;
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
event.event = mxEvent::Size;
event.width = (int) LOWORD (lParam);
event.height = (int) HIWORD (lParam);
window->handleEvent (&event);
}
}
break;
case WM_WINDOWPOSCHANGED:
{
mxEvent event;
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
event.event = mxEvent::PosChanged;
WINDOWPOS *wp = ( WINDOWPOS * )lParam;
event.x = wp->x;
event.y = wp->y;
event.width = wp->cx;
event.height = wp->cy;
window->handleEvent (&event);
}
}
break;
case WM_ERASEBKGND:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
if (window->getType () == MX_GLWINDOW)
return 0;
if (window->getType () == MX_MATSYSWINDOW)
return 0;
if ( !isClosing && !window->PaintBackground() )
{
return 0;
}
}
}
break;
case WM_HSCROLL:
case WM_VSCROLL:
{
mxWidget *widget = (mxWidget *) GetWindowLong ((HWND) lParam, GWL_USERDATA);
if (!widget)
{
break;
}
if (widget->getType() != MX_SCROLLBAR && widget->getType() != MX_SLIDER)
{
break;
}
switch (LOWORD (wParam))
{
case TB_LINEUP: // SB_LINEUP SB_LINELEFT
break;
case TB_LINEDOWN: // SB_LINEDOWN SB_LINERIGHT
break;
case TB_PAGEUP: // SB_PAGEUP SB_PAGELEFT
break;
case TB_PAGEDOWN: // SB_PAGEDOWN SB_PAGERIGHT
break;
case TB_THUMBPOSITION: // SB_THUMBPOSITION
break;
case TB_THUMBTRACK: // SB_THUMBTRACK
break;
case TB_TOP: // SB_TOP SB_LEFT
break;
case TB_BOTTOM: // SB_BOTTOM SB_RIGHT
break;
case TB_ENDTRACK: // SB_ENDSCROLL
break;
default:
break;
}
switch (LOWORD (wParam))
{
case TB_LINEUP: // SB_LINEUP SB_LINELEFT
case TB_LINEDOWN: // SB_LINEDOWN SB_LINERIGHT
case TB_PAGEUP: // SB_PAGEUP SB_PAGELEFT
case TB_PAGEDOWN: // SB_PAGEDOWN SB_PAGERIGHT
case TB_THUMBPOSITION: // SB_THUMBPOSITION
case TB_THUMBTRACK: // SB_THUMBTRACK
case TB_TOP: // SB_TOP SB_LEFT
case TB_BOTTOM: // SB_BOTTOM SB_RIGHT
case TB_ENDTRACK: // SB_ENDSCROLL
{
mxEvent event;
event.event = mxEvent::Action;
event.widget = widget;
event.action = widget->getId ();
event.modifiers = LOWORD (wParam);
event.height = HIWORD( wParam );
mxWindow *window = widget->getParent ();
if ( event.action > 0 )
{
RecursiveHandleEvent( window, &event );
}
}
break;
}
}
break;
case WM_PAINT:
{
if ( !isClosing )
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
window->redraw ();
}
}
}
break;
case WM_PARENTNOTIFY:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
if ( wParam == WM_LBUTTONDOWN ||
wParam == WM_MBUTTONDOWN ||
wParam == WM_RBUTTONDOWN /*||
wParam & WM_XBUTTONDOWN*/ )
{
mxEvent event;
event.event = mxEvent::ParentNotify;
event.x = (short)LOWORD (lParam);
event.y = (short)HIWORD (lParam);
event.buttons = 0;
event.modifiers = 0;
if ( wParam == WM_LBUTTONDOWN )
event.buttons |= mxEvent::MouseLeftButton;
if ( wParam == WM_RBUTTONDOWN )
event.buttons |= mxEvent::MouseRightButton;
if ( wParam == WM_MBUTTONDOWN )
event.buttons |= mxEvent::MouseMiddleButton;
window->handleEvent (&event);
RecursiveHandleEvent( window, &event );
return 0;
}
}
}
break;
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
{
bDragging = TRUE;
SetCapture (hwnd);
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::MouseDown;
event.x = (short)LOWORD (lParam);
event.y = (short)HIWORD (lParam);
event.buttons = 0;
event.modifiers = 0;
if (uMessage == WM_MBUTTONDOWN)
event.buttons |= mxEvent::MouseMiddleButton;
else if (uMessage == WM_RBUTTONDOWN)
event.buttons |= mxEvent::MouseRightButton;
else
event.buttons |= mxEvent::MouseLeftButton;
if (wParam & MK_LBUTTON)
event.buttons |= mxEvent::MouseLeftButton;
if (wParam & MK_RBUTTON)
event.buttons |= mxEvent::MouseRightButton;
if (wParam & MK_MBUTTON)
event.buttons |= mxEvent::MouseMiddleButton;
if (wParam & MK_CONTROL)
event.modifiers |= mxEvent::KeyCtrl;
if (wParam & MK_SHIFT)
event.modifiers |= mxEvent::KeyShift;
window->handleEvent (&event);
}
}
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::MouseUp;
event.x = (short) LOWORD (lParam);
event.y = (short) HIWORD (lParam);
event.buttons = 0;
event.modifiers = 0;
if (uMessage == WM_MBUTTONUP)
event.buttons |= mxEvent::MouseMiddleButton;
else if (uMessage == WM_RBUTTONUP)
event.buttons |= mxEvent::MouseRightButton;
else
event.buttons |= mxEvent::MouseLeftButton;
if (wParam & MK_LBUTTON)
event.buttons |= mxEvent::MouseLeftButton;
if (wParam & MK_RBUTTON)
event.buttons |= mxEvent::MouseRightButton;
if (wParam & MK_MBUTTON)
event.buttons |= mxEvent::MouseMiddleButton;
if (wParam & MK_CONTROL)
event.modifiers |= mxEvent::KeyCtrl;
if (wParam & MK_SHIFT)
event.modifiers |= mxEvent::KeyShift;
window->handleEvent (&event);
}
bDragging = FALSE;
ReleaseCapture ();
}
break;
case WM_MOUSEMOVE:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
if (bDragging)
event.event = mxEvent::MouseDrag;
else
event.event = mxEvent::MouseMove;
event.x = (short) LOWORD (lParam);
event.y = (short) HIWORD (lParam);
event.buttons = 0;
event.modifiers = 0;
if (wParam & MK_LBUTTON)
event.buttons |= mxEvent::MouseLeftButton;
if (wParam & MK_RBUTTON)
event.buttons |= mxEvent::MouseRightButton;
if (wParam & MK_MBUTTON)
event.buttons |= mxEvent::MouseMiddleButton;
if (wParam & MK_CONTROL)
event.modifiers |= mxEvent::KeyCtrl;
if (wParam & MK_SHIFT)
event.modifiers |= mxEvent::KeyShift;
window->handleEvent (&event);
}
}
break;
case WM_NCLBUTTONDOWN:
case WM_NCMBUTTONDOWN:
case WM_NCRBUTTONDOWN:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::NCMouseDown;
event.x = (short) LOWORD (lParam);
event.y = (short) HIWORD (lParam);
event.buttons = 0;
event.modifiers = 0;
if (uMessage == WM_NCMBUTTONDOWN)
event.buttons |= mxEvent::MouseMiddleButton;
else if (uMessage == WM_NCRBUTTONDOWN)
event.buttons |= mxEvent::MouseRightButton;
else
event.buttons |= mxEvent::MouseLeftButton;
window->handleEvent (&event);
}
}
break;
case WM_NCLBUTTONUP:
case WM_NCMBUTTONUP:
case WM_NCRBUTTONUP:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::NCMouseUp;
event.x = (short) LOWORD (lParam);
event.y = (short) HIWORD (lParam);
event.buttons = 0;
event.modifiers = 0;
if (uMessage == WM_NCMBUTTONUP)
event.buttons |= mxEvent::MouseMiddleButton;
else if (uMessage == WM_NCRBUTTONUP)
event.buttons |= mxEvent::MouseRightButton;
else
event.buttons |= mxEvent::MouseLeftButton;
window->handleEvent (&event);
}
}
break;
case WM_NCMOUSEMOVE:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::NCMouseMove;
event.x = (short) LOWORD (lParam);
event.y = (short) HIWORD (lParam);
event.buttons = 0;
event.modifiers = 0;
window->handleEvent (&event);
}
}
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::KeyDown;
event.key = (int) wParam;
if ( window->handleEvent (&event) )
return 0;
}
}
break;
case WM_CHAR:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::Char;
event.key = (int) wParam;
if ( window->handleEvent (&event) )
return 0;
}
}
break;
case WM_SYSCHAR:
return 0;
break;
case WM_KEYUP:
case WM_SYSKEYUP:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::KeyUp;
event.key = (int) wParam;
if ( window->handleEvent (&event) )
return 0;
}
}
break;
case WM_MOUSEWHEEL:
{
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
memset( &event, 0, sizeof( event ) );
event.event = mxEvent::MouseWheeled;
event.x = (short) LOWORD (lParam);
event.y = (short) HIWORD (lParam);
if (wParam & MK_LBUTTON)
event.buttons |= mxEvent::MouseLeftButton;
if (wParam & MK_RBUTTON)
event.buttons |= mxEvent::MouseRightButton;
if (wParam & MK_MBUTTON)
event.buttons |= mxEvent::MouseMiddleButton;
if (wParam & MK_CONTROL)
event.modifiers |= mxEvent::KeyCtrl;
if (wParam & MK_SHIFT)
event.modifiers |= mxEvent::KeyShift;
event.height = (short)HIWORD( wParam );;
RecursiveHandleEvent( window, &event );
}
}
break;
case WM_TIMER:
{
if (isClosing)
break;
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::Timer;
window->handleEvent (&event);
}
}
break;
case WM_CLOSE:
if (g_mainWindow)
{
if ((void *) hwnd == g_mainWindow->getHandle ())
{
mx::quit ();
}
else
{
ShowWindow (hwnd, SW_HIDE);
mxWindow *window = (mxWindow *) GetWindowLong (hwnd, GWL_USERDATA);
if (window)
{
mxEvent event;
event.event = mxEvent::Close;
window->handleEvent( &event );
}
}
}
//else // shouldn't happen
//DestroyWindow (hwnd);
return 0;
/*
case WM_DESTROY:
if (g_mainWindow)
{
if ((void *) hwnd == g_mainWindow->getHandle ())
mx::quit ();
}
break;
*/
}
return DefWindowProc (hwnd, uMessage, wParam, lParam);
}
int
mx::init(int argc, char **argv)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = (HINSTANCE) GetModuleHandle (NULL);
wc.hIcon = LoadIcon (wc.hInstance, "MX_ICON");
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
wc.lpszMenuName = NULL;
wc.lpszClassName = "mx_class";
if (!wc.hIcon)
wc.hIcon = LoadIcon (NULL, IDI_WINLOGO);
if (!RegisterClass (&wc))
return 0;
InitCommonControls ();
g_widgetList = new mxLinkedList ();
isClosing = false;
return 1;
}
int
mx::run()
{
int messagecount = 0;
while (1)
{
bool doframe = false;
if ( PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE) || !g_idleWindow )
{
if (!GetMessage (&msg, NULL, 0, 0))
{
doframe = false;
break;
}
if ( !g_hAcceleratorTable ||
!TranslateAccelerator( (HWND)g_mainWindow->getHandle (), g_hAcceleratorTable, &msg ))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
messagecount++;
if ( messagecount > 10 )
{
messagecount = 0;
doframe = true;
}
}
else if (g_idleWindow)
{
doframe = true;
messagecount = 0;
}
if ( doframe && g_idleWindow )
{
mxEvent event;
event.event = mxEvent::Idle;
g_idleWindow->handleEvent (&event);
}
}
return msg.wParam;
}
int
mx::check ()
{
if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return 1;
}
return 0;
}
void
mx::quit ()
{
isClosing = true;
mxWindow *mainwnd = getMainWindow();
if ( mainwnd )
{
if ( !mainwnd->Closing() )
{
isClosing = false;
return;
}
}
if (g_widgetList)
{
// remove from back to front
mxListNode *node = g_widgetList->getLast ();
// Pass 1, see if anyone objects to closing
while (node)
{
mxWidget *widget = (mxWidget *) g_widgetList->getData (node);
node = g_widgetList->getPrev (node);
bool canclose = true;
if ( widget )
{
if ( !widget->CanClose() )
{
canclose = false;
}
}
if ( !canclose )
{
isClosing = false;
return;
}
}
node = g_widgetList->getLast ();
// Pass 2, call OnDelete to allow final cleanup
while (node)
{
mxWidget *widget = (mxWidget *) g_widgetList->getData (node);
node = g_widgetList->getPrev (node);
if ( widget )
{
widget->OnDelete();
}
}
node = g_widgetList->getLast ();
// Pass 3, delete stuff
while (node)
{
mxWidget *widget = (mxWidget *) g_widgetList->getData (node);
node = g_widgetList->getPrev (node);
// remove it!
if ( widget )
{
delete widget;
}
}
delete g_widgetList;
}
if (g_hwndToolTipControl)
DestroyWindow (g_hwndToolTipControl);
if ( g_hAcceleratorTable )
{
DestroyAcceleratorTable( g_hAcceleratorTable );
g_hAcceleratorTable = 0;
}
PostQuitMessage (0);
UnregisterClass ("mx_class", (HINSTANCE) GetModuleHandle (NULL));
}
int
mx::setDisplayMode (int w, int h, int bpp)
{
DEVMODE dm;
dm.dmSize = sizeof (DEVMODE);
dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
dm.dmBitsPerPel = bpp;
dm.dmPelsWidth = w;
dm.dmPelsHeight = h;
if (w == 0 || h == 0 || bpp == 0)
ChangeDisplaySettings (0, 0);
else
ChangeDisplaySettings (&dm, CDS_FULLSCREEN);
return 0;
}
void
mx::setIdleWindow (mxWindow *window)
{
g_idleWindow = window;
}
int
mx::getDisplayWidth ()
{
return (int) GetSystemMetrics (SM_CXSCREEN);
}
int
mx::getDisplayHeight ()
{
return (int) GetSystemMetrics (SM_CYSCREEN);
}
mxWindow*
mx::getMainWindow ()
{
return g_mainWindow;
}
const char *
mx::getApplicationPath ()
{
static char path[256];
GetModuleFileName (0, path, 256);
char *ptr = strrchr (path, '\\');
if (ptr)
*ptr = '\0';
return path;
}
int
mx::getTickCount ()
{
return (int) GetTickCount ();
}