#include "win32\win32guts.h"
#ifndef _APRICOT_H_
#include "apricot.h"
#endif
#include "guts.h"
#include "Window.h"
#include "Application.h"
#include "Menu.h"
#ifdef __cplusplus
extern "C" {
#endif
#define sys (( PDrawableData)(( PComponent) self)-> sysData)->
#define dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
#define var (( PWidget) self)->
#define HANDLE sys handle
#define DHANDLE(x) dsys(x) handle
// #define FONT_CHECK
WinGuts guts;
DWORD rc;
PHash stylusMan = nil; // pen & brush manager
PHash fontMan = nil; // font manager
PHash patMan = nil; // pattern resource manager
PHash menuMan = nil; // HMENU manager
PHash imageMan = nil; // HBITMAP manager
PHash regnodeMan = nil; // cache for apc_widget_user_profile
PHash myfontMan = nil; // hash of calls to apc_font_load
HPEN hPenHollow;
HBRUSH hBrushHollow;
PatResource hPatHollow;
DIBMONOBRUSH bmiHatch = {
{ sizeof( BITMAPINFOHEADER), 8, 8, 1, 1, BI_RGB, 0, 0, 0, 2, 2},
{{0,0,0,0}, {0,0,0,0}}
};
int FONTSTRUCSIZE;
Handle lastMouseOver = nilHandle;
MusClkRec musClk = {0};
char * keyLayouts[] = { "0409", "0403", "0405", "0406", "0407",
"0807","0809","080A","080C","0C0C","100C","0810","0814","0816",
"040A","040B","040C","040E","040F","0410","0413","0414","0415","0416",
"0417","0418","041A","041D"
};
WCHAR lastDeadKey = 0;
Bool debug = false;
BOOL APIENTRY
DllMain( HINSTANCE hInstance, DWORD reason, LPVOID reserved)
{
if ( reason == DLL_PROCESS_ATTACH) {
memset( &guts, 0, sizeof( guts));
guts. instance = hInstance;
guts. cmdShow = SW_SHOWDEFAULT;
}
return TRUE;
}
Bool
window_subsystem_init( char * error_buf)
{
WNDCLASSW wc;
HDC dc;
HBITMAP hbm;
OSVERSIONINFO os = { sizeof( OSVERSIONINFO)};
guts. version = GetVersion();
GetVersionEx( &os);
guts. utf8_prepend_0x202D =
(( os.dwMajorVersion > 5) || (os.dwMajorVersion == 5 && os.dwMinorVersion > 1)) ?
1 : 0;
guts. alloc_utf8_to_wchar_visual =
guts. utf8_prepend_0x202D ?
alloc_utf8_to_wchar_visual :
alloc_utf8_to_wchar;
guts. mainThreadId = GetCurrentThreadId();
guts. errorMode = SetErrorMode( SEM_FAILCRITICALERRORS);
guts. desktopWindow = GetDesktopWindow();
memset( &wc, 0, sizeof( wc));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = ( WNDPROC) generic_app_handler;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = guts. instance;
wc.hIcon = LoadIcon( guts. instance, IDI_APPLICATION);
wc.hCursor = LoadCursor( NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)NULL;
wc.lpszClassName = L"GenericApp";
RegisterClassW( &wc);
memset( &wc, 0, sizeof( wc));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = ( WNDPROC) generic_frame_handler;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = guts. instance;
wc.hIcon = LoadIcon( guts. instance, IDI_APPLICATION);
wc.hCursor = LoadCursor( NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)NULL;
wc.lpszClassName = L"GenericFrame";
RegisterClassW( &wc);
memset( &wc, 0, sizeof( wc));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = ( WNDPROC) layered_frame_handler;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = guts. instance;
wc.hIcon = LoadIcon( guts. instance, IDI_APPLICATION);
wc.hCursor = LoadCursor( NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)NULL;
wc.lpszClassName = L"LayeredFrame";
RegisterClassW( &wc);
memset( &wc, 0, sizeof( wc));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = ( WNDPROC) generic_view_handler;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = guts. instance;
wc.hIcon = LoadIcon( guts. instance, IDI_APPLICATION);
wc.hCursor = NULL; // LoadCursor( NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)NULL;
wc.lpszClassName = L"Generic";
RegisterClassW( &wc);
stylusMan = hash_create();
fontMan = hash_create();
patMan = hash_create();
menuMan = hash_create();
imageMan = hash_create();
regnodeMan = hash_create();
myfontMan = hash_create();
create_font_hash();
{
LOGBRUSH b = { BS_HOLLOW, 0, 0};
Font f;
hPenHollow = CreatePen( PS_NULL, 0, 0);
hBrushHollow = CreateBrushIndirect( &b);
hPatHollow. dotsCount = 0;
hPatHollow. dotsPtr = nil;
FONTSTRUCSIZE = (char *)(&(f. name)) - (char *)(&f);
}
if (!( dc = dc_alloc())) return false;
guts. displayResolution. x = GetDeviceCaps( dc, LOGPIXELSX);
guts. displayResolution. y = GetDeviceCaps( dc, LOGPIXELSY);
{
LOGFONT lf;
HFONT sfont;
// getting most common font name
memset( &lf, 0, sizeof( lf));
lf. lfCharSet = OEM_CHARSET;
lf. lfOutPrecision = OUT_DEFAULT_PRECIS;
lf. lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf. lfQuality = PROOF_QUALITY;
lf. lfPitchAndFamily = DEFAULT_PITCH;
sfont = SelectObject( dc, CreateFontIndirect( &lf));
GetTextFace( dc, 256, guts. defaultSystemFont);
// getting common fixed font name
lf. lfHeight = 320;
lf. lfPitchAndFamily = FIXED_PITCH;
DeleteObject( SelectObject( dc, CreateFontIndirect( &lf)));
GetTextFace( dc, 256, guts. defaultFixedFont);
// getting common variable font name
lf. lfPitchAndFamily = VARIABLE_PITCH;
DeleteObject( SelectObject( dc, CreateFontIndirect( &lf)));
GetTextFace( dc, 256, guts. defaultVariableFont);
DeleteObject( SelectObject( dc, sfont));
// getting system font presets
memset( &guts. windowFont, 0, sizeof( Font));
strcpy( guts. windowFont. name, DEFAULT_WIDGET_FONT);
guts. windowFont. size = DEFAULT_WIDGET_FONT_SIZE;
guts. windowFont. width = guts. windowFont. height = C_NUMERIC_UNDEF;
#ifdef FONT_CHECK
guts. windowFont. size = 12;
#endif
apc_font_pick( nilHandle, &guts. windowFont, &guts. windowFont);
guts. ncmData. cbSize = sizeof( NONCLIENTMETRICS);
SystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof( NONCLIENTMETRICS),
( PVOID) &guts. ncmData, 0);
font_logfont2font( &guts. ncmData. lfMenuFont, &guts. menuFont, &guts. displayResolution);
font_logfont2font( &guts. ncmData. lfMessageFont, &guts. msgFont, &guts. displayResolution);
font_logfont2font( &guts. ncmData. lfCaptionFont, &guts. capFont, &guts. displayResolution);
}
memset( &guts. displayBMInfo, 0, sizeof( guts. displayBMInfo));
guts. displayBMInfo. bmiHeader. biSize = sizeof( BITMAPINFO);
if ( !( hbm = GetCurrentObject( dc, OBJ_BITMAP))) {
apiErr;
dc_free();
return false;
}
if ( !GetDIBits( dc, hbm, 0, 0, NULL, &guts. displayBMInfo, DIB_PAL_COLORS)) {
guts. displayBMInfo. bmiHeader. biBitCount = GetDeviceCaps( dc, BITSPIXEL);
guts. displayBMInfo. bmiHeader. biPlanes = GetDeviceCaps( dc, PLANES);
}
dc_free();
guts. insertMode = true;
guts. iconSizeSmall. x = GetSystemMetrics( SM_CXSMICON);
guts. iconSizeSmall. y = GetSystemMetrics( SM_CYSMICON);
guts. iconSizeLarge. x = GetSystemMetrics( SM_CXICON);
guts. iconSizeLarge. y = GetSystemMetrics( SM_CYICON);
guts. pointerSize. x = GetSystemMetrics( SM_CXCURSOR);
guts. pointerSize. y = GetSystemMetrics( SM_CYCURSOR);
list_create( &guts. transp, 8, 8);
list_create( &guts. files, 8, 8);
list_create( &guts. sockets, 8, 8);
// selecting locale layout, more or less latin-like
{
char buf[ KL_NAMELENGTH * 2] = "";
HKL current = GetKeyboardLayout( 0);
int i, j, size = GetKeyboardLayoutList( 0, nil);
HKL * kl = ( HKL *) malloc( sizeof( HKL) * size);
guts. keyLayout = nil;
if ( !GetKeyboardLayoutName( buf)) apiErr;
for ( j = 0; j < ( sizeof( keyLayouts) / sizeof( char*)); j++) {
if ( strncmp( buf + 4, keyLayouts[ j], 4) == 0) {
guts. keyLayout = current;
goto found_1;
}
}
if ( kl) {
GetKeyboardLayoutList( size, kl);
for ( i = 0; i < size; i++) {
ActivateKeyboardLayout( kl[ i], 0);
if ( !GetKeyboardLayoutName( buf)) apiErr;
for ( j = 0; j < ( sizeof( keyLayouts) / sizeof( char*)); j++) {
if ( strncmp( buf + 4, keyLayouts[ j], 4) == 0) {
guts. keyLayout = kl[ i];
goto found_2;
}
}
}
found_2:;
ActivateKeyboardLayout( current, 0);
}
found_1:;
free( kl);
}
guts. currentKeyState = guts. keyState;
memset( guts. emptyKeyState, 0, sizeof( guts. emptyKeyState));
guts. smDblClk. x = GetSystemMetrics( SM_CXDOUBLECLK);
guts. smDblClk. y = GetSystemMetrics( SM_CYDOUBLECLK);
return true;
}
Bool
window_subsystem_get_options( int * argc, char *** argv)
{
static char * win32_argv[] = {
"debug", "turns on debugging"
};
*argv = win32_argv;
*argc = sizeof( win32_argv) / sizeof( char*);
return true;
}
Bool
window_subsystem_set_option( char * option, char * value)
{
if ( strcmp( option, "debug") == 0) {
debug = value ? *value != '0' : true;
return true;
}
return false;
}
static Bool myfont_cleaner( void * value, int keyLen, void * key, void * dummy) {
RemoveFontResource((LPCTSTR)key);
return false;
}
void
window_subsystem_done()
{
list_destroy( &guts. files);
if ( guts. socketMutex) {
// appDead must be TRUE for this moment!
appDead = true;
CloseHandle( guts. socketMutex);
}
list_destroy( &guts. sockets);
list_destroy( &guts. transp);
destroy_font_hash();
font_clean();
stylus_clean();
hash_destroy( imageMan, false);
hash_destroy( menuMan, false);
hash_destroy( patMan, true);
hash_destroy( fontMan, true);
hash_destroy( stylusMan, true);
hash_destroy( regnodeMan, false);
hash_first_that( myfontMan, myfont_cleaner, nil, nil, nil);
hash_destroy( myfontMan, false);
DeleteObject( hPenHollow);
DeleteObject( hBrushHollow);
SetErrorMode( guts. errorMode);
}
void
window_subsystem_cleanup()
{
while ( guts. appLock > 0) apc_application_unlock( application);
while ( guts. pointerLock < 0) {
ShowCursor( 1);
guts. pointerLock++;
}
}
static char err_buf[ 256] = "";
char * err_msg( DWORD errId, char * buffer)
{
LPVOID lpMsgBuf;
int len;
if ( buffer == nil) buffer = err_buf;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errId,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
( LPTSTR) &lpMsgBuf, 0, NULL);
if ( lpMsgBuf)
strncpy( buffer, ( const char *) lpMsgBuf, 256);
else
buffer[0] = 0;
buffer[ 255] = 0;
LocalFree( lpMsgBuf);
/* chomp! */
len = strlen(buffer);
while ( len > 0) {
len--;
if ( buffer[len] != '\xD' && buffer[len] != '\xA' && buffer[len] != '.')
break;
buffer[len] = 0;
}
return buffer;
}
char *
apc_last_error(void)
{
switch (apcError) {
case errApcError : return err_buf;
case errOk : return NULL;
case errInvObject : return "Bad object";
case errInvParams : return "Bad parameters";
case errInvWindowIcon : return "Bad window icon";
case errInvClipboardData : return "Bad clipboard request";
case errInvPrinter : return "Bad printer request";
case errNoPrinters : return "No printers";
case errUserCancelled : return "User cancelled";
default : return "Unknown error";
}
}
static Bool move_back( PWidget self, PWidget child, int * delta)
{
RECT r;
int oStage = child-> stage;
if ( !dsys( child) options. aptClipOwner) return false;
child-> stage = csFrozen;
GetWindowRect( DHANDLE( child), &r);
if ( dsys( child) options. aptClipOwner)
MapWindowPoints( NULL, ( HWND) self-> handle, ( LPPOINT)&r, 2);
SetWindowPos( DHANDLE( child), 0, r. left, r. top + *delta, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
child-> stage = oStage;
return false;
}
static Bool
local_wnd( HWND who, HWND client)
{
PComponent v;
Handle self;
if ( who == client)
return true;
self = GetWindowLongPtr( client, GWLP_USERDATA);
v = (PComponent) hwnd_to_view( who);
while (v && ( Handle) v != application)
{
if ( (Handle)v == self) return true;
v = ( PComponent) ( v-> owner);
}
return false;
}
extern Handle ctx_kb2VK[];
extern Handle ctx_kb2VK2[];
extern Handle ctx_kb2VK3[];
static Bool
find_oid( PAbstractMenu menu, PMenuItemReg m, int id)
{
return m-> down && ( m-> down-> id == id);
}
Handle ctx_deadkeys[] = {
0x5E, 0x302, // Circumflex accent
0x60, 0x300, // Grave accent
0xA8, 0x308, // Diaeresis
0xB4, 0x301, // Acute accent
0xB8, 0x327, // Cedilla
endCtx
};
static void
zorder_sync( Handle self, HWND me, LPWINDOWPOS lp)
{
if ( lp-> hwndInsertAfter == HWND_TOP ||
lp-> hwndInsertAfter == HWND_NOTOPMOST ||
lp-> hwndInsertAfter == HWND_TOPMOST) {
me = GetNextWindow( me, GW_HWNDPREV);
if ( me)
PostMessage( me, WM_ZORDERSYNC, 0, 0);
} else if ( lp-> hwndInsertAfter == HWND_BOTTOM) {
me = GetNextWindow( me, GW_HWNDNEXT);
if ( me)
PostMessage( me, WM_ZORDERSYNC, 0, 0);
}
}
LRESULT CALLBACK generic_view_handler( HWND win, UINT msg, WPARAM mp1, LPARAM mp2)
{
LRESULT ret = 0;
Handle self = GetWindowLongPtr( win, GWLP_USERDATA);
PWidget v = ( PWidget) self;
UINT orgMsg = msg;
Event ev;
Bool hiStage = false;
int orgCmd;
Bool message_result = true;
if ( !self || appDead)
return DefWindowProcW( win, msg, mp1, mp2);
memset( &ev, 0, sizeof (ev));
ev. gen. source = self;
switch ( msg) {
case WM_NCACTIVATE:
// if activation or deactivation is concerned with declipped window ( e.g.self),
// notify its top level frame so that it will have the chance to redraw itself correspondingly
if ( is_declipped_child( self) && !Widget_is_child( hwnd_to_view(( HWND) mp2), hwnd_top_level( self))) {
Handle x = hwnd_top_level( self);
if ( x) SendMessage( DHANDLE( x), WM_NCACTIVATE, mp1, mp2);
}
break;
case WM_MOUSEACTIVATE:
// if pointing to non-active frame, but its declipped child is active at the moment,
// cancel activation - it could produce unwilling focus changes
if ( sys className == WC_FRAME) {
Handle x = hwnd_to_view( GetActiveWindow());
if ( is_declipped_child(x) && Widget_is_child( x, self))
return MA_NOACTIVATE;
}
break;
case WM_CLOSE:
if ( sys className != WC_FRAME)
return 0;
break;
case WM_COMMAND:
if (( HIWORD( mp1) == 0 /* menu source */) && ( mp2 == 0)) {
if ( LOWORD( mp1) <= MENU_ID_AUTOSTART) {
HWND active = GetFocus();
if ( active != nil) SendMessage( active, LOWORD( mp1), 0, 0);
} else if ( sys lastMenu) {
PAbstractMenu a = ( PAbstractMenu) sys lastMenu;
if ( a-> stage <= csNormal)
a-> self-> sub_call_id(( Handle) a, LOWORD( mp1) - MENU_ID_AUTOSTART);
}
}
break;
case WM_CONTEXTMENU:
{
POINT a;
a. x = ( short)LOWORD( mp2);
a. y = ( short)HIWORD( mp2);
ev. cmd = cmPopup;
// mouse event
ev. gen. B = ( GetKeyState( VK_LBUTTON) < 0) | ( GetKeyState( VK_RBUTTON) < 0);
if ( !ev. gen. B && GetSystemMetrics( SM_MOUSEPRESENT))
GetCursorPos(( POINT*) &a);
MapWindowPoints( NULL, win, &a, 1);
ev. gen. P. x = a. x;
ev. gen. P. y = sys lastSize. y - a. y - 1;
}
break;
case WM_ENABLE:
ev. cmd = mp1 ? cmEnable : cmDisable;
hiStage = true;
break;
case WM_ERASEBKGND:
return 1;
case WM_FORCEFOCUS:
if ( mp2)
((( PWidget) mp2)-> self)-> set_selected(( Handle) mp2, 1);
return 0;
case WM_HASMATE:
*(( Handle*) mp2) = self;
return HASMATE_MAGIC;
case WM_IME_CHAR:
if ( apc_widget_is_responsive( self)) {
ev. cmd = cmKeyDown;
ev. key. mod = kmUnicode;
ev. key. key = kbNoKey;
ev. key. code = mp1;
}
break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
if ( mp2 & ( 1 << 29)) ev. key. mod = kmAlt;
case WM_KEYDOWN:
case WM_KEYUP:
if ( apc_widget_is_responsive( self)) {
BYTE * keyState;
Bool up = ( msg == WM_KEYUP) || ( msg == WM_SYSKEYUP);
Bool extended = mp2 & ( 1 << 24);
UINT scan = ( HIWORD( mp2) & 0xFF) | ( up ? 0x80000000 : 0);
int deadPollCount = 0;
HKL kl = GetKeyboardLayout(0);
// basic assignments
ev. cmd = up ? cmKeyUp : cmKeyDown;
ev. key. key = ctx_remap_def( mp1, ctx_kb2VK, false, kbNoKey);
ev. key. code = mp1;
ev. key. repeat = mp2 & 0x000000FF;
// VK validations
if ( extended) {
int ks = ev. key. key;
ev. key. key = ctx_remap_def( ks, ctx_kb2VK3, true, ks);
if ( ev. key. key != ks)
extended = false; // avoid (Ctrl|Alt)R+KeyPad combinations
} else if ( mp1 >= VK_NUMPAD0 && mp1 <= VK_DIVIDE)
extended = true; // include numpads
ev. key. mod = 0 |
( extended ? kmKeyPad : 0) |
(( GetKeyState( VK_SHIFT) < 0) ? kmShift : 0) |
(( GetKeyState( VK_CONTROL) < 0) ? kmCtrl : 0) |
(( GetKeyState( VK_MENU) < 0) ? kmAlt : 0);
keyState = guts. keyState;
AGAIN:
if ( PApplication(application)-> wantUnicodeInput) {
WCHAR keys[ 2];
// unicode mapping
switch ( ToUnicodeEx( mp1, scan, keyState, keys, 2, 0, kl)) {
case 1: // char
if ( lastDeadKey ) {
WCHAR wcBuffer[3];
WCHAR out[3];
wcBuffer[0] = keys[0];
wcBuffer[1] = lastDeadKey;
wcBuffer[2] = '\0';
if ( FoldStringW(MAP_PRECOMPOSED, (LPWSTR) wcBuffer, 3, (LPWSTR) out, 3) )
keys[0] = out[0];
}
if ( !deadPollCount && ( GetKeyState( VK_MENU) < 0) && ( GetKeyState( VK_SHIFT) >= 0)) {
WCHAR keys2[2];
if (( ToUnicodeEx( mp1, scan, guts. emptyKeyState, keys2, 2, 0, kl) == 1) &&
( keys2[0] != keys[0])) {
/* example - (AltGr+2) == '@' on danish keyboard.
this hack is to tell whether the key without mods
will give same character code ... */
ev. key. mod &= ~(kmAlt|kmCtrl|kmShift);
}
}
if (!up) lastDeadKey = 0;
break;
case 2: { // dead key
lastDeadKey = ctx_remap_def( keys[0], ctx_deadkeys, true, keys[0]);
keys[ 0] = 0;
ev. key. mod |= kmDeadKey;
}
break;
case 0: // virtual key
if ( deadPollCount == 0) {
/* can't have character code - maybe fish out without mods? */
keyState = guts. emptyKeyState;
deadPollCount = 1;
goto AGAIN;
} else {
/* same meaning without mods, no code anyway */
keys[ 0] = 0;
}
if (!up) lastDeadKey = 0;
break;
default:
ev. key. mod |= kmDeadKey;
if (!up) lastDeadKey = 0;
}
ev. key. code = keys[ 0];
ev. key. mod |= kmUnicode;
} else {
BYTE keys[ 4];
switch ( ToAsciiEx( mp1, scan, keyState, (LPWORD) keys, 0, kl)) {
case 1: // char
if ( lastDeadKey ) {
BYTE cBuffer[3];
BYTE out[3];
cBuffer[0] = keys[0];
cBuffer[1] = lastDeadKey;
cBuffer[2] = '\0';
if ( FoldStringA(MAP_PRECOMPOSED, (LPSTR) cBuffer, 3, (LPSTR) out, 3) )
keys[0] = out[0];
}
if ( !deadPollCount && ( GetKeyState( VK_MENU) < 0) && ( GetKeyState( VK_SHIFT) >= 0)) {
BYTE keys2[4];
if (( ToAsciiEx( mp1, scan, guts. emptyKeyState, (LPWORD) keys2, 0, kl) == 1) &&
( keys2[0] != keys[0])) {
/* example - (AltGr+2) == '@' on danish keyboard.
this hack is to tell whether the key without mods
will give same character code ... */
ev. key. mod &= ~(kmAlt|kmCtrl|kmShift);
}
}
break;
case 2: { // dead key
lastDeadKey = keys[0];
keys[ 0] = 0;
ev. key. mod |= kmDeadKey;
}
break;
case 0: // virtual key
if ( deadPollCount == 0) {
/* can't have character code - maybe fish out without mods? */
keyState = guts. emptyKeyState;
deadPollCount = 1;
goto AGAIN;
} else {
/* same meaning without mods, no code anyway */
keys[ 0] = 0;
}
if (!up) lastDeadKey = 0;
break;
default:
ev. key. mod |= kmDeadKey;
if (!up) lastDeadKey = 0;
}
ev. key. code = keys[ 0];
}
// simulated key codes
if ( ev. key. key == kbTab && ( ev. key. mod & kmShift))
ev. key. key = kbBackTab;
if ( ev. key. code >= 'A' && ev. key. code <= 'z' && ev. key. mod & kmCtrl) {
ev. key. code = toupper(ev. key. code & 0xFF) - '@';
if (!( ev. key. mod & kmShift)) ev. key. code = tolower( ev. key. code);
}
}
break;
case WM_INITMENUPOPUP:
if ( HIWORD( mp2)) break; // do not use system popup
case WM_INITMENU:
{
PMenuWndData mwd = ( PMenuWndData) hash_fetch( menuMan, &mp1, sizeof( void*));
PMenuItemReg m = nil;
sys lastMenu = mwd ? mwd-> menu : nilHandle;
if ( mwd && mwd-> menu && ( PAbstractMenu(mwd-> menu)->stage <= csNormal)) {
m = ( PMenuItemReg) AbstractMenu_first_that( mwd-> menu, find_oid, INT2PTR(void*,mwd->id), true);
hiStage = true;
ev. cmd = cmMenu;
ev. gen. H = mwd-> menu;
ev. gen. i = m ? m-> id : 0;
}
if (( msg == WM_INITMENUPOPUP) && ( m == nil))
ev. cmd = 0;
}
break;
case WM_KILLFOCUS:
if (( HWND) mp1 != win) {
ev. cmd = cmReleaseFocus;
hiStage = true;
apt_assign( aptFocused, 0);
DestroyCaret();
}
break;
case WM_LBUTTONDOWN:
ev. pos. button = mbLeft;
goto MB_DOWN;
case WM_RBUTTONDOWN:
ev. pos. button = mbRight;
goto MB_DOWN;
case WM_MBUTTONDOWN:
ev. pos. button = mbMiddle;
goto MB_DOWN;
case WM_LBUTTONUP:
ev. pos. button = mbLeft;
goto MB_UP;
case WM_RBUTTONUP:
ev. pos. button = mbRight;
goto MB_UP;
case WM_MBUTTONUP:
ev. pos. button = mbMiddle;
goto MB_UP;
case WM_LBUTTONDBLCLK:
ev. pos. button = mbLeft;
goto MB_DBLCLK;
case WM_RBUTTONDBLCLK:
ev. pos. button = mbRight;
goto MB_DBLCLK;
case WM_MBUTTONDBLCLK:
ev. pos. button = mbMiddle;
goto MB_DBLCLK;
case WM_LMOUSECLICK:
ev. pos. button = mbLeft;
goto MB_CLICK;
case WM_RMOUSECLICK:
ev. pos. button = mbRight;
goto MB_CLICK;
case WM_MMOUSECLICK:
ev. pos. button = mbMiddle;
goto MB_CLICK;
case WM_MOUSEWHEEL:
{
POINT p;
p. x = (short)LOWORD( mp2);
p. y = (short)HIWORD( mp2);
ev. cmd = cmMouseWheel;
ev. pos. button = ( short) HIWORD( mp1);
MapWindowPoints( nil, win, &p, 1);
ev. pos. where. x = p. x;
ev. pos. where. y = sys lastSize. y - p. y - 1;
}
goto MB_MAIN_NOPOS;
case WM_MOUSEMOVE:
ev. cmd = cmMouseMove;
if ( self != lastMouseOver) {
Handle old = lastMouseOver;
lastMouseOver = self;
if ( old && ( PWidget( old)-> stage == csNormal))
SendMessage(( HWND)(( PWidget) old)-> handle, WM_MOUSEEXIT, mp1, mp2);
SendMessage( win, WM_MOUSEENTER, mp1, mp2);
if ( !guts. mouseTimer) {
guts. mouseTimer = 1;
if ( !SetTimer( dsys(application)handle, TID_USERMAX, 100, nil)) apiErr;
}
}
goto MB_MAIN;
case WM_MOUSEENTER:
ev. cmd = cmMouseEnter;
goto MB_MAIN;
case WM_MOUSEEXIT:
ev. cmd = cmMouseLeave;
goto MB_MAIN;
MB_DOWN:
ev. cmd = cmMouseDown;
goto MB_MAINACT;
MB_UP:
ev. cmd = cmMouseUp;
goto MB_MAINACT;
MB_DBLCLK:
ev. pos. dblclk = 1;
MB_CLICK:
ev. cmd = cmMouseClick;
goto MB_MAINACT;
MB_MAINACT:
if ( !is_apt( aptEnabled) || !apc_widget_is_responsive( self))
{
if ( ev. cmd == cmMouseDown || (ev. cmd == cmMouseClick && ev. pos. dblclk))
MessageBeep( MB_OK);
return 0;
}
goto MB_MAIN;
MB_MAIN:
if ( ev. cmd == cmMouseDown && !is_apt( aptFirstClick)) {
Handle x = self;
while ( dsys(x) className != WC_FRAME && ( x != application)) x = (( PWidget) x)-> owner;
if ( x != application && !local_wnd( GetActiveWindow(), DHANDLE( x)))
{
ev. cmd = 0; // yes, we abandon mousedown but we should force selection:
if ((( PApplication) application)-> hintUnder == self) v-> self-> set_hintVisible( self, 0);
if (( v-> options. optSelectable) && ( v-> selectingButtons & ev. pos. button))
apc_widget_set_focused( self);
}
}
ev. pos. where. x = (short)LOWORD( mp2);
ev. pos. where. y = sys lastSize. y - (short)HIWORD( mp2) - 1;
MB_MAIN_NOPOS:
ev. pos. mod = 0 |
(( mp1 & MK_CONTROL ) ? kmCtrl : 0) |
(( mp1 & MK_SHIFT ) ? kmShift : 0) |
(( GetKeyState( VK_MENU) < 0) ? kmAlt : 0) |
apc_pointer_get_state(self)
;
break;
case WM_MENUCHAR:
{
int key;
ev. key. key = ctx_remap_def( mp1, ctx_kb2VK2, false, kbNoKey);
ev. key. code = mp1;
ev. key. mod |=
(( GetKeyState( VK_SHIFT) < 0) ? kmShift : 0) |
(( GetKeyState( VK_CONTROL) < 0) ? kmCtrl : 0) |
(( GetKeyState( VK_MENU) < 0) ? kmAlt : 0);
if (( ev. key. mod & kmCtrl) && ( ev. key. code <= 'z'))
ev. key. code += 'A' - 1;
key = CAbstractMenu-> translate_key( nilHandle, ev. key. code, ev. key. key, ev. key. mod);
if ( v-> self-> process_accel( self, key))
return MAKELONG( 0, MNC_CLOSE);
}
break;
case WM_SYNCMOVE:
{
Handle parent = v-> self-> get_parent(( Handle) v);
if ( parent) {
Point pos = var self-> get_origin( self);
ev. cmd = cmMove;
ev. gen. P = pos;
if ( pos. x == var pos. x && pos. y == var pos. y) ev. cmd = 0;
}
}
break;
case WM_MOVE:
{
Handle parent = v-> self-> get_parent(( Handle) v);
if ( parent) {
Point sz = CWidget(parent)-> get_size( parent);
ev. cmd = cmMove;
ev. gen . P. x = ( short) LOWORD( mp2);
ev. gen . P. y = sz. y - ( short) HIWORD( mp2) - sys yOverride;
if ( is_apt( aptTransparent))
InvalidateRect( win, nil, false);
}
}
break;
case WM_NCHITTEST:
if ( guts. focSysDialog) return HTERROR;
// dlg protect code - protecting from user actions
if ( !guts. focSysDisabled && ( Application_map_focus( application, self) != self))
return HTERROR;
break;
case WM_PAINT:
ev. cmd = cmPaint;
if (
( sys className == WC_CUSTOM) &&
( var stage == csNormal) &&
( list_index_of( &guts. transp, self) >= 0)
)
return 0;
if ( is_apt( aptLayered )) {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(win, &ps);
EndPaint(win, &ps);
return 0;
}
break;
case WM_QUERYNEWPALETTE:
return palette_change( self);
case WM_PALETTECHANGED:
if (( HWND) mp1 != win) {
Handle mp = hwnd_to_view(( HWND) mp1);
if ( mp && ( hwnd_top_level( mp) == hwnd_top_level( self)))
return 0;
palette_change( self);
}
break;
case WM_POSTAL:
ev. cmd = cmPost;
ev. gen. H = ( Handle) mp1;
ev. gen. p = ( void *) mp2;
break;
case WM_PRIMA_CREATE:
ev. cmd = cmSetup;
break;
case WM_REPAINT_LAYERED:
hwnd_repaint_layered( self, true );
break;
case WM_SETFOCUS:
if ( guts. focSysDialog) return 1;
// dlg protect code - general case
if ( !guts. focSysDisabled && !guts. focSysGranted) {
Handle hf = Application_map_focus( application, self);
if ( hf != self) {
PostMessage( win, WM_FORCEFOCUS, 0, ( LPARAM) hf);
return 1;
}
}
if (( HWND) mp1 != win) {
ev. cmd = cmReceiveFocus;
hiStage = true;
apt_assign( aptFocused, 1);
cursor_update( self);
}
break;
case WM_SETVISIBLE:
if ( list_index_of( &guts. transp, self) < 0) {
if ( v-> stage <= csNormal) ev. cmd = mp1 ? cmShow : cmHide;
hiStage = true;
apt_assign( aptVisible, mp1);
}
break;
case WM_SIZE:
ev. cmd = cmSize;
ev. gen. R. left = sys lastSize. x;
ev. gen. R. bottom = sys lastSize. y;
sys lastSize. x = ev. gen. R. right = ev. gen . P. x = ( short) LOWORD( mp2);
sys lastSize. y = ev. gen. R. top = ev. gen . P. y = ( short) HIWORD( mp2);
if ( ev. gen. R. top != ev. gen. R. bottom) {
int delta = ev. gen. R. top - ev. gen. R. bottom;
Widget_first_that( self, move_back, &delta);
if ( is_apt( aptFocused)) cursor_update(( Handle) self);
}
if ( sys sizeLockLevel == 0 && var stage <= csNormal)
var virtualSize = sys lastSize;
break;
case WM_TIMER:
{
int id = mp1 - 1;
if ( id >= 0 && id < sys timeDefsCount) ev. gen. H = ( Handle) sys timeDefs[ id]. item;
if ( ev. gen. H) {
v = ( PWidget)( self = ev. gen. H);
ev. cmd = cmTimer;
}
}
break;
case WM_WINDOWPOSCHANGING:
{
LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
if ( sys className == WC_CUSTOM) {
if (( l-> flags & SWP_NOSIZE) == 0) {
ev. cmd = cmCalcBounds;
ev. gen. R. right = l-> cx;
ev. gen. R. top = l-> cy;
}
}
if (( l-> flags & SWP_NOZORDER) == 0)
zorder_sync( self, win, l);
}
break;
case WM_WINDOWPOSCHANGED:
{
LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
if (( l-> flags & SWP_NOZORDER) == 0)
PostMessage( win, WM_ZORDERSYNC, 0, 0);
if (( l-> flags & SWP_NOSIZE) == 0) {
sys yOverride = l-> cy;
SendMessage( win, WM_SYNCMOVE, 0, 0);
}
if ( l-> flags & SWP_HIDEWINDOW) SendMessage( win, WM_SETVISIBLE, 0, 0);
if ( l-> flags & SWP_SHOWWINDOW) SendMessage( win, WM_SETVISIBLE, 1, 0);
}
break;
case WM_ZORDERSYNC:
ev. cmd = cmZOrderChanged;
break;
}
if ( hiStage)
ret = DefWindowProcW( win, msg, mp1, mp2);
orgCmd = ev. cmd;
if ( ev. cmd)
message_result = v-> self-> message( self, &ev);
else
ev. cmd = orgMsg;
if ( v-> stage > csNormal) orgMsg = 0; // protect us from dead body
switch ( orgMsg) {
case WM_DESTROY:
v-> handle = nilHandle; // tell apc not to kill this HWND
SetWindowLongPtr( win, GWLP_USERDATA, 0);
Object_destroy(( Handle) v);
break;
case WM_PAINT:
return 0;
case WM_SYSKEYDOWN:
if ( !message_result)
guts. dont_xlate_message = true;
break;
case WM_SYSKEYUP:
// ev. cmd = 1; // forced call DefWindowProc superseded for test reasons
break;
case WM_MOUSEMOVE:
if ( is_apt( aptEnabled)) SetCursor( sys pointer);
break;
case WM_MOUSEWHEEL:
return ( LRESULT)1;
case WM_WINDOWPOSCHANGING:
{
LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
if ( sys className == WC_CUSTOM) {
if (( l-> flags & SWP_NOSIZE) == 0) {
int dy = l-> cy - ev. gen. R. top;
l-> cx = ev. gen. R. right;
l-> cy = ev. gen. R. top;
l-> y += dy;
}
return false;
}
if (( l-> flags & SWP_NOZORDER) == 0)
zorder_sync( self, win, l);
}
break;
}
if ( ev. cmd && !hiStage)
ret = DefWindowProcW( win, msg, mp1, mp2);
return ret;
}
LRESULT CALLBACK generic_frame_handler( HWND win, UINT msg, WPARAM mp1, LPARAM mp2)
{
LRESULT ret = 0;
Handle self = GetWindowLongPtr( win, GWLP_USERDATA);
PWidget v = ( PWidget) self;
UINT orgMsg = msg;
Event ev;
Bool hiStage = false;
int orgCmd;
if ( !self)
return DefWindowProcW( win, msg, mp1, mp2);
memset( &ev, 0, sizeof (ev));
ev. gen. source = self;
switch ( msg) {
case WM_ACTIVATE:
if ( guts. focSysDialog) return 1;
// dlg protect code - protecting from window activation
if ( LOWORD( mp1) && !guts. focSysDisabled) {
Handle hf = Application_map_focus( application, self);
if ( hf != self) {
guts. focSysDisabled = 1;
Application_popup_modal( application);
PostMessage( win, msg, 0, 0);
guts. focSysDisabled = 0;
return 1;
}
}
ev. cmd = ( LOWORD( mp1) != WA_INACTIVE) ? cmActivate : cmDeactivate;
hiStage = true;
break;
case WM_CLOSE:
ev. cmd = cmClose;
break;
case WM_COMMAND:
// case WM_MENUSELECT:
case WM_INITMENUPOPUP:
case WM_INITMENU:
case WM_MENUCHAR:
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SETVISIBLE:
case WM_ENABLE:
case WM_FORCEFOCUS:
case WM_MOUSEWHEEL:
case WM_ZORDERSYNC:
return generic_view_handler(( HWND) v-> handle, msg, mp1, mp2);
case WM_QUERYNEWPALETTE:
return generic_view_handler(( HWND) v-> handle, msg, mp1, mp2);
case WM_PALETTECHANGED:
if (( HWND) mp1 == win) return 0;
return generic_view_handler(( HWND) v-> handle, msg, mp1, mp2);
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
if ( generic_view_handler(( HWND) v-> handle, msg, mp1, mp2) == 0)
return 0;
hiStage = true;
break;
case WM_DLGENTERMODAL:
ev. cmd = mp1 ? cmExecute : cmEndModal;
break;
case WM_ERASEBKGND:
return 1;
case WM_NCACTIVATE:
if ( guts. focSysDialog) return 1;
if (( mp1 == 0) && ( mp2 != 0)) {
Handle x = hwnd_to_view(( HWND) mp2);
if ( is_declipped_child( x) && Widget_is_child( x, self)) {
return 1;
}
}
// dlg protect code - protecting from window activation
if ( mp1 && !guts. focSysDisabled) {
Handle hf = Application_map_focus( application, self);
if ( hf != self) {
guts. focSysDisabled = 1;
Application_popup_modal( application);
PostMessage( win, msg, 0, 0);
guts. focSysDisabled = 0;
return 1;
}
}
break;
case WM_NCHITTEST:
if ( guts. focSysDialog) return HTERROR;
// dlg protect code - protecting from user actions
if ( !guts. focSysDisabled) {
Handle foc = Application_map_focus( application, self);
if ( foc != self) {
return ( foc == apc_window_get_active()) ? HTERROR : HTCLIENT;
}
}
break;
case WM_SETFOCUS:
if ( guts. focSysDialog) return 1;
// dlg protect code - general case
if ( !guts. focSysDisabled && !guts. focSysGranted) {
Handle hf = Application_map_focus( application, self);
if ( hf != self) {
PostMessage( win, WM_FORCEFOCUS, 0, ( LPARAM) hf);
return 1;
}
}
// This code is about to protect frame events when set_selected would
// grant SetFocus() call to another frame.
{
Handle x = var self-> get_selectee( self);
Handle w = x;
Bool hasCO = w == self;
while ( w && w != self) {
if ( !dsys( w) options. aptClipOwner) {
hasCO = true;
break;
}
w = (( PWidget) w)-> owner;
}
if ( !hasCO) {
var self-> set_selected( self, true);
}
// else we do not select any widget, but still have a chance to resize frame :)
}
break;
case WM_SIZE:
{
int state = wsNormal;
Bool doWSChange = false;
if (( int) mp1 == SIZE_RESTORED) {
state = wsNormal;
if ( sys s. window. state != state) doWSChange = true;
} else if (( int) mp1 == SIZE_MAXIMIZED) {
state = wsMaximized;
doWSChange = true;
} else if (( int) mp1 == SIZE_MINIMIZED) {
state = wsMinimized;
doWSChange = true;
}
if ( doWSChange) {
ev. gen. i = sys s. window. state = state;
ev. cmd = cmWindowState;
}
}
break;
case WM_SYNCMOVE:
{
Handle parent = v-> self-> get_parent(( Handle) v);
if ( parent) {
Point pos = var self-> get_origin( self);
ev. cmd = cmMove;
ev. gen. P = pos;
if ( pos. x == var pos. x && pos. y == var pos. y) ev. cmd = 0;
}
}
break;
case WM_MOVE:
{
Handle parent = v-> self-> get_parent(( Handle) v);
if ( parent) {
Point sz = CWidget(parent)-> get_size( parent);
ev. cmd = cmMove;
ev. gen . P. x = ( short) LOWORD( mp2);
ev. gen . P. y = sz. y - ( short) HIWORD( mp2) - sys yOverride;
}
}
break;
// case WM_SYSCHAR:return 1;
case WM_TIMER:
if ( mp1 == TID_USERMAX)
// application local timer
{
POINT p;
HWND wp;
if ( lastMouseOver && !GetCapture() && ( PObject( lastMouseOver)-> stage == csNormal))
{
HWND desktop = HWND_DESKTOP;
GetCursorPos( &p);
wp = WindowFromPoint( p);
if ( wp) {
POINT xp = p;
MapWindowPoints( desktop, wp, &xp, 1);
wp = ChildWindowFromPointEx( wp, xp, CWP_SKIPINVISIBLE);
} else
wp = ChildWindowFromPointEx( wp, p, CWP_SKIPINVISIBLE);
if ( wp != ( HWND)(( PWidget) lastMouseOver)-> handle)
{
HWND old = ( HWND)(( PWidget) lastMouseOver)-> handle;
Handle s;
lastMouseOver = nilHandle;
SendMessage( old, WM_MOUSEEXIT, 0, 0);
s = hwnd_to_view( wp);
if ( s && ( HWND)(( PWidget) s)-> handle == wp)
{
MapWindowPoints( desktop, wp, &p, 1);
SendMessage( wp, WM_MOUSEENTER, 0, MAKELPARAM( p. x, p. y));
lastMouseOver = s;
} else if ( guts. mouseTimer) {
guts. mouseTimer = 0;
if ( !KillTimer( dsys(application)handle, TID_USERMAX)) apiErr;
}
}
}
return 0;
}
break;
case WM_GETMINMAXINFO:
{
LPMINMAXINFO l = ( LPMINMAXINFO) mp2;
Point min = var self-> get_sizeMin( self);
Point max = var self-> get_sizeMax( self);
Point bor = get_window_borders( sys s. window. borderStyle);
int dy = 0 +
(( sys s. window. borderIcons & biTitleBar) ? GetSystemMetrics( SM_CYCAPTION) : 0) +
( PWindow(self)-> menu ? GetSystemMetrics( SM_CYMENU) : 0);
l-> ptMinTrackSize. x = min. x + bor.x * 2;
l-> ptMinTrackSize. y = min. y + bor.y * 2 + dy;
l-> ptMaxTrackSize. x = max. x + bor.x * 2;
l-> ptMaxTrackSize. y = max. y + bor.y * 2 + dy;
}
break;
case WM_WINDOWPOSCHANGED:
{
LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
if (( l-> flags & SWP_NOZORDER) == 0)
PostMessage( win, WM_ZORDERSYNC, 0, 0);
if (( l-> flags & SWP_NOSIZE) == 0) {
RECT r;
GetClientRect( win, &r);
sys yOverride = r. bottom - r. top;
SendMessage( win, WM_SYNCMOVE, 0, 0);
}
if ( l-> flags & SWP_HIDEWINDOW) SendMessage( win, WM_SETVISIBLE, 0, 0);
if ( l-> flags & SWP_SHOWWINDOW) SendMessage( win, WM_SETVISIBLE, 1, 0);
{
RECT r;
GetClientRect( win, &r);
SetWindowPos(( HWND) var handle, 0, 0, 0, r. right, r.bottom, SWP_NOZORDER);
}
}
break;
}
if ( hiStage)
ret = DefWindowProcW( win, msg, mp1, mp2);
orgCmd = ev. cmd;
if ( ev. cmd) v-> self-> message( self, &ev); else ev. cmd = orgMsg;
if ( var stage == csDead) orgMsg = 0;
switch ( orgMsg) {
case WM_CLOSE:
if ( ev. cmd) {
if ( sys className == WC_FRAME && PWindow(self)->modal) {
CWindow( self)-> cancel( self);
return 0;
} else {
SetWindowLongPtr( win, GWLP_USERDATA, 0);
Object_destroy(( Handle) v);
}
break;
} else
return 0;
}
if ( ev. cmd && !hiStage)
ret = DefWindowProcW( win, msg, mp1, mp2);
return ret;
}
static void
update_layered_frame(Handle self)
{
HRGN r1, r2;
RECT frame, client;
POINT frame_size, client_size;
Point delta_upper_left, delta_lower_right, move;
HWND win = HANDLE;
delta_lower_right = get_window_borders( sys s. window. borderStyle);
GetWindowRect(win, &frame);
GetClientRect(win, &client);
frame_size. x = frame. right - frame. left;
frame_size. y = frame. bottom - frame. top;
client_size. x = client. right - client. left;
client_size. y = client. bottom - client. top;
r2 = CreateRectRgn( 0, 0, frame_size.x, frame_size.y);
r1 = CreateRectRgn( 0, 0, client_size.x, client_size.y);
delta_upper_left.x = frame_size.x - client_size.x - delta_lower_right.x;
delta_upper_left.y = frame_size.y - client_size.y - delta_lower_right.y;
OffsetRgn( r1, delta_upper_left.x, delta_upper_left.y);
CombineRgn( r2, r2, r1, RGN_XOR);
if (!SetWindowRgn( win, r2, true)) apiErr;
DeleteObject(r1);
DeleteObject(r2);
move.x = frame.left + delta_upper_left.x;
move.y = frame.top + delta_upper_left.y;
if ( !SetWindowPos(( HWND ) var handle, win,
client.left + move.x, client.top + move.y, client_size.x, client_size.y,
SWP_NOACTIVATE)) apiErr;
hwnd_repaint_layered( self, false );
}
LRESULT CALLBACK layered_frame_handler( HWND win, UINT msg, WPARAM mp1, LPARAM mp2)
{
Handle self = GetWindowLongPtr( win, GWLP_USERDATA);
if ( !self)
return DefWindowProcW( win, msg, mp1, mp2);
switch ( msg) {
case WM_NCACTIVATE:
case WM_NCHITTEST:
case WM_SETFOCUS:
return DefWindowProcW( win, msg, mp1, mp2);
case WM_SIZE:
case WM_MOVE:
update_layered_frame(self);
return DefWindowProcW( win, msg, mp1, mp2);
case WM_WINDOWPOSCHANGED: {
LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
Bool updated = false;
if (( l-> flags & SWP_NOSIZE) == 0) {
RECT r;
update_layered_frame(self);
updated = true;
GetClientRect( win, &r);
sys yOverride = r. bottom - r. top;
SendMessage( win, WM_SYNCMOVE, 0, 0);
}
if (( l-> flags & SWP_NOMOVE) == 0) {
if ( !updated ) {
update_layered_frame(self);
updated = true;
}
}
if (( l-> flags & SWP_NOZORDER) == 0) {
PostMessage( win, WM_ZORDERSYNC, 0, 0);
if ( !updated ) {
update_layered_frame(self);
updated = true;
}
}
if ( l-> flags & SWP_HIDEWINDOW) {
ShowWindow((HWND) var handle, SW_HIDE);
SendMessage( win, WM_SETVISIBLE, 0, 0);
}
if ( l-> flags & SWP_SHOWWINDOW) {
ShowWindow((HWND) var handle, SW_SHOW);
SendMessage( win, WM_SETVISIBLE, 1, 0);
}
}
return DefWindowProcW( win, msg, mp1, mp2);
}
return generic_frame_handler( win, msg, mp1, mp2 );
}
static Bool kill_img_cache( Handle self, int keyLen, void * key, void * killDBM)
{
if ( is_apt( aptDeviceBitmap)) {
if ( killDBM) dbm_recreate( self);
} else
image_destroy_cache( self);
return false;
}
LRESULT CALLBACK generic_app_handler( HWND win, UINT msg, WPARAM mp1, LPARAM mp2)
{
switch ( msg) {
case WM_DISPLAYCHANGE:
{
HDC dc = dc_alloc();
int oldBPP = guts. displayBMInfo. bmiHeader. biBitCount;
HBITMAP hbm;
if ( dc) {
guts. displayBMInfo. bmiHeader. biBitCount = 0;
guts. displayBMInfo. bmiHeader. biSize = sizeof( BITMAPINFO);
if ( !( hbm = GetCurrentObject( dc, OBJ_BITMAP))) apiErr;
if ( !GetDIBits( dc, hbm, 0, 0, NULL, &guts. displayBMInfo, DIB_PAL_COLORS)) {
guts. displayBMInfo. bmiHeader. biBitCount = ( int) mp1;
guts. displayBMInfo. bmiHeader. biPlanes = GetDeviceCaps( dc, PLANES);
};
}
dsys( application) lastSize. x = ( short) LOWORD( mp2);
dsys( application) lastSize. y = ( short) HIWORD( mp2);
if ( dc) {
if ( oldBPP != guts. displayBMInfo. bmiHeader. biBitCount)
hash_first_that( imageMan, kill_img_cache, (void*)1, nil, nil);
dc_free();
}
}
break;
case WM_FONTCHANGE:
destroy_font_hash();
break;
case WM_COMPACTING:
stylus_clean();
font_clean();
destroy_font_hash();
hash_first_that( imageMan, kill_img_cache, nil, nil, nil);
hash_destroy( regnodeMan, false);
regnodeMan = hash_create();
break;
case WM_QUERYNEWPALETTE:
case WM_PALETTECHANGED:
return 0;
}
return generic_frame_handler( win, msg, mp1, mp2);
}
#ifdef __cplusplus
}
#endif