merge master_jammy and udpate to use latest cosmic panel config

This commit is contained in:
Ashley Wulber 2022-07-06 12:41:49 -04:00
commit 488fe6f186
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
32 changed files with 616 additions and 1057 deletions

View file

@ -5,7 +5,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"}
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"] }
cascade = "1.0.0"
gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_4"] }
gio = { git = "https://github.com/gtk-rs/gtk-rs-core" }

View file

@ -76,90 +76,93 @@ fn app(application: &Application) {
});
pa.connect().unwrap(); // XXX unwrap
view! {
window = libcosmic_applet::Applet {
window = libcosmic_applet::AppletWindow {
set_application: Some(application),
set_title: Some("COSMIC Network Applet"),
// TODO: adjust based on volume, mute
set_button_icon_name: "multimedia-volume-control-symbolic",
#[wrap(Some)]
set_popover_child: window_box = &GtkBox {
set_orientation: Orientation::Vertical,
set_spacing: 24,
append: output_box = &GtkBox {
set_orientation: Orientation::Horizontal,
set_spacing: 16,
append: output_icon = &Image {
set_icon_name: Some("audio-speakers-symbolic"),
},
append: output_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) {
set_format_value_func: |_, value| {
format!("{:.0}%", value)
},
set_value_pos: PositionType::Right,
set_hexpand: true
}
},
append: input_box = &GtkBox {
set_orientation: Orientation::Horizontal,
set_spacing: 16,
append: input_icon = &Image {
set_icon_name: Some("audio-input-microphone-symbolic"),
},
append: input_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) {
set_format_value_func: |_, value| {
format!("{:.0}%", value)
},
set_value_pos: PositionType::Right,
set_hexpand: true
}
},
append: _sep = &Separator {
set_orientation: Orientation::Horizontal,
},
append: output_list_box = &GtkBox {
set_child = &libcosmic_applet::AppletButton {
// TODO: adjust based on volume, mute
set_button_icon_name: "multimedia-volume-control-symbolic",
#[wrap(Some)]
set_popover_child: window_box = &GtkBox {
set_orientation: Orientation::Vertical,
append: current_output_button = &Button {
#[wrap(Some)]
set_child: current_output = &Label {},
connect_clicked[outputs_revealer] => move |_| {
outputs_revealer.set_reveal_child(!outputs_revealer.reveals_child());
set_spacing: 24,
append: output_box = &GtkBox {
set_orientation: Orientation::Horizontal,
set_spacing: 16,
append: output_icon = &Image {
set_icon_name: Some("audio-speakers-symbolic"),
},
append: output_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) {
set_format_value_func: |_, value| {
format!("{:.0}%", value)
},
set_value_pos: PositionType::Right,
set_hexpand: true
}
},
append: outputs_revealer = &Revealer {
set_transition_type: RevealerTransitionType::SlideDown,
#[wrap(Some)]
set_child: outputs = &ListBox {
set_selection_mode: SelectionMode::None,
set_activate_on_single_click: true
}
}
},
append: _sep = &Separator {
set_orientation: Orientation::Horizontal,
},
append: input_list_box = &GtkBox {
set_orientation: Orientation::Vertical,
append: current_input_button = &Button {
#[wrap(Some)]
set_child: current_input = &Label {},
connect_clicked[inputs_revealer] => move |_| {
inputs_revealer.set_reveal_child(!inputs_revealer.reveals_child());
append: input_box = &GtkBox {
set_orientation: Orientation::Horizontal,
set_spacing: 16,
append: input_icon = &Image {
set_icon_name: Some("audio-input-microphone-symbolic"),
},
append: input_volume = &Scale::with_range(Orientation::Horizontal, 0., 100., 1.) {
set_format_value_func: |_, value| {
format!("{:.0}%", value)
},
set_value_pos: PositionType::Right,
set_hexpand: true
}
},
append: inputs_revealer = &Revealer {
set_transition_type: RevealerTransitionType::SlideDown,
#[wrap(Some)]
set_child: inputs = &ListBox {
set_selection_mode: SelectionMode::None,
set_activate_on_single_click: true
append: _sep = &Separator {
set_orientation: Orientation::Horizontal,
},
append: output_list_box = &GtkBox {
set_orientation: Orientation::Vertical,
append: current_output_button = &Button {
#[wrap(Some)]
set_child: current_output = &Label {},
connect_clicked[outputs_revealer] => move |_| {
outputs_revealer.set_reveal_child(!outputs_revealer.reveals_child());
}
},
append: outputs_revealer = &Revealer {
set_transition_type: RevealerTransitionType::SlideDown,
#[wrap(Some)]
set_child: outputs = &ListBox {
set_selection_mode: SelectionMode::None,
set_activate_on_single_click: true
}
}
},
append: _sep = &Separator {
set_orientation: Orientation::Horizontal,
},
append: input_list_box = &GtkBox {
set_orientation: Orientation::Vertical,
append: current_input_button = &Button {
#[wrap(Some)]
set_child: current_input = &Label {},
connect_clicked[inputs_revealer] => move |_| {
inputs_revealer.set_reveal_child(!inputs_revealer.reveals_child());
}
},
append: inputs_revealer = &Revealer {
set_transition_type: RevealerTransitionType::SlideDown,
#[wrap(Some)]
set_child: inputs = &ListBox {
set_selection_mode: SelectionMode::None,
set_activate_on_single_click: true
}
}
},
append: _sep = &Separator {
set_orientation: Orientation::Horizontal,
},
append: playing_apps = &ListBox {
set_selection_mode: SelectionMode::None,
}
},
append: _sep = &Separator {
set_orientation: Orientation::Horizontal,
},
append: playing_apps = &ListBox {
set_selection_mode: SelectionMode::None,
}
}
}

View file

@ -57,6 +57,7 @@ struct AppModel {
kbd_backlight: Option<KbdBacklightProxy<'static>>,
}
#[derive(Debug)]
enum AppMsg {
SetDisplayBrightness(f64),
SetKeyboardBrightness(f64),
@ -77,115 +78,118 @@ impl SimpleComponent for AppModel {
type Output = ();
view! {
libcosmic_applet::Applet {
#[watch]
set_button_icon_name: &model.icon_name,
libcosmic_applet::AppletWindow {
#[wrap(Some)]
set_popover_child = &gtk4::Box {
set_orientation: gtk4::Orientation::Vertical,
set_child = &libcosmic_applet::AppletButton {
#[watch]
set_button_icon_name: &model.icon_name,
#[wrap(Some)]
set_popover_child = &gtk4::Box {
set_orientation: gtk4::Orientation::Vertical,
// Battery
gtk4::Box {
set_orientation: gtk4::Orientation::Horizontal,
gtk4::Image {
#[watch]
set_icon_name: Some(&model.icon_name),
},
// Battery
gtk4::Box {
set_orientation: gtk4::Orientation::Vertical,
gtk4::Label {
set_halign: gtk4::Align::Start,
set_label: "Battery",
},
gtk4::Label {
set_halign: gtk4::Align::Start,
// XXX time to full, fully changed, etc.
set_orientation: gtk4::Orientation::Horizontal,
gtk4::Image {
#[watch]
set_label: &format!("{} until empty ({:.0}%)", format_duration(model.time_remaining), model.battery_percent),
set_icon_name: Some(&model.icon_name),
},
gtk4::Box {
set_orientation: gtk4::Orientation::Vertical,
gtk4::Label {
set_halign: gtk4::Align::Start,
set_label: "Battery",
},
gtk4::Label {
set_halign: gtk4::Align::Start,
// XXX time to full, fully changed, etc.
#[watch]
set_label: &format!("{} until empty ({:.0}%)", format_duration(model.time_remaining), model.battery_percent),
},
},
},
},
gtk4::Separator {
},
gtk4::Separator {
},
// Limit charging
gtk4::Box {
set_orientation: gtk4::Orientation::Horizontal,
// Limit charging
gtk4::Box {
set_orientation: gtk4::Orientation::Vertical,
gtk4::Label {
set_halign: gtk4::Align::Start,
set_label: "Limit Battery Charging",
set_orientation: gtk4::Orientation::Horizontal,
gtk4::Box {
set_orientation: gtk4::Orientation::Vertical,
gtk4::Label {
set_halign: gtk4::Align::Start,
set_label: "Limit Battery Charging",
},
gtk4::Label {
set_halign: gtk4::Align::Start,
set_label: "Increase the lifespan of your battery by setting a maximum charge value of 80%."
},
},
gtk4::Switch {
set_valign: gtk4::Align::Center,
},
},
gtk4::Separator {
},
// Brightness
gtk4::Box {
#[watch]
set_visible: model.backlight.is_some(),
set_orientation: gtk4::Orientation::Horizontal,
gtk4::Image {
set_icon_name: Some("display-brightness-symbolic"),
},
gtk4::Scale {
set_hexpand: true,
set_adjustment: &gtk4::Adjustment::new(0., 0., 1., 1., 1., 0.),
#[watch]
set_value: model.display_brightness,
connect_change_value[sender] => move |_, _, value| {
sender.input(AppMsg::SetDisplayBrightness(value));
gtk4::Inhibit(false)
},
},
gtk4::Label {
set_halign: gtk4::Align::Start,
set_label: "Increase the lifespan of your battery by setting a maximum charge value of 80%."
#[watch]
set_label: &format!("{:.0}%", model.display_brightness * 100.),
},
},
gtk4::Switch {
set_valign: gtk4::Align::Center,
},
},
gtk4::Separator {
},
// Brightness
gtk4::Box {
#[watch]
set_visible: model.backlight.is_some(),
set_orientation: gtk4::Orientation::Horizontal,
gtk4::Image {
set_icon_name: Some("display-brightness-symbolic"),
},
gtk4::Scale {
set_hexpand: true,
set_adjustment: &gtk4::Adjustment::new(0., 0., 1., 1., 1., 0.),
gtk4::Box {
#[watch]
set_value: model.display_brightness,
connect_change_value[sender] => move |_, _, value| {
sender.input(AppMsg::SetDisplayBrightness(value));
gtk4::Inhibit(false)
set_visible: model.kbd_backlight.is_some(),
set_orientation: gtk4::Orientation::Horizontal,
gtk4::Image {
set_icon_name: Some("keyboard-brightness-symbolic"),
},
gtk4::Scale {
set_hexpand: true,
set_adjustment: &gtk4::Adjustment::new(0., 0., 1., 1., 1., 0.),
#[watch]
set_value: model.keyboard_brightness,
connect_change_value[sender] => move |_, _, value| {
sender.input(AppMsg::SetKeyboardBrightness(value));
gtk4::Inhibit(false)
},
},
gtk4::Label {
#[watch]
set_label: &format!("{:.0}%", model.keyboard_brightness * 100.),
},
},
gtk4::Label {
#[watch]
set_label: &format!("{:.0}%", model.display_brightness * 100.),
},
},
gtk4::Box {
#[watch]
set_visible: model.kbd_backlight.is_some(),
set_orientation: gtk4::Orientation::Horizontal,
gtk4::Image {
set_icon_name: Some("keyboard-brightness-symbolic"),
},
gtk4::Scale {
set_hexpand: true,
set_adjustment: &gtk4::Adjustment::new(0., 0., 1., 1., 1., 0.),
#[watch]
set_value: model.keyboard_brightness,
connect_change_value[sender] => move |_, _, value| {
sender.input(AppMsg::SetKeyboardBrightness(value));
gtk4::Inhibit(false)
},
},
gtk4::Label {
#[watch]
set_label: &format!("{:.0}%", model.keyboard_brightness * 100.),
},
},
gtk4::Separator {
},
gtk4::Separator {
},
gtk4::Button {
set_label: "Power Settings...",
connect_clicked => move |_| {
// XXX open subpanel
let _ = Command::new("cosmic-settings").spawn();
// TODO hide
gtk4::Button {
set_label: "Power Settings...",
connect_clicked => move |_| {
// XXX open subpanel
let _ = Command::new("cosmic-settings").spawn();
// TODO hide
}
}
}
}

View file

@ -7,8 +7,8 @@ edition = "2021"
[dependencies]
gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_2"] }
libcosmic-applet = { path = "../../libcosmic-applet" }
once_cell = "1.9.0"
relm4-macros = { git = "https://github.com/Relm4/Relm4.git", branch = "next" }
tokio = { version = "1.16.1", features = ["full"] }
zbus = "2.1.1"
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"}

View file

@ -11,28 +11,15 @@ pub mod mode_box;
use self::{dbus::PowerDaemonProxy, graphics::Graphics, mode_box::ModeSelection};
use gtk4::{
gdk::Display,
gio::ApplicationFlags,
glib::{self, clone, MainContext, PRIORITY_DEFAULT},
prelude::*,
Align, CssProvider, Label, ListBox, ListBoxRow, Orientation, Overlay, Separator, Spinner,
StyleContext, STYLE_PROVIDER_PRIORITY_APPLICATION,
Align, Label, ListBox, ListBoxRow, Orientation, Overlay, Separator, Spinner,
};
use once_cell::sync::Lazy;
use tokio::runtime::Runtime;
use cosmic_panel_config::CosmicPanelConfig;
static RT: Lazy<Runtime> = Lazy::new(|| Runtime::new().expect("failed to build tokio runtime"));
fn main() {
let application = gtk4::Application::new(
Some("com.system76.cosmic.applets.graphics"),
ApplicationFlags::default(),
);
application.connect_activate(build_ui);
application.run();
}
async fn get_current_graphics() -> zbus::Result<Graphics> {
let connection = zbus::Connection::system().await?;
let proxy = PowerDaemonProxy::new(&connection).await?;
@ -53,7 +40,9 @@ fn row_clicked(_: &ListBox, row: &ListBoxRow) {
selector.emit_activate();
}
fn build_ui(application: &gtk4::Application) {
fn main() {
gtk4::init().unwrap();
let provider = gtk4::CssProvider::new();
provider.load_from_data(include_bytes!("style.css"));
gtk4::StyleContext::add_provider_for_display(
@ -62,141 +51,119 @@ fn build_ui(application: &gtk4::Application) {
gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
let window = gtk4::ApplicationWindow::builder()
.application(application)
.title("COSMIC Graphics Applet")
.decorated(false)
.resizable(false)
.width_request(1)
.height_request(1)
.css_classes(vec!["root_window".to_string()])
.build();
let config = CosmicPanelConfig::load_from_env().unwrap_or_default();
let popover = gtk4::builders::PopoverBuilder::new()
.autohide(true)
.has_arrow(false)
.build();
let button = gtk4::Button::new();
button.add_css_class("panel_icon");
button.connect_clicked(glib::clone!(@weak popover => move |_| {
popover.show();
}));
// TODO cleanup
let image = gtk4::Image::from_icon_name("input-gaming");
image.add_css_class("panel_icon");
image.set_pixel_size(config.get_applet_icon_size().try_into().unwrap());
button.set_child(Some(&image));
let current_graphics = RT
let current_graphics = RT
.block_on(get_current_graphics())
.expect("failed to connect to system76-power");
view! {
icon_box = gtk4::Box {
set_orientation: Orientation::Vertical,
set_spacing: 0,
add_css_class: "icon_box",
}
}
let (tx, rx) = MainContext::channel::<bool>(PRIORITY_DEFAULT);
view! {
main_overlay = Overlay {
add_overlay: loading_box = &gtk4::Box {
append: loading_explain_box = &gtk4::Box {
set_orientation: Orientation::Vertical,
set_halign: Align::Center,
set_valign: Align::Center,
append: loading_spinner = &Spinner {
set_halign: Align::Center,
},
append: loading_explain = &Label {
set_label: "Please wait while your graphics mode is set...",
set_halign: Align::Center,
},
},
set_halign: Align::Center,
set_valign: Align::Center,
set_hexpand: true,
set_vexpand: true,
set_visible: false,
add_css_class: "loading-overlay",
},
window = libcosmic_applet::AppletWindow {
set_title: Some("COSMIC Graphics Applet"),
#[wrap(Some)]
set_child: main_box = &gtk4::Box {
set_orientation: Orientation::Vertical,
set_spacing: 10,
set_margin_top: 20,
set_margin_bottom: 20,
set_margin_start: 24,
set_margin_end: 24,
append: mode_label = &Label {
set_text: "Graphics Mode"
},
append: separator = &Separator {
set_orientation: Orientation::Horizontal
},
append: graphics_modes_list = &ListBox {
connect_row_activated: row_clicked,
append: integrated_selector = &ModeSelection {
set_title: "Integrated Graphics",
set_description: "Disables external displays. Requires Restart.",
set_active: (current_graphics == Graphics::Integrated),
connect_toggled: clone!(@strong tx => move |_| {
tx.send(true).expect("failed to send to main context");
let tx = tx.clone();
RT.spawn(async move {
set_graphics(Graphics::Integrated).await.expect("failed to set graphics mode");
tx.send(false).expect("failed to send to main context");
});
})
},
append: nvidia_selector = &ModeSelection {
set_title: "NVIDIA Graphics",
set_group: Some(&integrated_selector),
set_active: (current_graphics == Graphics::Nvidia),
connect_toggled: clone!(@strong tx => move |_| {
tx.send(true).expect("failed to send to main context");
let tx = tx.clone();
RT.spawn(async move {
set_graphics(Graphics::Nvidia).await.expect("failed to set graphics mode");
tx.send(false).expect("failed to send to main context");
});
})
},
append: hybrid_selector = &ModeSelection {
set_title: "Hybrid Graphics",
set_description: "Requires Restart.",
set_group: Some(&integrated_selector),
set_active: (current_graphics == Graphics::Hybrid),
connect_toggled: clone!(@strong tx => move |_| {
tx.send(true).expect("failed to send to main context");
let tx = tx.clone();
RT.spawn(async move {
set_graphics(Graphics::Hybrid).await.expect("failed to set graphics mode");
tx.send(false).expect("failed to send to main context");
});
})
},
append: compute_selector = &ModeSelection {
set_title: "Compute Graphics",
set_description: "Disables external displays. Requires Restart.",
set_group: Some(&integrated_selector),
set_active: (current_graphics == Graphics::Compute),
connect_toggled: clone!(@strong tx => move |_| {
tx.send(true).expect("failed to send to main context");
let tx = tx.clone();
RT.spawn(async move {
set_graphics(Graphics::Compute).await.expect("failed to set graphics mode");
tx.send(false).expect("failed to send to main context");
});
})
set_child = &libcosmic_applet::AppletButton {
set_button_icon_name: "input-gaming",
#[wrap(Some)]
set_popover_child: main_overlay = &Overlay {
add_overlay: loading_box = &gtk4::Box {
append: loading_explain_box = &gtk4::Box {
set_orientation: Orientation::Vertical,
set_halign: Align::Center,
set_valign: Align::Center,
append: loading_spinner = &Spinner {
set_halign: Align::Center,
},
append: loading_explain = &Label {
set_label: "Please wait while your graphics mode is set...",
set_halign: Align::Center,
},
},
set_halign: Align::Center,
set_valign: Align::Center,
set_hexpand: true,
set_vexpand: true,
set_visible: false,
add_css_class: "loading-overlay",
},
#[wrap(Some)]
set_child: main_box = &gtk4::Box {
set_orientation: Orientation::Vertical,
set_spacing: 10,
set_margin_top: 20,
set_margin_bottom: 20,
set_margin_start: 24,
set_margin_end: 24,
append: mode_label = &Label {
set_text: "Graphics Mode"
},
append: separator = &Separator {
set_orientation: Orientation::Horizontal
},
append: graphics_modes_list = &ListBox {
connect_row_activated: row_clicked,
append: integrated_selector = &ModeSelection {
set_title: "Integrated Graphics",
set_description: "Disables external displays. Requires Restart.",
set_active: (current_graphics == Graphics::Integrated),
connect_toggled: clone!(@strong tx => move |_| {
tx.send(true).expect("failed to send to main context");
let tx = tx.clone();
RT.spawn(async move {
set_graphics(Graphics::Integrated).await.expect("failed to set graphics mode");
tx.send(false).expect("failed to send to main context");
});
})
},
append: nvidia_selector = &ModeSelection {
set_title: "NVIDIA Graphics",
set_group: Some(&integrated_selector),
set_active: (current_graphics == Graphics::Nvidia),
connect_toggled: clone!(@strong tx => move |_| {
tx.send(true).expect("failed to send to main context");
let tx = tx.clone();
RT.spawn(async move {
set_graphics(Graphics::Nvidia).await.expect("failed to set graphics mode");
tx.send(false).expect("failed to send to main context");
});
})
},
append: hybrid_selector = &ModeSelection {
set_title: "Hybrid Graphics",
set_description: "Requires Restart.",
set_group: Some(&integrated_selector),
set_active: (current_graphics == Graphics::Hybrid),
connect_toggled: clone!(@strong tx => move |_| {
tx.send(true).expect("failed to send to main context");
let tx = tx.clone();
RT.spawn(async move {
set_graphics(Graphics::Hybrid).await.expect("failed to set graphics mode");
tx.send(false).expect("failed to send to main context");
});
})
},
append: compute_selector = &ModeSelection {
set_title: "Compute Graphics",
set_description: "Disables external displays. Requires Restart.",
set_group: Some(&integrated_selector),
set_active: (current_graphics == Graphics::Compute),
connect_toggled: clone!(@strong tx => move |_| {
tx.send(true).expect("failed to send to main context");
let tx = tx.clone();
RT.spawn(async move {
set_graphics(Graphics::Compute).await.expect("failed to set graphics mode");
tx.send(false).expect("failed to send to main context");
});
})
},
}
}
}
}
}
}
rx.attach(
None,
clone!(@weak loading_box, @weak loading_spinner => @default-return Continue(true), move |val| {
@ -205,11 +172,9 @@ fn build_ui(application: &gtk4::Application) {
Continue(true)
}),
);
popover.set_child(Some(&main_overlay));
icon_box.append(&button);
icon_box.append(&popover);
window.set_child(Some(&icon_box));
window.show();
let main_loop = glib::MainLoop::new(None, false);
main_loop.run();
}

View file

@ -2,32 +2,3 @@
background-color: #2f2f2f;
opacity: 0.85;
}
image.panel_icon {
padding-left: 0px;
padding-right: 0px;
padding-top: 0px;
padding-bottom: 0px;
}
button.panel_icon {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: transparent;
background: transparent;
outline-color: transparent;
}
button.panel_icon:hover {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: rgba(255, 255, 255, 0.1);
outline-color: rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.1);
}
window.root_window {
background: transparent;
}

View file

@ -14,5 +14,5 @@ relm4-macros = { git = "https://github.com/Relm4/Relm4.git", branch = "next" }
slotmap = "1.0.6"
tokio = { version = "1.15.0", features = ["full"] }
zbus = "2.0.1"
libcosmic-applet = { path = "../../libcosmic-applet" }
libcosmic-widgets = { git = "https://github.com/pop-os/libcosmic", branch = "relm4-next" }
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"}

View file

@ -7,90 +7,43 @@ pub mod task;
pub mod ui;
pub mod widgets;
use cosmic_panel_config::CosmicPanelConfig;
use gtk4::{gio::ApplicationFlags, glib, prelude::*, Orientation, Separator};
use gtk4::{glib, prelude::*, Orientation, Separator};
use once_cell::sync::Lazy;
use tokio::runtime::Runtime;
static RT: Lazy<Runtime> = Lazy::new(|| Runtime::new().expect("failed to build tokio runtime"));
fn main() {
let application = gtk4::Application::new(
Some("com.system76.cosmic.applets.network"),
ApplicationFlags::default(),
);
application.connect_activate(build_ui);
application.run();
}
fn build_ui(application: &gtk4::Application) {
let provider = gtk4::CssProvider::new();
provider.load_from_data(include_bytes!("style.css"));
gtk4::StyleContext::add_provider_for_display(
&gtk4::gdk::Display::default().expect("Could not connect to a display."),
&provider,
gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
let window = gtk4::ApplicationWindow::builder()
.application(application)
.title("COSMIC Network Applet")
.decorated(false)
.resizable(false)
.width_request(1)
.height_request(1)
.css_classes(vec!["root_window".to_string()])
.build();
gtk4::init().unwrap();
view! {
main_box = gtk4::Box {
set_orientation: Orientation::Vertical,
set_spacing: 10,
set_margin_top: 20,
set_margin_bottom: 20,
set_margin_start: 24,
set_margin_end: 24
window = libcosmic_applet::AppletWindow {
set_title: Some("COSMIC Network Applet"),
#[wrap(Some)]
set_child: button = &libcosmic_applet::AppletButton {
set_button_icon_name: "preferences-system-network",
#[wrap(Some)]
set_popover_child: main_box = &gtk4::Box {
set_orientation: Orientation::Vertical,
set_spacing: 10,
set_margin_top: 20,
set_margin_bottom: 20,
set_margin_start: 24,
set_margin_end: 24
}
}
}
}
let config = CosmicPanelConfig::load_from_env().unwrap_or_default();
let popover = gtk4::builders::PopoverBuilder::new()
.autohide(true)
.has_arrow(false)
.build();
let button = gtk4::Button::new();
button.add_css_class("panel_icon");
button.connect_clicked(glib::clone!(@weak popover => move |_| {
popover.show();
}));
// TODO cleanup
let image = gtk4::Image::from_icon_name("preferences-system-network");
image.add_css_class("panel_icon");
image.set_pixel_size(config.get_applet_icon_size().try_into().unwrap());
button.set_child(Some(&image));
view! {
icon_box = gtk4::Box {
set_orientation: Orientation::Vertical,
set_spacing: 0,
add_css_class: "icon_box",
}
}
popover.set_child(Some(&main_box));
icon_box.append(&button);
icon_box.append(&popover);
ui::current_networks::add_current_networks(&main_box, &image);
ui::current_networks::add_current_networks(&main_box, &button);
main_box.append(&Separator::new(Orientation::Horizontal));
ui::toggles::add_toggles(&main_box);
let available_wifi_separator = Separator::new(Orientation::Horizontal);
main_box.append(&available_wifi_separator);
available_wifi_separator.hide();
ui::available_wifi::add_available_wifi(&main_box, available_wifi_separator);
window.set_child(Some(&icon_box));
window.show();
let main_loop = glib::MainLoop::new(None, false);
main_loop.run();
}

View file

@ -1,28 +0,0 @@
image.panel_icon {
padding-left: 0px;
padding-right: 0px;
padding-top: 0px;
padding-bottom: 0px;
}
button.panel_icon {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: transparent;
background: transparent;
outline-color: transparent;
}
button.panel_icon:hover {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: rgba(255, 255, 255, 0.1);
outline-color: rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.1);
}
window.root_window {
background: transparent;
}

View file

@ -18,7 +18,7 @@ use gtk4::{
use std::{cell::RefCell, net::IpAddr, rc::Rc};
use zbus::Connection;
pub fn add_current_networks(target: &gtk4::Box, icon_image: &gtk4::Image) {
pub fn add_current_networks(target: &gtk4::Box, icon_image: &libcosmic_applet::AppletButton) {
let networks_list = ListBox::builder().show_separators(true).build();
let entries = Rc::<RefCell<Vec<ListBoxRow>>>::default();
let (tx, rx) = MainContext::channel::<Vec<ActiveConnectionInfo>>(PRIORITY_DEFAULT);
@ -38,7 +38,7 @@ fn display_active_connections(
connections: Vec<ActiveConnectionInfo>,
target: &ListBox,
entries: &mut Vec<ListBoxRow>,
icon_image: &gtk4::Image,
icon_image: &libcosmic_applet::AppletButton,
) {
for old_entry in entries.drain(..) {
target.remove(&old_entry);
@ -51,7 +51,7 @@ fn display_active_connections(
speed,
ip_addresses,
} => {
icon_image.set_icon_name(Some("network-wired-symbolic"));
icon_image.set_button_icon_name("network-wired-symbolic");
render_wired_connection(name, speed, ip_addresses)
}
ActiveConnectionInfo::WiFi {
@ -62,7 +62,7 @@ fn display_active_connections(
wpa_flags,
} => continue,
ActiveConnectionInfo::Vpn { name, ip_addresses } => {
icon_image.set_icon_name(Some("network-vpn-symbolic"));
icon_image.set_button_icon_name("network-vpn-symbolic");
render_vpn(name, ip_addresses)
}
};

View file

@ -10,8 +10,8 @@ futures = "0.3"
gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs" }
libcosmic-applet = { path = "../../libcosmic-applet" }
once_cell = "1.12"
relm4-macros = { git = "https://github.com/Relm4/Relm4.git", branch = "next" }
serde = "1"
zbus = "2.0.1"
zbus_names = "2"
zvariant = "3"
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"}

View file

@ -1,5 +1,5 @@
use cascade::cascade;
use gtk4::{glib, prelude::*};
use relm4_macros::view;
mod dbus_service;
mod deref_cell;
@ -19,18 +19,20 @@ fn main() {
let notification_list = NotificationList::new(&notifications);
let window = cascade! {
libcosmic_applet::Applet::new();
..set_button_icon_name("user-invisible-symbolic"); // TODO
..set_popover_child(Some(&notification_list));
..show();
};
view! {
window = libcosmic_applet::AppletWindow {
#[wrap(Some)]
set_child: applet_button = &libcosmic_applet::AppletButton {
set_button_icon_name: "user-invisible-symbolic", // TODO
set_popover_child: Some(&notification_list)
}
}
}
window.show();
// XXX show in correct place
cascade! {
NotificationPopover::new(&notifications);
..set_parent(&window.child().unwrap()); // XXX better way?
};
let notification_popover = NotificationPopover::new(&notifications);
notification_popover.set_parent(&applet_button);
let main_loop = glib::MainLoop::new(None, false);
main_loop.run();

View file

@ -24,34 +24,37 @@ fn main() {
fn build_ui(application: &gtk4::Application) {
view! {
window = libcosmic_applet::Applet {
window = libcosmic_applet::AppletWindow {
set_title: Some("COSMIC Power Applet"),
set_application: Some(application),
// TODO adjust battery icon based on charge
set_button_icon_name: "system-shutdown-symbolic",
#[wrap(Some)]
set_popover_child: main_box = &gtk4::Box {
set_orientation: Orientation::Vertical,
set_spacing: 10,
set_margin_top: 20,
set_margin_bottom: 20,
set_margin_start: 24,
set_margin_end: 24,
append: settings_button = &Button {
#[wrap(Some)]
set_child = &Label {
set_label: "Settings...",
set_halign: Align::Start,
set_hexpand: true
set_child = &libcosmic_applet::AppletButton {
set_button_icon_name: "system-shutdown-symbolic",
#[wrap(Some)]
set_popover_child: main_box = &gtk4::Box {
set_orientation: Orientation::Vertical,
set_spacing: 10,
set_margin_top: 20,
set_margin_bottom: 20,
set_margin_start: 24,
set_margin_end: 24,
append: settings_button = &Button {
#[wrap(Some)]
set_child = &Label {
set_label: "Settings...",
set_halign: Align::Start,
set_hexpand: true
},
connect_clicked => move |_| {
let _ = Command::new("cosmic-settings").spawn();
}
},
connect_clicked => move |_| {
let _ = Command::new("cosmic-settings").spawn();
}
},
append = &Separator {},
append: &ui::session::build(),
append: second_separator = &Separator {},
append: &ui::system::build(),
append = &Separator {},
append: &ui::session::build(),
append: second_separator = &Separator {},
append: &ui::system::build(),
}
}
}
}

View file

@ -8,9 +8,9 @@ license = "GPL-3.0-or-later"
cascade = "1"
futures = "0.3"
gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs" }
libcosmic-applet = { path = "../../libcosmic-applet" }
once_cell = "1.12"
serde = "1"
zbus = "2.0.1"
zbus_names = "2"
zvariant = "3"
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"}

View file

@ -1,3 +1,4 @@
use cascade::cascade;
use gtk4::{glib, prelude::*};
mod dbus_service;
@ -14,24 +15,12 @@ fn main() {
// XXX Implement DBus service somewhere other than applet?
glib::MainContext::default().spawn_local(status_notifier_watcher::start());
let provider = gtk4::CssProvider::new();
provider.load_from_data(include_bytes!("style.css"));
gtk4::StyleContext::add_provider_for_display(
&gtk4::gdk::Display::default().expect("Could not connect to a display."),
&provider,
gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
let status_area = StatusArea::new();
gtk4::Window::builder()
.decorated(false)
.child(&status_area)
.resizable(false)
.width_request(1)
.height_request(1)
.css_classes(vec!["root_window".to_string()])
.build()
.show();
cascade! {
libcosmic_applet::AppletWindow::new();
..set_child(Some(&status_area));
..show();
};
let main_loop = glib::MainLoop::new(None, false);
main_loop.run();

View file

@ -19,7 +19,7 @@ struct Menu {
#[derive(Default)]
pub struct StatusMenuInner {
menu_button: DerefCell<gtk4::MenuButton>,
menu_button: DerefCell<libcosmic_applet::AppletButton>,
vbox: DerefCell<gtk4::Box>,
item: DerefCell<StatusNotifierItemProxy<'static>>,
dbus_menu: DerefCell<DBusMenuProxy<'static>>,
@ -43,17 +43,10 @@ impl ObjectImpl for StatusMenuInner {
gtk4::Box::new(gtk4::Orientation::Vertical, 0);
};
let popover = cascade! {
gtk4::Popover::new();
..set_child(Some(&vbox));
};
let menu_button = cascade! {
gtk4::MenuButton::new();
..add_css_class("panel_icon");
..set_has_frame(false);
libcosmic_applet::AppletButton::new();
..set_parent(obj);
..set_popover(Some(&popover));
..set_popover_child(Some(&vbox));
};
self.menu_button.set(menu_button);
@ -88,7 +81,7 @@ impl StatusMenu {
.await?;
let obj = glib::Object::new::<Self>(&[]).unwrap();
let icon_name = item.icon_name().await?;
obj.inner().menu_button.set_icon_name(&icon_name);
obj.inner().menu_button.set_button_icon_name(&icon_name);
let menu = item.menu().await?;
let menu = DBusMenuProxy::builder(&connection)

View file

@ -1,33 +0,0 @@
.loading-overlay {
background-color: #2f2f2f;
opacity: 0.85;
}
image.panel_icon {
padding-left: 0px;
padding-right: 0px;
padding-top: 0px;
padding-bottom: 0px;
}
button.panel_icon {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: transparent;
background: transparent;
outline-color: transparent;
}
button.panel_icon:hover {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: rgba(255, 255, 255, 0.1);
outline-color: rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.1);
}
window.root_window {
background: transparent;
}

View file

@ -9,9 +9,9 @@ cascade = "1"
chrono = "0.4"
futures = "0.3"
gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = [ "v4_6" ] }
libcosmic-applet = { path = "../../libcosmic-applet" }
once_cell = "1.12"
serde = "1"
zbus = "2.0.1"
zbus_names = "2"
zvariant = "3"
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"}

View file

@ -1,3 +1,4 @@
use cascade::cascade;
use gtk4::{glib, prelude::*};
mod deref_cell;
@ -7,25 +8,11 @@ use time_button::TimeButton;
fn main() {
gtk4::init().unwrap();
let provider = gtk4::CssProvider::new();
provider.load_from_data(include_bytes!("style.css"));
gtk4::StyleContext::add_provider_for_display(
&gtk4::gdk::Display::default().expect("Could not connect to a display."),
&provider,
gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
let time_button = TimeButton::new();
gtk4::Window::builder()
.decorated(false)
.child(&time_button)
.resizable(false)
.width_request(1)
.height_request(1)
.css_classes(vec!["root_window".to_string()])
.build()
.show();
cascade! {
libcosmic_applet::AppletWindow::new();
..set_child(Some(&TimeButton::new()));
..show();
};
let main_loop = glib::MainLoop::new(None, false);
main_loop.run();

View file

@ -1,33 +0,0 @@
.loading-overlay {
background-color: #2f2f2f;
opacity: 0.85;
}
image.panel_icon {
padding-left: 0px;
padding-right: 0px;
padding-top: 0px;
padding-bottom: 0px;
}
button.panel_icon {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: transparent;
background: transparent;
outline-color: transparent;
}
button.panel_icon:hover {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: rgba(255, 255, 255, 0.1);
outline-color: rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.1);
}
window.root_window {
background: transparent;
}

View file

@ -11,7 +11,7 @@ use crate::deref_cell::DerefCell;
#[derive(Default)]
pub struct TimeButtonInner {
calendar: DerefCell<gtk4::Calendar>,
button: DerefCell<gtk4::MenuButton>,
button: DerefCell<libcosmic_applet::AppletButton>,
label: DerefCell<gtk4::Label>,
}
@ -40,21 +40,15 @@ impl ObjectImpl for TimeButtonInner {
}));
};
let popover = cascade! {
gtk4::Popover::new();
..set_child(Some(&cascade! {
let button = cascade! {
libcosmic_applet::AppletButton::new();
..set_parent(obj);
..connect_activate(clone!(@strong obj => move |_| obj.opening()));
..set_button_child(Some(&label));
..set_popover_child(Some(&cascade! {
gtk4::Box::new(gtk4::Orientation::Horizontal, 0);
..append(&calendar);
}));
..connect_show(clone!(@strong obj => move |_| obj.opening()));
};
let button = cascade! {
gtk4::MenuButton::new();
..set_child(Some(&label));
..set_has_frame(false);
..set_parent(obj);
..set_popover(Some(&popover));
};
self.calendar.set(calendar);

View file

@ -7,7 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"}
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"] }
cascade = "1.0.0"
gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_4"] }
once_cell = "1.9.0"

View file

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0-only
use calloop::channel::SyncSender;
use gtk4::{
gdk::Display,
gio::{self, ApplicationFlags},
@ -13,7 +14,6 @@ use tokio::sync::mpsc;
use utils::{Activate, WorkspaceEvent};
use wayland::State;
use window::CosmicWorkspacesWindow;
use calloop::channel::SyncSender;
mod localize;
mod utils;

View file

@ -92,8 +92,8 @@ pub fn spawn_workspaces(tx: glib::Sender<State>) -> SyncSender<WorkspaceEvent> {
running: true,
};
let loop_handle = event_loop.handle();
loop_handle.insert_source(workspaces_rx, |e, _, state| {
match e {
loop_handle
.insert_source(workspaces_rx, |e, _, state| match e {
Event::Msg(WorkspaceEvent::Activate(id)) => {
if let Some(w) = state
.workspace_groups
@ -136,15 +136,16 @@ pub fn spawn_workspaces(tx: glib::Sender<State>) -> SyncSender<WorkspaceEvent> {
}
}
}
Event::Closed => if let Some(workspace_manager) = &mut state.workspace_manager {
for g in &mut state.workspace_groups {
g.workspace_group_handle.destroy();
Event::Closed => {
if let Some(workspace_manager) = &mut state.workspace_manager {
for g in &mut state.workspace_groups {
g.workspace_group_handle.destroy();
}
workspace_manager.stop();
}
workspace_manager.stop();
},
}
}).unwrap();
}
})
.unwrap();
while state.running {
event_loop
.dispatch(Duration::from_millis(16), &mut state)

View file

@ -43,9 +43,7 @@ impl WorkspaceButton {
new_button.connect_clicked(move |_| {
let id_clone = id.clone();
if !is_active {
let _ = TX.get()
.unwrap()
.send(WorkspaceEvent::Activate(id_clone));
let _ = TX.get().unwrap().send(WorkspaceEvent::Activate(id_clone));
}
});

View file

@ -61,9 +61,7 @@ impl WorkspaceList {
.build();
scroll_controller.connect_scroll(|_, dx, dy| {
let _ = TX.get()
.unwrap()
.send(WorkspaceEvent::Scroll(dx + dy));
let _ = TX.get().unwrap().send(WorkspaceEvent::Scroll(dx + dy));
Inhibit::default()
});

View file

@ -5,7 +5,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"], branch = "rework_0.30"}
cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"] }
cascade = "1.0.0"
gtk4 = { git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_4"] }
once_cell = "1.9.0"