Compare commits

..

1 commit

Author SHA1 Message Date
ecf5a572ab fix(widgets): restore the fork-local test/gltf/csg re-exports
The upstream sync at abd70f4 dropped three fork-local optional
dependencies from widgets/Cargo.toml and their re-exports from lib.rs.
They were fork additions, so the merge simply lost them.

The visible symptom in nigig-org was a resolver failure:

  package `nigig-pdf-makepad` depends on `makepad-widgets` with feature
  `test` but `makepad-widgets` does not have that feature.
  help: available features: default, serde
  failed to select a version for `makepad-widgets`

With no `test` feature on widgets 2.0.0, cargo falls back to the stale
old/widgets copy, which is 1.0.0 and offers only default and serde -
hence the misleading "available features" list.

libs/makepad_test itself was never removed; only the manifest entries and
the re-export were. Restores both, so makepad_widgets::makepad_test
resolves again.
2026-08-16 17:33:30 +00:00
15 changed files with 65 additions and 876 deletions

View file

@ -6,8 +6,15 @@ app_main!(App);
script_mod! {
use mod.prelude.widgets.*
let state = {
counter: 0
}
mod.state = state
startup() do #(App::script_component(vm)){
ui: Root{
on_startup:||{ // right now render isnt called automatically yet
ui.main_view.render()
}
main_window := Window{
window.inner_size: vec2(420, 220)
body +: {
@ -17,9 +24,11 @@ script_mod! {
flow: Down
spacing: 12
align: Center
counter_label := Label{
text: "Count: 0"
draw_text.text_style.font_size: 24
on_render: ||{
counter_label := Label{
text: "Count: " + state.counter
draw_text.text_style.font_size: 24
}
}
}
increment_button := Button{
@ -35,15 +44,15 @@ script_mod! {
pub struct App {
#[live]
ui: WidgetRef,
#[rust]
counter: i32,
}
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
if self.ui.button(cx, ids!(increment_button)).clicked(actions) {
self.counter += 1;
self.ui.label(cx, ids!(counter_label)).set_text(cx, &format!("Count: {}", self.counter));
script_eval!(cx,{
mod.state.counter += 1
ui.main_view.render()
});
}
}
}

View file

@ -5,10 +5,8 @@ use makepad_micro_serde::{SerBin, SerJson};
use makepad_studio_hub::{HubConfig, HubConnection, MountConfig, StudioHub};
use makepad_studio_protocol::hub_protocol::{ClientToHub, HubToClient, LogEntry, QueryId};
use makepad_studio_protocol::{
KeyCode, KeyEvent, KeyModifiers, MouseButton, RemoteIMEComposition, RemoteKeyModifiers,
RemoteLongPress, RemoteMouseDown, RemoteMouseMove, RemoteMouseUp, RemoteScroll,
RemoteTextPaste, RemoteTouchPoint, RemoteTouchState, RemoteTouchUpdate, StudioToApp,
StudioToAppVec, WidgetSnapshot,
KeyCode, KeyEvent, KeyModifiers, MouseButton, RemoteKeyModifiers, RemoteMouseDown,
RemoteMouseMove, RemoteMouseUp, RemoteScroll, StudioToApp, StudioToAppVec, WidgetSnapshot,
};
use std::cell::RefCell;
use std::cmp;
@ -87,11 +85,6 @@ pub struct TestConfig {
pub startup_pause: Duration,
pub action_delay: Duration,
pub keep_open: Duration,
pub android: bool,
pub device_serial: Option<String>,
pub adb_path: Option<String>,
pub android_port: u16,
pub android_native_activity: bool,
}
impl TestConfig {
@ -133,11 +126,6 @@ impl TestConfig {
startup_pause: env_duration_ms("MAKEPAD_TEST_STARTUP_DELAY_MS"),
action_delay: env_duration_ms("MAKEPAD_TEST_ACTION_DELAY_MS"),
keep_open: env_duration_ms("MAKEPAD_TEST_KEEP_OPEN_MS"),
android: android_test_enabled(),
device_serial: android_device_serial(),
adb_path: android_adb_path(),
android_port: android_hub_port(),
android_native_activity: env_truthy("MAKEPAD_TEST_NATIVE_ACTIVITY"),
})
}
@ -169,13 +157,6 @@ impl TestConnection {
Self::Remote(connection) => connection.recv_timeout(timeout),
}
}
fn studio_addr(&self) -> Option<String> {
match self {
Self::InProcess(connection) => connection.studio_addr(),
Self::Remote(_) => None,
}
}
}
struct TestAppInner {
@ -227,9 +208,7 @@ impl TestApp {
}
fn start_once(config: TestConfig) -> TestResult<Self> {
let (connection, build_id) = if config.android {
start_android_app(&config)?
} else if visible_mode_enabled() {
let (connection, build_id) = if visible_mode_enabled() {
start_visible_app(&config)?
} else {
start_headless_app(&config)?
@ -475,128 +454,6 @@ impl TestApp {
Ok(())
}
pub fn touch_down(&self, x: f64, y: f64) {
if let Err(err) = self.try_touch_down(x, y) {
panic_for_error(err);
}
}
pub fn try_touch_down(&self, x: f64, y: f64) -> TestResult<()> {
self.try_forward(vec![StudioToApp::TouchUpdate(RemoteTouchUpdate {
time: now_seconds(),
touches: vec![RemoteTouchPoint {
state: RemoteTouchState::Start,
abs_x: x,
abs_y: y,
time: now_seconds(),
uid: 0,
rotation_angle: 0.0,
force: 1.0,
radius_x: 4.0,
radius_y: 4.0,
}],
})])?;
self.pace_after_action();
Ok(())
}
pub fn touch_move(&self, x: f64, y: f64) {
if let Err(err) = self.try_touch_move(x, y) {
panic_for_error(err);
}
}
pub fn try_touch_move(&self, x: f64, y: f64) -> TestResult<()> {
self.try_forward(vec![StudioToApp::TouchUpdate(RemoteTouchUpdate {
time: now_seconds(),
touches: vec![RemoteTouchPoint {
state: RemoteTouchState::Move,
abs_x: x,
abs_y: y,
time: now_seconds(),
uid: 0,
rotation_angle: 0.0,
force: 1.0,
radius_x: 4.0,
radius_y: 4.0,
}],
})])?;
self.pace_after_action();
Ok(())
}
pub fn touch_up(&self, x: f64, y: f64) {
if let Err(err) = self.try_touch_up(x, y) {
panic_for_error(err);
}
}
pub fn try_touch_up(&self, x: f64, y: f64) -> TestResult<()> {
self.try_forward(vec![StudioToApp::TouchUpdate(RemoteTouchUpdate {
time: now_seconds(),
touches: vec![RemoteTouchPoint {
state: RemoteTouchState::Stop,
abs_x: x,
abs_y: y,
time: now_seconds(),
uid: 0,
rotation_angle: 0.0,
force: 0.0,
radius_x: 4.0,
radius_y: 4.0,
}],
})])?;
self.pace_after_action();
Ok(())
}
pub fn long_press(&self, x: f64, y: f64, duration_ms: f64) {
if let Err(err) = self.try_long_press(x, y, duration_ms) {
panic_for_error(err);
}
}
pub fn try_long_press(&self, x: f64, y: f64, duration_ms: f64) -> TestResult<()> {
self.try_forward(vec![StudioToApp::LongPress(RemoteLongPress {
x,
y,
time: now_seconds(),
duration_ms,
})])?;
self.pace_after_action();
Ok(())
}
pub fn paste_text(&self, text: impl AsRef<str>) {
if let Err(err) = self.try_paste_text(text) {
panic_for_error(err);
}
}
pub fn try_paste_text(&self, text: impl AsRef<str>) -> TestResult<()> {
let text = text.as_ref().to_string();
self.try_forward(vec![StudioToApp::TextPaste(RemoteTextPaste {
text,
})])?;
self.pace_after_action();
Ok(())
}
pub fn ime_composition(&self, text: impl AsRef<str>) {
if let Err(err) = self.try_ime_composition(text) {
panic_for_error(err);
}
}
pub fn try_ime_composition(&self, text: impl AsRef<str>) -> TestResult<()> {
let text = text.as_ref().to_string();
self.try_forward(vec![StudioToApp::IMEComposition(
RemoteIMEComposition { text },
)])?;
self.pace_after_action();
Ok(())
}
fn query_widgets(
&self,
selector: &Selector,
@ -766,10 +623,6 @@ impl TestApp {
if inner.build_stopped.is_some() {
return;
}
if inner.config.android {
let full_package = android_full_package_name(&inner.config.package_name);
let _ = adb_force_stop(&inner.config, &full_package);
}
let build_id = inner.build_id;
let _ = inner.connection.send(ClientToHub::ClearBuild { build_id });
}
@ -1111,82 +964,6 @@ impl Locator {
self.app.try_drag_from(&target, dx, dy)
}
pub fn touch_down(self) -> Self {
if let Err(err) = self.try_touch_down() {
panic_for_error(err);
}
self
}
pub fn try_touch_down(&self) -> TestResult<()> {
let target = self.resolve_unique_visible()?;
let (x, y) = snapshot_center_f64(&target);
self.app.try_touch_down(x, y)
}
pub fn touch_move(self, dx: f64, dy: f64) -> Self {
if let Err(err) = self.try_touch_move(dx, dy) {
panic_for_error(err);
}
self
}
pub fn try_touch_move(&self, dx: f64, dy: f64) -> TestResult<()> {
let target = self.resolve_unique_visible()?;
let (cx, cy) = snapshot_center_f64(&target);
self.app.try_touch_move(cx + dx, cy + dy)
}
pub fn touch_up(self) -> Self {
if let Err(err) = self.try_touch_up() {
panic_for_error(err);
}
self
}
pub fn try_touch_up(&self) -> TestResult<()> {
let target = self.resolve_unique_visible()?;
let (x, y) = snapshot_center_f64(&target);
self.app.try_touch_up(x, y)
}
pub fn long_press(self, duration_ms: f64) -> Self {
if let Err(err) = self.try_long_press(duration_ms) {
panic_for_error(err);
}
self
}
pub fn try_long_press(&self, duration_ms: f64) -> TestResult<()> {
let target = self.resolve_unique_visible()?;
let (x, y) = snapshot_center_f64(&target);
self.app.try_long_press(x, y, duration_ms)
}
pub fn paste(self, text: impl AsRef<str>) -> Self {
if let Err(err) = self.try_paste(text) {
panic_for_error(err);
}
self
}
pub fn try_paste(&self, text: impl AsRef<str>) -> TestResult<()> {
self.try_click()?;
self.app.try_paste_text(text)
}
pub fn ime_composition(self, text: impl AsRef<str>) -> Self {
if let Err(err) = self.try_ime_composition(text) {
panic_for_error(err);
}
self
}
pub fn try_ime_composition(&self, text: impl AsRef<str>) -> TestResult<()> {
self.try_click()?;
self.app.try_ime_composition(text)
}
pub fn snapshot(&self) -> WidgetSnapshot {
match self.try_snapshot() {
Ok(widget) => widget,
@ -1734,380 +1511,6 @@ fn env_duration_ms(name: &str) -> Duration {
.unwrap_or(Duration::ZERO)
}
// ---------------------------------------------------------------------------
// Android test helpers
// ---------------------------------------------------------------------------
const DEFAULT_ANDROID_PORT: u16 = 8001;
const ANDROID_STARTUP_TIMEOUT: Duration = Duration::from_secs(120);
const ANDROID_LAUNCH_TIMEOUT: Duration = Duration::from_secs(60);
fn android_test_enabled() -> bool {
env_truthy("MAKEPAD_TEST_ANDROID")
}
fn android_device_serial() -> Option<String> {
std::env::var("MAKEPAD_TEST_DEVICE")
.ok()
.map(|v| v.trim().to_string())
.filter(|v| !v.is_empty())
}
fn android_hub_port() -> u16 {
std::env::var("MAKEPAD_TEST_ANDROID_PORT")
.ok()
.and_then(|v| v.trim().parse().ok())
.unwrap_or(DEFAULT_ANDROID_PORT)
}
fn android_adb_path() -> Option<String> {
std::env::var("MAKEPAD_TEST_ADB")
.ok()
.map(|v| v.trim().to_string())
.filter(|v| !v.is_empty())
}
fn adb_command(config: &TestConfig) -> std::process::Command {
let adb = config
.adb_path
.as_deref()
.unwrap_or("adb");
let mut cmd = std::process::Command::new(adb);
if let Some(ref serial) = config.device_serial {
cmd.arg("-s").arg(serial);
}
cmd
}
fn adb_exec(config: &TestConfig, args: &[&str]) -> TestResult<String> {
let output = adb_command(config)
.args(args)
.output()
.map_err(|err| TestError::new(format!("failed to run adb: {err}")))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(TestError::new(format!(
"adb {} failed: {}",
args.join(" "),
stderr.trim()
)));
}
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}
fn android_full_package_name(package_name: &str) -> String {
let underscore = package_name.replace('-', "_");
format!("dev.makepad.{underscore}")
}
fn adb_forward(config: &TestConfig, port: u16) -> TestResult<()> {
let _ = adb_exec(config, &["reverse", "--remove", &format!("tcp:{port}")]);
adb_exec(
config,
&["reverse", &format!("tcp:{port}"), &format!("tcp:{port}")],
)?;
Ok(())
}
fn adb_install(config: &TestConfig, apk_path: &std::path::Path) -> TestResult<()> {
let output = adb_command(config)
.args(["install", "-r"])
.arg(apk_path)
.output()
.map_err(|err| TestError::new(format!("failed to run adb install: {err}")))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(TestError::new(format!("adb install failed: {}", stderr.trim())));
}
Ok(())
}
fn adb_launch(
config: &TestConfig,
package: &str,
build_id: u64,
crate_name: &str,
port: u16,
) -> TestResult<()> {
// Native-activity builds launch `android.app.NativeActivity` directly (no
// Java Activity). Legacy Java builds launch the generated `MakepadApp`
// subclass that bridges into `MakepadNative.activityOnCreate`.
let activity = if config.android_native_activity {
format!("{package}/android.app.NativeActivity")
} else {
format!("{package}/.MakepadApp")
};
let studio_host = format!("127.0.0.1:{port}");
let output = adb_command(config)
.args([
"shell", "am", "start",
"-n", &activity,
"-e", "makepad.STUDIO_HOST", &studio_host,
"-e", "makepad.STUDIO_BUILD", &build_id.to_string(),
"-e", "makepad.STUDIO_CRATE", crate_name,
])
.output()
.map_err(|err| TestError::new(format!("failed to run adb shell am start: {err}")))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(TestError::new(format!("adb launch failed: {}", stderr.trim())));
}
Ok(())
}
fn adb_force_stop(config: &TestConfig, package: &str) -> TestResult<()> {
let _ = adb_exec(config, &["shell", "am", "force-stop", package]);
// Also force-stop known interfering apps that share the Makepad runtime
// and may reclaim the foreground during our tests.
let interfering = ["rs.robius.robrix"];
for pkg in &interfering {
let _ = adb_exec(config, &["shell", "am", "force-stop", pkg]);
}
Ok(())
}
fn adb_enable_package(config: &TestConfig, package: &str) -> TestResult<()> {
let _ = adb_exec(config, &["shell", "pm", "enable", package]);
Ok(())
}
fn adb_grant_permissions(config: &TestConfig, package: &str) -> TestResult<()> {
let perms = [
"android.permission.READ_MEDIA_IMAGES",
"android.permission.READ_MEDIA_VIDEO",
"android.permission.READ_MEDIA_VISUAL_USER_SELECTED",
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO",
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.BLUETOOTH_CONNECT",
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.ACCESS_COARSE_LOCATION",
];
for perm in &perms {
let _ = adb_exec(config, &["shell", "pm", "grant", package, perm]);
}
Ok(())
}
fn resolve_workspace_root(manifest_dir: &std::path::Path) -> std::path::PathBuf {
if let Ok(env_root) = std::env::var("MAKEPAD_WORKSPACE_ROOT") {
let root = std::path::PathBuf::from(env_root);
if root.join("Cargo.toml").exists() {
return root;
}
}
let mut dir = manifest_dir.to_path_buf();
loop {
let cargo_toml = dir.join("Cargo.toml");
if cargo_toml.exists() {
if let Ok(content) = std::fs::read_to_string(&cargo_toml) {
if content.contains("tools/cargo_makepad") {
// skip Cargo.toml files that reference the tool as a path
}
let has_workspace = content.contains("[workspace]")
|| content.contains("workspace.members")
|| content.contains("workspace.package");
if has_workspace && dir.join("tools/cargo_makepad").exists() {
return dir;
}
}
}
if !dir.pop() {
break;
}
}
manifest_dir.to_path_buf()
}
fn build_android_apk(config: &TestConfig) -> TestResult<std::path::PathBuf> {
let workspace_root = resolve_workspace_root(&config.manifest_dir);
let cargo_makepad = workspace_root
.join("target")
.join("release")
.join("cargo-makepad");
if !cargo_makepad.exists() {
return Err(TestError::new(format!(
"cargo-makepad not found at {}. Run: cargo build --release -p cargo-makepad",
cargo_makepad.display()
)));
}
let mut args = vec!["android"];
if config.android_native_activity {
args.push("--native-activity");
}
args.extend_from_slice(&["build", "-p", &config.package_name]);
let output = std::process::Command::new(&cargo_makepad)
.args(&args)
.current_dir(&workspace_root)
.output()
.map_err(|err| TestError::new(format!("failed to run cargo makepad: {err}")))?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
return Err(TestError::new(format!(
"android build failed:\nstdout: {}\nstderr: {}",
stdout.trim(),
stderr.trim()
)));
}
let apk_dir_name = config.package_name.replace('-', "_");
let apk_dir = workspace_root
.join("target")
.join("android")
.join("makepad-android-apk")
.join(&apk_dir_name)
.join("apk");
let apk_name = format!("{}.apk", &apk_dir_name);
let apk_path = apk_dir.join(&apk_name);
if !apk_path.exists() {
return Err(TestError::new(format!(
"APK not found at {}",
apk_path.display()
)));
}
Ok(apk_path)
}
fn wait_for_android_app_started(
connection: &TestConnection,
build_id: QueryId,
timeout: Duration,
) -> TestResult<()> {
let deadline = Instant::now() + timeout;
loop {
if Instant::now() >= deadline {
return Err(TestError::new(
"timed out waiting for Android app to connect to hub",
));
}
let slice = cmp::min(
POLL_INTERVAL,
deadline.saturating_duration_since(Instant::now()),
);
let Some(msg) = connection.recv_timeout(slice) else {
continue;
};
match msg {
HubToClient::AppStarted {
build_id: msg_build_id,
} if msg_build_id == build_id => {
return Ok(());
}
HubToClient::Error { message } => return Err(TestError::new(message)),
_ => {}
}
}
}
fn wait_for_android_app_responsive(
connection: &mut TestConnection,
build_id: QueryId,
timeout: Duration,
) -> TestResult<()> {
let deadline = Instant::now() + timeout;
while Instant::now() < deadline {
let query_id = connection.send(ClientToHub::WidgetTreeDump { build_id })?;
let attempt_deadline = Instant::now() + ACTION_TIMEOUT;
let mut replied = false;
while Instant::now() < attempt_deadline {
if Instant::now() >= deadline {
break;
}
let slice = cmp::min(
POLL_INTERVAL,
attempt_deadline.saturating_duration_since(Instant::now()),
);
let Some(msg) = connection.recv_timeout(slice) else {
continue;
};
if let HubToClient::WidgetTreeDump {
query_id: id, dump: _, ..
} = &msg
{
if *id == query_id {
replied = true;
break;
}
}
}
if replied {
return Ok(());
}
thread::sleep(POLL_INTERVAL);
}
Err(TestError::new(
"timed out waiting for Android app to become responsive",
))
}
fn start_android_app(config: &TestConfig) -> TestResult<(TestConnection, QueryId)> {
let hub_port = config.android_port;
let listen_address = SocketAddr::from((Ipv4Addr::LOCALHOST, hub_port));
let mut connection = TestConnection::InProcess(
StudioHub::start_in_process(HubConfig {
listen_address,
mounts: vec![MountConfig {
name: config.mount_name.clone(),
path: config.manifest_dir.clone(),
}],
enable_in_process_gateway: true,
..Default::default()
})
.map_err(TestError::new)?,
);
let build_id = QueryId(1);
let full_package = android_full_package_name(&config.package_name);
// The hub may have bound a fallback port (e.g. when a real Studio already
// owns `android_port`). Route adb and the app at the port actually bound,
// never a hardcoded one, or the app would dial a dead listener.
let hub_port = connection
.studio_addr()
.and_then(|addr| addr.rsplit_once(':').map(|(_, p)| p.to_string()))
.and_then(|p| p.parse::<u16>().ok())
.unwrap_or(config.android_port);
eprintln!("[makepad-test] Android: forwarding ADB port {hub_port}");
adb_forward(config, hub_port)?;
eprintln!("[makepad-test] Android: building APK for {}", config.package_name);
let apk_path = build_android_apk(config)?;
eprintln!("[makepad-test] Android: installing APK");
adb_install(config, &apk_path)?;
eprintln!("[makepad-test] Android: granting runtime permissions");
adb_grant_permissions(config, &full_package)?;
eprintln!("[makepad-test] Android: force-stopping previous instance");
let _ = adb_force_stop(config, &full_package);
thread::sleep(Duration::from_secs(1));
eprintln!("[makepad-test] Android: launching app");
adb_launch(config, &full_package, build_id.0, &config.package_name, hub_port)?;
thread::sleep(Duration::from_secs(2));
eprintln!("[makepad-test] Android: waiting for app to connect to hub");
wait_for_android_app_started(&connection, build_id, ANDROID_STARTUP_TIMEOUT)?;
eprintln!("[makepad-test] Android: app connected");
// The websocket connects on a background thread before the app's event
// loop is up, so a cold start can answer the handshake well before it can
// service hub requests. Legacy Java starts are the slowest: the first
// frame (and with it the main loop that drains requests) only comes after
// the SurfaceView surface materializes, which on a first launch after
// install can exceed the per-request action timeout. Settle until the app
// actually answers a request so the test's first query does not lose that
// boot race.
eprintln!("[makepad-test] Android: waiting for app to become responsive");
wait_for_android_app_responsive(&mut connection, build_id, ANDROID_STARTUP_TIMEOUT)?;
eprintln!("[makepad-test] Android: app responsive");
Ok((connection, build_id))
}
fn now_seconds() -> f64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)

View file

@ -59,50 +59,24 @@ pub enum HttpServerRequest {
},
}
/// Handle to a running HTTP server. Sending on `shutdown` (or dropping the
/// sender) makes the accept loop exit so the listen port is released and the
/// thread can be joined.
pub struct HttpServerHandle {
pub thread: std::thread::JoinHandle<()>,
pub shutdown: mpsc::Sender<()>,
}
pub fn start_http_server(http_server: HttpServer) -> Option<HttpServerHandle> {
pub fn start_http_server(http_server: HttpServer) -> Option<std::thread::JoinHandle<()>> {
let listener = if let Ok(listener) = TcpListener::bind(http_server.listen_address) {
listener
} else {
println!("Cannot bind http server port");
return None;
};
if listener.set_nonblocking(true).is_err() {
println!("Cannot set http server non-blocking");
return None;
}
let (shutdown_tx, shutdown_rx) = mpsc::channel::<()>();
let listen_thread = {
std::thread::spawn(move || {
let mut connection_counter = 0u64;
loop {
if shutdown_rx.try_recv().is_ok() {
break;
}
let mut tcp_stream = match listener.accept() {
Ok((tcp_stream, _)) => tcp_stream,
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
// No pending connection; poll the shutdown channel
// periodically so a drop releases the port promptly.
std::thread::sleep(std::time::Duration::from_millis(5));
continue;
}
Err(_) => {
println!("Incoming stream failure");
continue;
}
};
if tcp_stream.set_nonblocking(false).is_err() {
for tcp_stream in listener.incoming() {
let mut tcp_stream = if let Ok(tcp_stream) = tcp_stream {
tcp_stream
} else {
println!("Incoming stream failure");
continue;
}
};
let http_server = http_server.clone();
connection_counter += 1;
let _read_thread = std::thread::spawn(move || {
@ -134,10 +108,7 @@ pub fn start_http_server(http_server: HttpServer) -> Option<HttpServerHandle> {
}
})
};
Some(HttpServerHandle {
thread: listen_thread,
shutdown: shutdown_tx,
})
Some(listen_thread)
}
fn handle_post(

View file

@ -11,7 +11,7 @@ pub mod web_socket_parser;
pub use crate::backend::{EventSink, NetworkBackend, UnsupportedBackend};
pub use crate::http_server::{
start_http_server, HttpServer, HttpServerHandle, HttpServerRequest, HttpServerResponse,
start_http_server, HttpServer, HttpServerRequest, HttpServerResponse,
};
pub use crate::runtime::{NetworkConfig, NetworkRuntime};
pub use crate::socket_stream::SocketStream;

View file

@ -5,7 +5,7 @@ use std::time::Duration;
use makepad_live_id::LiveId;
use crate::backend::{default_backend, EventSink, NetworkBackend};
use crate::http_server::{HttpServer, HttpServerHandle};
use crate::http_server::HttpServer;
use crate::types::{HttpRequest, NetworkError, NetworkResponse, WsSend};
#[derive(Default)]
@ -62,7 +62,7 @@ impl NetworkRuntime {
pub fn start_http_server(
&self,
http_server: HttpServer,
) -> Option<HttpServerHandle> {
) -> Option<std::thread::JoinHandle<()>> {
crate::http_server::start_http_server(http_server)
}

View file

@ -604,84 +604,6 @@ impl Cx {
StudioToApp::Custom(data) => {
self.call_event_handler(&Event::Custom(data));
}
StudioToApp::TouchUpdate(remote_touch) => {
let touches: Vec<crate::event::finger::TouchPoint> = remote_touch
.touches
.iter()
.map(|rt| crate::event::finger::TouchPoint {
state: match rt.state {
makepad_studio_protocol::RemoteTouchState::Start => {
crate::event::finger::TouchState::Start
}
makepad_studio_protocol::RemoteTouchState::Stop => {
crate::event::finger::TouchState::Stop
}
makepad_studio_protocol::RemoteTouchState::Move => {
crate::event::finger::TouchState::Move
}
makepad_studio_protocol::RemoteTouchState::Stable => {
crate::event::finger::TouchState::Stable
}
},
abs: crate::makepad_math::dvec2(rt.abs_x - pos.x, rt.abs_y - pos.y),
time: rt.time,
uid: rt.uid,
rotation_angle: rt.rotation_angle,
force: rt.force,
radius: crate::makepad_math::dvec2(rt.radius_x, rt.radius_y),
handled: Cell::new(Area::Empty),
sweep_lock: Cell::new(Area::Empty),
})
.collect();
self.fingers.process_touch_update_start(remote_touch.time, &touches);
self.call_event_handler(&Event::TouchUpdate(
crate::event::finger::TouchUpdateEvent {
time: remote_touch.time,
window_id,
modifiers: crate::event::KeyModifiers::default(),
touches,
},
));
}
StudioToApp::LongPress(remote_long) => {
let abs = crate::makepad_math::dvec2(remote_long.x - pos.x, remote_long.y - pos.y);
self.fingers.process_tap_count(abs, remote_long.time);
self.fingers.mouse_down(crate::event::MouseButton::PRIMARY, window_id);
self.call_event_handler(&Event::MouseDown(crate::event::MouseDownEvent {
abs,
button: crate::event::MouseButton::PRIMARY,
window_id,
modifiers: crate::event::KeyModifiers::default(),
time: remote_long.time,
handled: Cell::new(Area::Empty),
}));
self.call_event_handler(&Event::MouseUp(crate::event::MouseUpEvent {
abs,
button: crate::event::MouseButton::PRIMARY,
window_id,
modifiers: crate::event::KeyModifiers::default(),
time: remote_long.time + remote_long.duration_ms * 0.001,
}));
self.fingers.mouse_up(crate::event::MouseButton::PRIMARY);
self.fingers.cycle_hover_area(live_id!(mouse).into());
self.send_studio_key_focus_rect_response();
}
StudioToApp::TextPaste(remote_paste) => {
self.call_event_handler(&Event::TextInput(crate::event::TextInputEvent {
input: remote_paste.text,
replace_last: false,
was_paste: true,
..Default::default()
}));
}
StudioToApp::IMEComposition(remote_ime) => {
self.call_event_handler(&Event::TextInput(crate::event::TextInputEvent {
input: remote_ime.text,
replace_last: true,
was_paste: false,
..Default::default()
}));
}
StudioToApp::KeepAlive | StudioToApp::None => {}
StudioToApp::LiveChange { file_name, content } => {
self.script_data

View file

@ -299,9 +299,7 @@ impl Cx {
self.display_context.screen_size = self.os.display_size / dpi_factor;
self.display_context.safe_area_insets = insets;
self.update_safe_inset_script_values(insets);
Self::send_studio_message(AppToStudio::BeforeStartup);
self.call_event_handler(&Event::Startup);
Self::send_studio_message(AppToStudio::AfterStartup);
self.redraw_all();
self.start_network_live_file_watcher();

View file

@ -331,7 +331,6 @@ unsafe fn get_intent_string_extra(
const MAKEPAD_PREFS_NAME: &str = "makepad";
const MAKEPAD_STUDIO_HOST_PREF_KEY: &str = "studio_host";
const MAKEPAD_STUDIO_CRATE_PREF_KEY: &str = "studio_crate";
const MAKEPAD_STUDIO_BUILD_PREF_KEY: &str = "studio_build";
const ANDROID_MODE_PRIVATE: i32 = 0;
unsafe fn new_jstring(env: *mut jni_sys::JNIEnv, value: &str) -> Option<jni_sys::jstring> {
@ -454,8 +453,6 @@ pub unsafe fn apply_studio_env_from_activity(activity: *const std::ffi::c_void)
.filter(|v| !v.trim().is_empty());
let intent_studio_crate = get_intent_string_extra(env, activity, "makepad.STUDIO_CRATE")
.filter(|v| !v.trim().is_empty());
let intent_studio_build = get_intent_string_extra(env, activity, "makepad.STUDIO_BUILD")
.filter(|v| !v.trim().is_empty());
if let Some(studio_host) = intent_studio_host {
let _ = persist_string_pref(env, activity, MAKEPAD_STUDIO_HOST_PREF_KEY, &studio_host);
@ -474,15 +471,6 @@ pub unsafe fn apply_studio_env_from_activity(activity: *const std::ffi::c_void)
{
std::env::set_var("STUDIO_CRATE", &studio_crate);
}
if let Some(studio_build) = intent_studio_build {
let _ = persist_string_pref(env, activity, MAKEPAD_STUDIO_BUILD_PREF_KEY, &studio_build);
std::env::set_var("STUDIO_BUILD", &studio_build);
} else if let Some(studio_build) =
get_persisted_string_pref(env, activity, MAKEPAD_STUDIO_BUILD_PREF_KEY)
{
std::env::set_var("STUDIO_BUILD", &studio_build);
}
}
pub unsafe fn attach_jni_env() -> *mut jni_sys::JNIEnv {

View file

@ -240,52 +240,6 @@ pub struct RemoteScroll {
pub modifiers: RemoteKeyModifiers,
}
#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
pub enum RemoteTouchState {
Start,
Stop,
Move,
#[default]
Stable,
}
#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
pub struct RemoteTouchPoint {
pub state: RemoteTouchState,
pub abs_x: f64,
pub abs_y: f64,
pub time: f64,
pub uid: u64,
pub rotation_angle: f64,
pub force: f64,
pub radius_x: f64,
pub radius_y: f64,
}
#[derive(Clone, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
pub struct RemoteTouchUpdate {
pub time: f64,
pub touches: Vec<RemoteTouchPoint>,
}
#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
pub struct RemoteLongPress {
pub x: f64,
pub y: f64,
pub time: f64,
pub duration_ms: f64,
}
#[derive(Clone, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
pub struct RemoteTextPaste {
pub text: String,
}
#[derive(Clone, Debug, Default, SerBin, DeBin, SerJson, DeJson, PartialEq)]
pub struct RemoteIMEComposition {
pub text: String,
}
#[derive(SerBin, DeBin, SerJson, DeJson, Debug, Clone)]
pub enum AppToStudio {
LogItem(StudioLogItem),
@ -465,10 +419,6 @@ pub enum StudioToApp {
/// changes. Level state rather than edges, because that is what the OS
/// APIs report and what `Cx::game_input_states` hands back.
GameInput(Vec<RemoteGameInput>),
TouchUpdate(RemoteTouchUpdate),
LongPress(RemoteLongPress),
TextPaste(RemoteTextPaste),
IMEComposition(RemoteIMEComposition),
/// Application-defined event. Delivered to the app as `Event::Custom`.
Custom(String),
#[default]

View file

@ -5,10 +5,6 @@ edition = "2021"
description = "Studio2 hub (protocol + gateway + virtual fs)"
license = "MIT OR Apache-2.0"
[[bin]]
name = "hub-server"
path = "src/bin/hub_server.rs"
[dependencies]
makepad-script-std = { path = "../../platform/script/std", version = "1.0.0" }
makepad-studio-protocol = { path = "../../platform/studio", version = "0.1.0" }

View file

@ -1,38 +0,0 @@
use makepad_studio_hub::{HubConfig, MountConfig, StudioHub};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::PathBuf;
fn main() {
let port: u16 = std::env::args()
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(8001);
let listen_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port);
let mount_path = std::env::args()
.nth(2)
.map(PathBuf::from)
.unwrap_or_else(|| std::env::current_dir().unwrap());
println!("[hub-server] Listening on {}", listen_address);
println!("[hub-server] Mount path: {}", mount_path.display());
let _handle = StudioHub::start_headless(HubConfig {
listen_address,
mounts: vec![MountConfig {
name: "makepad".into(),
path: mount_path,
}],
enable_in_process_gateway: true,
..Default::default()
})
.expect("Failed to start hub");
println!("[hub-server] Hub started successfully on {}", listen_address);
println!("[hub-server] Waiting for connections...");
loop {
std::thread::sleep(std::time::Duration::from_secs(3600));
}
}

View file

@ -1,8 +1,7 @@
use crate::dispatch::HubEvent;
use makepad_micro_serde::SerBin;
use makepad_script_std::makepad_network::{
start_http_server, HttpServer, HttpServerHandle, HttpServerRequest, HttpServerResponse,
ToUISender,
start_http_server, HttpServer, HttpServerRequest, HttpServerResponse, ToUISender,
};
use makepad_studio_protocol::hub_protocol::{HubToClient, QueryId};
use std::collections::HashMap;
@ -20,21 +19,8 @@ enum SocketRole {
pub struct GatewayHandle {
pub listen_address: SocketAddr,
pub request_thread: Option<JoinHandle<()>>,
pub http_thread: Option<JoinHandle<()>>,
http_shutdown: Sender<()>,
}
impl Drop for GatewayHandle {
fn drop(&mut self) {
// Stop the accept loop so the listen port is released. Dropping the
// request channel senders then makes the request thread exit, which
// drops its hub event sender and lets the hub core shut down too.
let _ = self.http_shutdown.send(());
if let Some(http_thread) = self.http_thread.take() {
let _ = http_thread.join();
}
}
pub request_thread: JoinHandle<()>,
pub http_thread: JoinHandle<()>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -53,10 +39,7 @@ pub fn start_http_gateway(
event_tx: Sender<HubEvent>,
) -> Result<GatewayHandle, String> {
let (request_tx, request_rx) = mpsc::channel::<HttpServerRequest>();
let HttpServerHandle {
thread: http_thread,
shutdown: http_shutdown,
} = start_http_server(HttpServer {
let http_thread = start_http_server(HttpServer {
listen_address,
request: request_tx,
post_max_size,
@ -235,9 +218,8 @@ pub fn start_http_gateway(
Ok(GatewayHandle {
listen_address,
request_thread: Some(request_thread),
http_thread: Some(http_thread),
http_shutdown,
request_thread,
http_thread,
})
}

View file

@ -24,7 +24,7 @@ fn main() {
}
let root_path = args[1].clone();
let _http_server = net.start_http_server(HttpServer{
net.start_http_server(HttpServer{
listen_address:addr,
post_max_size: 1024*1024,
request: tx_request

View file

@ -18,11 +18,6 @@ i_overlay = { path = "../libs/i_overlay", version = "7.0.3", optional = true, de
makepad-fast-inflate = { path = "../libs/fast_inflate", optional = true }
makepad-voice = { path = "../libs/voice", version = "0.1.0", optional = true }
makepad-cef = { path = "../libs/cef", optional = true }
# Public optional sibling crates. These are re-exported from lib.rs so an
# application can depend on makepad-widgets as its sole Makepad source.
makepad-gltf = { path = "../libs/gltf", optional = true }
makepad-csg = { path = "../libs/csg/csg", optional = true }
makepad-test = { path = "../libs/makepad_test", optional = true }
makepad-html = { path = "../libs/html", version = "1.0.0" }
unicode-segmentation = { version = "1.12.0", path = "../libs/unicode/unicode-segmentation" }
@ -33,16 +28,32 @@ ttf-parser = { path = "../libs/ttf-parser" }
serde = { version = "1.0", optional = true, features = ["derive"] }
# Public optional sibling crates, re-exported from lib.rs so an application
# can depend on makepad-widgets as its sole Makepad source. These are
# fork-local additions; an upstream sync dropped them at abd70f4, which
# removed the `test` feature and broke every crate using makepad_test.
[dependencies.makepad-gltf]
path = "../libs/gltf"
optional = true
[dependencies.makepad-csg]
path = "../libs/csg/csg"
optional = true
[dependencies.makepad-test]
path = "../libs/makepad_test"
optional = true
[features]
default = []
voice = ["dep:makepad-voice"]
maps = ["dep:makepad-mbtile-reader", "dep:makepad-fast-inflate", "dep:i_overlay"]
gltf = ["dep:makepad-gltf"]
csg = ["dep:makepad-csg"]
test = ["dep:makepad-test"]
pdf = ["dep:makepad-pdf-parse"]
cef = ["dep:makepad-cef"]
## Enables certain public-facing types to derive serde serialization traits.
serde = ["dep:serde", "makepad-draw/serde", "makepad-derive-widget/serde"]
gltf = ["dep:makepad-gltf"]
csg = ["dep:makepad-csg"]
test = ["dep:makepad-test"]

View file

@ -9,25 +9,22 @@ pub use makepad_script::script_eval;
pub use makepad_script::{ScriptValue, ScriptVm};
pub use makepad_html;
#[cfg(feature = "pdf")]
pub use makepad_pdf_parse;
pub use makepad_draw::makepad_zune_jpeg;
pub use makepad_draw::makepad_zune_png;
// Optional sibling Makepad workspace crates. These re-exports permit a
// downstream application to depend on makepad-widgets as the single Makepad
// source while keeping all extra APIs feature-gated.
#[cfg(feature = "maps")]
pub use makepad_fast_inflate;
#[cfg(feature = "maps")]
pub use makepad_mbtile_reader;
// Fork-local re-exports of the optional sibling crates, so an application
// can depend on makepad-widgets alone. Lost in the upstream sync at
// abd70f4; `makepad_test` in particular is imported as
// `makepad_widgets::makepad_test` by every UI test suite in nigig-org.
#[cfg(feature = "gltf")]
pub use makepad_gltf;
#[cfg(feature = "csg")]
pub use makepad_csg;
#[cfg(feature = "test")]
pub use makepad_test;
#[cfg(feature = "pdf")]
pub use makepad_pdf_parse;
pub use makepad_draw::makepad_zune_jpeg;
pub use makepad_draw::makepad_zune_png;
// Core modules (used internally first)
pub mod animator;