每特17劃

及時當勉勵 2004/06/07

我的 Linux 啓蒙緣起 — 2023-03-18

我的 Linux 啓蒙緣起

記得還在高中的時候,有次在電視上看到國外有人在抗議電腦強迫搭載 Windows 作業系統的遊行。新聞畫面裏,有人呼喊他們不要裝 Windows, 他們要裝 Linux, 他們要退費。

雖然這則新聞只佔了短短的邊角片段,但引起了我的好奇心: " Linux 是什麼? 好像是很酷的東西的樣子?!"

於是,我就去書店找看看有沒有相關的東西可以學習。記得當年買的第一本書是 ”施威銘“ 的,裏面附了 3 片光碟,其中一片是 Slaceware 3.6 。是我第一次嘗試安裝的 Linux distro。

這次回高雄時,看到以前的舊書籍,一時興起調查起來以前的舊新聞。沒想到還能找到以前的資料。

新聞

如果記憶沒錯的話,當時國外的活動應該就是 Windows Refond Day。

而當初買的第一本書,後來查出來是這一本:

  • ISBN: 9789577174642
  • 書名: LIUNX實務應用
  • 施威銘研究室
  • 出版日期: 1998-12-01
  • 旗標出版股份有限公司

其中,我在一個舊網頁 瞥見了下面敘述:

Imgur

其中提到的 3 片光碟,到今天我都還有印象:

  • Slaceware 3.6
  • Redhat 5.2
  • Debian 2.0

相關鏈接:

粗略調查 XQueryPointer 背後的運作 — 2023-03-10

粗略調查 XQueryPointer 背後的運作

這兩天於聊天頻道看到一個問題:

請問這個是函數封裝嗎~對c++還不太熟悉 我搜尋找不到 XQueryPointer 的 function 定義

註: 程式碼類似於 barrier/XWindowsImpl.cpp :

Bool XWindowsImpl::XQueryPointer(Display* display, Window w,
                                 Window* root_return, Window* child_return,
                                 int* root_x_return, int* root_y_return,
                                 int* win_x_return,  int* win_y_return,
                                 unsigned int* mask_return)
{
    return ::XQueryPointer(display, w, root_return, child_return, root_x_return,
                           root_y_return, win_x_return, win_y_return,
                           mask_return);
}

因爲,昨晚剛好有聊到 Xwindow System 及 libinput 的話題,加上剛好有人問到 QueryPointer 的問題,便 trace code 一番,並分享了一下看到的內容跟過程。

C++ 的 :: 開頭語法的疑問

很久沒用 C++ 了,看到 ::XLockDisplay(display);:: 開頭的寫法,一時不知道是什麼意思。 後來查到了, :: 是指 global namespace 。

參考資料如下:

程式架構

上面程式感覺像 Design Patterns 中的一段 p.63

Imgur

用途大約是:

  • XWindowsImpl 是要實作的類別, 而產生的物件是符合某個 XWindows 的通用規範。ex: IXWindowsImpl
  • 呼叫 XWindowsImpl::XQueryPointer() 時,背後會呼叫既存的 ::XQueryPointer()

XQueryPointer

我對後面發生什麼事好奇,請 ChatGPT 生一段 sample code 給我, 如下(截圖):

from Xlib import X, display

# 顯示器物件
d = display.Display()

# 螢幕物件
screen = d.screen()

# 根視窗
root = screen.root

# 取得滑鼠位置
pointer = root.query_pointer()

# 輸出滑鼠位置
print("滑鼠位置: (%d, %d)" % (pointer.root_x, pointer.root_y))

(註: 要裝 python-xlib 套件)

程式真的有執行如下圖

Imgur

下一步,根據裏面主要函式 root.query_pointer() 這個線索,去 GitHub 查背後內容, 找到 source code 片段:

    def query_pointer(self):
        return request.QueryPointer(display = self.display,
                                    window = self.id)

看出這有種類似發送 HTTP request 的味道, 進一步查 QueryPointer 的實作,找到 source code 如下:

class QueryPointer(rq.ReplyRequest):
    _request = rq.Struct(
        rq.Opcode(38),
        rq.Pad(1),
        rq.RequestLength(),
        rq.Window('window')
        )

    _reply = rq.Struct(
        rq.ReplyCode(),
        rq.Card8('same_screen'),
        rq.Card16('sequence_number'),
        rq.ReplyLength(),
        rq.Window('root'),
        rq.Window('child', (X.NONE, )),
        rq.Int16('root_x'),
        rq.Int16('root_y'),
        rq.Int16('win_x'),
        rq.Int16('win_y'),
        rq.Card16('mask'),
        rq.Pad(6),
        )

根據上面的程式片段,我注意到有 opcode38 這兩個關鍵字。 依此線索,之後在 google 查到相關的兩處相關定義:

概況

從上述的線索跟取得的資訊,推測取得滑鼠座標的框架大概是:

  • 視窗系統背後是 client, server 架構

  • 使用者應用程式,屬 client 端

  • User App 依通訊標準(XWindow prototol) 產生 request 封包,並向系統內的 XWindow server 發送要求。

    • 產生 request 封包有多種方式
      • 以 C/C++ 透過 libx11 (Xlib.h, libX11.so) 來生成 QueryPointer request 封包
      • 以 Python 透過 python-xlib, 來生成 QueryPointer request 封包
      • 以 Rust 生成 QueryPointer request 封包
  • XWindow server 處理完後回應資料給 User App。收到回應後的 User App 再繼續它的後續動作。

  • C/C++ => libX11.so => 產生 QueryPointer 要求封包 => 發給 Xwindow System(server)

  • Python => python-xlib(底層應該還是 libX11.so) => 產生 QueryPointer 要求封包 => 發給 Xwindow System(server)

Server 在哪?

在 Linux 上用 ps 指令查詢,找到 X server:

/usr/lib/Xorg :0 -seat seat0 -auth /run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch

以下述的 netstat 指令找 Xorg 相關的線索:

sudo netstat -n -p | grep Xorg

得到結果如下:

unix  3      [ ]         STREAM     CONNECTED     21239    548/Xorg             @/tmp/.X11-unix/X0
unix  3      [ ]         STREAM     CONNECTED     31689    548/Xorg             @/tmp/.X11-unix/X0
unix  3      [ ]         STREAM     CONNECTED     19362    548/Xorg             @/tmp/.X11-unix/X0
unix  3      [ ]         STREAM     CONNECTED     24421    548/Xorg             @/tmp/.X11-unix/X0
unix  3      [ ]         STREAM     CONNECTED     24419    548/Xorg             @/tmp/.X11-unix/X0
unix  3      [ ]         STREAM     CONNECTED     25019    548/Xorg             @/tmp/.X11-unix/X0

大略得知, 系統內由 Xorg 運行 XWindow server ,並於 @/tmp/.X11-unix/X0 接收 User Apps 發來的 request.

X client 從那裏知道 X server 的指向位置?

透過 DISPLAY 這個環境變數,例如:

export DISPLAY=:0

Xephyr :42 &
DISPLAY=:42 ssh -Y host

註: Xephyr 爲一個 nested X server ,可在目前的 Xwindow 下執行另一個 X server.

Server 於何處接 XQueryPointer 的 request?

一樣進 GitHub 查 QueryPointer。 但直接查, 搜尋結果太多太雜。(如圖)

Imgur

憑經驗, freedesktop.org 是 XWindow 發展的主力組織之一,在搜尋 GitHub 搜尋時加上 org:freedesktop 的範圍條件, 可大幅減少搜尋雜音,從 32K 多筆結果精簡到約 50 多筆資料(如圖):

Imgur

進一步檢視後,不久就找到處理 QueryPointer request 的 source code:

Imgur

此處再往下,預期能進一步找到 XWindow server 去取得 keyboard/mouse 數據的動作。

2023-03-19 試用 Rust 寫 sample code

準備目錄與檔案如下:

./test/
├── build.rs
├── Cargo.toml
└── src
    └── main.rs

Cargo.toml:

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

[dependencies]
x11 = "2.21.0"

main.rs:

extern crate x11;

use std::ptr;
use x11::xlib::{XOpenDisplay, XCloseDisplay, XDefaultRootWindow, XQueryPointer};

fn main() {
    unsafe {
        let display = XOpenDisplay(ptr::null());
        let root_window = XDefaultRootWindow(display);

        let mut root_return = 0;
        let mut child_return = 0;
        let mut root_x_return = 0;
        let mut root_y_return = 0;
        let mut win_x_return = 0;
        let mut win_y_return = 0;
        let mut mask_return = 0;
        XQueryPointer(
            display,
            root_window,
            &mut root_return,
            &mut child_return,
            &mut root_x_return,
            &mut root_y_return,
            &mut win_x_return,
            &mut win_y_return,
            &mut mask_return
        );

        println!("Mouse position: ({}, {})", root_x_return, root_y_return);

        XCloseDisplay(display);
    }
}

build.rs:

fn main(){
    println!("cargo:rustc-link-lib=X11");
}

( 註: build.rs 是特殊檔案,用於編譯參數設定。Ref: Build Scripts – The Cargo Book )

然後再執行:

cargo build
cargo run

預期會得到結果如下:

    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/test`
Mouse position: (653, 967)
自己對茶與咖啡的不同之處 — 2023-03-03

自己對茶與咖啡的不同之處

昨晚聚會時,由 autoteamaker 之故而聊到茶與咖啡的不同的話題。 有的人比較偏好咖啡, 而我自己是比較喜歡茶的。 不過,不代表我不喝或是排斥咖啡。基本上,只要是好喝的飲料,我都喜歡喝。

更精確一點的說,對於固定每天都要來上一份的,我比較傾向茶。 列了一下自己對茶和咖啡的感覺差異大致有:

咖啡
感覺 像是放一顆炭精進烤肉架 像是用水沖洗被油封塵蓋的地方
喝的量 1~2 杯 1 杯 ~ 3 壺
器具 大勝,咖啡機按一下就有 相對麻煩。還要洗濾茶網、清茶渣之類的
上火程度 較容易上火 較溫和。有些喝多會覺得冷(偏寒)
抒壓 不太有、反而會更亢奮 稍有緩解緊張感
調味 除單品外,常佐糖、奶精、檸檬、… 傾向不加任何調味
口味 多元 清爽、喝多不膩

總的來說,我偏好茶的帶給我的特色是:一種逐漸神清氣爽的感覺,順便喝很多水。

這裏特意避開對茶與咖啡的健康成份的分析。 因爲在沒有被可靠的驗證之下,這些資訊對我來說,多是扮演一種”安慰劑效應“的角色,說服自己 ”正在固定攝取對自己有益的東西“ 而已。 若認真以對身體健康的來說,兩者可能都遠不如一顆綜合維他命或一份表飛鳴(益生菌)來得簡單有效。 於是,最終還是會回到本質: “因爲它好喝” ! 而 “好喝” 就每人口味各異,各自表述、見仁見智了。

茶與咖啡的比較有太多地方被討論了,自己就不獻醜了。 但客觀來說,在 2023 的這個當下, 咖啡的發展體系顯然是遠遠勝於茶的體系。(在 18 世紀時可能是反過來的) 而目前在生活中,想要喝到“好茶”,也是確實有他麻煩的地方,這可能也是自己想作工具來改善的動機吧。

人多少會想得到認同,然爲身外物,可遇不可求。更重要的是,內觀自己真正追求的是什麼? 願大家都能找到並跟隨自己真心喜歡的事物。