1 #include "win32\win32guts.h"
2 #include <ole2.h>
3 #ifndef _APRICOT_H_
4 #include "apricot.h"
5 #endif
6 #include "guts.h"
7 #include "Window.h"
8 #include "Application.h"
9 #include "Menu.h"
10 
11 #ifdef __cplusplus
12 extern "C" {
13 #endif
14 
15 
16 #define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
17 #define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
18 #define var (( PWidget) self)->
19 #define HANDLE sys handle
20 #define DHANDLE(x) dsys(x) handle
21 
22 WinGuts guts;
23 DWORD   rc;
24 PHash   stylusMan      = NULL; // pen & brush manager
25 PHash   stylusGpMan    = NULL; // pen & brush manager for GDI+
26 PHash   fontMan        = NULL; // font manager
27 PHash   patMan         = NULL; // pattern resource manager
28 PHash   menuMan        = NULL; // HMENU manager
29 PHash   imageMan       = NULL; // HBITMAP manager
30 PHash   regnodeMan     = NULL; // cache for apc_widget_user_profile
31 PHash   myfontMan      = NULL; // hash of calls to apc_font_load
32 PHash   menuBitmapMan  = NULL; // HBITMAP manager for SetMenuItemBitmaps
33 PHash   scriptCacheMan = NULL; // SCRIPT_CACHE entries per font/script
34 HPEN    hPenHollow;
35 HBRUSH  hBrushHollow;
36 HCURSOR arrowCursor;
37 PatResource hPatHollow;
38 DIBMONOBRUSH bmiHatch = {
39 	{ sizeof( BITMAPINFOHEADER), 8, 8, 1, 1, BI_RGB, 0, 0, 0, 2, 2},
40 	{{0,0,0,0}, {0,0,0,0}}
41 };
42 int     FONTSTRUCSIZE;
43 Handle lastMouseOver = NULL_HANDLE;
44 MusClkRec musClk = {0};
45 char * keyLayouts[]   = {  "0409", "0403", "0405", "0406", "0407",
46 	"0807","0809","080A","080C","0C0C","100C","0810","0814","0816",
47 	"040A","040B","040C","040E","040F","0410","0413","0414","0415","0416",
48 	"0417","0418","041A","041D"
49 };
50 WCHAR lastDeadKey = 0;
51 int          timeDefsCount = 0;
52 PItemRegRec  timeDefs = NULL;
53 Bool debug = false;
54 HBITMAP uncheckedBitmap = NULL;
55 
56 BOOL APIENTRY
DllMain(HINSTANCE hInstance,DWORD reason,LPVOID reserved)57 DllMain( HINSTANCE hInstance, DWORD reason, LPVOID reserved)
58 {
59 	if ( reason == DLL_PROCESS_ATTACH) {
60 		memset( &guts, 0, sizeof( guts));
61 		guts. instance = hInstance;
62 		guts. cmdShow  = SW_SHOWDEFAULT;
63 	}
64 	return TRUE;
65 }
66 
67 typedef enum _PROCESS_DPI_AWARENESS {
68 	PROCESS_DPI_UNAWARE            = 0,
69 	PROCESS_SYSTEM_DPI_AWARE       = 1,
70 	PROCESS_PER_MONITOR_DPI_AWARE  = 2
71 } PROCESS_DPI_AWARENESS;
72 
73 typedef enum _MONITOR_DPI_TYPE {
74 	MDT_EFFECTIVE_DPI              = 0,
75 	MDT_ANGULAR_DPI                = 1,
76 	MDT_RAW_DPI                    = 2
77 } MONITOR_DPI_TYPE;
78 
79 #ifndef MONITOR_DEFAULTTONEAREST
80 #define MONITOR_DEFAULTTONULL            0
81 #define MONITOR_DEFAULTTOPRIMARY         1
82 #define MONITOR_DEFAULTTONEAREST         2
83 #endif
84 
85 static HRESULT (__stdcall *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS)  = NULL;
86 static HRESULT (__stdcall *GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*) = NULL;
87 static HRESULT (__stdcall *DwmIsCompositionEnabled)(BOOL *pfEnabled) = NULL;
88 static BOOL    (__stdcall *GetUserPreferredUILanguages)(DWORD dwFlags, PULONG pulNumLanguages, PZZWSTR pwszLanguagesBuffer, PULONG pcchLanguagesBuffer) = NULL;
89 
90 BOOL
my_GetUserPreferredUILanguages(DWORD dwFlags,PULONG pulNumLanguages,PZZWSTR pwszLanguagesBuffer,PULONG pcchLanguagesBuffer)91 my_GetUserPreferredUILanguages(
92 	DWORD dwFlags, PULONG pulNumLanguages,
93 	PZZWSTR pwszLanguagesBuffer, PULONG pcchLanguagesBuffer
94 ) {
95 	if ( GetUserPreferredUILanguages == NULL)
96 		return false;
97 	return GetUserPreferredUILanguages(dwFlags, pulNumLanguages, pwszLanguagesBuffer, pcchLanguagesBuffer);
98 }
99 
100 
101 void
dpi_change(void)102 dpi_change(void)
103 {
104 	UINT dx, dy;
105 	POINT pt = {1,1};
106 	HMONITOR m = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
107 	if ( GetDpiForMonitor && (GetDpiForMonitor( m, MDT_EFFECTIVE_DPI, &dx, &dy) == S_OK )) {
108 		guts. displayResolution. x = dx;
109 		guts. displayResolution. y = dy;
110 	}
111 }
112 
113 Bool
is_dwm_enabled(void)114 is_dwm_enabled( void )
115 {
116 	if ( DwmIsCompositionEnabled ) {
117 		BOOL b;
118 		if ( DwmIsCompositionEnabled(&b) != S_OK) goto NOPE;
119 		return b;
120 	} else {
121 		HKEY hKey;
122 		DWORD valSize = 256, valType = REG_SZ, dw = 0;
123 	NOPE:
124 		if ( LOBYTE(LOWORD(guts.version)) > 5 )
125 			return 1;
126 		valType = REG_DWORD;
127 		valSize = sizeof(DWORD);
128 		if ( RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\DWM", 0, KEY_READ, &hKey) == 0 ) {
129 			if ( RegQueryValueEx( hKey, "CompositionPolicy", NULL, &valType, ( LPBYTE)&dw, &valSize) != 0 )
130 				dw = 1;
131 			RegCloseKey( hKey);
132 			return dw == 0;
133 		} else
134 			return 0;
135 	}
136 }
137 
138 static void
load_function(HMODULE module,void ** ptr,const char * name)139 load_function(HMODULE module, void ** ptr, const char * name)
140 {
141 	(*ptr) = (void*) GetProcAddress(module, name);
142 }
143 
144 Bool
window_subsystem_init(char * error_buf)145 window_subsystem_init( char * error_buf)
146 {
147 	WNDCLASSW wc;
148 	HDC dc;
149 	HBITMAP hbm;
150 	OSVERSIONINFO os = { sizeof( OSVERSIONINFO)};
151 	GdiplusStartupInput gdiplusStartupInputDef = { 1, NULL, FALSE, FALSE };
152 
153 	guts. version  = GetVersion();
154 	GetVersionEx( &os);
155 	guts. utf8_prepend_0x202D =
156 		(( os.dwMajorVersion > 5) || (os.dwMajorVersion == 5 && os.dwMinorVersion > 1)) ?
157 					1 : 0;
158 	guts. alloc_utf8_to_wchar_visual =
159 		guts. utf8_prepend_0x202D ?
160 			alloc_utf8_to_wchar_visual :
161 			alloc_utf8_to_wchar;
162 	guts. mainThreadId = GetCurrentThreadId();
163 	guts. errorMode = SetErrorMode( SEM_FAILCRITICALERRORS);
164 	guts. desktopWindow = GetDesktopWindow();
165 	arrowCursor    = LoadCursor( NULL, IDC_ARROW);
166 
167 	memset( &wc, 0, sizeof( wc));
168 	wc.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
169 	wc.lpfnWndProc   = ( WNDPROC) generic_app_handler;
170 	wc.cbClsExtra    = 0;
171 	wc.cbWndExtra    = 0;
172 	wc.hInstance     = guts. instance;
173 	wc.hIcon         = LoadIcon( guts. instance, IDI_APPLICATION);
174 	wc.hCursor       = LoadCursor( NULL, IDC_ARROW);
175 	wc.hbrBackground = (HBRUSH)NULL;
176 	wc.lpszClassName = L"GenericApp";
177 	RegisterClassW( &wc);
178 
179 	memset( &wc, 0, sizeof( wc));
180 	wc.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
181 	wc.lpfnWndProc   = ( WNDPROC) generic_frame_handler;
182 	wc.cbClsExtra    = 0;
183 	wc.cbWndExtra    = 0;
184 	wc.hInstance     = guts. instance;
185 	wc.hIcon         = LoadIcon( guts. instance, IDI_APPLICATION);
186 	wc.hCursor       = arrowCursor;
187 	wc.hbrBackground = (HBRUSH)NULL;
188 	wc.lpszClassName = L"GenericFrame";
189 	RegisterClassW( &wc);
190 
191 	memset( &wc, 0, sizeof( wc));
192 	wc.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
193 	wc.lpfnWndProc   = ( WNDPROC) layered_frame_handler;
194 	wc.cbClsExtra    = 0;
195 	wc.cbWndExtra    = 0;
196 	wc.hInstance     = guts. instance;
197 	wc.hIcon         = LoadIcon( guts. instance, IDI_APPLICATION);
198 	wc.hCursor       = arrowCursor;
199 	wc.hbrBackground = (HBRUSH)NULL;
200 	wc.lpszClassName = L"LayeredFrame";
201 	RegisterClassW( &wc);
202 
203 	memset( &wc, 0, sizeof( wc));
204 	wc.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
205 	wc.lpfnWndProc   = ( WNDPROC) generic_view_handler;
206 	wc.cbClsExtra    = 0;
207 	wc.cbWndExtra    = 0;
208 	wc.hInstance     = guts. instance;
209 	wc.hIcon         = LoadIcon( guts. instance, IDI_APPLICATION);
210 	wc.hCursor       = NULL; // LoadCursor( NULL, IDC_ARROW);
211 	wc.hbrBackground = (HBRUSH)NULL;
212 	wc.lpszClassName = L"Generic";
213 	RegisterClassW( &wc);
214 
215 	stylusMan  = hash_create();
216 	stylusGpMan= hash_create();
217 	fontMan    = hash_create();
218 	patMan     = hash_create();
219 	menuMan    = hash_create();
220 	imageMan   = hash_create();
221 	regnodeMan = hash_create();
222 	myfontMan  = hash_create();
223 	menuBitmapMan  = hash_create();
224 	scriptCacheMan = hash_create();
225 	create_font_hash();
226 	{
227 		LOGBRUSH b = { BS_HOLLOW, 0, 0};
228 		Font f;
229 		hPenHollow        = CreatePen( PS_NULL, 0, 0);
230 		hBrushHollow      = CreateBrushIndirect( &b);
231 		hPatHollow. dotsCount = 0;
232 		hPatHollow. dotsPtr   = NULL;
233 		FONTSTRUCSIZE    = (char *)(&(f. name)) - (char *)(&f);
234 	}
235 
236 	if (!( dc = dc_alloc())) return false;
237 	guts. displayResolution. x = GetDeviceCaps( dc, LOGPIXELSX);
238 	guts. displayResolution. y = GetDeviceCaps( dc, LOGPIXELSY);
239 
240 	/* Win7 DWM */
241 #define LOAD_FUNC(m,f) load_function(m, (void**) &f, #f)
242 	if ( os.dwMajorVersion >= 5) {
243 		HMODULE mod = LoadLibrary("DWMAPI.DLL");
244 		if ( mod ) {
245 			LOAD_FUNC(mod, DwmIsCompositionEnabled);
246 		}
247 		mod = LoadLibrary("KERNEL32.DLL");
248 		if ( mod ) {
249 			LOAD_FUNC(mod, GetUserPreferredUILanguages);
250 		}
251 	}
252 
253 	/* Win8 - high dpi awareness stuff */
254 	if (( os.dwMajorVersion > 5) || (os.dwMajorVersion == 5 && os.dwMinorVersion > 1)) {
255 		HMODULE shcore = LoadLibrary("SHCORE.DLL");
256 		if ( shcore ) {
257 			LOAD_FUNC(shcore, SetProcessDpiAwareness);
258 			LOAD_FUNC(shcore, GetDpiForMonitor);
259 		}
260 		if (
261 			SetProcessDpiAwareness && GetDpiForMonitor &&
262 			(SetProcessDpiAwareness( PROCESS_PER_MONITOR_DPI_AWARE) == S_OK )
263 		)
264 			dpi_change();
265 	}
266 #undef LOAD_FUNC
267 
268 	{
269 		LOGFONT lf;
270 		HFONT   sfont;
271 
272 		// getting most common font name
273 		memset( &lf, 0, sizeof( lf));
274 		lf. lfCharSet        = OEM_CHARSET;
275 		lf. lfOutPrecision   = OUT_DEFAULT_PRECIS;
276 		lf. lfClipPrecision  = CLIP_DEFAULT_PRECIS;
277 		lf. lfQuality        = PROOF_QUALITY;
278 		lf. lfPitchAndFamily = DEFAULT_PITCH;
279 		sfont = SelectObject( dc, CreateFontIndirect( &lf));
280 		GetTextFace( dc, 256, guts. defaultSystemFont);
281 
282 		// getting common fixed font name
283 		lf. lfHeight = 320;
284 		lf. lfPitchAndFamily = FIXED_PITCH;
285 		DeleteObject( SelectObject( dc, CreateFontIndirect( &lf)));
286 		GetTextFace( dc, 256, guts. defaultFixedFont);
287 
288 		// getting common variable font name
289 		lf. lfPitchAndFamily = VARIABLE_PITCH;
290 		DeleteObject( SelectObject( dc, CreateFontIndirect( &lf)));
291 		GetTextFace( dc, 256, guts. defaultVariableFont);
292 		DeleteObject( SelectObject( dc, sfont));
293 
294 		// getting system font presets
295 		reset_system_fonts();
296 		register_mapper_fonts();
297 	}
298 
299 	memset( &guts. displayBMInfo, 0, sizeof( guts. displayBMInfo));
300 	guts. displayBMInfo. bmiHeader. biSize = sizeof( BITMAPINFO);
301 	if ( !( hbm = GetCurrentObject( dc, OBJ_BITMAP))) {
302 		apiErr;
303 		dc_free();
304 		return false;
305 	}
306 
307 	if ( !GetDIBits( dc, hbm, 0, 0, NULL, &guts. displayBMInfo, DIB_PAL_COLORS)) {
308 		guts. displayBMInfo. bmiHeader. biBitCount = GetDeviceCaps( dc, BITSPIXEL);
309 		guts. displayBMInfo. bmiHeader. biPlanes   = GetDeviceCaps( dc, PLANES);
310 	}
311 
312 	dc_free();
313 	guts. insertMode = true;
314 	guts. iconSizeSmall. x = GetSystemMetrics( SM_CXSMICON);
315 	guts. iconSizeSmall. y = GetSystemMetrics( SM_CYSMICON);
316 	guts. iconSizeLarge. x = GetSystemMetrics( SM_CXICON);
317 	guts. iconSizeLarge. y = GetSystemMetrics( SM_CYICON);
318 	guts. pointerSize. x   = GetSystemMetrics( SM_CXCURSOR);
319 	guts. pointerSize. y   = GetSystemMetrics( SM_CYCURSOR);
320 	list_create( &guts. transp, 8, 8);
321 	list_create( &guts. files, 8, 8);
322 	list_create( &guts. sockets, 8, 8);
323 
324 	// selecting locale layout, more or less latin-like
325 
326 	{
327 		char buf[ KL_NAMELENGTH * 2] = "";
328 		HKL current      = GetKeyboardLayout( 0);
329 		int i, j, size   = GetKeyboardLayoutList( 0, NULL);
330 		HKL * kl         = ( HKL *) malloc( sizeof( HKL) * size);
331 
332 		guts. keyLayout = NULL;
333 		if ( !GetKeyboardLayoutName( buf)) apiErr;
334 		for ( j = 0; j < ( sizeof( keyLayouts) / sizeof( char*)); j++) {
335 			if ( strncmp( buf + 4, keyLayouts[ j], 4) == 0) {
336 				guts. keyLayout = current;
337 				goto found_1;
338 			}
339 		}
340 
341 		if ( kl) {
342 			GetKeyboardLayoutList( size, kl);
343 			for ( i = 0; i < size; i++) {
344 				ActivateKeyboardLayout( kl[ i], 0);
345 				if ( !GetKeyboardLayoutName( buf)) apiErr;
346 				for ( j = 0; j < ( sizeof( keyLayouts) / sizeof( char*)); j++) {
347 					if ( strncmp( buf + 4, keyLayouts[ j], 4) == 0) {
348 						guts. keyLayout = kl[ i];
349 						goto found_2;
350 					}
351 				}
352 			}
353 		found_2:;
354 			ActivateKeyboardLayout( current, 0);
355 		}
356 	found_1:;
357 		free( kl);
358 	}
359 	guts. currentKeyState = guts. keyState;
360 	memset( guts. emptyKeyState, 0, sizeof( guts. emptyKeyState));
361 	guts. smDblClk. x = GetSystemMetrics( SM_CXDOUBLECLK);
362 	guts. smDblClk. y = GetSystemMetrics( SM_CYDOUBLECLK);
363 
364 	GdiplusStartup(&guts.gdiplusToken, &gdiplusStartupInputDef, NULL);
365 	{
366 		HRESULT r = OleInitialize(NULL);
367 		guts. ole_initialized = (r == S_OK || r == S_FALSE );
368 	}
369 
370 	return true;
371 }
372 
373 Bool
window_subsystem_get_options(int * argc,char *** argv)374 window_subsystem_get_options( int * argc, char *** argv)
375 {
376 	static char * win32_argv[] = {
377 		"debug", "turns on debugging"
378 	};
379 	*argv = win32_argv;
380 	*argc = sizeof( win32_argv) / sizeof( char*);
381 	return true;
382 }
383 
384 Bool
window_subsystem_set_option(char * option,char * value)385 window_subsystem_set_option( char * option, char * value)
386 {
387 	if ( strcmp( option, "debug") == 0) {
388 		debug = value ? *value != '0' : true;
389 		return true;
390 	}
391 	return false;
392 }
393 
394 static Bool
myfont_cleaner(void * value,int keyLen,void * key,void * dummy)395 myfont_cleaner( void * value, int keyLen, void * key, void * dummy)
396 {
397 	RemoveFontResource((LPCTSTR)key);
398 	return false;
399 }
400 
401 static Bool
menu_bitmap_cleaner(void * value,int keyLen,void * key,void * dummy)402 menu_bitmap_cleaner( void * value, int keyLen, void * key, void * dummy)
403 {
404 	DeleteObject((HBITMAP) value);
405 	return false;
406 }
407 
408 void
window_subsystem_done()409 window_subsystem_done()
410 {
411 	if (guts. ole_initialized)
412 		OleUninitialize();
413 	free( timeDefs);
414 	timeDefs = NULL;
415 	list_destroy( &guts. files);
416 
417 	if ( guts. socketMutex) {
418 		// appDead must be TRUE for this moment!
419 		appDead = true;
420 		CloseHandle( guts. socketMutex);
421 	}
422 
423 	list_destroy( &guts. sockets);
424 	list_destroy( &guts. transp);
425 	destroy_font_hash();
426 
427 	font_clean();
428 	stylus_clean();
429 
430 	stylus_gp_clean();
431 	GdiplusShutdown(guts.gdiplusToken);
432 
433 	hash_destroy( imageMan,   false);
434 	hash_destroy( menuMan,    false);
435 	hash_destroy( patMan,     true);
436 	hash_destroy( fontMan,    true);
437 	hash_destroy( stylusGpMan,true);
438 	hash_destroy( stylusMan,  true);
439 	hash_destroy( regnodeMan, false);
440 
441 	hash_first_that( menuBitmapMan, menu_bitmap_cleaner, NULL, NULL, NULL);
442 	hash_destroy( menuBitmapMan,  false);
443 	hash_destroy( scriptCacheMan,  true);
444 
445 	hash_first_that( myfontMan, myfont_cleaner, NULL, NULL, NULL);
446 	hash_destroy( myfontMan,  false);
447 	DeleteObject( hPenHollow);
448 	DeleteObject( hBrushHollow);
449 	if ( uncheckedBitmap && uncheckedBitmap != (HBITMAP)-1)
450 		DeleteObject( uncheckedBitmap);
451 	SetErrorMode( guts. errorMode);
452 }
453 
454 void
window_subsystem_cleanup()455 window_subsystem_cleanup()
456 {
457 	while ( guts. appLock > 0) apc_application_unlock( application);
458 	while ( guts. pointerLock < 0) {
459 		ShowCursor( 1);
460 		guts. pointerLock++;
461 	}
462 }
463 
464 static char err_buf[ 256] = "";
err_msg(DWORD errId,char * buffer)465 char * err_msg( DWORD errId, char * buffer)
466 {
467 	LPVOID lpMsgBuf;
468 	int len;
469 	if ( buffer == NULL) buffer = err_buf;
470 	FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errId,
471 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
472 		( LPTSTR) &lpMsgBuf, 0, NULL);
473 	if ( lpMsgBuf)
474 		strncpy( buffer, ( const char *) lpMsgBuf, 256);
475 	else
476 		buffer[0] = 0;
477 	buffer[ 255] = 0;
478 	LocalFree( lpMsgBuf);
479 
480 	/* chomp! */
481 	len = strlen(buffer);
482 	while ( len > 0) {
483 		len--;
484 		if ( buffer[len] != '\xD' && buffer[len] != '\xA' && buffer[len] != '.')
485 			break;
486 		buffer[len] = 0;
487 	}
488 
489 	return buffer;
490 }
491 
err_msg_gplus(GpStatus errId,char * buffer)492 char * err_msg_gplus( GpStatus errId, char * buffer)
493 {
494 	if ( buffer == nil) buffer = err_buf;
495 	switch(errId) {
496 	case Ok                        : strcpy(buffer, "Ok");                               break;
497 	case GenericError              : strcpy(buffer, "GDI+ generic error");               break;
498 	case InvalidParameter          : strcpy(buffer, "GDI+ invalid parameter");           break;
499 	case OutOfMemory               : strcpy(buffer, "GDI+ out of memory");               break;
500 	case ObjectBusy                : strcpy(buffer, "GDI+ object busy");                 break;
501 	case InsufficientBuffer        : strcpy(buffer, "GDI+ insufficient buffer");         break;
502 	case NotImplemented            : strcpy(buffer, "GDI+ not implemented");             break;
503 	case Win32Error                : strcpy(buffer, "GDI+ Win32 error");                 break;
504 	case WrongState                : strcpy(buffer, "GDI+ Wrong state");                 break;
505 	case Aborted                   : strcpy(buffer, "GDI+ aborted");                     break;
506 	case FileNotFound              : strcpy(buffer, "GDI+ file not found");              break;
507 	case ValueOverflow             : strcpy(buffer, "GDI+ value overflow");              break;
508 	case AccessDenied              : strcpy(buffer, "GDI+ access denied");               break;
509 	case UnknownImageFormat        : strcpy(buffer, "GDI+ unknown image format");        break;
510 	case FontFamilyNotFound        : strcpy(buffer, "GDI+ font family not found");       break;
511 	case FontStyleNotFound         : strcpy(buffer, "GDI+ font style not found");        break;
512 	case NotTrueTypeFont           : strcpy(buffer, "GDI+ not a TrueType font");         break;
513 	case UnsupportedGdiplusVersion : strcpy(buffer, "GDI+ unsipported Gdiplus version"); break;
514 	case GdiplusNotInitialized     : strcpy(buffer, "GDI+ not initialized");             break;
515 	case PropertyNotFound          : strcpy(buffer, "GDI+ property not found");          break;
516 	case PropertyNotSupported      : strcpy(buffer, "GDI+ property not supported");      break;
517 	case ProfileNotFound           : strcpy(buffer, "GDI+ profile not found");           break;
518 	default                        : strcpy(buffer, "GDI+ unknown error");
519 	}
520 	return buffer;
521 }
522 
523 char *
apc_last_error(void)524 apc_last_error(void)
525 {
526 	switch (apcError) {
527 	case errApcError              : return err_buf;
528 	case errOk                    : return NULL;
529 	case errInvObject             : return "Bad object";
530 	case errInvParams             : return "Bad parameters";
531 	case errInvWindowIcon         : return "Bad window icon";
532 	case errInvClipboardData      : return "Bad clipboard request";
533 	case errInvPrinter            : return "Bad printer request";
534 	case errNoPrinters            : return "No printers";
535 	case errUserCancelled         : return "User cancelled";
536 	default                       : return "Unknown error";
537 	}
538 }
539 
move_back(PWidget self,PWidget child,int * delta)540 static Bool move_back( PWidget self, PWidget child, int * delta)
541 {
542 	RECT r;
543 	int oStage = child-> stage;
544 
545 	if ( !dsys( child) options. aptClipOwner) return false;
546 
547 	child-> stage = csFrozen;
548 	GetWindowRect( DHANDLE( child), &r);
549 	if ( dsys( child) options. aptClipOwner)
550 		MapWindowPoints( NULL, ( HWND) self-> handle, ( LPPOINT)&r, 2);
551 	SetWindowPos( DHANDLE( child), 0, r. left, r. top + *delta, 0, 0,
552 		SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
553 	child-> stage = oStage;
554 
555 	return false;
556 }
557 
558 
559 static Bool
local_wnd(HWND who,HWND client)560 local_wnd( HWND who, HWND client)
561 {
562 	PComponent v;
563 	Handle self;
564 	if ( who == client)
565 		return true;
566 	self = GetWindowLongPtr( client, GWLP_USERDATA);
567 	v = (PComponent) hwnd_to_view( who);
568 	while (v && ( Handle) v != application)
569 	{
570 		if ( (Handle)v == self) return true;
571 		v = ( PComponent) ( v-> owner);
572 	}
573 	return false;
574 }
575 
576 extern Handle ctx_kb2VK[];
577 extern Handle ctx_kb2VK2[];
578 extern Handle ctx_kb2VK3[];
579 
580 static Bool
find_oid(PAbstractMenu menu,PMenuItemReg m,int id)581 find_oid( PAbstractMenu menu, PMenuItemReg m, int id)
582 {
583 	return m-> down && ( m-> down-> id == id);
584 }
585 
586 Handle ctx_deadkeys[] = {
587 	0x5E, 0x302, // Circumflex accent
588 	0x60, 0x300, // Grave accent
589 	0xA8, 0x308, // Diaeresis
590 	0xB4, 0x301, // Acute accent
591 	0xB8, 0x327, // Cedilla
592 	endCtx
593 };
594 
595 static void
zorder_sync(Handle self,HWND me,LPWINDOWPOS lp)596 zorder_sync( Handle self, HWND me, LPWINDOWPOS lp)
597 {
598 	if ( lp-> hwndInsertAfter == HWND_TOP ||
599 		lp-> hwndInsertAfter == HWND_NOTOPMOST ||
600 		lp-> hwndInsertAfter == HWND_TOPMOST) {
601 		me = GetNextWindow( me, GW_HWNDPREV);
602 		if ( me)
603 			PostMessage( me, WM_ZORDERSYNC, 0, 0);
604 	} else if ( lp-> hwndInsertAfter == HWND_BOTTOM) {
605 		me = GetNextWindow( me, GW_HWNDNEXT);
606 		if ( me)
607 			PostMessage( me, WM_ZORDERSYNC, 0, 0);
608 	}
609 }
610 
611 static Bool
id_match(Handle self,PMenuItemReg m,void * params)612 id_match( Handle self, PMenuItemReg m, void * params)
613 {
614 	return m-> id == *(( int*) params);
615 }
616 
generic_view_handler(HWND win,UINT msg,WPARAM mp1,LPARAM mp2)617 LRESULT CALLBACK generic_view_handler( HWND win, UINT  msg, WPARAM mp1, LPARAM mp2)
618 {
619 	LRESULT ret = 0;
620 	Handle  self   = GetWindowLongPtr( win, GWLP_USERDATA);
621 	PWidget v      = ( PWidget) self;
622 	UINT    orgMsg = msg;
623 	Event   ev;
624 	Bool    hiStage   = false;
625 	Bool    message_result = true;
626 
627 	if ( !self || appDead)
628 		return DefWindowProcW( win, msg, mp1, mp2);
629 
630 	memset( &ev, 0, sizeof (ev));
631 	ev. gen. source = self;
632 
633 	switch ( msg) {
634 	case WM_NCACTIVATE:
635 		// if activation or deactivation is concerned with declipped window ( e.g.self),
636 		// notify its top level frame so that it will have the chance to redraw itself correspondingly
637 		if ( is_declipped_child( self) && !Widget_is_child( hwnd_to_view(( HWND) mp2), hwnd_top_level( self))) {
638 			Handle x = hwnd_top_level( self);
639 			if ( x) SendMessage( DHANDLE( x), WM_NCACTIVATE, mp1, mp2);
640 		}
641 		break;
642 	case WM_MOUSEACTIVATE:
643 		// if pointing to non-active frame, but its declipped child is active at the moment,
644 		// cancel activation - it could produce unwilling focus changes
645 		if ( sys className == WC_FRAME) {
646 			Handle x = hwnd_to_view( GetActiveWindow());
647 			if ( is_declipped_child(x) && Widget_is_child( x, self))
648 				return MA_NOACTIVATE;
649 		}
650 		break;
651 	case WM_CLOSE:
652 		if ( guts. focSysDialog) return 0;
653 		if ( sys className != WC_FRAME)
654 			return 0;
655 		break;
656 	case WM_COMMAND:
657 		if (( HIWORD( mp1) == 0 /* menu source */) && ( mp2 == 0)) {
658 			if ( LOWORD( mp1) <= MENU_ID_AUTOSTART) {
659 				HWND active = GetFocus();
660 				if ( active != NULL) SendMessage( active, LOWORD( mp1), 0, 0);
661 			} else if ( sys lastMenu) {
662 				PAbstractMenu a = ( PAbstractMenu) sys lastMenu;
663 				if ( a-> stage <= csNormal)
664 					a-> self-> sub_call_id(( Handle) a, LOWORD( mp1) - MENU_ID_AUTOSTART);
665 			}
666 		}
667 		break;
668 	case WM_CONTEXTMENU:
669 		{
670 			POINT a;
671 			a. x = ( short)LOWORD( mp2);
672 			a. y = ( short)HIWORD( mp2);
673 			ev. cmd       = cmPopup;
674 			// mouse event
675 			ev. gen. B    = ( GetKeyState( VK_LBUTTON) < 0) | ( GetKeyState( VK_RBUTTON) < 0);
676 			if ( !ev. gen. B && GetSystemMetrics( SM_MOUSEPRESENT))
677 				GetCursorPos(( POINT*) &a);
678 
679 			MapWindowPoints( NULL, win, &a, 1);
680 			ev. gen. P. x = a. x;
681 			ev. gen. P. y = sys lastSize. y - a. y - 1;
682 		}
683 		break;
684 	case WM_DRAG_RESPONSE:
685 		SetCursor( sys pointer );
686 		break;
687 	case WM_DRAWITEM:
688 		{
689 			DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*) mp2;
690 			if ( dis-> CtlType == ODT_MENU && dis-> itemData != 0) {
691 				RECT r;
692 				self = (Handle) dis-> itemData;
693 				v = (PWidget) self;
694 				GetClientRect(WindowFromDC(dis->hDC), &r);
695 				ev.cmd          = cmMenuItemPaint;
696 				ev.gen.i        = (Handle) dis-> itemID - MENU_ID_AUTOSTART;
697 				ev.gen.p        = (void*) dis->hDC;
698 				ev.gen.B        = ((dis-> itemState & ODS_SELECTED) != 0);
699 				ev.gen.P.x      = r.right;
700 				ev.gen.P.y      = r.bottom;
701 				ev.gen.R.left   = dis-> rcItem.left;
702 				ev.gen.R.bottom = r.bottom - dis-> rcItem.bottom;
703 				ev.gen.R.right  = dis-> rcItem.right - 1;
704 				ev.gen.R.top    = r.bottom - dis-> rcItem.top - 1;
705 			}
706 		}
707 		break;
708 	case WM_ENABLE:
709 		ev. cmd = mp1 ? cmEnable : cmDisable;
710 		hiStage = true;
711 		break;
712 	case WM_ERASEBKGND:
713 		return 1;
714 	case WM_FORCEFOCUS:
715 		if ( mp2)
716 			((( PWidget) mp2)-> self)-> set_selected(( Handle) mp2, 1);
717 		return 0;
718 	case WM_HASMATE:
719 		*(( Handle*) mp2) = self;
720 		return HASMATE_MAGIC;
721 	case WM_IME_CHAR:
722 		if ( apc_widget_is_responsive( self)) {
723 			ev. cmd = cmKeyDown;
724 			ev. key. mod  = kmUnicode;
725 			ev. key. key  = kbNoKey;
726 			ev. key. code = mp1;
727 		}
728 		break;
729 	case WM_SYSKEYDOWN:
730 	case WM_SYSKEYUP:
731 		if ( mp2 & ( 1 << 29)) ev. key. mod = kmAlt;
732 	case WM_KEYDOWN:
733 	case WM_KEYUP:
734 		if ( apc_widget_is_responsive( self)) {
735 			BYTE * keyState;
736 			Bool up = ( msg == WM_KEYUP) || ( msg == WM_SYSKEYUP);
737 			Bool extended = mp2 & ( 1 << 24);
738 			UINT scan = ( HIWORD( mp2) & 0xFF) | ( up ? 0x80000000 : 0);
739 			int deadPollCount = 0;
740 			HKL kl = GetKeyboardLayout(0);
741 
742 			// basic assignments
743 			ev. cmd = up ? cmKeyUp : cmKeyDown;
744 			ev. key. key    = ctx_remap_def( mp1, ctx_kb2VK, false, kbNoKey);
745 			ev. key. code   = mp1;
746 			ev. key. repeat = mp2 & 0x000000FF;
747 
748 			// VK validations
749 			if ( extended) {
750 				int ks = ev. key. key;
751 				ev. key. key = ctx_remap_def( ks, ctx_kb2VK3, true, ks);
752 				if ( ev. key. key != ks)
753 					extended = false; // avoid (Ctrl|Alt)R+KeyPad combinations
754 			} else if ( mp1 >= VK_NUMPAD0 && mp1 <= VK_DIVIDE)
755 				extended = true; // include numpads
756 
757 			ev. key. mod   = 0 |
758 				( extended ? kmKeyPad : 0) |
759 				(( GetKeyState( VK_SHIFT)   < 0) ? kmShift : 0) |
760 				(( GetKeyState( VK_CONTROL) < 0) ? kmCtrl  : 0) |
761 				(( GetKeyState( VK_MENU)    < 0) ? kmAlt   : 0);
762 
763 			keyState = guts. keyState;
764 AGAIN:
765 			if ( PApplication(application)-> wantUnicodeInput) {
766 				WCHAR keys[ 2];
767 				// unicode mapping
768 				switch ( ToUnicodeEx( mp1, scan, keyState, keys, 2, 0, kl)) {
769 				case 1: // char
770 					if ( lastDeadKey ) {
771 						WCHAR wcBuffer[3];
772 						WCHAR out[3];
773 						wcBuffer[0] = keys[0];
774 						wcBuffer[1] = lastDeadKey;
775 						wcBuffer[2] = '\0';
776 						if ( FoldStringW(MAP_PRECOMPOSED, (LPWSTR) wcBuffer, 3, (LPWSTR) out, 3) )
777 							keys[0] = out[0];
778 					}
779 					if ( !deadPollCount && ( GetKeyState( VK_MENU) < 0) && ( GetKeyState( VK_SHIFT) >= 0)) {
780 						WCHAR keys2[2];
781 						if (( ToUnicodeEx( mp1, scan, guts. emptyKeyState, keys2, 2, 0, kl) == 1) &&
782 							( keys2[0] != keys[0])) {
783 							/* example - (AltGr+2) == '@' on danish keyboard.
784 								this hack is to tell whether the key without mods
785 								will give same character code ...  */
786 							ev. key. mod &= ~(kmAlt|kmCtrl|kmShift);
787 						}
788 					}
789 					if (!up) lastDeadKey = 0;
790 					break;
791 				case 2: { // dead key
792 						lastDeadKey = ctx_remap_def( keys[0], ctx_deadkeys, true, keys[0]);
793 						keys[ 0] = 0;
794 						   ev. key. mod |= kmDeadKey;
795 					}
796 					break;
797 				case 0: // virtual key
798 					if ( deadPollCount == 0) {
799 					/* can't have character code - maybe fish out without mods? */
800 						keyState = guts. emptyKeyState;
801 						deadPollCount = 1;
802 						goto AGAIN;
803 					} else {
804 					/* same meaning without mods, no code anyway */
805 						keys[ 0] = 0;
806 					}
807 					if (!up) lastDeadKey = 0;
808 					break;
809 				default:
810 					ev. key. mod |= kmDeadKey;
811 					if (!up) lastDeadKey = 0;
812 				}
813 				ev. key. code = keys[ 0];
814 				ev. key. mod |= kmUnicode;
815 			} else {
816 				BYTE keys[ 4];
817 				switch ( ToAsciiEx( mp1, scan, keyState, (LPWORD) keys, 0, kl)) {
818 				case 1: // char
819 					if ( lastDeadKey ) {
820 						BYTE cBuffer[3];
821 						BYTE out[3];
822 						cBuffer[0] = keys[0];
823 						cBuffer[1] = lastDeadKey;
824 						cBuffer[2] = '\0';
825 						if ( FoldStringA(MAP_PRECOMPOSED, (LPSTR) cBuffer, 3, (LPSTR) out, 3) )
826 		   					keys[0] = out[0];
827 					}
828 					if ( !deadPollCount && ( GetKeyState( VK_MENU) < 0) && ( GetKeyState( VK_SHIFT) >= 0)) {
829 						BYTE keys2[4];
830 						if (( ToAsciiEx( mp1, scan, guts. emptyKeyState, (LPWORD) keys2, 0, kl) == 1) &&
831 							( keys2[0] != keys[0])) {
832 							/* example - (AltGr+2) == '@' on danish keyboard.
833 								this hack is to tell whether the key without mods
834 								will give same character code ...  */
835 							ev. key. mod &= ~(kmAlt|kmCtrl|kmShift);
836 						}
837 					}
838 					break;
839 				case 2: // dead key
840 					lastDeadKey = keys[0];
841 					keys[ 0] = 0;
842 						ev. key. mod |= kmDeadKey;
843 					break;
844 				case 0: // virtual key
845 					if ( deadPollCount == 0) {
846 					/* can't have character code - maybe fish out without mods? */
847 						keyState = guts. emptyKeyState;
848 						deadPollCount = 1;
849 						goto AGAIN;
850 					} else {
851 					/* same meaning without mods, no code anyway */
852 						keys[ 0] = 0;
853 					}
854 					if (!up) lastDeadKey = 0;
855 					break;
856 				default:
857 					ev. key. mod |= kmDeadKey;
858 					if (!up) lastDeadKey = 0;
859 				}
860 				ev. key. code = keys[ 0];
861 			}
862 
863 			// simulated key codes
864 			if ( ev. key. key == kbTab && ( ev. key. mod & kmShift))
865 				ev. key. key = kbBackTab;
866 
867 			if ( ev. key. code >= 'A' && ev. key. code <= 'z' && ev. key. mod & kmCtrl) {
868 				ev. key. code = toupper(ev. key. code & 0xFF) - '@';
869 				if (!( ev. key. mod & kmShift)) ev. key. code = tolower( ev. key. code);
870 			}
871 		}
872 		break;
873 	case WM_INITMENUPOPUP:
874 		if ( HIWORD( mp2)) break; // do not use system popup
875 	case WM_INITMENU:
876 		{
877 			PMenuWndData mwd = ( PMenuWndData) hash_fetch( menuMan, &mp1, sizeof( void*));
878 			PMenuItemReg m = NULL;
879 			sys lastMenu = mwd ? mwd-> menu : NULL_HANDLE;
880 			if ( mwd && mwd-> menu && ( PAbstractMenu(mwd-> menu)->stage <= csNormal)) {
881 				m = ( PMenuItemReg) AbstractMenu_first_that( mwd-> menu, find_oid, INT2PTR(void*,mwd->id), true);
882 				hiStage    = true;
883 				ev. cmd    = cmMenu;
884 				ev. gen. H = mwd-> menu;
885 				ev. gen. i = m ? m-> id : 0;
886 			}
887 			if (( msg == WM_INITMENUPOPUP) && ( m == NULL))
888 				ev. cmd = 0;
889 		}
890 		break;
891 	case WM_KILLFOCUS:
892 		if (( HWND) mp1 != win) {
893 			ev. cmd = cmReleaseFocus;
894 			hiStage = true;
895 			apt_assign( aptFocused, 0);
896 			DestroyCaret();
897 		}
898 		break;
899 	case WM_LBUTTONDOWN:
900 		ev. pos. button = mbLeft;
901 		goto MB_DOWN;
902 	case WM_RBUTTONDOWN:
903 		ev. pos. button = mbRight;
904 		goto MB_DOWN;
905 	case WM_MBUTTONDOWN:
906 		ev. pos. button = mbMiddle;
907 		goto MB_DOWN;
908 	case WM_XBUTTONDOWN:
909 		ev. pos. button = (HIWORD(mp1) == XBUTTON1) ? mb4 : mb5;
910 		goto MB_DOWN;
911 	case WM_LBUTTONUP:
912 		ev. pos. button = mbLeft;
913 		goto MB_UP;
914 	case WM_RBUTTONUP:
915 		ev. pos. button = mbRight;
916 		goto MB_UP;
917 	case WM_MBUTTONUP:
918 		ev. pos. button = mbMiddle;
919 		goto MB_UP;
920 	case WM_XBUTTONUP:
921 		ev. pos. button = (HIWORD(mp1) == XBUTTON1) ? mb4 : mb5;
922 		goto MB_UP;
923 	case WM_LBUTTONDBLCLK:
924 		ev. pos. button = mbLeft;
925 		goto MB_DBLCLK;
926 	case WM_RBUTTONDBLCLK:
927 		ev. pos. button = mbRight;
928 		goto MB_DBLCLK;
929 	case WM_MBUTTONDBLCLK:
930 		ev. pos. button = mbMiddle;
931 		goto MB_DBLCLK;
932 	case WM_XBUTTONDBLCLK:
933 		ev. pos. button = (HIWORD(mp1) == XBUTTON1) ? mb4 : mb5;
934 		goto MB_DBLCLK;
935 	case WM_LMOUSECLICK:
936 		ev. pos. button = mbLeft;
937 		goto MB_CLICK;
938 	case WM_RMOUSECLICK:
939 		ev. pos. button = mbRight;
940 		goto MB_CLICK;
941 	case WM_MMOUSECLICK:
942 		ev. pos. button = mbMiddle;
943 		goto MB_CLICK;
944 	case WM_XMOUSECLICK:
945 		ev. pos. button = (HIWORD(mp1) == XBUTTON1) ? mb4 : mb5;
946 		goto MB_CLICK;
947 	case WM_MOUSEWHEEL:
948 		{
949 			POINT p;
950 			p. x = (short)LOWORD( mp2);
951 			p. y = (short)HIWORD( mp2);
952 			ev. cmd         = cmMouseWheel;
953 			ev. pos. button = ( short) HIWORD( mp1);
954 			MapWindowPoints( NULL, win, &p, 1);
955 			ev. pos. where. x = p. x;
956 			ev. pos. where. y = sys lastSize. y - p. y - 1;
957 		}
958 		goto MB_MAIN_NOPOS;
959 	case WM_MOUSEMOVE:
960 		ev. cmd = cmMouseMove;
961 		if ( self != lastMouseOver) {
962 			Handle old = lastMouseOver;
963 			lastMouseOver = self;
964 			if ( old && ( PWidget( old)-> stage == csNormal))
965 				SendMessage(( HWND)(( PWidget) old)-> handle, WM_MOUSEEXIT, mp1, mp2);
966 			SendMessage( win, WM_MOUSEENTER, mp1, mp2);
967 			if ( !guts. mouseTimer) {
968 				guts. mouseTimer = 1;
969 				if ( !SetTimer( dsys(application)handle, TID_USERMAX, 100, NULL)) apiErr;
970 			}
971 		}
972 		goto MB_MAIN;
973 	case WM_MOUSEENTER:
974 		ev. cmd = cmMouseEnter;
975 		goto MB_MAIN;
976 	case WM_MOUSEEXIT:
977 		ev. cmd = cmMouseLeave;
978 		goto MB_MAIN;
979 	MB_DOWN:
980 		ev. cmd = cmMouseDown;
981 		goto MB_MAINACT;
982 	MB_UP:
983 		ev. cmd = cmMouseUp;
984 		goto MB_MAINACT;
985 	MB_DBLCLK:
986 		ev. pos. dblclk = 1;
987 	MB_CLICK:
988 		ev. cmd = cmMouseClick;
989 		goto MB_MAINACT;
990 	MB_MAINACT:
991 		if ( !is_apt( aptEnabled) || !apc_widget_is_responsive( self))
992 		{
993 			if ( ev. cmd == cmMouseDown || (ev. cmd == cmMouseClick && ev. pos. dblclk))
994 				MessageBeep( MB_OK);
995 			return 0;
996 		}
997 		goto MB_MAIN;
998 	MB_MAIN:
999 		if ( ev. cmd == cmMouseDown && !is_apt( aptFirstClick)) {
1000 			Handle x = self;
1001 			while ( dsys(x) className != WC_FRAME && ( x != application)) x = (( PWidget) x)-> owner;
1002 			if ( x != application && !local_wnd( GetActiveWindow(), DHANDLE( x)))
1003 			{
1004 				ev. cmd = 0; // yes, we abandon mousedown but we should force selection:
1005 				if ((( PApplication) application)-> hintUnder == self) v-> self-> set_hintVisible( self, 0);
1006 				if (( v-> options. optSelectable) && ( v-> selectingButtons & ev. pos. button))
1007 					apc_widget_set_focused( self);
1008 			}
1009 		}
1010 		ev. pos. where. x = (short)LOWORD( mp2);
1011 		ev. pos. where. y = sys lastSize. y - (short)HIWORD( mp2) - 1;
1012 	MB_MAIN_NOPOS:
1013 		ev. pos. mod      = 0 |
1014 			(( mp1 & MK_CONTROL )         ? kmCtrl   : 0) |
1015 			(( mp1 & MK_SHIFT   )         ? kmShift  : 0) |
1016 			(( GetKeyState( VK_MENU) < 0) ? kmAlt    : 0) |
1017 			apc_pointer_get_state(self)
1018 		;
1019 		break;
1020 	case WM_MEASUREITEM: {
1021 		MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT*) mp2;
1022 		if ( mis-> CtlType == ODT_MENU && mis-> itemData != 0) {
1023 			ev.cmd     = cmMenuItemMeasure;
1024 			self = (Handle) mis-> itemData;
1025 			v = (PWidget) self;
1026 			ev.gen.i   = (Handle) mis-> itemID - MENU_ID_AUTOSTART;
1027 			ev.gen.P.x = ev.gen.P.y = 0;
1028 		}
1029 		break;
1030 	}
1031 	case WM_MENUCHAR: {
1032 		int key;
1033 		PMenuWndData mwd;
1034 		ev. key. key    = ctx_remap_def( mp1, ctx_kb2VK2, false, kbNoKey);
1035 		ev. key. code   = LOWORD(mp1);
1036 		ev. key. mod   |=
1037 			(( GetKeyState( VK_SHIFT)   < 0) ? kmShift : 0) |
1038 			(( GetKeyState( VK_CONTROL) < 0) ? kmCtrl  : 0) |
1039 			(( GetKeyState( VK_MENU)    < 0) ? kmAlt   : 0);
1040 		if (( ev. key. mod & kmCtrl) && ( ev. key. code <= 'z'))
1041 			ev. key. code += 'A' - 1;
1042 		key = CAbstractMenu-> translate_key( NULL_HANDLE, ev. key. code, ev. key. key, ev. key. mod);
1043 		if ( v-> self-> process_accel( self, key))
1044 			return MAKELONG( 0, MNC_CLOSE);
1045 
1046 		ev.key.code = tolower(ev.key.code);
1047 		if (( mwd = (MenuWndData*) hash_fetch(menuMan, &mp2, sizeof(mp2))) != NULL) {
1048 			int pos = 0;
1049 			PMenuItemReg m = CAbstractMenu(mwd->menu)-> first_that(mwd->menu, (void*)id_match, &mwd->id, false);
1050 			while ( m != NULL ) {
1051 				if ( m-> flags.custom_draw && m-> text != NULL ) {
1052 					char * t = m-> text;
1053 					while (*t) {
1054 						if ( t[0] == '~' && tolower(t[1]) == ev.key.code )
1055 							return MAKELONG( pos, MNC_EXECUTE);
1056 						t++;
1057 					}
1058 				}
1059 				m = m-> next;
1060 				pos++;
1061 			}
1062 		}
1063 		break;
1064 	}
1065 	case WM_SYNCMOVE: {
1066 		Handle parent = v-> self-> get_parent(( Handle) v);
1067 		if ( parent) {
1068 			Point pos  = var self-> get_origin( self);
1069 			ev. cmd    = cmMove;
1070 			ev. gen. P = pos;
1071 			if ( pos. x == var pos. x && pos. y == var pos. y) ev. cmd = 0;
1072 		}
1073 		break;
1074 	}
1075 	case WM_MOVE: {
1076 		Handle parent = v-> self-> get_parent(( Handle) v);
1077 		if ( parent) {
1078 			Point sz = CWidget(parent)-> get_size( parent);
1079 			ev. cmd = cmMove;
1080 			ev. gen . P. x = ( short) LOWORD( mp2);
1081 			ev. gen . P. y = sz. y - ( short) HIWORD( mp2) - sys yOverride;
1082 			if ( is_apt( aptTransparent))
1083 				InvalidateRect( win, NULL, false);
1084 		}
1085 		break;
1086 	}
1087 	case WM_NCHITTEST:
1088 		if ( guts. focSysDialog) return HTERROR;
1089 		// dlg protect code - protecting from user actions
1090 		if ( !guts. focSysDisabled && ( Application_map_focus( application, self) != self))
1091 			return HTERROR;
1092 		break;
1093 	case WM_PAINT:
1094 		ev. cmd = cmPaint;
1095 		if (
1096 			( sys className == WC_CUSTOM) &&
1097 			( var stage == csNormal) &&
1098 			( list_index_of( &guts. transp, self) >= 0)
1099 			)
1100 			return 0;
1101 
1102 		if (
1103 			( var self->get_locked(self) > 0) || /* or WM_PAINT bashing occurs */
1104 			is_apt( aptLayered ) ||
1105 			( opt_InPaint && !is_apt(aptWM_PAINT) )
1106 		) {
1107 			PAINTSTRUCT ps;
1108 			BeginPaint(win, &ps);
1109 			EndPaint(win, &ps);
1110 			return 0;
1111 		}
1112 
1113 		break;
1114 	case WM_QUERYNEWPALETTE:
1115 		return palette_change( self);
1116 	case WM_PALETTECHANGED:
1117 		if (( HWND) mp1 != win) {
1118 			Handle mp = hwnd_to_view(( HWND) mp1);
1119 			if ( mp && ( hwnd_top_level( mp) == hwnd_top_level( self)))
1120 				return 0;
1121 			palette_change( self);
1122 		}
1123 		break;
1124 	case WM_POSTAL:
1125 		ev. cmd    = cmPost;
1126 		ev. gen. H = ( Handle) mp1;
1127 		ev. gen. p = ( void *) mp2;
1128 		break;
1129 	case WM_PRIMA_CREATE:
1130 		ev. cmd = cmSetup;
1131 		break;
1132 	case WM_REPAINT_LAYERED:
1133 		if ( var stage == csNormal )
1134 			hwnd_repaint_layered( self, true );
1135 		break;
1136 	case WM_SETFOCUS:
1137 		if ( guts. focSysDialog) return 1;
1138 		// dlg protect code - general case
1139 		if ( !guts. focSysDisabled && !guts. focSysGranted) {
1140 			Handle hf = Application_map_focus( application, self);
1141 			if ( hf != self) {
1142 				PostMessage( win, WM_FORCEFOCUS, 0, ( LPARAM) hf);
1143 				return 1;
1144 			}
1145 		}
1146 		if (( HWND) mp1 != win) {
1147 			ev. cmd = cmReceiveFocus;
1148 			hiStage = true;
1149 			apt_assign( aptFocused, 1);
1150 			cursor_update( self);
1151 		}
1152 		break;
1153 	case WM_SETVISIBLE:
1154 	if ( list_index_of( &guts. transp, self) < 0) {
1155 		if ( v-> stage <= csNormal) ev. cmd = mp1 ? cmShow : cmHide;
1156 		hiStage = true;
1157 		apt_assign( aptVisible, mp1);
1158 	}
1159 	break;
1160 	case WM_SIZE:
1161 		ev. cmd = cmSize;
1162 		ev. gen. R. left   = sys lastSize. x;
1163 		ev. gen. R. bottom = sys lastSize. y;
1164 		sys lastSize. x    = ev. gen. R. right  = ev. gen . P. x = ( short) LOWORD( mp2);
1165 		sys lastSize. y    = ev. gen. R. top    = ev. gen . P. y = ( short) HIWORD( mp2);
1166 		if ( ev. gen. R. top != ev. gen. R. bottom) {
1167 			int delta = ev. gen. R. top - ev. gen. R. bottom;
1168 			Widget_first_that( self, move_back, &delta);
1169 			if ( is_apt( aptFocused)) cursor_update(( Handle) self);
1170 		}
1171 		if ( sys sizeLockLevel == 0 && var stage <= csNormal)
1172 			var virtualSize = sys lastSize;
1173 		break;
1174 	case WM_WINDOWPOSCHANGING: {
1175 		LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
1176 		if ( sys className == WC_CUSTOM) {
1177 			if (( l-> flags & SWP_NOSIZE) == 0) {
1178 				ev. cmd = cmCalcBounds;
1179 				ev. gen. R. right = l-> cx;
1180 				ev. gen. R. top   = l-> cy;
1181 			}
1182 		}
1183 		if (( l-> flags & SWP_NOZORDER) == 0)
1184 			zorder_sync( self, win, l);
1185 		break;
1186 	}
1187 	case WM_WINDOWPOSCHANGED: {
1188 		LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
1189 		if (( l-> flags & SWP_NOZORDER) == 0)
1190 			PostMessage( win, WM_ZORDERSYNC, 0, 0);
1191 		if (( l-> flags & SWP_NOSIZE) == 0) {
1192 			sys yOverride = l-> cy;
1193 			SendMessage( win, WM_SYNCMOVE, 0, 0);
1194 		}
1195 		if ( l-> flags & SWP_HIDEWINDOW) SendMessage( win, WM_SETVISIBLE, 0, 0);
1196 		if ( l-> flags & SWP_SHOWWINDOW) SendMessage( win, WM_SETVISIBLE, 1, 0);
1197 		break;
1198 	}
1199 	case WM_ZORDERSYNC:
1200 		ev. cmd = cmZOrderChanged;
1201 		break;
1202 	}
1203 
1204 	if ( hiStage)
1205 		ret = DefWindowProcW( win, msg, mp1, mp2);
1206 
1207 	if ( ev. cmd)
1208 		message_result = v-> self-> message( self, &ev);
1209 	else
1210 		ev. cmd = orgMsg;
1211 
1212 	if ( v-> stage > csNormal) orgMsg = 0; // protect us from dead body
1213 
1214 	switch ( orgMsg) {
1215 	case WM_DRAWITEM: {
1216 		DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*) mp2;
1217 		if ( dis-> CtlType == ODT_MENU && dis-> itemData != 0)
1218 			return (LRESULT) 1;
1219 		break;
1220 	}
1221 	case WM_DESTROY:
1222 		v-> handle = NULL_HANDLE;       // tell apc not to kill this HWND
1223 		SetWindowLongPtr( win, GWLP_USERDATA, 0);
1224 		Object_destroy(( Handle) v);
1225 		break;
1226 	case WM_PAINT:
1227 		return 0;
1228 	case WM_SYSKEYDOWN:
1229 		if ( !message_result)
1230 			guts. dont_xlate_message = true;
1231 		break;
1232 	case WM_SYSKEYUP:
1233 		// ev. cmd = 1; // forced call DefWindowProc superseded for test reasons
1234 		break;
1235 	case WM_MEASUREITEM: {
1236 		MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT*) mp2;
1237 		if ( mis-> CtlType == ODT_MENU && mis-> itemData != 0) {
1238 			mis-> itemWidth  = ev.gen.P.x;
1239 			mis-> itemHeight = ev.gen.P.y;
1240 			return (LRESULT) 1;
1241 		}
1242 		break;
1243 	}
1244 	case WM_MOUSEMOVE:
1245 		SetCursor( is_apt( aptEnabled) ? sys pointer : arrowCursor);
1246 		break;
1247 	case WM_MOUSEWHEEL:
1248 		return ( LRESULT)1;
1249 	case WM_WINDOWPOSCHANGING: {
1250 		LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
1251 		if ( sys className == WC_CUSTOM) {
1252 			if (( l-> flags & SWP_NOSIZE) == 0) {
1253 				int dy = l-> cy - ev. gen. R. top;
1254 				l-> cx = ev. gen. R. right;
1255 				l-> cy = ev. gen. R. top;
1256 				l-> y += dy;
1257 			}
1258 			return false;
1259 		}
1260 		if (( l-> flags & SWP_NOZORDER) == 0)
1261 			zorder_sync( self, win, l);
1262 		break;
1263 	}
1264 	}
1265 
1266 	if ( ev. cmd && !hiStage)
1267 		ret = DefWindowProcW( win, msg, mp1, mp2);
1268 
1269 	return ret;
1270 }
1271 
generic_frame_handler(HWND win,UINT msg,WPARAM mp1,LPARAM mp2)1272 LRESULT CALLBACK generic_frame_handler( HWND win, UINT  msg, WPARAM mp1, LPARAM mp2)
1273 {
1274 	LRESULT ret = 0;
1275 	Handle  self   = GetWindowLongPtr( win, GWLP_USERDATA);
1276 	PWidget   v    = ( PWidget) self;
1277 	UINT    orgMsg = msg;
1278 	Event   ev;
1279 	Bool    hiStage   = false;
1280 
1281 	if ( !self)
1282 		return DefWindowProcW( win, msg, mp1, mp2);
1283 
1284 	memset( &ev, 0, sizeof (ev));
1285 	ev. gen. source = self;
1286 
1287 	switch ( msg) {
1288 	case WM_ACTIVATE:
1289 		if ( guts. focSysDialog) return 1;
1290 		// dlg protect code - protecting from window activation
1291 		if ( LOWORD( mp1) && !guts. focSysDisabled) {
1292 			Handle hf = Application_map_focus( application, self);
1293 			if ( hf != self) {
1294 				guts. focSysDisabled = 1;
1295 				Application_popup_modal( application);
1296 				PostMessage( win, msg, 0, 0);
1297 				guts. focSysDisabled = 0;
1298 				return 1;
1299 			}
1300 		}
1301 		ev. cmd = ( LOWORD( mp1) != WA_INACTIVE) ? cmActivate : cmDeactivate;
1302 		hiStage = true;
1303 		break;
1304 	case WM_CLOSE:
1305 		if ( guts. focSysDialog) return 0;
1306 		ev. cmd = cmClose;
1307 		break;
1308 	case WM_COMMAND:
1309 	case WM_DRAWITEM:
1310 	case WM_INITMENUPOPUP:
1311 	case WM_INITMENU:
1312 	case WM_MEASUREITEM:
1313 	case WM_MENUCHAR:
1314 	case WM_KEYDOWN:
1315 	case WM_KEYUP:
1316 	case WM_SETVISIBLE:
1317 	case WM_ENABLE:
1318 	case WM_FORCEFOCUS:
1319 	case WM_MOUSEWHEEL:
1320 	case WM_ZORDERSYNC:
1321 		return generic_view_handler(( HWND) v-> handle, msg, mp1, mp2);
1322 	case WM_QUERYNEWPALETTE:
1323 		return generic_view_handler(( HWND) v-> handle, msg, mp1, mp2);
1324 	case WM_PALETTECHANGED:
1325 		if (( HWND) mp1 == win) return 0;
1326 		return generic_view_handler(( HWND) v-> handle, msg, mp1, mp2);
1327 	case WM_SYSKEYDOWN:
1328 	case WM_SYSKEYUP:
1329 		if ( generic_view_handler(( HWND) v-> handle, msg, mp1, mp2) == 0)
1330 			return 0;
1331 		hiStage = true;
1332 		break;
1333 	case WM_DLGENTERMODAL:
1334 		ev. cmd = mp1 ? cmExecute : cmEndModal;
1335 		break;
1336 	case WM_ERASEBKGND:
1337 		return 1;
1338 	case WM_NCACTIVATE:
1339 		if ( guts. focSysDialog) return 1;
1340 
1341 		if (( mp1 == 0) && ( mp2 != 0)) {
1342 			Handle x = hwnd_to_view(( HWND) mp2);
1343 			if ( is_declipped_child( x) && Widget_is_child( x, self)) {
1344 				return 1;
1345 			}
1346 		}
1347 		// dlg protect code - protecting from window activation
1348 		if ( mp1 && !guts. focSysDisabled) {
1349 			Handle hf = Application_map_focus( application, self);
1350 			if ( hf != self) {
1351 				guts. focSysDisabled = 1;
1352 				Application_popup_modal( application);
1353 				PostMessage( win, msg, 0, 0);
1354 				guts. focSysDisabled = 0;
1355 				return 1;
1356 			}
1357 		}
1358 		break;
1359 	case WM_NCHITTEST:
1360 		if ( guts. focSysDialog) return HTERROR;
1361 		// dlg protect code - protecting from user actions
1362 		if ( !guts. focSysDisabled) {
1363 			Handle foc = Application_map_focus( application, self);
1364 			if ( foc != self) {
1365 				return ( foc == apc_window_get_active()) ? HTERROR : HTCLIENT;
1366 			}
1367 		}
1368 		break;
1369 	case WM_SETFOCUS:
1370 		if ( guts. focSysDialog) return 1;
1371 
1372 		// dlg protect code - general case
1373 		if ( !guts. focSysDisabled && !guts. focSysGranted) {
1374 			Handle hf = Application_map_focus( application, self);
1375 			if ( hf != self) {
1376 				PostMessage( win, WM_FORCEFOCUS, 0, ( LPARAM) hf);
1377 				return 1;
1378 			}
1379 		}
1380 
1381 		// This code is about to protect frame events when set_selected would
1382 		// grant SetFocus() call to another frame.
1383 		{
1384 			Handle x  = var self-> get_selectee( self);
1385 			Handle w  = x;
1386 			Bool hasCO = w == self;
1387 			while ( w && w != self) {
1388 				if ( !dsys( w) options. aptClipOwner) {
1389 					hasCO = true;
1390 					break;
1391 				}
1392 				w = (( PWidget) w)-> owner;
1393 			}
1394 			if ( !hasCO) {
1395 				var self-> set_selected( self, true);
1396 			}
1397 			// else we do not select any widget, but still have a chance to resize frame :)
1398 		}
1399 		break;
1400 	case WM_SIZE: {
1401 		int state = wsNormal;
1402 		Bool doWSChange = false;
1403 		if (( int) mp1 == SIZE_RESTORED) {
1404 			state = wsNormal;
1405 			if ( sys s. window. state != state) doWSChange = true;
1406 		} else if (( int) mp1 == SIZE_MAXIMIZED) {
1407 			state = wsMaximized;
1408 			doWSChange = true;
1409 		} else if (( int) mp1 == SIZE_MINIMIZED) {
1410 			state = wsMinimized;
1411 			doWSChange = true;
1412 		}
1413 		if ( doWSChange) {
1414 			ev. gen. i = sys s. window. state = state;
1415 			ev. cmd = cmWindowState;
1416 		}
1417 		break;
1418 	}
1419 	case WM_SYNCMOVE: {
1420 		Handle parent = v-> self-> get_parent(( Handle) v);
1421 		if ( parent) {
1422 			Point pos  = var self-> get_origin( self);
1423 			ev. cmd    = cmMove;
1424 			ev. gen. P = pos;
1425 			if ( pos. x == var pos. x && pos. y == var pos. y) ev. cmd = 0;
1426 		}
1427 		break;
1428 	}
1429 	case WM_MOVE: {
1430 		Handle parent = v-> self-> get_parent(( Handle) v);
1431 		if ( parent) {
1432 			Point sz = CWidget(parent)-> get_size( parent);
1433 			ev. cmd = cmMove;
1434 			ev. gen . P. x = ( short) LOWORD( mp2);
1435 			ev. gen . P. y = sz. y - ( short) HIWORD( mp2) - sys yOverride;
1436 		}
1437 		break;
1438 	}
1439 // case WM_SYSCHAR:return 1;
1440 	case WM_TIMER:
1441 		if ( mp1 == TID_USERMAX) {
1442 			POINT p;
1443 			HWND wp;
1444 			if ( lastMouseOver && !GetCapture() && ( PObject( lastMouseOver)-> stage == csNormal)) {
1445 				HWND desktop = HWND_DESKTOP;
1446 				GetCursorPos( &p);
1447 				wp = WindowFromPoint( p);
1448 				if ( wp) {
1449 					POINT xp = p;
1450 					MapWindowPoints( desktop, wp, &xp, 1);
1451 					wp = ChildWindowFromPointEx( wp, xp, CWP_SKIPINVISIBLE);
1452 				} else
1453 					wp = ChildWindowFromPointEx( wp, p, CWP_SKIPINVISIBLE);
1454 				if ( wp != ( HWND)(( PWidget) lastMouseOver)-> handle)
1455 				{
1456 					HWND old = ( HWND)(( PWidget) lastMouseOver)-> handle;
1457 					Handle s;
1458 					lastMouseOver = NULL_HANDLE;
1459 					SendMessage( old, WM_MOUSEEXIT, 0, 0);
1460 					s = hwnd_to_view( wp);
1461 					if ( s && ( HWND)(( PWidget) s)-> handle == wp)
1462 					{
1463 						MapWindowPoints( desktop, wp, &p, 1);
1464 						SendMessage( wp, WM_MOUSEENTER, 0, MAKELPARAM( p. x, p. y));
1465 						lastMouseOver = s;
1466 					} else if ( guts. mouseTimer) {
1467 						guts. mouseTimer = 0;
1468 						if ( !KillTimer( dsys(application)handle, TID_USERMAX)) apiErr;
1469 					}
1470 				}
1471 			}
1472 			return 0;
1473 		} else {
1474 			int id = mp1 - 1;
1475 			if ( id >= 0 && id < timeDefsCount) {
1476 				ev. gen. H = ( Handle) timeDefs[ id]. item;
1477 				if ( ev. gen. H) {
1478 					v = ( PWidget)( self = ev. gen. H);
1479 					ev. cmd = cmTimer;
1480 				}
1481 			}
1482 		}
1483 		break;
1484 	case WM_GETMINMAXINFO: {
1485 		LPMINMAXINFO l = ( LPMINMAXINFO) mp2;
1486 		Point min = var self-> get_sizeMin( self);
1487 		Point max = var self-> get_sizeMax( self);
1488 		Point bor = get_window_borders( sys s. window. borderStyle);
1489 		int   dy  = 0 +
1490 			(( sys s. window. borderIcons & biTitleBar) ? GetSystemMetrics( SM_CYCAPTION) : 0) +
1491 			( PWindow(self)-> menu ? GetSystemMetrics( SM_CYMENU) : 0);
1492 		l-> ptMinTrackSize. x = min. x + bor.x * 2;
1493 		l-> ptMinTrackSize. y = min. y + bor.y * 2 + dy;
1494 		l-> ptMaxTrackSize. x = max. x + bor.x * 2;
1495 		l-> ptMaxTrackSize. y = max. y + bor.y * 2 + dy;
1496 		break;
1497 	}
1498 	case WM_WINDOWPOSCHANGED:
1499 		if ( !is_apt(aptIgnoreSizeMessages)) {
1500 			LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
1501 			if (( l-> flags & SWP_NOZORDER) == 0)
1502 				PostMessage( win, WM_ZORDERSYNC, 0, 0);
1503 			if (( l-> flags & SWP_NOSIZE) == 0) {
1504 				RECT r;
1505 				GetClientRect( win, &r);
1506 				sys yOverride = r. bottom - r. top;
1507 				SendMessage( win, WM_SYNCMOVE, 0, 0);
1508 			}
1509 			if ( l-> flags & SWP_HIDEWINDOW) SendMessage( win, WM_SETVISIBLE, 0, 0);
1510 			if ( l-> flags & SWP_SHOWWINDOW) SendMessage( win, WM_SETVISIBLE, 1, 0);
1511 			{
1512 				RECT r;
1513 				GetClientRect( win, &r);
1514 				SetWindowPos(( HWND) var handle, 0, 0, 0, r. right, r.bottom, SWP_NOZORDER);
1515 			}
1516 		}
1517 		break;
1518 	}
1519 
1520 	if ( hiStage)
1521 		ret = DefWindowProcW( win, msg, mp1, mp2);
1522 
1523 	if ( ev. cmd) v-> self-> message( self, &ev); else ev. cmd = orgMsg;
1524 
1525 	if ( var stage == csDead) orgMsg = 0;
1526 
1527 	switch ( orgMsg) {
1528 	case WM_CLOSE:
1529 		if ( ev. cmd) {
1530 			if ( sys className == WC_FRAME && PWindow(self)->modal) {
1531 				CWindow( self)-> cancel( self);
1532 				return 0;
1533 			} else {
1534 				SetWindowLongPtr( win, GWLP_USERDATA, 0);
1535 				Object_destroy(( Handle) v);
1536 			}
1537 			break;
1538 		} else
1539 			return 0;
1540 	}
1541 
1542 	if ( ev. cmd && !hiStage)
1543 		ret = DefWindowProcW( win, msg, mp1, mp2);
1544 	return ret;
1545 }
1546 
1547 static void
update_layered_frame(Handle self)1548 update_layered_frame(Handle self)
1549 {
1550 	HRGN r1, r2;
1551 	RECT frame, client;
1552 	POINT frame_size, client_size;
1553 	Point delta_upper_left, delta_lower_right, move;
1554 	HWND win = HANDLE;
1555 
1556 	delta_lower_right = get_window_borders( sys s. window. borderStyle);
1557 	GetWindowRect(win, &frame);
1558 	GetClientRect(win, &client);
1559 	frame_size. x = frame. right  - frame. left;
1560 	frame_size. y = frame. bottom - frame. top;
1561 	client_size. x = client. right  - client. left;
1562 	client_size. y = client. bottom - client. top;
1563 	r2 = CreateRectRgn( 0, 0, frame_size.x, frame_size.y);
1564 	r1 = CreateRectRgn( 0, 0, client_size.x, client_size.y);
1565 	delta_upper_left.x = frame_size.x - client_size.x - delta_lower_right.x;
1566 	delta_upper_left.y = frame_size.y - client_size.y - delta_lower_right.y;
1567 	OffsetRgn( r1, delta_upper_left.x, delta_upper_left.y);
1568 	CombineRgn( r2, r2, r1, RGN_XOR);
1569 	if (!SetWindowRgn( win, r2, true)) apiErr;
1570 	DeleteObject(r1);
1571 	DeleteObject(r2);
1572 
1573 	move.x = frame.left + delta_upper_left.x;
1574 	move.y = frame.top  + delta_upper_left.y;
1575 	if ( !SetWindowPos(( HWND ) var handle, win,
1576 		client.left + move.x, client.top + move.y, client_size.x, client_size.y,
1577 		SWP_NOACTIVATE)) apiErr;
1578 	hwnd_repaint_layered( self, false );
1579 }
1580 
layered_frame_handler(HWND win,UINT msg,WPARAM mp1,LPARAM mp2)1581 LRESULT CALLBACK layered_frame_handler( HWND win, UINT  msg, WPARAM mp1, LPARAM mp2)
1582 {
1583 	Handle  self = GetWindowLongPtr( win, GWLP_USERDATA);
1584 
1585 	if ( !self)
1586 		return DefWindowProcW( win, msg, mp1, mp2);
1587 
1588 	switch ( msg) {
1589 	case WM_NCACTIVATE:
1590 	case WM_NCHITTEST:
1591 	case WM_SETFOCUS:
1592 		return DefWindowProcW( win, msg, mp1, mp2);
1593 
1594 	case WM_SIZE:
1595 	case WM_MOVE:
1596 		update_layered_frame(self);
1597 		return DefWindowProcW( win, msg, mp1, mp2);
1598 
1599 	case WM_WINDOWPOSCHANGED: {
1600 		LPWINDOWPOS l = ( LPWINDOWPOS) mp2;
1601 		Bool updated = false;
1602 
1603 		if (( l-> flags & SWP_NOSIZE) == 0) {
1604 			RECT r;
1605 			update_layered_frame(self);
1606 			updated = true;
1607 
1608 			GetClientRect( win, &r);
1609 			sys yOverride = r. bottom - r. top;
1610 			SendMessage( win, WM_SYNCMOVE, 0, 0);
1611 		}
1612 		if (( l-> flags & SWP_NOMOVE) == 0) {
1613 			if ( !updated ) {
1614 				update_layered_frame(self);
1615 				updated = true;
1616 			}
1617 		}
1618 		if (( l-> flags & SWP_NOZORDER) == 0) {
1619 			PostMessage( win, WM_ZORDERSYNC, 0, 0);
1620 			if ( !updated ) {
1621 				update_layered_frame(self);
1622 				updated = true;
1623 			}
1624 		}
1625 		if ( l-> flags & SWP_HIDEWINDOW) {
1626 			ShowWindow((HWND) var handle, SW_HIDE);
1627 			SendMessage( win, WM_SETVISIBLE, 0, 0);
1628 		}
1629 		if ( l-> flags & SWP_SHOWWINDOW) {
1630 			ShowWindow((HWND) var handle, SW_SHOW);
1631 			SendMessage( win, WM_SETVISIBLE, 1, 0);
1632 		}
1633 		return DefWindowProcW( win, msg, mp1, mp2);
1634 	}
1635 
1636 	}
1637 
1638 	return generic_frame_handler( win, msg, mp1, mp2 );
1639 }
1640 
kill_img_cache(Handle self,int keyLen,void * key,void * killDBM)1641 static Bool kill_img_cache( Handle self, int keyLen, void * key, void * killDBM)
1642 {
1643 	if ( is_apt( aptDeviceBitmap)) {
1644 		if ( killDBM) dbm_recreate( self);
1645 	} else
1646 		image_destroy_cache( self);
1647 	return false;
1648 }
1649 
generic_app_handler(HWND win,UINT msg,WPARAM mp1,LPARAM mp2)1650 LRESULT CALLBACK generic_app_handler( HWND win, UINT  msg, WPARAM mp1, LPARAM mp2)
1651 {
1652 	switch ( msg) {
1653 		case WM_DISPLAYCHANGE: {
1654 			HDC dc = dc_alloc();
1655 			int oldBPP = guts. displayBMInfo. bmiHeader. biBitCount;
1656 			HBITMAP hbm;
1657 
1658 			if ( dc) {
1659 				guts. displayBMInfo. bmiHeader. biBitCount = 0;
1660 				guts. displayBMInfo. bmiHeader. biSize = sizeof( BITMAPINFO);
1661 				if ( !( hbm = GetCurrentObject( dc, OBJ_BITMAP))) apiErr;
1662 
1663 				if ( !GetDIBits( dc, hbm, 0, 0, NULL, &guts. displayBMInfo, DIB_PAL_COLORS)) {
1664 					guts. displayBMInfo. bmiHeader. biBitCount = ( int) mp1;
1665 					guts. displayBMInfo. bmiHeader. biPlanes   = GetDeviceCaps( dc, PLANES);
1666 				};
1667 			}
1668 			dsys( application) lastSize. x = ( short) LOWORD( mp2);
1669 			dsys( application) lastSize. y = ( short) HIWORD( mp2);
1670 			if ( dc) {
1671 				if ( oldBPP != guts. displayBMInfo. bmiHeader. biBitCount)
1672 					hash_first_that( imageMan, kill_img_cache, (void*)1, NULL, NULL);
1673 				dc_free();
1674 			}
1675 			break;
1676 		}
1677 		case WM_FONTCHANGE:
1678 			destroy_font_hash();
1679 			break;
1680 		case WM_DPICHANGED: {
1681 			Event ev = {cmFontChanged};
1682 			dpi_change();
1683 			reset_system_fonts();
1684 			destroy_font_hash();
1685 			font_clean();
1686 			PComponent(application)-> self-> message( application, &ev);
1687 			break;
1688 		}
1689 		case WM_COMPACTING:
1690 			stylus_clean();
1691 			stylus_gp_clean();
1692 			font_clean();
1693 			destroy_font_hash();
1694 			hash_first_that( imageMan, kill_img_cache, NULL, NULL, NULL);
1695 			hash_destroy( regnodeMan, false);
1696 			regnodeMan = hash_create();
1697 			break;
1698 		case WM_QUERYNEWPALETTE:
1699 		case WM_PALETTECHANGED:
1700 			return 0;
1701 	}
1702 	return generic_frame_handler( win, msg, mp1, mp2);
1703 }
1704 
1705 #ifdef __cplusplus
1706 }
1707 #endif
1708