Skip to content

Commit 465c320

Browse files
authored
fix: there is no effect on changing the application scale factor. (#144)
* fix: there is no effect on changing application scale factor. In this commit, a `window_size` is introduced in the window state. There are three types of coordinates: 1. `window_size`: The coordinates that the client believes it is using. These are used to communicate with the Wayland server. 2. `viewport.physical_size`: The coordinates of the screen. These are used to render the final view that the user sees. 3. `viewport.logical_size`: The coordinates used by Iced. Iced draws widgets based on these coordinates. `viewport.physical_size` = `window_size` * `wayland_scale_factor` = `viewport.logical_size` * `application_scale_factor` * `wayland_scale_factor` Signed-off-by: fortime <palfortime@gmail.com> * feat: add multi window example. Signed-off-by: fortime <palfortime@gmail.com> --------- Signed-off-by: fortime <palfortime@gmail.com>
1 parent 69d71d8 commit 465c320

File tree

13 files changed

+657
-259
lines changed

13 files changed

+657
-259
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "multi_window"
3+
authors.workspace = true
4+
edition.workspace = true
5+
version.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
description.workspace = true
9+
keywords.workspace = true
10+
readme.workspace = true
11+
12+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
13+
14+
[dependencies]
15+
iced = { workspace = true }
16+
iced_runtime.workspace = true
17+
iced_layershell.workspace = true
18+
tracing.workspace = true
19+
tracing-subscriber.workspace = true
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
use iced::alignment::Vertical;
2+
use iced::widget::{
3+
button, center, column, container, horizontal_space, row, scrollable, text, text_input,
4+
};
5+
use iced::{Center, Element, Fill, Subscription, Task, Theme, event};
6+
use iced::{Color, window};
7+
use iced_layershell::build_pattern::{self, MainSettings};
8+
use iced_layershell::reexport::{Anchor, Layer, NewLayerShellSettings};
9+
use iced_layershell::settings::{LayerShellSettings, StartMode};
10+
use iced_layershell::{Appearance, DefaultStyle, to_layer_message};
11+
use tracing_subscriber::layer::SubscriberExt;
12+
use tracing_subscriber::util::SubscriberInitExt;
13+
use tracing_subscriber::{EnvFilter, fmt};
14+
15+
use std::collections::BTreeMap;
16+
17+
fn main() -> iced_layershell::Result {
18+
tracing_subscriber::registry()
19+
.with(fmt::layer())
20+
.with(EnvFilter::from_default_env())
21+
.init();
22+
build_pattern::daemon(
23+
"multi_window",
24+
Example::update,
25+
Example::view,
26+
Example::remove_id,
27+
)
28+
.theme(Example::theme)
29+
.style(Example::style)
30+
.subscription(Example::subscription)
31+
.scale_factor(Example::scale_factor)
32+
.settings(MainSettings {
33+
layer_settings: LayerShellSettings {
34+
start_mode: StartMode::Background,
35+
..Default::default()
36+
},
37+
..Default::default()
38+
})
39+
.run_with(Example::new)?;
40+
Ok(())
41+
}
42+
43+
struct Example {
44+
windows: BTreeMap<window::Id, Window>,
45+
}
46+
47+
#[derive(Debug)]
48+
struct Window {
49+
title: String,
50+
scale_input: String,
51+
current_scale: f64,
52+
theme: Theme,
53+
transparent: bool,
54+
}
55+
56+
#[to_layer_message(multi)]
57+
#[derive(Debug, Clone)]
58+
enum Message {
59+
OpenWindow,
60+
CloseWindow(window::Id),
61+
WindowOpened(window::Id),
62+
WindowClosed(window::Id),
63+
ScaleInputChanged(window::Id, String),
64+
ScaleChanged(window::Id, String),
65+
TitleChanged(window::Id, String),
66+
}
67+
68+
impl Example {
69+
fn open(count: usize) -> (window::Id, Task<Message>) {
70+
let anchor = match count % 8 {
71+
0 => Anchor::Bottom,
72+
1 => Anchor::Bottom | Anchor::Right,
73+
2 => Anchor::Right,
74+
3 => Anchor::Right | Anchor::Top,
75+
4 => Anchor::Top,
76+
5 => Anchor::Top | Anchor::Left,
77+
6 => Anchor::Left,
78+
7 => Anchor::Left | Anchor::Bottom,
79+
_ => Anchor::Bottom,
80+
};
81+
let size = (1024, 768);
82+
let id = window::Id::unique();
83+
(
84+
id,
85+
Task::done(Message::NewLayerShell {
86+
settings: NewLayerShellSettings {
87+
size: Some(size),
88+
exclusive_zone: None,
89+
anchor,
90+
layer: Layer::Top,
91+
margin: None,
92+
//keyboard_interactivity: KeyboardInteractivity::None,
93+
use_last_output: false,
94+
..Default::default()
95+
},
96+
id,
97+
}),
98+
)
99+
}
100+
101+
fn new() -> (Self, Task<Message>) {
102+
let (id, open) = Self::open(0);
103+
104+
(
105+
Self {
106+
windows: BTreeMap::new(),
107+
},
108+
open.chain(Task::done(Message::WindowOpened(id))),
109+
)
110+
}
111+
112+
fn update(&mut self, message: Message) -> Task<Message> {
113+
match message {
114+
Message::OpenWindow => {
115+
let len = self.windows.len();
116+
let (id, open) = Self::open(len);
117+
open.chain(Task::done(Message::WindowOpened(id)))
118+
}
119+
Message::CloseWindow(id) => iced::window::close(id),
120+
Message::WindowOpened(id) => {
121+
let window = Window::new(self.windows.len() + 1);
122+
let focus_input = text_input::focus(format!("input-{id}"));
123+
124+
self.windows.insert(id, window);
125+
126+
focus_input
127+
}
128+
Message::WindowClosed(id) => {
129+
self.windows.remove(&id);
130+
131+
if self.windows.is_empty() {
132+
iced::exit()
133+
} else {
134+
Task::none()
135+
}
136+
}
137+
Message::ScaleInputChanged(id, scale) => {
138+
if let Some(window) = self.windows.get_mut(&id) {
139+
window.scale_input = scale;
140+
}
141+
142+
Task::none()
143+
}
144+
Message::ScaleChanged(id, scale) => {
145+
if let Some(window) = self.windows.get_mut(&id) {
146+
window.current_scale = scale
147+
.parse::<f64>()
148+
.unwrap_or(window.current_scale)
149+
.clamp(0.5, 5.0);
150+
}
151+
152+
Task::none()
153+
}
154+
Message::TitleChanged(id, title) => {
155+
if let Some(window) = self.windows.get_mut(&id) {
156+
window.title = title;
157+
}
158+
159+
Task::none()
160+
}
161+
_ => Task::none(),
162+
}
163+
}
164+
165+
fn view(&self, window_id: window::Id) -> Element<Message> {
166+
if let Some(window) = self.windows.get(&window_id) {
167+
center(window.view(window_id)).into()
168+
} else {
169+
horizontal_space().into()
170+
}
171+
}
172+
173+
fn theme(&self, window: window::Id) -> Theme {
174+
if let Some(window) = self.windows.get(&window) {
175+
window.theme.clone()
176+
} else {
177+
Theme::default()
178+
}
179+
}
180+
181+
fn style(&self, theme: &Theme, window: window::Id) -> Appearance {
182+
let mut style = theme.default_style();
183+
if let Some(window) = self.windows.get(&window) {
184+
if window.transparent {
185+
style.background_color = Color::TRANSPARENT;
186+
}
187+
}
188+
style
189+
}
190+
191+
fn scale_factor(&self, window: window::Id) -> f64 {
192+
self.windows
193+
.get(&window)
194+
.map(|window| window.current_scale)
195+
.unwrap_or(1.0)
196+
}
197+
198+
fn subscription(&self) -> Subscription<Message> {
199+
event::listen_with(|event, status, id| {
200+
tracing::debug!("event: {}, {:?}, {:?}", id, status, event);
201+
if let iced::Event::Window(iced::window::Event::Closed) = event {
202+
Some(Message::WindowClosed(id))
203+
} else {
204+
None
205+
}
206+
})
207+
}
208+
209+
fn remove_id(&mut self, _window: window::Id) {
210+
// self.windows.remove(&window);
211+
}
212+
}
213+
214+
impl Window {
215+
fn new(count: usize) -> Self {
216+
Self {
217+
title: format!("Window_{}", count),
218+
scale_input: "1.0".to_string(),
219+
current_scale: 1.0,
220+
theme: Theme::ALL[count % Theme::ALL.len()].clone(),
221+
transparent: count % 2 == 0,
222+
}
223+
}
224+
225+
fn view(&self, id: window::Id) -> Element<Message> {
226+
let scale_input = column![
227+
text("Window scale factor:"),
228+
text_input("Window Scale", &self.scale_input)
229+
.on_input(move |msg| { Message::ScaleInputChanged(id, msg) })
230+
.on_submit(Message::ScaleChanged(id, self.scale_input.to_string()))
231+
];
232+
233+
let title_input = column![
234+
text("Window title:"),
235+
text_input("Window Title", &self.title)
236+
.on_input(move |msg| { Message::TitleChanged(id, msg) })
237+
.id(format!("input-{id}"))
238+
];
239+
240+
let new_window_button = button(text("New Window")).on_press(Message::OpenWindow);
241+
242+
let close_window_button = button(text("Close")).on_press(Message::CloseWindow(id));
243+
244+
let content = scrollable(
245+
column![
246+
scale_input,
247+
title_input,
248+
row![new_window_button, close_window_button]
249+
.spacing(10)
250+
.align_y(Vertical::Center)
251+
]
252+
.spacing(50)
253+
.width(Fill)
254+
.align_x(Center),
255+
);
256+
257+
container(content).center_x(200).into()
258+
}
259+
}

iced_layershell/src/application.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ async fn run_instance<A, E, C>(
391391
&application,
392392
cache,
393393
&mut renderer,
394-
state.logical_size(),
394+
state.viewport().logical_size(),
395395
&mut debug,
396396
));
397397

@@ -415,16 +415,15 @@ async fn run_instance<A, E, C>(
415415
p_fractal_scale = fractal_scale;
416416

417417
state.update_view_port(width, height, fractal_scale);
418-
let logical_size = state.logical_size();
419418

420419
debug.layout_started();
421420
user_interface = ManuallyDrop::new(
422421
ManuallyDrop::into_inner(user_interface)
423-
.relayout(logical_size, &mut renderer),
422+
.relayout(state.viewport().logical_size(), &mut renderer),
424423
);
425424
debug.layout_finished();
426425

427-
let physical_size = state.physical_size();
426+
let physical_size = state.viewport().physical_size();
428427
compositor.configure_surface(
429428
&mut surface,
430429
physical_size.width,
@@ -506,7 +505,11 @@ async fn run_instance<A, E, C>(
506505
IcedLayerEvent::Window(event) => {
507506
state.update(&event);
508507

509-
if let Some(event) = conversion::window_event(&event, state.modifiers()) {
508+
if let Some(event) = conversion::window_event(
509+
&event,
510+
state.application_scale_factor(),
511+
state.modifiers(),
512+
) {
510513
events.push(event);
511514
}
512515
}
@@ -530,7 +533,7 @@ async fn run_instance<A, E, C>(
530533
&application,
531534
cache,
532535
&mut renderer,
533-
state.logical_size(),
536+
state.viewport().logical_size(),
534537
&mut debug,
535538
));
536539
if should_exit {
@@ -575,7 +578,7 @@ async fn run_instance<A, E, C>(
575578
&application,
576579
cache,
577580
&mut renderer,
578-
state.logical_size(),
581+
state.viewport().logical_size(),
579582
&mut debug,
580583
));
581584
}
@@ -694,7 +697,7 @@ pub(crate) fn run_action<A, C>(
694697
application,
695698
current_cache,
696699
renderer,
697-
state.logical_size(),
700+
state.viewport().logical_size(),
698701
debug,
699702
);
700703

@@ -729,12 +732,12 @@ pub(crate) fn run_action<A, C>(
729732
);
730733
let _ = channel.send(window::Screenshot::new(
731734
bytes,
732-
state.physical_size(),
733-
state.scale_factor(),
735+
state.viewport().physical_size(),
736+
state.viewport().scale_factor(),
734737
));
735738
}
736739
WindowAction::GetScaleFactor(_id, channel) => {
737-
let _ = channel.send(state.scale_factor() as f32);
740+
let _ = channel.send(state.wayland_scale_factor() as f32);
738741
}
739742
_ => {}
740743
},

0 commit comments

Comments
 (0)