diff --git a/CHANGELOG.md b/CHANGELOG.md index 2be6854f..01299e49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +# [3.7.1] - 2021-06-11 +### Changed +- Refine graphics mode switching: + + Disallow switching to compute or vfio mode unless existing mode is "Integrated" + # [3.7.0] - 2021-06-06 ### Changed - Set PM to auto for Nvidia always diff --git a/Cargo.lock b/Cargo.lock index 7919fe84..aa05ed72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,7 +206,7 @@ dependencies = [ [[package]] name = "daemon" -version = "3.7.0" +version = "3.7.1" dependencies = [ "env_logger", "log", diff --git a/Makefile b/Makefile index a1f8def5..0125072d 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,13 @@ install: $(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png" $(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png" $(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png" + + $(INSTALL_DATA) "./data/icons/scalable/gpu-compute.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-compute.svg" + $(INSTALL_DATA) "./data/icons/scalable/gpu-hybrid.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-hybrid.svg" + $(INSTALL_DATA) "./data/icons/scalable/gpu-integrated.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-integrated.svg" + $(INSTALL_DATA) "./data/icons/scalable/gpu-nvidia.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-nvidia.svg" + $(INSTALL_DATA) "./data/icons/scalable/gpu-vfio.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-vfio.svg" + $(INSTALL_DATA) "./data/icons/scalable/notification-reboot.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/notification-reboot.svg" $(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl" $(INSTALL_DATA) "./data/completions/asusctl.fish" "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish" cd data && find "./anime" -type f -exec install -Dm 755 "{}" "$(DESTDIR)$(datarootdir)/asusd/{}" \; @@ -74,6 +81,12 @@ uninstall: rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png" rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png" rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png" + rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-compute.svg" + rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-hybrid.svg" + rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-integrated.svg" + rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-nvidia.svg" + rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-vfio.svg" + rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/notification-reboot.svg" rm -f "$(DESTDIR)$(zshcpl)/_asusctl" rm -f "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish" rm -rf "$(DESTDIR)$(datarootdir)/asusd" diff --git a/asus-notify/src/main.rs b/asus-notify/src/main.rs index dc6cade6..71910957 100644 --- a/asus-notify/src/main.rs +++ b/asus-notify/src/main.rs @@ -2,8 +2,10 @@ use notify_rust::{Hint, Notification, NotificationHandle}; use rog_aura::AuraEffect; use rog_dbus::{DbusProxies, Signals}; use rog_profiles::profiles::{FanLevel, Profile}; +use rog_types::gfx_vendors::GfxRequiredUserAction; use rog_types::gfx_vendors::GfxVendors; use std::error::Error; +use std::process; use std::thread::sleep; use std::time::Duration; @@ -20,6 +22,16 @@ macro_rules! notify { }; } +macro_rules! base_notification { + ($body:expr) => { + Notification::new() + .summary(NOTIF_HEADER) + .body($body) + .timeout(2000) + .show() + }; +} + fn main() -> Result<(), Box> { println!("asus-notify version {}", env!("CARGO_PKG_VERSION")); println!(" rog-dbus version {}", rog_dbus::VERSION); @@ -59,6 +71,19 @@ fn main() -> Result<(), Box> { if let Ok(data) = signals.gfx_vendor.try_recv() { notify!(do_gfx_notif, last_notification, &data); } + if let Ok(data) = signals.gfx_action.try_recv() { + match data { + GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => { + do_gfx_action_notif(&data)?; + } + GfxRequiredUserAction::Integrated => { + base_notification!( + "You must be in integrated mode first to switch to the requested mode" + )?; + } + GfxRequiredUserAction::None => {} + } + } } } @@ -86,16 +111,6 @@ fn do_thermal_notif(profile: &Profile) -> Result { - Notification::new() - .summary(NOTIF_HEADER) - .body($body) - .timeout(2000) - .show() - }; -} - fn do_led_notif(ledmode: &AuraEffect) -> Result { base_notification!(&format!( "Keyboard LED mode changed to {}", @@ -108,8 +123,50 @@ fn do_charge_notif(limit: &u8) -> Result Result { - base_notification!(&format!( - "Graphics mode changed to {}", - <&str>::from(vendor) - )) + let icon = match vendor { + GfxVendors::Nvidia => "/usr/share/icons/hicolor/scalable/status/gpu-nvidia.svg", + GfxVendors::Integrated => "/usr/share/icons/hicolor/scalable/status/gpu-integrated.svg", + GfxVendors::Compute => "/usr/share/icons/hicolor/scalable/status/gpu-compute.svg", + GfxVendors::Vfio => "/usr/share/icons/hicolor/scalable/status/gpu-vfio.svg", + GfxVendors::Hybrid => "/usr/share/icons/hicolor/scalable/status/gpu-hybrid.svg", + }; + Notification::new() + .summary(NOTIF_HEADER) + .body(&format!( + "Graphics mode changed to {}", + <&str>::from(vendor) + )) + .timeout(2000) + .icon(icon) + .show() +} + +fn do_gfx_action_notif(vendor: &GfxRequiredUserAction) -> Result<(), notify_rust::error::Error> { + let mut notif = Notification::new() + .summary(NOTIF_HEADER) + .timeout(2000) + .urgency(notify_rust::Urgency::Critical) + .icon("/usr/share/icons/hicolor/scalable/status/notification-reboot.svg") + .finalize(); + + if matches!(vendor, GfxRequiredUserAction::Logout) { + notif.action("logout", "Logout now?"); + } else if matches!(vendor, GfxRequiredUserAction::Reboot) { + notif.action("reboot", "Reboot now?"); + } + + notif.body("Graphics mode changed"); + notif.show()?.wait_for_action(|action| match action { + "logout" => { + process::Command::new("gnome-session-quit").spawn().ok(); + } + "reboot" => { + process::Command::new("systemctl") + .arg("reboot") + .spawn() + .ok(); + } + _ => (), + }); + Ok(()) } diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index b095c603..a247cb1e 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -11,7 +11,7 @@ use rog_aura::{self, AuraEffect}; use rog_dbus::RogDbusClient; use rog_profiles::profiles::Profile; use rog_types::{ - gfx_vendors::GfxVendors, + gfx_vendors::{GfxRequiredUserAction, GfxVendors}, supported::{ FanCpuSupportedFunctions, LedSupportedFunctions, RogBiosSupportedFunctions, SupportedFunctions, @@ -309,11 +309,24 @@ fn do_gfx( err })?; let res = dbus.gfx_wait_changed()?; - println!( - "Graphics mode changed to {}. User action required is: {}", - <&str>::from(mode), - <&str>::from(&res) - ); + match res { + GfxRequiredUserAction::Integrated => { + println!( + "You must change to Integrated before you can change to {}", + <&str>::from(mode) + ); + } + GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => { + println!( + "Graphics mode changed to {}. User action required is: {}", + <&str>::from(mode), + <&str>::from(&res) + ); + } + GfxRequiredUserAction::None => { + println!("Graphics mode changed to {}", <&str>::from(mode)); + } + } std::process::exit(0) } if command.get { diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 8ecbc5fa..200e1229 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "3.7.0" +version = "3.7.1" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/daemon/src/ctrl_gfx/controller.rs b/daemon/src/ctrl_gfx/controller.rs index 8e76951c..d4d92c3c 100644 --- a/daemon/src/ctrl_gfx/controller.rs +++ b/daemon/src/ctrl_gfx/controller.rs @@ -8,8 +8,8 @@ use logind_zbus::{ ManagerProxy, SessionProxy, }; use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors}; +use std::iter::FromIterator; use std::{io::Write, ops::Add, path::Path, time::Instant}; -use std::{iter::FromIterator, thread::JoinHandle}; use std::{process::Command, thread::sleep, time::Duration}; use std::{str::FromStr, sync::mpsc}; use std::{sync::Arc, sync::Mutex}; @@ -126,7 +126,7 @@ impl CtrlGraphics { } /// Associated method to get which vendor mode is set - pub fn get_gfx_mode(&self) -> Result { + pub(super) fn get_gfx_mode(&self) -> Result { if let Ok(config) = self.config.lock() { if let Some(mode) = config.gfx_tmp_mode { return Ok(mode); @@ -275,6 +275,7 @@ impl CtrlGraphics { .map_err(|err| RogError::Command("device unbind error".into(), err)) } + /// Add or remove driver modules fn do_driver_action(driver: &str, action: &str) -> Result<(), GfxError> { let mut cmd = Command::new(action); cmd.arg(driver); @@ -359,14 +360,15 @@ impl CtrlGraphics { let mut count = 0; - while count <= 5 { + while count <= (4 * 3) { + // 3 seconds max let output = cmd .output() .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; if output.stdout.starts_with(state.as_bytes()) { return Ok(()); } - std::thread::sleep(std::time::Duration::from_millis(500)); + std::thread::sleep(std::time::Duration::from_millis(250)); count += 1; } Err(GfxError::DisplayManagerTimeout(state.into()).into()) @@ -374,9 +376,10 @@ impl CtrlGraphics { /// Determine if we need to logout/thread. Integrated<->Vfio mode does not /// require logout. - fn logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction { + fn is_logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction { if let Ok(config) = self.config.lock() { let current = config.gfx_mode; + // Modes that can switch without logout if matches!( current, GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute @@ -386,22 +389,28 @@ impl CtrlGraphics { ) { return GfxRequiredUserAction::None; } + // Modes that require a switch to integrated first + if matches!(current, GfxVendors::Nvidia | GfxVendors::Hybrid) + && matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio) + { + return GfxRequiredUserAction::Integrated; + } } GfxRequiredUserAction::Logout } - /// Write the config changes and add/remove drivers and devices depending - /// on selected mode: + /// Do a full setup flow for the chosen mode: /// /// Tasks: + /// - rescan for devices /// - write xorg config /// - write modprobe config - /// - rescan for devices /// + add drivers /// + or remove drivers and devices /// /// The daemon needs direct access to this function when it detects that the - pub fn do_vendor_tasks( + /// bios has G-Sync switch is enabled + pub fn do_mode_setup_tasks( vendor: GfxVendors, vfio_enable: bool, devices: &[GraphicsDevice], @@ -425,8 +434,14 @@ impl CtrlGraphics { dev.set_runtime_pm(sysfs_class::RuntimePowerManagement::On)?; } } - // - Self::write_xorg_conf(vendor)?; + // Only these modes should have xorg config + if matches!( + vendor, + GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Integrated + ) { + Self::write_xorg_conf(vendor)?; + } + // Write different modprobe to enable boot control to work Self::write_modprobe_conf(vendor, devices)?; @@ -492,7 +507,7 @@ impl CtrlGraphics { } /// Spools until all user sessions are ended then switches to requested mode - fn fire_starter( + fn create_mode_change_thread( vendor: GfxVendors, devices: Vec, bus: PciBus, @@ -538,7 +553,7 @@ impl CtrlGraphics { Self::do_display_manager_action("stop")?; Self::wait_display_manager_state("inactive")?; - let mut mode_to_save = vendor; + let mut mode_to_save = vendor; // Need to change to integrated before we can change to vfio or compute if let Ok(mut config) = config.try_lock() { // Since we have a lock, reset tmp to none. This thread should only ever run @@ -546,18 +561,17 @@ impl CtrlGraphics { config.gfx_tmp_mode = None; // let vfio_enable = config.gfx_vfio_enable; - + + // Failsafe. In the event this loop is run with a switch from nvidia in use + // to vfio or compute do a forced switch to integrated instead to prevent issues if matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio) && matches!(config.gfx_mode, GfxVendors::Nvidia | GfxVendors::Hybrid) { - Self::do_vendor_tasks(GfxVendors::Integrated, vfio_enable, &devices, &bus)?; + Self::do_mode_setup_tasks(GfxVendors::Integrated, vfio_enable, &devices, &bus)?; Self::do_display_manager_action("restart")?; - sleep(Duration::from_millis(1500)); // Allow some time for the desktop to start - Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?; - config.gfx_tmp_mode = Some(vendor); mode_to_save = GfxVendors::Integrated; } else { - Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?; + Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?; Self::do_display_manager_action("restart")?; } } @@ -572,7 +586,7 @@ impl CtrlGraphics { } /// Before starting a new thread the old one *must* be cancelled - fn cancel_thread(&self) { + fn cancel_mode_change_thread(&self) { if let Ok(lock) = self.thread_kill.lock() { if let Some(tx) = lock.as_ref() { // Cancel the running thread @@ -587,7 +601,7 @@ impl CtrlGraphics { } /// The thread is used only in cases where a logout is required - fn setup_thread(&mut self, vendor: GfxVendors) { + fn setup_mode_change_thread(&mut self, vendor: GfxVendors) { let config = self.config.clone(); let devices = self.nvidia.clone(); let bus = self.bus.clone(); @@ -595,16 +609,16 @@ impl CtrlGraphics { if let Ok(mut lock) = self.thread_kill.lock() { *lock = Some(tx); } - let killer = self.thread_kill.clone(); + let thread_kill = self.thread_kill.clone(); - let _join: JoinHandle<()> = std::thread::spawn(move || { - Self::fire_starter(vendor, devices, bus, rx, config) + std::thread::spawn(move || { + Self::create_mode_change_thread(vendor, devices, bus, rx, config) .map_err(|err| { error!("GFX: {}", err); }) .ok(); // clear the tx/rx when done - if let Ok(mut lock) = killer.try_lock() { + if let Ok(mut lock) = thread_kill.try_lock() { *lock = None; } }); @@ -615,10 +629,7 @@ impl CtrlGraphics { /// to switch modes. /// /// For manually calling (not on boot/startup) via dbus - pub fn set_gfx_config( - &mut self, - vendor: GfxVendors, - ) -> Result { + pub fn set_gfx_mode(&mut self, vendor: GfxVendors) -> Result { if let Ok(gsync) = CtrlRogBios::get_gfx_mode() { if gsync == 1 { return Err(GfxError::GsyncModeActive.into()); @@ -636,29 +647,40 @@ impl CtrlGraphics { } // Must always cancel any thread running - self.cancel_thread(); + self.cancel_mode_change_thread(); // determine which method we need here - let action_required = self.logout_required(vendor); - if matches!(action_required, GfxRequiredUserAction::Logout) { - // Yeah need the thread to check if all users are logged out - info!("GFX: mode change requires a logout to complete"); - self.setup_thread(vendor); - } else { - // Okay cool, we can switch on/off vfio - info!("GFX: mode change does not require logout"); - let devices = self.nvidia.clone(); - let bus = self.bus.clone(); - Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?; - info!("GFX: Graphics mode changed to {}", <&str>::from(vendor)); - if let Ok(mut config) = self.config.try_lock() { - if matches!(vendor, GfxVendors::Vfio | GfxVendors::Compute) { - config.gfx_tmp_mode = Some(vendor); - } else { + let action_required = self.is_logout_required(vendor); + + match action_required { + GfxRequiredUserAction::Logout => { + info!("GFX: mode change requires a logout to complete"); + self.setup_mode_change_thread(vendor); + } + GfxRequiredUserAction::Reboot => { + info!("GFX: mode change requires reboot"); + let devices = self.nvidia.clone(); + let bus = self.bus.clone(); + Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?; + info!("GFX: Graphics mode changed to {}", <&str>::from(vendor)); + } + GfxRequiredUserAction::Integrated => { + info!("GFX: mode change requires user to be in Integrated mode first"); + } + GfxRequiredUserAction::None => { + info!("GFX: mode change does not require logout"); + let devices = self.nvidia.clone(); + let bus = self.bus.clone(); + Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?; + info!("GFX: Graphics mode changed to {}", <&str>::from(vendor)); + if let Ok(mut config) = self.config.try_lock() { config.gfx_tmp_mode = None; + if matches!(vendor, GfxVendors::Vfio | GfxVendors::Compute) { + config.gfx_tmp_mode = Some(vendor); + } } } } - // TODO: undo if failed? Save last mode, catch errors... + Ok(action_required) } @@ -674,7 +696,7 @@ impl CtrlGraphics { false }; - Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?; + Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?; Self::toggle_fallback_service(vendor)?; Ok(()) } diff --git a/daemon/src/ctrl_gfx/zbus_gfx.rs b/daemon/src/ctrl_gfx/zbus_gfx.rs index 53dd403b..8c66ac1d 100644 --- a/daemon/src/ctrl_gfx/zbus_gfx.rs +++ b/daemon/src/ctrl_gfx/zbus_gfx.rs @@ -25,7 +25,7 @@ impl CtrlGraphics { fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result { info!("GFX: Switching gfx mode to {}", <&str>::from(vendor)); - let msg = self.set_gfx_config(vendor).map_err(|err| { + let msg = self.set_gfx_mode(vendor).map_err(|err| { error!("GFX: {}", err); zbus::fdo::Error::Failed(format!("GFX fail: {}", err)) })?; diff --git a/daemon/src/ctrl_leds/controller.rs b/daemon/src/ctrl_leds/controller.rs index 15445858..e37b5fea 100644 --- a/daemon/src/ctrl_leds/controller.rs +++ b/daemon/src/ctrl_leds/controller.rs @@ -17,11 +17,11 @@ use rog_aura::{ AuraEffect, LedBrightness, LED_MSG_LEN, }; use rog_types::supported::LedSupportedFunctions; -use std::{fs::OpenOptions, thread::spawn}; use std::io::{Read, Write}; use std::path::Path; use std::sync::Arc; use std::sync::Mutex; +use std::{fs::OpenOptions, thread::spawn}; use zbus::Connection; use crate::GetSupported; @@ -75,12 +75,13 @@ impl<'a> CtrlKbdLedTask<'a> { // wait a fraction for things to wake up properly //std::thread::sleep(Duration::from_millis(100)); loop { - if let Ok(ref mut lock) = c1.try_lock() { - lock.set_brightness(lock.config.brightness).ok(); - break; - }} + if let Ok(ref mut lock) = c1.try_lock() { + lock.set_brightness(lock.config.brightness).ok(); + break; + } + } }); - } + } Ok(()) }) .map_err(|err| { diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 2c85274d..7944efeb 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -155,7 +155,7 @@ fn start_daemon() -> Result<(), Box> { warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode"); let devices = ctrl.devices(); let bus = ctrl.bus(); - CtrlGraphics::do_vendor_tasks( + CtrlGraphics::do_mode_setup_tasks( GfxVendors::Nvidia, false, &devices, @@ -165,7 +165,7 @@ fn start_daemon() -> Result<(), Box> { info!("Dedicated GFX toggle is off"); let devices = ctrl.devices(); let bus = ctrl.bus(); - CtrlGraphics::do_vendor_tasks( + CtrlGraphics::do_mode_setup_tasks( config.gfx_mode, false, &devices, diff --git a/data/icons/scalable/gpu-compute.svg b/data/icons/scalable/gpu-compute.svg new file mode 100644 index 00000000..37509170 --- /dev/null +++ b/data/icons/scalable/gpu-compute.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/data/icons/scalable/gpu-hybrid.svg b/data/icons/scalable/gpu-hybrid.svg new file mode 100644 index 00000000..abafc73e --- /dev/null +++ b/data/icons/scalable/gpu-hybrid.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + diff --git a/data/icons/scalable/gpu-integrated.svg b/data/icons/scalable/gpu-integrated.svg new file mode 100644 index 00000000..90df643f --- /dev/null +++ b/data/icons/scalable/gpu-integrated.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + diff --git a/data/icons/scalable/gpu-nvidia.svg b/data/icons/scalable/gpu-nvidia.svg new file mode 100644 index 00000000..d73963a3 --- /dev/null +++ b/data/icons/scalable/gpu-nvidia.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + diff --git a/data/icons/scalable/gpu-vfio.svg b/data/icons/scalable/gpu-vfio.svg new file mode 100644 index 00000000..e74d450a --- /dev/null +++ b/data/icons/scalable/gpu-vfio.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/data/icons/scalable/notification-reboot.svg b/data/icons/scalable/notification-reboot.svg new file mode 100644 index 00000000..8783bc2d --- /dev/null +++ b/data/icons/scalable/notification-reboot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rog-types/src/gfx_vendors.rs b/rog-types/src/gfx_vendors.rs index 62a2b48c..86636b55 100644 --- a/rog-types/src/gfx_vendors.rs +++ b/rog-types/src/gfx_vendors.rs @@ -86,6 +86,7 @@ impl From for &str { pub enum GfxRequiredUserAction { Logout, Reboot, + Integrated, None, } @@ -94,6 +95,7 @@ impl From<&GfxRequiredUserAction> for &str { match gfx { GfxRequiredUserAction::Logout => "logout", GfxRequiredUserAction::Reboot => "reboot", + GfxRequiredUserAction::Integrated => "switch to integrated first", GfxRequiredUserAction::None => "no action", } }