#![cfg(target_os = "linux")]
use std::sync::Arc;
use x11rb::connection::Connection;
use x11rb::protocol::xproto::*;
use x11rb::protocol::Event;
use x11rb::rust_connection::RustConnection;
use x11rb::protocol::xproto::ConnectionExt;
use x11rb::COPY_DEPTH_FROM_PARENT;
use crate::support::point::{Point, Extent};
use crate::view::{
View, BaseView, MouseButton, MouseButtonKind, KeyCode, KeyAction, KeyInfo,
TextInfo, CursorTracking, CursorType, DropInfo,
};
pub fn translate_key(keycode: u8) -> KeyCode {
match keycode {
9 => KeyCode::Escape,
10..=19 => {
let idx = keycode - 10;
match idx {
0 => KeyCode::Key1,
1 => KeyCode::Key2,
2 => KeyCode::Key3,
3 => KeyCode::Key4,
4 => KeyCode::Key5,
5 => KeyCode::Key6,
6 => KeyCode::Key7,
7 => KeyCode::Key8,
8 => KeyCode::Key9,
9 => KeyCode::Key0,
_ => KeyCode::Unknown,
}
}
22 => KeyCode::Backspace,
23 => KeyCode::Tab,
24 => KeyCode::Q,
25 => KeyCode::W,
26 => KeyCode::E,
27 => KeyCode::R,
28 => KeyCode::T,
29 => KeyCode::Y,
30 => KeyCode::U,
31 => KeyCode::I,
32 => KeyCode::O,
33 => KeyCode::P,
36 => KeyCode::Enter,
37 => KeyCode::LeftControl,
38 => KeyCode::A,
39 => KeyCode::S,
40 => KeyCode::D,
41 => KeyCode::F,
42 => KeyCode::G,
43 => KeyCode::H,
44 => KeyCode::J,
45 => KeyCode::K,
46 => KeyCode::L,
50 => KeyCode::LeftShift,
52 => KeyCode::Z,
53 => KeyCode::X,
54 => KeyCode::C,
55 => KeyCode::V,
56 => KeyCode::B,
57 => KeyCode::N,
58 => KeyCode::M,
62 => KeyCode::RightShift,
64 => KeyCode::LeftAlt,
65 => KeyCode::Space,
66 => KeyCode::CapsLock,
67..=76 => {
let idx = keycode - 67;
match idx {
0 => KeyCode::F1,
1 => KeyCode::F2,
2 => KeyCode::F3,
3 => KeyCode::F4,
4 => KeyCode::F5,
5 => KeyCode::F6,
6 => KeyCode::F7,
7 => KeyCode::F8,
8 => KeyCode::F9,
9 => KeyCode::F10,
_ => KeyCode::Unknown,
}
}
95 => KeyCode::F11,
96 => KeyCode::F12,
105 => KeyCode::RightControl,
108 => KeyCode::RightAlt,
110 => KeyCode::Home,
111 => KeyCode::Up,
112 => KeyCode::PageUp,
113 => KeyCode::Left,
114 => KeyCode::Right,
115 => KeyCode::End,
116 => KeyCode::Down,
117 => KeyCode::PageDown,
118 => KeyCode::Insert,
119 => KeyCode::Delete,
133 => KeyCode::LeftSuper,
134 => KeyCode::RightSuper,
_ => KeyCode::Unknown,
}
}
pub fn translate_modifiers(state: u16) -> i32 {
use crate::view::modifiers;
let mut mods = 0i32;
if state & 0x01 != 0 {
mods |= modifiers::SHIFT;
}
if state & 0x04 != 0 {
mods |= modifiers::CONTROL;
}
if state & 0x08 != 0 {
mods |= modifiers::ALT;
}
if state & 0x40 != 0 {
mods |= modifiers::SUPER;
}
if state & 0x02 != 0 {
mods |= modifiers::CAPS_LOCK;
}
mods
}
pub struct LinuxApp {
conn: Arc<RustConnection>,
screen_num: usize,
running: bool,
}
impl LinuxApp {
pub fn new() -> Option<Self> {
let (conn, screen_num) = RustConnection::connect(None).ok()?;
Some(Self {
conn: Arc::new(conn),
screen_num,
running: false,
})
}
pub fn connection(&self) -> &Arc<RustConnection> {
&self.conn
}
pub fn screen_num(&self) -> usize {
self.screen_num
}
pub fn run(&mut self) {
self.running = true;
while self.running {
match self.conn.wait_for_event() {
Ok(event) => {
self.handle_event(event);
}
Err(_) => {
self.running = false;
}
}
}
}
pub fn stop(&mut self) {
self.running = false;
}
fn handle_event(&mut self, event: Event) {
match event {
Event::Expose(_) => {
}
Event::ConfigureNotify(_) => {
}
Event::ButtonPress(e) => {
}
Event::ButtonRelease(e) => {
}
Event::MotionNotify(e) => {
}
Event::KeyPress(e) => {
}
Event::KeyRelease(e) => {
}
Event::DestroyNotify(_) => {
self.running = false;
}
_ => {}
}
}
}
pub struct LinuxWindow {
conn: Arc<RustConnection>,
window: Window,
view: Option<View>,
}
impl LinuxWindow {
pub fn new(app: &LinuxApp, title: &str, size: Extent) -> Option<Self> {
let conn = app.connection().clone();
let screen = &conn.setup().roots[app.screen_num()];
let window = conn.generate_id().ok()?;
let values = CreateWindowAux::default()
.background_pixel(screen.white_pixel)
.event_mask(
EventMask::EXPOSURE
| EventMask::STRUCTURE_NOTIFY
| EventMask::BUTTON_PRESS
| EventMask::BUTTON_RELEASE
| EventMask::POINTER_MOTION
| EventMask::KEY_PRESS
| EventMask::KEY_RELEASE
| EventMask::ENTER_WINDOW
| EventMask::LEAVE_WINDOW
| EventMask::FOCUS_CHANGE,
);
conn.create_window(
COPY_DEPTH_FROM_PARENT,
window,
screen.root,
0,
0,
size.x as u16,
size.y as u16,
0,
WindowClass::INPUT_OUTPUT,
0,
&values,
)
.ok()?;
conn.change_property8(
PropMode::REPLACE,
window,
AtomEnum::WM_NAME,
AtomEnum::STRING,
title.as_bytes(),
)
.ok()?;
conn.flush().ok()?;
Some(Self {
conn,
window,
view: Some(View::new(size)),
})
}
pub fn show(&self) {
let _ = self.conn.map_window(self.window);
let _ = self.conn.flush();
}
pub fn hide(&self) {
let _ = self.conn.unmap_window(self.window);
let _ = self.conn.flush();
}
pub fn close(&self) {
let _ = self.conn.destroy_window(self.window);
let _ = self.conn.flush();
}
pub fn window_id(&self) -> Window {
self.window
}
pub fn view(&self) -> Option<&View> {
self.view.as_ref()
}
pub fn view_mut(&mut self) -> Option<&mut View> {
self.view.as_mut()
}
}