Compare commits
10 Commits
89e64d3896
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 3fb5042e64 | |||
| ee71c28dcc | |||
| 60a5340895 | |||
| f31af10c9f | |||
| c72001a991 | |||
| a119162d28 | |||
| eb6903e8a3 | |||
| 5b81f2bef6 | |||
| cddd54ee33 | |||
| 62e36cd0a2 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -203,7 +203,7 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "practicalrunner"
|
name = "practicalrunner"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"fontconfig",
|
"fontconfig",
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "practicalrunner"
|
name = "practicalrunner"
|
||||||
description = "A practical application runner"
|
description = "A practical application runner"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
authors = ["409"]
|
authors = ["409"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "MIT"
|
||||||
|
homepage = "https://github.com/4-0-9/practical-runner"
|
||||||
|
repository = "https://github.com/4-0-9/practical-runner"
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "z"
|
opt-level = "z"
|
||||||
|
|||||||
35
README.md
35
README.md
@@ -2,8 +2,43 @@
|
|||||||
|
|
||||||
A practical application runner written in Rust. Inspired by [dmenu](https://tools.suckless.org/dmenu/)
|
A practical application runner written in Rust. Inspired by [dmenu](https://tools.suckless.org/dmenu/)
|
||||||
|
|
||||||
|
|
||||||
|
### Screenshots
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- theming (colors, font family, font size, line spacing, window border)
|
- theming (colors, font family, font size, line spacing, window border)
|
||||||
- custom row count
|
- custom row count
|
||||||
|
- smart row scrolling
|
||||||
- prompt message
|
- prompt message
|
||||||
- open menu on a specific display
|
- open menu on a specific display
|
||||||
|
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
To use practical-runner run the following command:
|
||||||
|
```console
|
||||||
|
cargo install practicalrunner
|
||||||
|
```
|
||||||
|
Or clone this repository and run the following command in the repository's root directory:
|
||||||
|
```console
|
||||||
|
cargo install --path .
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
```console
|
||||||
|
practicalrunner
|
||||||
|
```
|
||||||
|
For information about the various arguments run the following command:
|
||||||
|
```console
|
||||||
|
practicalrunner --help
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Controls
|
||||||
|
- [enter] to run the selected suggestion
|
||||||
|
- [up] / [down] arrow to scroll the suggestions
|
||||||
|
- [escape] / [ctrl-c] to quit
|
||||||
|
|||||||
BIN
screenshots/screenshot-1716407683.webp
Normal file
BIN
screenshots/screenshot-1716407683.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
screenshots/screenshot-1716407811.webp
Normal file
BIN
screenshots/screenshot-1716407811.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
BIN
screenshots/screenshot-1716408039.webp
Normal file
BIN
screenshots/screenshot-1716408039.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
@@ -8,7 +8,7 @@ use sdl2::{
|
|||||||
render::{Canvas, WindowCanvas},
|
render::{Canvas, WindowCanvas},
|
||||||
ttf,
|
ttf,
|
||||||
video::Window,
|
video::Window,
|
||||||
Sdl,
|
Sdl, VideoSubsystem,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -26,6 +26,7 @@ pub struct Runner {
|
|||||||
input: String,
|
input: String,
|
||||||
window_size: (u32, u32),
|
window_size: (u32, u32),
|
||||||
settings: RunnerMenuSettings,
|
settings: RunnerMenuSettings,
|
||||||
|
target_display_index: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Runner {
|
impl Runner {
|
||||||
@@ -59,43 +60,43 @@ impl Runner {
|
|||||||
|
|
||||||
let video = context.video().expect("Error initializing SDL video");
|
let video = context.video().expect("Error initializing SDL video");
|
||||||
|
|
||||||
let (mut window_x, mut window_y): (i32, i32) = (0, 0);
|
|
||||||
|
|
||||||
match settings.display_index {
|
|
||||||
Some(display) => {
|
|
||||||
if (display as i32).lt(&video
|
|
||||||
.num_video_displays()
|
|
||||||
.expect("Error getting number of displays"))
|
|
||||||
{
|
|
||||||
let bounds = video
|
|
||||||
.display_bounds(display.into())
|
|
||||||
.expect(&format!("Error getting bounds for display {}", display));
|
|
||||||
|
|
||||||
window_x = bounds.x() + (bounds.width().div_euclid(2) as i32)
|
|
||||||
- window_width.div_euclid(2) as i32;
|
|
||||||
window_y = bounds.y() + (bounds.height().div_euclid(2) as i32)
|
|
||||||
- window_height.div_euclid(2) as i32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let window = video
|
let window = video
|
||||||
.window("Practical runner", window_width, window_height)
|
.window("Practical runner", window_width, window_height)
|
||||||
.borderless()
|
.borderless()
|
||||||
.always_on_top()
|
.always_on_top()
|
||||||
|
.set_shaped()
|
||||||
.build()
|
.build()
|
||||||
.expect("Error creating window");
|
.expect("Error creating window");
|
||||||
|
|
||||||
let mut canvas = window.into_canvas().build().expect("Error creating canvas");
|
let mut canvas = window.into_canvas().build().expect("Error creating canvas");
|
||||||
|
|
||||||
canvas.present();
|
canvas.present();
|
||||||
if window_x.ne(&0) || window_y.ne(&0) {
|
|
||||||
canvas.window_mut().set_position(
|
// If we don't call this before window.display_index() it always returns 0
|
||||||
sdl2::video::WindowPos::Positioned(window_x),
|
let _ = context
|
||||||
sdl2::video::WindowPos::Positioned(window_y),
|
.event_pump()
|
||||||
);
|
.expect("Error getting SDL event pump")
|
||||||
|
.poll_iter()
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let target_display_index: Option<i32>;
|
||||||
|
|
||||||
|
let current_display_index = canvas
|
||||||
|
.window()
|
||||||
|
.display_index()
|
||||||
|
.expect("Error getting window display index");
|
||||||
|
|
||||||
|
match settings.display_index {
|
||||||
|
Some(display_index) => {
|
||||||
|
target_display_index = Some(current_display_index);
|
||||||
|
center_on_display(canvas.window_mut(), display_index.into(), &video);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
target_display_index = None;
|
||||||
|
center_on_display(canvas.window_mut(), current_display_index.into(), &video);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.window_mut().raise();
|
canvas.window_mut().raise();
|
||||||
|
|
||||||
let mut cloned_executables = executables.clone();
|
let mut cloned_executables = executables.clone();
|
||||||
@@ -111,6 +112,7 @@ impl Runner {
|
|||||||
window_size: (window_width, window_height),
|
window_size: (window_width, window_height),
|
||||||
settings,
|
settings,
|
||||||
font_path,
|
font_path,
|
||||||
|
target_display_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +140,11 @@ impl Runner {
|
|||||||
let mut event_pump = self.context.event_pump().unwrap();
|
let mut event_pump = self.context.event_pump().unwrap();
|
||||||
|
|
||||||
'run: loop {
|
'run: loop {
|
||||||
|
if !self.canvas.window().has_input_focus() {
|
||||||
|
self.input.clear();
|
||||||
|
break 'run;
|
||||||
|
}
|
||||||
|
|
||||||
self.canvas.set_draw_color(background_color);
|
self.canvas.set_draw_color(background_color);
|
||||||
self.canvas.clear();
|
self.canvas.clear();
|
||||||
self.canvas.set_draw_color(border_color);
|
self.canvas.set_draw_color(border_color);
|
||||||
@@ -329,12 +336,33 @@ impl Runner {
|
|||||||
|
|
||||||
self.canvas.present();
|
self.canvas.present();
|
||||||
|
|
||||||
std::thread::sleep(Duration::from_millis(8))
|
std::thread::sleep(Duration::from_millis(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.input.is_empty() {
|
if self.input.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
match self.target_display_index {
|
||||||
|
Some(target_display_index) => {
|
||||||
|
let window = self.canvas.window_mut();
|
||||||
|
let target_display_bounds = self
|
||||||
|
.context
|
||||||
|
.video()
|
||||||
|
.expect("Error getting SDL video")
|
||||||
|
.display_bounds(target_display_index)
|
||||||
|
.expect("Error getting target display bounds");
|
||||||
|
|
||||||
|
window.set_position(
|
||||||
|
sdl2::video::WindowPos::Positioned(target_display_bounds.x()),
|
||||||
|
sdl2::video::WindowPos::Positioned(target_display_bounds.y()),
|
||||||
|
);
|
||||||
|
|
||||||
|
window.raise();
|
||||||
|
window.hide();
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
|
||||||
Some(self.input.clone())
|
Some(self.input.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,3 +401,28 @@ fn draw_borders(border_size: u8, window_size: (u32, u32), canvas: &mut WindowCan
|
|||||||
let _ = canvas.fill_rect(Rect::new(0, 0, border_size.into(), window_size.1));
|
let _ = canvas.fill_rect(Rect::new(0, 0, border_size.into(), window_size.1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn center_on_display(window: &mut Window, display_index: i32, video: &VideoSubsystem) {
|
||||||
|
if (display_index as i32).lt(&video
|
||||||
|
.num_video_displays()
|
||||||
|
.expect("Error getting number of displays"))
|
||||||
|
{
|
||||||
|
let bounds = video.display_bounds(display_index.into()).expect(&format!(
|
||||||
|
"Error getting bounds for display {}",
|
||||||
|
display_index
|
||||||
|
));
|
||||||
|
|
||||||
|
let window_size = window.size();
|
||||||
|
|
||||||
|
window.set_position(
|
||||||
|
sdl2::video::WindowPos::Positioned(
|
||||||
|
bounds.x() + bounds.width().div_euclid(2) as i32
|
||||||
|
- window_size.0.div_euclid(2) as i32,
|
||||||
|
),
|
||||||
|
sdl2::video::WindowPos::Positioned(
|
||||||
|
bounds.y() + bounds.height().div_euclid(2) as i32
|
||||||
|
- window_size.1.div_euclid(2) as i32,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user