makepad_platform/os/windows/
windows.rs

1use {
2    std::{
3        time::Instant,
4        rc::Rc,
5        cell::RefCell,
6    },
7    crate::{
8        makepad_live_id::*,
9        cx::*,
10        event::*,
11        thread::SignalToUI,
12        os::{
13            windows::{
14                windows_media::CxWindowsMedia,
15                win32_event::*,
16                d3d11::{D3d11Window, D3d11Cx},
17                win32_app::*,
18                win32_window::Win32Window,
19            },
20            cx_native::EventFlow,
21        },
22        makepad_math::*,
23        pass::CxPassParent,
24        cx_api::{CxOsApi, CxOsOp, OpenUrlInPlace},
25        window::CxWindowPool,
26        windows::Win32::Graphics::Direct3D11::ID3D11Device,
27    }
28};
29
30impl Cx {
31    
32    pub fn event_loop(cx: Rc<RefCell<Cx >>) {
33        
34        cx.borrow_mut().self_ref = Some(cx.clone());
35        cx.borrow_mut().os_type = OsType::Windows;
36        
37        let d3d11_cx = Rc::new(RefCell::new(D3d11Cx::new()));
38
39        // hack: store ID3D11Device in CxOs, so texture-related operations become possible on the makepad/studio side, yet don't completely destroy the code there
40        cx.borrow_mut().os.d3d11_device = Some(d3d11_cx.borrow().device.clone());
41
42        for arg in std::env::args() {
43            if arg == "--stdin-loop" {
44                let mut cx = cx.borrow_mut();
45                cx.in_makepad_studio = true;
46                let mut d3d11_cx = d3d11_cx.borrow_mut();
47                return cx.stdin_event_loop(&mut d3d11_cx);
48            }
49        }
50        
51        let d3d11_windows = Rc::new(RefCell::new(Vec::new()));
52        
53        init_win32_app_global(Box::new({
54            let cx = cx.clone();
55            move | event | {
56                let mut cx = cx.borrow_mut();
57                let mut d3d11_cx = d3d11_cx.borrow_mut();
58                let mut d3d11_windows = d3d11_windows.borrow_mut();
59                cx.win32_event_callback(event, &mut d3d11_cx, &mut d3d11_windows)
60            }
61        }));
62        // the signal poll timer
63        with_win32_app(|app| app.start_timer(0, 0.008, true));
64        cx.borrow_mut().call_event_handler(&Event::Startup);
65        cx.borrow_mut().redraw_all();
66        with_win32_app(|app| app.start_signal_poll());
67        Win32App::event_loop();
68    }
69    
70    fn win32_event_callback(
71        &mut self,
72        event: Win32Event,
73        d3d11_cx: &mut D3d11Cx,
74        d3d11_windows: &mut Vec<D3d11Window>
75    ) -> EventFlow {
76        if let EventFlow::Exit = self.handle_platform_ops(d3d11_windows, d3d11_cx) {
77            return EventFlow::Exit
78        }
79        
80        //let mut paint_dirty = false;
81        /*match &event{
82            Win32Event::Timer(time) =>{
83                
84            }
85            _=>{}
86        }*/
87
88        //self.process_desktop_pre_event(&mut event);
89        match event {
90            Win32Event::AppGotFocus => { // repaint all window passes. Metal sometimes doesnt flip buffers when hidden/no focus
91                for window in d3d11_windows.iter_mut() {
92                    if let Some(main_pass_id) = self.windows[window.window_id].main_pass_id {
93                        self.repaint_pass(main_pass_id);
94                    }
95                }
96                //paint_dirty = true;
97                self.call_event_handler(&Event::AppGotFocus);
98            }
99            Win32Event::AppLostFocus => {
100                self.call_event_handler(&Event::AppLostFocus);
101            }
102            Win32Event::WindowResizeLoopStart(window_id) => {
103                if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
104                    window.start_resize();
105                }
106            }
107            Win32Event::WindowResizeLoopStop(window_id) => {
108                if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
109                    window.stop_resize();
110                }
111            }
112            Win32Event::WindowGeomChange(mut re) => { // do this here because mac
113               
114                if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == re.window_id) {
115                    if let Some(dpi_override) = self.windows[re.window_id].dpi_override {
116                        re.new_geom.inner_size *= re.new_geom.dpi_factor / dpi_override;
117                        re.new_geom.dpi_factor = dpi_override;
118                    }
119                                        
120                    window.window_geom = re.new_geom.clone();
121                    self.windows[re.window_id].window_geom = re.new_geom.clone();
122                    // redraw just this windows root draw list
123                    if re.old_geom.inner_size != re.new_geom.inner_size {
124                        
125                        if let Some(main_pass_id) = self.windows[re.window_id].main_pass_id {
126                            self.redraw_pass_and_child_passes(main_pass_id);
127                        }
128                    }
129                }
130                // ok lets not redraw all, just this window
131                self.redraw_all();
132                self.call_event_handler(&Event::WindowGeomChange(re));
133            }
134            Win32Event::WindowClosed(wc) => {
135                let window_id = wc.window_id;
136                self.call_event_handler(&Event::WindowClosed(wc));
137                // lets remove the window from the set
138                self.windows[window_id].is_created = false;
139                if let Some(index) = d3d11_windows.iter().position( | w | w.window_id == window_id) {
140                    d3d11_windows.remove(index);
141                    if d3d11_windows.len() == 0 {
142                        self.call_event_handler(&Event::Shutdown);
143                        return EventFlow::Exit
144                    }
145                }
146            }
147            Win32Event::Paint => {
148                if self.new_next_frames.len() != 0 {
149                    self.call_next_frame_event(with_win32_app(|app| app.time_now()));
150                }
151                if self.need_redrawing() {
152                    self.call_draw_event();
153                    self.hlsl_compile_shaders(&d3d11_cx);
154                }
155                // ok here we send out to all our childprocesses
156                
157                self.handle_repaint(d3d11_windows, d3d11_cx);
158            }
159            Win32Event::MouseDown(e) => {
160                self.fingers.process_tap_count(
161                    e.abs,
162                    e.time
163                );
164                self.fingers.mouse_down(e.button, e.window_id);
165                self.call_event_handler(&Event::MouseDown(e.into()))
166            }
167            Win32Event::MouseMove(e) => {
168                self.call_event_handler(&Event::MouseMove(e.into()));
169                self.fingers.cycle_hover_area(live_id!(mouse).into());
170                self.fingers.switch_captures();
171            }
172            Win32Event::MouseUp(e) => {
173                
174                let button = e.button;
175                self.call_event_handler(&Event::MouseUp(e.into()));
176                self.fingers.mouse_up(button);
177                self.fingers.cycle_hover_area(live_id!(mouse).into());
178            }
179            Win32Event::MouseLeave(e) => {
180                self.call_event_handler(&Event::MouseLeave(e.into()));
181                self.fingers.cycle_hover_area(live_id!(mouse).into());
182                self.fingers.switch_captures();
183            }
184            Win32Event::Scroll(e) => {
185                self.call_event_handler(&Event::Scroll(e.into()))
186            }
187            Win32Event::WindowDragQuery(e) => {
188                self.call_event_handler(&Event::WindowDragQuery(e))
189            }
190            Win32Event::WindowCloseRequested(e) => {
191                self.call_event_handler(&Event::WindowCloseRequested(e))
192            }
193            Win32Event::TextInput(e) => {
194                self.call_event_handler(&Event::TextInput(e))
195            }
196            Win32Event::Drag(e) => {
197                self.call_event_handler(&Event::Drag(e));
198                self.drag_drop.cycle_drag();
199            },
200            Win32Event::Drop(e) => {
201                self.call_event_handler(&Event::Drop(e));
202                self.drag_drop.cycle_drag();
203            },
204            Win32Event::DragEnd => {
205                // send MouseUp
206                self.call_event_handler(&Event::MouseUp(MouseUpEvent {
207                    abs: dvec2(-100000.0, -100000.0),
208                    button: MouseButton::PRIMARY,
209                    window_id: CxWindowPool::id_zero(),
210                    modifiers: Default::default(),
211                    time: 0.0
212                }));
213                self.fingers.mouse_up(MouseButton::PRIMARY);
214                self.fingers.cycle_hover_area(live_id!(mouse).into());
215            }
216            Win32Event::KeyDown(e) => {
217                self.keyboard.process_key_down(e.clone());
218                self.call_event_handler(&Event::KeyDown(e))
219            }
220            Win32Event::KeyUp(e) => {
221                self.keyboard.process_key_up(e.clone());
222                self.call_event_handler(&Event::KeyUp(e))
223            }
224            Win32Event::TextCopy(e) => {
225                self.call_event_handler(&Event::TextCopy(e))
226            }
227            Win32Event::TextCut(e) => {
228                self.call_event_handler(&Event::TextCut(e))
229            }
230            Win32Event::Timer(e) => {
231                self.call_event_handler(&Event::Timer(e))
232            }
233            Win32Event::Signal => {
234                if SignalToUI::check_and_clear_ui_signal() {
235                    self.handle_media_signals();
236                    self.call_event_handler(&Event::Signal);
237                }
238                if SignalToUI::check_and_clear_action_signal() {
239                    self.handle_action_receiver();
240                }
241
242                if self.handle_live_edit() {
243                    self.call_event_handler(&Event::LiveEdit);
244                    self.redraw_all();
245                }
246                self.handle_networking_events();
247                
248                self.win32_event_callback(Win32Event::Paint, d3d11_cx, d3d11_windows);
249                
250                return EventFlow::Wait;
251            }
252        }
253        
254        return EventFlow::Poll;
255        /*
256        if self.any_passes_dirty() || self.need_redrawing() || self.new_next_frames.len() != 0 || paint_dirty {
257            EventFlow::Poll
258        } else {
259            EventFlow::Wait
260        }*/
261        
262    }
263    
264    pub (crate) fn handle_repaint(&mut self, d3d11_windows: &mut Vec<D3d11Window>, d3d11_cx: &mut D3d11Cx) {
265        
266        let mut passes_todo = Vec::new();
267        self.compute_pass_repaint_order(&mut passes_todo);
268        self.repaint_id += 1;
269        for pass_id in &passes_todo {
270            self.passes[*pass_id].set_time(with_win32_app(|app| app.time_now() as f32));
271            match self.passes[*pass_id].parent.clone() {
272                CxPassParent::Xr => {}
273                CxPassParent::Window(window_id) => {
274                    if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
275                        //let dpi_factor = window.window_geom.dpi_factor;                        
276                        window.resize_buffers(&d3d11_cx);
277                        self.draw_pass_to_window(*pass_id, false, window, d3d11_cx);
278                    }
279                }
280                CxPassParent::Pass(_) => {
281                    //let dpi_factor = self.get_delegated_dpi_factor(parent_pass_id);
282                    self.draw_pass_to_texture(*pass_id, d3d11_cx, None);
283                },
284                CxPassParent::None => {
285                    self.draw_pass_to_texture(*pass_id, d3d11_cx, None);
286                }
287            }
288        }
289    }
290    
291    pub(crate) fn handle_networking_events(&mut self) {
292        let mut out = Vec::new();
293        while let Ok(event) = self.os.network_response.receiver.try_recv(){
294            out.push(event);
295        }
296        if out.len()>0{
297            self.call_event_handler(& Event::NetworkResponses(out))
298        }
299    }
300    
301    fn handle_platform_ops(&mut self, d3d11_windows: &mut Vec<D3d11Window>, d3d11_cx: &D3d11Cx) -> EventFlow {
302        let mut ret = EventFlow::Poll;
303        let mut geom_changes = Vec::new();
304        while let Some(op) = self.platform_ops.pop() {
305            match op {
306                CxOsOp::CreateWindow(window_id) => {
307                    let window = &mut self.windows[window_id];
308                    let d3d11_window = D3d11Window::new(
309                        window_id,
310                        &d3d11_cx,
311                        window.create_inner_size.unwrap_or(dvec2(800., 600.)),
312                        window.create_position,
313                        &window.create_title
314                    );
315                    
316                    window.window_geom = d3d11_window.window_geom.clone();
317                    d3d11_windows.push(d3d11_window);
318                    window.is_created = true;
319                    geom_changes.push(WindowGeomChangeEvent{
320                        window_id,
321                        old_geom: window.window_geom.clone(),
322                        new_geom: window.window_geom.clone()
323                    });
324                },
325                CxOsOp::CloseWindow(window_id) => {
326                    self.call_event_handler(&Event::WindowClosed(WindowClosedEvent { window_id }));
327                    if let Some(index) = d3d11_windows.iter().position( | w | w.window_id == window_id) {
328                        self.windows[window_id].is_created = false;
329                        d3d11_windows[index].win32_window.close_window();
330                        d3d11_windows.remove(index);
331                        if d3d11_windows.len() == 0 {
332                            ret = EventFlow::Exit
333                        }
334                    }
335                },
336                CxOsOp::MinimizeWindow(window_id) => {
337                    if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
338                        window.win32_window.minimize();
339                    }
340                },
341                CxOsOp::Deminiaturize(_window_id) => todo!(),
342                CxOsOp::HideWindow(_window_id) => todo!(),
343                CxOsOp::MaximizeWindow(window_id) => {
344                    if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
345                        window.win32_window.maximize();
346                    }
347                },
348                CxOsOp::ResizeWindow(window_id, size) => {
349                    if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
350                        window.win32_window.set_inner_size(size);
351                    }
352                }
353                CxOsOp::RepositionWindow(window_id, pos) => {
354                    if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
355                        window.win32_window.set_position(pos);
356                    }
357                }
358                CxOsOp::RestoreWindow(window_id) => {
359                    if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
360                        window.win32_window.restore();
361                    }
362                },
363                CxOsOp::Quit=>{
364                    ret = EventFlow::Exit
365                }
366                CxOsOp::SetTopmost(window_id, is_topmost) => {
367                    if d3d11_windows.len() == 0 {
368                        self.platform_ops.insert(0, CxOsOp::SetTopmost(window_id, is_topmost));
369                        continue;
370                    }
371                    if let Some(window) = d3d11_windows.iter_mut().find( | w | w.window_id == window_id) {
372                        window.win32_window.set_topmost(is_topmost);
373                    }
374                }
375                CxOsOp::CopyToClipboard(content) => {
376                    unsafe {
377                        Win32Window::copy_to_clipboard(&content);
378                    }
379                },
380                CxOsOp::SetCursor(cursor) => {
381                    with_win32_app(|app| app.set_mouse_cursor(cursor));
382                },
383                CxOsOp::StartTimer {timer_id, interval, repeats} => {
384                    with_win32_app(|app| app.start_timer(timer_id, interval, repeats));
385                },
386                CxOsOp::StopTimer(timer_id) => {
387                    with_win32_app(|app| app.stop_timer(timer_id));
388                },
389                CxOsOp::StartDragging(dragged_item) => {
390                    with_win32_app(|app| app.start_dragging(dragged_item));
391                },
392                CxOsOp::HttpRequest {request_id, request} => {
393                    use crate::os::windows::http::WindowsHttpSocket;
394                    WindowsHttpSocket::open(request_id, request, self.os.network_response.sender.clone());
395
396                    //todo!("HttpRequest not implemented yet on windows, we'll get there");
397                },
398                CxOsOp::ShowTextIME{..}=>{
399                    
400                }
401                CxOsOp::HideTextIME=>{
402                                        
403                }
404                e=>{
405                    crate::error!("Not implemented on this platform: CxOsOp::{:?}", e);
406                }
407            }
408        }
409        if geom_changes.len()>0{
410            self.redraw_all();
411            for geom_change in geom_changes{
412                self.call_event_handler(&Event::WindowGeomChange(geom_change));
413            }
414        }
415        ret
416    }
417}
418
419impl CxOsApi for Cx {
420    fn init_cx_os(&mut self) {
421        self.os.start_time = Some(Instant::now());
422        if let Some(item) = std::option_env!("MAKEPAD_PACKAGE_DIR"){
423            self.live_registry.borrow_mut().package_root = Some(item.to_string());
424        }
425        
426        self.live_expand();
427        if std::env::args().find( | v | v == "--stdin-loop").is_none() {
428            self.start_disk_live_file_watcher(100);
429        }
430        self.live_scan_dependencies();
431        self.native_load_dependencies();
432    }
433    
434    fn spawn_thread<F>(&mut self, f: F) where F: FnOnce() + Send + 'static {
435        std::thread::spawn(f);
436    }
437    
438    fn seconds_since_app_start(&self)->f64{
439        Instant::now().duration_since(self.os.start_time.unwrap()).as_secs_f64()
440    }
441    
442    fn open_url(&mut self, _url:&str, _in_place:OpenUrlInPlace){
443        crate::error!("open_url not implemented on this platform");
444    }
445}
446
447#[derive(Default)]
448pub struct CxOs {
449    pub (crate) start_time: Option<Instant>,
450    pub (crate) media: CxWindowsMedia,
451    pub (crate) d3d11_device: Option<ID3D11Device>,
452    pub (crate) network_response: NetworkResponseChannel,
453    //pub (crate) new_frame_being_rendered: Option<crate::cx_stdin::PresentableDraw>,
454}