LINUX.ORG.RU

История изменений

Исправление LightDiver, (текущая версия) :

Понимаешь в чем беда, тебе всеравно придется через что то рисовать. Через винапи, через х11, через вейленд. Но их писали негуманоидные виды для таких же как они. Причем явно для противоестественного использования.

Вот смотри пример:

Cargo.toml

[package]
name = "dancing_strings_demo"
version = "0.1.0"
edition = "2021"

# Для работы с системными вызовами
[dependencies]
libc = "0.2"

main.rs

use std::ptr::{null, null_mut};
use std::thread;
use std::time::Duration;
use libc::{c_int, c_ulong};

#[repr(C)]
struct XEvent {
    pub type_: c_int,
    pub xany: [u8; 24],
}

// Константы
const KEY_PRESS_MASK: c_int = 1 << 0;
const CLIENT_MESSAGE: c_int = 21;

const WIDTH: usize = 400;
const HEIGHT: usize = 300;

#[link(name = "X11")]
extern "C" {
    fn XOpenDisplay(display_name: *const i8) -> *mut Display;
    fn XDefaultScreen(dpy: *mut Display) -> c_int;
    fn XRootWindow(dpy: *mut Display, screen: c_int) -> Window;
    fn XCreateSimpleWindow(
        dpy: *mut Display,
        parent: Window,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
        border_width: u32,
        border: c_ulong,
        background: c_ulong,
    ) -> Window;
    fn XMapWindow(dpy: *mut Display, w: Window);
    fn XSelectInput(dpy: *mut Display, w: Window, event_mask: c_int);
    fn XNextEvent(dpy: *mut Display, event: *mut XEvent) -> c_int;
    fn XFlush(dpy: *mut Display) -> c_int;
    fn XCloseDisplay(dpy: *mut Display) -> c_int;
    fn XCreateGC(dpy: *mut Display, d: Drawable, valuemask: u64, values: *mut ()) -> GC;
    fn XSetForeground(dpy: *mut Display, gc: GC, foreground: c_ulong);
    fn XFillRectangle(
        dpy: *mut Display,
        d: Drawable,
        gc: GC,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
    );
    fn XPending(dpy: *mut Display) -> c_int;
}

type Display = std::ffi::c_void;
type Window = c_ulong;
type Drawable = c_ulong;
type GC = *mut std::ffi::c_void;

fn main() {
    // Открываем дисплей
    let display = unsafe { XOpenDisplay(null()) };
    if display.is_null() {
        panic!("Не удалось подключиться к X серверу");
    }

    // Получаем корневое окно
    let screen = unsafe { XDefaultScreen(display) };
    let root_window = unsafe { XRootWindow(display, screen) };

    // Создаём наше окно
    let window = unsafe {
        XCreateSimpleWindow(
            display,
            root_window,
            0,
            0,
            WIDTH as u32,
            HEIGHT as u32,
            0,
            0,
            0xff000000, // Чёрный фон
        )
    };

    if window == 0 {
        panic!("Не удалось создать окно!");
    }

    // Подписываемся на события
    unsafe {
        XSelectInput(display, window, KEY_PRESS_MASK | CLIENT_MESSAGE);
        XMapWindow(display, window);
        XFlush(display); // Отправляем команду на экран
    }

    // Создаём графический контекст
    let gc = unsafe { XCreateGC(display, window, 0, null_mut()) };
    if gc.is_null() {
        panic!("Не удалось создать GC");
    }

    // Устанавливаем цвет: красный (RGB: FF0000)
    unsafe {
        XSetForeground(display, gc, 0xFF0000); // красный
    }

    println!("Окно создано. Ждём событий...");

    // Цикл обработки событий
    let mut running = true;
    while running {
        if unsafe { XPending(display) } > 0 {
            let mut event: XEvent = unsafe { std::mem::zeroed() };
            unsafe {
                XNextEvent(display, &mut event);
            }

            match event.type_ {
                2 => {
                    // KeyPress
                    running = false;
                }
                _ => {}
            }
        } else {
            // Рисуем красный квадрат 10x10 по центру
            unsafe {
                XFillRectangle(display, window, gc, 195, 145, 10, 10);
                XFlush(display);
            }

            thread::sleep(Duration::from_millis(100));
        }
    }

    unsafe {
        XCloseDisplay(display);
    }

    println!("Программа завершена.");
}

Это вывод красного квадрата в окне. Работа напрямую через иксы. Понимаешь, егуи добавляет тебе совсем минималистичную либу на 1 метр, зато дает в ней тебе гуи, работу с 2д, работу с 3д. Да вообще полное удобство с минимальными затратами. Оно реально того стоит. Но можешь глянуть пример выше.

И да, в прямой работа навреное действительно лучше сразу си использовать. Ибо всеравно придется. Но как по мне - вместо компактного, быстрого, красивого какая то порнография выходит в таком случае.

И да, я тебя полностью понимаю. Я это прошел. И вариант с ассемблером тоже, кстати. Они забавно, прикольно, но нежизнеспособно в итоге для реальной работы. Игрушки. Когда начинаешь делать практический проект, нужна абстракция кое какая. Затраченные усилия не окупаются, когда вот тут рядом можно сделать быстро и удобно.

Но! Даже в реальных проектах бывают «узкие места», где уже можно запихать конкретно низкоуровневое свое решение урезанное вместо жирного готового - тогда оно оправданно. Только фрагментарно, а не как весь проект.

Исправление LightDiver, :

Понимаешь в чем беда, тебе всеравно придется через что то рисовать. Через винапи, через х11, через вейленд. Но их писали негуманоидные виды для таких же как они. Причем явно для противоестественного использования.

Вот смотри пример:

Cargo.toml

[package]
name = "dancing_strings_demo"
version = "0.1.0"
edition = "2021"

# Для работы с системными вызовами
[dependencies]
libc = "0.2"

main.rs

use std::ptr::{null, null_mut};
use std::thread;
use std::time::Duration;
use libc::{c_int, c_ulong};

#[repr(C)]
struct XEvent {
    pub type_: c_int,
    pub xany: [u8; 24],
}

// Константы
const KEY_PRESS_MASK: c_int = 1 << 0;
const CLIENT_MESSAGE: c_int = 21;

const WIDTH: usize = 400;
const HEIGHT: usize = 300;

#[link(name = "X11")]
extern "C" {
    fn XOpenDisplay(display_name: *const i8) -> *mut Display;
    fn XDefaultScreen(dpy: *mut Display) -> c_int;
    fn XRootWindow(dpy: *mut Display, screen: c_int) -> Window;
    fn XCreateSimpleWindow(
        dpy: *mut Display,
        parent: Window,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
        border_width: u32,
        border: c_ulong,
        background: c_ulong,
    ) -> Window;
    fn XMapWindow(dpy: *mut Display, w: Window);
    fn XSelectInput(dpy: *mut Display, w: Window, event_mask: c_int);
    fn XNextEvent(dpy: *mut Display, event: *mut XEvent) -> c_int;
    fn XFlush(dpy: *mut Display) -> c_int;
    fn XCloseDisplay(dpy: *mut Display) -> c_int;
    fn XCreateGC(dpy: *mut Display, d: Drawable, valuemask: u64, values: *mut ()) -> GC;
    fn XSetForeground(dpy: *mut Display, gc: GC, foreground: c_ulong);
    fn XFillRectangle(
        dpy: *mut Display,
        d: Drawable,
        gc: GC,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
    );
    fn XPending(dpy: *mut Display) -> c_int;
}

type Display = std::ffi::c_void;
type Window = c_ulong;
type Drawable = c_ulong;
type GC = *mut std::ffi::c_void;

fn main() {
    // Открываем дисплей
    let display = unsafe { XOpenDisplay(null()) };
    if display.is_null() {
        panic!("Не удалось подключиться к X серверу");
    }

    // Получаем корневое окно
    let screen = unsafe { XDefaultScreen(display) };
    let root_window = unsafe { XRootWindow(display, screen) };

    // Создаём наше окно
    let window = unsafe {
        XCreateSimpleWindow(
            display,
            root_window,
            0,
            0,
            WIDTH as u32,
            HEIGHT as u32,
            0,
            0,
            0xff000000, // Чёрный фон
        )
    };

    if window == 0 {
        panic!("Не удалось создать окно!");
    }

    // Подписываемся на события
    unsafe {
        XSelectInput(display, window, KEY_PRESS_MASK | CLIENT_MESSAGE);
        XMapWindow(display, window);
        XFlush(display); // Отправляем команду на экран
    }

    // Создаём графический контекст
    let gc = unsafe { XCreateGC(display, window, 0, null_mut()) };
    if gc.is_null() {
        panic!("Не удалось создать GC");
    }

    // Устанавливаем цвет: красный (RGB: FF0000)
    unsafe {
        XSetForeground(display, gc, 0xFF0000); // красный
    }

    println!("Окно создано. Ждём событий...");

    // Цикл обработки событий
    let mut running = true;
    while running {
        if unsafe { XPending(display) } > 0 {
            let mut event: XEvent = unsafe { std::mem::zeroed() };
            unsafe {
                XNextEvent(display, &mut event);
            }

            match event.type_ {
                2 => {
                    // KeyPress
                    running = false;
                }
                _ => {}
            }
        } else {
            // Рисуем красный квадрат 10x10 по центру
            unsafe {
                XFillRectangle(display, window, gc, 195, 145, 10, 10);
                XFlush(display);
            }

            thread::sleep(Duration::from_millis(100));
        }
    }

    unsafe {
        XCloseDisplay(display);
    }

    println!("Программа завершена.");
}

Это вывод красного квадрата в окне. Работа напрямую через иксы. Понимаешь, егуи добавляет тебе совсем минималистичную либу на 1 метр, зато дает в ней тебе гуи, работу с 2д, работу с 3д. Да вообще полное удобство с минимальными затратами. Оно реально того стоит. Но можешь глянуть пример выше.

И да, в прямой работа навреное действительно лучше сразу си использовать. Ибо всеравно придется. Но как по мне - вместо компактного, быстрого, красивого какая то порнография выходит в таком случае.

И да, я тебя полностью понимаю. Я это прошел. И вариант с ассемблером тоже, кстати. Они забавно, прикольно, но нежизнеспособно в итоге для реальной работы. Игрушки. Когда начинаешь делать практический проект, нужна абстракция кое какая. Затраченные усилия не окупаются, когда вот тут рядом можно сделать быстро и удобно.

Но! Даже в реальных проектах бывают «узкие места», где уже можно запихать конкретно низкоуровневое свое решение урезанное вместо жирного готового - тогда оно оправданно.

Исправление LightDiver, :

Понимаешь в чем беда, тебе всеравно придется через что то рисовать. Через винапи, через х11, через вейленд. Но их писали негуманоидные виды для таких же как они. Причем явно для противоестественного использования.

Вот смотри пример:

Cargo.toml

[package]
name = "dancing_strings_demo"
version = "0.1.0"
edition = "2021"

# Для работы с системными вызовами
[dependencies]
libc = "0.2"

main.rs

use std::ptr::{null, null_mut};
use std::thread;
use std::time::Duration;
use libc::{c_int, c_ulong};

#[repr(C)]
struct XEvent {
    pub type_: c_int,
    pub xany: [u8; 24],
}

// Константы
const KEY_PRESS_MASK: c_int = 1 << 0;
const CLIENT_MESSAGE: c_int = 21;

const WIDTH: usize = 400;
const HEIGHT: usize = 300;

#[link(name = "X11")]
extern "C" {
    fn XOpenDisplay(display_name: *const i8) -> *mut Display;
    fn XDefaultScreen(dpy: *mut Display) -> c_int;
    fn XRootWindow(dpy: *mut Display, screen: c_int) -> Window;
    fn XCreateSimpleWindow(
        dpy: *mut Display,
        parent: Window,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
        border_width: u32,
        border: c_ulong,
        background: c_ulong,
    ) -> Window;
    fn XMapWindow(dpy: *mut Display, w: Window);
    fn XSelectInput(dpy: *mut Display, w: Window, event_mask: c_int);
    fn XNextEvent(dpy: *mut Display, event: *mut XEvent) -> c_int;
    fn XFlush(dpy: *mut Display) -> c_int;
    fn XCloseDisplay(dpy: *mut Display) -> c_int;
    fn XCreateGC(dpy: *mut Display, d: Drawable, valuemask: u64, values: *mut ()) -> GC;
    fn XSetForeground(dpy: *mut Display, gc: GC, foreground: c_ulong);
    fn XFillRectangle(
        dpy: *mut Display,
        d: Drawable,
        gc: GC,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
    );
    fn XPending(dpy: *mut Display) -> c_int;
}

type Display = std::ffi::c_void;
type Window = c_ulong;
type Drawable = c_ulong;
type GC = *mut std::ffi::c_void;

fn main() {
    // Открываем дисплей
    let display = unsafe { XOpenDisplay(null()) };
    if display.is_null() {
        panic!("Не удалось подключиться к X серверу");
    }

    // Получаем корневое окно
    let screen = unsafe { XDefaultScreen(display) };
    let root_window = unsafe { XRootWindow(display, screen) };

    // Создаём наше окно
    let window = unsafe {
        XCreateSimpleWindow(
            display,
            root_window,
            0,
            0,
            WIDTH as u32,
            HEIGHT as u32,
            0,
            0,
            0xff000000, // Чёрный фон
        )
    };

    if window == 0 {
        panic!("Не удалось создать окно!");
    }

    // Подписываемся на события
    unsafe {
        XSelectInput(display, window, KEY_PRESS_MASK | CLIENT_MESSAGE);
        XMapWindow(display, window);
        XFlush(display); // Отправляем команду на экран
    }

    // Создаём графический контекст
    let gc = unsafe { XCreateGC(display, window, 0, null_mut()) };
    if gc.is_null() {
        panic!("Не удалось создать GC");
    }

    // Устанавливаем цвет: красный (RGB: FF0000)
    unsafe {
        XSetForeground(display, gc, 0xFF0000); // красный
    }

    println!("Окно создано. Ждём событий...");

    // Цикл обработки событий
    let mut running = true;
    while running {
        if unsafe { XPending(display) } > 0 {
            let mut event: XEvent = unsafe { std::mem::zeroed() };
            unsafe {
                XNextEvent(display, &mut event);
            }

            match event.type_ {
                2 => {
                    // KeyPress
                    running = false;
                }
                _ => {}
            }
        } else {
            // Рисуем красный квадрат 10x10 по центру
            unsafe {
                XFillRectangle(display, window, gc, 195, 145, 10, 10);
                XFlush(display);
            }

            thread::sleep(Duration::from_millis(100));
        }
    }

    unsafe {
        XCloseDisplay(display);
    }

    println!("Программа завершена.");
}

Это вывод красного квадрата в окне. Работа напрямую через иксы. Понимаешь, егуи добавляет тебе совсем минималистичную либу на 1 метр, зато дает в ней тебе гуи, работу с 2д, работу с 3д. Да вообще полное удобство с минимальными затратами. Оно реально того стоит. Но можешь глянуть пример выше.

И да, в прямой работа навреное действительно лучше сразу си использовать. Ибо всеравно придется. Но как по мне - вместо компактного, быстрого, красивого какая то порнография выходит в таком случае.

И да, я тебя полностью понимаю. Я это прошел. И вариант с ассемблером тоже, кстати. Они забавно, прикольно, но нежизнеспособно в итоге для реальной работы. Игрушки. Когда начинаешь делать практический проект, нужна абстракция кое какая. Затраченные усилия не окупаются, когда вот тут рядом можно сделать быстро и удобно.

Исправление LightDiver, :

Понимаешь в чем беда, тебе всеравно придется через что то рисовать. Через винапи, через х11, через вейленд. Но их писали негуманоидные виды для таких же как они. Причем явно для противоестественного использования.

Вот смотри пример:

Cargo.toml

[package]
name = "dancing_strings_demo"
version = "0.1.0"
edition = "2021"

# Для работы с системными вызовами
[dependencies]
libc = "0.2"

main.rs

use std::ptr::{null, null_mut};
use std::thread;
use std::time::Duration;
use libc::{c_int, c_ulong};

#[repr(C)]
struct XEvent {
    pub type_: c_int,
    pub xany: [u8; 24],
}

// Константы
const KEY_PRESS_MASK: c_int = 1 << 0;
const CLIENT_MESSAGE: c_int = 21;

const WIDTH: usize = 400;
const HEIGHT: usize = 300;

#[link(name = "X11")]
extern "C" {
    fn XOpenDisplay(display_name: *const i8) -> *mut Display;
    fn XDefaultScreen(dpy: *mut Display) -> c_int;
    fn XRootWindow(dpy: *mut Display, screen: c_int) -> Window;
    fn XCreateSimpleWindow(
        dpy: *mut Display,
        parent: Window,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
        border_width: u32,
        border: c_ulong,
        background: c_ulong,
    ) -> Window;
    fn XMapWindow(dpy: *mut Display, w: Window);
    fn XSelectInput(dpy: *mut Display, w: Window, event_mask: c_int);
    fn XNextEvent(dpy: *mut Display, event: *mut XEvent) -> c_int;
    fn XFlush(dpy: *mut Display) -> c_int;
    fn XCloseDisplay(dpy: *mut Display) -> c_int;
    fn XCreateGC(dpy: *mut Display, d: Drawable, valuemask: u64, values: *mut ()) -> GC;
    fn XSetForeground(dpy: *mut Display, gc: GC, foreground: c_ulong);
    fn XFillRectangle(
        dpy: *mut Display,
        d: Drawable,
        gc: GC,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
    );
    fn XPending(dpy: *mut Display) -> c_int;
}

type Display = std::ffi::c_void;
type Window = c_ulong;
type Drawable = c_ulong;
type GC = *mut std::ffi::c_void;

fn main() {
    // Открываем дисплей
    let display = unsafe { XOpenDisplay(null()) };
    if display.is_null() {
        panic!("Не удалось подключиться к X серверу");
    }

    // Получаем корневое окно
    let screen = unsafe { XDefaultScreen(display) };
    let root_window = unsafe { XRootWindow(display, screen) };

    // Создаём наше окно
    let window = unsafe {
        XCreateSimpleWindow(
            display,
            root_window,
            0,
            0,
            WIDTH as u32,
            HEIGHT as u32,
            0,
            0,
            0xff000000, // Чёрный фон
        )
    };

    if window == 0 {
        panic!("Не удалось создать окно!");
    }

    // Подписываемся на события
    unsafe {
        XSelectInput(display, window, KEY_PRESS_MASK | CLIENT_MESSAGE);
        XMapWindow(display, window);
        XFlush(display); // Отправляем команду на экран
    }

    // Создаём графический контекст
    let gc = unsafe { XCreateGC(display, window, 0, null_mut()) };
    if gc.is_null() {
        panic!("Не удалось создать GC");
    }

    // Устанавливаем цвет: красный (RGB: FF0000)
    unsafe {
        XSetForeground(display, gc, 0xFF0000); // красный
    }

    println!("Окно создано. Ждём событий...");

    // Цикл обработки событий
    let mut running = true;
    while running {
        if unsafe { XPending(display) } > 0 {
            let mut event: XEvent = unsafe { std::mem::zeroed() };
            unsafe {
                XNextEvent(display, &mut event);
            }

            match event.type_ {
                2 => {
                    // KeyPress
                    running = false;
                }
                _ => {}
            }
        } else {
            // Рисуем красный квадрат 10x10 по центру
            unsafe {
                XFillRectangle(display, window, gc, 195, 145, 10, 10);
                XFlush(display);
            }

            thread::sleep(Duration::from_millis(100));
        }
    }

    unsafe {
        XCloseDisplay(display);
    }

    println!("Программа завершена.");
}

Это вывод красного квадрата в окне. Работа напрямую через иксы. Понимаешь, егуи добавляет тебе совсем минималистичную либу на 1 метр, зато дает в ней тебе гуи, работу с 2д, работу с 3д. Да вообще полное удобство с минимальными затратами. Оно реально того стоит. Но можешь глянуть пример выше.

И да, в прямой работа навреное действительно лучше сразу си использовать. Ибо всеравно придется. Но как по мне - вместо компактного, быстрого, красивого какая то порнография выходит в таком случае.

Исправление LightDiver, :

Понимаешь в чем беда, тебе всеравно придется через что то рисовать. Через винапи, через х11, через вейленд. Но их писали негуманоидные виды для таких же как они. Причем явно для противоестественного использования.

Вот смотри пример:

Cargo.toml

[package]
name = "dancing_strings_demo"
version = "0.1.0"
edition = "2021"

# Для работы с системными вызовами
[dependencies]
libc = "0.2"

main.rs

use std::ptr::{null, null_mut};
use std::thread;
use std::time::Duration;
use libc::{c_int, c_ulong};

#[repr(C)]
struct XEvent {
    pub type_: c_int,
    pub xany: [u8; 24],
}

// Константы
const KEY_PRESS_MASK: c_int = 1 << 0;
const CLIENT_MESSAGE: c_int = 21;

const WIDTH: usize = 400;
const HEIGHT: usize = 300;

#[link(name = "X11")]
extern "C" {
    fn XOpenDisplay(display_name: *const i8) -> *mut Display;
    fn XDefaultScreen(dpy: *mut Display) -> c_int;
    fn XRootWindow(dpy: *mut Display, screen: c_int) -> Window;
    fn XCreateSimpleWindow(
        dpy: *mut Display,
        parent: Window,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
        border_width: u32,
        border: c_ulong,
        background: c_ulong,
    ) -> Window;
    fn XMapWindow(dpy: *mut Display, w: Window);
    fn XSelectInput(dpy: *mut Display, w: Window, event_mask: c_int);
    fn XNextEvent(dpy: *mut Display, event: *mut XEvent) -> c_int;
    fn XFlush(dpy: *mut Display) -> c_int;
    fn XCloseDisplay(dpy: *mut Display) -> c_int;
    fn XCreateGC(dpy: *mut Display, d: Drawable, valuemask: u64, values: *mut ()) -> GC;
    fn XSetForeground(dpy: *mut Display, gc: GC, foreground: c_ulong);
    fn XFillRectangle(
        dpy: *mut Display,
        d: Drawable,
        gc: GC,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
    );
    fn XPending(dpy: *mut Display) -> c_int;
}

type Display = std::ffi::c_void;
type Window = c_ulong;
type Drawable = c_ulong;
type GC = *mut std::ffi::c_void;

fn main() {
    // Открываем дисплей
    let display = unsafe { XOpenDisplay(null()) };
    if display.is_null() {
        panic!("Не удалось подключиться к X серверу");
    }

    // Получаем корневое окно
    let screen = unsafe { XDefaultScreen(display) };
    let root_window = unsafe { XRootWindow(display, screen) };

    // Создаём наше окно
    let window = unsafe {
        XCreateSimpleWindow(
            display,
            root_window,
            0,
            0,
            WIDTH as u32,
            HEIGHT as u32,
            0,
            0,
            0xff000000, // Чёрный фон
        )
    };

    if window == 0 {
        panic!("Не удалось создать окно!");
    }

    // Подписываемся на события
    unsafe {
        XSelectInput(display, window, KEY_PRESS_MASK | CLIENT_MESSAGE);
        XMapWindow(display, window);
        XFlush(display); // Отправляем команду на экран
    }

    // Создаём графический контекст
    let gc = unsafe { XCreateGC(display, window, 0, null_mut()) };
    if gc.is_null() {
        panic!("Не удалось создать GC");
    }

    // Устанавливаем цвет: красный (RGB: FF0000)
    unsafe {
        XSetForeground(display, gc, 0xFF0000); // красный
    }

    println!("Окно создано. Ждём событий...");

    // Цикл обработки событий
    let mut running = true;
    while running {
        if unsafe { XPending(display) } > 0 {
            let mut event: XEvent = unsafe { std::mem::zeroed() };
            unsafe {
                XNextEvent(display, &mut event);
            }

            match event.type_ {
                2 => {
                    // KeyPress
                    running = false;
                }
                _ => {}
            }
        } else {
            // Рисуем красный квадрат 10x10 по центру
            unsafe {
                XFillRectangle(display, window, gc, 195, 145, 10, 10);
                XFlush(display);
            }

            thread::sleep(Duration::from_millis(100));
        }
    }

    unsafe {
        XCloseDisplay(display);
    }

    println!("Программа завершена.");
}

Это вывод красного квадрата в окне. Работа напрямую через иксы. Понимаешь, егуи добавляет тебе совсем минималистичную либу на 1 метр, зато дает в ней тебе гуи, работу с 2д, работу с 3д. Да вообще полное удобство с минимальными затратами. Оно реально того стоит. Но можешь глянуть пример выше.

И да, в прямой работа навреное действительно лучше сразу си использовать. Ибо всеравно придется.

Исправление LightDiver, :

Понимаешь в чем беда, тебе всеравно придется через что то рисовать. Через винапи, через х11, через вейленд. Но их писали негуманоидные виды для таких же как они. Причем явно для противоестественного использования.

Вот смотри пример:

Cargo.toml

[package]
name = "dancing_strings_demo"
version = "0.1.0"
edition = "2021"

# Для работы с системными вызовами
[dependencies]
libc = "0.2"

main.rs

use std::ptr::{null, null_mut};
use std::thread;
use std::time::Duration;
use libc::{c_int, c_ulong};

#[repr(C)]
struct XEvent {
    pub type_: c_int,
    pub xany: [u8; 24],
}

// Константы
const KEY_PRESS_MASK: c_int = 1 << 0;
const CLIENT_MESSAGE: c_int = 21;

const WIDTH: usize = 400;
const HEIGHT: usize = 300;

#[link(name = "X11")]
extern "C" {
    fn XOpenDisplay(display_name: *const i8) -> *mut Display;
    fn XDefaultScreen(dpy: *mut Display) -> c_int;
    fn XRootWindow(dpy: *mut Display, screen: c_int) -> Window;
    fn XCreateSimpleWindow(
        dpy: *mut Display,
        parent: Window,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
        border_width: u32,
        border: c_ulong,
        background: c_ulong,
    ) -> Window;
    fn XMapWindow(dpy: *mut Display, w: Window);
    fn XSelectInput(dpy: *mut Display, w: Window, event_mask: c_int);
    fn XNextEvent(dpy: *mut Display, event: *mut XEvent) -> c_int;
    fn XFlush(dpy: *mut Display) -> c_int;
    fn XCloseDisplay(dpy: *mut Display) -> c_int;
    fn XCreateGC(dpy: *mut Display, d: Drawable, valuemask: u64, values: *mut ()) -> GC;
    fn XSetForeground(dpy: *mut Display, gc: GC, foreground: c_ulong);
    fn XFillRectangle(
        dpy: *mut Display,
        d: Drawable,
        gc: GC,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
    );
    fn XPending(dpy: *mut Display) -> c_int;
}

type Display = std::ffi::c_void;
type Window = c_ulong;
type Drawable = c_ulong;
type GC = *mut std::ffi::c_void;

fn main() {
    // Открываем дисплей
    let display = unsafe { XOpenDisplay(null()) };
    if display.is_null() {
        panic!("Не удалось подключиться к X серверу");
    }

    // Получаем корневое окно
    let screen = unsafe { XDefaultScreen(display) };
    let root_window = unsafe { XRootWindow(display, screen) };

    // Создаём наше окно
    let window = unsafe {
        XCreateSimpleWindow(
            display,
            root_window,
            0,
            0,
            WIDTH as u32,
            HEIGHT as u32,
            0,
            0,
            0xff000000, // Чёрный фон
        )
    };

    if window == 0 {
        panic!("Не удалось создать окно!");
    }

    // Подписываемся на события
    unsafe {
        XSelectInput(display, window, KEY_PRESS_MASK | CLIENT_MESSAGE);
        XMapWindow(display, window);
        XFlush(display); // Отправляем команду на экран
    }

    // Создаём графический контекст
    let gc = unsafe { XCreateGC(display, window, 0, null_mut()) };
    if gc.is_null() {
        panic!("Не удалось создать GC");
    }

    // Устанавливаем цвет: красный (RGB: FF0000)
    unsafe {
        XSetForeground(display, gc, 0xFF0000); // красный
    }

    println!("Окно создано. Ждём событий...");

    // Цикл обработки событий
    let mut running = true;
    while running {
        if unsafe { XPending(display) } > 0 {
            let mut event: XEvent = unsafe { std::mem::zeroed() };
            unsafe {
                XNextEvent(display, &mut event);
            }

            match event.type_ {
                2 => {
                    // KeyPress
                    running = false;
                }
                _ => {}
            }
        } else {
            // Рисуем красный квадрат 10x10 по центру
            unsafe {
                XFillRectangle(display, window, gc, 195, 145, 10, 10);
                XFlush(display);
            }

            thread::sleep(Duration::from_millis(100));
        }
    }

    unsafe {
        XCloseDisplay(display);
    }

    println!("Программа завершена.");
}

Это вывод красного квадрата в окне. Работа напрямую через иксы. Понимаешь, егуи добавляет тебе совсем минималистичную либу на 1 метр, зато дает в ней тебе гуи, работу с 2д, работу с 3д. Да вообще полное удобство с минимальными затратами. Оно реально того стоит. Но можешь глянуть пример выше.

Исходная версия LightDiver, :

Понимаешь в чем беда, тебе всеравно придется через что то рисовать. Через винапи, через х11, через вейленд. Но их писали негуманоидные виды для таких же как они. Причем явно для противоестественного использования.

Вот смотри пример:

Cargo.toml

[package]
name = "dancing_strings_demo"
version = "0.1.0"
edition = "2021"

# Для работы с системными вызовами
[dependencies]
libc = "0.2"
use std::ptr::{null, null_mut};
use std::thread;
use std::time::Duration;
use libc::{c_int, c_ulong};

#[repr(C)]
struct XEvent {
    pub type_: c_int,
    pub xany: [u8; 24],
}

// Константы
const KEY_PRESS_MASK: c_int = 1 << 0;
const CLIENT_MESSAGE: c_int = 21;

const WIDTH: usize = 400;
const HEIGHT: usize = 300;

#[link(name = "X11")]
extern "C" {
    fn XOpenDisplay(display_name: *const i8) -> *mut Display;
    fn XDefaultScreen(dpy: *mut Display) -> c_int;
    fn XRootWindow(dpy: *mut Display, screen: c_int) -> Window;
    fn XCreateSimpleWindow(
        dpy: *mut Display,
        parent: Window,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
        border_width: u32,
        border: c_ulong,
        background: c_ulong,
    ) -> Window;
    fn XMapWindow(dpy: *mut Display, w: Window);
    fn XSelectInput(dpy: *mut Display, w: Window, event_mask: c_int);
    fn XNextEvent(dpy: *mut Display, event: *mut XEvent) -> c_int;
    fn XFlush(dpy: *mut Display) -> c_int;
    fn XCloseDisplay(dpy: *mut Display) -> c_int;
    fn XCreateGC(dpy: *mut Display, d: Drawable, valuemask: u64, values: *mut ()) -> GC;
    fn XSetForeground(dpy: *mut Display, gc: GC, foreground: c_ulong);
    fn XFillRectangle(
        dpy: *mut Display,
        d: Drawable,
        gc: GC,
        x: c_int,
        y: c_int,
        width: u32,
        height: u32,
    );
    fn XPending(dpy: *mut Display) -> c_int;
}

type Display = std::ffi::c_void;
type Window = c_ulong;
type Drawable = c_ulong;
type GC = *mut std::ffi::c_void;

fn main() {
    // Открываем дисплей
    let display = unsafe { XOpenDisplay(null()) };
    if display.is_null() {
        panic!("Не удалось подключиться к X серверу");
    }

    // Получаем корневое окно
    let screen = unsafe { XDefaultScreen(display) };
    let root_window = unsafe { XRootWindow(display, screen) };

    // Создаём наше окно
    let window = unsafe {
        XCreateSimpleWindow(
            display,
            root_window,
            0,
            0,
            WIDTH as u32,
            HEIGHT as u32,
            0,
            0,
            0xff000000, // Чёрный фон
        )
    };

    if window == 0 {
        panic!("Не удалось создать окно!");
    }

    // Подписываемся на события
    unsafe {
        XSelectInput(display, window, KEY_PRESS_MASK | CLIENT_MESSAGE);
        XMapWindow(display, window);
        XFlush(display); // Отправляем команду на экран
    }

    // Создаём графический контекст
    let gc = unsafe { XCreateGC(display, window, 0, null_mut()) };
    if gc.is_null() {
        panic!("Не удалось создать GC");
    }

    // Устанавливаем цвет: красный (RGB: FF0000)
    unsafe {
        XSetForeground(display, gc, 0xFF0000); // красный
    }

    println!("Окно создано. Ждём событий...");

    // Цикл обработки событий
    let mut running = true;
    while running {
        if unsafe { XPending(display) } > 0 {
            let mut event: XEvent = unsafe { std::mem::zeroed() };
            unsafe {
                XNextEvent(display, &mut event);
            }

            match event.type_ {
                2 => {
                    // KeyPress
                    running = false;
                }
                _ => {}
            }
        } else {
            // Рисуем красный квадрат 10x10 по центру
            unsafe {
                XFillRectangle(display, window, gc, 195, 145, 10, 10);
                XFlush(display);
            }

            thread::sleep(Duration::from_millis(100));
        }
    }

    unsafe {
        XCloseDisplay(display);
    }

    println!("Программа завершена.");
}

Это вывод красного квадрата в окне. Работа напрямую через иксы. Понимаешь, егуи добавляет тебе совсем минималистичную либу на 1 метр, зато дает в ней тебе гуи, работу с 2д, работу с 3д. Да вообще полное удобство с минимальными затратами. Оно реально того стоит. Но можешь глянуть пример выше.