實作 X11 底下的 Popup Menu

既然要投入 JavaScript 的發展,一個很重要的目標就是讓 JavaScript 能被用來開發 Native 桌面程式。而為了達成這樣的願景,我們的團隊沒日沒夜的發展各類基礎技術和擴充底階 API,甚至是將以 JavaScript 開發整個桌面環境(Desktop Environment, 如:GNOME、KDE、LXDE 或 XFCE 這類專案)為終極目標。

當然,跳出瀏覽器之後的 JavaScript,缺少了繪圖引擎,所以要拿來做圖型化使用者介面,會更為困難。慶幸的是,前些日子發展出的 jsdx-toolkit 已經解決了大多數的問題,除了有 3D、動畫等支援,也已經有了許多現代桌面有的UI元件(如:Entry、Label、Button... 等),以致我們完全可以放心的開發屬於自己的圖型化應用程式。

不過,目前的情況,在手機、平板或是特定用途的嵌入式系統中完全夠用,一旦回到更為複雜的桌面環境下,就會遭遇到許多的問題。像是回到 XWindow 底下後,會遇到許多 X11 的視窗管理機制,其視窗之間錯縱複雜的交互關係,就是我們要處理的。尤其是當我們在開發桌面環境時,就會發現在一般的桌面環境下,使用者可能會同時開無數個視窗和程式,並且隨機又大量的切換使用,這迫使我們必須去修改 jsdx-toolkit 以處理 X11 底下的更多狀況,符合並更完整支援一般桌面環境下的操作習慣。

你可能用過 GTK+/Qt 這類常見的 Toolkit,也知道在 X11 之下有很多種類型的視窗(Window),像是 Dialog、Splash、Menu、Popup Menu 等等,但你可能不知道這些現代 Toolkit 內部做了多少事。事實上,X11 本身雖定義了各類視窗的類型,但實際上 XWindow 和 Window Manager 並不會完全去照定義去處理你的視窗行為,更準確的說法是,X11 HWMH 中的基本定義和我們實際的認知是有出入的,該定義只是說希望達成的行為,但沒說是由誰(XWindow、Window Manage 還是 GUI Toolkit)去處理。

舉例來說,我們現在寫一支程式,該程式不使用任何現代的 GUI Toolkit,然後單純使用 X11 API 把一個 Window 的類型設成 Popup Menu。但是你會發現,它的實際行為並不像我們所想的,失去焦點(Focus)後就會消失,無論你是點擊其他視窗讓他失去焦點,還是採用快速鍵讓他失去焦點。此外,他也仍然會保留 Title bar 裝飾(Decorator),還有會在你的 Panel Taskbar 上出現一個新的 Task。就是這些種種視窗行為,和我們心中所認知的 Popup Menu 有很大的差異。

仔細研究 X11 EWMH Spec 就會發現,對於一個 Popup Menu 的視窗,除了設定類型外,你應該要做更多屬性設定,才會讓它合乎我們預想的行為,而這些東西被分散於 Spec 文件內的各處描述,想要一次性找出來困難重重。此外,失去焦點後要關閉 Popup Menu 視窗的功能,就不僅僅是設定屬性這麼簡單,而是要使用 XGrabPointer 攔截整個畫面的輸入事件(Input event),採用特殊的做法,才能達成。

說了這麼多,既然我們是自己開發一套新的 Toolkit,當然就要來實作一個合乎我們預期行為的 Popup Menu Window,首先在建立視窗並設定為 Popup Menu 類型後,需要做一些設定並欄截事件:
...

    /* Grab pointer */
    int i;
    Window grabWin = -1;
    XGetInputFocus(disp, &grabWin, &i);
    XGrabPointer(disp, grabWin, TRUE,
        ButtonPressMask | ButtonReleaseMask,
        GrabModeAsync, GrabModeAsync,
        None, None, CurrentTime);


    /* Skip Taskbar */
    Atom wm_state = XInternAtom(disp, "WM_STATE", False);
    Atom atom = XInternAtom(disp, "_NET_WM_STATE_SKIP_TASKBAR", False);

    XChangeProperty(disp, win, wm_state,
        XA_ATOM, 32, PropModeAppend,
        (unsigned char *)&atom, 1);


    /* Override redirect */
    XSetWindowAttributes attr;

    attr.override_redirect = True;
    XChangeWindowAttributes(disp, win, CWOverrideRedirect, &attr);


...

接著在監聽 X Event 迴圈處,去檢查是否為 grabWin 傳來的 ButtonRelease Event(意即使用者用點擊了 Popup Menu Window 之外的區域),如果是就停止 Event 的欄截並關閉視窗。
...
    if (xev->type == ButtonRelease && grabWin == xev->xbutton.window) {
        XUngrabPointer(disp, CurrentTime);
        grabWin = -1;

        XUnmapWindow(disp, win);

        continue;
    }
...

後記

經過許多努力,完善各項功能,完全用 JavaScript 打造的桌面環境,指日可待。:-P

留言

  1. > 完全用 JavaScript 打造的桌面環境

    這不就是 WebOS 的目的嗎? 但純用 JS 作的桌面市場未來性大嗎? 為什麼不將資源放在 HTML5 的 JS 上?

    回覆刪除
  2. 個人認為,JavaScript 只是種加速開發效率的途徑。因為還是遵循標準 Freedesktop.org spec,所以使用 JavaScript 開發出來的桌面,仍然能與過去的程式相容,市場大不大,就要看做的好不好用了。此外,由於 JavaScript 彈性相當大也容易使用,拿來客制起複雜的桌面,會比 C/C++ 寫的桌面更為容易。:-P

    其實 Web O.S. (這邊不是指 HP WebOS)這個議題若真要追朔,可以追到十幾年前。會不停被拿出來探討,我認為其中有一點動機很重要:『Web 的開發者都夢想開發底層和整套屬於自己的系統。』

    因為 Web 的開發太容易了,開發者不需要懂太多底層知識,或是理解任何高深的理論。任何種炫麗的特效,藉由 Browser 的 Render Engine,都可輕易達成。所以,HTML5 為何會為許多人追捧?就是因為這個 Spec 可以達成更多事情,給予了 Web 開發者更大的發展空間。

    以前我也曾這樣想,如果完全用 HTML + JS 有多好,但當你開過一個網頁可以吃掉 1GB ~ 2GB 的記憶體時(重點是這非惡意網頁,而是前端工程師做出來準備拿來當上線的東西),你就會開始重新省視問題出在哪了,水能載舟亦能覆舟。

    我其實同意,HTML5 應該是未來的方向,但短期內應該還不會完全在各領域成局,尤其是拿它做應用程式和系統開發會有一段辛苦路要走,硬體資源能不能負擔肯定是最主要的原因之一。你可能會說,目前 iOS/Android 上已有 HTML5+JS 的一些 Toolkit,可以拿來開發應用程式。但開發者在使用上其實都有一定開發模式,不會像寫一般網頁一樣自由亂做。所以你會發現,雖然用 HTML+JS,但並不會這麼美好的讓你有機會亂搞一通。既然如此,使用 HTML5 可以自由惡搞的優勢就失去了,但你仍然得承受效能帶來的負面影響,和功能的限制,剩下的唯一價值,就是你很熟悉 JavaScript。

    當然我們也可以全力做 HTML5,但那就限死了自己,也分散了力量,畢竟我們不開發瀏覽器,如果說把未來放在我們無法控制的瀏覽器上,未來無法評估。反過來想,若不考慮 HTML5,只考慮可以用 JavaScript 控制整個作業系統和開發各種應用(其實 Python 就有這樣的味道存在),那麼,HTML5 對我們來說不過就只是種 Render Engine Backend。我們不但不用承擔硬體能力限制的問題及風險,更可以全力加強 JavaScript 的能力,廣泛走進任何一種應用。

    然後,等到 HTML5 成熟,再轉向 HTML5 也不遲。

    回覆刪除
  3. 因為能力限制想像力。我的腦袋一直是活在瀏覽器中的,也不是慣C一族(我多半是用 Python, JavaScript, shell script),對你所說的 JavaScript in browser 的缺點沒完全參透。

    事實上,我個人一直在期待 ChromeOS 變成主流,這樣大家都會用瀏覽器來作應用程式介面,我甚至也在規劃用瀏覽器來取代開發 IDE(如: vim, Netbeans ...),以及研究在瀏覽器上作影音編輯軟體的可行性。因為雲端運算系統能幫使用者把所有資料及重度運算資源的項目作妥善管理,讓使用者只需要一個介面(就是瀏覽器)去操作它,就這個角度來看,桌面應用程式好像可以不用存在了。

    最後,我以網頁程式設計師的角度來請教一個問題:『這個開發桌面程式的 JavaScript toolkit ,對網頁程式設計師有幫助嗎』? 也就是說我們使用了這個 JavaScript toolkit 去開發桌面程式,之後能"無縫(或者說大約無縫)"轉到瀏覽器上嗎? 反之亦然嗎?

    回覆刪除
    回覆
    1. 先回答您最後的問題,其實 GUI Toolkit 對我們來說只是其中一個元件,我們目標是提供完善的 Platform 和 Framework ,讓 JavaScript 開發者可以走入更底層的系統,有更大的發揮空間。而單純就 GUI Toolkit 這部份來說,未來會去支援 HTML5 是肯定的。因為就如我之前我說,我們視 HTML5(Browser) 為繪圖引擎的一種,雖然何時會達成我現在還不敢跟你說。

      所以我喜歡將 HTML 和 JavaScript 拆開來理解,而對 JavaScript 的看法是,他就是一個非常有彈性,大家都會的一種語言。所以,誰說 JavaScript 程式就一定要有 UI 介面呢?最後是用 Browser 還是自己開發 UI Render Engine 我覺得那是因用途而定。

      至於桌面應用程式(泛指 Native Application)會不會不用存在?我想,短期內是不太可能消失。換方面想,若跳出桌面,跳出有 UI 的應用框架。也是屬於 Native 的系統程式難道就不會存在了嗎?我想,這應該是不會消失的。那麼,JavaScript 為何不能做這塊呢?這就是我為什麼說不希望被 Browser 思維限死的原因。:-)

      BTW, 既然你提到了 Online IDE,老實跟你說,我們有部份的資源其實也正在往這方向走,如果你剛好是同路人,我們可以一同討論。:-)

      我認為也同意,工具類的應用,是很適合使用 Web 來達成。

      刪除
  4. 看到你這篇讓我想到以前的一個想法~~~所有的window都是用html5畫出來的,你的桌面就是一個可以瀏覽的browser看網頁看~~~~任何的程式都透過java script就可以完成~~~感覺這個東西完成就能達成

    回覆刪除
    回覆
    1. 其實,您說的東西就是 xPUD,之前曾經參與開發。:-)

      但我個人是認為,達成方式不同,目標也不同。

      HTML5 不是萬靈丹,事實上,離開 Web 應用之後,他的問題遠遠超過許多人的想像。
      (除非你是某個瀏覽器開發商,也做好長期奮戰的準備)

      刪除

張貼留言

這個網誌中的熱門文章

Web 技術中的 Session 是什麼?

上手使用 JavaScript 的 Map、Reduce 吧!

淺談 USB 通訊架構之定義(二)

淺談 USB 通訊架構之定義(一)

JavaScript async/await 的奇淫技巧