Closed rp1231 closed 11 months ago
Also, looking at the source code, I see that you've enabled mica. That doesn't really seem to be working for me on windows 11.
Also, looking at the source code, I see that you've enabled mica. That doesn't really seem to be working for me on windows 11.
Could you provide a screenshot and your OS build (in Settings/System/About)? Mica works fine on my 22631.2715
I'm on the same build as you. I've posted a screenshot of both twinkle tray with mica blur enabled and brightness-tray for comparison.
Also the power button isn't working. Not that I have a need for it. But just thought I would mention it just in case.
you can't scroll over the sliders to change the values.
Done in d6ee080c3cec57f956a169dc4a8dd4ea89c24600
Confirmed working.
I've posted a screenshot of both twinkle tray with mica blur enabled and brightness-tray for comparison.
Mica is actually working. You can try a dark theme or a vivid wallpaper to see it clearly.
The difference is caused by different implementation. Twinkle Tray is mimicking Mica by itself -- its panel is actually transparent, and it retrieves your wallpaper and blends with it, see https://github.com/xanderfrangos/twinkle-tray/blob/master/src/electron.js#L3455-L3507. On the contrary, my implementation uses the official API DWM_SYSTEMBACKDROP_TYPE
which is introduced in Windows 11 22H2 (that is also the reason why we need a very high Windows version). The Mica effect is done by Desktop Window Manager (DWM).
In the custom implementation of Mica in Twinkle Tray, Mica is blended in a more transparent (or more vivid?) way than system default. I don't know whether it is intentional. Maybe we can use HostBackdropBrush
to achieve a similar effect, but I think we can do it latter.
I see. I'll close this issue in that case.
Also the power button isn't working. Not that I have a need for it. But just thought I would mention it just in case.
My implementation will display the power button if it can read the powerstate of your monitor. However, being able to read it does not mean being able to write it. You can have a look at the DevTool to see if it is an error whiling setting the powerstate.
In Twinkle Tray, power button is not displayed by default even the powerstate is detected. You need to enable it in the settings. You can try to enable it and see whether Twinkle Tray is able to control powerstate. We can adopt a similar approach after the settings page is implemented.
The devtools console doesn't show any error while pressing the power button. However I get this error when scrolling over any of the controls.
Also I'm able to turn off my screen via twinkle tray through both the software signal and the ddcci method
Ok, I've tweaked the power button in 01a1327. It will not show if the reported powerstate maximum is less than 4, and it will try the maximum state by default. Could you have a try to see whether it works?
However I get this error when scrolling over any of the controls.
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#passive
Well, I've learned new knowledge:
If this option is not specified it defaults to false – except that in browsers other than Safari, it defaults to true for
wheel
,mousewheel
,touchstart
andtouchmove
events.
Meanwhile, React has made decision for me: https://github.com/facebook/react/issues/22794#issuecomment-975618944 🤣
I'm on the same build as you. I've posted a screenshot of both twinkle tray with mica blur enabled and brightness-tray for comparison.
It seems that your BOE0A9B (Display 1) is an internal laptop display and cannot be controlled by DDC/CI but WMI. WMI support is currently not implemented yet. Maybe someday I will get a laptop to implement it.
There's no way to turn the eventlistener passive mode to false?
It seems that your BOE0A9B (Display 1) is an internal laptop display and cannot be controlled by DDC/CI but WMI. WMI support is currently not implemented yet. Maybe someday I will get a laptop to implement it.
Yes, it also needs to have a different icon for the laptop internal monitor as seen in the screenshot.
Also regarding the power button, it's working now but just for turning the screen off.
Twinkle tray also doesn't support turning on the monitor, if turned off.
Also regarding the power button, it's working now but just for turning the screen off.
Yes, it is just a power off button. You can see https://github.com/ruihe774/brightness-tray/blob/01a132778e84af34df1b2c9ca9588841630bd5f8/src/MonitorList.tsx#L39 The text label is hidden for beauty. Maybe I can hide the button if the monitor is powered off. I did not spot this issue because I have only one display, so if it is powered off, I cannot see this button literally. 🤣
Switching to vue seems to have solved the eventlistener preventdefault errors. But there's still this one strange error showing up in the console:
:1420/favicon.ico:1
Failed to load resource: the server responded with a status of 404 (Not Found)
Switching to vue seems to have solved the eventlistener preventdefault errors. But there's still this one strange error showing up in the console:
:1420/favicon.ico:1 Failed to load resource: the server responded with a status of 404 (Not Found)
Well, switching to Vue is for other reasons, yet it does solve the onWheel problem. The 404 of icon is known. I don't think we need a favicon here, so save some space.
@ruihe774 Can you help me with a bit of code I'm stuck on with my tauri app? I need to connect to this bulb once:
let my_bulb_ip = "<my_bulb_ip>";
let mut bulb = Bulb::connect(my_bulb_ip, 55443).await?;
And then keep the connection alive so that other functions can use this connection. Right now I'm using this code:
use std::sync::Mutex;
use std::time::Duration;
use tauri::State;
use yeelight::{Bulb, Effect, Mode, Power};
#[tauri::command]
async fn bulb_toggle() {
let my_bulb_ip = "<my_bulb_ip>";
let mut bulb = Bulb::connect(my_bulb_ip, 55443)
.await
.expect("Connection failed");
if let Some(response) = bulb.toggle().await.expect("Error") {
for v in response.iter() {
println!("{}", v);
}
}
}
#[tauri::command]
async fn set_brightness(level: u8) {
let my_bulb_ip = "<my_bulb_ip>";
let mut bulb = Bulb::connect(my_bulb_ip, 55443)
.await
.expect("Connection failed");
if let Some(response) = bulb
.set_bright(level, Effect::Sudden, Duration::new(0, 0))
.await
.expect("Error")
{
for v in response.iter() {
println!("{}", v);
}
}
}
// Ideally I want to call this function once on app start and use this connection in the set_brightness and bulb_toggle functions
//#[tauri::command]
//async fn bulb_connect() -> Result<(), Box<dyn std::error::Error>> {
// let my_bulb_ip = "<my_bulb_ip>";
// let mut bulb = Bulb::connect(my_bulb_ip, 55443).await?;
// // .expect("Connection Failed");
// Ok(())
//}
fn main() {
env_logger::init();
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![set_brightness, bulb_toggle, bulb_connect])
// .manage(Mutex::new(BulbConnection { bulb: "" }))
//.manage(AppState { bulb: None })
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
As you can see in this, I'm connecting to this bulb every time the tauri command is called from the frontend
@ruihe774 Can you help me with a bit of code I'm stuck on with my tauri app? I need to connect to this bulb once:
let my_bulb_ip = "<my_bulb_ip>"; let mut bulb = Bulb::connect(my_bulb_ip, 55443).await?;
And then keep the connection alive so that other functions can use this connection. Right now I'm using this code:
use std::sync::Mutex; use std::time::Duration; use tauri::State; use yeelight::{Bulb, Effect, Mode, Power}; #[tauri::command] async fn bulb_toggle() { let my_bulb_ip = "<my_bulb_ip>"; let mut bulb = Bulb::connect(my_bulb_ip, 55443) .await .expect("Connection failed"); if let Some(response) = bulb.toggle().await.expect("Error") { for v in response.iter() { println!("{}", v); } } } #[tauri::command] async fn set_brightness(level: u8) { let my_bulb_ip = "<my_bulb_ip>"; let mut bulb = Bulb::connect(my_bulb_ip, 55443) .await .expect("Connection failed"); if let Some(response) = bulb .set_bright(level, Effect::Sudden, Duration::new(0, 0)) .await .expect("Error") { for v in response.iter() { println!("{}", v); } } } // Ideally I want to call this function once on app start and use this connection in the set_brightness and bulb_toggle functions //#[tauri::command] //async fn bulb_connect() -> Result<(), Box<dyn std::error::Error>> { // let my_bulb_ip = "<my_bulb_ip>"; // let mut bulb = Bulb::connect(my_bulb_ip, 55443).await?; // // .expect("Connection Failed"); // Ok(()) //} fn main() { env_logger::init(); tauri::Builder::default() .invoke_handler(tauri::generate_handler![set_brightness, bulb_toggle, bulb_connect]) // .manage(Mutex::new(BulbConnection { bulb: "" })) //.manage(AppState { bulb: None }) .run(tauri::generate_context!()) .expect("error while running tauri application"); }
As you can see in this, I'm connecting to this bulb every time the tauri command is called from the frontend
You can use manage
and access your bulb using a State
. You can use OnceLock
or Mutex
for deferred connection.
# in main()
.manage(OnceLock::<BulbConnection>::new())
#[tauri::command]
async fn bulb_connect(bulb: State<OnceLock<BulbConnection>>) -> Result<(), Box<dyn std::error::Error>> {
let my_bulb_ip = "<my_bulb_ip>";
bulb.set(Bulb::connect(my_bulb_ip, 55443).await?)?;
Ok(())
}
Another way
# in main()
.manage(Mutex::<Option<BulbConnection>>::new())
#[tauri::command]
async fn bulb_connect(bulb: State<Mutex<Option<BulbConnection>>>) -> Result<(), Box<dyn std::error::Error>> {
let my_bulb_ip = "<my_bulb_ip>";
bulb.lock()?.insert(Bulb::connect(my_bulb_ip, 55443).await?)?;
Ok(())
}
Or use Mutex<HashMap>
if you have multiple bulbs.
Thanks a lot!
@ruihe774 After a lot of ChatGpt'ing I finally arrived at this code with only one error:
use std::sync::{Arc, Mutex};
use tauri::{Manager, State, Window};
use yeelight::{Bulb, Effect, Mode, Power};
// Bulb state
#[derive(Default)]
struct BulbState {
bulb: Option<Mutex<Option<Bulb>>>,
}
// Command to connect
#[tauri::command]
async fn connect_bulb(window: Window) {
let ip = "<ip>";
let bulb = Bulb::connect(ip, 55443).await.unwrap();
// Get the Mutex
let state_mutex = window.state::<Mutex<BulbState>>();
let mut state = state_mutex.lock().unwrap();
// Lock the Mutex and access the inner state
if let Some(ref mut bulb_mutex) = state.bulb {
let mut bulb_guard = bulb_mutex.lock().unwrap();
*bulb_guard = Some(bulb);
}
}
// Main app
fn main() {
let mutex = Mutex::new(BulbState::default());
let window = tauri::Builder::default()
.manage(mutex)
.invoke_handler(tauri::generate_handler![connect_bulb])
.run(tauri::generate_context!())
.expect("error");
// Now you can call connect_bulb with the actual window instance
connect_bulb(window);
}
When I call the connect_bulb function from inside fn main, it requires an argument.
Do you have any idea of what to do about that? I'm trying to connect to the bulb on app start so that I can access it from other functions. Thanks
Looks good, It detected my internal monitor and external monitor. And the ddcci brightness/contrast/volume controls work perfectly for the external one. Except you can't scroll over the sliders to change the values.