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