Skip to content

Commit fea1852

Browse files
committed
fix: shared window class issue, state not resetting, thread issue
1 parent 0726a0c commit fea1852

File tree

9 files changed

+246
-177
lines changed

9 files changed

+246
-177
lines changed

Cargo.lock

Lines changed: 16 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ slint-build="1.9.2"
3333
anyhow ="1.0.95"
3434
crossbeam-channel="0.5.14"
3535
directories ="5.0.1"
36-
rustc-hash ="2.1.0"
3736
tray-item ="0.10.0"
3837

3938
serde ={ version="1.0.217", default-features=false, features=["derive"] }
@@ -68,3 +67,4 @@ windows={ version="0.59.0", default-features=false, features=[
6867
"Win32_UI_Shell",
6968
"Win32_UI_WindowsAndMessaging",
7069
] }
70+
async-compat = "0.2.4"

src/app_state.rs

Lines changed: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::path::PathBuf;
33
use std::sync::Arc;
44
use tokio::sync::{broadcast, RwLock};
55

6-
use crate::monitor::{refresh_config, reset_config};
76
use crate::transparency::create_rules_window;
87
use crate::util::Config;
98
use crate::win_utils::{self, create_percentage_window};
@@ -49,6 +48,15 @@ impl AppState {
4948
}
5049
});
5150
}
51+
pub fn spawn_force_config(&self, value: WindowConfig) {
52+
let app_state: Arc<AppState> = Arc::new(self.clone());
53+
54+
tokio::spawn(async move {
55+
if let Err(e) = app_state.add_force_config(value).await {
56+
eprintln!("Failed to update window config: {}", e);
57+
}
58+
});
59+
}
5260

5361
pub async fn get_window_rules(&self) -> Vec<TransparencyRule> {
5462
let config = self.get_config().await;
@@ -86,71 +94,81 @@ impl AppState {
8694

8795
pub async fn add_window_config(
8896
&self,
89-
mut window_config: WindowConfig,
97+
window_config: WindowConfig,
9098
) -> Result<(), anyhow::Error> {
9199
let mut config = self.get_config_mut().await;
92100

93-
if window_config.is_wide() && window_config.get_old_classname().is_none() {
94-
let old_key: String = window_config.get_key();
95-
let old_class: String = window_config.get_window_class().to_owned();
96-
97-
config.get_windows().remove(&old_key);
98-
99-
match find_parent_from_child_class(window_config.get_window_class()) {
100-
Ok(class) => {
101-
if let Some(info) = class {
102-
window_config.set_window_class(info.1);
103-
refresh_config(window_config.clone());
104-
config.get_windows().remove(&window_config.get_key());
105-
window_config.set_old_classname(Some(old_class));
106-
}
107-
}
108-
Err(_) => (),
109-
}
110-
}
101+
config
102+
.get_windows()
103+
.insert(window_config.get_key(), window_config);
104+
105+
let config_json = serde_json::to_string_pretty(&config.to_owned())?;
106+
self.config_tx.send(config.to_owned())?;
107+
108+
fs::write(&self.get_config_path(), config_json)?;
111109

112-
if !window_config.is_wide() {
113-
println!("d");
114-
match find_parent_from_child_class(window_config.get_window_class()) {
115-
Ok(class) => {
116-
if let Some(info) = class {
117-
let key = &format!("{}|{}", window_config.get_name(), info.1);
118-
println!("hrere {:?}", info);
119-
if config.get_windows().contains_key(key) {
120-
println!("key yo {:?}", key);
121-
let clone_config = window_config.clone();
122-
let real_class = clone_config.get_window_class();
123-
window_config.set_window_class(info.1);
124-
reset_config(window_config.clone());
125-
// let handles = window_config.get_window_hwnds();
126-
window_config.set_window_class(real_class.to_string());
127-
// println!("handles yo {:?}", handles);
128-
129-
config.get_windows().remove(key);
130-
}
131-
} else {
132-
println!("2{:?}", class);
133-
}
134-
}
135-
Err(_) => {
136-
println!("2");
137-
()
138-
}
110+
Ok(())
111+
}
112+
113+
pub async fn add_force_config(
114+
&self,
115+
mut window_config: WindowConfig,
116+
) -> Result<(), anyhow::Error> {
117+
let mut config = self.get_config_mut().await;
118+
119+
// Get the class name to use for parent lookup
120+
let lookup_class = window_config
121+
.get_old_classname()
122+
.clone()
123+
.unwrap_or_else(|| window_config.get_window_class().to_owned());
124+
125+
// Try to find parent class
126+
if let Ok(Some(parent_info)) = find_parent_from_child_class(&lookup_class) {
127+
let parent_class = parent_info.1;
128+
129+
// Remove existing configuration
130+
self.remove_existing_config(&mut config, &window_config);
131+
132+
if window_config.is_forced() {
133+
window_config.set_window_class(&parent_class);
134+
window_config.refresh_config();
135+
window_config.set_old_classname(Some(lookup_class));
136+
} else {
137+
window_config.set_window_class(&parent_class);
138+
window_config.reset_config();
139+
window_config.set_window_class(&lookup_class);
140+
window_config.set_old_classname(None);
141+
142+
// Remove parent configuration
143+
let parent_key = format!("{}|{}", window_config.get_name(), parent_class);
144+
config.get_windows().remove(&parent_key);
139145
}
140146
}
141147

148+
// Update configuration
142149
config
143150
.get_windows()
144151
.insert(window_config.get_key(), window_config);
145152

146153
let config_json = serde_json::to_string_pretty(&config.to_owned())?;
147-
fs::write(&self.get_config_path(), config_json)?;
154+
self.config_tx.send(config.to_owned())?;
148155

149-
self.config_tx.send(config.clone())?;
156+
fs::write(&self.get_config_path(), config_json)?;
150157

151158
Ok(())
152159
}
153160

161+
fn remove_existing_config(&self, config: &mut Config, window_config: &WindowConfig) {
162+
// Remove configuration by original key
163+
config.get_windows().remove(&window_config.get_key());
164+
165+
// Remove configuration by old class if it exists
166+
if let Some(old_class) = window_config.get_old_classname() {
167+
let key = format!("{}|{}", window_config.get_name(), old_class);
168+
config.get_windows().remove(&key);
169+
}
170+
}
171+
154172
pub fn subscribe_config_updates(&self) -> broadcast::Receiver<Config> {
155173
self.config_tx.subscribe()
156174
}

src/monitor.rs

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::window_config::WindowConfig;
21
use crate::{app_state::AppState, util::Config, win_utils::make_window_transparent};
32

43
use core::time::Duration;
@@ -42,19 +41,35 @@ impl WindowHandleState {
4241
pub fn is_enabled(&self) -> bool {
4342
self.enabled
4443
}
44+
45+
pub fn refresh_window(&mut self) {
46+
if make_window_transparent(self.get_handle(), 255).is_ok() {
47+
self.update_state(255, false);
48+
}
49+
}
50+
51+
pub fn update_window(&mut self, mut new_transparency: u8, enabled: bool) {
52+
let real_transparency = new_transparency;
53+
if enabled == false {
54+
new_transparency = 255;
55+
}
56+
if make_window_transparent(self.get_handle(), new_transparency).is_ok() {
57+
self.update_state(real_transparency, enabled);
58+
}
59+
}
4560
}
4661

4762
/*
4863
Monitors the current windows specified in the config file. This is setup to target based on the window class rather than title (multiple windows open of X application...)
4964
*/
5065
#[inline(always)]
5166
pub async fn monitor_windows(app_state: Arc<AppState>) {
52-
let mut window_cache = HashMap::with_capacity(8);
5367
let refresh_interval = Duration::from_millis(120);
68+
5469
let mut config = app_state.get_config().await;
5570
let mut is_enabled = app_state.is_enabled().await;
71+
let mut window_cache = HashMap::with_capacity(8);
5672
let mut config_rx = app_state.subscribe_config_updates();
57-
5873
let mut enabled_rx = app_state.subscribe_enabled_updates();
5974

6075
loop {
@@ -65,7 +80,6 @@ pub async fn monitor_windows(app_state: Arc<AppState>) {
6580
Ok(new_config) = config_rx.recv() => {
6681
config = new_config;
6782
}
68-
6983
Ok(state) = enabled_rx.recv() => {
7084
if state != is_enabled && is_enabled {
7185
reset_windows(&mut window_cache);
@@ -113,19 +127,14 @@ fn refresh_window_cache(config: &Config, cache: &mut HashMap<String, Vec<WindowH
113127
fn update_windows(config: &Config, window_cache: &mut HashMap<String, Vec<WindowHandleState>>) {
114128
for window_config in config.get_windows_non_mut().values() {
115129
if let Some(handle_states) = window_cache.get_mut(&window_config.get_cache_key()) {
116-
let mut new_transparency = window_config.get_transparency();
130+
let new_transparency = window_config.get_transparency();
117131
let new_state = window_config.is_enabled();
118132

119133
for state in handle_states.iter_mut() {
120134
if state.get_transparency() != window_config.get_transparency()
121135
|| state.is_enabled() != new_state
122136
{
123-
if new_state == false {
124-
new_transparency = 255;
125-
}
126-
if make_window_transparent(state.get_handle(), new_transparency).is_ok() {
127-
state.update_state(window_config.get_transparency(), new_state);
128-
}
137+
state.update_window(new_transparency, new_state);
129138
}
130139
}
131140
}
@@ -138,26 +147,6 @@ fn reset_windows(window_cache: &mut HashMap<String, Vec<WindowHandleState>>) {
138147
.values_mut()
139148
.flat_map(|handles| handles.iter_mut())
140149
.for_each(|handle| {
141-
if make_window_transparent(handle.get_handle(), 255).is_ok() {
142-
handle.update_state(255, false);
143-
}
150+
handle.refresh_window();
144151
});
145152
}
146-
147-
pub fn reset_config(window_config: WindowConfig) {
148-
let handles = window_config.get_window_hwnds();
149-
for handle in handles {
150-
if make_window_transparent(HWND(handle as *mut c_void), 255).is_ok() {}
151-
}
152-
}
153-
pub fn refresh_config(window_config: WindowConfig) {
154-
let handles = window_config.get_window_hwnds();
155-
for handle in handles {
156-
if make_window_transparent(
157-
HWND(handle as *mut c_void),
158-
window_config.get_transparency(),
159-
)
160-
.is_ok()
161-
{}
162-
}
163-
}

src/transparency.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::{rc::Rc, sync::Arc};
22

33
use crate::{app_state::AppState, RulesStorage, RulesWindow, TransparencyRule};
44

5-
use slint::{ComponentHandle, VecModel};
5+
use slint::{ComponentHandle, Model, VecModel};
66

77
/*
88
Creates the rules window, this is so the user can see what rules are currently active.
@@ -12,19 +12,52 @@ pub async fn create_rules_window(app_state: Arc<AppState>) -> Result<(), core::f
1212
let window = RulesWindow::new().unwrap();
1313
let window_handle = window.as_weak();
1414

15+
// Create the model once
1516
let mut window_info = app_state.get_window_rules().await;
16-
17-
// Oh boo hoo its sorted every time the rules window is opened 😢
1817
window_info.sort_by_key(|rule| rule.process_name.clone());
18+
let items_model = Rc::new(VecModel::from(window_info));
1919

20+
// Set initial items
2021
window
2122
.global::<RulesStorage>()
22-
.set_items(Rc::new(VecModel::from(window_info)).into());
23+
.set_items(items_model.clone().into());
24+
25+
// Handle submit events
26+
let app_clone = app_state.clone();
2327

2428
window.on_submit(move |value: TransparencyRule| {
25-
app_state.spawn_update_config(value.into());
29+
app_clone.spawn_update_config(value.clone().into());
30+
});
31+
32+
let items_model_weak = window.as_weak();
33+
// Handle force events
34+
window.on_force(move |value: TransparencyRule| {
35+
app_state.spawn_force_config(value.clone().into());
36+
37+
let handle = items_model_weak.clone();
38+
let app_state_clone = app_state.clone();
39+
tokio::spawn(async move {
40+
let current_items = app_state_clone.get_window_rules().await;
41+
42+
handle.upgrade_in_event_loop(move |window| {
43+
if let Some(items_vec) = window
44+
.global::<RulesStorage>()
45+
.get_items()
46+
.as_any()
47+
.downcast_ref::<VecModel<TransparencyRule>>()
48+
{
49+
if let Some(idx) = (0..items_vec.row_count()).find(|&i| {
50+
items_vec.row_data(i).unwrap().process_name == value.process_name
51+
}) {
52+
items_vec.set_row_data(idx, current_items.get(idx).unwrap().clone());
53+
}
54+
}
55+
})?;
56+
Ok::<(), anyhow::Error>(())
57+
});
2658
});
2759

60+
// Handle cancel events
2861
window.on_cancel(move || {
2962
if let Some(window) = window_handle.upgrade() {
3063
window.hide().unwrap();

0 commit comments

Comments
 (0)