1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Main window creation and management.
12  *
13  *      By Stefan Schimanski.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include "allegro.h"
20 #include "allegro/internal/aintern.h"
21 #include "allegro/platform/aintwin.h"
22 #include "wddraw.h"
23 
24 #ifndef SCAN_DEPEND
25    #include <string.h>
26    #include <process.h>
27    #include <time.h>
28 #endif
29 
30 #ifndef ALLEGRO_WINDOWS
31    #error something is wrong with the makefile
32 #endif
33 
34 #define PREFIX_I                "al-wwnd INFO: "
35 #define PREFIX_W                "al-wwnd WARNING: "
36 #define PREFIX_E                "al-wwnd ERROR: "
37 
38 
39 /* general */
40 static HWND allegro_wnd = NULL;
41 char wnd_title[WND_TITLE_SIZE];  /* ASCII string */
42 int wnd_x = 0;
43 int wnd_y = 0;
44 int wnd_width = 0;
45 int wnd_height = 0;
46 int wnd_sysmenu = FALSE;
47 
48 static int last_wnd_x = -1;
49 static int last_wnd_y = -1;
50 
51 static int window_is_initialized = FALSE;
52 
53 /* graphics */
54 WIN_GFX_DRIVER *win_gfx_driver;
55 CRITICAL_SECTION gfx_crit_sect;
56 int gfx_crit_sect_nesting = 0;
57 
58 /* close button user hook */
59 void (*user_close_proc)(void) = NULL;
60 
61 /* window thread internals */
62 #define ALLEGRO_WND_CLASS "AllegroWindow"
63 static HWND user_wnd = NULL;
64 static WNDPROC user_wnd_proc = NULL;
65 static HANDLE wnd_thread = NULL;
66 static HWND (*wnd_create_proc)(WNDPROC) = NULL;
67 static int old_style = 0;
68 
69 static int (*wnd_msg_pre_proc)(HWND, UINT, WPARAM, LPARAM, int *) = NULL;
70 
71 /* custom window msgs */
72 #define SWITCH_TIMER  1
73 static UINT msg_call_proc = 0;
74 static UINT msg_suicide = 0;
75 
76 /* window modules management */
77 struct WINDOW_MODULES {
78    int keyboard;
79    int mouse;
80    int joystick;
81    int joy_type;
82    int sound;
83    int digi_card;
84    int midi_card;
85    int sound_input;
86    int digi_input_card;
87    int midi_input_card;
88 };
89 
90 /* Used in adjust_window(). */
91 #ifndef CCHILDREN_TITLEBAR
92    #define CCHILDREN_TITLEBAR 5
93 typedef struct {
94    DWORD cbSize;
95    RECT  rcTitleBar;
96    DWORD rgstate[CCHILDREN_TITLEBAR + 1];
97 } TITLEBARINFO, *PTITLEBARINFO, *LPTITLEBARINFO;
98 #endif /* ifndef CCHILDREN_TITLEBAR */
99 
100 
101 
102 /* init_window_modules:
103  *  Initialises the modules that are specified by the WM argument.
104  */
init_window_modules(struct WINDOW_MODULES * wm)105 static int init_window_modules(struct WINDOW_MODULES *wm)
106 {
107    if (wm->keyboard)
108       install_keyboard();
109 
110    if (wm->mouse)
111       install_mouse();
112 
113    if (wm->joystick)
114       install_joystick(wm->joy_type);
115 
116    if (wm->sound)
117       install_sound(wm->digi_card, wm->midi_card, NULL);
118 
119    if (wm->sound_input)
120       install_sound_input(wm->digi_input_card, wm->midi_input_card);
121 
122    return 0;
123 }
124 
125 
126 
127 /* exit_window_modules:
128  *  Removes the modules that depend upon the main window:
129  *   - keyboard (DirectInput),
130  *   - mouse (DirectInput),
131  *   - joystick (DirectInput),
132  *   - sound (DirectSound),
133  *   - sound input (DirectSoundCapture).
134  *  If WM is not NULL, record which modules are really removed.
135  */
exit_window_modules(struct WINDOW_MODULES * wm)136 static void exit_window_modules(struct WINDOW_MODULES *wm)
137 {
138    if (wm)
139       memset(wm, 0, sizeof(*wm));
140 
141    if (_keyboard_installed) {
142      if (wm)
143          wm->keyboard = TRUE;
144 
145       remove_keyboard();
146    }
147 
148    if (_mouse_installed) {
149       if (wm)
150          wm->mouse = TRUE;
151 
152       remove_mouse();
153    }
154 
155    if (_joystick_installed) {
156       if (wm) {
157          wm->joystick = TRUE;
158          wm->joy_type = _joy_type;
159       }
160 
161       remove_joystick();
162    }
163 
164    if (_sound_installed) {
165       if (wm) {
166          wm->sound = TRUE;
167          wm->digi_card = digi_card;
168          wm->midi_card = midi_card;
169       }
170 
171       remove_sound();
172    }
173 
174    if (_sound_input_installed) {
175       if (wm) {
176          wm->sound_input = TRUE;
177          wm->digi_input_card = digi_input_card;
178          wm->midi_input_card = midi_input_card;
179       }
180 
181       remove_sound_input();
182    }
183 }
184 
185 
186 
187 /* wnd_call_proc:
188  *  Instructs the window thread to call the specified procedure and
189  *  waits until the procedure has returned.
190  */
wnd_call_proc(int (* proc)(void))191 int wnd_call_proc(int (*proc) (void))
192 {
193    return SendMessage(allegro_wnd, msg_call_proc, (WPARAM)proc, (LPARAM)0);
194 }
195 
196 
197 
198 /* wnd_schedule_proc:
199  *  Instructs the window thread to call the specified procedure but
200  *  doesn't wait until the procedure has returned.
201  */
wnd_schedule_proc(int (* proc)(void))202 void wnd_schedule_proc(int (*proc) (void))
203 {
204    PostMessage(allegro_wnd, msg_call_proc, (WPARAM)proc, (LPARAM)0);
205 }
206 
207 
208 
209 /* directx_wnd_proc:
210  *  Window procedure for the Allegro window class.
211  */
directx_wnd_proc(HWND wnd,UINT message,WPARAM wparam,LPARAM lparam)212 static LRESULT CALLBACK directx_wnd_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
213 {
214    PAINTSTRUCT ps;
215 
216    if (message == msg_call_proc)
217       return ( ( LRESULT(*)( void ) )wparam ) ( );
218 
219    if (message == msg_suicide) {
220       DestroyWindow(wnd);
221       return 0;
222    }
223 
224    /* Call user callback if available */
225    if (wnd_msg_pre_proc){
226       int retval = 0;
227       if (wnd_msg_pre_proc(wnd, message, wparam, lparam, &retval) == 0)
228          return (LRESULT)retval;
229    }
230 
231    /* See get_reverse_mapping() in wkeybd.c to see what this is for. */
232    if (FALSE && (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)) {
233       static char name[256];
234       TCHAR str[256];
235       WCHAR wstr[256];
236 
237       GetKeyNameText(lparam, str, sizeof str);
238       MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstr, sizeof wstr);
239       uconvert((char *)wstr, U_UNICODE, name, U_CURRENT, sizeof name);
240       _TRACE(PREFIX_I" key[%s] = 0x%08lx;\n", name, lparam & 0x1ff0000);
241    }
242 
243    switch (message) {
244 
245       case WM_CREATE:
246          if (!user_wnd_proc)
247             allegro_wnd = wnd;
248          break;
249 
250       case WM_DESTROY:
251          if (user_wnd_proc) {
252             exit_window_modules(NULL);
253             _win_reset_switch_mode();
254          }
255          else {
256             PostQuitMessage(0);
257          }
258 
259          allegro_wnd = NULL;
260          break;
261 
262       case WM_SETCURSOR:
263          if (!user_wnd_proc || _mouse_installed) {
264             mouse_set_syscursor();
265             return 1;  /* not TRUE */
266          }
267          break;
268 
269       case WM_ACTIVATE:
270          if (LOWORD(wparam) == WA_INACTIVE) {
271             _win_switch_out();
272          }
273          else {
274 	    /* Ignore the WM_ACTIVATE event if the window is minimized. */
275 	    if (HIWORD(wparam))
276 	       break;
277 
278             if (gfx_driver && !gfx_driver->windowed) {
279                /* 1.2s delay to let Windows complete the switch in fullscreen mode */
280                SetTimer(allegro_wnd, SWITCH_TIMER, 1200, NULL);
281             }
282             else {
283                /* no delay in windowed mode */
284                _win_switch_in();
285             }
286          }
287          break;
288 
289       case WM_TIMER:
290          if (wparam == SWITCH_TIMER) {
291             KillTimer(allegro_wnd, SWITCH_TIMER);
292             _win_switch_in();
293             return 0;
294          }
295          break;
296 
297       case WM_ENTERSIZEMOVE:
298          if (win_gfx_driver && win_gfx_driver->enter_sysmode)
299             win_gfx_driver->enter_sysmode();
300          break;
301 
302       case WM_EXITSIZEMOVE:
303          if (win_gfx_driver && win_gfx_driver->exit_sysmode)
304             win_gfx_driver->exit_sysmode();
305          break;
306 
307       case WM_MOVE:
308          if (GetActiveWindow() == allegro_wnd) {
309             if (!IsIconic(allegro_wnd)) {
310                wnd_x = (short) LOWORD(lparam);
311                wnd_y = (short) HIWORD(lparam);
312 
313                if (win_gfx_driver && win_gfx_driver->move)
314                   win_gfx_driver->move(wnd_x, wnd_y, wnd_width, wnd_height);
315             }
316             else if (win_gfx_driver && win_gfx_driver->iconify) {
317                win_gfx_driver->iconify();
318             }
319          }
320          break;
321 
322       case WM_SIZE:
323          wnd_width = LOWORD(lparam);
324          wnd_height = HIWORD(lparam);
325          break;
326 
327       case WM_PAINT:
328          if (!user_wnd_proc || win_gfx_driver) {
329             BeginPaint(wnd, &ps);
330             if (win_gfx_driver && win_gfx_driver->paint)
331                 win_gfx_driver->paint(&ps.rcPaint);
332             EndPaint(wnd, &ps);
333             return 0;
334          }
335          break;
336 
337       case WM_KEYDOWN:
338       case WM_KEYUP:
339       case WM_SYSKEYDOWN:
340       case WM_SYSKEYUP:
341          /* Disable the default message-based key handler
342           * in order to prevent conflicts on NT kernels.
343           */
344          if (!user_wnd_proc || _keyboard_installed)
345             return 0;
346          break;
347 
348       case WM_SYSCOMMAND:
349          if (wparam == SC_MONITORPOWER || wparam == SC_SCREENSAVE) {
350             if (_screensaver_policy == ALWAYS_DISABLED
351                 || (_screensaver_policy == FULLSCREEN_DISABLED
352                     && gfx_driver && !gfx_driver->windowed))
353             return 0;
354          }
355          break;
356 
357       case WM_INITMENUPOPUP:
358          wnd_sysmenu = TRUE;
359          mouse_set_sysmenu(TRUE);
360 
361          if (win_gfx_driver && win_gfx_driver->enter_sysmode)
362             win_gfx_driver->enter_sysmode();
363          break;
364 
365       case WM_MENUSELECT:
366          if ((HIWORD(wparam) == 0xFFFF) && (!lparam)) {
367             wnd_sysmenu = FALSE;
368             mouse_set_sysmenu(FALSE);
369 
370             if (win_gfx_driver && win_gfx_driver->exit_sysmode)
371                win_gfx_driver->exit_sysmode();
372          }
373          break;
374 
375       case WM_MENUCHAR :
376          return (MNC_CLOSE<<16)|(wparam&0xffff);
377 
378       case WM_CLOSE:
379          if (!user_wnd_proc) {
380             if (user_close_proc)
381                (*user_close_proc)();
382             return 0;
383          }
384          break;
385 
386       case WM_QUERYNEWPALETTE:
387       case WM_PALETTECHANGED:
388          if ((HWND)wparam != wnd && gfx_directx_primary_surface) {
389             IDirectDrawSurface2_SetPalette(gfx_directx_primary_surface->id, ddpalette);
390             InvalidateRect(wnd, NULL, 1);
391             return 1;
392          }
393          break;
394    }
395 
396    /* pass message to default window proc */
397    if (user_wnd_proc)
398       return CallWindowProc(user_wnd_proc, wnd, message, wparam, lparam);
399    else
400       return DefWindowProc(wnd, message, wparam, lparam);
401 }
402 
403 
404 
405 /* create_directx_window:
406  *  Creates the Allegro window.
407  */
create_directx_window(void)408 static HWND create_directx_window(void)
409 {
410    static int first = 1;
411    WNDCLASS wnd_class;
412    char fname[1024];
413    HWND wnd;
414 
415    if (first) {
416       /* setup the window class */
417       wnd_class.style = CS_HREDRAW | CS_VREDRAW;
418       wnd_class.lpfnWndProc = directx_wnd_proc;
419       wnd_class.cbClsExtra = 0;
420       wnd_class.cbWndExtra = 0;
421       wnd_class.hInstance = allegro_inst;
422       wnd_class.hIcon = LoadIcon(allegro_inst, "allegro_icon");
423       if (!wnd_class.hIcon)
424          wnd_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
425       wnd_class.hCursor = LoadCursor(NULL, IDC_ARROW);
426       wnd_class.hbrBackground = NULL;
427       wnd_class.lpszMenuName = NULL;
428       wnd_class.lpszClassName = ALLEGRO_WND_CLASS;
429 
430       RegisterClass(&wnd_class);
431 
432       /* what are we called? */
433       get_executable_name(fname, sizeof(fname));
434       ustrlwr(fname);
435 
436       usetc(get_extension(fname), 0);
437       if (ugetat(fname, -1) == '.')
438          usetat(fname, -1, 0);
439 
440       do_uconvert(get_filename(fname), U_CURRENT, wnd_title, U_ASCII, WND_TITLE_SIZE);
441 
442       first = 0;
443    }
444 
445    /* create the window now */
446    wnd = CreateWindowEx(WS_EX_APPWINDOW, ALLEGRO_WND_CLASS, wnd_title,
447                         WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
448                         -100, -100, 0, 0,
449                         NULL, NULL, allegro_inst, NULL);
450    if (!wnd) {
451       _TRACE(PREFIX_E "CreateWindowEx() failed (%s)\n", win_err_str(GetLastError()));
452       return NULL;
453    }
454 
455    SetSystemPaletteUse(GetDC(wnd), SYSPAL_NOSTATIC256);
456    ShowWindow(wnd, SW_SHOWNORMAL);
457    SetForegroundWindow(wnd);
458    UpdateWindow(wnd);
459 
460    return wnd;
461 }
462 
463 
464 
465 /* wnd_thread_proc:
466  *  Thread function that handles the messages of the directx window.
467  */
wnd_thread_proc(HANDLE setup_event)468 static void wnd_thread_proc(HANDLE setup_event)
469 {
470    DWORD result;
471    MSG msg;
472 
473    _win_thread_init();
474    _TRACE(PREFIX_I "window thread starts\n");
475 
476    /* setup window */
477    if (wnd_create_proc)
478       allegro_wnd = wnd_create_proc(directx_wnd_proc);
479    else
480       allegro_wnd = create_directx_window();
481 
482    if (!allegro_wnd)
483       goto End;
484 
485    /* now the thread it running successfully, let's acknowledge */
486    SetEvent(setup_event);
487 
488    /* message loop */
489    while (TRUE) {
490       result = MsgWaitForMultipleObjects(_win_input_events, _win_input_event_id, FALSE, INFINITE, QS_ALLINPUT);
491       if ((result >= WAIT_OBJECT_0) && (result < (int)(WAIT_OBJECT_0 + _win_input_events))) {
492          /* one of the registered events is in signaled state */
493          (*_win_input_event_handler[result - WAIT_OBJECT_0])();
494       }
495       else if (result == WAIT_OBJECT_0 + _win_input_events) {
496          /* messages are waiting in the queue */
497          while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
498             if (GetMessage(&msg, NULL, 0, 0)) {
499                DispatchMessage(&msg);
500             }
501             else {
502                goto End;
503             }
504          }
505       }
506    }
507 
508  End:
509    _TRACE(PREFIX_I "window thread exits\n");
510    _win_thread_exit();
511 }
512 
513 
514 
515 /* init_directx_window:
516  *  If the user called win_set_window, the user window will be hooked to receive
517  *  messages from Allegro. Otherwise a thread is created to own the new window.
518  */
init_directx_window(void)519 int init_directx_window(void)
520 {
521    union {
522      POINT p;
523      RECT r;
524    } win_rect;
525    HANDLE events[2];
526    long result;
527 
528    /* setup globals */
529    msg_call_proc = RegisterWindowMessage("Allegro call proc");
530    msg_suicide = RegisterWindowMessage("Allegro window suicide");
531 
532    /* initialize gfx critical section */
533    InitializeCriticalSection(&gfx_crit_sect);
534 
535    if (user_wnd) {
536       /* initializes input module and requests dedicated thread */
537       _win_input_init(TRUE);
538 
539       /* hook the user window */
540       user_wnd_proc = (WNDPROC) SetWindowLongPtr(user_wnd, GWLP_WNDPROC, (LONG_PTR)directx_wnd_proc);
541       if (!user_wnd_proc)
542          return -1;
543 
544       allegro_wnd = user_wnd;
545 
546       /* retrieve the window dimensions */
547       GetWindowRect(allegro_wnd, &win_rect.r);
548       ClientToScreen(allegro_wnd, &win_rect.p);
549       ClientToScreen(allegro_wnd, &win_rect.p + 1);
550       wnd_x = win_rect.r.left;
551       wnd_y = win_rect.r.top;
552       wnd_width = win_rect.r.right - win_rect.r.left;
553       wnd_height = win_rect.r.bottom - win_rect.r.top;
554    }
555    else {
556       /* initializes input module without dedicated thread */
557       _win_input_init(FALSE);
558 
559       /* create window thread */
560       events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);        /* acknowledges that thread is up */
561       events[1] = (HANDLE) _beginthread(wnd_thread_proc, 0, events[0]);
562       result = WaitForMultipleObjects(2, events, FALSE, INFINITE);
563 
564       CloseHandle(events[0]);
565 
566       switch (result) {
567 	 case WAIT_OBJECT_0:    /* window was created successfully */
568 	    wnd_thread = events[1];
569 	    SetThreadPriority(wnd_thread, THREAD_PRIORITY_ABOVE_NORMAL);
570 	    break;
571 
572 	 default:               /* thread failed to create window */
573 	    return -1;
574       }
575    }
576 
577    /* save window style */
578    old_style = GetWindowLong(allegro_wnd, GWL_STYLE);
579 
580    return 0;
581 }
582 
583 
584 
585 /* exit_directx_window:
586  *  If a user window was hooked, the old window proc is set. Otherwise
587  *  the window thread is destroyed.
588  */
exit_directx_window(void)589 void exit_directx_window(void)
590 {
591    if (user_wnd) {
592       /* restore old window proc */
593       SetWindowLongPtr(user_wnd, GWLP_WNDPROC, (LONG_PTR)user_wnd_proc);
594       user_wnd_proc = NULL;
595       user_wnd = NULL;
596       allegro_wnd = NULL;
597    }
598    else {
599       /* Destroy the window: we cannot directly use DestroyWindow() because
600        * we are not running in the same thread as that of the window.
601        */
602       PostMessage(allegro_wnd, msg_suicide, 0, 0);
603 
604       /* wait until the window thread ends */
605       WaitForSingleObject(wnd_thread, INFINITE);
606       wnd_thread = NULL;
607    }
608 
609    DeleteCriticalSection(&gfx_crit_sect);
610 
611    _win_input_exit();
612 
613    window_is_initialized = FALSE;
614 }
615 
616 
617 
618 /* restore_window_style:
619  *  Restores the previous style of the window.
620  */
restore_window_style(void)621 void restore_window_style(void)
622 {
623    SetWindowLong(allegro_wnd, GWL_STYLE, old_style);
624    SetWindowPos(allegro_wnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
625 }
626 
627 
628 
629 /* adjust_window:
630  *  Moves and resizes the window if we have full control over it.
631  */
adjust_window(int w,int h)632 int adjust_window(int w, int h)
633 {
634    RECT working_area, win_size;
635    TITLEBARINFO tb_info;
636    HMODULE user32_handle;
637    typedef BOOL (WINAPI *func)(HWND, PTITLEBARINFO);
638    func get_title_bar_info = NULL;
639    int tb_height = 0;
640    static int last_w=-1, last_h=-1;
641 
642    if (!user_wnd) {
643       SystemParametersInfo(SPI_GETWORKAREA, 0, &working_area, 0);
644 
645       if ((last_w == -1) && (last_h == -1)) {
646          /* first window placement: try to center it */
647          last_wnd_x = (working_area.left + working_area.right - w)/2;
648          last_wnd_y = (working_area.top + working_area.bottom - h)/2;
649       }
650       else {
651          /* try to get the height of the window's title bar */
652          user32_handle = GetModuleHandle("user32");
653          if (user32_handle) {
654             get_title_bar_info
655                = (func)GetProcAddress(user32_handle, "GetTitleBarInfo");
656             if (get_title_bar_info) {
657                tb_info.cbSize = sizeof(TITLEBARINFO);
658                if (get_title_bar_info(allegro_wnd, &tb_info))
659                   tb_height
660                      = tb_info.rcTitleBar.bottom - tb_info.rcTitleBar.top;
661             }
662          }
663          if (!user32_handle || !get_title_bar_info)
664             tb_height = GetSystemMetrics(SM_CYSIZE);
665 
666 	 /* try to center the window relative to its last position */
667 	 last_wnd_x += (last_w - w)/2;
668 	 last_wnd_y += (last_h - h)/2;
669 
670 	 if (last_wnd_x + w >= working_area.right)
671 	    last_wnd_x = working_area.right - w;
672 	 if (last_wnd_y + h >= working_area.bottom)
673 	    last_wnd_y = working_area.bottom - h;
674 	 if (last_wnd_x < working_area.left)
675 	    last_wnd_x = working_area.left;
676 	 if (last_wnd_y - tb_height < working_area.top)
677 	    last_wnd_y = working_area.top + tb_height;
678       }
679 
680 #ifdef ALLEGRO_COLORCONV_ALIGNED_WIDTH
681       last_wnd_x &= 0xfffffffc;
682 #endif
683 
684       win_size.left = last_wnd_x;
685       win_size.top = last_wnd_y;
686       win_size.right = last_wnd_x+w;
687       win_size.bottom = last_wnd_y+h;
688 
689       last_w = w;
690       last_h = h;
691 
692       /* retrieve the size of the decorated window */
693       AdjustWindowRect(&win_size, GetWindowLong(allegro_wnd, GWL_STYLE), FALSE);
694 
695       /* display the window */
696       MoveWindow(allegro_wnd, win_size.left, win_size.top,
697                  win_size.right - win_size.left, win_size.bottom - win_size.top, TRUE);
698 
699       /* check that the actual window size is the one requested */
700       GetClientRect(allegro_wnd, &win_size);
701       if (((win_size.right - win_size.left) != w) || ((win_size.bottom - win_size.top) != h))
702          return -1;
703 
704       wnd_x = last_wnd_x;
705       wnd_y = last_wnd_y;
706       wnd_width = w;
707       wnd_height = h;
708    }
709 
710    return 0;
711 }
712 
713 
714 
715 /* save_window_pos:
716  *  Stores the position of the current window before closing it so that
717  *  it can be used as the initial position for the next window.
718  */
save_window_pos(void)719 void save_window_pos(void)
720 {
721    last_wnd_x = wnd_x;
722    last_wnd_y = wnd_y;
723 }
724 
725 
726 
727 /* win_set_window:
728  *  Selects an user-defined window for Allegro or
729  *  the built-in window if NULL is passed.
730  */
win_set_window(HWND wnd)731 void win_set_window(HWND wnd)
732 {
733    static int (*saved_scbc)(void (*proc)(void)) = NULL;
734    struct WINDOW_MODULES wm;
735 
736    if (window_is_initialized || !wnd) {
737       exit_window_modules(&wm);
738       exit_directx_window();
739    }
740 
741    user_wnd = wnd;
742 
743    /* The user retains full control over the close button if he registers
744       a user-defined window. */
745    if (user_wnd) {
746       if (!saved_scbc)
747          saved_scbc = system_directx.set_close_button_callback;
748 
749       system_directx.set_close_button_callback = NULL;
750    }
751    else {
752       if (saved_scbc)
753          system_directx.set_close_button_callback = saved_scbc;
754    }
755 
756    if (window_is_initialized || !wnd) {
757       init_directx_window();
758       init_window_modules(&wm);
759    }
760 
761    window_is_initialized = TRUE;
762 }
763 
764 
765 
766 /* win_get_window:
767  *  Returns the Allegro window handle.
768  */
win_get_window(void)769 HWND win_get_window(void)
770 {
771    return allegro_wnd;
772 }
773 
774 
win_set_msg_pre_proc(int (* proc)(HWND,UINT,WPARAM,LPARAM,int *))775 void win_set_msg_pre_proc(int (*proc)(HWND, UINT, WPARAM, LPARAM, int *))
776 {
777    wnd_msg_pre_proc = proc;
778 }
779 
780 
781 /* win_set_wnd_create_proc:
782  *  Sets a custom window creation proc.
783  */
win_set_wnd_create_proc(HWND (* proc)(WNDPROC))784 void win_set_wnd_create_proc(HWND (*proc)(WNDPROC))
785 {
786    wnd_create_proc = proc;
787 }
788 
789 
790 
791 /* win_grab_input:
792  *  Grabs the input devices.
793  */
win_grab_input(void)794 void win_grab_input(void)
795 {
796    wnd_schedule_proc(key_dinput_acquire);
797    wnd_schedule_proc(mouse_dinput_grab);
798    wnd_schedule_proc(joystick_dinput_acquire);
799 }
800