├── src ├── cli │ ├── mod.rs │ ├── error.rs │ └── clap.rs ├── nvapi │ ├── mod.rs │ ├── general.rs │ ├── rotation.rs │ ├── monitor.rs │ ├── vrr.rs │ ├── scaling.rs │ └── display.rs └── main.rs ├── .gitignore ├── docs ├── Gemfile ├── _config.yml ├── index.md └── Gemfile.lock ├── Cargo.toml ├── readme.md └── Cargo.lock /src/cli/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod clap; 2 | pub mod error; 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | *.log 3 | _site/ 4 | .bundle/ 5 | .jekyll-cache/ 6 | vendor/ 7 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "jekyll-include-cache" 4 | gem "webrick" 5 | gem "github-pages", group: :jekyll_plugins -------------------------------------------------------------------------------- /src/nvapi/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod display; 2 | pub mod general; 3 | pub mod monitor; 4 | pub mod rotation; 5 | pub mod scaling; 6 | pub mod vrr; 7 | -------------------------------------------------------------------------------- /src/cli/error.rs: -------------------------------------------------------------------------------- 1 | pub enum Error { 2 | Argument { 3 | message: String, 4 | error: Box, 5 | }, 6 | } 7 | 8 | pub type Result = std::result::Result; 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nvcli" 3 | version = "1.1.4" 4 | edition = "2021" 5 | authors = ["sqooid"] 6 | description = "Command line interface to change a number of Nvidia control panel display settings" 7 | documentation = "https://github.com/sqooid/nvcli" 8 | homepage = "https://github.com/sqooid/nvcli" 9 | repository = "https://github.com/sqooid/nvcli" 10 | license = "MIT" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | nvapi_sys_new = "1.530.1" 16 | clap = {version="3.2.11", features=["derive"]} 17 | bunt = "0.2.6" -------------------------------------------------------------------------------- /src/nvapi/general.rs: -------------------------------------------------------------------------------- 1 | use nvapi_sys_new::{NvAPI_GetErrorMessage, NvAPI_Initialize, NvAPI_Unload, _NvAPI_Status}; 2 | 3 | pub fn initialize() { 4 | unsafe { 5 | NvAPI_Initialize(); 6 | } 7 | } 8 | 9 | pub fn unload() { 10 | unsafe { 11 | NvAPI_Unload(); 12 | } 13 | } 14 | 15 | pub fn get_status_message(status: &_NvAPI_Status) -> String { 16 | let mut buffer: [i8; 64] = [0; 64]; 17 | let str_buffer; 18 | unsafe { 19 | NvAPI_GetErrorMessage(*status, buffer.as_mut_ptr()); 20 | str_buffer = std::mem::transmute::<[i8; 64], [u8; 64]>(buffer); 21 | let mut message = std::str::from_utf8_unchecked(&str_buffer).to_owned(); 22 | message.truncate(message.find('\0').unwrap_or(64)); 23 | message 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/nvapi/rotation.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | pub struct Rotation(pub i32); 4 | 5 | impl TryFrom<&u32> for Rotation { 6 | type Error = String; 7 | 8 | fn try_from(value: &u32) -> Result { 9 | match value { 10 | 0 => Ok(Self(0)), 11 | 90 => Ok(Self(1)), 12 | 180 => Ok(Self(2)), 13 | 270 => Ok(Self(3)), 14 | _ => Err("Invalid rotation value".to_string()), 15 | } 16 | } 17 | } 18 | 19 | impl Display for Rotation { 20 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 21 | write!( 22 | f, 23 | "{}", 24 | match self.0 { 25 | 0 => "0", 26 | 90 => "90", 27 | 180 => "180", 28 | 270 => "270", 29 | _ => "Invalid", 30 | } 31 | ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | remote_theme: "mmistakes/minimal-mistakes@4.24.0" 2 | minimal_mistakes_skin: "dark" 3 | plugins: 4 | - jekyll-include-cache 5 | 6 | title: "nvcli" 7 | name: "Lucas Liu" 8 | description: "A cli interface to some features of the Nvidia control panel" 9 | repository: "sqooid/nvcli" 10 | google_site_verification: "NVEiESCtwdsS2FVZfDiBbTsgl4weDvpWrQbfnJ6VsYM" 11 | 12 | social: 13 | links: 14 | - "https://github.com/sqooid" 15 | - "https://www.linkedin.com/in/lucas-liu-a92859217" 16 | 17 | defaults: 18 | - scope: 19 | path: "" 20 | type: pages 21 | values: 22 | layout: single 23 | author_profile: true 24 | title: About 25 | 26 | author: 27 | name: "Lucas Liu" 28 | avatar: "https://avatars.githubusercontent.com/u/64120036" 29 | bio: "A computer science and electrical engineering student" 30 | location: "Melbourne, Australia" 31 | links: 32 | - label: "Download" 33 | icon: "fas fa-fw fa-download" 34 | url: "https://github.com/sqooid/nvcli/releases" 35 | - label: "Repository" 36 | icon: "fab fa-fw fa-github" 37 | url: "https://github.com/sqooid/nvcli" 38 | -------------------------------------------------------------------------------- /src/nvapi/monitor.rs: -------------------------------------------------------------------------------- 1 | use crate::{cli::error::Result, nvapi::display::get_display_config}; 2 | 3 | pub fn find_primary_display_id() -> Result { 4 | let result = get_display_config(); 5 | 6 | let display_configs = match result { 7 | Ok(configs) => configs, 8 | Err(e) => { 9 | return Err(e); 10 | } 11 | }; 12 | let mut display_id: u32 = 0; 13 | if display_configs 14 | .iter() 15 | .find(|x| { 16 | if x.source_mode_info.bGDIPrimary() == 1 { 17 | display_id = x.target_info[0].display_id; 18 | true 19 | } else { 20 | false 21 | } 22 | }) 23 | .is_none() 24 | { 25 | Err("No primary display found".to_owned()) 26 | } else { 27 | Ok(display_id) 28 | } 29 | } 30 | 31 | #[cfg(test)] 32 | mod tests { 33 | use crate::nvapi::general::{initialize, unload}; 34 | 35 | use super::*; 36 | 37 | #[test] 38 | fn test_find_primary_display() { 39 | initialize(); 40 | let primary_id = find_primary_display_id(); 41 | match primary_id { 42 | Ok(id) => println!("{id}"), 43 | Err(e) => println!("{e}"), 44 | } 45 | unload(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/nvapi/vrr.rs: -------------------------------------------------------------------------------- 1 | use crate::cli::error::Result; 2 | use nvapi_sys_new::{ 3 | NvAPI_Disp_GetVRRInfo, _NvAPI_Status_NVAPI_OK, make_nvapi_version, NV_GET_VRR_INFO, 4 | }; 5 | 6 | use super::general::get_status_message; 7 | 8 | #[derive(Debug)] 9 | pub struct VvrData { 10 | version: u32, 11 | vrr_enabled: u32, 12 | reserved: u32, 13 | reserved_ex: [u32; 4], 14 | } 15 | 16 | pub fn get_vvr_data(display_id: u32) -> Result { 17 | let mut data = NV_GET_VRR_INFO::default(); 18 | data.version = make_nvapi_version::(1); 19 | let result: i32; 20 | unsafe { 21 | result = NvAPI_Disp_GetVRRInfo(display_id, &mut data); 22 | } 23 | if result != _NvAPI_Status_NVAPI_OK { 24 | Err(get_status_message(&result)) 25 | } else { 26 | Ok(VvrData { 27 | version: data.version, 28 | vrr_enabled: data.bIsVRREnabled(), 29 | reserved: data.reserved(), 30 | reserved_ex: data.reservedEx, 31 | }) 32 | } 33 | } 34 | 35 | // pub fn set_vvr_data(display_id: u32, data: &VvrData) -> Result<()> { 36 | // let mut input = NV_SET_VIRTUAL_REFRESH_RATE_DATA { 37 | // version: data.version, 38 | // frameIntervalUs: data.frame_interval, 39 | // reservedEx: data.reserved, 40 | // }; 41 | // let result: i32; 42 | // unsafe { 43 | // result = NvAPI_DISP_SetVirtualRefreshRateData(display_id, &mut input); 44 | // } 45 | // if result != _NvAPI_Status_NVAPI_OK { 46 | // Err(get_status_message(&result)) 47 | // } else { 48 | // Ok(()) 49 | // } 50 | // } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use crate::nvapi::{ 55 | general::{initialize, unload}, 56 | monitor::find_primary_display_id, 57 | }; 58 | 59 | use super::*; 60 | 61 | #[test] 62 | fn test_get_vrr_data() { 63 | initialize(); 64 | if let Ok(primary_id) = find_primary_display_id() { 65 | match get_vvr_data(primary_id) { 66 | Ok(data) => println!("{:?}", data), 67 | Err(e) => println!("{e}"), 68 | } 69 | } 70 | unload(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/nvapi/scaling.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt::Display, str::FromStr}; 2 | 3 | #[derive(Debug)] 4 | #[repr(i32)] 5 | pub enum Scaling { 6 | Default = 0, 7 | BalancedFullScreen = 1, 8 | ForcedFullScreen = 2, 9 | ForcedCentered = 3, 10 | ForcedAspectRatio = 5, 11 | BalancedAspectRatio = 6, 12 | BalancedCentered = 7, 13 | ForcedIntegerScaling = 8, 14 | } 15 | 16 | impl FromStr for Scaling { 17 | type Err = String; 18 | 19 | fn from_str(s: &str) -> Result { 20 | match s { 21 | "default" => Ok(Self::Default), 22 | "bfs" => Ok(Self::BalancedFullScreen), 23 | "ffs" => Ok(Self::ForcedFullScreen), 24 | "fc" => Ok(Self::ForcedCentered), 25 | "far" => Ok(Self::ForcedAspectRatio), 26 | "bar" => Ok(Self::BalancedAspectRatio), 27 | "bc" => Ok(Self::BalancedCentered), 28 | "fis" => Ok(Self::ForcedIntegerScaling), 29 | _ => Err("Invalid scaling argument".to_string()), 30 | } 31 | } 32 | } 33 | 34 | impl From for Scaling { 35 | fn from(num: i32) -> Self { 36 | match num { 37 | 0 => Self::Default, 38 | 1 => Self::BalancedFullScreen, 39 | 2 => Self::ForcedFullScreen, 40 | 3 => Self::ForcedCentered, 41 | 5 => Self::ForcedAspectRatio, 42 | 6 => Self::BalancedAspectRatio, 43 | 7 => Self::BalancedCentered, 44 | 8 => Self::ForcedIntegerScaling, 45 | _ => Self::Default, 46 | } 47 | } 48 | } 49 | 50 | impl Display for Scaling { 51 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 52 | write!( 53 | f, 54 | "{}", 55 | match self { 56 | Scaling::Default => "default", 57 | Scaling::BalancedFullScreen => "balanced full screen", 58 | Scaling::ForcedFullScreen => "forced full screen", 59 | Scaling::ForcedCentered => "forced centered", 60 | Scaling::ForcedAspectRatio => "forced aspect ratio", 61 | Scaling::BalancedAspectRatio => "balanced aspect ratio", 62 | Scaling::BalancedCentered => "balanced centered", 63 | Scaling::ForcedIntegerScaling => "forced integer scaling", 64 | } 65 | ) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/cli/clap.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | 3 | #[derive(Debug, Parser)] 4 | #[clap(author, version, about, long_about = None)] 5 | pub struct Cli { 6 | /// Horizontal resolution in pixels. Defaults to current resolution. 7 | #[clap(short = 'x', long)] 8 | pub resolution_x: Option, 9 | 10 | /// Vertical resolution in pixels. Defaults to current resolution. 11 | #[clap(short = 'y', long)] 12 | pub resolution_y: Option, 13 | 14 | /// Scaling setting. Defaults to current scaling setting. Valid values are: 15 | /// bfs - balanced full screen (stretch to fill), 16 | /// bar - balanced aspect ratio (fill without stretching), 17 | /// bc - balanced centered (no scaling), 18 | /// fis - forced integer scaling (scale by integer multiples) 19 | #[clap(short, long)] 20 | pub scaling: Option, 21 | 22 | /// Display ID to apply settings to. Defaults to primary display. 23 | #[clap(short, long)] 24 | pub display: Option, 25 | 26 | /// List connected display ID's and settings instead of applying settings. Defaults to false. 27 | #[clap(short, long)] 28 | pub list: bool, 29 | 30 | /// Refresh rate. Defaults to current refresh rate 31 | #[clap(short, long)] 32 | pub refresh: Option, 33 | 34 | /// x coordinate of monitor's top left corner. 35 | /// (0,0) is located at the top left corner of the primary monitor. 36 | /// Negative values must be specified using "=" e.g. `-X=-1080`. 37 | /// If a collision is detected the monitor is placed in its default position. 38 | /// Defaults to current value 39 | #[clap(short = 'X', long)] 40 | pub position_x: Option, 41 | 42 | /// y coordinate of monitor's top left corner. 43 | #[clap(short = 'Y', long)] 44 | pub position_y: Option, 45 | 46 | /// Clockwise rotation of monitor in degrees. Valid values are 0, 90, 180 and 270. Defaults to current value. 47 | #[clap(short = 'R', long)] 48 | pub rotation: Option, 49 | } 50 | 51 | impl Cli { 52 | pub fn display_config_needed(&self) -> bool { 53 | self.resolution_x.is_some() 54 | || self.resolution_y.is_some() 55 | || self.scaling.is_some() 56 | || self.refresh.is_some() 57 | || self.position_x.is_some() 58 | || self.position_y.is_some() 59 | || self.rotation.is_some() 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | This is a tiny application that allows you to set your monitors' resolution, refresh rate, scaling mode, position and rotation in the command-line. 4 | Typically this would be done using the Nvidia control panel, but due to its lack of a cli interface, it is difficult to automate those changes. 5 | 6 | Note that this program only works on Windows computers. 7 | 8 | ## Installation 9 | 10 | The 64 bit binary can be downloaded from the releases page. In order to get a 32 bit installation, the project must be built from source. This process can be simplified with cargo by running `cargo install nvcli`. 11 | 12 | ## Usage 13 | 14 | Help text will be printed if the program is run with no arguments or by passing the `--help` option. 15 | 16 | Each invocation of the program applies the options passed to it. 17 | By default the settings apply to the primary monitor if there are multiple monitors connected. 18 | In order to target a different monitor, passing the monitor's display id to the `--display` option causes the other specified options to apply to that monitor instead. 19 | 20 | In order to obtain a monitor's display id, run `nvcli -l` to list the connected displays. 21 | This lists each source and their targets (the vast majority of the time each source only has one target). 22 | The display id of each target can be found in the listed information 23 | 24 | The valid values for each setting can be found by looking in the Nvidia control panel and seeing what options are available. 25 | 26 | Gamma settings can be set by installing GeForce Experience and using Freestyle to apply a filter. 27 | 28 | ## Examples 29 | 30 | ### Listing displays 31 | 32 | Running `nvcli -l` will output something that looks like this: 33 | ``` 34 | Source 35 | Primary: true (Whether this source is the primary monitor) 36 | Resolution: 2560x1440 (The current resolution of this output) 37 | Position: (0,0) (The current position of this monitor) 38 | Target 1 39 | ID: 2147881089 (The display id of this target, which is used to change which monitor settings are applied to) 40 | Refresh rate: 165 Hz (The current refresh rate) 41 | Scaling: balanced full screen (The current scaling mode) 42 | Rotation: 0 (The current display clockwise rotation in degrees) 43 | 44 | Source 45 | Primary: false 46 | Resolution: 1920x1080 47 | Position: (2560,0) 48 | Target 1 49 | ID: 2147881090 50 | Refresh rate: 120 Hz 51 | Scaling: balanced aspect ratio 52 | Rotation: 0 53 | ``` 54 | 55 | ### Stretched 56 | 57 | If the primary monitor is originally configured to have 2560x1440 resolution, 165Hz refresh rate and balanced full screen scaling, 58 | setting the monitor to 4:3 stretched can be done with any of the following commands: 59 | ``` 60 | nvcli -w 1920 -h 1440 -s ffs 61 | ``` 62 | (`bfs` also works here as there is no discernible difference between the forced and balanced scaling options). 63 | ``` 64 | nvcli -w 1920 65 | ``` 66 | (other settings remain the same if unspecified) 67 | 68 | ### Non-primary monitors 69 | 70 | Changing the refresh rate of a non-primary monitor with display id `2147881090` to 120Hz: 71 | ``` 72 | nvcli -d 2147881090 -r 120 73 | ``` 74 | 75 | ### Changing position/rotation of secondary monitor 76 | 77 | If there are two monitors both of resolution 1920x1080, the following command would place the secondary monitor above the primary monitor: 78 | ``` 79 | nvcli -d 2147881090 -X 0 -Y=-1080 80 | ``` 81 | The following command would place the secondary monitor right beside the primary monitor on its right: 82 | ``` 83 | nvcli -d 2147881090 -X 1920 -Y 0 84 | ``` 85 | The following command would rotate the secondary monitor to vertical and place it centered above the primary monitor: 86 | ``` 87 | nvcli -d 2147881090 -R 90 -X 420 -Y=-1920 88 | ``` 89 | 90 | ## Notes 91 | 92 | Output color can be disabled by setting the environment variable `NO_COLOR=1`. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Due to no longer having an Nvidia GPU I'm unable to develop this tool any further. Apologies to anyone requesting additional features. 2 | 3 | ## Description 4 | 5 | This is a tiny application that allows you to set your monitors' resolution, refresh rate, scaling mode, position and rotation in the command-line. 6 | Typically this would be done using the Nvidia control panel, but due to its lack of a cli interface, it is difficult to automate those changes. 7 | 8 | Note that this program only works on Windows computers. 9 | 10 | ## Installation 11 | 12 | The 64 bit binary can be downloaded from the releases page. In order to get a 32 bit installation, the project must be built from source. This process can be simplified with cargo by running `cargo install nvcli`. 13 | 14 | ## Usage 15 | 16 | Help text will be printed if the program is run with no arguments or by passing the `--help` option. 17 | 18 | Each invocation of the program applies the options passed to it. 19 | By default the settings apply to the primary monitor if there are multiple monitors connected. 20 | In order to target a different monitor, passing the monitor's display id to the `--display` option causes the other specified options to apply to that monitor instead. 21 | 22 | In order to obtain a monitor's display id, run `nvcli -l` to list the connected displays. 23 | This lists each source and their targets (the vast majority of the time each source only has one target). 24 | The display id of each target can be found in the listed information 25 | 26 | The valid values for each setting can be found by looking in the Nvidia control panel and seeing what options are available. 27 | 28 | Gamma settings can be set by installing GeForce Experience and using Freestyle to apply a filter. 29 | 30 | ## Examples 31 | 32 | ### Listing displays 33 | 34 | Running `nvcli -l` will output something that looks like this: 35 | ``` 36 | Source 37 | Primary: true (Whether this source is the primary monitor) 38 | Resolution: 2560x1440 (The current resolution of this output) 39 | Position: (0,0) (The current position of this monitor) 40 | Target 1 41 | ID: 2147881089 (The display id of this target, which is used to change which monitor settings are applied to) 42 | Refresh rate: 165 Hz (The current refresh rate) 43 | Scaling: balanced full screen (The current scaling mode) 44 | Rotation: 0 (The current display clockwise rotation in degrees) 45 | 46 | Source 47 | Primary: false 48 | Resolution: 1920x1080 49 | Position: (2560,0) 50 | Target 1 51 | ID: 2147881090 52 | Refresh rate: 120 Hz 53 | Scaling: balanced aspect ratio 54 | Rotation: 0 55 | ``` 56 | 57 | ### Stretched 58 | 59 | If the primary monitor is originally configured to have 2560x1440 resolution, 165Hz refresh rate and balanced full screen scaling, 60 | setting the monitor to 4:3 stretched can be done with any of the following commands: 61 | ``` 62 | nvcli -w 1920 -h 1440 -s ffs 63 | ``` 64 | (`bfs` also works here as there is no discernible difference between the forced and balanced scaling options). 65 | ``` 66 | nvcli -w 1920 67 | ``` 68 | (other settings remain the same if unspecified) 69 | 70 | ### Non-primary monitors 71 | 72 | Changing the refresh rate of a non-primary monitor with display id `2147881090` to 120Hz: 73 | ``` 74 | nvcli -d 2147881090 -r 120 75 | ``` 76 | 77 | ### Changing position/rotation of secondary monitor 78 | 79 | If there are two monitors both of resolution 1920x1080, the following command would place the secondary monitor above the primary monitor: 80 | ``` 81 | nvcli -d 2147881090 -X 0 -Y=-1080 82 | ``` 83 | The following command would place the secondary monitor right beside the primary monitor on its right: 84 | ``` 85 | nvcli -d 2147881090 -X 1920 -Y 0 86 | ``` 87 | The following command would rotate the secondary monitor to vertical and place it centered above the primary monitor: 88 | ``` 89 | nvcli -d 2147881090 -R 90 -X 420 -Y=-1920 90 | ``` 91 | 92 | ## Notes 93 | 94 | Output color can be disabled by setting the environment variable `NO_COLOR=1`. 95 | 96 | Unit tests should be run with `cargo test -- --nocapture --test-threads 1` 97 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; 2 | pub mod nvapi; 3 | 4 | use std::str::FromStr; 5 | 6 | use clap::Parser; 7 | use nvapi::{ 8 | display::get_display_config, 9 | general::{initialize, unload}, 10 | rotation::Rotation, 11 | }; 12 | 13 | use crate::{ 14 | cli::clap::Cli, 15 | nvapi::display::Output, 16 | nvapi::{display::set_display_config, scaling::Scaling}, 17 | }; 18 | 19 | fn main() { 20 | if std::env::args().len() < 2 { 21 | Cli::parse_from(["", "--help"]); 22 | } 23 | 24 | let config = Cli::parse(); 25 | 26 | initialize(); 27 | let result = get_display_config(); 28 | let mut display_configs = match result { 29 | Ok(configs) => configs, 30 | Err(e) => { 31 | bunt::println!("{$red}Failed to get current display config: {}{/$}", e); 32 | unload(); 33 | return; 34 | } 35 | }; 36 | 37 | if config.list { 38 | for config in display_configs.iter() { 39 | config.print_short(); 40 | } 41 | 42 | unload(); 43 | return; 44 | } 45 | 46 | let mut display_idx: [usize; 2] = [0, 0]; 47 | match config.display { 48 | Some(id) => { 49 | if display_configs 50 | .iter() 51 | .find(|info| { 52 | if info 53 | .target_info 54 | .iter() 55 | .find(|target| { 56 | if target.display_id == id { 57 | true 58 | } else { 59 | display_idx[1] += 1; 60 | false 61 | } 62 | }) 63 | .is_none() 64 | { 65 | display_idx[0] += 1; 66 | display_idx[1] = 0; 67 | false 68 | } else { 69 | true 70 | } 71 | }) 72 | .is_none() 73 | { 74 | bunt::println!("{$red}Display with specified ID not found{/$}"); 75 | unload(); 76 | return; 77 | }; 78 | } 79 | None => { 80 | if display_configs 81 | .iter() 82 | .find(|x| { 83 | if x.source_mode_info.bGDIPrimary() == 1 { 84 | true 85 | } else { 86 | display_idx[0] += 1; 87 | false 88 | } 89 | }) 90 | .is_none() 91 | { 92 | bunt::println!("{$red}No primary display found{/$}"); 93 | unload(); 94 | return; 95 | }; 96 | } 97 | }; 98 | 99 | if let Some(width) = &config.resolution_x { 100 | display_configs[display_idx[0]] 101 | .source_mode_info 102 | .resolution 103 | .width = width.to_owned(); 104 | } 105 | 106 | if let Some(height) = &config.resolution_y { 107 | display_configs[display_idx[0]] 108 | .source_mode_info 109 | .resolution 110 | .height = height.to_owned(); 111 | } 112 | 113 | if let Some(scaling) = &config.scaling { 114 | display_configs[display_idx[0]].target_info[display_idx[1]] 115 | .details 116 | .scaling = match Scaling::from_str(scaling) { 117 | Ok(scaling) => scaling, 118 | Err(_) => { 119 | bunt::println!("{$red}Invalid scaling option{/$}"); 120 | unload(); 121 | return; 122 | } 123 | } as i32; 124 | } 125 | 126 | if let Some(position_x) = &config.position_x { 127 | display_configs[display_idx[0]].source_mode_info.position.x = position_x.clone(); 128 | } 129 | 130 | if let Some(position_y) = &config.position_y { 131 | display_configs[display_idx[0]].source_mode_info.position.y = position_y.clone(); 132 | } 133 | 134 | if let Some(refresh) = &config.refresh { 135 | display_configs[display_idx[0]].target_info[display_idx[1]] 136 | .details 137 | .refreshRate1K = refresh * 1000; 138 | } 139 | 140 | if let Some(rotation) = &config.rotation { 141 | let rotation = match Rotation::try_from(rotation) { 142 | Ok(rot) => rot.0, 143 | Err(e) => { 144 | bunt::println!("{[red]}", e); 145 | unload(); 146 | return; 147 | } 148 | }; 149 | display_configs[display_idx[0]].target_info[display_idx[1]] 150 | .details 151 | .rotation = rotation; 152 | } 153 | 154 | if config.display_config_needed() { 155 | let result = set_display_config(display_configs); 156 | match result { 157 | Ok(_) => bunt::println!("{$green}Successfully applied display settings{/$}"), 158 | Err(e) => { 159 | bunt::println!("{$red}Failed to apply display config: {}{/$}", e); 160 | } 161 | }; 162 | } 163 | 164 | unload(); 165 | } 166 | -------------------------------------------------------------------------------- /src/nvapi/display.rs: -------------------------------------------------------------------------------- 1 | use crate::cli::error::Result; 2 | use nvapi_sys_new::{ 3 | make_nvapi_version, NvAPI_DISP_GetDisplayConfig, NvAPI_DISP_SetDisplayConfig, 4 | _NvAPI_Status_NVAPI_OK, NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO, NV_DISPLAYCONFIG_PATH_INFO, 5 | NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2, NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1, 6 | }; 7 | 8 | use super::{general::get_status_message, rotation::Rotation, scaling::Scaling}; 9 | 10 | pub fn get_display_config() -> Result> { 11 | let mut path_info_count: u32 = 0; 12 | // Get count 13 | unsafe { 14 | let result = NvAPI_DISP_GetDisplayConfig(&mut path_info_count, std::ptr::null_mut()); 15 | if result != 0 { 16 | return Err(get_status_message(&result)); 17 | } 18 | } 19 | // Allocate path info 20 | let mut path_info = vec![]; 21 | for _ in 0..path_info_count { 22 | path_info.push(NV_DISPLAYCONFIG_PATH_INFO { 23 | version: make_nvapi_version::(2), 24 | sourceModeInfo: Box::into_raw( 25 | Box::new(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1::default()), 26 | ), 27 | ..Default::default() 28 | }); 29 | } 30 | 31 | unsafe { 32 | let result = NvAPI_DISP_GetDisplayConfig(&mut path_info_count, path_info.as_mut_ptr()); 33 | if result != 0 { 34 | return Err(get_status_message(&result)); 35 | } 36 | } 37 | 38 | for info in path_info.iter_mut() { 39 | info.targetInfo = Box::into_raw( 40 | vec![ 41 | NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 { 42 | details: Box::into_raw(Box::new(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO { 43 | version: make_nvapi_version::( 44 | 1 45 | ), 46 | ..Default::default() 47 | })), 48 | ..Default::default() 49 | }; 50 | info.targetInfoCount as usize 51 | ] 52 | .into_boxed_slice(), 53 | ) as *mut NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2; 54 | } 55 | 56 | // Get target info 57 | unsafe { 58 | let result = NvAPI_DISP_GetDisplayConfig(&mut path_info_count, path_info.as_mut_ptr()); 59 | if result != 0 { 60 | return Err(get_status_message(&result)); 61 | } 62 | } 63 | 64 | // Collect outputs 65 | let output: Vec = path_info 66 | .into_iter() 67 | .map(NvDisplayConfigPathInfo::from) 68 | .collect(); 69 | Ok(output) 70 | } 71 | 72 | pub fn set_display_config(config: Vec) -> Result<()> { 73 | let mut config: Vec = config 74 | .into_iter() 75 | .map(NV_DISPLAYCONFIG_PATH_INFO::from) 76 | .collect(); 77 | let result; 78 | unsafe { 79 | result = NvAPI_DISP_SetDisplayConfig(config.len() as u32, config.as_mut_ptr(), 0); 80 | } 81 | 82 | // Change back for cleanup 83 | let _config: Vec = config 84 | .into_iter() 85 | .map(NvDisplayConfigPathInfo::from) 86 | .collect(); 87 | 88 | if result != _NvAPI_Status_NVAPI_OK { 89 | Err(get_status_message(&result)) 90 | } else { 91 | Ok(()) 92 | } 93 | } 94 | 95 | #[derive(Debug, Clone)] 96 | pub struct NvDisplayConfigPathInfo { 97 | pub target_info: Vec, 98 | pub source_mode_info: Box, 99 | pub is_non_nvidia_adapter: bool, 100 | } 101 | #[derive(Debug, Clone)] 102 | pub struct NvDisplayConfigPathTargetInfo { 103 | pub display_id: u32, 104 | pub details: Box, 105 | pub target_id: u32, 106 | } 107 | 108 | pub trait Output { 109 | fn print_short(&self); 110 | fn long_display(&self) -> String; 111 | } 112 | 113 | impl Output for NvDisplayConfigPathInfo { 114 | fn print_short(&self) { 115 | bunt::println!( 116 | "{[blue+bold]}\nPrimary: {}\nResolution: {}x{}\nPosition: ({},{})", 117 | "Source", 118 | if self.source_mode_info.bGDIPrimary() == 1 { 119 | "true" 120 | } else { 121 | "false" 122 | }, 123 | self.source_mode_info.resolution.width, 124 | self.source_mode_info.resolution.height, 125 | self.source_mode_info.position.x, 126 | self.source_mode_info.position.y, 127 | ); 128 | for (i, target) in self.target_info.iter().enumerate() { 129 | bunt::println!( 130 | "{[green+bold]} {[green+bold]}\nID: {}\nRefresh rate: {} Hz\nScaling: {}\nRotation: {}", 131 | "Target", 132 | (i + 1).to_string(), 133 | target.display_id, 134 | target.details.refreshRate1K / 1000, 135 | Scaling::from(target.details.scaling), 136 | Rotation(target.details.rotation) 137 | ); 138 | } 139 | } 140 | 141 | fn long_display(&self) -> String { 142 | todo!() 143 | } 144 | } 145 | 146 | impl From for NV_DISPLAYCONFIG_PATH_INFO { 147 | fn from(e: NvDisplayConfigPathInfo) -> Self { 148 | let mut targets: Vec = vec![]; 149 | for target in e.target_info { 150 | targets.push(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 { 151 | displayId: target.display_id, 152 | details: Box::into_raw(target.details), 153 | targetId: target.target_id, 154 | }); 155 | } 156 | NV_DISPLAYCONFIG_PATH_INFO { 157 | version: make_nvapi_version::(2), 158 | sourceModeInfo: Box::into_raw(e.source_mode_info), 159 | targetInfoCount: targets.len() as u32, 160 | targetInfo: Box::into_raw(targets.into_boxed_slice()) 161 | as *mut NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2, 162 | ..Default::default() 163 | } 164 | } 165 | } 166 | 167 | impl From for NvDisplayConfigPathInfo { 168 | fn from(info: NV_DISPLAYCONFIG_PATH_INFO) -> Self { 169 | let mut targets: Vec = vec![]; 170 | unsafe { 171 | for target in std::slice::from_raw_parts(info.targetInfo, info.targetInfoCount as usize) 172 | { 173 | targets.push(NvDisplayConfigPathTargetInfo { 174 | display_id: target.displayId, 175 | details: Box::from_raw(target.details), 176 | target_id: target.targetId, 177 | }); 178 | } 179 | NvDisplayConfigPathInfo { 180 | target_info: targets, 181 | source_mode_info: Box::from_raw(info.sourceModeInfo), 182 | is_non_nvidia_adapter: info.IsNonNVIDIAAdapter() == 1, 183 | } 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /docs/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (6.0.5.1) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 0.7, < 2) 7 | minitest (~> 5.1) 8 | tzinfo (~> 1.1) 9 | zeitwerk (~> 2.2, >= 2.2.2) 10 | addressable (2.8.0) 11 | public_suffix (>= 2.0.2, < 5.0) 12 | coffee-script (2.4.1) 13 | coffee-script-source 14 | execjs 15 | coffee-script-source (1.11.1) 16 | colorator (1.1.0) 17 | commonmarker (0.23.5) 18 | concurrent-ruby (1.1.10) 19 | dnsruby (1.61.9) 20 | simpleidn (~> 0.1) 21 | em-websocket (0.5.3) 22 | eventmachine (>= 0.12.9) 23 | http_parser.rb (~> 0) 24 | ethon (0.15.0) 25 | ffi (>= 1.15.0) 26 | eventmachine (1.2.7) 27 | execjs (2.8.1) 28 | faraday (2.3.0) 29 | faraday-net_http (~> 2.0) 30 | ruby2_keywords (>= 0.0.4) 31 | faraday-net_http (2.0.3) 32 | ffi (1.15.5) 33 | forwardable-extended (2.6.0) 34 | gemoji (3.0.1) 35 | github-pages (227) 36 | github-pages-health-check (= 1.17.9) 37 | jekyll (= 3.9.2) 38 | jekyll-avatar (= 0.7.0) 39 | jekyll-coffeescript (= 1.1.1) 40 | jekyll-commonmark-ghpages (= 0.2.0) 41 | jekyll-default-layout (= 0.1.4) 42 | jekyll-feed (= 0.15.1) 43 | jekyll-gist (= 1.5.0) 44 | jekyll-github-metadata (= 2.13.0) 45 | jekyll-include-cache (= 0.2.1) 46 | jekyll-mentions (= 1.6.0) 47 | jekyll-optional-front-matter (= 0.3.2) 48 | jekyll-paginate (= 1.1.0) 49 | jekyll-readme-index (= 0.3.0) 50 | jekyll-redirect-from (= 0.16.0) 51 | jekyll-relative-links (= 0.6.1) 52 | jekyll-remote-theme (= 0.4.3) 53 | jekyll-sass-converter (= 1.5.2) 54 | jekyll-seo-tag (= 2.8.0) 55 | jekyll-sitemap (= 1.4.0) 56 | jekyll-swiss (= 1.0.0) 57 | jekyll-theme-architect (= 0.2.0) 58 | jekyll-theme-cayman (= 0.2.0) 59 | jekyll-theme-dinky (= 0.2.0) 60 | jekyll-theme-hacker (= 0.2.0) 61 | jekyll-theme-leap-day (= 0.2.0) 62 | jekyll-theme-merlot (= 0.2.0) 63 | jekyll-theme-midnight (= 0.2.0) 64 | jekyll-theme-minimal (= 0.2.0) 65 | jekyll-theme-modernist (= 0.2.0) 66 | jekyll-theme-primer (= 0.6.0) 67 | jekyll-theme-slate (= 0.2.0) 68 | jekyll-theme-tactile (= 0.2.0) 69 | jekyll-theme-time-machine (= 0.2.0) 70 | jekyll-titles-from-headings (= 0.5.3) 71 | jemoji (= 0.12.0) 72 | kramdown (= 2.3.2) 73 | kramdown-parser-gfm (= 1.1.0) 74 | liquid (= 4.0.3) 75 | mercenary (~> 0.3) 76 | minima (= 2.5.1) 77 | nokogiri (>= 1.13.6, < 2.0) 78 | rouge (= 3.26.0) 79 | terminal-table (~> 1.4) 80 | github-pages-health-check (1.17.9) 81 | addressable (~> 2.3) 82 | dnsruby (~> 1.60) 83 | octokit (~> 4.0) 84 | public_suffix (>= 3.0, < 5.0) 85 | typhoeus (~> 1.3) 86 | html-pipeline (2.14.2) 87 | activesupport (>= 2) 88 | nokogiri (>= 1.4) 89 | http_parser.rb (0.8.0) 90 | i18n (0.9.5) 91 | concurrent-ruby (~> 1.0) 92 | jekyll (3.9.2) 93 | addressable (~> 2.4) 94 | colorator (~> 1.0) 95 | em-websocket (~> 0.5) 96 | i18n (~> 0.7) 97 | jekyll-sass-converter (~> 1.0) 98 | jekyll-watch (~> 2.0) 99 | kramdown (>= 1.17, < 3) 100 | liquid (~> 4.0) 101 | mercenary (~> 0.3.3) 102 | pathutil (~> 0.9) 103 | rouge (>= 1.7, < 4) 104 | safe_yaml (~> 1.0) 105 | jekyll-avatar (0.7.0) 106 | jekyll (>= 3.0, < 5.0) 107 | jekyll-coffeescript (1.1.1) 108 | coffee-script (~> 2.2) 109 | coffee-script-source (~> 1.11.1) 110 | jekyll-commonmark (1.4.0) 111 | commonmarker (~> 0.22) 112 | jekyll-commonmark-ghpages (0.2.0) 113 | commonmarker (~> 0.23.4) 114 | jekyll (~> 3.9.0) 115 | jekyll-commonmark (~> 1.4.0) 116 | rouge (>= 2.0, < 4.0) 117 | jekyll-default-layout (0.1.4) 118 | jekyll (~> 3.0) 119 | jekyll-feed (0.15.1) 120 | jekyll (>= 3.7, < 5.0) 121 | jekyll-gist (1.5.0) 122 | octokit (~> 4.2) 123 | jekyll-github-metadata (2.13.0) 124 | jekyll (>= 3.4, < 5.0) 125 | octokit (~> 4.0, != 4.4.0) 126 | jekyll-include-cache (0.2.1) 127 | jekyll (>= 3.7, < 5.0) 128 | jekyll-mentions (1.6.0) 129 | html-pipeline (~> 2.3) 130 | jekyll (>= 3.7, < 5.0) 131 | jekyll-optional-front-matter (0.3.2) 132 | jekyll (>= 3.0, < 5.0) 133 | jekyll-paginate (1.1.0) 134 | jekyll-readme-index (0.3.0) 135 | jekyll (>= 3.0, < 5.0) 136 | jekyll-redirect-from (0.16.0) 137 | jekyll (>= 3.3, < 5.0) 138 | jekyll-relative-links (0.6.1) 139 | jekyll (>= 3.3, < 5.0) 140 | jekyll-remote-theme (0.4.3) 141 | addressable (~> 2.0) 142 | jekyll (>= 3.5, < 5.0) 143 | jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) 144 | rubyzip (>= 1.3.0, < 3.0) 145 | jekyll-sass-converter (1.5.2) 146 | sass (~> 3.4) 147 | jekyll-seo-tag (2.8.0) 148 | jekyll (>= 3.8, < 5.0) 149 | jekyll-sitemap (1.4.0) 150 | jekyll (>= 3.7, < 5.0) 151 | jekyll-swiss (1.0.0) 152 | jekyll-theme-architect (0.2.0) 153 | jekyll (> 3.5, < 5.0) 154 | jekyll-seo-tag (~> 2.0) 155 | jekyll-theme-cayman (0.2.0) 156 | jekyll (> 3.5, < 5.0) 157 | jekyll-seo-tag (~> 2.0) 158 | jekyll-theme-dinky (0.2.0) 159 | jekyll (> 3.5, < 5.0) 160 | jekyll-seo-tag (~> 2.0) 161 | jekyll-theme-hacker (0.2.0) 162 | jekyll (> 3.5, < 5.0) 163 | jekyll-seo-tag (~> 2.0) 164 | jekyll-theme-leap-day (0.2.0) 165 | jekyll (> 3.5, < 5.0) 166 | jekyll-seo-tag (~> 2.0) 167 | jekyll-theme-merlot (0.2.0) 168 | jekyll (> 3.5, < 5.0) 169 | jekyll-seo-tag (~> 2.0) 170 | jekyll-theme-midnight (0.2.0) 171 | jekyll (> 3.5, < 5.0) 172 | jekyll-seo-tag (~> 2.0) 173 | jekyll-theme-minimal (0.2.0) 174 | jekyll (> 3.5, < 5.0) 175 | jekyll-seo-tag (~> 2.0) 176 | jekyll-theme-modernist (0.2.0) 177 | jekyll (> 3.5, < 5.0) 178 | jekyll-seo-tag (~> 2.0) 179 | jekyll-theme-primer (0.6.0) 180 | jekyll (> 3.5, < 5.0) 181 | jekyll-github-metadata (~> 2.9) 182 | jekyll-seo-tag (~> 2.0) 183 | jekyll-theme-slate (0.2.0) 184 | jekyll (> 3.5, < 5.0) 185 | jekyll-seo-tag (~> 2.0) 186 | jekyll-theme-tactile (0.2.0) 187 | jekyll (> 3.5, < 5.0) 188 | jekyll-seo-tag (~> 2.0) 189 | jekyll-theme-time-machine (0.2.0) 190 | jekyll (> 3.5, < 5.0) 191 | jekyll-seo-tag (~> 2.0) 192 | jekyll-titles-from-headings (0.5.3) 193 | jekyll (>= 3.3, < 5.0) 194 | jekyll-watch (2.2.1) 195 | listen (~> 3.0) 196 | jemoji (0.12.0) 197 | gemoji (~> 3.0) 198 | html-pipeline (~> 2.2) 199 | jekyll (>= 3.0, < 5.0) 200 | kramdown (2.3.2) 201 | rexml 202 | kramdown-parser-gfm (1.1.0) 203 | kramdown (~> 2.0) 204 | liquid (4.0.3) 205 | listen (3.7.1) 206 | rb-fsevent (~> 0.10, >= 0.10.3) 207 | rb-inotify (~> 0.9, >= 0.9.10) 208 | mercenary (0.3.6) 209 | minima (2.5.1) 210 | jekyll (>= 3.5, < 5.0) 211 | jekyll-feed (~> 0.9) 212 | jekyll-seo-tag (~> 2.1) 213 | minitest (5.16.2) 214 | nokogiri (1.13.7-x86_64-linux) 215 | racc (~> 1.4) 216 | octokit (4.25.1) 217 | faraday (>= 1, < 3) 218 | sawyer (~> 0.9) 219 | pathutil (0.16.2) 220 | forwardable-extended (~> 2.6) 221 | public_suffix (4.0.7) 222 | racc (1.6.0) 223 | rb-fsevent (0.11.1) 224 | rb-inotify (0.10.1) 225 | ffi (~> 1.0) 226 | rexml (3.2.5) 227 | rouge (3.26.0) 228 | ruby2_keywords (0.0.5) 229 | rubyzip (2.3.2) 230 | safe_yaml (1.0.5) 231 | sass (3.7.4) 232 | sass-listen (~> 4.0.0) 233 | sass-listen (4.0.0) 234 | rb-fsevent (~> 0.9, >= 0.9.4) 235 | rb-inotify (~> 0.9, >= 0.9.7) 236 | sawyer (0.9.2) 237 | addressable (>= 2.3.5) 238 | faraday (>= 0.17.3, < 3) 239 | simpleidn (0.2.1) 240 | unf (~> 0.1.4) 241 | terminal-table (1.8.0) 242 | unicode-display_width (~> 1.1, >= 1.1.1) 243 | thread_safe (0.3.6) 244 | typhoeus (1.4.0) 245 | ethon (>= 0.9.0) 246 | tzinfo (1.2.9) 247 | thread_safe (~> 0.1) 248 | unf (0.1.4) 249 | unf_ext 250 | unf_ext (0.0.8.2) 251 | unicode-display_width (1.8.0) 252 | webrick (1.7.0) 253 | zeitwerk (2.6.0) 254 | 255 | PLATFORMS 256 | x86_64-linux 257 | 258 | DEPENDENCIES 259 | github-pages 260 | jekyll-include-cache 261 | webrick 262 | 263 | BUNDLED WITH 264 | 2.3.18 265 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "atty" 7 | version = "0.2.14" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 10 | dependencies = [ 11 | "hermit-abi", 12 | "libc", 13 | "winapi", 14 | ] 15 | 16 | [[package]] 17 | name = "autocfg" 18 | version = "1.1.0" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 21 | 22 | [[package]] 23 | name = "bindgen" 24 | version = "0.65.1" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" 27 | dependencies = [ 28 | "bitflags", 29 | "cexpr", 30 | "clang-sys", 31 | "lazy_static", 32 | "lazycell", 33 | "log", 34 | "peeking_take_while", 35 | "prettyplease", 36 | "proc-macro2", 37 | "quote", 38 | "regex", 39 | "rustc-hash", 40 | "shlex", 41 | "syn 2.0.18", 42 | "which", 43 | ] 44 | 45 | [[package]] 46 | name = "bitflags" 47 | version = "1.3.2" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 50 | 51 | [[package]] 52 | name = "bunt" 53 | version = "0.2.6" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "192bac6c13e04373feb683e4438cbc156e6bbe432f614a9d6247445108fc5551" 56 | dependencies = [ 57 | "bunt-macros", 58 | "termcolor", 59 | ] 60 | 61 | [[package]] 62 | name = "bunt-macros" 63 | version = "0.2.5" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "181ae31bbb8b46f840a70dc1323ad938f2cd7a504e7adc98d6fe58094900a680" 66 | dependencies = [ 67 | "litrs", 68 | "proc-macro2", 69 | "quote", 70 | "unicode-xid", 71 | ] 72 | 73 | [[package]] 74 | name = "cexpr" 75 | version = "0.6.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 78 | dependencies = [ 79 | "nom", 80 | ] 81 | 82 | [[package]] 83 | name = "cfg-if" 84 | version = "1.0.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 87 | 88 | [[package]] 89 | name = "clang-sys" 90 | version = "1.6.1" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" 93 | dependencies = [ 94 | "glob", 95 | "libc", 96 | "libloading", 97 | ] 98 | 99 | [[package]] 100 | name = "clap" 101 | version = "3.2.11" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "d646c7ade5eb07c4aa20e907a922750df0c448892513714fd3e4acbc7130829f" 104 | dependencies = [ 105 | "atty", 106 | "bitflags", 107 | "clap_derive", 108 | "clap_lex", 109 | "indexmap", 110 | "once_cell", 111 | "strsim", 112 | "termcolor", 113 | "textwrap", 114 | ] 115 | 116 | [[package]] 117 | name = "clap_derive" 118 | version = "3.2.7" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" 121 | dependencies = [ 122 | "heck", 123 | "proc-macro-error", 124 | "proc-macro2", 125 | "quote", 126 | "syn 1.0.98", 127 | ] 128 | 129 | [[package]] 130 | name = "clap_lex" 131 | version = "0.2.4" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 134 | dependencies = [ 135 | "os_str_bytes", 136 | ] 137 | 138 | [[package]] 139 | name = "either" 140 | version = "1.8.1" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 143 | 144 | [[package]] 145 | name = "glob" 146 | version = "0.3.1" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 149 | 150 | [[package]] 151 | name = "hashbrown" 152 | version = "0.12.2" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" 155 | 156 | [[package]] 157 | name = "heck" 158 | version = "0.4.0" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 161 | 162 | [[package]] 163 | name = "hermit-abi" 164 | version = "0.1.19" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 167 | dependencies = [ 168 | "libc", 169 | ] 170 | 171 | [[package]] 172 | name = "indexmap" 173 | version = "1.9.1" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 176 | dependencies = [ 177 | "autocfg", 178 | "hashbrown", 179 | ] 180 | 181 | [[package]] 182 | name = "lazy_static" 183 | version = "1.4.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 186 | 187 | [[package]] 188 | name = "lazycell" 189 | version = "1.3.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 192 | 193 | [[package]] 194 | name = "libc" 195 | version = "0.2.126" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 198 | 199 | [[package]] 200 | name = "libloading" 201 | version = "0.7.4" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 204 | dependencies = [ 205 | "cfg-if", 206 | "winapi", 207 | ] 208 | 209 | [[package]] 210 | name = "litrs" 211 | version = "0.2.3" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "f9275e0933cf8bb20f008924c0cb07a0692fe54d8064996520bf998de9eb79aa" 214 | dependencies = [ 215 | "proc-macro2", 216 | ] 217 | 218 | [[package]] 219 | name = "log" 220 | version = "0.4.19" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" 223 | 224 | [[package]] 225 | name = "memchr" 226 | version = "2.5.0" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 229 | 230 | [[package]] 231 | name = "minimal-lexical" 232 | version = "0.2.1" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 235 | 236 | [[package]] 237 | name = "nom" 238 | version = "7.1.3" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 241 | dependencies = [ 242 | "memchr", 243 | "minimal-lexical", 244 | ] 245 | 246 | [[package]] 247 | name = "nvapi_sys_new" 248 | version = "1.530.1" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "121d6bf56723d69df42277e7c32d4fb3464297edf025dcd6be10b961b2337737" 251 | dependencies = [ 252 | "bindgen", 253 | ] 254 | 255 | [[package]] 256 | name = "nvcli" 257 | version = "1.1.4" 258 | dependencies = [ 259 | "bunt", 260 | "clap", 261 | "nvapi_sys_new", 262 | ] 263 | 264 | [[package]] 265 | name = "once_cell" 266 | version = "1.13.0" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" 269 | 270 | [[package]] 271 | name = "os_str_bytes" 272 | version = "6.1.0" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" 275 | 276 | [[package]] 277 | name = "peeking_take_while" 278 | version = "0.1.2" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 281 | 282 | [[package]] 283 | name = "prettyplease" 284 | version = "0.2.7" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "43ded2b5b204571f065ab8540367d738dfe1b3606ab9eb669dcfb5e7a3a07501" 287 | dependencies = [ 288 | "proc-macro2", 289 | "syn 2.0.18", 290 | ] 291 | 292 | [[package]] 293 | name = "proc-macro-error" 294 | version = "1.0.4" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 297 | dependencies = [ 298 | "proc-macro-error-attr", 299 | "proc-macro2", 300 | "quote", 301 | "syn 1.0.98", 302 | "version_check", 303 | ] 304 | 305 | [[package]] 306 | name = "proc-macro-error-attr" 307 | version = "1.0.4" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 310 | dependencies = [ 311 | "proc-macro2", 312 | "quote", 313 | "version_check", 314 | ] 315 | 316 | [[package]] 317 | name = "proc-macro2" 318 | version = "1.0.60" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" 321 | dependencies = [ 322 | "unicode-ident", 323 | ] 324 | 325 | [[package]] 326 | name = "quote" 327 | version = "1.0.28" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" 330 | dependencies = [ 331 | "proc-macro2", 332 | ] 333 | 334 | [[package]] 335 | name = "regex" 336 | version = "1.8.4" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" 339 | dependencies = [ 340 | "regex-syntax", 341 | ] 342 | 343 | [[package]] 344 | name = "regex-syntax" 345 | version = "0.7.2" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" 348 | 349 | [[package]] 350 | name = "rustc-hash" 351 | version = "1.1.0" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 354 | 355 | [[package]] 356 | name = "shlex" 357 | version = "1.1.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" 360 | 361 | [[package]] 362 | name = "strsim" 363 | version = "0.10.0" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 366 | 367 | [[package]] 368 | name = "syn" 369 | version = "1.0.98" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" 372 | dependencies = [ 373 | "proc-macro2", 374 | "quote", 375 | "unicode-ident", 376 | ] 377 | 378 | [[package]] 379 | name = "syn" 380 | version = "2.0.18" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" 383 | dependencies = [ 384 | "proc-macro2", 385 | "quote", 386 | "unicode-ident", 387 | ] 388 | 389 | [[package]] 390 | name = "termcolor" 391 | version = "1.1.3" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 394 | dependencies = [ 395 | "winapi-util", 396 | ] 397 | 398 | [[package]] 399 | name = "textwrap" 400 | version = "0.15.0" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" 403 | 404 | [[package]] 405 | name = "unicode-ident" 406 | version = "1.0.1" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" 409 | 410 | [[package]] 411 | name = "unicode-xid" 412 | version = "0.2.3" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" 415 | 416 | [[package]] 417 | name = "version_check" 418 | version = "0.9.4" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 421 | 422 | [[package]] 423 | name = "which" 424 | version = "4.4.0" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" 427 | dependencies = [ 428 | "either", 429 | "libc", 430 | "once_cell", 431 | ] 432 | 433 | [[package]] 434 | name = "winapi" 435 | version = "0.3.9" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 438 | dependencies = [ 439 | "winapi-i686-pc-windows-gnu", 440 | "winapi-x86_64-pc-windows-gnu", 441 | ] 442 | 443 | [[package]] 444 | name = "winapi-i686-pc-windows-gnu" 445 | version = "0.4.0" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 448 | 449 | [[package]] 450 | name = "winapi-util" 451 | version = "0.1.5" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 454 | dependencies = [ 455 | "winapi", 456 | ] 457 | 458 | [[package]] 459 | name = "winapi-x86_64-pc-windows-gnu" 460 | version = "0.4.0" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 463 | --------------------------------------------------------------------------------