1#![allow(clippy::needless_doctest_main)]
2#![doc = include_str!("../README.md")]
3
4use fltk::{
5 app, enums,
6 prelude::{GroupExt, WidgetBase, WidgetExt, WindowExt},
7 window,
8};
9use fltk_webview_sys as wv;
10use std::os::raw;
11use std::sync::Arc;
12pub use wv::SizeHint;
13pub use wv::Webview;
14
15pub trait FromFltkWindow {
18 fn create(debug: bool, win: &mut window::Window) -> Webview;
19}
20
21impl FromFltkWindow for Webview {
22 fn create(debug: bool, win: &mut window::Window) -> Webview {
24 assert!(win.shown());
25 win.end();
26 win.set_color(enums::Color::White);
27 let inner;
28 unsafe {
29 #[cfg(target_os = "windows")]
30 {
31 extern "C" {
32 pub fn move_focus(wv: *mut wv::webview_t);
33 }
34 extern "system" {
35 pub fn SetFocus(child: *mut ()) -> *mut ();
36 pub fn CoInitializeEx(pvReserved: *mut (), dwCoInit: u32) -> i32;
37 pub fn SetParent(child: *mut (), parent: *mut ()) -> *mut ();
44 pub fn SetWindowPos(
45 hwnd: *mut (),
46 hwnd_insert_after: *mut (),
47 x: i32,
48 y: i32,
49 cx: i32,
50 cy: i32,
51 flags: u32,
52 ) -> i32;
53 pub fn SetWindowLongW(hwnd: *mut (), index: i32, new_long: i32) -> i32;
55 }
56 const COINIT_APARTMENTTHREADED: u32 = 0x2;
57 CoInitializeEx(std::ptr::null_mut(), COINIT_APARTMENTTHREADED);
59 inner = wv::webview_create(debug as i32, std::ptr::null_mut());
60 wv::webview_set_size(inner, win.w(), win.h(), 3);
61 let wv_hwnd = wv::webview_get_window(inner);
62 const GWL_STYLE: i32 = -16;
64 const WS_CHILD: i32 = 0x40000000;
65 const WS_VISIBLE: i32 = 0x10000000;
66 const SWP_NOZORDER: u32 = 0x0004;
67 const SWP_NOACTIVATE: u32 = 0x0010;
68 const SWP_FRAMECHANGED: u32 = 0x0020;
69 SetWindowLongW(wv_hwnd as _, GWL_STYLE, WS_CHILD | WS_VISIBLE);
71 SetParent(wv_hwnd as _, win.raw_handle() as _);
72 SetWindowPos(
73 wv_hwnd as _,
74 std::ptr::null_mut(),
75 0,
76 0,
77 win.w(),
78 win.h(),
79 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED,
80 );
81 move_focus(inner as *mut _);
82 win.resize_callback(move |w, _, _, _, _| {
83 wv::webview_set_size(inner, w.w(), w.h(), 3);
84 });
85 win.resize(win.x(), win.y(), win.w(), win.h());
86 win.handle(move |_w, ev| {
87 if ev == enums::Event::Focus {
88 move_focus(inner as *mut _);
89 true
90 } else {
91 false
92 }
93 });
94 let mut topwin =
95 window::Window::from_widget_ptr(win.top_window().unwrap().as_widget_ptr());
96 topwin.set_callback(|t| {
97 if app::event() == enums::Event::Close {
98 t.hide();
99 }
100 });
101 topwin.assume_derived();
102 topwin.handle(move |w, ev| match ev {
103 fltk::enums::Event::Push => {
104 SetFocus(w.raw_handle() as _);
105 true
106 }
107 _ => false,
108 });
109 }
110 #[cfg(target_os = "macos")]
111 {
112 pub enum NSWindow {}
113 extern "C" {
114 pub fn make_delegate(
115 child: *mut NSWindow,
116 parent: *mut NSWindow,
117 add_menu: i32,
118 );
119 pub fn my_close_win(win: *mut NSWindow);
120 }
121 let handle = win.raw_handle();
122 inner = wv::webview_create(debug as i32, handle as _);
123 make_delegate(wv::webview_get_window(inner) as _, handle as _, 1);
124 win.resize_callback(move |w, _, _, _, _| {
125 wv::webview_set_size(inner, w.w(), w.h(), 0);
126 });
127 win.resize(win.x(), win.y(), win.w(), win.h());
128 let mut topwin =
129 window::Window::from_widget_ptr(win.top_window().unwrap().as_widget_ptr());
130 let inner = inner.clone();
131 topwin.set_callback(move |t| {
132 if app::event() == enums::Event::Close {
133 my_close_win(wv::webview_get_window(inner) as _);
134 t.hide();
135 }
136 });
137 }
138 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
139 {
140 pub enum GdkWindow {}
141 pub enum GtkWindow {}
142 pub enum Display {}
143 extern "C" {
144 pub fn gtk_init(argc: *mut i32, argv: *mut *mut raw::c_char);
145 pub fn my_gtk_events_pending() -> i32;
146 pub fn my_get_win(wid: *mut GtkWindow) -> *mut GdkWindow;
147 pub fn my_get_xid(w: *mut GdkWindow) -> u64;
148 pub fn x_init(disp: *mut Display, child: u64, parent: u64);
149 pub fn x_focus(disp: *mut Display, child: u64);
150 pub fn gtk_main_iteration_do(blocking: bool);
151 }
152 std::env::set_var("GDK_BACKEND", "x11");
153 gtk_init(&mut 0, std::ptr::null_mut());
154 inner = wv::webview_create(debug as i32, std::ptr::null_mut() as _);
155 assert!(!inner.is_null());
156 let temp_win = wv::webview_get_window(inner);
157 assert!(!temp_win.is_null());
158 let temp = my_get_win(temp_win as _);
159 assert!(!temp.is_null());
160 let xid = my_get_xid(temp as _);
161 let flxid = win.raw_handle();
162
163 x_init(app::display() as _, xid, flxid);
165 x_focus(app::display() as _, xid);
167
168 win.resize_callback(move |w, _, _, _, _| {
169 wv::webview_set_size(inner, w.w(), w.h(), 0);
170 });
171 win.resize(win.x(), win.y(), win.w(), win.h());
172 let xid_for_focus = xid;
174 win.handle(move |_, ev| {
175 if ev == enums::Event::Push {
176 x_focus(app::display() as _, xid_for_focus);
177 true
178 } else {
179 false
180 }
181 });
182
183 app::add_timeout3(0.016, |handle| {
184 let mut spins = 0;
185 while my_gtk_events_pending() != 0 && spins < 4 {
186 gtk_main_iteration_do(false);
187 spins += 1;
188 }
189 app::repeat_timeout3(0.016, handle);
190 });
191 }
192 }
193 assert!(!inner.is_null());
194 #[allow(clippy::arc_with_non_send_sync)]
195 let inner = Arc::new(inner);
196 Webview::from_raw(inner)
197 }
198}