makepad_platform/os/windows/
win32_window.rs

1use {
2    std::{
3        cell::{
4            RefCell,
5            Cell,
6        },
7        rc::Rc,
8        ffi::OsStr,
9        os::windows::ffi::OsStrExt,
10        mem,
11    },
12    
13    crate::{
14        windows::{
15            core::PCWSTR,
16            core::IntoParam,
17            core::Result as coreResult,
18            core::HRESULT,
19            Win32::{
20                Foundation::{
21                    HWND,
22                    HANDLE,
23                    HGLOBAL,
24                    WPARAM,
25                    LPARAM,
26                    LRESULT,
27                    RECT,
28                    POINT,
29                    POINTL,
30                },
31                System::{
32                    Memory::{
33                        GlobalLock,
34                        GlobalAlloc,
35                        GlobalSize,
36                        GlobalUnlock,
37                        GLOBAL_ALLOC_FLAGS,
38                    },
39                    Ole::{
40                        CF_UNICODETEXT,
41                        //RegisterDragDrop,
42                        //IDropTarget,
43                        DROPEFFECT,
44                        DROPEFFECT_COPY,
45                        DROPEFFECT_MOVE,
46                        DROPEFFECT_LINK,
47                    },
48                    SystemServices::{
49                        MODIFIERKEYS_FLAGS,
50                        MK_CONTROL,
51                        MK_SHIFT,
52                    },
53                    WindowsProgramming::GMEM_DDESHARE,
54                    DataExchange::{
55                        OpenClipboard,
56                        EmptyClipboard,
57                        GetClipboardData,
58                        SetClipboardData,
59                        CloseClipboard,
60                    },
61                    LibraryLoader::GetModuleHandleW,
62                },
63                UI::{
64                    WindowsAndMessaging::{
65                        CreateWindowExW,
66                        SetWindowLongPtrW,
67                        GetWindowLongPtrW,
68                        DefWindowProcW,
69                        ShowWindow,
70                        PostMessageW,
71                        GetWindowRect,
72                        DestroyWindow,
73                        SetWindowPos,
74                        GetWindowPlacement,
75                        WINDOWPLACEMENT,
76                        GetClientRect,
77                        MoveWindow,
78                        GWL_EXSTYLE,
79                        HWND_TOPMOST,
80                        HWND_NOTOPMOST,
81                        WS_SIZEBOX,
82                        WS_MAXIMIZEBOX,
83                        WS_MINIMIZEBOX,
84                        WS_POPUP,
85                        WS_CLIPSIBLINGS,
86                        WS_CLIPCHILDREN,
87                        WS_SYSMENU,
88                        WS_EX_WINDOWEDGE,
89                        WS_EX_APPWINDOW,
90                        WS_EX_ACCEPTFILES,
91                        WS_EX_TOPMOST,
92                        CW_USEDEFAULT,
93                        GWLP_USERDATA,
94                        SW_SHOW,
95                        SW_RESTORE,
96                        SW_MAXIMIZE,
97                        SW_MINIMIZE,
98                        SWP_NOMOVE,
99                        SWP_NOSIZE,
100                        WM_ACTIVATE,
101                        WM_NCCALCSIZE,
102                        WM_NCHITTEST,
103                        WA_ACTIVE,
104                        WM_ERASEBKGND,
105                        WM_MOUSEMOVE,
106                        WM_MOUSEWHEEL,
107                        WM_LBUTTONDOWN,
108                        WM_LBUTTONUP,
109                        WM_RBUTTONDOWN,
110                        WM_RBUTTONUP,
111                        WM_MBUTTONDOWN,
112                        WM_MBUTTONUP,
113                        WM_KEYDOWN,
114                        WM_SYSKEYDOWN,
115                        WM_CLOSE,
116                        WM_KEYUP,
117                        WM_SYSKEYUP,
118                        WM_CHAR,
119                        WM_ENTERSIZEMOVE,
120                        WM_EXITSIZEMOVE,
121                        WM_SIZE,
122                        WM_DPICHANGED,
123                        WM_DESTROY,
124                        HTTOPLEFT,
125                        HTBOTTOMLEFT,
126                        HTLEFT,
127                        HTTOPRIGHT,
128                        HTBOTTOMRIGHT,
129                        HTRIGHT,
130                        HTTOP,
131                        HTBOTTOM,
132                        HTCLIENT,
133                        HTCAPTION,
134                        HTSYSMENU
135                    },
136                    Controls::{
137                        MARGINS,
138                        WM_MOUSELEAVE
139                    },
140                    Input::KeyboardAndMouse::{
141                        VIRTUAL_KEY,
142                        ReleaseCapture,
143                        SetCapture,
144                        TrackMouseEvent,
145                        GetKeyState,
146                        TRACKMOUSEEVENT,
147                        TME_LEAVE,
148                        VK_CONTROL,
149                        VK_SHIFT,
150                        VK_MENU,
151                        VK_LWIN,
152                        VK_RWIN,
153                        VK_ESCAPE,
154                        VK_OEM_3,
155                        VK_0,
156                        VK_1,
157                        VK_2,
158                        VK_3,
159                        VK_4,
160                        VK_5,
161                        VK_6,
162                        VK_7,
163                        VK_8,
164                        VK_9,
165                        VK_OEM_MINUS,
166                        VK_OEM_PLUS,
167                        VK_BACK,
168                        VK_TAB,
169                        VK_Q,
170                        VK_W,
171                        VK_E,
172                        VK_R,
173                        VK_T,
174                        VK_Y,
175                        VK_U,
176                        VK_I,
177                        VK_O,
178                        VK_P,
179                        VK_OEM_4,
180                        VK_OEM_6,
181                        VK_RETURN,
182                        VK_A,
183                        VK_S,
184                        VK_D,
185                        VK_F,
186                        VK_G,
187                        VK_H,
188                        VK_J,
189                        VK_K,
190                        VK_L,
191                        VK_OEM_1,
192                        VK_OEM_7,
193                        VK_OEM_5,
194                        VK_Z,
195                        VK_X,
196                        VK_C,
197                        VK_V,
198                        VK_B,
199                        VK_N,
200                        VK_M,
201                        VK_OEM_COMMA,
202                        VK_OEM_PERIOD,
203                        VK_OEM_2,
204                        VK_LCONTROL,
205                        VK_RCONTROL,
206                        VK_LMENU,
207                        VK_RMENU,
208                        VK_LSHIFT,
209                        VK_RSHIFT,
210                        VK_SPACE,
211                        VK_CAPITAL,
212                        VK_F1,
213                        VK_F2,
214                        VK_F3,
215                        VK_F4,
216                        VK_F5,
217                        VK_F6,
218                        VK_F7,
219                        VK_F8,
220                        VK_F9,
221                        VK_F10,
222                        VK_F11,
223                        VK_F12,
224                        VK_SNAPSHOT,
225                        VK_SCROLL,
226                        VK_PAUSE,
227                        VK_INSERT,
228                        VK_DELETE,
229                        VK_HOME,
230                        VK_END,
231                        VK_PRIOR,
232                        VK_NEXT,
233                        VK_NUMPAD0,
234                        VK_NUMPAD1,
235                        VK_NUMPAD2,
236                        VK_NUMPAD3,
237                        VK_NUMPAD4,
238                        VK_NUMPAD5,
239                        VK_NUMPAD6,
240                        VK_NUMPAD7,
241                        VK_NUMPAD8,
242                        VK_NUMPAD9,
243                        VK_SUBTRACT,
244                        VK_ADD,
245                        VK_DECIMAL,
246                        VK_MULTIPLY,
247                        VK_DIVIDE,
248                        VK_NUMLOCK,
249                        VK_UP,
250                        VK_DOWN,
251                        VK_LEFT,
252                        VK_RIGHT,
253                    },
254                },
255                Graphics::{
256                    Dwm::DwmExtendFrameIntoClientArea,
257                    Gdi::ScreenToClient,
258                },
259            },
260        },
261        event::*,
262        area::Area,
263        os::windows::{
264            win32_app::{
265                Win32App,
266                encode_wide,
267                FALSE,
268                get_win32_app_global,
269            },
270            win32_event::*,
271            droptarget::*,
272        },
273        window::WindowId,
274        cx::*,
275        cursor::MouseCursor,
276    },
277};
278
279// Copied from Microsoft so it refers to the right IDropTarget
280#[allow(non_snake_case)]
281pub unsafe fn RegisterDragDrop<P0, P1>(hwnd: P0, pdroptarget: P1) -> coreResult<()>
282where
283    P0: IntoParam<HWND>,
284    P1: IntoParam<IDropTarget>,
285{
286    ::windows_targets::link!("ole32.dll" "system" fn RegisterDragDrop(hwnd : HWND, pdroptarget : * mut::core::ffi::c_void) -> HRESULT);
287    RegisterDragDrop(hwnd.into_param().abi(), pdroptarget.into_param().abi()).ok()
288}
289
290//#[derive(Clone)]
291pub struct Win32Window {
292    pub window_id: WindowId,
293    pub last_window_geom: WindowGeom,
294    
295    pub mouse_buttons_down: usize,
296    pub last_key_mod: KeyModifiers,
297    pub ime_spot: DVec2,
298    pub current_cursor: MouseCursor,
299    pub last_mouse_pos: DVec2,
300    pub ignore_wmsize: usize,
301    pub hwnd: HWND,
302    pub track_mouse_event: bool,
303}
304
305impl Win32Window {
306    
307    // 2-stage initialization (new and init) to connect GWLP_USERDATA 
308
309    // create window structure and register drag/drop
310    pub fn new(window_id: WindowId,title: &str, position: Option<DVec2>) -> Win32Window {
311
312        let title = encode_wide(title);
313        
314        let style = WS_SIZEBOX
315            | WS_MAXIMIZEBOX
316            | WS_MINIMIZEBOX
317            | WS_POPUP
318            | WS_CLIPSIBLINGS
319            | WS_CLIPCHILDREN
320            | WS_SYSMENU;
321        
322        let style_ex = WS_EX_WINDOWEDGE
323            | WS_EX_APPWINDOW
324            | WS_EX_ACCEPTFILES;
325        
326        let (x, y) = if let Some(position) = position {
327            (position.x as i32, position.y as i32)
328        }
329        else {
330            (CW_USEDEFAULT, CW_USEDEFAULT)
331        };
332
333        let hwnd = unsafe { CreateWindowExW(
334            style_ex,
335            PCWSTR(get_win32_app_global().window_class_name.as_ptr()),
336            PCWSTR(title.as_ptr()),
337            style,
338            x,
339            y,
340            CW_USEDEFAULT,
341            CW_USEDEFAULT,
342            None,
343            None,
344            GetModuleHandleW(None).unwrap(),
345            None,
346        ) };
347
348        // create DropTarget object that accesses the same data object, convert to COM and give to Microsoft
349        let drop_target: IDropTarget = DropTarget { drag_item: RefCell::new(None),hwnd, }.into();
350        unsafe { RegisterDragDrop(hwnd, &drop_target).unwrap() };
351
352        Win32Window {
353            window_id,
354            mouse_buttons_down: 0,
355            last_window_geom: WindowGeom::default(),
356            last_key_mod: KeyModifiers::default(),
357            ime_spot: DVec2::default(),
358            current_cursor: MouseCursor::Default,
359            last_mouse_pos: DVec2::default(),
360            ignore_wmsize: 0,
361            hwnd,
362            track_mouse_event: false,
363        }
364    }
365
366    // initialize GWLP_USERDATA and registration of global stuff, and set outer size
367    pub fn init(&mut self,size: DVec2) {
368
369        unsafe { SetWindowLongPtrW(self.hwnd, GWLP_USERDATA, self as *const _ as isize) };
370
371        get_win32_app_global().dpi_functions.enable_non_client_dpi_scaling(self.hwnd);
372        get_win32_app_global().all_windows.push(self.hwnd);
373
374        self.set_outer_size(size);
375    }
376    
377    pub unsafe extern "system" fn window_class_proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM,) -> LRESULT {
378        
379        let user_data = GetWindowLongPtrW(hwnd, GWLP_USERDATA);
380        if user_data == 0 {
381            return DefWindowProcW(hwnd, msg, wparam, lparam);
382        };
383        
384        let window = &mut (*(user_data as *mut Win32Window));
385        match msg {
386            WM_ACTIVATE => {
387                if wparam.0 & 0xffff == WA_ACTIVE as usize {
388                    window.do_callback(Win32Event::AppGotFocus);
389                }
390                else {
391                    window.do_callback(Win32Event::AppLostFocus);
392                }
393            },
394            WM_NCCALCSIZE => {
395                // check if we are maximised
396                if window.get_is_maximized() {
397                    return DefWindowProcW(hwnd, msg, wparam, lparam);
398                }
399                if wparam == WPARAM(1) {
400                    let margins = MARGINS {
401                        cxLeftWidth: 0,
402                        cxRightWidth: 0,
403                        cyTopHeight: 0,
404                        cyBottomHeight: 1
405                    };
406                    DwmExtendFrameIntoClientArea(hwnd, &margins).unwrap();
407                    return LRESULT(0)
408                }
409            },
410            WM_NCHITTEST => {
411                //let ycoord = (lparam.0 >> 16) as u16 as i16 as i32;
412                //let xcoord = (lparam.0 & 0xffff) as u16 as i16 as i32;
413                let abs = window.get_mouse_pos_from_lparam(lparam);
414                let mut rect = RECT {left: 0, top: 0, bottom: 0, right: 0};
415                const EDGE: f64 = 4.0; 
416                let dpi = window.get_dpi_factor();
417                GetWindowRect(hwnd, &mut rect).unwrap();
418                let rect = Rect{pos:dvec2(rect.left as f64 / dpi, rect.top as f64 / dpi),
419                size:dvec2( (rect.right-rect.left) as f64 / dpi,  (rect.bottom-rect.top) as f64/ dpi) 
420                }; 
421                if abs.x < rect.pos.x + EDGE {
422                    if abs.y < rect.pos.y  + EDGE {
423                        get_win32_app_global().set_mouse_cursor(MouseCursor::NwseResize);
424                        return LRESULT(HTTOPLEFT as isize);
425                    }
426                    if abs.y > rect.pos.y + rect.size.y - EDGE {
427                        get_win32_app_global().set_mouse_cursor(MouseCursor::NeswResize);
428                        return LRESULT(HTBOTTOMLEFT as isize);
429                    }
430                    get_win32_app_global().set_mouse_cursor(MouseCursor::EwResize);
431                    return LRESULT(HTLEFT as isize);
432                }
433                if abs.x > rect.pos.x+rect.size.x - EDGE {
434                    if abs.y < rect.pos.y  + EDGE {
435                        get_win32_app_global().set_mouse_cursor(MouseCursor::NeswResize);
436                        return LRESULT(HTTOPRIGHT as isize);
437                    }
438                    if abs.y > rect.pos.y + rect.size.y - EDGE {
439                        get_win32_app_global().set_mouse_cursor(MouseCursor::NwseResize);
440                        return LRESULT(HTBOTTOMRIGHT as isize);
441                    }
442                    get_win32_app_global().set_mouse_cursor(MouseCursor::EwResize);
443                    return LRESULT(HTRIGHT as isize);
444                }
445                if abs.y < rect.pos.y + EDGE {
446                    get_win32_app_global().set_mouse_cursor(MouseCursor::NsResize);
447                    return LRESULT(HTTOP as isize);
448                }
449                if abs.y > rect.pos.y+rect.size.y - EDGE {
450                    get_win32_app_global().set_mouse_cursor(MouseCursor::NsResize);
451                    return LRESULT(HTBOTTOM as isize);
452                }
453                let response = Rc::new(Cell::new(WindowDragQueryResponse::NoAnswer));
454                window.do_callback(
455                    Win32Event::WindowDragQuery(WindowDragQueryEvent {
456                        window_id: window.window_id,
457                        abs: window.get_mouse_pos_from_lparam(lparam)- rect.pos,
458                        response: response.clone()
459                    })
460                );
461                match response.get() {
462                    WindowDragQueryResponse::Client => {
463                        return LRESULT(HTCLIENT as isize);
464                    }
465                    WindowDragQueryResponse::Caption => {
466                        get_win32_app_global().set_mouse_cursor(MouseCursor::Default);
467                        return LRESULT(HTCAPTION as isize);
468                    },
469                    WindowDragQueryResponse::SysMenu => {
470                        get_win32_app_global().set_mouse_cursor(MouseCursor::Default);
471                        return LRESULT(HTSYSMENU as isize);
472                    }
473                    _ => ()
474                }
475                return LRESULT(HTCLIENT as isize);
476            },
477            WM_ERASEBKGND => {
478                return LRESULT(1)
479            },
480            WM_MOUSEMOVE => {
481                if get_win32_app_global().start_dragging_items.is_some(){
482                    return LRESULT(0)
483                }
484                if !window.track_mouse_event {
485                    window.track_mouse_event = true;
486                    let mut tme = TRACKMOUSEEVENT {
487                        cbSize: mem::size_of::<TRACKMOUSEEVENT>() as u32,
488                        dwFlags: TME_LEAVE,
489                        hwndTrack: hwnd,
490                        dwHoverTime: 0
491                    };
492                    TrackMouseEvent(&mut tme).unwrap();
493                }
494                window.send_mouse_move(
495                    window.get_mouse_pos_from_lparam(lparam),
496                    Self::get_key_modifiers()
497                )
498            },
499            WM_MOUSELEAVE => {
500                if get_win32_app_global().start_dragging_items.is_some() {
501                    return LRESULT(0)
502                }
503                window.track_mouse_event = false;
504                window.send_mouse_move(
505                    window.last_mouse_pos,
506                    Self::get_key_modifiers()
507                );
508                get_win32_app_global().current_cursor = MouseCursor::Hidden;
509            },
510            WM_MOUSEWHEEL => {
511                let delta = (wparam.0 >> 16) as u16 as i16 as f64;
512                window.send_scroll(DVec2 {x: 0.0, y: -delta}, Self::get_key_modifiers(), true);
513            },
514            WM_LBUTTONDOWN => {
515                // hack for drag/drop: save which window was last clicked on in win32_app
516                get_win32_app_global().currently_clicked_window_id = Some(window.window_id);
517                window.send_mouse_down(0, Self::get_key_modifiers());
518            },
519            WM_LBUTTONUP => window.send_mouse_up(0, Self::get_key_modifiers()),
520            WM_RBUTTONDOWN => window.send_mouse_down(1, Self::get_key_modifiers()),
521            WM_RBUTTONUP => window.send_mouse_up(1, Self::get_key_modifiers()),
522            WM_MBUTTONDOWN => window.send_mouse_down(2, Self::get_key_modifiers()),
523            WM_MBUTTONUP => window.send_mouse_up(2, Self::get_key_modifiers()),
524            WM_KEYDOWN | WM_SYSKEYDOWN => {
525                // detect control/cmd - c / v / x
526                let modifiers = Self::get_key_modifiers();
527                let key_code = Self::virtual_key_to_key_code(wparam);
528                if modifiers.alt && key_code == KeyCode::F4 {
529                    PostMessageW(hwnd, WM_CLOSE, WPARAM(0), LPARAM(0)).unwrap();
530                }
531                if modifiers.control || modifiers.logo {
532                    match key_code {
533                        KeyCode::KeyV => { // paste
534                            if let Ok(()) = OpenClipboard(None) {
535                                let mut data: Vec<u16> = Vec::new();
536                                let h_clipboard_data = GetClipboardData(CF_UNICODETEXT.0 as u32).unwrap();
537                                let h_clipboard_ptr = GlobalLock(std::mem::transmute::<_,HGLOBAL>(h_clipboard_data)) as *mut u16;
538                                let clipboard_size = GlobalSize(std::mem::transmute::<_,HGLOBAL>(h_clipboard_data));
539                                if clipboard_size > 2 {
540                                    data.resize((clipboard_size >> 1) - 1, 0);
541                                    std::ptr::copy_nonoverlapping(h_clipboard_ptr, data.as_mut_ptr(), data.len());
542                                    GlobalUnlock(std::mem::transmute::<_,HGLOBAL>(h_clipboard_data)).unwrap();
543                                    CloseClipboard().unwrap();
544                                    if let Ok(utf8) = String::from_utf16(&data) {
545                                        window.do_callback(
546                                            Win32Event::TextInput(TextInputEvent {
547                                                input: utf8,
548                                                was_paste: true,
549                                                replace_last: false
550                                            })
551                                        );
552                                    }
553                                }
554                                else {
555                                    GlobalUnlock(std::mem::transmute::<_,HGLOBAL>(h_clipboard_data)).unwrap();
556                                    CloseClipboard().unwrap();
557                                }
558                            }
559                        }
560                        KeyCode::KeyC => {
561                            let response = Rc::new(RefCell::new(None));
562                            window.do_callback(
563                                Win32Event::TextCut(TextClipboardEvent {
564                                    response: response.clone()
565                                })
566                            );
567                            let response = response.borrow();
568                            if let Some(response) = response.as_ref() {
569                                Self::copy_to_clipboard(response);
570                            }
571                        },
572                        KeyCode::KeyX => {
573                            let response = Rc::new(RefCell::new(None));
574                            window.do_callback(
575                                Win32Event::TextCut(TextClipboardEvent {
576                                    response: response.clone()
577                                })
578                            );
579                            let response = response.borrow();
580                            if let Some(response) = response.as_ref() {
581                                Self::copy_to_clipboard(response);
582                            }
583                        }
584                        _ => ()
585                    }
586                }
587                window.do_callback(
588                    Win32Event::KeyDown(KeyEvent {
589                        key_code: key_code,
590                        is_repeat: (lparam.0 & 0x7000_0000)>0,
591                        modifiers: modifiers,
592                        time: window.time_now()
593                    })
594                );
595            },
596            WM_KEYUP | WM_SYSKEYUP => {
597                window.do_callback(
598                    Win32Event::KeyUp(KeyEvent {
599                        key_code: Self::virtual_key_to_key_code(wparam),
600                        is_repeat: lparam.0 & 0x7fff>0,
601                        modifiers: Self::get_key_modifiers(),
602                        time: window.time_now()
603                    })
604                );
605                
606            },
607            WM_CHAR => {
608                if let Ok(utf8) = String::from_utf16(&[wparam.0 as u16]) {
609                    let char_code = utf8.chars().next().unwrap();
610                    if char_code >= ' ' {
611                        window.do_callback(
612                            Win32Event::TextInput(TextInputEvent {
613                                input: utf8,
614                                was_paste: false,
615                                replace_last: false
616                            })
617                        );
618                    }
619                }
620            },
621            WM_ENTERSIZEMOVE => {
622                get_win32_app_global().start_resize();
623                window.do_callback(Win32Event::WindowResizeLoopStart(window.window_id));
624            }
625            WM_EXITSIZEMOVE => {
626                get_win32_app_global().stop_resize();
627                window.do_callback(Win32Event::WindowResizeLoopStop(window.window_id));
628            },
629            WM_SIZE | WM_DPICHANGED => {
630                window.send_change_event();
631            },
632            WM_CLOSE => { // close requested
633                let accept_close = Rc::new(Cell::new(true));
634                window.do_callback(Win32Event::WindowCloseRequested(WindowCloseRequestedEvent {
635                    window_id: window.window_id,
636                    accept_close: accept_close.clone()
637                }));
638                if accept_close.get() {
639                    DestroyWindow(hwnd).unwrap();
640                }
641            },
642            WM_DESTROY => { // window actively destroyed
643                window.do_callback(
644                    Win32Event::WindowClosed(WindowClosedEvent {
645                        window_id: window.window_id,
646                    })
647                );
648            },
649
650            // from DropTarget
651            WM_DROPTARGET => {
652
653                // restore the Box<>
654                let message = unsafe { Box::from_raw(lparam.0 as *mut DropTargetMessage) };
655
656                match *message {
657
658                    DropTargetMessage::Leave => {
659                        if get_win32_app_global().is_dragging_internal.get() {
660                            // TODO: cancel DoDragDrop somehow
661                            window.do_callback(Win32Event::DragEnd);
662                        }
663                    },
664                    DropTargetMessage::Enter(flags,mut point,effect,drag_item) |
665                    DropTargetMessage::Over(flags,mut point,effect,drag_item) => {
666                        
667                        // decode message
668                        unsafe { ScreenToClient(window.hwnd,&mut point as *mut POINTL as *mut POINT) };
669                        let response = if (effect & DROPEFFECT_LINK) != DROPEFFECT(0) { DragResponse::Link }
670                        else if (effect & DROPEFFECT_MOVE) != DROPEFFECT(0) { DragResponse::Move }
671                        else if (effect & DROPEFFECT_COPY) != DROPEFFECT(0) { DragResponse::Copy }
672                        else { DragResponse::None };
673
674                        let dpi_factor = window.get_dpi_factor();
675
676                        // send to makepad
677                        window.do_callback(
678                            Win32Event::Drag(
679                                DragEvent {
680                                    modifiers: KeyModifiers {
681                                        shift: (flags & MK_SHIFT) != MODIFIERKEYS_FLAGS(0),
682                                        control: (flags & MK_CONTROL) != MODIFIERKEYS_FLAGS(0),
683                                        alt: false,  // TODO
684                                        logo: false,  // Windows doesn't have a logo button
685                                    },
686                                    handled: Cell::new(false),
687                                    abs: DVec2 { x: point.x as f64 / dpi_factor,y: point.y as f64 / dpi_factor, },
688                                    items: Rc::new(vec![drag_item]),
689                                    response: Rc::new(Cell::new(response)),
690                                }
691                            )
692                        );        
693                    }, 
694
695                    DropTargetMessage::Drop(flags,mut point,_effect,drag_item) => {
696
697                        // decode message
698                        unsafe { ScreenToClient(window.hwnd,&mut point as *mut POINTL as *mut POINT) };
699
700                        //log!("dropping at ({},{}), flags: {:04X}, response: {:?}, drag_item: {:?}",point.x,point.y,flags.0,response,drag_item);
701                        let dpi_factor = window.get_dpi_factor();
702
703                        // send to makepad
704                        window.do_callback(
705                            Win32Event::Drop(
706                                DropEvent {
707                                    modifiers: KeyModifiers {
708                                        shift: (flags & MK_SHIFT) != MODIFIERKEYS_FLAGS(0),
709                                        control: (flags & MK_CONTROL) != MODIFIERKEYS_FLAGS(0),
710                                        alt: false,  // TODO
711                                        logo: false,  // Windows doesn't have a logo button
712                                    },
713                                    handled: Cell::new(false),
714                                    abs: DVec2 { x: point.x as f64 / dpi_factor,y: point.y as f64 / dpi_factor, },
715                                    items: Rc::new(vec![drag_item]),
716                                }
717                            )
718                        );
719
720                        window.do_callback(
721                            Win32Event::DragEnd
722                        );        
723                    },
724                }
725            },
726
727            _ => {
728                return DefWindowProcW(hwnd, msg, wparam, lparam)
729            }
730        }
731        return LRESULT(1)
732        // lets get the window
733        // Unwinding into foreign code is undefined behavior. So we catch any panics that occur in our
734        // code, and if a panic happens we cancel any future operations.
735        //run_catch_panic(-1, || callback_inner(window, msg, wparam, lparam))
736    }
737
738    unsafe fn copy_to_clipboard(text: &String) {
739        // plug it into the windows clipboard
740        // make utf16 dta
741        if let Ok(()) = OpenClipboard(None) {
742            EmptyClipboard().unwrap();
743
744            let data: Vec<u16> = OsStr::new(text).encode_wide().chain(Some(0).into_iter()).collect();
745
746            let h_clipboard_data = GlobalAlloc(GLOBAL_ALLOC_FLAGS(GMEM_DDESHARE), 2 * data.len()).expect("GlobalAlloc for clipboard failed");
747
748            let h_clipboard_ptr = GlobalLock(h_clipboard_data) as *mut u16;
749
750            std::ptr::copy_nonoverlapping(data.as_ptr(), h_clipboard_ptr, data.len());
751
752            GlobalUnlock(h_clipboard_data).unwrap();
753            SetClipboardData(CF_UNICODETEXT.0 as u32, std::mem::transmute::<_,HANDLE>(h_clipboard_data)).unwrap();
754            CloseClipboard().unwrap();
755        }
756    }
757    
758    pub fn get_mouse_pos_from_lparam(&self, lparam: LPARAM) -> DVec2 {
759        let dpi = self.get_dpi_factor();
760        let ycoord = (lparam.0 >> 16) as u16 as i16 as f64;
761        let xcoord = (lparam.0 & 0xffff) as u16 as i16 as f64;
762        DVec2 {x: xcoord / dpi, y: ycoord / dpi}
763    }
764    
765    pub fn get_key_modifiers() -> KeyModifiers {
766        unsafe {
767            KeyModifiers {
768                control: GetKeyState(VK_CONTROL.0 as i32) & 0x80>0,
769                shift: GetKeyState(VK_SHIFT.0 as i32) & 0x80>0,
770                alt: GetKeyState(VK_MENU.0 as i32) & 0x80>0,
771                logo: GetKeyState(VK_LWIN.0 as i32) & 0x80>0
772                    || GetKeyState(VK_RWIN.0 as i32) & 0x80>0,
773            }
774        }
775    }
776    
777    pub fn on_mouse_move(&self) {
778    }
779    
780    pub fn set_mouse_cursor(&mut self, _cursor: MouseCursor) {
781    }
782    
783    pub fn restore(&self) {
784        unsafe {
785            ShowWindow(self.hwnd, SW_RESTORE);
786            PostMessageW(self.hwnd, WM_SIZE, WPARAM(0), LPARAM(0)).unwrap();
787        }
788    }
789    
790    pub fn maximize(&self) {
791        unsafe {
792            ShowWindow(self.hwnd, SW_MAXIMIZE);
793            PostMessageW(self.hwnd, WM_SIZE, WPARAM(0), LPARAM(0)).unwrap();
794        }
795    }
796    
797    pub fn close_window(&self) {
798        unsafe {
799            DestroyWindow(self.hwnd).unwrap();
800        }
801    }
802    
803    pub fn show(&self) {
804        unsafe {
805            ShowWindow(self.hwnd, SW_SHOW);
806        }
807    }
808    
809    pub fn minimize(&self) {
810        unsafe {
811            ShowWindow(self.hwnd, SW_MINIMIZE);
812        }
813    }
814    
815    pub fn set_topmost(&self, topmost: bool) {
816        unsafe {
817            if topmost {
818                SetWindowPos(
819                    self.hwnd,
820                    HWND_TOPMOST,
821                    0,
822                    0,
823                    0,
824                    0,
825                    SWP_NOMOVE | SWP_NOSIZE
826                ).unwrap();
827            }
828            else {
829                SetWindowPos(
830                    self.hwnd,
831                    HWND_NOTOPMOST,
832                    0,
833                    0,
834                    0,
835                    0,
836                    SWP_NOMOVE | SWP_NOSIZE
837                ).unwrap();
838            }
839        }
840    }
841    
842    pub fn get_is_topmost(&self) -> bool {
843        unsafe {
844            let ex_style = GetWindowLongPtrW(self.hwnd, GWL_EXSTYLE);
845            if ex_style as u32 & WS_EX_TOPMOST.0 != 0 {
846                return true
847            }
848            return false
849        }
850    }
851    
852    pub fn get_window_geom(&self) -> WindowGeom {
853        WindowGeom {
854            xr_is_presenting: false,
855            can_fullscreen: false,
856            is_topmost: self.get_is_topmost(),
857            is_fullscreen: self.get_is_maximized(),
858            inner_size: if self.get_is_maximized(){self.get_outer_size()}else{self.get_inner_size()},
859            outer_size: self.get_outer_size(),
860            dpi_factor: self.get_dpi_factor(),
861            position: self.get_position()
862        }
863    }
864    
865    pub fn get_is_maximized(&self) -> bool {
866        unsafe {
867            let wp: mem::MaybeUninit<WINDOWPLACEMENT> = mem::MaybeUninit::uninit();
868            let mut wp = wp.assume_init();
869            wp.length = mem::size_of::<WINDOWPLACEMENT>() as u32;
870            GetWindowPlacement(self.hwnd, &mut wp).unwrap();
871            if wp.showCmd == SW_MAXIMIZE.0 as u32 {
872                return true
873            }
874            return false
875        }
876    }
877    
878    pub fn time_now(&self) -> f64 {
879        get_win32_app_global().time_now()
880    }
881    
882    pub fn set_ime_spot(&mut self, spot: DVec2) {
883        self.ime_spot = spot;
884    }
885    
886    pub fn get_position(&self) -> DVec2 {
887        unsafe {
888            let mut rect = RECT {left: 0, top: 0, bottom: 0, right: 0};
889            GetWindowRect(self.hwnd, &mut rect).unwrap();
890            DVec2 {x: rect.left as f64, y: rect.top as f64}
891        }
892    }
893    
894    pub fn get_inner_size(&self) -> DVec2 {
895        unsafe {
896            let mut rect = RECT {left: 0, top: 0, bottom: 0, right: 0};
897            GetClientRect(self.hwnd, &mut rect).unwrap();
898            let dpi = self.get_dpi_factor();
899            DVec2 {x: (rect.right - rect.left) as f64 / dpi, y: (rect.bottom - rect.top)as f64 / dpi}
900        }
901    }
902    
903    pub fn get_outer_size(&self) -> DVec2 {
904        unsafe {
905            let mut rect = RECT {left: 0, top: 0, bottom: 0, right: 0};
906            GetWindowRect(self.hwnd, &mut rect).unwrap();
907            let dpi = self.get_dpi_factor();
908            DVec2 {x: (rect.right - rect.left) as f64/ dpi, y: (rect.bottom - rect.top)as f64/ dpi}
909        }
910    }
911    
912    pub fn set_position(&mut self, pos: DVec2) {
913        unsafe {
914            let mut window_rect = RECT {left: 0, top: 0, bottom: 0, right: 0};
915            GetWindowRect(self.hwnd, &mut window_rect).unwrap();
916            let dpi = self.get_dpi_factor();
917            MoveWindow(
918                self.hwnd,
919                (pos.x * dpi) as i32,
920                (pos.y * dpi) as i32,
921                window_rect.right - window_rect.left,
922                window_rect.bottom - window_rect.top,
923                FALSE
924            ).unwrap();
925        }
926    }
927    
928    pub fn set_outer_size(&self, size: DVec2) {
929        unsafe {
930            let mut window_rect = RECT {left: 0, top: 0, bottom: 0, right: 0};
931            GetWindowRect(self.hwnd, &mut window_rect).unwrap();
932            let dpi = self.get_dpi_factor();
933            MoveWindow(
934                self.hwnd,
935                window_rect.left,
936                window_rect.top,
937                (size.x * dpi) as i32,
938                (size.y * dpi) as i32,
939                FALSE
940            ).unwrap();
941        }
942    }
943    
944    pub fn set_inner_size(&self, size: DVec2) {
945        unsafe {
946            let mut window_rect = RECT {left: 0, top: 0, bottom: 0, right: 0};
947            GetWindowRect(self.hwnd, &mut window_rect).unwrap();
948            let mut client_rect = RECT {left: 0, top: 0, bottom: 0, right: 0};
949            GetClientRect(self.hwnd, &mut client_rect).unwrap();
950            let dpi = self.get_dpi_factor();
951            MoveWindow(
952                self.hwnd,
953                window_rect.left,
954                window_rect.top,
955                (size.x * dpi) as i32
956                    + ((window_rect.right - window_rect.left) - (client_rect.right - client_rect.left)),
957                (size.y * dpi) as i32
958                    + ((window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top)),
959                FALSE
960            ).unwrap();
961        }
962    }
963    
964    pub fn get_dpi_factor(&self) -> f64 {
965        get_win32_app_global().dpi_functions.hwnd_dpi_factor(self.hwnd) as f64
966    }
967    
968    pub fn do_callback(&mut self, event: Win32Event) {
969        Win32App::do_callback(event);
970    }
971    
972    pub fn send_change_event(&mut self) {
973        
974        let new_geom = self.get_window_geom();
975        let old_geom = self.last_window_geom.clone();
976        self.last_window_geom = new_geom.clone();
977        
978        self.do_callback(
979            Win32Event::WindowGeomChange(WindowGeomChangeEvent {
980                window_id: self.window_id,
981                old_geom: old_geom,
982                new_geom: new_geom
983            }),
984        );
985        self.do_callback(
986            Win32Event::Paint
987        );
988    }
989    
990    pub fn send_focus_event(&mut self) {
991        self.do_callback(Win32Event::AppGotFocus);
992    }
993    
994    pub fn send_focus_lost_event(&mut self) {
995        self.do_callback(Win32Event::AppLostFocus);
996    }
997    
998    pub fn send_mouse_down(&mut self, button: usize, modifiers: KeyModifiers) {
999        if self.mouse_buttons_down == 0 {
1000            unsafe {SetCapture(self.hwnd);}
1001        }
1002        self.mouse_buttons_down += 1;
1003        self.do_callback(Win32Event::MouseDown(MouseDownEvent {
1004            button,
1005            modifiers,
1006            window_id: self.window_id,
1007            abs: self.last_mouse_pos,
1008            time: self.time_now(),
1009            handled: Cell::new(Area::Empty),
1010        }));
1011    }
1012    
1013    pub fn send_mouse_up(&mut self, button: usize, modifiers: KeyModifiers) {
1014        if self.mouse_buttons_down > 1 {
1015            self.mouse_buttons_down -= 1;
1016        }
1017        else {
1018            unsafe { ReleaseCapture().unwrap(); }
1019            self.mouse_buttons_down = 0;
1020        }
1021        self.do_callback(Win32Event::MouseUp(MouseUpEvent {
1022            button,
1023            modifiers,
1024            window_id: self.window_id,
1025            abs: self.last_mouse_pos,
1026            time: self.time_now()
1027        }));
1028    }
1029    
1030    pub fn send_mouse_move(&mut self, pos: DVec2, modifiers: KeyModifiers) {
1031        self.last_mouse_pos = pos;
1032        self.do_callback(Win32Event::MouseMove(MouseMoveEvent {
1033            window_id: self.window_id,
1034            abs: pos,
1035            modifiers: modifiers,
1036            time: self.time_now(),
1037            handled: Cell::new(Area::Empty),
1038        }));
1039    }
1040    
1041    pub fn send_scroll(&mut self, scroll: DVec2, modifiers: KeyModifiers, is_mouse: bool) {
1042        self.do_callback(
1043            Win32Event::Scroll(ScrollEvent {
1044                window_id: self.window_id,
1045                scroll,
1046                abs: self.last_mouse_pos,
1047                modifiers,
1048                time: self.time_now(),
1049                is_mouse,
1050                handled_x: Cell::new(false),
1051                handled_y: Cell::new(false),
1052            })
1053        );
1054    }
1055    
1056    pub fn send_close_requested_event(&mut self) -> bool {
1057        let accept_close = Rc::new(Cell::new(true));
1058        self.do_callback(Win32Event::WindowCloseRequested(WindowCloseRequestedEvent {
1059            window_id: self.window_id,
1060            accept_close: accept_close.clone()
1061        }));
1062        if !accept_close.get() {
1063            return false
1064        }
1065        true
1066    }
1067    
1068    pub fn send_text_input(&mut self, input: String, replace_last: bool) {
1069        self.do_callback(Win32Event::TextInput(TextInputEvent {
1070            input: input,
1071            was_paste: false,
1072            replace_last: replace_last
1073        }))
1074    }
1075    
1076    pub fn virtual_key_to_key_code(wparam: WPARAM) -> KeyCode {
1077        match VIRTUAL_KEY(wparam.0 as u16) {
1078            VK_ESCAPE => KeyCode::Escape,
1079            VK_OEM_3 => KeyCode::Backtick,
1080            VK_0 => KeyCode::Key0,
1081            VK_1 => KeyCode::Key1,
1082            VK_2 => KeyCode::Key2,
1083            VK_3 => KeyCode::Key3,
1084            VK_4 => KeyCode::Key4,
1085            VK_5 => KeyCode::Key5,
1086            VK_6 => KeyCode::Key6,
1087            VK_7 => KeyCode::Key7,
1088            VK_8 => KeyCode::Key8,
1089            VK_9 => KeyCode::Key9,
1090            VK_OEM_MINUS => KeyCode::Minus,
1091            VK_OEM_PLUS => KeyCode::Equals,
1092            VK_BACK => KeyCode::Backspace,
1093            VK_TAB => KeyCode::Tab,
1094            VK_Q => KeyCode::KeyQ,
1095            VK_W => KeyCode::KeyW,
1096            VK_E => KeyCode::KeyE,
1097            VK_R => KeyCode::KeyR,
1098            VK_T => KeyCode::KeyT,
1099            VK_Y => KeyCode::KeyY,
1100            VK_U => KeyCode::KeyU,
1101            VK_I => KeyCode::KeyI,
1102            VK_O => KeyCode::KeyO,
1103            VK_P => KeyCode::KeyP,
1104            VK_OEM_4 => KeyCode::LBracket,
1105            VK_OEM_6 => KeyCode::RBracket,
1106            VK_RETURN => KeyCode::ReturnKey,
1107            VK_A => KeyCode::KeyA,
1108            VK_S => KeyCode::KeyS,
1109            VK_D => KeyCode::KeyD,
1110            VK_F => KeyCode::KeyF,
1111            VK_G => KeyCode::KeyG,
1112            VK_H => KeyCode::KeyH,
1113            VK_J => KeyCode::KeyJ,
1114            VK_K => KeyCode::KeyK,
1115            VK_L => KeyCode::KeyL,
1116            VK_OEM_1 => KeyCode::Semicolon,
1117            VK_OEM_7 => KeyCode::Quote,
1118            VK_OEM_5 => KeyCode::Backslash,
1119            VK_Z => KeyCode::KeyZ,
1120            VK_X => KeyCode::KeyX,
1121            VK_C => KeyCode::KeyC,
1122            VK_V => KeyCode::KeyV,
1123            VK_B => KeyCode::KeyB,
1124            VK_N => KeyCode::KeyN,
1125            VK_M => KeyCode::KeyM,
1126            VK_OEM_COMMA => KeyCode::Comma,
1127            VK_OEM_PERIOD => KeyCode::Period,
1128            VK_OEM_2 => KeyCode::Slash,
1129            VK_LCONTROL => KeyCode::Control,
1130            VK_RCONTROL => KeyCode::Control,
1131            VK_CONTROL => KeyCode::Control,
1132            VK_LMENU => KeyCode::Alt,
1133            VK_RMENU => KeyCode::Alt,
1134            VK_MENU => KeyCode::Alt,
1135            VK_LSHIFT => KeyCode::Shift,
1136            VK_RSHIFT => KeyCode::Shift,
1137            VK_SHIFT => KeyCode::Shift,
1138            VK_LWIN => KeyCode::Logo,
1139            VK_RWIN => KeyCode::Logo,
1140            VK_SPACE => KeyCode::Space,
1141            VK_CAPITAL => KeyCode::Capslock,
1142            VK_F1 => KeyCode::F1,
1143            VK_F2 => KeyCode::F2,
1144            VK_F3 => KeyCode::F3,
1145            VK_F4 => KeyCode::F4,
1146            VK_F5 => KeyCode::F5,
1147            VK_F6 => KeyCode::F6,
1148            VK_F7 => KeyCode::F7,
1149            VK_F8 => KeyCode::F8,
1150            VK_F9 => KeyCode::F9,
1151            VK_F10 => KeyCode::F10,
1152            VK_F11 => KeyCode::F11,
1153            VK_F12 => KeyCode::F12,
1154            VK_SNAPSHOT => KeyCode::PrintScreen,
1155            VK_SCROLL => KeyCode::ScrollLock,
1156            VK_PAUSE => KeyCode::Pause,
1157            VK_INSERT => KeyCode::Insert,
1158            VK_DELETE => KeyCode::Delete,
1159            VK_HOME => KeyCode::Home,
1160            VK_END => KeyCode::End,
1161            VK_PRIOR => KeyCode::PageUp,
1162            VK_NEXT => KeyCode::PageDown,
1163            VK_NUMPAD0 => KeyCode::Numpad0,
1164            VK_NUMPAD1 => KeyCode::Numpad1,
1165            VK_NUMPAD2 => KeyCode::Numpad2,
1166            VK_NUMPAD3 => KeyCode::Numpad3,
1167            VK_NUMPAD4 => KeyCode::Numpad4,
1168            VK_NUMPAD5 => KeyCode::Numpad5,
1169            VK_NUMPAD6 => KeyCode::Numpad6,
1170            VK_NUMPAD7 => KeyCode::Numpad7,
1171            VK_NUMPAD8 => KeyCode::Numpad8,
1172            VK_NUMPAD9 => KeyCode::Numpad9,
1173            VK_SUBTRACT => KeyCode::NumpadSubtract,
1174            VK_ADD => KeyCode::NumpadAdd,
1175            VK_DECIMAL => KeyCode::NumpadDecimal,
1176            VK_MULTIPLY => KeyCode::NumpadMultiply,
1177            VK_DIVIDE => KeyCode::NumpadDivide,
1178            VK_NUMLOCK => KeyCode::Numlock,
1179            VK_UP => KeyCode::ArrowUp,
1180            VK_DOWN => KeyCode::ArrowDown,
1181            VK_LEFT => KeyCode::ArrowLeft,
1182            VK_RIGHT => KeyCode::ArrowRight,
1183            _ => KeyCode::Unknown
1184        }
1185    }
1186}
1187