1 #include "win32\win32guts.h"
2 #include <commdlg.h>
3 #ifndef _APRICOT_H_
4 #include "apricot.h"
5 #endif
6 #include "guts.h"
7 #include "File.h"
8 #include "Image.h"
9 #include "Region.h"
10 #include "Application.h"
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 
17 #define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
18 #define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
19 #define var (( PWidget) self)->
20 #define HANDLE sys handle
21 #define DHANDLE(x) dsys(x) handle
22 #define GET_REGION(obj) (&(dsys(obj)s.region))
23 
24 
25 Bool
apc_application_begin_paint(Handle self)26 apc_application_begin_paint ( Handle self)
27 {
28 	objCheck false;
29 	apcErrClear;
30 	if ( !( sys ps = dc_alloc())) apiErrRet;
31 	apt_set( aptWinPS);
32 	apt_set( aptCompatiblePS);
33 	hwnd_enter_paint( self);
34 	if (( sys pal = palette_create( self))) {
35 		SelectPalette( sys ps, sys pal, 0);
36 		RealizePalette( sys ps);
37 	}
38 	return true;
39 }
40 
41 
42 Bool
apc_application_begin_paint_info(Handle self)43 apc_application_begin_paint_info( Handle self)
44 {
45 	Bool ok = apc_application_begin_paint( self);
46 	objCheck false;
47 	if ( ok) {
48 		HRGN rgn = CreateRectRgn( 0, 0, 0, 0);
49 		SelectClipRgn( sys ps, rgn);
50 		DeleteObject( rgn);
51 	}
52 	return ok;
53 }
54 
55 Bool
apc_application_create(Handle self)56 apc_application_create( Handle self)
57 {
58 	HWND h;
59 	RECT r;
60 	MSG msg;
61 	const WCHAR wnull = 0;
62 
63 	objCheck false;
64 
65 	// make sure that no leftover messages, esp.WM_QUIT, are floating around
66 	while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE));
67 
68 	if ( !( h = CreateWindowExW( 0, L"GenericApp", &wnull, 0, 0, 0, 0, 0,
69 			NULL, NULL, guts. instance, NULL))) apiErrRet;
70 	sys handle = h;
71 	sys parent = sys owner = HWND_DESKTOP;
72 	SetWindowLongPtr( sys handle, GWLP_USERDATA, self);
73 	PostMessage( sys handle, WM_PRIMA_CREATE, 0, 0);
74 	sys className = WC_APPLICATION;
75 	// if ( !SetTimer( h, TID_USERMAX, 100, NULL)) apiErr;
76 	GetClientRect( h, &r);
77 	if ( !( var handle = ( Handle) CreateWindowExW( 0,  L"Generic", &wnull, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN,
78 		0, 0, r. right - r. left, r. bottom - r. top, h, NULL,
79 		guts. instance, NULL))) apiErrRet;
80 	SetWindowLongPtr(( HWND) var handle, GWLP_USERDATA, self);
81 	apt_set( aptEnabled);
82 	sys lastSize = apc_application_get_size( self);
83 	return true;
84 }
85 
86 Bool
apc_application_close(Handle self)87 apc_application_close( Handle self)
88 {
89 	PostQuitMessage(0);
90 	return true;
91 }
92 
93 Bool
apc_application_destroy(Handle self)94 apc_application_destroy( Handle self)
95 {
96 	objCheck false;
97 	SetWindowLongPtr( sys handle, GWLP_USERDATA, 0);
98 	if ( IsWindow( sys handle))  {
99 		if ( guts. mouseTimer) {
100 			guts. mouseTimer = 0;
101 			if ( !KillTimer( sys handle, TID_USERMAX)) apiErr;
102 		}
103 		if ( !DestroyWindow( sys handle)) apiErr;
104 	}
105 	PostThreadMessage( guts. mainThreadId, WM_TERMINATE, 0, 0);
106 	PostQuitMessage(0);
107 	application = NULL_HANDLE;
108 	return true;
109 }
110 
111 Bool
apc_application_end_paint(Handle self)112 apc_application_end_paint( Handle self)
113 {
114 	apcErrClear;
115 	objCheck false;
116 	hwnd_leave_paint( self);
117 	if ( sys pal) DeleteObject( sys pal);
118 	dc_free();
119 	apt_clear( aptWinPS);
120 	apt_clear( aptCompatiblePS);
121 	sys pal = NULL;
122 	sys ps = NULL;
123 	return true;
124 }
125 
126 Bool
apc_application_end_paint_info(Handle self)127 apc_application_end_paint_info( Handle self)
128 {
129 	return apc_application_end_paint( self);
130 }
131 
132 
133 int
apc_application_get_gui_info(char * description,int len1,char * language,int len2)134 apc_application_get_gui_info( char * description, int len1, char * language, int len2)
135 {
136 	if ( description) {
137 		strncpy( description, "Windows", len1);
138 		description[len1-1] = 0;
139 	}
140 	if ( language ) {
141 		ULONG n_lang, n_words = 128;
142 		WORD buffer[128];
143 		if ( my_GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &n_lang, buffer, &n_words)) {
144 			if ( len2 < n_words ) n_words = len2;
145 			wchar2char( language, buffer, n_words );
146 		} else
147 			*language = 0;
148 	}
149 	return guiWindows;
150 }
151 
152 Bool
apc_application_get_bitmap(Handle self,Handle image,int x,int y,int xLen,int yLen)153 apc_application_get_bitmap( Handle self, Handle image, int x, int y, int xLen, int yLen)
154 {
155 	HBITMAP bm, bm2;
156 	HDC dc, dc2;
157 	XLOGPALETTE lpg;
158 	HPALETTE hp, hp2, hp3;
159 	if ( image == NULL_HANDLE) apcErrRet( errInvParams);
160 	dobjCheck( image) false;
161 
162 
163 	apcErrClear;
164 	if (!( dc  = dc_alloc())) return false;
165 	lpg. palNumEntries = GetSystemPaletteEntries( dc, 0, 256, lpg. palPalEntry);
166 	lpg. palVersion = 0x300;
167 
168 	hp  = CreatePalette(( LOGPALETTE*)&lpg);
169 	dc2 = CreateCompatibleDC( dc);
170 	if ( !dc2) {
171 		DeleteObject( hp);
172 		dc_free();
173 		return false;
174 	}
175 	hp2 = SelectPalette( dc2, hp, 0);
176 	RealizePalette( dc2);
177 	hp3 = SelectPalette( dc, hp, 1);
178 
179 	bm  = CreateCompatibleBitmap( dc, xLen, yLen);
180 	if ( !bm) {
181 		SelectPalette( dc, hp3, 1);
182 		SelectPalette( dc2, hp2, 1);
183 		DeleteObject( hp);
184 		dc_free();
185 		return false;
186 	}
187 	bm2 = SelectObject( dc2, bm);
188 	BitBlt( dc2, 0, 0, xLen, yLen, dc, x, sys lastSize.y - y - yLen, SRCCOPY);
189 	SelectObject( dc2, bm2);
190 	SelectPalette( dc2, hp2, 1);
191 	DeleteObject( hp);
192 	DeleteDC( dc2);
193 
194 	bm2 = dsys(image)bm;
195 	dsys(image)bm = bm;
196 	image_query_bits( image, true);
197 	dsys(image)bm = bm2;
198 	DeleteObject( bm);
199 	SelectPalette( dc, hp3, 1);
200 	dc_free();
201 
202 	apc_image_update_change( image);
203 
204 	return true;
205 }
206 
207 
208 Handle
hwnd_to_view(HWND win)209 hwnd_to_view( HWND win)
210 {
211 	Handle h;
212 	LONG_PTR ll;
213 	if (( !win) || ( !IsWindow( win)))
214 		return NULL_HANDLE;
215 	if ( GetWindowThreadProcessId( win, NULL) != guts. mainThreadId)
216 		return NULL_HANDLE;
217 	h = GetWindowLongPtr( win, GWLP_USERDATA);
218 	if ( !h) return NULL_HANDLE;
219 	ll = GetWindowLongPtr( win, GWLP_WNDPROC);
220 	if (
221 		( ll == ( LONG_PTR) generic_view_handler) ||
222 		( ll == ( LONG_PTR) generic_app_handler) ||
223 		( ll == ( LONG_PTR) generic_frame_handler)
224 		) return h;
225 
226 	if ( SendMessage( win, WM_HASMATE, 0, ( LPARAM) &h) == (LRESULT) HASMATE_MAGIC)
227 		return h;
228 	return NULL_HANDLE;
229 }
230 
231 
232 int
apc_application_get_os_info(char * system,int slen,char * release,int rlen,char * vendor,int vlen,char * arch,int alen)233 apc_application_get_os_info( char *system, int slen,
234 									char *release, int rlen,
235 									char *vendor, int vlen,
236 									char *arch, int alen)
237 {
238 	SYSTEM_INFO si;
239 	OSVERSIONINFO os = { sizeof( OSVERSIONINFO)};
240 	DWORD  version;
241 	GetSystemInfo( &si);
242 	version = GetVersion();
243 	GetVersionEx( &os);
244 	if ( system) {
245 		strncpy( system, "Windows NT", slen);
246 		system[ slen-1] = 0;
247 	}
248 	if ( vendor) {
249 		strncpy( vendor, "Microsoft", vlen);
250 		vendor[ vlen-1] = 0;
251 	}
252 	if ( arch) {
253 		char * pb = "Unknown";
254 #if defined( __BORLANDC__) && ! ( defined( __cplusplus) || defined( _ANONYMOUS_STRUCT))
255 		switch ( si. u. s. wProcessorArchitecture) {
256 #else
257 		switch ( si. wProcessorArchitecture) {
258 #endif
259 		case PROCESSOR_ARCHITECTURE_INTEL :   pb = "i386";  break;
260 		case PROCESSOR_ARCHITECTURE_MIPS  :   pb = "MIPS";  break;
261 		case PROCESSOR_ARCHITECTURE_ALPHA :   pb = "Alpha"; break;
262 		case PROCESSOR_ARCHITECTURE_PPC   :   pb = "PPC";   break;
263 		}
264 		strncpy( arch, pb, alen);
265 		arch[ alen-1] = 0;
266 	}
267 	if ( release)
268 		snprintf( release, rlen, "%d.%d",
269 			LOBYTE( LOWORD( version)),
270 			HIBYTE( LOWORD( version)));
271 	return apcWin32;
272 }
273 
274 Handle
275 apc_application_get_handle( Handle self, ApiHandle apiHandle)
276 {
277 	return hwnd_to_view(( HWND) apiHandle);
278 }
279 
280 Rect
281 apc_application_get_indents( Handle self)
282 {
283 		Point size;
284 		UINT rc;
285 		Rect ret = {0,0,0,0};
286 		APPBARDATA d;
287 
288 		size = apc_application_get_size( self);
289 
290 		memset( &d, 0, sizeof(d));
291 		d. cbSize = sizeof(d);
292 		rc = SHAppBarMessage( ABM_GETSTATE, &d);
293 		if (( rc & ABS_AUTOHIDE) == 0) {
294 			memset( &d, 0, sizeof(d));
295 			d. cbSize = sizeof(d);
296 			rc = SHAppBarMessage( ABM_GETTASKBARPOS, &d);
297 			switch ( d. uEdge) {
298 			case ABE_TOP:
299 				ret. top = d. rc. bottom;
300 				if ( ret. top < 0) ret. top = 0;
301 				break;
302 			case ABE_BOTTOM:
303 				ret. bottom = size. y - d. rc. top;
304 				if ( ret. bottom < 0) ret. bottom = 0;
305 				break;
306 			case ABE_RIGHT:
307 				ret. right = size. x - d. rc. left;
308 				if ( ret. right < 0) ret. right = 0;
309 				break;
310 			case ABE_LEFT:
311 				ret. left = d. rc. right;
312 				if ( ret. left < 0) ret. left = 0;
313 				break;
314 			}
315 		}
316 
317 		return ret;
318 }
319 
320 Point
321 apc_application_get_size( Handle self)
322 {
323 	RECT  r;
324 	Point ret = {0,0};
325 	objCheck ret;
326 	GetWindowRect( HWND_DESKTOP, &r);
327 	ret. x = r. right;
328 	ret. y = r. bottom;
329 	return ret;
330 }
331 
332 #define PRIMA_MAX_MONITORS 1024
333 typedef struct {
334 	int nrects;
335 	int max_height;
336 	Box rects[PRIMA_MAX_MONITORS];
337 } EnumMonitorData;
338 
339 static BOOL
340 _enum_monitors( HMONITOR monitor, HDC dc, LPRECT rect, LPARAM data)
341 {
342 	EnumMonitorData * d;
343 	Box * current;
344 
345 	d = ( EnumMonitorData * ) data;
346 	if ( d-> nrects >= PRIMA_MAX_MONITORS ) return false;
347 	current = &d->rects[ d->nrects ];
348 
349 	current-> x = rect-> left;
350 	current-> y = rect-> bottom; /* fixup later */
351 	current-> width = rect-> right - rect-> left;
352 	current-> height = rect-> bottom - rect-> top;
353 	if ( d-> max_height < rect-> bottom ) d-> max_height = rect-> bottom;
354 	d->nrects++;
355 
356 	return true;
357 }
358 
359 Box *
360 apc_application_get_monitor_rects( Handle self, int * nrects)
361 {
362 	int i;
363 	Box * ret;
364 	EnumMonitorData d = {0,0};
365 
366 	EnumDisplayMonitors( NULL, NULL, (MONITORENUMPROC) _enum_monitors, (LPARAM) &d);
367 	if ( d. nrects == 0) return NULL;
368 	if (!(ret = malloc( d.nrects * sizeof(Box) )))
369 		return NULL;
370 
371 	for ( i = 0; i < d.nrects; i++)
372 		d.rects[i]. y = d.max_height - d.rects[i]. y;
373 	memcpy( ret, d.rects, d.nrects * sizeof(Box));
374 	*nrects = d.nrects;
375 	return ret;
376 }
377 
378 int
379 apcUpdateWindow( HWND win )
380 {
381 	int ret;
382 	ret = UpdateWindow( win );
383 	exception_check_raise();
384 	return ret;
385 }
386 
387 static Bool
388 files_rehash( Handle self, void * dummy)
389 {
390 	CFile( self)-> is_active( self, true);
391 	return false;
392 }
393 
394 Bool
395 process_msg( MSG * msg)
396 {
397 	Bool postpone_msg_translation = false;
398 	switch ( msg-> message)
399 	{
400 	case WM_TERMINATE:
401 	case WM_QUIT:
402 		return false;
403 	case WM_CROAK:
404 		if ( msg-> wParam)
405 			croak("%s", ( char *) msg-> lParam);
406 		else
407 			warn("%s", ( char *) msg-> lParam);
408 		return true;
409 	case WM_SYSKEYDOWN:
410 		/*
411 			If Prima handles an Alt-Key combination that is also handled by a menu
412 			in TranslateMessage(), we need to prevent the message from being
413 			processed by the menu, by setting guts.dont_xlate_message flag.
414 		*/
415 		postpone_msg_translation = true;
416 	case WM_SYSKEYUP:
417 	case WM_KEYDOWN:
418 	case WM_KEYUP:
419 		GetKeyboardState( guts. keyState);
420 		break;
421 	case WM_KEYPACKET: {
422 		KeyPacket * kp = ( KeyPacket *) msg-> lParam;
423 		BYTE * mod = mod_select( kp-> mod);
424 		Bool wui = PApplication(application)-> wantUnicodeInput;
425 		PApplication(application)-> wantUnicodeInput = kp-> mod & kmUnicode;
426 		SendMessage( kp-> wnd, kp-> msg, kp-> mp1, kp-> mp2);
427 		mod_free( mod);
428 		PApplication(application)-> wantUnicodeInput = wui;
429 		exception_check_raise();
430 		break;
431 	}
432 	case WM_LBUTTONDOWN:  musClk. emsg = WM_LBUTTONUP; goto MUS1;
433 	case WM_MBUTTONDOWN:  musClk. emsg = WM_MBUTTONUP; goto MUS1;
434 	case WM_RBUTTONDOWN:  musClk. emsg = WM_RBUTTONUP; goto MUS1;
435 	case WM_XBUTTONDOWN:  musClk. emsg = WM_XBUTTONUP; goto MUS1;
436 	MUS1:
437 		musClk. pending = 1;
438 		musClk. msg     = *msg;
439 		musClk. msg. wParam &=  MK_CONTROL|MK_SHIFT;
440 		break;
441 	case WM_LBUTTONUP:   musClk. msg. message = WM_LMOUSECLICK; goto MUS2;
442 	case WM_MBUTTONUP:   musClk. msg. message = WM_MMOUSECLICK; goto MUS2;
443 	case WM_RBUTTONUP:   musClk. msg. message = WM_RMOUSECLICK; goto MUS2;
444 	case WM_XBUTTONUP:   musClk. msg. message = WM_XMOUSECLICK; goto MUS2;
445 	MUS2:
446 		if ( musClk. pending &&
447 			( musClk. emsg         == msg-> message) &&
448 			( musClk. msg. hwnd    == msg-> hwnd)    &&
449 			( musClk. msg. wParam  == ( msg-> wParam & ( MK_CONTROL|MK_SHIFT))) &&
450 			( abs( musClk. msg. time  - msg-> time) < 200)
451 			)
452 			PostMessage( msg-> hwnd, musClk. msg. message, msg-> wParam, msg-> lParam);
453 		musClk. pending = 0;
454 		break;
455 	case WM_LBUTTONDBLCLK:
456 	case WM_MBUTTONDBLCLK:
457 	case WM_RBUTTONDBLCLK:
458 		musClk. pending = 0;
459 		break;
460 	case WM_SOCKET: {
461 		int i;
462 		SOCKETHANDLE socket = ( SOCKETHANDLE) msg-> lParam;
463 		for ( i = 0; i < guts. sockets. count; i++) {
464 			Handle self = guts. sockets. items[ i];
465 			if (( sys s. file. object == socket) &&
466 				( PFile( self)-> eventMask & msg-> wParam)) {
467 				Event ev;
468 				ev. cmd = ( msg-> wParam == feRead) ? cmFileRead :
469 					(( msg-> wParam == feWrite) ? cmFileWrite : cmFileException);
470 				CComponent( self)-> message( self, &ev);
471 				break;
472 			}
473 		}
474 		guts. socketPostSync = 0; // clear semaphore
475 		return true;
476 	}
477 	case WM_SOCKET_REHASH:
478 		socket_rehash();
479 		guts. socketPostSync = 0; // clear semaphore
480 		return true;
481 	case WM_FILE:
482 		if ( msg-> wParam == 0) {
483 			int i;
484 
485 			if ( guts. files. count == 0) return true;
486 
487 			list_first_that( &guts. files, files_rehash, NULL);
488 			for ( i = 0; i < guts. files. count; i++) {
489 				Handle self = guts. files. items[i];
490 				if ( PFile( self)-> eventMask & feRead)
491 					PostMessage( NULL, WM_FILE, feRead, ( LPARAM) self);
492 				if ( PFile( self)-> eventMask & feWrite)
493 					PostMessage( NULL, WM_FILE, feWrite, ( LPARAM) self);
494 			}
495 			PostMessage( NULL, WM_FILE, 0, 0);
496 		} else {
497 			int i;
498 			Handle self = NULL_HANDLE;
499 			for ( i = 0; i < guts. files. count; i++)
500 				if (( guts. files. items[i] == ( Handle) msg-> lParam) &&
501 					( PFile(guts. files. items[i])-> eventMask & msg-> wParam)) {
502 					self = ( Handle) msg-> lParam;
503 					break;
504 				}
505 			if ( self) {
506 				Event ev;
507 				ev. cmd = ( msg-> wParam == feRead) ? cmFileRead : cmFileWrite;
508 				CComponent( self)-> message( self, &ev);
509 			}
510 		}
511 		return true;
512 	}
513 	if ( !postpone_msg_translation)
514 		TranslateMessage( msg);
515 	DispatchMessage(msg);
516 	exception_check_raise();
517 	if ( postpone_msg_translation) {
518 		if ( guts. dont_xlate_message)
519 			guts. dont_xlate_message = false;
520 		else
521 			TranslateMessage( msg);
522 	}
523 	prima_kill_zombies();
524 	return true;
525 }
526 
527 Bool
528 apc_application_go( Handle self)
529 {
530 	MSG msg;
531 	objCheck false;
532 
533 	guts. application_stop_signal = false;
534 	while ( !guts. application_stop_signal && GetMessage( &msg, NULL, 0, 0) && process_msg( &msg));
535 	guts. application_stop_signal = false;
536 	return true;
537 }
538 
539 Bool
540 HWND_lock( Bool lock)
541 {
542 	if ( lock)
543 	{
544 		if ( guts. appLock++ == 0) return LockWindowUpdate( HWND_DESKTOP);
545 	}
546 	else
547 	{
548 		if ( --guts. appLock == 0) return LockWindowUpdate( NULL);
549 	}
550 	return true;
551 }
552 
553 Bool
554 apc_application_lock( Handle self)
555 {
556 	return HWND_lock( true);
557 }
558 
559 Bool
560 apc_application_unlock( Handle self)
561 {
562 	return HWND_lock( false);
563 }
564 
565 Bool
566 apc_application_stop( Handle self)
567 {
568 	if ( application == NULL_HANDLE ) return false;
569 	guts. application_stop_signal = true;
570 	return true;
571 }
572 
573 Bool
574 apc_application_sync( void)
575 {
576 	return true;
577 }
578 
579 Bool
580 apc_application_yield(Bool wait_for_event)
581 {
582 	MSG msg;
583 	Bool got_events = false;
584 	guts. application_stop_signal = false;
585 	while ( !guts. application_stop_signal && PeekMessage( &msg, NULL, 0, 0, PM_REMOVE)) {
586 		got_events = true;
587 		if ( !process_msg( &msg)) {
588 			PostThreadMessage( guts. mainThreadId, appDead ? WM_QUIT : WM_TERMINATE, 0, 0);
589 			return false;
590 		}
591 	}
592 	if ( application && wait_for_event && !got_events && !guts. application_stop_signal) {
593 		Event ev;
594 		ev. cmd = cmIdle;
595 		CComponent( application)-> message( application, &ev);
596 		if ( application ) {
597 			GetMessage( &msg, NULL, 0, 0);
598 			process_msg( &msg);
599 		}
600 	}
601 	guts. application_stop_signal = false;
602 	return application != NULL_HANDLE;
603 }
604 
605 Handle
606 apc_application_get_widget_from_point( Handle self, Point point)
607 {
608 	DWORD pid, tid;
609 	POINT pt;
610 	HWND  p;
611 
612 	objCheck NULL_HANDLE;
613 	pt.x = point. x;
614 	pt.y = sys lastSize. y - point. y - 1;
615 	p    =  WindowFromPoint( pt);
616 
617 	if ( p) {
618 		POINT xp = pt;
619 		MapWindowPoints( HWND_DESKTOP, p, &xp, 1);
620 		p = ChildWindowFromPointEx( p, xp, CWP_SKIPINVISIBLE);
621 	} else
622 		p = ChildWindowFromPointEx( HWND_DESKTOP, pt, CWP_SKIPINVISIBLE);
623 
624 	if ( !p) return NULL_HANDLE;
625 	if ( !( tid = GetWindowThreadProcessId( p, &pid))) apiErr;
626 	if ( tid != guts. mainThreadId) return NULL_HANDLE;
627 	return ( Handle) GetWindowLongPtr( p, GWLP_USERDATA);
628 }
629 
630 // Component
631 Bool
632 apc_component_create( Handle self)
633 {
634 	PComponent c = ( PComponent) self;
635 	PDrawableData d = ( PDrawableData) c-> sysData;
636 
637 	objCheck false;
638 
639 	if ( d) return false;
640 	d = ( PDrawableData) malloc( sizeof( DrawableData));
641 	if ( !d) return false;
642 	memset( d, 0, sizeof( DrawableData));
643 	c-> sysData = d;
644 	return true;
645 }
646 
647 Bool
648 apc_component_destroy( Handle self)
649 {
650 	PComponent    c = ( PComponent) self;
651 	PDrawableData d = ( PDrawableData) c-> sysData;
652 	objCheck false;
653 	var handle = NULL_HANDLE;
654 	if ( d == NULL) return false;
655 	free( d);
656 	c-> sysData = NULL;
657 	return true;
658 }
659 
660 Bool
661 apc_component_fullname_changed_notify( Handle self)
662 {
663 	return true;
664 }
665 
666 // View attributes
667 
668 int
669 apc_kbd_get_state( Handle self)
670 {
671 	return
672 		(( GetKeyState( VK_MENU)    < 0) ? kmAlt      : 0) |
673 		(( GetKeyState( VK_CONTROL) < 0) ? kmCtrl     : 0) |
674 		(( GetKeyState( VK_SHIFT)   < 0) ? kmShift    : 0);
675 }
676 
677 Handle ctx_kb2VK[] = {
678 	kbNoKey       ,   0                 ,
679 	kbAltL        ,   VK_MENU           ,
680 	kbAltR        ,   VK_RMENU          ,
681 	kbCtrlL       ,   VK_CONTROL        ,
682 	kbCtrlR       ,   VK_RCONTROL       ,
683 	kbShiftL      ,   VK_SHIFT          ,
684 	kbShiftR      ,   VK_RSHIFT         ,
685 	kbBackspace   ,   VK_BACK           ,
686 	kbTab         ,   VK_TAB            ,
687 	kbPause       ,   VK_PAUSE          ,
688 	kbEsc         ,   VK_ESCAPE         ,
689 	kbSpace       ,   VK_SPACE          ,
690 	kbPgUp        ,   VK_PRIOR          ,
691 	kbPgDn        ,   VK_NEXT           ,
692 	kbEnd         ,   VK_END            ,
693 	kbHome        ,   VK_HOME           ,
694 	kbLeft        ,   VK_LEFT           ,
695 	kbUp          ,   VK_UP             ,
696 	kbRight       ,   VK_RIGHT          ,
697 	kbDown        ,   VK_DOWN           ,
698 	kbPrintScr    ,   VK_PRINT          ,
699 	kbInsert      ,   VK_INSERT         ,
700 	kbDelete      ,   VK_DELETE         ,
701 	kbEnter       ,   VK_RETURN         ,
702 	kbF1          ,   VK_F1             ,
703 	kbF2          ,   VK_F2             ,
704 	kbF3          ,   VK_F3             ,
705 	kbF4          ,   VK_F4             ,
706 	kbF5          ,   VK_F5             ,
707 	kbF6          ,   VK_F6             ,
708 	kbF7          ,   VK_F7             ,
709 	kbF8          ,   VK_F8             ,
710 	kbF9          ,   VK_F9             ,
711 	kbF10         ,   VK_F10            ,
712 	kbF11         ,   VK_F11            ,
713 	kbF12         ,   VK_F12            ,
714 	kbF13         ,   VK_F13            ,
715 	kbF14         ,   VK_F14            ,
716 	kbF15         ,   VK_F15            ,
717 	kbF16         ,   VK_F16            ,
718 	kbNumLock     ,   VK_NUMLOCK        ,
719 	kbScrollLock  ,   VK_SCROLL         ,
720 	kbCapsLock    ,   VK_CAPITAL        ,
721 	kbClear       ,   VK_CLEAR          ,
722 	kbSelect      ,   VK_SELECT         ,
723 	kbExecute     ,   VK_EXECUTE        ,
724 	kbSysRq       ,   VK_SNAPSHOT       ,
725 	endCtx
726 };
727 
728 Handle ctx_kb2VK2[] = {
729 	kbBackspace   ,   VK_BACK           ,
730 	kbTab         ,   VK_TAB            ,
731 	kbEsc         ,   VK_ESCAPE         ,
732 	kbSpace       ,   VK_SPACE          ,
733 	kbEnter       ,   VK_RETURN         ,
734 	endCtx
735 };
736 
737 Handle ctx_kb2VK3[] = {
738 	kbAltL        ,   kbAltR            ,
739 	kbShiftL      ,   kbShiftR          ,
740 	kbCtrlL       ,   kbCtrlR           ,
741 	endCtx
742 };
743 
744 Bool
745 apc_message( Handle self, PEvent ev, Bool post)
746 {
747 	ULONG msg;
748 	USHORT mp1s = 0;
749 	objCheck false;
750 	switch ( ev-> cmd) {
751 	case cmPost:
752 		if (post)
753 			PostMessage(( HWND) var handle, WM_POSTAL, ( WPARAM) ev-> gen. H, ( LPARAM) ev-> gen. p);
754 		else {
755 			SendMessage(( HWND) var handle, WM_POSTAL, ( WPARAM) ev-> gen. H, ( LPARAM) ev-> gen. p);
756 			exception_check_raise();
757 		}
758 		break;
759 	case cmMouseMove:
760 		msg = WM_MOUSEMOVE;
761 		goto general;
762 	case cmMouseUp:
763 		if ( ev-> pos. button & mbMiddle) msg = WM_MBUTTONUP; else
764 		if ( ev-> pos. button & mbRight)  msg = WM_RBUTTONUP; else
765 		if ( ev-> pos. button & mbLeft)   msg = WM_XBUTTONUP; else
766 		{
767 			msg  = WM_XBUTTONUP;
768 			mp1s = MAKEWPARAM(0, (ev-> pos. button & mb4) ? XBUTTON1 : XBUTTON2);
769 		}
770 		goto general;
771 	case cmMouseDown:
772 		if ( ev-> pos. button & mbMiddle) msg = WM_MBUTTONDOWN; else
773 		if ( ev-> pos. button & mbRight)  msg = WM_RBUTTONDOWN; else
774 		if ( ev-> pos. button & mbLeft)   msg = WM_LBUTTONDOWN; else
775 		{
776 			msg = WM_XBUTTONDOWN;
777 			mp1s = MAKEWPARAM(0, (ev-> pos. button & mb4) ? XBUTTON1 : XBUTTON2);
778 		}
779 		goto general;
780 	case cmMouseWheel:
781 		msg  = WM_MOUSEWHEEL;
782 		mp1s = ( SHORT) ev-> pos. button;
783 		goto general;
784 	case cmMouseClick:
785 		if ( ev-> pos. dblclk) {
786 			if ( ev-> pos. button & mbMiddle) msg = WM_MBUTTONDBLCLK; else
787 			if ( ev-> pos. button & mbRight)  msg = WM_RBUTTONDBLCLK; else
788 			if ( ev-> pos. button & mbLeft)   msg = WM_LBUTTONDBLCLK; else
789 			{
790 				msg = WM_XBUTTONDBLCLK;
791 				mp1s = MAKEWPARAM(0, (ev-> pos. button & mb4) ? XBUTTON1 : XBUTTON2);
792 			}
793 		} else {
794 			Event newEvent = *ev;
795 			if ( ev-> pos. button & mbMiddle) msg = WM_MMOUSECLICK; else
796 			if ( ev-> pos. button & mbRight)  msg = WM_RMOUSECLICK; else
797 			if ( ev-> pos. button & mbLeft)   msg = WM_LMOUSECLICK; else
798 			{
799 				msg = WM_XMOUSECLICK;
800 				mp1s = MAKEWPARAM(0, (ev-> pos. button & mb4) ? XBUTTON1 : XBUTTON2);
801 			}
802 			newEvent. cmd = cmMouseDown;
803 			apc_message( self, &newEvent, post);
804 			newEvent. cmd = cmMouseUp;
805 			apc_message( self, &newEvent, post);
806 		}
807 	general: {
808 		LPARAM mp2 = MAKELPARAM( ev-> pos. where. x, sys lastSize. y - ev-> pos. where. y - 1);
809 		WPARAM mp1 = mp1s |
810 			(( ev-> pos. mod & kmShift) ? MK_SHIFT   : 0) |
811 			(( ev-> pos. mod & kmCtrl ) ? MK_CONTROL : 0);
812 		if ( post) {
813 			KeyPacket * kp;
814 			kp = ( KeyPacket *) malloc( sizeof( KeyPacket));
815 			if ( kp) {
816 				kp-> mp1 = mp1;
817 				kp-> mp2 = mp2;
818 				kp-> msg = msg;
819 				kp-> wnd = ( HWND) var handle;
820 				kp-> mod = ev-> pos. mod;
821 				PostMessage( 0, WM_KEYPACKET, 0, ( LPARAM) kp);
822 			}
823 		} else {
824 			BYTE * mod = NULL;
825 			Bool wui = PApplication(application)-> wantUnicodeInput;
826 			if (( GetKeyState( VK_MENU) < 0) ^ (( ev-> pos. mod & kmAlt) != 0))
827 				mod = mod_select( ev-> pos. mod);
828 			PApplication(application)-> wantUnicodeInput = ev-> key. mod & kmUnicode;
829 			SendMessage(( HWND) var handle, msg, mp1, mp2);
830 			if ( mod) mod_free( mod);
831 			PApplication(application)-> wantUnicodeInput = wui;
832 		}
833 		break;
834 	}
835 	case cmKeyDown:
836 	case cmKeyUp: {
837 		WPARAM mp1;
838 		LPARAM mp2;
839 		int scan = 0;
840 		UINT msg;
841 		Bool specF10 = ( ev-> key. key == kbF10) && !( ev-> key. mod & kmAlt);
842 		// constructing mp1
843 		if ( ev-> key. key == kbNoKey) {
844 			if ( ev-> key. code == 0) {
845 				if ( ev-> key. mod & kmAlt   ) mp1 = VK_MENU;    else
846 				if ( ev-> key. mod & kmShift ) mp1 = VK_SHIFT;   else
847 				if ( ev-> key. mod & kmCtrl  ) mp1 = VK_CONTROL; else
848 					return false;
849 			} else {
850 				SHORT c = VkKeyScan(( CHAR ) ev-> key. code);
851 				if ( c == -1) {
852 					HKL kl = guts. keyLayout ? guts. keyLayout : GetKeyboardLayout( 0);
853 					c = VkKeyScanEx(( CHAR) ev-> key. code, kl);
854 					if ( c == -1) return false;
855 					scan = MapVirtualKeyEx( LOBYTE( c), 0, kl);
856 				} else {
857 					scan = MapVirtualKey( LOBYTE( c), 0);
858 				}
859 				mp1 = LOBYTE( c);
860 				c = HIBYTE( c);
861 				ev-> key. mod |=
862 					(( c & 1) ? kmShift : 0) |
863 					(( c & 2) ? kmCtrl  : 0) |
864 					(( c & 4) ? kmAlt   : 0);
865 			}
866 		} else {
867 			if ( ev-> key. key == kbBackTab) {
868 				mp1  = VK_TAB;
869 				ev-> key. mod |= kmShift;
870 			} else {
871 				mp1 = ctx_remap( ev-> key. key, ctx_kb2VK, true);
872 				if ( mp1 == 0) return false;
873 			}
874 			scan = MapVirtualKey( mp1, 0);
875 		}
876 
877 		// constructing msg
878 		msg = ( ev-> key. mod & kmAlt) ? (
879 			( ev-> cmd == cmKeyUp) ? WM_SYSKEYUP : WM_SYSKEYDOWN
880 		) : (
881 			( ev-> cmd == cmKeyUp) ? WM_KEYUP : WM_KEYDOWN
882 		);
883 
884 		// constructing mp2
885 		mp2 = MAKELPARAM( ev-> key. repeat,  scan);
886 		switch ( msg) {
887 		case WM_KEYDOWN:
888 			mp2 |= 0x00000000;
889 			break;
890 		case WM_SYSKEYDOWN:
891 			mp2 |= 0x20000000;
892 			break;
893 		case WM_KEYUP:
894 			mp2 |= 0xC0000000;
895 			break;
896 		case WM_SYSKEYUP:
897 			mp2 |= 0xE0000000;
898 			break;
899 		}
900 
901 		if ( specF10)
902 			msg = ( ev-> cmd == cmKeyUp) ? WM_SYSKEYUP : WM_SYSKEYDOWN;
903 
904 		if ( post) {
905 			KeyPacket * kp;
906 			kp = ( KeyPacket *) malloc( sizeof( KeyPacket));
907 			if ( kp) {
908 				kp-> mp1 = mp1;
909 				kp-> mp2 = mp2;
910 				kp-> msg = msg;
911 				kp-> wnd = HANDLE;
912 				kp-> mod = ev-> key. mod;
913 				PostMessage( 0, WM_KEYPACKET, 0, ( LPARAM) kp);
914 			}
915 		} else {
916 			Bool wui = PApplication(application)-> wantUnicodeInput;
917 			BYTE * mod = mod_select( ev-> key. mod);
918 			PApplication(application)-> wantUnicodeInput = ev-> key. mod & kmUnicode;
919 			SendMessage( HANDLE, msg, mp1, mp2);
920 			mod_free( mod);
921 			PApplication(application)-> wantUnicodeInput = wui;
922 		}
923 		break;
924 	}
925 	default:
926 		return false;
927 	}
928 	return true;
929 }
930 
931 /* Convert explorer-string format (asciiz,asciiz,...,0) into
932 backslash-escaped string.
933 Spaces and backslashes are escaped */
934 static char *
935 duplicate_zz_string( const WCHAR * c)
936 {
937 	int sz = 1;
938 	WCHAR * d = ( WCHAR *) c;
939 	WCHAR buf[20480];
940 
941 	while ( d[0] || d[1]) {
942 		if ( *d == L' ' || *d == L'\\') sz++;
943 		sz++;
944 		d++;
945 	}
946 
947 	d = buf;
948 	while ( c[0] || c[1]) {
949 		if ( !*c) {
950 			*d++ = L' ';
951 			c++;
952 			continue;
953 		}
954 		if ( *c == L' ' || *c == L'\\')
955 			*d++ = L'\\';
956 		*d++ = *c++;
957 	}
958 	*d++ = 0;
959 
960 	return alloc_wchar_to_utf8(buf, &sz);
961 }
962 
963 /* performs non-standard windows open file function */
964 static char *
965 win32_openfile( const char * params)
966 {
967 	static OPENFILENAMEW o;
968 	static Bool initialized = false;
969 	static WCHAR filter[2048]    = L"";
970 	static WCHAR defext[32]      = L"";
971 	static WCHAR directory[2048] = L"";
972 	static WCHAR title[256]      = L"";
973 	static WCHAR filters[20480];
974 
975 #define UTF8COPY(dst) {\
976 	MultiByteToWideChar(CP_UTF8, 0, params, -1, dst, sizeof(dst)/sizeof(WCHAR));\
977 	dst[sizeof(dst)/sizeof(WCHAR) - 1] = 0;\
978 }
979 	if ( !initialized) {
980 		memset( &o, 0, sizeof(o));
981 		o. lStructSize = sizeof(o);
982 		o. nMaxFile = 20479;
983 		o. nMaxCustFilter = 2047;
984 		initialized = true;
985 	}
986 
987 	if ( strncmp( params, "filters=", 8) == 0) {
988 		params += 8;
989 		if ( strcmp( params, "NULL") == 0) {
990 			o. lpstrFilter = NULL;
991 		} else {
992 			/* copy \0\0-terminated string */
993 			const char *p = params;
994 			int paramsz = 2, fsz = sizeof(filters)/sizeof(WCHAR);
995 			while ( p[0] || p[1]) p++, paramsz++;
996 			MultiByteToWideChar(CP_UTF8, 0, params, paramsz, filters, fsz);
997 			filters[fsz - 1] = filters[fsz - 2] = 0;
998 			o. lpstrFilter = filters;
999 		}
1000 	} else if ( strncmp( params, "directory", 9) == 0) {
1001 		params += 9;
1002 		if ( *params == '=') {
1003 			params += 1;
1004 			if ( strcmp( params, "NULL") == 0) {
1005 				o. lpstrInitialDir = NULL;
1006 			} else {
1007 				UTF8COPY(directory);
1008 				o. lpstrInitialDir = directory;
1009 			}
1010 		} else {
1011 			return alloc_wchar_to_utf8( directory, NULL);
1012 		}
1013 	} else if ( strncmp( params, "title=", 6) == 0) {
1014 		params += 6;
1015 		if ( strcmp( params, "NULL") == 0) {
1016 			o. lpstrTitle = NULL;
1017 		} else {
1018 			UTF8COPY(title);
1019 			o. lpstrTitle = title;
1020 		}
1021 	} else if ( strncmp( params, "defext=", 7) == 0) {
1022 		params += 7;
1023 		if ( strcmp( params, "NULL") == 0) {
1024 			o. lpstrDefExt = NULL;
1025 		} else {
1026 			UTF8COPY(defext);
1027 			o. lpstrDefExt = defext;
1028 		}
1029 	} else if ( strncmp( params, "filter=", 7) == 0) {
1030 		params += 7;
1031 		if ( strcmp( params, "NULL") == 0) {
1032 			o. lpstrCustomFilter = NULL;
1033 		} else if ( strcmp( params, "DEFAULT") == 0) {
1034 			o. lpstrCustomFilter = filter;
1035 		} else {
1036 			UTF8COPY(filter);
1037 			o. lpstrCustomFilter = filter;
1038 		}
1039 	} else if ( strncmp( params, "filterindex", 11) == 0) {
1040 		params += 11;
1041 		if ( *params == '=') {
1042 			int fi = 0;
1043 			sscanf( params + 1, "%d", &fi);
1044 			o. nFilterIndex = fi;
1045 		} else {
1046 			char buf[25];
1047 			sprintf( buf, "%d", (int) o. nFilterIndex);
1048 			return duplicate_string( buf);
1049 		}
1050 	} else if ( strncmp( params, "flags=", 6) == 0) {
1051 		params += 6;
1052 		o. Flags = 0;
1053 		while ( *params) {
1054 			char * cp = ( char *) params, pp;
1055 			while ( *cp && *cp != ',') cp++;
1056 			pp = *cp;
1057 			*cp = 0;
1058 			if ( stricmp( params, "READONLY") == 0) o. Flags |=              OFN_READONLY; else
1059 			if ( stricmp( params, "OVERWRITEPROMPT") == 0) o. Flags |=       OFN_OVERWRITEPROMPT; else
1060 			if ( stricmp( params, "HIDEREADONLY") == 0) o. Flags |=          OFN_HIDEREADONLY; else
1061 			if ( stricmp( params, "NOCHANGEDIR") == 0) o. Flags |=           OFN_NOCHANGEDIR; else
1062 			if ( stricmp( params, "SHOWHELP") == 0) o. Flags |=              OFN_SHOWHELP; else
1063 			if ( stricmp( params, "NOVALIDATE") == 0) o. Flags |=            OFN_NOVALIDATE; else
1064 			if ( stricmp( params, "ALLOWMULTISELECT") == 0) o. Flags |=      OFN_ALLOWMULTISELECT; else
1065 			if ( stricmp( params, "EXTENSIONDIFFERENT") == 0) o. Flags |=    OFN_EXTENSIONDIFFERENT; else
1066 			if ( stricmp( params, "PATHMUSTEXIST") == 0) o. Flags |=         OFN_PATHMUSTEXIST; else
1067 			if ( stricmp( params, "FILEMUSTEXIST") == 0) o. Flags |=         OFN_FILEMUSTEXIST; else
1068 			if ( stricmp( params, "CREATEPROMPT") == 0) o. Flags |=          OFN_CREATEPROMPT; else
1069 			if ( stricmp( params, "SHAREAWARE") == 0) o. Flags |=            OFN_SHAREAWARE; else
1070 			if ( stricmp( params, "NOREADONLYRETURN") == 0) o. Flags |=      OFN_NOREADONLYRETURN; else
1071 			if ( stricmp( params, "NOTESTFILECREATE") == 0) o. Flags |=      OFN_NOTESTFILECREATE; else
1072 			if ( stricmp( params, "NONETWORKBUTTON") == 0) o. Flags |=       OFN_NONETWORKBUTTON; else
1073 			if ( stricmp( params, "NOLONGNAMES") == 0) o. Flags |=           OFN_NOLONGNAMES; else
1074 #ifndef OFN_EXPLORER
1075 #define OFN_EXPLORER 0
1076 #define OFN_NODEREFERENCELINKS 0
1077 #define OFN_LONGNAMES 0
1078 #endif
1079 			if ( stricmp( params, "EXPLORER") == 0) o. Flags |=              OFN_EXPLORER; else
1080 			if ( stricmp( params, "NODEREFERENCELINKS") == 0) o. Flags |=    OFN_NODEREFERENCELINKS; else
1081 			if ( stricmp( params, "LONGNAMES") == 0) o. Flags |=             OFN_LONGNAMES; else
1082 			warn("win32.OpenFile: Unknown constant OFN_%s", params);
1083 			params = cp + 1;
1084 			if ( !pp) break;
1085 		}
1086 	} else if (
1087 		( strncmp( params, "open", 4) == 0) ||
1088 		( strncmp( params, "save", 4) == 0)
1089 	) {
1090 		Bool ret;
1091 		WCHAR filename[20480] = L"";
1092 
1093 		guts. focSysDialog = 1;
1094 		o. lpstrFile = filename;
1095 		ret = (strncmp( params, "open", 4) == 0) ?
1096 			GetOpenFileNameW( &o) :
1097 			GetSaveFileNameW( &o);
1098 		if ( ret == 0) {
1099 			DWORD error;
1100 			error = CommDlgExtendedError();
1101 			if ( error != 0) {
1102 				warn("win32.OpenFile: Get%sFileName error %lu at line %d at %s\n",
1103 			 		(strncmp( params, "open", 4) == 0) ? "Open" : "Save",
1104 					error,
1105 			 		__LINE__, __FILE__
1106 				);
1107 			}
1108 		}
1109 		guts. focSysDialog = 0;
1110 		if ( !ret) return 0;
1111 		wcsncpy( directory, o. lpstrFile, o. nFileOffset);
1112 		if ( o. Flags & OFN_ALLOWMULTISELECT) {
1113 			if ( o. Flags & OFN_EXPLORER)
1114 				return duplicate_zz_string( o. lpstrFile + o. nFileOffset );
1115 			else
1116 				return alloc_wchar_to_utf8( o. lpstrFile + o. nFileOffset, NULL );
1117 		}
1118 		return alloc_wchar_to_utf8( o. lpstrFile, NULL);
1119 	} else {
1120 		warn("win32.OpenFile: Unknown function %s", params);
1121 	}
1122 
1123 	return 0;
1124 }
1125 
1126 static BOOL CALLBACK
1127 find_console( HWND w, LPARAM ptr)
1128 {
1129 	DWORD pid;
1130 	char buf[256];
1131 	DWORD tid = GetWindowThreadProcessId( w, &pid);
1132 	if ( tid != guts. mainThreadId) return TRUE;
1133 	if ( GetClassName( w, buf, 255) == 0) return TRUE;
1134 	if ( strcmp( buf, "ConsoleWindowClass") != 0) return TRUE;
1135 	*(HWND*)(ptr) = w;
1136 	return FALSE;
1137 }
1138 
1139 char *
1140 apc_system_action( const char * params)
1141 {
1142 	switch ( *params) {
1143 	case 'b':
1144 #define STR "browser"
1145 		if ( strncmp( params, STR, strlen( STR)) == 0) {
1146 #undef STR
1147 			HKEY k;
1148 			DWORD valSize = MAX_PATH, valType = REG_SZ, res;
1149 			char buf[ MAX_PATH] = "";
1150 			RegOpenKeyEx( HKEY_CLASSES_ROOT, "http\\shell\\open\\command", 0, KEY_READ, &k);
1151 			res = RegQueryValueEx( k, NULL, NULL, &valType, ( LPBYTE)buf, &valSize);
1152 			RegCloseKey( k);
1153 			if ( res != ERROR_SUCCESS) return NULL;
1154 			return duplicate_string( buf);
1155 		}
1156 		break;
1157 	case 'r':
1158 		if ( strncmp( params, "resolution", 10) == 0) {
1159 			int dx, dy;
1160 			int i = sscanf( params + 10, "%u %u", &dx, &dy);
1161 			if ( i != 2 || (dx < 1 || dy < 1)) {
1162 				warn("Bad resolution\n");
1163 				return 0;
1164 			}
1165 			guts. displayResolution. x = dx;
1166 			guts. displayResolution. y = dy;
1167 			reset_system_fonts();
1168 			destroy_font_hash();
1169 			font_clean();
1170 		}
1171 		break;
1172 	case 'w':
1173 		if ( strncmp( params, "win32.SetVersion", 16) == 0) {
1174 			const char * ver = params + 17;
1175 			while ( *ver && ( *ver == ' '  || *ver == '\t')) ver++;
1176 
1177 			if ( stricmp( ver, "NT") == 0) {
1178 				guts. version = 0;
1179 			} else if (( stricmp( ver, "95") == 0) || ( stricmp( ver, "mustdie") == 0)) {
1180 				guts. version = 0x80000095;
1181 			} else if ( stricmp( ver, "98") == 0) {
1182 				guts. version = 0x80000098;
1183 			} else {
1184 				guts. version = 0x80000000;
1185 			}
1186 		} else if ( strncmp( params, "win32.ConsoleWindow", 19) == 0) {
1187 			params += 19;
1188 
1189 			if ( !guts. console) {
1190 				EnumWindows((WNDENUMPROC) find_console, (LPARAM) &guts. console);
1191 				if ( strcmp( params, " exists") == 0) return 0;
1192 				if ( !guts. console) {
1193 					warn("No associated console window found");
1194 					return 0;
1195 				}
1196 			}
1197 
1198 			if ( strcmp( params, " exists") == 0) {
1199 				char * p = ( char *) malloc(12);
1200 				if ( p) snprintf( p, 12, PR_HANDLE_FMT, ( Handle) guts. console);
1201 				return p;
1202 			} else
1203 			if ( strcmp( params, " hide") == 0)     { ShowWindow( guts. console, SW_HIDE); } else
1204 			if ( strcmp( params, " show") == 0)     { ShowWindow( guts. console, SW_SHOW); } else
1205 			if ( strcmp( params, " minimize") == 0) { ShowWindow( guts. console, SW_MINIMIZE); } else
1206 			if ( strcmp( params, " maximize") == 0) { ShowWindow( guts. console, SW_SHOWMAXIMIZED ); } else
1207 			if ( strcmp( params, " restore") == 0)  { ShowWindow( guts. console, SW_RESTORE); } else
1208 			if ( strcmp( params, " topmost") == 0)  { SetWindowPos( guts. console, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); } else
1209 			if ( strcmp( params, " notopmost") == 0)  { SetWindowPos( guts. console, HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); } else
1210 			if ( strncmp( params, " text", 5) == 0)  {
1211 				char * p = (char*)params + 5;
1212 				while ( *p == ' ') p++;
1213 				if ( *p) {
1214 					SetWindowText( guts. console, p);
1215 				} else {
1216 					int lc = GetWindowTextLength( guts. console);
1217 					p = (char*)malloc( lc + 2);
1218 					if ( p) GetWindowText( guts. console, p, lc+1);
1219 					return p;
1220 				}
1221 			} else {
1222 				warn( "Bad parameters '%s' to sysaction win32.ConsoleWindow", params);
1223 				return 0;
1224 			}
1225 		} else if ( strncmp( params, "win32.OpenFile.", 15) == 0) {
1226 			params += 15;
1227 			return win32_openfile( params);
1228 		} else
1229 			goto DEFAULT;
1230 		break;
1231 	DEFAULT:
1232 	default:
1233 		warn( "Unknown sysaction \"%s\"", params);
1234 	}
1235 	return 0;
1236 }
1237 
1238 int
1239 apc_application_get_mapper_font( Handle self, int index, Font * font)
1240 {
1241 	return 0;
1242 }
1243 
1244 int
1245 apc_application_set_mapper_font( Handle self, int index, Font * font)
1246 {
1247 	return 0;
1248 }
1249 
1250 
1251 #ifdef __cplusplus
1252 }
1253 #endif
1254