Skip to content

Commit

Permalink
WIP: port to gtk4 (compiles but doesn't work properly)
Browse files Browse the repository at this point in the history
- some icons are broken
- clearing osd window doesn't work
- gtk4_layer_shell crashes more often than not
  • Loading branch information
Ferdi265 committed Sep 15, 2024
1 parent 2cc81b8 commit 7628440
Show file tree
Hide file tree
Showing 10 changed files with 469 additions and 467 deletions.
502 changes: 219 additions & 283 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ toml = "0.8"
serde = "1"
serde_derive = "1"
# GUI Dependencies
gtk = "0.18.1"
gtk-layer-shell = "0.8.1"
gtk4 = "0.9.1"
gtk4-layer-shell = "0.4.0"
shrinkwraprs = "0.3.0"
cascade = "1.0.1"
pulse = { version = "2.26.0", package = "libpulse-binding" }
Expand Down
6 changes: 3 additions & 3 deletions src/client/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ mod brightness_backend;

use config::APPLICATION_NAME;
use global_utils::{handle_application_args, HandleLocalStatus};
use gtk::glib::{OptionArg, OptionFlags};
use gtk::{gio::ApplicationFlags, Application};
use gtk::{glib, prelude::*};
use gtk4::glib::{OptionArg, OptionFlags};
use gtk4::{gio::ApplicationFlags, Application};
use gtk4::{glib, prelude::*};
use std::env::args_os;
use std::path::PathBuf;
use zbus::{blocking::Connection, proxy};
Expand Down
2 changes: 1 addition & 1 deletion src/config/backend.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use gtk::glib::system_config_dirs;
use gtk4::glib::system_config_dirs;
use serde_derive::Deserialize;
use std::error::Error;
use std::path::PathBuf;
Expand Down
4 changes: 2 additions & 2 deletions src/config/user.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use gtk::glib::system_config_dirs;
use gtk::glib::user_config_dir;
use gtk4::glib::system_config_dirs;
use gtk4::glib::user_config_dir;
use serde_derive::Deserialize;
use std::error::Error;
use std::path::Path;
Expand Down
2 changes: 1 addition & 1 deletion src/global_utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use gtk::glib::{variant::DictEntry, Variant};
use gtk4::glib::{variant::DictEntry, Variant};

use crate::argtypes::ArgTypes;

Expand Down
272 changes: 164 additions & 108 deletions src/server/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ use crate::osd_window::SwayosdWindow;
use crate::utils::{self, *};
use async_channel::Receiver;
use glib::{ControlFlow::Break, ControlFlow::Continue, MainContext};
use gtk::gio::SignalSubscriptionId;
use gtk::gio::{ApplicationFlags, BusNameWatcherFlags, BusType};
use gtk::glib::{clone, OptionArg, OptionFlags};
use gtk::prelude::*;
use gtk::*;
use gtk4::gio::prelude::*;
use gtk4::gio::SignalSubscriptionId;
use gtk4::gio::{ApplicationFlags, BusNameWatcherFlags, BusType};
use gtk4::glib::{clone, variant::ToVariant, OptionArg, OptionFlags};
use gtk4::prelude::*;
use gtk4::*;
use pulsectl::controllers::{SinkController, SourceController};
use std::cell::RefCell;
use std::rc::Rc;
Expand All @@ -20,7 +21,7 @@ use super::config::user::ServerConfig;
#[derive(Clone, Shrinkwrap)]
pub struct SwayOSDApplication {
#[shrinkwrap(main_field)]
app: gtk::Application,
app: gtk4::Application,
windows: Rc<RefCell<Vec<SwayosdWindow>>>,
}

Expand Down Expand Up @@ -77,111 +78,143 @@ impl SwayOSDApplication {
}

// Parse args
app.connect_handle_local_options(clone!(@strong osd_app => move |_app, args| {
let actions = match handle_application_args(args.to_variant()) {
(HandleLocalStatus::SUCCESS | HandleLocalStatus::CONTINUE, actions) => actions,
(status @ HandleLocalStatus::FAILURE, _) => return status as i32,
};
for (arg_type, data) in actions {
match (arg_type, data) {
(ArgTypes::TopMargin, margin) => {
let margin: Option<f32> = margin
.and_then(|margin| margin.parse().ok())
.and_then(|margin| (0_f32..1_f32).contains(&margin).then_some(margin));
app.connect_handle_local_options(clone!(
#[strong]
osd_app,
move |_app, args| {
let actions = match handle_application_args(args.to_variant()) {
(HandleLocalStatus::SUCCESS | HandleLocalStatus::CONTINUE, actions) => actions,
(status @ HandleLocalStatus::FAILURE, _) => return status as i32,
};
for (arg_type, data) in actions {
match (arg_type, data) {
(ArgTypes::TopMargin, margin) => {
let margin: Option<f32> = margin
.and_then(|margin| margin.parse().ok())
.and_then(|margin| {
(0_f32..1_f32).contains(&margin).then_some(margin)
});

if let Some(margin) = margin {
set_top_margin(margin)
if let Some(margin) = margin {
set_top_margin(margin)
}
}
},
(ArgTypes::MaxVolume, max) => {
let max: Option<u8> = max
.and_then(|max| max.parse().ok());
(ArgTypes::MaxVolume, max) => {
let max: Option<u8> = max.and_then(|max| max.parse().ok());

if let Some(max) = max {
set_default_max_volume(max);
if let Some(max) = max {
set_default_max_volume(max);
}
}
},
(arg_type, data) => Self::action_activated(&osd_app, arg_type, data),
(arg_type, data) => Self::action_activated(&osd_app, arg_type, data),
}
}
}

HandleLocalStatus::CONTINUE as i32
}));
HandleLocalStatus::CONTINUE as i32
}
));

// Listen to any Client actions
MainContext::default().spawn_local(clone!(@strong osd_app => async move {
while let Ok((arg_type, data)) = action_receiver.recv().await {
Self::action_activated(&osd_app, arg_type, (!data.is_empty()).then_some(data));
MainContext::default().spawn_local(clone!(
#[strong]
osd_app,
async move {
while let Ok((arg_type, data)) = action_receiver.recv().await {
Self::action_activated(&osd_app, arg_type, (!data.is_empty()).then_some(data));
}
Break
}
Break
}));
));

// Listen to the LibInput Backend and activate the Application action
let (sender, receiver) = async_channel::bounded::<(u16, i32)>(1);
MainContext::default().spawn_local(clone!(@strong osd_app => async move {
while let Ok((key_code, state)) = receiver.recv().await {
let (arg_type, data): (ArgTypes, Option<String>) =
match evdev_rs::enums::int_to_ev_key(key_code as u32) {
Some(evdev_rs::enums::EV_KEY::KEY_CAPSLOCK) => {
(ArgTypes::CapsLock, Some(state.to_string()))
}
Some(evdev_rs::enums::EV_KEY::KEY_NUMLOCK) => {
(ArgTypes::NumLock, Some(state.to_string()))
}
Some(evdev_rs::enums::EV_KEY::KEY_SCROLLLOCK) => {
(ArgTypes::ScrollLock, Some(state.to_string()))
}
_ => return Continue,
};
Self::action_activated(&osd_app, arg_type, data);
MainContext::default().spawn_local(clone!(
#[strong]
osd_app,
async move {
while let Ok((key_code, state)) = receiver.recv().await {
let (arg_type, data): (ArgTypes, Option<String>) =
match evdev_rs::enums::int_to_ev_key(key_code as u32) {
Some(evdev_rs::enums::EV_KEY::KEY_CAPSLOCK) => {
(ArgTypes::CapsLock, Some(state.to_string()))
}
Some(evdev_rs::enums::EV_KEY::KEY_NUMLOCK) => {
(ArgTypes::NumLock, Some(state.to_string()))
}
Some(evdev_rs::enums::EV_KEY::KEY_SCROLLLOCK) => {
(ArgTypes::ScrollLock, Some(state.to_string()))
}
_ => return Continue,
};
Self::action_activated(&osd_app, arg_type, data);
}
Break
}
Break
}));
));
// Start watching for the LibInput Backend
let signal_id: Arc<Mutex<Option<SignalSubscriptionId>>> = Arc::new(Mutex::new(None));
gio::bus_watch_name(
BusType::System,
DBUS_BACKEND_NAME,
BusNameWatcherFlags::NONE,
clone!(@strong sender, @strong signal_id => move |connection, _, _| {
println!("Connecting to the SwayOSD LibInput Backend");
let mut mutex = match signal_id.lock() {
Ok(mut mutex) => match mutex.as_mut() {
Some(_) => return,
None => mutex,
},
Err(error) => return println!("Mutex lock Error: {}", error),
};
mutex.replace(connection.signal_subscribe(
Some(config::DBUS_BACKEND_NAME),
Some(config::DBUS_BACKEND_NAME),
Some("KeyPressed"),
Some(config::DBUS_PATH),
None,
gio::DBusSignalFlags::NONE,
clone!(@strong sender => move |_, _, _, _, _, variant| {
let key_code = variant.try_child_get::<u16>(0);
let state = variant.try_child_get::<i32>(1);
match (key_code, state) {
(Ok(Some(key_code)), Ok(Some(state))) => {
if let Err(error) = sender.send_blocking((key_code, state)) {
eprintln!("Channel Send error: {}", error);
}
},
variables => return eprintln!("Variables don't match: {:?}", variables),
};
}),
));
}),
clone!(@strong signal_id => move|connection, _| {
eprintln!("SwayOSD LibInput Backend isn't available, waiting...");
match signal_id.lock() {
Ok(mut mutex) => if let Some(sig_id) = mutex.take() {
connection.signal_unsubscribe(sig_id);
},
Err(error) => println!("Mutex lock Error: {}", error),
clone!(
#[strong]
sender,
#[strong]
signal_id,
move |connection, _, _| {
println!("Connecting to the SwayOSD LibInput Backend");
let mut mutex = match signal_id.lock() {
Ok(mut mutex) => match mutex.as_mut() {
Some(_) => return,
None => mutex,
},
Err(error) => return println!("Mutex lock Error: {}", error),
};
mutex.replace(connection.signal_subscribe(
Some(config::DBUS_BACKEND_NAME),
Some(config::DBUS_BACKEND_NAME),
Some("KeyPressed"),
Some(config::DBUS_PATH),
None,
gio::DBusSignalFlags::NONE,
clone!(
#[strong]
sender,
move |_, _, _, _, _, variant| {
let key_code = variant.try_child_get::<u16>(0);
let state = variant.try_child_get::<i32>(1);
match (key_code, state) {
(Ok(Some(key_code)), Ok(Some(state))) => {
if let Err(error) = sender.send_blocking((key_code, state))
{
eprintln!("Channel Send error: {}", error);
}
}
variables => {
return eprintln!("Variables don't match: {:?}", variables)
}
};
}
),
));
}
),
clone!(
#[strong]
signal_id,
move |connection, _| {
eprintln!("SwayOSD LibInput Backend isn't available, waiting...");
match signal_id.lock() {
Ok(mut mutex) => {
if let Some(sig_id) = mutex.take() {
connection.signal_unsubscribe(sig_id);
}
}
Err(error) => println!("Mutex lock Error: {}", error),
}
}
}),
),
);

return osd_app;
Expand Down Expand Up @@ -372,24 +405,43 @@ impl SwayOSDApplication {

let _self = self;

display.connect_opened(clone!(@strong _self => move |d| {
_self.init_windows(d);
}));

display.connect_closed(clone!(@strong _self => move |_d, is_error| {
if is_error {
eprintln!("Display closed due to errors...");
display.connect_opened(clone!(
#[strong]
_self,
move |d| {
_self.init_windows(d);
}
_self.close_all_windows();
}));
));

display.connect_monitor_added(clone!(@strong _self => move |d, mon| {
_self.add_window(d, mon);
}));
display.connect_closed(clone!(
#[strong]
_self,
move |_d, is_error| {
if is_error {
eprintln!("Display closed due to errors...");
}
_self.close_all_windows();
}
));

display.connect_monitor_removed(clone!(@strong _self => move |d, _mon| {
_self.init_windows(d);
}));
display.monitors().connect_items_changed(clone!(
#[strong]
_self,
move |monitors, position, removed, added| {
if removed != 0 {
_self.init_windows(&display);
} else if added != 0 {
for i in 0..added {
if let Some(mon) = monitors
.item(position + i)
.and_then(|obj| obj.downcast::<gdk::Monitor>().ok())
{
_self.add_window(&display, &mon);
}
}
}
}
));
}

fn add_window(&self, display: &gdk::Display, monitor: &gdk::Monitor) {
Expand All @@ -400,8 +452,12 @@ impl SwayOSDApplication {
fn init_windows(&self, display: &gdk::Display) {
self.close_all_windows();

for i in 0..display.n_monitors() {
let monitor: gdk::Monitor = match display.monitor(i) {
let monitors = display.monitors();
for i in 0..monitors.n_items() {
let monitor = match monitors
.item(i)
.and_then(|obj| obj.downcast::<gdk::Monitor>().ok())
{
Some(x) => x,
_ => continue,
};
Expand Down
Loading

0 comments on commit 7628440

Please sign in to comment.