Add touchscreen support with onscreen keyboard (#1)
Possible that framebuffer doesn't update without actual keypress (eg, volume down). But, works.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
Audio player with playlist and folder support.
|
Audio player with playlist and folder support. Requires the dev version of `alsa` lib.
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
|
|||||||
1
docs/window-likes/onscreen-keyboard.md
Normal file
1
docs/window-likes/onscreen-keyboard.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is primarily intended for mobile users.
|
||||||
@@ -12,6 +12,7 @@ fn main() {
|
|||||||
height: fb.var_screen_info.yres_virtual as usize,
|
height: fb.var_screen_info.yres_virtual as usize,
|
||||||
bytes_per_pixel,
|
bytes_per_pixel,
|
||||||
stride: fb.fix_screen_info.line_length as usize / bytes_per_pixel,
|
stride: fb.fix_screen_info.line_length as usize / bytes_per_pixel,
|
||||||
|
old_stride: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
init(fb, fb_info);
|
init(fb, fb_info);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use crate::window_manager::DrawInstructions;
|
|||||||
pub mod toggle_button;
|
pub mod toggle_button;
|
||||||
pub mod highlight_button;
|
pub mod highlight_button;
|
||||||
pub mod paragraph;
|
pub mod paragraph;
|
||||||
|
pub mod press_button;
|
||||||
|
|
||||||
pub trait Component<T> {
|
pub trait Component<T> {
|
||||||
fn handle_message(&mut self, message: WindowMessage) -> Option<T>;
|
fn handle_message(&mut self, message: WindowMessage) -> Option<T>;
|
||||||
@@ -17,6 +18,7 @@ pub trait Component<T> {
|
|||||||
//focusing for components is purely to give a visual representation
|
//focusing for components is purely to give a visual representation
|
||||||
fn focusable(&self) -> bool;
|
fn focusable(&self) -> bool;
|
||||||
fn clickable(&self) -> bool;
|
fn clickable(&self) -> bool;
|
||||||
|
//fn pressable(&self) -> bool; //touch
|
||||||
fn name(&self) -> &String; //should be unique
|
fn name(&self) -> &String; //should be unique
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
69
src/components/press_button.rs
Normal file
69
src/components/press_button.rs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
use std::vec;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
use crate::components::Component;
|
||||||
|
use crate::framebuffer::{ Dimensions, Point };
|
||||||
|
use crate::themes::ThemeInfo;
|
||||||
|
use crate::messages::WindowMessage;
|
||||||
|
use crate::window_manager::{ DrawInstructions };
|
||||||
|
|
||||||
|
const MONO_WIDTH: u8 = 10;
|
||||||
|
|
||||||
|
pub struct PressButton<T> {
|
||||||
|
pub top_left: Point,
|
||||||
|
pub size: Dimensions,
|
||||||
|
text: String,
|
||||||
|
press_return: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Component<T> for PressButton<T> {
|
||||||
|
//
|
||||||
|
fn handle_message(&mut self, message: WindowMessage) -> Option<T> {
|
||||||
|
match message {
|
||||||
|
WindowMessage::Touch(_, _) => {
|
||||||
|
//assume that the parent window-like passed it to us intentionally and checked already
|
||||||
|
//we can check again, but why?
|
||||||
|
Some(self.press_return.clone())
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
||||||
|
let half = self.size[0] / 2 - self.text.len() * MONO_WIDTH as usize / 2;
|
||||||
|
vec![
|
||||||
|
DrawInstructions::Rect(self.top_left, [self.size[0], 1], theme_info.border_left_top),
|
||||||
|
DrawInstructions::Rect(self.top_left, [1, self.size[1]], theme_info.border_left_top),
|
||||||
|
DrawInstructions::Rect([self.top_left[0], self.top_left[1] + self.size[1]], [self.size[0], 1], theme_info.border_right_bottom),
|
||||||
|
DrawInstructions::Rect([self.top_left[0] + self.size[0], self.top_left[1]], [1, self.size[1]], theme_info.border_right_bottom),
|
||||||
|
//assume normal background colour
|
||||||
|
DrawInstructions::Text([self.top_left[0] + half, self.top_left[1] + 8], vec!["times-new-romono".to_string()], self.text.clone(), theme_info.text, theme_info.background, Some(0), Some(MONO_WIDTH)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
//properties
|
||||||
|
fn focusable(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clickable(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &String {
|
||||||
|
//sorry
|
||||||
|
&self.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PressButton<T> {
|
||||||
|
pub fn new(top_left: Point, size: Dimensions, text: String, press_return: T) -> Self {
|
||||||
|
Self {
|
||||||
|
top_left,
|
||||||
|
size,
|
||||||
|
text,
|
||||||
|
press_return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ pub mod taskbar;
|
|||||||
pub mod lock_screen;
|
pub mod lock_screen;
|
||||||
pub mod workspace_indicator;
|
pub mod workspace_indicator;
|
||||||
pub mod start_menu;
|
pub mod start_menu;
|
||||||
|
pub mod onscreen_keyboard;
|
||||||
|
|
||||||
pub mod about;
|
pub mod about;
|
||||||
pub mod help;
|
pub mod help;
|
||||||
|
|||||||
200
src/essential/onscreen_keyboard.rs
Normal file
200
src/essential/onscreen_keyboard.rs
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
use std::vec;
|
||||||
|
use std::vec::Vec;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::window_manager::{ DrawInstructions, WindowLike, WindowLikeType, KeyChar };
|
||||||
|
use crate::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest };
|
||||||
|
use crate::framebuffer::Dimensions;
|
||||||
|
use crate::themes::ThemeInfo;
|
||||||
|
use crate::components::Component;
|
||||||
|
use crate::components::press_button::PressButton;
|
||||||
|
use crate::utils::point_inside;
|
||||||
|
|
||||||
|
//seems like framebuffer only updates if (real) key is pressed...
|
||||||
|
//on mobile, volume down button seems to work but is annoying
|
||||||
|
|
||||||
|
const PADDING_Y: usize = 15;
|
||||||
|
const PADDING_X: usize = 15;
|
||||||
|
//padding in between keys in the x direction
|
||||||
|
const KEY_PADDING_X: usize = 5;
|
||||||
|
const KEY_PADDING_Y: usize = 5;
|
||||||
|
|
||||||
|
#[derive(Clone, Default, Eq, PartialEq, Hash)]
|
||||||
|
enum Board {
|
||||||
|
#[default]
|
||||||
|
Regular,
|
||||||
|
Shift,
|
||||||
|
Symbols,
|
||||||
|
SymbolsShift,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Board {
|
||||||
|
fn inc(&mut self) -> Self {
|
||||||
|
match self {
|
||||||
|
Board::Regular => Board::Shift,
|
||||||
|
Board::Shift => Board::Symbols,
|
||||||
|
Board::Symbols => Board::SymbolsShift,
|
||||||
|
Board::SymbolsShift => Board::Regular,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum KeyResponse {
|
||||||
|
Key(char),
|
||||||
|
Alt,
|
||||||
|
Ctrl,
|
||||||
|
SwitchBoard,
|
||||||
|
}
|
||||||
|
|
||||||
|
//if alt is true and ctrl is true, only alt will be sent.
|
||||||
|
//because I don't care about ctrl+alt stuff, and won't use it.
|
||||||
|
//(and probably not supported by this with a real keyboard anyways)
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct OnscreenKeyboard {
|
||||||
|
dimensions: Dimensions,
|
||||||
|
components: Vec<Box<PressButton<KeyResponse>>>,
|
||||||
|
alt: bool,
|
||||||
|
ctrl: bool,
|
||||||
|
board: Board,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowLike for OnscreenKeyboard {
|
||||||
|
fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse {
|
||||||
|
match message {
|
||||||
|
WindowMessage::Init(dimensions) => {
|
||||||
|
self.dimensions = dimensions;
|
||||||
|
self.set_key_components();
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
},
|
||||||
|
WindowMessage::Touch(x, y) => {
|
||||||
|
for c in &mut self.components {
|
||||||
|
if point_inside([x, y], c.top_left, c.size) {
|
||||||
|
let returned = c.handle_message(WindowMessage::Touch(x, y));
|
||||||
|
if let Some(returned) = returned {
|
||||||
|
return match returned {
|
||||||
|
KeyResponse::Key(ch) => {
|
||||||
|
let kc = if self.alt {
|
||||||
|
self.alt = false;
|
||||||
|
KeyChar::Alt(ch)
|
||||||
|
} else if self.ctrl {
|
||||||
|
self.ctrl = false;
|
||||||
|
KeyChar::Ctrl(ch)
|
||||||
|
} else {
|
||||||
|
KeyChar::Press(ch)
|
||||||
|
};
|
||||||
|
WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(kc))
|
||||||
|
},
|
||||||
|
KeyResponse::Alt => {
|
||||||
|
self.alt = !self.alt;
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
},
|
||||||
|
KeyResponse::Ctrl => {
|
||||||
|
self.ctrl = !self.ctrl;
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
},
|
||||||
|
KeyResponse::SwitchBoard => {
|
||||||
|
self.board = self.board.inc();
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
},
|
||||||
|
_ => WindowMessageResponse::DoNothing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
||||||
|
let mut instructions = vec![DrawInstructions::Rect([0, 0], self.dimensions, theme_info.background)];
|
||||||
|
for component in &self.components {
|
||||||
|
instructions.extend(component.draw(theme_info));
|
||||||
|
}
|
||||||
|
instructions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subtype(&self) -> WindowLikeType {
|
||||||
|
WindowLikeType::OnscreenKeyboard
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ideal_dimensions(&self, dimensions: Dimensions) -> Dimensions {
|
||||||
|
[dimensions[0] - 175, 250]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OnscreenKeyboard {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_key_components(&mut self) {
|
||||||
|
self.components = Vec::new();
|
||||||
|
let rows: [HashMap<Board, Vec<char>>; 4] = [
|
||||||
|
HashMap::from([
|
||||||
|
(Board::Regular, vec!['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p']),
|
||||||
|
(Board::Shift, vec!['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P']),
|
||||||
|
(Board::Symbols, vec!['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']),
|
||||||
|
(Board::SymbolsShift, vec![]), //empty
|
||||||
|
]),
|
||||||
|
HashMap::from([
|
||||||
|
(Board::Regular, vec!['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l']),
|
||||||
|
(Board::Shift, vec!['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L']),
|
||||||
|
(Board::Symbols, vec!['|', '=', '$', '%', '&', '-', '+', '(', ')']),
|
||||||
|
(Board::SymbolsShift, vec!['`', '@', '#', '^']),
|
||||||
|
]),
|
||||||
|
HashMap::from([
|
||||||
|
(Board::Regular, vec!['𐘃', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '𐘁']), //escape and backspace
|
||||||
|
(Board::Shift, vec!['𐘃', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '𐘁']), //escape and backspace
|
||||||
|
(Board::Symbols, vec!['~', '*', '"', '\'', ':', ';', '!', '?', '𐘁']), //backspace
|
||||||
|
(Board::SymbolsShift, vec!['[', ']', '{', '}', '𐘁']), //backspace
|
||||||
|
]),
|
||||||
|
HashMap::from([
|
||||||
|
(Board::Regular, vec!['𐘧', '𐘎', ' ', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), enter
|
||||||
|
(Board::Shift, vec!['𐘧', '𐘎', ' ', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), enter
|
||||||
|
(Board::Symbols, vec!['𐘧', '𐘎', ',', '_', ' ', '/', '.', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), enter
|
||||||
|
(Board::SymbolsShift, vec!['𐘧', '𐘎', '\\', '<', ' ', '>', '𐘾', '𐘂']), //switch board (special case, not a real key), alt (special case, not a real key), ctrl (special case, not a real key), enter
|
||||||
|
//ctrl = shimazu
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
//hardcoded for now
|
||||||
|
let mut y = PADDING_Y;
|
||||||
|
let key_height = (self.dimensions[1] - PADDING_Y * 2 - KEY_PADDING_Y * (rows.len() - 1)) / rows.len();
|
||||||
|
let reg_key_width = (self.dimensions[0] - PADDING_X * 2 - KEY_PADDING_X * (10 - 1)) / 10;
|
||||||
|
for row in rows {
|
||||||
|
let row_keys = &row[&self.board];
|
||||||
|
//centre
|
||||||
|
let mut x = PADDING_X + (10 - row_keys.len()) * (reg_key_width + KEY_PADDING_X) / 2;
|
||||||
|
for key in row_keys {
|
||||||
|
let press_return = if key == &'𐘧' {
|
||||||
|
KeyResponse::SwitchBoard
|
||||||
|
} else if key == &'𐘎' {
|
||||||
|
KeyResponse::Alt
|
||||||
|
} else if key == &'𐘾' {
|
||||||
|
KeyResponse::Ctrl
|
||||||
|
} else {
|
||||||
|
KeyResponse::Key(*key)
|
||||||
|
};
|
||||||
|
let mut text = key.to_string();
|
||||||
|
if text == "𐘧" {
|
||||||
|
text = "Switch".to_string();
|
||||||
|
} else if text == "𐘎" {
|
||||||
|
text = "Alt".to_string();
|
||||||
|
} else if text == "𐘂" {
|
||||||
|
text = "Enter".to_string();
|
||||||
|
} else if text == "𐘁" {
|
||||||
|
text = "Back".to_string();
|
||||||
|
} else if text == "𐘃" {
|
||||||
|
text = "Esc".to_string();
|
||||||
|
} else if text == "𐘾" {
|
||||||
|
text = "Ctrl".to_string();
|
||||||
|
}
|
||||||
|
self.components.push(Box::new(PressButton::new([x, y], [reg_key_width, key_height], text, press_return)));
|
||||||
|
x += reg_key_width + KEY_PADDING_X;
|
||||||
|
}
|
||||||
|
y += key_height + KEY_PADDING_Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -38,6 +38,7 @@ pub struct FramebufferInfo {
|
|||||||
pub height: usize,
|
pub height: usize,
|
||||||
pub bytes_per_pixel: usize,
|
pub bytes_per_pixel: usize,
|
||||||
pub stride: usize,
|
pub stride: usize,
|
||||||
|
pub old_stride: Option<usize>, //used/set only when rotate is true
|
||||||
}
|
}
|
||||||
|
|
||||||
//currently doesn't check if writing onto next line accidentally
|
//currently doesn't check if writing onto next line accidentally
|
||||||
@@ -45,6 +46,7 @@ pub struct FramebufferWriter {
|
|||||||
info: FramebufferInfo,
|
info: FramebufferInfo,
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
saved_buffer: Option<Vec<u8>>,
|
saved_buffer: Option<Vec<u8>>,
|
||||||
|
rotate_buffer: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FramebufferWriter {
|
impl FramebufferWriter {
|
||||||
@@ -57,10 +59,25 @@ impl FramebufferWriter {
|
|||||||
self.info.clone()
|
self.info.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_buffer(&self) -> &[u8] {
|
pub fn get_buffer(&mut self) -> &[u8] {
|
||||||
&self.buffer
|
&self.buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_transposed_buffer(&mut self) -> &[u8] {
|
||||||
|
let mut output_array = vec![255; self.info.byte_len];
|
||||||
|
let row_bytes_len = self.info.stride * self.info.bytes_per_pixel;
|
||||||
|
let row_bytes_len_transposed = self.info.old_stride.unwrap_or(self.info.height) * self.info.bytes_per_pixel;
|
||||||
|
for y in 0..self.info.height {
|
||||||
|
for x in 0..self.info.width {
|
||||||
|
for i in 0..self.info.bytes_per_pixel {
|
||||||
|
output_array[(self.info.width - x - 1) * row_bytes_len_transposed + y * self.info.bytes_per_pixel + i] = self.buffer[y * row_bytes_len + x * self.info.bytes_per_pixel + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.rotate_buffer = Some(output_array);
|
||||||
|
&self.rotate_buffer.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn save_buffer(&mut self) {
|
pub fn save_buffer(&mut self) {
|
||||||
self.saved_buffer = Some(self.buffer.clone());
|
self.saved_buffer = Some(self.buffer.clone());
|
||||||
}
|
}
|
||||||
@@ -237,6 +254,7 @@ impl Default for FramebufferWriter {
|
|||||||
info: Default::default(),
|
info: Default::default(),
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
saved_buffer: None,
|
saved_buffer: None,
|
||||||
|
rotate_buffer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
use termion::event::Key;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum KeyChar {
|
|
||||||
Press(char),
|
|
||||||
Alt(char),
|
|
||||||
Ctrl(char),
|
|
||||||
}
|
|
||||||
|
|
||||||
//use Linear A for escape, backspace, enter
|
|
||||||
pub fn key_to_char(key: Key) -> Option<KeyChar> {
|
|
||||||
match key {
|
|
||||||
Key::Char('\n') => Some(KeyChar::Press('𐘂')),
|
|
||||||
Key::Char(c) => Some(KeyChar::Press(c)),
|
|
||||||
Key::Alt(c) => Some(KeyChar::Alt(c)),
|
|
||||||
Key::Ctrl(c) => Some(KeyChar::Ctrl(c)),
|
|
||||||
Key::Backspace => Some(KeyChar::Press('𐘁')),
|
|
||||||
Key::Esc => Some(KeyChar::Press('𐘃')),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -8,6 +8,5 @@ pub mod utils;
|
|||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod ipc;
|
pub mod ipc;
|
||||||
mod proxy_window_like;
|
mod proxy_window_like;
|
||||||
mod keyboard;
|
|
||||||
mod essential;
|
mod essential;
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ use std::vec::Vec;
|
|||||||
|
|
||||||
use serde::{ Deserialize, Serialize };
|
use serde::{ Deserialize, Serialize };
|
||||||
|
|
||||||
use crate::keyboard::KeyChar;
|
|
||||||
use crate::framebuffer::Dimensions;
|
use crate::framebuffer::Dimensions;
|
||||||
use crate::window_manager::WindowLike;
|
use crate::window_manager::{ WindowLike, KeyChar };
|
||||||
|
|
||||||
pub enum WindowManagerMessage {
|
pub enum WindowManagerMessage {
|
||||||
KeyChar(KeyChar),
|
KeyChar(KeyChar),
|
||||||
|
Touch(usize, usize),
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,22 +24,17 @@ impl PartialEq for WindowBox {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[derive(PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum WindowManagerRequest {
|
pub enum WindowManagerRequest {
|
||||||
OpenWindow(String),
|
OpenWindow(String),
|
||||||
ClipboardCopy(String),
|
ClipboardCopy(String),
|
||||||
CloseStartMenu,
|
CloseStartMenu,
|
||||||
Unlock,
|
Unlock,
|
||||||
Lock,
|
Lock,
|
||||||
|
DoKeyChar(KeyChar),
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for WindowManagerRequest{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "WindowManagerRequest lmao")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Debug, Serialize, Deserialize)]
|
||||||
pub enum WindowMessageResponse {
|
pub enum WindowMessageResponse {
|
||||||
Request(WindowManagerRequest),
|
Request(WindowManagerRequest),
|
||||||
@@ -47,6 +42,16 @@ pub enum WindowMessageResponse {
|
|||||||
DoNothing,
|
DoNothing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WindowMessageResponse {
|
||||||
|
pub fn is_key_char_request(&self) -> bool {
|
||||||
|
if let WindowMessageResponse::Request(WindowManagerRequest::DoKeyChar(_)) = self {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct KeyPress {
|
pub struct KeyPress {
|
||||||
pub key: char,
|
pub key: char,
|
||||||
@@ -99,5 +104,14 @@ pub enum WindowMessage {
|
|||||||
Unfocus,
|
Unfocus,
|
||||||
FocusClick,
|
FocusClick,
|
||||||
ChangeDimensions(Dimensions),
|
ChangeDimensions(Dimensions),
|
||||||
|
Touch(usize, usize), //for onscreen keyboard only
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ThreadMessage {
|
||||||
|
KeyChar(KeyChar),
|
||||||
|
Touch(usize, usize),
|
||||||
|
Clear,
|
||||||
|
Exit,
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
34
src/utils.rs
34
src/utils.rs
@@ -1,5 +1,28 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use termion::event::Key;
|
||||||
|
|
||||||
|
use crate::window_manager::KeyChar;
|
||||||
|
use crate::framebuffer::{ Dimensions, Point };
|
||||||
|
|
||||||
|
//use Linear A for escape, backspace, enter
|
||||||
|
//Linear A used only internally in onscreen keyboard: 𐘎 is alt, 𐘧 is switch board, 𐘾 is ctrl
|
||||||
|
pub fn key_to_char(key: Key) -> Option<KeyChar> {
|
||||||
|
match key {
|
||||||
|
Key::Char('\n') => Some(KeyChar::Press('𐘂')),
|
||||||
|
Key::Char(c) => Some(KeyChar::Press(c)),
|
||||||
|
Key::Alt(c) => Some(KeyChar::Alt(c)),
|
||||||
|
Key::Ctrl(c) => Some(KeyChar::Ctrl(c)),
|
||||||
|
Key::Backspace => Some(KeyChar::Press('𐘁')),
|
||||||
|
Key::Esc => Some(KeyChar::Press('𐘃')),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min(one: usize, two: usize) -> usize {
|
||||||
|
if one > two { two } else { one }
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Substring {
|
pub trait Substring {
|
||||||
fn substring(&self, start: usize, end: usize) -> &str;
|
fn substring(&self, start: usize, end: usize) -> &str;
|
||||||
fn remove(&self, index: usize, len: usize) -> String;
|
fn remove(&self, index: usize, len: usize) -> String;
|
||||||
@@ -20,7 +43,6 @@ impl Substring for String {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
byte_end += char_length;
|
byte_end += char_length;
|
||||||
|
|
||||||
}
|
}
|
||||||
&self[byte_start..byte_end]
|
&self[byte_start..byte_end]
|
||||||
}
|
}
|
||||||
@@ -125,3 +147,13 @@ pub fn is_hex(c: char) -> bool {
|
|||||||
HEX_CHARS.iter().position(|hc| hc == &c).is_some()
|
HEX_CHARS.iter().position(|hc| hc == &c).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool {
|
||||||
|
let x = point[0];
|
||||||
|
let y = point[1];
|
||||||
|
let x2 = top_left[0];
|
||||||
|
let y2 = top_left[1];
|
||||||
|
let x3 = x2 + size[0];
|
||||||
|
let y3 = y2 + size[1];
|
||||||
|
x >= x2 && y >= y2 && x <= x3 && y <= y3
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,24 @@ use std::vec;
|
|||||||
use std::collections::{ HashMap, VecDeque };
|
use std::collections::{ HashMap, VecDeque };
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
use std::io::{ stdin, stdout, Write };
|
use std::io::{ stdin, stdout, BufReader, BufRead, Write };
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::env;
|
||||||
|
use std::process::{ Command, Stdio };
|
||||||
|
|
||||||
use linux_framebuffer::Framebuffer;
|
use linux_framebuffer::Framebuffer;
|
||||||
use termion::input::TermRead;
|
use termion::input::TermRead;
|
||||||
use termion::raw::IntoRawMode;
|
use termion::raw::IntoRawMode;
|
||||||
use termion::cursor;
|
use termion::{ clear, cursor };
|
||||||
use serde::{ Deserialize, Serialize };
|
use serde::{ Deserialize, Serialize };
|
||||||
|
|
||||||
use crate::framebuffer::{ FramebufferWriter, FramebufferInfo, Point, Dimensions, RGBColor };
|
use crate::framebuffer::{ FramebufferWriter, FramebufferInfo, Point, Dimensions, RGBColor };
|
||||||
use crate::themes::{ ThemeInfo, Themes, get_theme_info };
|
use crate::themes::{ ThemeInfo, Themes, get_theme_info };
|
||||||
use crate::keyboard::{ KeyChar, key_to_char };
|
use crate::utils::{ min, key_to_char, point_inside };
|
||||||
use crate::messages::*;
|
use crate::messages::*;
|
||||||
use crate::proxy_window_like::ProxyWindowLike;
|
use crate::proxy_window_like::ProxyWindowLike;
|
||||||
use crate::essential::desktop_background::DesktopBackground;
|
use crate::essential::desktop_background::DesktopBackground;
|
||||||
@@ -25,13 +30,40 @@ use crate::essential::workspace_indicator::WorkspaceIndicator;
|
|||||||
use crate::essential::start_menu::StartMenu;
|
use crate::essential::start_menu::StartMenu;
|
||||||
use crate::essential::about::About;
|
use crate::essential::about::About;
|
||||||
use crate::essential::help::Help;
|
use crate::essential::help::Help;
|
||||||
|
use crate::essential::onscreen_keyboard::OnscreenKeyboard;
|
||||||
//use crate::logging::log;
|
//use crate::logging::log;
|
||||||
|
|
||||||
|
//todo: a lot of the usize should be changed to u16
|
||||||
|
|
||||||
pub const TASKBAR_HEIGHT: usize = 38;
|
pub const TASKBAR_HEIGHT: usize = 38;
|
||||||
pub const INDICATOR_HEIGHT: usize = 20;
|
pub const INDICATOR_HEIGHT: usize = 20;
|
||||||
const WINDOW_TOP_HEIGHT: usize = 26;
|
const WINDOW_TOP_HEIGHT: usize = 26;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub enum KeyChar {
|
||||||
|
Press(char),
|
||||||
|
Alt(char),
|
||||||
|
Ctrl(char),
|
||||||
|
}
|
||||||
|
|
||||||
pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
||||||
|
let args: Vec<_> = env::args().collect();
|
||||||
|
|
||||||
|
let rotate = args.contains(&"rotate".to_string());
|
||||||
|
|
||||||
|
let framebuffer_info = if rotate {
|
||||||
|
FramebufferInfo {
|
||||||
|
byte_len: framebuffer_info.byte_len,
|
||||||
|
width: framebuffer_info.height,
|
||||||
|
height: framebuffer_info.width,
|
||||||
|
bytes_per_pixel: framebuffer_info.bytes_per_pixel,
|
||||||
|
stride: framebuffer_info.height,
|
||||||
|
old_stride: Some(framebuffer_info.stride),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
framebuffer_info
|
||||||
|
};
|
||||||
|
|
||||||
let dimensions = [framebuffer_info.width, framebuffer_info.height];
|
let dimensions = [framebuffer_info.width, framebuffer_info.height];
|
||||||
|
|
||||||
println!("bg: {}x{}", dimensions[0], dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT);
|
println!("bg: {}x{}", dimensions[0], dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT);
|
||||||
@@ -40,38 +72,103 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
|||||||
|
|
||||||
writer.init(framebuffer_info.clone());
|
writer.init(framebuffer_info.clone());
|
||||||
|
|
||||||
let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions);
|
let mut wm: WindowManager = WindowManager::new(writer, framebuffer, dimensions, rotate);
|
||||||
|
|
||||||
|
let mut stdout = stdout().into_raw_mode().unwrap();
|
||||||
|
|
||||||
|
write!(stdout, "{}", clear::All).unwrap();
|
||||||
|
|
||||||
|
write!(stdout, "{}", cursor::Hide).unwrap();
|
||||||
|
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
|
||||||
wm.draw(None, false);
|
wm.draw(None, false);
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let tx1 = tx.clone();
|
||||||
|
|
||||||
|
//read key presses
|
||||||
|
thread::spawn(move || {
|
||||||
let stdin = stdin().lock();
|
let stdin = stdin().lock();
|
||||||
let mut stdout = stdout().into_raw_mode().unwrap();
|
|
||||||
|
|
||||||
write!(stdout, "{}", cursor::Hide).unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
|
|
||||||
|
|
||||||
for c in stdin.keys() {
|
for c in stdin.keys() {
|
||||||
if let Some(kc) = key_to_char(c.unwrap()) {
|
if let Some(kc) = key_to_char(c.unwrap()) {
|
||||||
//do not allow exit when locked unless debugging
|
//do not allow exit when locked unless debugging
|
||||||
//if kc == KeyChar::Alt('E') {
|
//if kc == KeyChar::Alt('E') {
|
||||||
if kc == KeyChar::Alt('E') && !wm.locked {
|
if kc == KeyChar::Alt('E') {
|
||||||
|
tx.send(ThreadMessage::Exit).unwrap();
|
||||||
|
} else {
|
||||||
|
tx.send(ThreadMessage::KeyChar(kc)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let touch = args.contains(&"touch".to_string());
|
||||||
|
|
||||||
|
//read touchscreen presses (hopefully)
|
||||||
|
thread::spawn(move || {
|
||||||
|
//spawn evtest, parse it for touch coords
|
||||||
|
if touch {
|
||||||
|
let mut evtest = Command::new("evtest").arg("/dev/input/by-path/first-touchscreen").stdout(Stdio::piped()).spawn().unwrap();
|
||||||
|
let reader = BufReader::new(evtest.stdout.as_mut().unwrap());
|
||||||
|
let mut x: Option<usize> = None;
|
||||||
|
let mut y: Option<usize> = None;
|
||||||
|
for line in reader.lines() {
|
||||||
|
let line = line.unwrap();
|
||||||
|
if line.contains(&"ABS_X), value ") || line.contains(&"ABS_Y), value ") {
|
||||||
|
let value: Vec<_> = line.split("), value ").collect();
|
||||||
|
let value = value[value.len() - 1].parse::<usize>().unwrap();
|
||||||
|
if line.contains(&"ABS_X") {
|
||||||
|
x = Some(value);
|
||||||
|
} else {
|
||||||
|
y = Some(value);
|
||||||
|
}
|
||||||
|
if x.is_some() && y.is_some() {
|
||||||
|
let (x2, y2) = if rotate {
|
||||||
|
(y.unwrap(), dimensions[1] - x.unwrap())
|
||||||
|
} else {
|
||||||
|
(x.unwrap(), y.unwrap())
|
||||||
|
};
|
||||||
|
//top right, clear
|
||||||
|
//useful sometimes, I think.
|
||||||
|
if x2 > dimensions[0] - 100 && y2 < 100 {
|
||||||
|
tx1.send(ThreadMessage::Clear).unwrap();
|
||||||
|
}
|
||||||
|
tx1.send(ThreadMessage::Touch(x2, y2)).unwrap();
|
||||||
|
x = None;
|
||||||
|
y = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if touch {
|
||||||
|
//opens osk
|
||||||
|
wm.handle_message(WindowManagerMessage::Touch(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for message in rx {
|
||||||
|
match message {
|
||||||
|
ThreadMessage::KeyChar(kc) => wm.handle_message(WindowManagerMessage::KeyChar(kc.clone())),
|
||||||
|
ThreadMessage::Touch(x, y) => wm.handle_message(WindowManagerMessage::Touch(x, y)),
|
||||||
|
ThreadMessage::Clear => {
|
||||||
|
write!(stdout, "{}", clear::All).unwrap();
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
},
|
||||||
|
ThreadMessage::Exit => {
|
||||||
|
if !wm.locked {
|
||||||
write!(stdout, "{}", cursor::Show).unwrap();
|
write!(stdout, "{}", cursor::Show).unwrap();
|
||||||
stdout.suspend_raw_mode().unwrap();
|
stdout.suspend_raw_mode().unwrap();
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
|
||||||
wm.handle_message(WindowManagerMessage::KeyChar(kc.clone()));
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn min(one: usize, two: usize) -> usize {
|
|
||||||
if one > two { two } else { one }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum DrawInstructions {
|
pub enum DrawInstructions {
|
||||||
Rect(Point, Dimensions, RGBColor),
|
Rect(Point, Dimensions, RGBColor),
|
||||||
@@ -89,6 +186,7 @@ pub enum WindowLikeType {
|
|||||||
Taskbar,
|
Taskbar,
|
||||||
StartMenu,
|
StartMenu,
|
||||||
WorkspaceIndicator,
|
WorkspaceIndicator,
|
||||||
|
OnscreenKeyboard,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WindowLike {
|
pub trait WindowLike {
|
||||||
@@ -133,8 +231,10 @@ impl fmt::Debug for WindowLikeInfo {
|
|||||||
|
|
||||||
pub struct WindowManager {
|
pub struct WindowManager {
|
||||||
writer: RefCell<FramebufferWriter>,
|
writer: RefCell<FramebufferWriter>,
|
||||||
|
rotate: bool,
|
||||||
id_count: usize,
|
id_count: usize,
|
||||||
window_infos: Vec<WindowLikeInfo>,
|
window_infos: Vec<WindowLikeInfo>,
|
||||||
|
osk: Option<WindowLikeInfo>,
|
||||||
dimensions: Dimensions,
|
dimensions: Dimensions,
|
||||||
theme: Themes,
|
theme: Themes,
|
||||||
focused_id: usize,
|
focused_id: usize,
|
||||||
@@ -147,11 +247,13 @@ pub struct WindowManager {
|
|||||||
//1 is up, 2 is down
|
//1 is up, 2 is down
|
||||||
|
|
||||||
impl WindowManager {
|
impl WindowManager {
|
||||||
pub fn new(writer: FramebufferWriter, framebuffer: Framebuffer, dimensions: Dimensions) -> Self {
|
pub fn new(writer: FramebufferWriter, framebuffer: Framebuffer, dimensions: Dimensions, rotate: bool) -> Self {
|
||||||
let mut wm = WindowManager {
|
let mut wm = WindowManager {
|
||||||
writer: RefCell::new(writer),
|
writer: RefCell::new(writer),
|
||||||
|
rotate,
|
||||||
id_count: 0,
|
id_count: 0,
|
||||||
window_infos: Vec::new(),
|
window_infos: Vec::new(),
|
||||||
|
osk: None,
|
||||||
dimensions,
|
dimensions,
|
||||||
theme: Themes::Standard,
|
theme: Themes::Standard,
|
||||||
focused_id: 0,
|
focused_id: 0,
|
||||||
@@ -169,10 +271,9 @@ impl WindowManager {
|
|||||||
let dimensions = dimensions.unwrap_or(window_like.ideal_dimensions(self.dimensions));
|
let dimensions = dimensions.unwrap_or(window_like.ideal_dimensions(self.dimensions));
|
||||||
self.id_count = self.id_count + 1;
|
self.id_count = self.id_count + 1;
|
||||||
let id = self.id_count;
|
let id = self.id_count;
|
||||||
self.focused_id = id;
|
|
||||||
window_like.handle_message(WindowMessage::Init(dimensions));
|
window_like.handle_message(WindowMessage::Init(dimensions));
|
||||||
let dimensions = if window_like.subtype() == WindowLikeType::Window { [dimensions[0], dimensions[1] + WINDOW_TOP_HEIGHT] } else { dimensions };
|
let dimensions = if window_like.subtype() == WindowLikeType::Window { [dimensions[0], dimensions[1] + WINDOW_TOP_HEIGHT] } else { dimensions };
|
||||||
self.window_infos.push(WindowLikeInfo {
|
let window_info = WindowLikeInfo {
|
||||||
id,
|
id,
|
||||||
window_like,
|
window_like,
|
||||||
top_left,
|
top_left,
|
||||||
@@ -183,7 +284,13 @@ impl WindowManager {
|
|||||||
Workspace::All
|
Workspace::All
|
||||||
},
|
},
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
});
|
};
|
||||||
|
if subtype == WindowLikeType::OnscreenKeyboard {
|
||||||
|
self.osk = Some(window_info);
|
||||||
|
} else {
|
||||||
|
self.focused_id = id;
|
||||||
|
self.window_infos.push(window_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_focused_index(&self) -> Option<usize> {
|
fn get_focused_index(&self) -> Option<usize> {
|
||||||
@@ -215,6 +322,7 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//if off_only is true, also handle request
|
//if off_only is true, also handle request
|
||||||
|
//written confusingly but it works I promise
|
||||||
fn toggle_start_menu(&mut self, off_only: bool) -> WindowMessageResponse {
|
fn toggle_start_menu(&mut self, off_only: bool) -> WindowMessageResponse {
|
||||||
let start_menu_exists = self.window_infos.iter().find(|w| w.window_like.subtype() == WindowLikeType::StartMenu).is_some();
|
let start_menu_exists = self.window_infos.iter().find(|w| w.window_like.subtype() == WindowLikeType::StartMenu).is_some();
|
||||||
if (start_menu_exists && off_only) || !off_only {
|
if (start_menu_exists && off_only) || !off_only {
|
||||||
@@ -518,22 +626,53 @@ impl WindowManager {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//
|
WindowManagerMessage::Touch(x, y) => {
|
||||||
|
if x < 100 && y < 100 {
|
||||||
|
//toggle onscreen keyboard if top left keyboard clicked
|
||||||
|
if self.osk.is_some() {
|
||||||
|
self.osk = None;
|
||||||
|
} else {
|
||||||
|
let osk = Box::new(OnscreenKeyboard::new());
|
||||||
|
let ideal_dimensions = osk.ideal_dimensions(self.dimensions);
|
||||||
|
self.add_window_like(osk, [175, self.dimensions[1] - TASKBAR_HEIGHT - 250], Some(ideal_dimensions));
|
||||||
|
}
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else {
|
||||||
|
//see if in onscreen keyboard, if so send to it after offsetting coords
|
||||||
|
if self.osk.is_some() {
|
||||||
|
let osk = self.osk.as_mut().unwrap();
|
||||||
|
if point_inside([x, y], osk.top_left, osk.dimensions) {
|
||||||
|
osk.window_like.handle_message(WindowMessage::Touch(x - osk.top_left[0], y - osk.top_left[1]))
|
||||||
|
} else {
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if response != WindowMessageResponse::DoNothing {
|
if response != WindowMessageResponse::DoNothing {
|
||||||
|
let is_key_char_request = response.is_key_char_request();
|
||||||
match response {
|
match response {
|
||||||
WindowMessageResponse::Request(request) => self.handle_request(request),
|
WindowMessageResponse::Request(request) => self.handle_request(request),
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
|
if !is_key_char_request {
|
||||||
self.draw(redraw_ids, use_saved_buffer);
|
self.draw(redraw_ids, use_saved_buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_request(&mut self, request: WindowManagerRequest) {
|
pub fn handle_request(&mut self, request: WindowManagerRequest) {
|
||||||
let focused_index = self.get_focused_index().unwrap();
|
let subtype = if let Some(focused_index) = self.get_focused_index() {
|
||||||
let subtype = self.window_infos[focused_index].window_like.subtype();
|
Some(self.window_infos[focused_index].window_like.subtype())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
match request {
|
match request {
|
||||||
WindowManagerRequest::OpenWindow(w) => {
|
WindowManagerRequest::OpenWindow(w) => {
|
||||||
|
let subtype = subtype.unwrap();
|
||||||
if subtype != WindowLikeType::Taskbar && subtype != WindowLikeType::StartMenu {
|
if subtype != WindowLikeType::Taskbar && subtype != WindowLikeType::StartMenu {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -565,6 +704,7 @@ impl WindowManager {
|
|||||||
self.taskbar_update_windows();
|
self.taskbar_update_windows();
|
||||||
},
|
},
|
||||||
WindowManagerRequest::CloseStartMenu => {
|
WindowManagerRequest::CloseStartMenu => {
|
||||||
|
let subtype = subtype.unwrap();
|
||||||
if subtype != WindowLikeType::Taskbar && subtype != WindowLikeType::StartMenu {
|
if subtype != WindowLikeType::Taskbar && subtype != WindowLikeType::StartMenu {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -574,13 +714,13 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
WindowManagerRequest::Unlock => {
|
WindowManagerRequest::Unlock => {
|
||||||
if subtype != WindowLikeType::LockScreen {
|
if subtype.unwrap() != WindowLikeType::LockScreen {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.unlock();
|
self.unlock();
|
||||||
},
|
},
|
||||||
WindowManagerRequest::Lock => {
|
WindowManagerRequest::Lock => {
|
||||||
if subtype != WindowLikeType::StartMenu {
|
if subtype.unwrap() != WindowLikeType::StartMenu {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.lock();
|
self.lock();
|
||||||
@@ -588,6 +728,9 @@ impl WindowManager {
|
|||||||
WindowManagerRequest::ClipboardCopy(content) => {
|
WindowManagerRequest::ClipboardCopy(content) => {
|
||||||
self.clipboard = Some(content);
|
self.clipboard = Some(content);
|
||||||
},
|
},
|
||||||
|
WindowManagerRequest::DoKeyChar(kc) => {
|
||||||
|
self.handle_message(WindowManagerMessage::KeyChar(kc));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,12 +748,15 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
//get windows to redraw
|
//get windows to redraw
|
||||||
let redraw_ids = maybe_redraw_ids.unwrap_or(Vec::new());
|
let redraw_ids = maybe_redraw_ids.unwrap_or(Vec::new());
|
||||||
let all_in_workspace = self.get_windows_in_workspace(true);
|
let mut all_in_workspace = self.get_windows_in_workspace(true);
|
||||||
|
if let Some(osk) = &self.osk {
|
||||||
|
all_in_workspace.push(osk);
|
||||||
|
}
|
||||||
let maybe_length = all_in_workspace.len();
|
let maybe_length = all_in_workspace.len();
|
||||||
let redraw_windows = all_in_workspace.iter().filter(|w| {
|
let redraw_windows = all_in_workspace.iter().filter(|w| {
|
||||||
//basically, maybe_redraw_ids was None
|
//basically, maybe_redraw_ids was None
|
||||||
if redraw_ids.len() > 0 {
|
if redraw_ids.len() > 0 {
|
||||||
redraw_ids.contains(&w.id)
|
redraw_ids.contains(&w.id) || w.window_like.subtype() == WindowLikeType::OnscreenKeyboard
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -697,6 +843,9 @@ impl WindowManager {
|
|||||||
self.writer.borrow_mut().draw_buffer(window_info.top_left, window_dimensions[1], window_dimensions[0] * bytes_per_pixel, &window_writer.get_buffer());
|
self.writer.borrow_mut().draw_buffer(window_info.top_left, window_dimensions[1], window_dimensions[0] * bytes_per_pixel, &window_writer.get_buffer());
|
||||||
w_index += 1;
|
w_index += 1;
|
||||||
}
|
}
|
||||||
self.framebuffer.write_frame(self.writer.borrow().get_buffer());
|
//could probably figure out a way to do borrow() when self.rotate is false but does it matter?
|
||||||
|
let mut writer_borrow = self.writer.borrow_mut();
|
||||||
|
let frame = if self.rotate { writer_borrow.get_transposed_buffer() } else { writer_borrow.get_buffer() };
|
||||||
|
self.framebuffer.write_frame(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user