* 發布第2.9.0版;

* 修復get_suitable_font函數的邏輯缺陷;
        * 修復操作中心圖標不對齊的缺陷;
        * 修復set_ewmh函數的數組越界的缺陷;
        * 修復get_prop函數的邏輯缺陷;
        * 使用按鈕構件代替按鈕窗口;
        * 使用面向對象思想重構界面部分;
        * 爲了更加模塊化而重構代碼;
        * 微調界面配色。
This commit is contained in:
gsm 2024-04-09 00:04:23 +08:00
parent 7051a9bd1b
commit a3a00eba5b
41 changed files with 2051 additions and 1209 deletions

View File

@ -9,6 +9,17 @@
* <http://www.gnu.org/licenses/>。
**************************************************************************/
2024年 04月 08日 星期一 12:38:21 HKT gsm <406643764@qq.com>
* 發布第2.9.0版;
* 修復get_suitable_font函數的邏輯缺陷
* 修復操作中心圖標不對齊的缺陷;
* 修復set_ewmh函數的數組越界的缺陷
* 修復get_prop函數的邏輯缺陷
* 使用按鈕構件代替按鈕窗口;
* 使用面向對象思想重構界面部分;
* 爲了更加模塊化而重構代碼;
* 微調界面配色。
2024年 02月 25日 星期日 19:54:55 HKT gsm <406643764@qq.com>
* 發布第2.8.3版;
* set_net_client_list*函數改爲只針對當前桌面;

6
NEWS
View File

@ -9,6 +9,12 @@
* <http://www.gnu.org/licenses/>。
* ************************************************************************/
第2.9.0版:
* 修復在某些情況下崩潰的缺陷;
* 修復操作中心圖標不對齊的缺陷;
* 修復任務欄按鈕提示色異常的缺陷;
* 微調界面配色。
第2.8.3版:
* 更好的兼容第三方任務欄。

3
TODO
View File

@ -9,6 +9,9 @@
* <http://www.gnu.org/licenses/>。
* ************************************************************************/
第2.9.0版的下一步的開發計劃:
* 實現界面自動配色功能。
第2.8.3版的下一步的開發計劃:
* 代碼重構。

View File

@ -12,7 +12,7 @@
./" program. Otherwise, see <http://www.gnu.org/licenses/>.
./" ************************************************* ***************************/
.TH gwm 1 February 2024 "gwm 2.8.3" gwm
.TH gwm 1 April 2024 "gwm 2.9.0" gwm
.
.SH NAME
.B
@ -37,7 +37,7 @@ Stacking mode is a layout mode in which windows can be stacked, and all normal w
.PP
Preview mode is a layout mode in which all windows equally distribute workarea space. If a window is selected in this mode, it will switch to the previous layout mode, the selected window will become the current window, and other windows will remain in the previous layout mode. If the previous layout mode is tiling mode, the selected window will be moved to the top of the main area.
.PP
gwm resets the parent window for all windows, the parent window also includes the border, the title bar, both of which are collectively called the window frame. The original window range before reparenting is called the non-frame area. Among them, the title bar sets the title area and buttons sequentially from left to right. The title area is used to display the title of the window and provide the function of moving the window. Buttons are used to implement specific functions, and the number of buttons varies with the basic window layout mode. In tiling mode, the text of each button from left to right is: ◁, ▼, ▷, △, —, ◲, 🗙. In stacking mode, ◁, ▼, ▷, △ buttons are not displayed. In preview mode, only the 🗙 button is displayed.
gwm resets the parent window for all windows, the parent window also includes the border, the title bar, both of which are collectively called the window frame. The original window range before reparenting is called the non-frame area. Among them, the title bar sets the logo button, title area and other buttons sequentially from left to right. The logo button is used to provide drop-down menu. The title area is used to display the title of the window and provide the function of moving the window. Other buttons are used to implement specific functions, and the number of buttons varies with the basic window layout mode. In tiling mode, the text of each button from left to right is: ◁, ▼, ▷, △, —, ◲, 🗙. In stacking mode, ◁, ▼, ▷, △ buttons are not displayed. In preview mode, only the 🗙 button is displayed.
.
.SH OPTIONS
none.

View File

@ -9,7 +9,7 @@
./" <http://www.gnu.org/licenses/>。
./" ************************************************************************/
.TH gwm 1 20242月 "gwm 2.8.3" gwm
.TH gwm 1 20244月 "gwm 2.9.0" gwm
.
.SH 名称
.B
@ -34,7 +34,7 @@ gwm把物理屏幕虚拟为多个逻辑屏幕即所谓的虚拟桌面。在
.PP
预览模式是所有窗口平均分配工作区域空间的布局模式。若在该模式下选中窗口,则切换至上一布局模式,选中的窗口变成当前窗口,其余窗口保持在前一布局模式中位置。若在前一布局模式为平铺模式,则选中的窗口移动至主区域顶部。
.PP
gwm为所有窗口分别重设父窗口该父窗口还包括边框、标题栏这两者统称窗口框架。重设父窗口之前的原窗口范围称为非框架区域。其中标题栏从左至右依次设置标题区域、按钮。标题区域用于显示窗口的标题以及提供移动窗口的功能。按钮用于实现特定的功能按钮的数量随基本窗口布局模式而异。在平铺模式下各按钮的文字从左至右依次为◁、▼、▷、△、—、◲、🗙。在堆叠模式下不显示◁、▼、▷、△按钮。在预览模式下仅显示🗙按钮。
gwm为所有窗口分别重设父窗口该父窗口还包括边框、标题栏这两者统称窗口框架。重设父窗口之前的原窗口范围称为非框架区域。其中标题栏从左至右依次设置程序标识按钮、标题区域、其他按钮。程序标识按钮用于实现下拉菜单功能。标题区域用于显示窗口的标题,以及提供移动窗口的功能。其他按钮用于实现特定的功能,按钮的数量随基本窗口布局模式而异。在平铺模式下,各按钮的文字从左至右依次为:◁、▼、▷、△、—、◲、🗙。在堆叠模式下,不显示◁、▼、▷、△按钮。在预览模式下,仅显示🗙按钮。
.
.SH 选项
无。

View File

@ -9,7 +9,7 @@
./" <http://www.gnu.org/licenses/>。
./" ************************************************************************/
.TH gwm 1 20242月 "gwm 2.8.3" gwm
.TH gwm 1 20244月 "gwm 2.9.0" gwm
.
.SH 名稱
.B
@ -34,7 +34,7 @@ gwm把物理屏幕虛擬爲多個邏輯屏幕即所謂的虛擬桌面。在
.PP
預覽模式是所有窗口平均分配工作區域空間的布局模式。若在該模式下選中窗口,則切換至上一布局模式,選中的窗口變成當前窗口,其餘窗口保持在前一布局模式中位置。若在前一布局模式爲平鋪模式,則選中的窗口移動至主區域頂部。
.PP
gwm爲所有窗口分別重設父窗口該父窗口還包括邊框、標題欄這兩者統稱窗口框架。重設父窗口之前的原窗口範圍稱爲非框架區域。其中標題欄從左至右依次設置標題區域、按鈕。標題區域用於顯示窗口的標題以及提供移動窗口的功能。按鈕用於實現特定的功能按鈕的數量隨基本窗口布局模式而異。在平鋪模式下各按鈕的文字從左至右依次爲◁、▼、▷、△、—、◲、🗙。在堆疊模式下不顯示◁、▼、▷、△按鈕。在預覽模式下僅顯示🗙按鈕。
gwm爲所有窗口分別重設父窗口該父窗口還包括邊框、標題欄這兩者統稱窗口框架。重設父窗口之前的原窗口範圍稱爲非框架區域。其中標題欄從左至右依次設置程序標識按鈕、標題區域、其他按鈕。程序標識按鈕用於實現下拉菜單功能。標題區域用於顯示窗口的標題,以及提供移動窗口的功能。其他按鈕用於實現特定的功能,按鈕的數量隨基本窗口布局模式而異。在平鋪模式下,各按鈕的文字從左至右依次爲:◁、▼、▷、△、—、◲、🗙。在堆疊模式下,不顯示◁、▼、▷、△按鈕。在預覽模式下,僅顯示🗙按鈕。
.
.SH 選項
無。

View File

@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
"Project-Id-Version: gwm 2.8.3\n"
"Project-Id-Version: gwm 2.9.0\n"
"Report-Msgid-Bugs-To: 406643764@qq.com\n"
"POT-Creation-Date: 2024-02-25 19:57+0800\n"
"POT-Creation-Date: 2024-04-08 13:09+0800\n"
"PO-Revision-Date: 2023-05-05 11:26+0800\n"
"Last-Translator: gsm <406643764@qq.com>\n"
"Language-Team: English (British) <(nothing)>\n"
@ -17,238 +17,366 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: client.c:805
#: client.c:765
msgid "錯誤:查詢窗口清單失敗!"
msgstr "Error: Failed to query window list!"
#. 操作中心按鈕類型 按鈕文字
#: config.c:487
msgid "🛟 幫助"
msgstr "🛟 Help"
#. 操作中心按鈕類型 圖標名 符號 標籤
#: config.c:549
msgid "🛟"
msgstr "🛟"
#: config.c:488
msgid "📁 文件"
msgstr "📁 Doc"
#: config.c:549
msgid "幫助"
msgstr "Help"
#: config.c:489
msgid "🖥️ 終端模擬器"
msgstr "🖥️ Terminal"
#: config.c:550
msgid "📁"
msgstr "📁"
#: config.c:490
msgid "🌐 網絡瀏覽器"
msgstr "🌐 Web browser"
#: config.c:550
msgid "文件"
msgstr "Doc"
#: config.c:492
msgid "🎮️ 遊戲"
msgstr "🎮️ Game"
#: config.c:551
msgid "🖥️"
msgstr "🖥️"
#: config.c:493
msgid "🎬 播放影音"
msgstr "🎬 Player"
#: config.c:551
msgid "終端模擬器"
msgstr "Terminal"
#: config.c:494
msgid "⏯️ 切換播放狀態"
#: config.c:552
msgid "🌐"
msgstr "🌐"
#: config.c:552
msgid "網絡瀏覽器"
msgstr "Web browser"
#: config.c:554
msgid "🎮️"
msgstr "🎮️"
#: config.c:554
msgid "遊戲"
msgstr "Game"
#: config.c:555
msgid "🎬"
msgstr "🎬"
#: config.c:555
msgid "播放影音"
msgstr "Player"
#: config.c:556
msgid "⏯️"
msgstr "⏯️"
#: config.c:556
msgid "切換播放狀態"
msgstr "Toggle play status"
#: config.c:495
msgid "⏹️ 關閉影音"
#: config.c:557
msgid "⏹️"
msgstr "⏹️"
#: config.c:557
msgid "關閉影音"
msgstr "Quit player"
#: config.c:497
msgid "🔈️ 减小音量"
msgstr "🔈️ Volume down"
#: config.c:559
msgid "🔈️"
msgstr "🔈️"
#: config.c:498
msgid "🔉 增大音量"
msgstr "🔉 Volume up"
#: config.c:559
msgid "减小音量"
msgstr "Volume down"
#: config.c:499
msgid "🔊 最大音量"
msgstr "🔊 Volume max"
#: config.c:560
msgid "🔉"
msgstr "🔉"
#: config.c:500
msgid "🔇 靜音切換"
msgstr "🔇 Mute toggle"
#: config.c:560
msgid "增大音量"
msgstr "Volume up"
#: config.c:502
msgid "▼ 暫主區開窗"
msgstr "▼ Main next"
#: config.c:561
msgid "🔊"
msgstr "🔊"
#: config.c:503
msgid "◁ 暫次區開窗"
msgstr "◁ Sec next"
#: config.c:561
msgid "最大音量"
msgstr "Volume max"
#: config.c:504
msgid "▷ 暫固定區開窗"
msgstr "▷ Fixed next"
#: config.c:562
msgid "🔇"
msgstr "🔇"
#: config.c:505
msgid "△ 暫懸浮層開窗"
msgstr "△ Float next"
#: config.c:562
msgid "靜音切換"
msgstr "Mute toggle"
#: config.c:507
msgid "⬆️ 增大主區容量"
msgstr "⬆️ Main area n+"
#: config.c:564
msgid ""
msgstr ""
#: config.c:508
msgid "⬇️ 减小主區容量"
msgstr "⬇️ Main area n-"
#: config.c:564
msgid "暫主區開窗"
msgstr "Main next"
#: config.c:509
msgid "🗔 開關當前窗口標題欄"
msgstr "🗔 Toggle cur win titlebar"
#: config.c:565
msgid ""
msgstr ""
#: config.c:510
msgid "⬚ 開關當前窗口邊框"
msgstr "⬚ Toggle cur win border"
#: config.c:565
msgid "暫次區開窗"
msgstr "Sec next"
#: config.c:512
msgid "❎ 關閉桌面所有窗口"
msgstr "❎ Close all win on desktop"
#: config.c:566
msgid ""
msgstr ""
#: config.c:513
msgid "✀ 當前窗口截圖"
msgstr "✀ Cur win screenshot"
#: config.c:566
msgid "暫固定區開窗"
msgstr "Fixed next"
#: config.c:514
msgid "🖵 全屏截圖"
msgstr "🖵 Full screen screenshot"
#: config.c:567
msgid ""
msgstr ""
#: config.c:515
msgid "👁️ 切換聚焦模式"
msgstr "👁️ Toggle focus mode"
#: config.c:567
msgid "暫懸浮層開窗"
msgstr "Float next"
#: config.c:517
msgid "🪡 開關合成器"
msgstr "🪡 Toggle compositor"
#: config.c:569
msgid "⬆️"
msgstr "⬆️"
#: config.c:518
msgid "🌌 切換壁紙"
msgstr "🌌 Switch wallpaper"
#: config.c:569
msgid "增大主區容量"
msgstr "Main area n+"
#: config.c:519
msgid "🎨 切換顏色主題"
msgstr "🎨 Switch color theme"
#: config.c:570
msgid "⬇️"
msgstr "⬇️"
#: config.c:520
msgid "❌ 退出gwm"
msgstr "❌ Quit gwm"
#: config.c:570
msgid "减小主區容量"
msgstr "Main area n-"
#: config.c:522
msgid "🚶 注銷"
msgstr "🚶 Log out"
#: config.c:571
msgid "🗔"
msgstr "🗔"
#: config.c:523
msgid "↻ 重啓"
msgstr "↻ Reboot"
#: config.c:571
msgid "開關當前窗口標題欄"
msgstr "Toggle cur win titlebar"
#: config.c:524
msgid "⏻ 關機"
msgstr "⏻ Shut down"
#: config.c:572
msgid ""
msgstr ""
#: config.c:525
msgid "🔍️ 運行"
msgstr "🔍️ Run command"
#: config.c:572
msgid "開關當前窗口邊框"
msgstr "Toggle cur win border"
#. 客戶窗口菜單項類型 按鈕文字
#: config.c:534
#: config.c:574
msgid "❎"
msgstr "❎"
#: config.c:574
msgid "關閉桌面所有窗口"
msgstr "Close all win on desktop"
#: config.c:575
msgid "✀"
msgstr "✀"
#: config.c:575
msgid "當前窗口截圖"
msgstr "Cur win screenshot"
#: config.c:576
msgid "🖵"
msgstr "🖵"
#: config.c:576
msgid "全屏截圖"
msgstr "Full screen screenshot"
#: config.c:577
msgid "👁️"
msgstr "👁️"
#: config.c:577
msgid "切換聚焦模式"
msgstr "Toggle focus mode"
#: config.c:579
msgid "🪡"
msgstr "🪡"
#: config.c:579
msgid "開關合成器"
msgstr "Toggle compositor"
#: config.c:580
msgid "🌌"
msgstr "🌌"
#: config.c:580
msgid "切換壁紙"
msgstr "Switch wallpaper"
#: config.c:581
msgid "🎨"
msgstr "🎨"
#: config.c:581
msgid "切換顏色主題"
msgstr "Switch color theme"
#: config.c:582
msgid "❌"
msgstr "❌"
#: config.c:582
msgid "退出gwm"
msgstr "Quit gwm"
#: config.c:584
msgid "🚶"
msgstr "🚶"
#: config.c:584
msgid "注銷"
msgstr "Log out"
#: config.c:585
msgid "↻"
msgstr "↻"
#: config.c:585
msgid "重啓"
msgstr "Reboot"
#: config.c:586
msgid "⏻"
msgstr "⏻"
#: config.c:586
msgid "關機"
msgstr "Shut down"
#: config.c:587
msgid "🔍️"
msgstr "Run command"
#: config.c:587
msgid "運行"
msgstr "Run command"
#. 客戶窗口菜單項類型 圖標名 符號 標籤
#: config.c:596
msgid "卷起/放下"
msgstr "Roll up / Put down"
#: config.c:535
#: config.c:597
msgid "縱向最大化"
msgstr "Vertical max"
#: config.c:536
#: config.c:598
msgid "橫向最大化"
msgstr "Horizontal max"
#: config.c:537
#: config.c:599
msgid "最大化至上半屏"
msgstr "Max to top half screen"
#: config.c:538
#: config.c:600
msgid "最大化至下半屏"
msgstr "Max to bottom half screen"
#: config.c:539
#: config.c:601
msgid "最大化至左半屏"
msgstr "Max to left half screen"
#: config.c:540
#: config.c:602
msgid "最大化至右半屏"
msgstr "Max to right half screen"
#: config.c:541
#: config.c:603
msgid "完全最大化"
msgstr "fully max"
#. 構件類型 構件功能提示文字
#: config.c:553
#. 構件標識 構件功能提示文字
#: config.c:615
msgid "切換到次要區域"
msgstr "To sec area"
#: config.c:554
#: config.c:616
msgid "切換到主要區域"
msgstr "To main area"
#: config.c:555
#: config.c:617
msgid "切換到固定區域"
msgstr "To fixed area"
#: config.c:556
#: config.c:618
msgid "切換到懸浮層"
msgstr "To float layer"
#: config.c:557
#: config.c:619
msgid "切換到圖符區域"
msgstr "To icon area"
#: config.c:558
#: config.c:620
msgid "最大化/還原窗口"
msgstr "Max/Restore window"
#: config.c:559
#: config.c:621
msgid "關閉窗口"
msgstr "Close window"
#: config.c:560
#: config.c:622
msgid "切換到虛擬桌面1"
msgstr "To virtual desktop 1"
#: config.c:561
#: config.c:623
msgid "切換到虛擬桌面2"
msgstr "To virtual desktop 2"
#: config.c:562
#: config.c:624
msgid "切換到虛擬桌面3"
msgstr "To virtual desktop 3"
#: config.c:563
#: config.c:625
msgid "切換到預覽模式"
msgstr "To preview mode"
#: config.c:564
#: config.c:626
msgid "切換到堆疊模式"
msgstr "To stacking mode"
#: config.c:565
#: config.c:627
msgid "切換到平鋪模式"
msgstr "To tiling mode"
#: config.c:566
#: config.c:628
msgid "顯示桌面"
msgstr "Show desktop"
#: config.c:567
#: config.c:629
msgid "打開操作中心"
msgstr "Open action center"
#: config.c:568
#: config.c:630
msgid "打開窗口菜單"
msgstr "Open window menu"
#: config.c:597
#: config.c:659
msgid "請輸入命令,然後按回車執行"
msgstr "Enter the command and press Enter to execute"
@ -324,7 +452,7 @@ msgstr "SIGQUIT signal handler cannot be installed"
msgid "不能安裝SIGHUP信號處理函數"
msgstr "SIGHUP signal handler cannot be installed"
#: init.c:120
#: init.c:121
#, c-format
msgid "錯誤: 不能設置輸入法"
msgstr "Error: Unable to set input method"
@ -342,17 +470,17 @@ msgstr "Error: There is already another window manager running!"
msgid "X錯誤資源號=%#lx, 請求量=%lu, 錯誤碼=%d, 主請求碼=%d, 次請求碼=%d\n"
msgstr "X error: Resource number=%#lx, Request number=%lu, Error code=%d, Major request code=%d, Minor request code=%d\n"
#: widget.c:123
#: widget.c:245
#, c-format
msgid "錯誤窗口0x%lx輸入法設置失敗"
msgstr "Error: Window (0x%lx) input method setup failed!"
#: widget.c:239
#: widget.c:359
#, c-format
msgid "錯誤:找不到指定的鍵符號相應的功能轉換鍵!\n"
msgstr "Error: The corresponding modifier key for the specified key symbol could not be found!\n"
#: widget.c:242
#: widget.c:362
#, c-format
msgid "錯誤:指定的鍵符號不存在對應的鍵代碼!\n"
msgstr "Error: The key symbol specified does not have a corresponding key code!\n"

View File

@ -6,9 +6,9 @@
#
msgid ""
msgstr ""
"Project-Id-Version: gwm 2.8.3\n"
"Project-Id-Version: gwm 2.9.0\n"
"Report-Msgid-Bugs-To: 406643764@qq.com\n"
"POT-Creation-Date: 2024-02-25 19:57+0800\n"
"POT-Creation-Date: 2024-04-08 13:03+0800\n"
"PO-Revision-Date: 2023-05-05 09:56+0800\n"
"Last-Translator: gsm <406643764@qq.com>\n"
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
@ -17,238 +17,366 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: client.c:805
#: client.c:765
msgid "錯誤:查詢窗口清單失敗!"
msgstr "错误:查询窗口列表失败!"
#. 操作中心按鈕類型 按鈕文字
#: config.c:487
msgid "🛟 幫助"
msgstr "🛟 帮助"
#. 操作中心按鈕類型 圖標名 符號 標籤
#: config.c:549
msgid "🛟"
msgstr "🛟"
#: config.c:488
msgid "📁 文件"
msgstr "📁 文件"
#: config.c:549
msgid "幫助"
msgstr "帮助"
#: config.c:489
msgid "🖥️ 終端模擬器"
msgstr "🖥️ 终端模拟器"
#: config.c:550
msgid "📁"
msgstr "📁"
#: config.c:490
msgid "🌐 網絡瀏覽器"
msgstr "🌐 网络浏览器"
#: config.c:550
msgid "文件"
msgstr "文件"
#: config.c:492
msgid "🎮️ 遊戲"
msgstr "🎮️ 游戏"
#: config.c:551
msgid "🖥️"
msgstr "🖥️"
#: config.c:493
msgid "🎬 播放影音"
msgstr "🎬 播放影音"
#: config.c:551
msgid "終端模擬器"
msgstr "终端模拟器"
#: config.c:494
msgid "⏯️ 切換播放狀態"
msgstr "⏯️ 切换播放状态"
#: config.c:552
msgid "🌐"
msgstr "🌐"
#: config.c:495
msgid "⏹️ 關閉影音"
msgstr "⏹️ 关闭影音"
#: config.c:552
msgid "網絡瀏覽器"
msgstr "网络浏览器"
#: config.c:497
msgid "🔈️ 减小音量"
msgstr "🔈️ 减小音量"
#: config.c:554
msgid "🎮️"
msgstr "🎮️"
#: config.c:498
msgid "🔉 增大音量"
msgstr "🔉 增大音量"
#: config.c:554
msgid "遊戲"
msgstr "游戏"
#: config.c:499
msgid "🔊 最大音量"
msgstr "🔊 最大音量"
#: config.c:555
msgid "🎬"
msgstr "🎬"
#: config.c:500
msgid "🔇 靜音切換"
msgstr "🔇 静音切换"
#: config.c:555
msgid "播放影音"
msgstr "播放影音"
#: config.c:502
msgid "▼ 暫主區開窗"
msgstr "▼ 暂主区开窗"
#: config.c:556
msgid "⏯️"
msgstr "⏯️"
#: config.c:503
msgid "◁ 暫次區開窗"
msgstr "◁ 暂次区开窗"
#: config.c:556
msgid "切換播放狀態"
msgstr "切换播放状态"
#: config.c:504
msgid "▷ 暫固定區開窗"
msgstr "▷ 暂固定区开窗"
#: config.c:557
msgid "⏹️"
msgstr "⏹️"
#: config.c:505
msgid "△ 暫懸浮層開窗"
msgstr "△ 暂悬浮层开窗"
#: config.c:557
msgid "關閉影音"
msgstr "关闭影音"
#: config.c:507
msgid "⬆️ 增大主區容量"
msgstr "⬆️ 增大主区容量"
#: config.c:559
msgid "🔈️"
msgstr "🔈️"
#: config.c:508
msgid "⬇️ 减小主區容量"
msgstr "⬇️ 减小主区容量"
#: config.c:559
msgid "减小音量"
msgstr "减小音量"
#: config.c:509
msgid "🗔 開關當前窗口標題欄"
msgstr "🗔 开关当前窗口标题栏"
#: config.c:560
msgid "🔉"
msgstr "🔉"
#: config.c:510
msgid "⬚ 開關當前窗口邊框"
msgstr "⬚ 开关当前窗口边框"
#: config.c:560
msgid "增大音量"
msgstr "增大音量"
#: config.c:512
msgid "❎ 關閉桌面所有窗口"
msgstr "❎ 关闭桌面所有窗口"
#: config.c:561
msgid "🔊"
msgstr "🔊"
#: config.c:513
msgid "✀ 當前窗口截圖"
msgstr "✀ 当前窗口截图"
#: config.c:561
msgid "最大音量"
msgstr "最大音量"
#: config.c:514
msgid "🖵 全屏截圖"
msgstr "🖵 全屏截图"
#: config.c:562
msgid "🔇"
msgstr "🔇"
#: config.c:515
msgid "👁️ 切換聚焦模式"
msgstr "👁️ 切换聚焦模式"
#: config.c:562
msgid "靜音切換"
msgstr "静音切换"
#: config.c:517
msgid "🪡 開關合成器"
msgstr "🪡 开关合成器"
#: config.c:564
msgid ""
msgstr ""
#: config.c:518
msgid "🌌 切換壁紙"
msgstr "🌌 切换壁纸"
#: config.c:564
msgid "暫主區開窗"
msgstr "暂主区开窗"
#: config.c:519
msgid "🎨 切換顏色主題"
msgstr "🎨 切换颜色主题"
#: config.c:565
msgid ""
msgstr ""
#: config.c:520
msgid "❌ 退出gwm"
msgstr "❌ 退出gwm"
#: config.c:565
msgid "暫次區開窗"
msgstr "暂次区开窗"
#: config.c:522
msgid "🚶 注銷"
msgstr "🚶 注销"
#: config.c:566
msgid ""
msgstr ""
#: config.c:523
msgid "↻ 重啓"
msgstr "↻ 重启"
#: config.c:566
msgid "暫固定區開窗"
msgstr "暂固定区开窗"
#: config.c:524
msgid "⏻ 關機"
msgstr "⏻ 关机"
#: config.c:567
msgid ""
msgstr ""
#: config.c:525
msgid "🔍️ 運行"
msgstr "🔍️ 运行"
#: config.c:567
msgid "暫懸浮層開窗"
msgstr "暂悬浮层开窗"
#. 客戶窗口菜單項類型 按鈕文字
#: config.c:534
#: config.c:569
msgid "⬆️"
msgstr "⬆️"
#: config.c:569
msgid "增大主區容量"
msgstr "增大主区容量"
#: config.c:570
msgid "⬇️"
msgstr "⬇️"
#: config.c:570
msgid "减小主區容量"
msgstr "减小主区容量"
#: config.c:571
msgid "🗔"
msgstr "🗔"
#: config.c:571
msgid "開關當前窗口標題欄"
msgstr "开关当前窗口标题栏"
#: config.c:572
msgid "⬚"
msgstr "⬚"
#: config.c:572
msgid "開關當前窗口邊框"
msgstr "开关当前窗口边框"
#: config.c:574
msgid "❎"
msgstr "❎"
#: config.c:574
msgid "關閉桌面所有窗口"
msgstr "关闭桌面所有窗口"
#: config.c:575
msgid "✀"
msgstr "✀"
#: config.c:575
msgid "當前窗口截圖"
msgstr "当前窗口截图"
#: config.c:576
msgid "🖵"
msgstr "🖵"
#: config.c:576
msgid "全屏截圖"
msgstr "全屏截图"
#: config.c:577
msgid "👁️"
msgstr "👁️"
#: config.c:577
msgid "切換聚焦模式"
msgstr "切换聚焦模式"
#: config.c:579
msgid "🪡"
msgstr "🪡"
#: config.c:579
msgid "開關合成器"
msgstr "开关合成器"
#: config.c:580
msgid "🌌"
msgstr "🌌"
#: config.c:580
msgid "切換壁紙"
msgstr "切换壁纸"
#: config.c:581
msgid "🎨"
msgstr "🎨"
#: config.c:581
msgid "切換顏色主題"
msgstr "切换颜色主题"
#: config.c:582
msgid "❌"
msgstr "❌"
#: config.c:582
msgid "退出gwm"
msgstr "退出gwm"
#: config.c:584
msgid "🚶"
msgstr "🚶"
#: config.c:584
msgid "注銷"
msgstr "注销"
#: config.c:585
msgid "↻"
msgstr "↻"
#: config.c:585
msgid "重啓"
msgstr "重启"
#: config.c:586
msgid "⏻"
msgstr "⏻"
#: config.c:586
msgid "關機"
msgstr "关机"
#: config.c:587
msgid "🔍️"
msgstr "🔍️"
#: config.c:587
msgid "運行"
msgstr "运行"
#. 客戶窗口菜單項類型 圖標名 符號 標籤
#: config.c:596
msgid "卷起/放下"
msgstr "卷起/放下"
#: config.c:535
#: config.c:597
msgid "縱向最大化"
msgstr "纵向最大化"
#: config.c:536
#: config.c:598
msgid "橫向最大化"
msgstr "横向最大化"
#: config.c:537
#: config.c:599
msgid "最大化至上半屏"
msgstr "最大化至上半屏"
#: config.c:538
#: config.c:600
msgid "最大化至下半屏"
msgstr "最大化至下半屏"
#: config.c:539
#: config.c:601
msgid "最大化至左半屏"
msgstr "最大化至左半屏"
#: config.c:540
#: config.c:602
msgid "最大化至右半屏"
msgstr "最大化至右半屏"
#: config.c:541
#: config.c:603
msgid "完全最大化"
msgstr "完全最大化"
#. 構件類型 構件功能提示文字
#: config.c:553
#. 構件標識 構件功能提示文字
#: config.c:615
msgid "切換到次要區域"
msgstr "切换到次要区域"
#: config.c:554
#: config.c:616
msgid "切換到主要區域"
msgstr "切换到主要区域"
#: config.c:555
#: config.c:617
msgid "切換到固定區域"
msgstr "切换到固定区域"
#: config.c:556
#: config.c:618
msgid "切換到懸浮層"
msgstr "切换到悬浮层"
#: config.c:557
#: config.c:619
msgid "切換到圖符區域"
msgstr "切换到图符区域"
#: config.c:558
#: config.c:620
msgid "最大化/還原窗口"
msgstr "最大化/还原窗口"
#: config.c:559
#: config.c:621
msgid "關閉窗口"
msgstr "关闭窗口"
#: config.c:560
#: config.c:622
msgid "切換到虛擬桌面1"
msgstr "切换到虚拟桌面1"
#: config.c:561
#: config.c:623
msgid "切換到虛擬桌面2"
msgstr "切换到虚拟桌面2"
#: config.c:562
#: config.c:624
msgid "切換到虛擬桌面3"
msgstr "切换到虚拟桌面3"
#: config.c:563
#: config.c:625
msgid "切換到預覽模式"
msgstr "切换到预览模式"
#: config.c:564
#: config.c:626
msgid "切換到堆疊模式"
msgstr "切换到堆叠模式"
#: config.c:565
#: config.c:627
msgid "切換到平鋪模式"
msgstr "切换到平铺模式"
#: config.c:566
#: config.c:628
msgid "顯示桌面"
msgstr "显示桌面"
#: config.c:567
#: config.c:629
msgid "打開操作中心"
msgstr "打开操作中心"
#: config.c:568
#: config.c:630
msgid "打開窗口菜單"
msgstr "打开窗口菜单"
#: config.c:597
#: config.c:659
msgid "請輸入命令,然後按回車執行"
msgstr "请输入命令,然后按回车执行"
@ -324,7 +452,7 @@ msgstr "不能安装SIGQUIT信号处理函数"
msgid "不能安裝SIGHUP信號處理函數"
msgstr "不能安装SIGHUP信号处理函数"
#: init.c:120
#: init.c:121
#, c-format
msgid "錯誤: 不能設置輸入法"
msgstr "错误: 不能设置输入法"
@ -342,17 +470,17 @@ msgstr "错误:已经有其他窗口管理器在运行!"
msgid "X錯誤資源號=%#lx, 請求量=%lu, 錯誤碼=%d, 主請求碼=%d, 次請求碼=%d\n"
msgstr "X错误资源号=%#lx请求量=%lu错误码=%d主请求码=%d次请求码=%d\n"
#: widget.c:123
#: widget.c:245
#, c-format
msgid "錯誤窗口0x%lx輸入法設置失敗"
msgstr "错误窗口0x%lx输入法设置失败"
#: widget.c:239
#: widget.c:359
#, c-format
msgid "錯誤:找不到指定的鍵符號相應的功能轉換鍵!\n"
msgstr "错误:找不到指定的键符号相应的功能转换键!\n"
#: widget.c:242
#: widget.c:362
#, c-format
msgid "錯誤:指定的鍵符號不存在對應的鍵代碼!\n"
msgstr "错误:指定的键符号不存在对应的键代码!\n"

111
src/button.c Normal file
View File

@ -0,0 +1,111 @@
/* *************************************************************************
* button.c
* (C) 2020-2024 gsm <406643764@qq.com>
*
* GNU通用公共許可證重新發布
* 使
* GNU通用公共許可證
* GNU通用公共許可證副本
* <http://www.gnu.org/licenses/>。
* ************************************************************************/
#include "gwm.h"
struct _button_tag
{
Widget base;
Imlib_Image image;
char *icon_name;
char *symbol;
char *label;
Align_type align; // 標籤的對齊方式
};
Button *create_button(Widget_id id, Widget_state state, Window parent, int x, int y, int w, int h, const char *label)
{
Button *button=malloc_s(sizeof(Button));
init_widget(WIDGET(button), id, BUTTON_TYPE, state, parent, x, y, w, h);
button->image=button->icon_name=button->symbol=NULL;
button->label=copy_string(label);
button->align=CENTER;
XSelectInput(xinfo.display, WIDGET_WIN(button), BUTTON_EVENT_MASK);
return button;
}
void set_button_icon(Button *button, Imlib_Image image, const char *icon_name, const char *symbol)
{
if(!image && !icon_name && !symbol)
return;
if(image)
button->image=image;
else if(icon_name)
button->icon_name=copy_string(icon_name);
else if(symbol)
button->symbol=copy_string(symbol);
else
return;
}
char *get_button_label(Button *button)
{
return button->label;
}
void set_button_label(Button *button, const char *label)
{
if(button->label)
free(button->label);
button->label=copy_string(label);
}
void set_button_align(Button *button, Align_type align)
{
button->align=align;
}
void destroy_button(Button *button)
{
vfree(button->icon_name, button->symbol, button->label, NULL);
destroy_widget(WIDGET(button));
}
void show_button(const Button *button)
{
Widget *widget=WIDGET(button);
show_widget(widget);
if(widget->state.hot || widget->state.warn)
update_hint_win_for_info(widget, widget->tooltip);
}
void update_button_fg(const Button *button)
{
XftColor fg=get_widget_fg(get_widget_fg_id(WIDGET(button)));
int xi=0, y=0, h=WIDGET_H(button), wi=h, xl=wi, wl=WIDGET_H(button)-wi;
if(button->image)
draw_image(button->image, WIDGET_WIN(button), xi, y, wi, h);
else if(button->symbol)
{
Str_fmt fmt={xi, y, wi, h, CENTER, false, false, 0, fg};
draw_string(WIDGET_WIN(button), button->symbol, &fmt);
}
else if(button->icon_name)
{
char s[2]={button->icon_name[0], '\0'};
Str_fmt fmt={xi, y, wi, h, CENTER, false, false, 0, fg};
draw_string(WIDGET_WIN(button), s, &fmt);
}
else
xl=0, wl=WIDGET_W(button);
if(button->label)
{
Str_fmt fmt={xl, y, wl, h, button->align, true, false, 0, fg};
draw_string(WIDGET_WIN(button), button->label, &fmt);
}
}

31
src/button.h Normal file
View File

@ -0,0 +1,31 @@
/* *************************************************************************
* button.hbutton.c相應的頭文件
* (C) 2020-2024 gsm <406643764@qq.com>
*
* GNU通用公共許可證重新發布
* 使
* GNU通用公共許可證
* GNU通用公共許可證副本
* <http://www.gnu.org/licenses/>。
* ************************************************************************/
#ifndef BUTTON_H
#define BUTTON_H
#include "gwm.h"
#include "font.h"
typedef struct _button_tag Button;
#define BUTTON(widget) ((Button *)(widget))
Button *create_button(Widget_id id, Widget_state state, Window parent, int x, int y, int w, int h, const char *label);
void set_button_icon(Button *button, Imlib_Image image, const char *icon_name, const char *symbol);
char *get_button_label(Button *button);
void set_button_label(Button *button, const char *label);
void set_button_align(Button *button, Align_type align);
void destroy_button(Button *button);
void show_button(const Button *button);
void update_button_fg(const Button *button);
#endif

View File

@ -23,13 +23,13 @@ static void set_default_place_type(Client *c);
static void set_default_win_rect(Client *c);
static void set_win_rect_by_attr(Client *c);
static void frame_client(Client *c);
static void unframe_client(Client *c);
static void del_client_node(Client *c);
static Window get_top_win(WM *wm, Client *c);
static void update_focus_client_pointer(WM *wm, unsigned int desktop_n, Client *c);
static bool is_map_client(Client *list, unsigned int desktop_n, Client *c);
static Client *get_prev_map_client(Client *list, unsigned int desktop_n, Client *c);
static Client *get_next_map_client(Client *list, unsigned int desktop_n, Client *c);
static bool have_same_class_icon_client(Client *list, Client *c);
static int cmp_map_order(const void *pclient1, const void *pclient2);
static long map_count=0; // 所有客戶窗口的累計映射次數
@ -40,18 +40,16 @@ void add_client(WM *wm, Window win)
apply_rules(c);
add_client_node(get_head_for_add_client(wm->clients, c), c);
grab_buttons(c->win);
set_gwm_widget_type(win, CLIENT_WIN);
grab_buttons(WIDGET_WIN(c));
XSelectInput(xinfo.display, win, EnterWindowMask|PropertyChangeMask);
set_cursor(win, NO_OP);
set_default_win_rect(c);
save_place_info_of_client(c);
frame_client(c);
request_layout_update();
XMapWindow(xinfo.display, c->frame);
XMapSubwindows(xinfo.display, c->frame);
show_widget(WIDGET(c->frame));
focus_client(wm, wm->cur_desktop, c);
set_net_wm_allowed_actions(c->win);
set_net_wm_allowed_actions(WIDGET_WIN(c));
}
void set_all_net_client_list(Client *list)
@ -71,21 +69,21 @@ static Client *new_client(WM *wm, Window win)
{
Client *c=malloc_s(sizeof(Client));
memset(c, 0, sizeof(Client));
c->win=win;
Widget_state state={.focus=(c==CUR_FOC_CLI(wm))};
init_widget(WIDGET(c), CLIENT_WIN, UNUSED_TYPE, state, xinfo.root_win, 0, 0, 1, 1);
WIDGET_WIN(c)=win;
c->map_n=++map_count;
c->title_text=get_title_text(win, "");
c->wm_hint=XGetWMHints(xinfo.display, win);
c->win_type=get_net_wm_win_type(win);
c->win_state=get_net_wm_state(win);
c->owner=win_to_client(wm->clients, get_transient_for(c->win));
c->owner=win_to_client(wm->clients, get_transient_for(WIDGET_WIN(c)));
c->subgroup_leader=get_subgroup_leader(c);
set_default_place_type(c);
if(!should_hide_frame(c))
c->border_w=cfg->border_width, c->titlebar_h=get_font_height_by_pad();
c->class_name="?";
XGetClassHint(xinfo.display, c->win, &c->class_hint);
c->image=get_icon_image(c->win, c->wm_hint, c->class_hint.res_name,
cfg->icon_image_size, cfg->cur_icon_theme);
XGetClassHint(xinfo.display, WIDGET_WIN(c), &c->class_hint);
set_default_desktop_mask(c, wm->cur_desktop);
return c;
@ -104,7 +102,7 @@ static void set_default_desktop_mask(Client *c, unsigned int cur_desktop)
else
{
unsigned int desktop;
if(!get_net_wm_desktop(c->win, &desktop))
if(!get_net_wm_desktop(WIDGET_WIN(c), &desktop))
desktop=cur_desktop-1;
c->desktop_mask = desktop==~0U ? desktop : get_desktop_mask(desktop+1);
}
@ -180,14 +178,18 @@ static void set_default_place_type(Client *c)
void set_win_rect_by_frame(Client *c, const Rect *frame)
{
c->x=frame->x+c->border_w, c->y=frame->y+c->titlebar_h+c->border_w;
c->w=frame->w-2*c->border_w, c->h=frame->h-c->titlebar_h-2*c->border_w;
WIDGET_X(c)=frame->x+c->border_w;
WIDGET_Y(c)=frame->y+c->titlebar_h+c->border_w;
WIDGET_W(c)=frame->w-2*c->border_w;
WIDGET_H(c)=frame->h-c->titlebar_h-2*c->border_w;
}
static void set_default_win_rect(Client *c)
{
c->w=xinfo.screen_width/4, c->h=xinfo.screen_height/4;
c->x=(xinfo.screen_width-c->w)/2, c->y=(xinfo.screen_height-c->h)/2;
WIDGET_W(c)=xinfo.screen_width/4;
WIDGET_H(c)=xinfo.screen_height/4;
WIDGET_X(c)=(xinfo.screen_width-WIDGET_W(c))/2;
WIDGET_Y(c)=(xinfo.screen_height-WIDGET_H(c))/2;
set_win_rect_by_attr(c);
}
@ -195,22 +197,27 @@ static void set_default_win_rect(Client *c)
static void set_win_rect_by_attr(Client *c)
{
XWindowAttributes a;
if(XGetWindowAttributes(xinfo.display, c->win, &a))
c->x=a.x, c->y=a.y, c->w=a.width, c->h=a.height;
if(XGetWindowAttributes(xinfo.display, WIDGET_WIN(c), &a))
WIDGET_X(c)=a.x, WIDGET_Y(c)=a.y, WIDGET_W(c)=a.width, WIDGET_H(c)=a.height;
}
static void frame_client(Client *c)
{
Rect fr=get_frame_rect(c);
c->frame=create_widget_win(CLIENT_FRAME, xinfo.root_win, fr.x, fr.y,
fr.w, fr.h, c->border_w, get_widget_color(CURRENT_BORDER_COLOR), 0);
XSelectInput(xinfo.display, c->frame, FRAME_EVENT_MASK);
c->frame=malloc_s(sizeof(Frame));
init_widget(WIDGET(c->frame), CLIENT_FRAME, UNUSED_TYPE, WIDGET_STATE(c),
xinfo.root_win, fr.x, fr.y, fr.w, fr.h);
set_widget_border_width(WIDGET(c->frame), cfg->border_width);
set_widget_border_color(WIDGET(c->frame),
get_widget_color(get_widget_border_color_id(WIDGET(c->frame))));
XSelectInput(xinfo.display, c->frame->base.win, FRAME_EVENT_MASK);
if(cfg->set_frame_prop)
copy_prop(c->frame, c->win);
copy_prop(c->frame->base.win, WIDGET_WIN(c));
if(c->titlebar_h)
create_titlebar(c);
XAddToSaveSet(xinfo.display, c->win);
XReparentWindow(xinfo.display, c->win, c->frame, 0, c->titlebar_h);
XAddToSaveSet(xinfo.display, WIDGET_WIN(c));
XReparentWindow(xinfo.display, WIDGET_WIN(c), c->frame->base.win, 0, c->titlebar_h);
show_widget(WIDGET(c->frame));
/* 以下是同時設置窗口前景和背景透明度的非EWMH標準方法
unsigned long opacity = (unsigned long)(0xfffffffful);
@ -220,28 +227,48 @@ static void frame_client(Client *c)
*/
}
static void unframe_client(Client *c)
{
if(c->titlebar_h)
{
destroy_button(c->frame->logo);
destroy_widget(c->frame->title_area);
for(int i=0; i<TITLE_BUTTON_N; i++)
destroy_button(c->frame->buttons[i]);
}
destroy_widget(WIDGET(c->frame));
XReparentWindow(xinfo.display, WIDGET_WIN(c), xinfo.root_win, WIDGET_X(c), WIDGET_Y(c));
}
void create_titlebar(Client *c)
{
Rect tr=get_title_area_rect(c);
for(size_t i=0; i<TITLE_BUTTON_N; i++)
{
Rect br=get_button_rect(c, i);
c->buttons[i]=create_widget_win(TITLE_BUTTON_BEGIN+i, c->frame, br.x,
br.y, br.w, br.h, 0, 0, get_widget_color(CURRENT_TITLEBAR_COLOR));
XSelectInput(xinfo.display, c->buttons[i], BUTTON_EVENT_MASK);
c->frame->buttons[i]=create_button(TITLE_BUTTON_BEGIN+i, WIDGET_STATE(c),
WIDGET_WIN(c->frame), br.x, br.y, br.w, br.h, cfg->title_button_text[i]);
set_widget_tooltip(WIDGET(c->frame->buttons[i]), cfg->tooltip[TITLE_BUTTON_BEGIN+i]);
}
c->title_area=create_widget_win(TITLE_AREA, c->frame, tr.x, tr.y,
tr.w, tr.w, 0, 0, get_widget_color(CURRENT_TITLEBAR_COLOR));
XSelectInput(xinfo.display, c->title_area, TITLE_AREA_EVENT_MASK);
c->logo=create_widget_win(TITLE_LOGO, c->frame, 0, 0, c->titlebar_h,
c->titlebar_h, 0, 0, get_widget_color(CURRENT_TITLEBAR_COLOR));
XSelectInput(xinfo.display, c->logo, BUTTON_EVENT_MASK);
c->frame->title_area=create_widget(TITLE_AREA, UNUSED_TYPE, WIDGET_STATE(c),
WIDGET_WIN(c->frame), tr.x, tr.y, tr.w, tr.w);
set_widget_tooltip(WIDGET(c->frame->title_area), c->title_text);
c->frame->logo=create_button(TITLE_LOGO, WIDGET_STATE(c), WIDGET_WIN(c->frame),
0, 0, c->titlebar_h, c->titlebar_h, NULL);
set_widget_tooltip(WIDGET(c->frame->logo), cfg->tooltip[TITLE_LOGO]);
Imlib_Image image=get_icon_image(WIDGET_WIN(c), c->class_hint.res_name,
cfg->icon_image_size, cfg->cur_icon_theme);
set_button_icon(BUTTON(c->frame->logo), image, c->class_hint.res_name, NULL);
}
Rect get_frame_rect(Client *c)
{
long bw=c->border_w, bh=c->titlebar_h;
return (Rect){c->x-bw, c->y-bh-bw, c->w, c->h+bh};
return (Rect){WIDGET_X(c)-bw, WIDGET_Y(c)-bh-bw, WIDGET_W(c), WIDGET_H(c)+bh};
}
Rect get_title_area_rect(Client *c)
@ -250,12 +277,12 @@ Rect get_title_area_rect(Client *c)
get_gwm_current_layout(&layout);
int buttons_n[]={[PREVIEW]=1, [STACK]=3, [TILE]=7},
n=buttons_n[layout], size=get_font_height_by_pad();
return (Rect){size, 0, c->w-cfg->title_button_width*n-size, size};
return (Rect){size, 0, WIDGET_W(c)-cfg->title_button_width*n-size, size};
}
Rect get_button_rect(Client *c, size_t index)
{
int cw=c->w, w=cfg->title_button_width, h=get_font_height_by_pad();
int cw=WIDGET_W(c), w=cfg->title_button_width, h=get_font_height_by_pad();
return (Rect){cw-w*(TITLE_BUTTON_N-index), 0, w, h};
}
@ -264,23 +291,33 @@ int get_clients_n(Client *list, Place_type type, bool count_icon, bool count_tra
int n=0;
for(Client *c=list->next; c!=list; c=c->next)
if( (type==ANY_PLACE || c->place_type==type)
&& (count_icon || !c->icon)
&& (count_icon || !is_iconic_client(c))
&& (count_trans || !c->owner)
&& (count_all_desktop || is_on_cur_desktop(c)))
&& (count_all_desktop || is_on_cur_desktop(c->desktop_mask)))
n++;
return n;
}
bool is_iconic_client(Client *c)
{
return WIDGET_WIN(c)!=xinfo.root_win && c->win_state.hidden;
}
Client *win_to_client(Client *list, Window win)
{
// 當隱藏標題欄時標題區和按鈕的窗口ID爲0。故win爲0時不應視爲找到
for(Client *c=list->next; win && c!=list; c=c->next)
{
if(win==c->win || win==c->frame || win==c->logo || win==c->title_area)
if(win==WIDGET_WIN(c) || win==c->frame->base.win)
return c;
for(size_t i=0; i<TITLE_BUTTON_N; i++)
if(win == c->buttons[i])
if(c->titlebar_h)
{
if(win==WIDGET_WIN(c->frame->logo) || win==WIDGET_WIN(c->frame->title_area))
return c;
for(size_t i=0; i<TITLE_BUTTON_N; i++)
if(win == WIDGET_WIN(c->frame->buttons[i]))
return c;
}
}
return NULL;
@ -291,14 +328,13 @@ void del_client(WM *wm, Client *c, bool is_for_quit)
if(!c)
return;
XReparentWindow(xinfo.display, c->win, xinfo.root_win, c->x, c->y);
XDestroyWindow(xinfo.display, c->frame);
unframe_client(c);
if(c->image)
imlib_context_set_image(c->image), imlib_free_image();
del_client_node(c);
if(!is_for_quit)
for(size_t i=1; i<=DESKTOP_N; i++)
if(is_on_desktop_n(i, c))
if(is_on_desktop_n(i, c->desktop_mask))
focus_client(wm, i, NULL);
XFree(c->class_hint.res_class);
@ -317,14 +353,6 @@ static void del_client_node(Client *c)
c->next->prev=c->prev;
}
Client *win_to_iconic_state_client(Client *list, Window win)
{
for(Client *c=list->next; c!=list; c=c->next)
if(c->icon && c->icon->win==win)
return c;
return NULL;
}
/* 僅在移動窗口、聚焦窗口時或窗口類型、狀態發生變化才有可能需要提升 */
void raise_client(WM *wm, Client *c)
{
@ -333,7 +361,7 @@ void raise_client(WM *wm, Client *c)
wins[0]=get_top_win(wm, c);
for(Client *ld=c->subgroup_leader, *p=ld; ld && p->subgroup_leader==ld; p=p->prev)
wins[i--]=p->frame;
wins[i--]=WIDGET_WIN(p->frame);
XRestackWindows(xinfo.display, wins, n+1);
set_all_net_client_list(wm->clients);
@ -356,12 +384,12 @@ static Window get_top_win(WM *wm, Client *c)
return wm->top_wins[index[c->place_type]];
}
/* 當c->win所在的亞組存在模態窗口時,跳過非模態窗口 */
/* 當WIDGET_WIN(c)所在的亞組存在模態窗口時,跳過非模態窗口 */
Client *get_next_client(Client *list, Client *c)
{
for(Client *m=NULL, *p=c->next; p!=list; p=p->next)
{
if(is_on_cur_desktop(p))
if(is_on_cur_desktop(p->desktop_mask))
{
m=get_top_transient_client(p->subgroup_leader, true);
if(!m || p==m)
@ -373,11 +401,11 @@ Client *get_next_client(Client *list, Client *c)
return list;
}
/* 當c->win所在的亞組存在模態窗口時,跳過非模態窗口 */
/* 當WIDGET_WIN(c)所在的亞組存在模態窗口時,跳過非模態窗口 */
Client *get_prev_client(Client *list, Client *c)
{
for(Client *m=NULL, *p=c->prev; p!=c; p=p->prev)
if(is_on_cur_desktop(p))
if(is_on_cur_desktop(p->desktop_mask))
return (m=get_top_transient_client(p->subgroup_leader, true)) ? m : p;
return list;
}
@ -410,7 +438,7 @@ void del_subgroup(Client *subgroup_leader)
bool is_last_typed_client(Client *list, Client *c, Place_type type)
{
for(Client *p=list->prev; p!=c; p=p->prev)
if(is_on_cur_desktop(p) && p->place_type==type)
if(is_on_cur_desktop(p->desktop_mask) && p->place_type==type)
return false;
return true;
}
@ -418,7 +446,7 @@ bool is_last_typed_client(Client *list, Client *c, Place_type type)
Client *get_head_client(Client *list, Place_type type)
{
for(Client *c=list->next; c!=list; c=c->next)
if(is_on_cur_desktop(c) && c->place_type==type)
if(is_on_cur_desktop(c->desktop_mask) && c->place_type==type)
return c->prev;
for(Client *c=list->next; c!=list; c=c->next)
if(c->place_type == type)
@ -465,23 +493,29 @@ void focus_client(WM *wm, unsigned int desktop_n, Client *c)
Desktop *d=wm->desktop[desktop_n-1];
Client *pc=d->cur_focus_client, *pp=d->prev_focus_client;
if(pc!=wm->clients && pc->titlebar_h)
{
WIDGET_STATE(pc).focus=WIDGET_STATE(pc->frame->logo).focus=WIDGET_STATE(pc->frame->title_area).focus=1;
for(size_t i=0; i<TITLE_BUTTON_N; i++)
WIDGET_STATE(pc->frame->buttons[i]).focus=1;
}
if(pp!=wm->clients && pp!=pc && pp->titlebar_h)
{
WIDGET_STATE(pp).focus=WIDGET_STATE(pp->frame->logo).focus=WIDGET_STATE(pp->frame->title_area).focus=0;
for(size_t i=0; i<TITLE_BUTTON_N; i++)
WIDGET_STATE(pp->frame->buttons[i]).focus=0;
}
if(desktop_n == wm->cur_desktop)
{
if(pc->win == xinfo.root_win)
if(WIDGET_WIN(pc) == xinfo.root_win)
XSetInputFocus(xinfo.display, xinfo.root_win, RevertToPointerRoot, CurrentTime);
else if(!pc->icon)
{
set_input_focus(pc->win, pc->wm_hint);
if(taskbar->urgency_n[desktop_n-1])
set_urgency(pc, false);
if(taskbar->attent_n[desktop_n-1])
set_attention(pc, false);
}
else if(!is_iconic_client(pc))
set_input_focus(WIDGET_WIN(pc), pc->wm_hint);
}
update_client_bg(wm, desktop_n, pc);
update_client_bg(wm, desktop_n, pp);
raise_client(wm, pc);
set_net_active_window(pc->win);
set_net_active_window(WIDGET_WIN(pc));
}
static void update_focus_client_pointer(WM *wm, unsigned int desktop_n, Client *c)
@ -525,7 +559,7 @@ static void update_focus_client_pointer(WM *wm, unsigned int desktop_n, Client *
static bool is_map_client(Client *list, unsigned int desktop_n, Client *c)
{
if(c && !c->icon && is_on_desktop_n(desktop_n, c))
if(c && !is_iconic_client(c) && is_on_desktop_n(desktop_n, c->desktop_mask))
for(Client *p=list->next; p!=list; p=p->next)
if(p == c)
return true;
@ -536,7 +570,7 @@ static bool is_map_client(Client *list, unsigned int desktop_n, Client *c)
static Client *get_prev_map_client(Client *list, unsigned int desktop_n, Client *c)
{
for(Client *p=c->prev; p!=list; p=p->prev)
if(!p->icon && is_on_desktop_n(desktop_n, p))
if(!is_iconic_client(p) && is_on_desktop_n(desktop_n, p->desktop_mask))
return p;
return NULL;
}
@ -545,90 +579,40 @@ static Client *get_prev_map_client(Client *list, unsigned int desktop_n, Client
static Client *get_next_map_client(Client *list, unsigned int desktop_n, Client *c)
{
for(Client *p=c->next; p!=list; p=p->next)
if(!p->icon && is_on_desktop_n(desktop_n, p))
if(!is_iconic_client(p) && is_on_desktop_n(desktop_n, p->desktop_mask))
return p;
return NULL;
}
bool is_on_desktop_n(unsigned int n, Client *c)
{
return (c->desktop_mask & get_desktop_mask(n));
}
bool is_on_cur_desktop(Client *c)
{
unsigned int desktop;
return get_net_current_desktop(&desktop)
&& (c->desktop_mask & get_desktop_mask(desktop+1));
}
unsigned int get_desktop_mask(unsigned int desktop_n)
{
return 1<<(desktop_n-1);
}
void update_icon_area(Client *list)
{
int x=0, w=0;
for(Client *c=list->prev; c!=list; c=c->prev)
{
if(is_on_cur_desktop(c) && c->icon)
{
Icon *i=c->icon;
i->w=taskbar->h;
if(have_same_class_icon_client(list, c))
{
get_string_size(i->title_text, &w, NULL);
i->w=MIN(i->w+w, cfg->icon_win_width_max);
i->show_text=true;
}
else
i->show_text=false;
i->x=x;
x+=i->w+cfg->icon_gap;
XMoveResizeWindow(xinfo.display, i->win, i->x, i->y, i->w, i->h);
}
}
}
static bool have_same_class_icon_client(Client *list, Client *c)
{
for(Client *p=list->next; p!=list; p=p->next)
if( p!=c && is_on_cur_desktop(p) && p->icon
&& !strcmp(c->class_name, p->class_name))
return true;
return false;
}
void save_place_info_of_client(Client *c)
{
c->ox=c->x, c->oy=c->y, c->ow=c->w, c->oh=c->h;
c->ox=WIDGET_X(c), c->oy=WIDGET_Y(c), c->ow=WIDGET_W(c), c->oh=WIDGET_H(c);
c->old_place_type=c->place_type;
}
void save_place_info_of_clients(Client *list)
{
for(Client *c=list->prev; c!=list; c=c->prev)
if(is_on_cur_desktop(c))
if(is_on_cur_desktop(c->desktop_mask))
save_place_info_of_client(c);
}
void restore_place_info_of_client(Client *c)
{
c->x=c->ox, c->y=c->oy, c->w=c->ow, c->h=c->oh;
WIDGET_X(c)=c->ox, WIDGET_Y(c)=c->oy, WIDGET_W(c)=c->ow, WIDGET_H(c)=c->oh;
c->place_type=c->old_place_type;
}
void restore_place_info_of_clients(Client *list)
{
for(Client *c=list->next; c!=list; c=c->next)
if(is_on_cur_desktop(c))
if(is_on_cur_desktop(c->desktop_mask))
restore_place_info_of_client(c);
}
bool is_tile_client(Client *c)
{
return is_on_cur_desktop(c) && !c->owner && !c->icon
return is_on_cur_desktop(c->desktop_mask) && !c->owner && !is_iconic_client(c)
&& is_normal_layer(c->place_type);
}
@ -647,12 +631,12 @@ Window *get_client_win_list(Client *list, int *n)
Client **clist=malloc_s(count*sizeof(Client *));
for(Client *c=list->prev; c!=list; c=c->prev)
if(is_on_cur_desktop(c))
if(is_on_cur_desktop(c->desktop_mask))
clist[i++]=c;
qsort(clist, *n, sizeof(Client *), cmp_map_order);
for(i=0; i<count; i++)
wlist[i]=clist[i]->win;
wlist[i]=WIDGET_WIN(clist[i]);
free(clist);
return wlist;
@ -675,41 +659,19 @@ Window *get_client_win_list_stacking(Client *list, int *n)
Window *wlist=malloc_s(count*sizeof(Window)), *w=wlist;
for(Client *c=list->prev; c!=list; c=c->prev, w++)
if(is_on_cur_desktop(c))
*w=c->win;
if(is_on_cur_desktop(c->desktop_mask))
*w=WIDGET_WIN(c);
return wlist;
}
void set_attention(Client *c, bool attent)
void set_state_attent(Client *c, bool attent)
{
if(c->win_state.attent == attent) // 避免重復設置
return;
c->win_state.attent=attent;
update_net_wm_state(c->win, c->win_state);
int incr = attent ? 1 : -1;
unsigned int cur_desktop;
for(unsigned int i=1; i<=DESKTOP_N; i++)
if( is_on_desktop_n(i, c) && get_net_current_desktop(&cur_desktop)
&& i!=cur_desktop)
taskbar->attent_n[i-1] += incr;
update_taskbar_buttons_bg();
}
void set_urgency(Client *c, bool urg)
{
if(!set_urgency_hint(c->win, c->wm_hint, urg))
return;
int incr = (urg ? 1 : -1);
unsigned int cur_desktop;
for(unsigned int i=1; i<=DESKTOP_N; i++)
if( is_on_desktop_n(i, c) && get_net_current_desktop(&cur_desktop)
&& i!=cur_desktop)
taskbar->urgency_n[i-1] += incr;
update_taskbar_buttons_bg();
update_net_wm_state(WIDGET_WIN(c), c->win_state);
}
bool is_wm_win(Client *list, Window win, bool before_wm)
@ -735,7 +697,7 @@ void restack_win(WM *wm, Window win)
Client *c=win_to_client(wm->clients, win);
Net_wm_win_type type=get_net_wm_win_type(win);
Window wins[2]={None, c ? c->frame : win};
Window wins[2]={None, c ? WIDGET_WIN(c->frame) : win};
if(type.desktop)
wins[0]=wm->top_wins[DESKTOP_TOP];
@ -763,10 +725,8 @@ void update_client_bg(WM *wm, unsigned int desktop_n, Client *c)
return;
Desktop *d=wm->desktop[desktop_n-1];
if(c->icon && d->cur_layout!=PREVIEW)
update_win_bg(c->icon->win, c==d->cur_focus_client ?
get_widget_color(ENTERED_NORMAL_BUTTON_COLOR) :
get_widget_color(TASKBAR_COLOR), None);
if(is_iconic_client(c) && d->cur_layout!=PREVIEW)
c->win_state.focused=1, update_net_wm_state(WIDGET_WIN(c), c->win_state);
else
update_frame_bg(wm, desktop_n, c);
}
@ -777,14 +737,14 @@ void update_frame_bg(WM *wm, unsigned int desktop_n, Client *c)
unsigned long color=get_widget_color(cur ? CURRENT_BORDER_COLOR : NORMAL_BORDER_COLOR);
if(c->border_w)
XSetWindowBorder(xinfo.display, c->frame, color);
XSetWindowBorder(xinfo.display, WIDGET_WIN(c->frame), color);
if(c->titlebar_h)
{
color=get_widget_color(cur ? CURRENT_TITLEBAR_COLOR : NORMAL_TITLEBAR_COLOR);
update_win_bg(c->logo, color, 0);
update_win_bg(c->title_area, color, 0);
update_widget_bg(WIDGET(c->frame->logo));
update_widget_bg(WIDGET(c->frame->title_area));
for(size_t i=0; i<TITLE_BUTTON_N; i++)
update_win_bg(c->buttons[i], color, None);
update_widget_bg(WIDGET(c->frame->buttons[i]));
}
}
@ -799,7 +759,7 @@ void create_clients(WM *wm)
memset(wm->clients, 0, sizeof(Client));
for(size_t i=0; i<DESKTOP_N; i++)
d[i]->cur_focus_client=d[i]->prev_focus_client=wm->clients;
wm->clients->win=xinfo.root_win;
WIDGET_WIN(wm->clients)=xinfo.root_win;
wm->clients->prev=wm->clients->next=wm->clients;
if(!XQueryTree(xinfo.display, xinfo.root_win, &root, &parent, &child, &n))
exit_with_msg(_("錯誤:查詢窗口清單失敗!"));

View File

@ -15,19 +15,19 @@
#include "drawable.h"
#include "ewmh.h"
struct icon_tag // 縮微窗口相關信息
typedef struct // 客戶窗口裝飾
{
Window win; // 位於任務欄的縮微窗口(可能含有圖標名)
int x, y, w, h; // 無邊框時win的坐標、尺寸
bool show_text; // 當存在圖標映像時,是否顯示圖標名
char *title_text; // 圖標名即XA_WM_ICON_NAME理論上應比XA_WM_NAME簡短實際上很多客戶窗口的都是與它一模一樣。
};
typedef struct icon_tag Icon;
Widget base;
Button *logo;
Widget *title_area;
Button *buttons[TITLE_BUTTON_N]; //標題區按鈕
} Frame;
struct client_tag // 客戶窗口相關信息
{ // 分別爲客戶窗口、父窗口、圖標窗口, 標題區、標題區按鈕、臨時窗口對應的主窗口
Window win, frame, logo, title_area, buttons[TITLE_BUTTON_N];
int x, y, w, h, ox, oy, ow, oh; // 分别爲win現在的和原來的橫、縱坐標和寬、高
{
Widget base;
Frame *frame; // 客戶窗口裝飾
int ox, oy, ow, oh; // 分别爲win原來的橫、縱坐標和寬、高
int titlebar_h, border_w; // win的標題欄高、邊框寬
unsigned int desktop_mask; // 所屬虚拟桌面的掩碼
long map_n; // win最後一次映射的序號
@ -35,7 +35,6 @@ struct client_tag // 客戶窗口相關信息
Net_wm_win_type win_type; // win的窗口類型
Net_wm_state win_state; // win的窗口狀態
char *title_text; // 標題的文字
Icon *icon; // 圖符信息
Imlib_Image image; // 圖標映像
const char *class_name; // 客戶窗口的程序類型名
XClassHint class_hint; // 客戶窗口的程序類型特性提示
@ -52,9 +51,9 @@ void set_win_rect_by_frame(Client *c, const Rect *frame);
void create_titlebar(Client *c);
Rect get_title_area_rect(Client *c);
int get_clients_n(Client *list, Place_type type, bool count_icon, bool count_trans, bool count_all_desktop);
bool is_iconic_client(Client *c);
Client *win_to_client(Client *list, Window win);
void del_client(WM *wm, Client *c, bool is_for_quit);
Client *win_to_iconic_state_client(Client *list, Window win);
void raise_client(WM *wm, Client *c);
Client *get_next_client(Client *list, Client *c);
Client *get_prev_client(Client *list, Client *c);
@ -65,10 +64,6 @@ int get_subgroup_n(Client *c);
Client *get_subgroup_leader(Client *c);
Client *get_top_transient_client(Client *subgroup_leader, bool only_modal);
void focus_client(WM *wm, unsigned int desktop_n, Client *c);
bool is_on_desktop_n(unsigned int n, Client *c);
bool is_on_cur_desktop(Client *c);
unsigned int get_desktop_mask(unsigned int desktop_n);
void update_icon_area(Client *list);
void save_place_info_of_client(Client *c);
void save_place_info_of_clients(Client *list);
void restore_place_info_of_client(Client *c);
@ -76,8 +71,7 @@ void restore_place_info_of_clients(Client *list);
bool is_tile_client(Client *c);
Window *get_client_win_list(Client *list, int *n);
Window *get_client_win_list_stacking(Client *list, int *n);
void set_attention(Client *c, bool attent);
void set_urgency(Client *c, bool urg);
void set_state_attent(Client *c, bool attent);
bool is_wm_win(Client *list, Window win, bool before_wm);
void restack_win(WM *wm, Window win);
void update_clients_bg(WM *wm);

View File

@ -114,7 +114,7 @@ static const Keybind keybind[] =
{WM_KEY, XK_Page_Up, prev_desktop, {0}},
{0, XK_Print, print_screen, {0}},
{WM_KEY, XK_Print, print_win, {0}},
{WM_KEY, XK_r, enter_and_run_cmd, {0}},
{WM_KEY, XK_r, show_run_cmd_entry, {0}},
{WM_KEY, XK_Delete, quit_wm, {0}},
DESKTOP_KEYBIND(XK_0, 0),
DESKTOP_KEYBIND(XK_1, 1), /* 注我的鍵盤按super+左shift+1鍵時產生多鍵衝突 */
@ -147,7 +147,7 @@ static const Buttonbind buttonbind[] =
DESKTOP_BUTTONBIND(2),
DESKTOP_BUTTONBIND(3),
/* 構件類型 功能轉換鍵 定位器按鈕 要綁定的函數 函數的參數 */
/* 構件標識 功能轉換鍵 定位器按鈕 要綁定的函數 函數的參數 */
{DESKTOP_BUTTON, WM_KEY, Button2, close_all_clients, {0}},
{CLIENT_WIN, WM_KEY, Button1, move_resize, {.resize=false}},
{CLIENT_WIN, WM_SKEY, Button1, move_resize, {.resize=true}},
@ -177,7 +177,6 @@ static const Rule rule[] =
{"QQ", "qq", "QQ", "QQ", TILE_LAYER_FIXED, false, false, 0},
{"explorer.exe", "explorer.exe", "*", NULL, FLOAT_LAYER, false, false, 0},
{"Thunder.exe", "Thunder.exe", "*", NULL, FLOAT_LAYER, true, true, 0},
// {"sketchup.exe", "sketchup.exe", "SketchUp", NULL, ABOVE_LAYER, false, false, 0},
{"firefox", "Toolkit", "*", NULL, TILE_LAYER_MAIN, true, true, 0},
{"Google-chrome", "google-chrome", "*", "chrome", ANY_PLACE, true, true, 0},
{"Org.gnome.Nautilus", "org.gnome.Nautilus", "*", "Nautilus", ANY_PLACE, true, true, 0},
@ -248,7 +247,7 @@ static void config_cursor_shape(void)
}
/* 功能:爲深色主題設置構件背景色。
* gwm.h:Widget_colorrgb.txt
* gwm.h:Widget_color_idrgb.txt
* locate rgb.txt搜索
*
* #RGB#RRGGBB#RRRGGGBBB#RRRRGGGGBBBB
@ -262,6 +261,17 @@ static void config_widget_color_for_dark(void)
color_name[CURRENT_BORDER_COLOR] = "grey31";
color_name[NORMAL_TITLEBAR_COLOR] = "grey11";
color_name[CURRENT_TITLEBAR_COLOR] = "grey31";
color_name[DISABLE_WIDGET_COLOR] = "grey91";
color_name[WARN_WIDGET_COLOR] = "red";
color_name[ACTIVE_WIDGET_COLOR] = "DarkOrange";
color_name[HOT_WIDGET_COLOR] = "DarkOrange";
color_name[URGENT_WIDGET_COLOR] = "red";
color_name[ATTENT_WIDGET_COLOR] = "Yellow4";
color_name[CHOSEN_WIDGET_COLOR] = "DeepSkyBlue4";
color_name[FOCUS_WIDGET_COLOR] = "grey31";
color_name[NORMAL_WIDGET_COLOR] = "grey11";
color_name[ENTERED_NORMAL_BUTTON_COLOR] = "DarkOrange";
color_name[ENTERED_CLOSE_BUTTON_COLOR] = "red";
color_name[CHOSEN_BUTTON_COLOR] = "DeepSkyBlue4";
@ -286,6 +296,17 @@ static void config_widget_color_for_normal(void)
color_name[CURRENT_BORDER_COLOR] = "DodgerBlue";
color_name[NORMAL_TITLEBAR_COLOR] = "grey31";
color_name[CURRENT_TITLEBAR_COLOR] = "DodgerBlue";
color_name[DISABLE_WIDGET_COLOR] = "grey91";
color_name[WARN_WIDGET_COLOR] = "red";
color_name[ACTIVE_WIDGET_COLOR] = "DarkOrange";
color_name[HOT_WIDGET_COLOR] = "DarkOrange";
color_name[URGENT_WIDGET_COLOR] = "red";
color_name[ATTENT_WIDGET_COLOR] = "Yellow4";
color_name[CHOSEN_WIDGET_COLOR] = "DeepSkyBlue4";
color_name[FOCUS_WIDGET_COLOR] = "DodgerBlue";
color_name[NORMAL_WIDGET_COLOR] = "grey11";
color_name[ENTERED_NORMAL_BUTTON_COLOR] = "DarkOrange";
color_name[ENTERED_CLOSE_BUTTON_COLOR] = "red";
color_name[CHOSEN_BUTTON_COLOR] = "DeepSkyBlue4";
@ -310,6 +331,17 @@ static void config_widget_color_for_light(void)
color_name[CURRENT_BORDER_COLOR] = "grey91";
color_name[NORMAL_TITLEBAR_COLOR] = "grey61";
color_name[CURRENT_TITLEBAR_COLOR] = "grey91";
color_name[DISABLE_WIDGET_COLOR] = "grey91";
color_name[WARN_WIDGET_COLOR] = "red";
color_name[ACTIVE_WIDGET_COLOR] = "DarkOrange";
color_name[HOT_WIDGET_COLOR] = "DarkOrange";
color_name[URGENT_WIDGET_COLOR] = "red";
color_name[ATTENT_WIDGET_COLOR] = "Yellow4";
color_name[CHOSEN_WIDGET_COLOR] = "DeepSkyBlue4";
color_name[FOCUS_WIDGET_COLOR] = "grey91";
color_name[NORMAL_WIDGET_COLOR] = "grey11";
color_name[ENTERED_NORMAL_BUTTON_COLOR] = "white";
color_name[ENTERED_CLOSE_BUTTON_COLOR] = "red";
color_name[CHOSEN_BUTTON_COLOR] = "LightSkyBlue";
@ -323,7 +355,7 @@ static void config_widget_color_for_light(void)
}
/* 功能:爲深色主題設置構件背景色的不透明度。
* gwm.h:Widget_color0~1.0
* gwm.h:Widget_color_id0~1.0
*/
static void config_widget_opacity_for_dark(void)
{
@ -389,13 +421,23 @@ static void config_widget_color_and_opacity(void)
}
/* 功能:爲深色主題設置文字顏色。
* gwm.h:Text_color
* gwm.h:Text_color_id
*/
static void config_text_color_for_dark(void)
{
const char **color_name=cfg->text_color_name[DARK_THEME];
/* 文字顏色號 顏色名 */
color_name[DISABLE_WIDGET_TEXT_COLOR] = "grey91";
color_name[WARN_WIDGET_TEXT_COLOR] = "grey71";
color_name[ACTIVE_WIDGET_TEXT_COLOR] = "grey71";
color_name[HOT_WIDGET_TEXT_COLOR] = "grey71";
color_name[URGENT_WIDGET_TEXT_COLOR] = "grey71";
color_name[ATTENT_WIDGET_TEXT_COLOR] = "grey71";
color_name[CHOSEN_WIDGET_TEXT_COLOR] = "grey71";
color_name[FOCUS_WIDGET_TEXT_COLOR] = "LightGreen";
color_name[NORMAL_WIDGET_TEXT_COLOR] = "grey71";
color_name[NORMAL_TITLEBAR_TEXT_COLOR] = "grey71";
color_name[CURRENT_TITLEBAR_TEXT_COLOR] = "LightGreen";
color_name[TASKBAR_TEXT_COLOR] = "white";
@ -413,6 +455,16 @@ static void config_text_color_for_normal(void)
const char **color_name=cfg->text_color_name[NORMAL_THEME];
/* 文字顏色號 顏色名 */
color_name[DISABLE_WIDGET_TEXT_COLOR] = "grey91";
color_name[WARN_WIDGET_TEXT_COLOR] = "grey71";
color_name[ACTIVE_WIDGET_TEXT_COLOR] = "grey71";
color_name[HOT_WIDGET_TEXT_COLOR] = "grey71";
color_name[URGENT_WIDGET_TEXT_COLOR] = "grey71";
color_name[ATTENT_WIDGET_TEXT_COLOR] = "grey71";
color_name[CHOSEN_WIDGET_TEXT_COLOR] = "grey71";
color_name[FOCUS_WIDGET_TEXT_COLOR] = "white";
color_name[NORMAL_WIDGET_TEXT_COLOR] = "grey71";
color_name[NORMAL_TITLEBAR_TEXT_COLOR] = "grey71";
color_name[CURRENT_TITLEBAR_TEXT_COLOR] = "white";
color_name[TASKBAR_TEXT_COLOR] = "white";
@ -430,6 +482,16 @@ static void config_text_color_for_light(void)
const char **color_name=cfg->text_color_name[LIGHT_THEME];
/* 文字顏色號 顏色名 */
color_name[DISABLE_WIDGET_TEXT_COLOR] = "grey91";
color_name[WARN_WIDGET_TEXT_COLOR] = "grey71";
color_name[ACTIVE_WIDGET_TEXT_COLOR] = "grey71";
color_name[HOT_WIDGET_TEXT_COLOR] = "grey71";
color_name[URGENT_WIDGET_TEXT_COLOR] = "grey71";
color_name[ATTENT_WIDGET_TEXT_COLOR] = "grey71";
color_name[CHOSEN_WIDGET_TEXT_COLOR] = "grey71";
color_name[FOCUS_WIDGET_TEXT_COLOR] = "black";
color_name[NORMAL_WIDGET_TEXT_COLOR] = "grey71";
color_name[NORMAL_TITLEBAR_TEXT_COLOR] = "grey31";
color_name[CURRENT_TITLEBAR_TEXT_COLOR] = "black";
color_name[TASKBAR_TEXT_COLOR] = "black";
@ -448,7 +510,7 @@ static void config_text_color(void)
}
/* 功能:設置標題按鈕的文字。
* gwm.h:Widget_type
* widget.h:Widget_id
*/
static void config_title_button_text(void)
{
@ -463,7 +525,7 @@ static void config_title_button_text(void)
}
/* 功能:設置任務欄按鈕的文字。
* gwm.h:Widget_type
* widget.h:Widget_id
*/
static void config_taskbar_button_text(void)
{
@ -478,78 +540,78 @@ static void config_taskbar_button_text(void)
SET_TASKBAR_BUTTON_TEXT(ACT_CENTER_ITEM, "^");
}
/* 功能:設置操作中心的文字
* gwm.h:Widget_type
/* 功能:設置操作中心菜單項
* widget.h:Widget_id
*/
static void config_act_center_item_text(void)
static void config_act_center_item(void)
{
/* 操作中心按鈕類型 按鈕文字 */
SET_ACT_CENTER_ITEM_TEXT(HELP_BUTTON, _("🛟 幫助"));
SET_ACT_CENTER_ITEM_TEXT(FILE_BUTTON, _("📁 文件"));
SET_ACT_CENTER_ITEM_TEXT(TERM_BUTTON, _("🖥️ 終端模擬器"));
SET_ACT_CENTER_ITEM_TEXT(BROWSER_BUTTON, _("🌐 網絡瀏覽器"));
/* 操作中心按鈕類型 圖標名 符號 標籤 */
SET_ACT_CENTER_MENU_ITEM(HELP_BUTTON, NULL, _("🛟"), _("幫助"));
SET_ACT_CENTER_MENU_ITEM(FILE_BUTTON, NULL, _("📁"), _("文件"));
SET_ACT_CENTER_MENU_ITEM(TERM_BUTTON, NULL, _("🖥️"), _("終端模擬器"));
SET_ACT_CENTER_MENU_ITEM(BROWSER_BUTTON, NULL, _("🌐"), _("網絡瀏覽器"));
SET_ACT_CENTER_ITEM_TEXT(GAME_BUTTON, _("🎮️ 遊戲"));
SET_ACT_CENTER_ITEM_TEXT(PLAY_START_BUTTON, _("🎬 播放影音"));
SET_ACT_CENTER_ITEM_TEXT(PLAY_TOGGLE_BUTTON, _("⏯️ 切換播放狀態"));
SET_ACT_CENTER_ITEM_TEXT(PLAY_QUIT_BUTTON, _("⏹️ 關閉影音"));
SET_ACT_CENTER_MENU_ITEM(GAME_BUTTON, NULL, _("🎮️"), _("遊戲"));
SET_ACT_CENTER_MENU_ITEM(PLAY_START_BUTTON, NULL, _("🎬"), _("播放影音"));
SET_ACT_CENTER_MENU_ITEM(PLAY_TOGGLE_BUTTON, NULL, _("⏯️"), _("切換播放狀態"));
SET_ACT_CENTER_MENU_ITEM(PLAY_QUIT_BUTTON, NULL, _("⏹️"), _("關閉影音"));
SET_ACT_CENTER_ITEM_TEXT(VOLUME_DOWN_BUTTON, _("🔈️ 减小音量"));
SET_ACT_CENTER_ITEM_TEXT(VOLUME_UP_BUTTON, _("🔉 增大音量"));
SET_ACT_CENTER_ITEM_TEXT(VOLUME_MAX_BUTTON, _("🔊 最大音量"));
SET_ACT_CENTER_ITEM_TEXT(VOLUME_TOGGLE_BUTTON, _("🔇 靜音切換"));
SET_ACT_CENTER_MENU_ITEM(VOLUME_DOWN_BUTTON, NULL, _("🔈️"), _("减小音量"));
SET_ACT_CENTER_MENU_ITEM(VOLUME_UP_BUTTON, NULL, _("🔉"), _("增大音量"));
SET_ACT_CENTER_MENU_ITEM(VOLUME_MAX_BUTTON, NULL, _("🔊"), _("最大音量"));
SET_ACT_CENTER_MENU_ITEM(VOLUME_TOGGLE_BUTTON, NULL, _("🔇"), _("靜音切換"));
SET_ACT_CENTER_ITEM_TEXT(MAIN_NEW_BUTTON, _(" 暫主區開窗"));
SET_ACT_CENTER_ITEM_TEXT(SEC_NEW_BUTTON, _(" 暫次區開窗"));
SET_ACT_CENTER_ITEM_TEXT(FIX_NEW_BUTTON, _(" 暫固定區開窗"));
SET_ACT_CENTER_ITEM_TEXT(FLOAT_NEW_BUTTON, _(" 暫懸浮層開窗"));
SET_ACT_CENTER_MENU_ITEM(MAIN_NEW_BUTTON, NULL, _(""), _("暫主區開窗"));
SET_ACT_CENTER_MENU_ITEM(SEC_NEW_BUTTON, NULL, _(""), _("暫次區開窗"));
SET_ACT_CENTER_MENU_ITEM(FIX_NEW_BUTTON, NULL, _(""), _("暫固定區開窗"));
SET_ACT_CENTER_MENU_ITEM(FLOAT_NEW_BUTTON, NULL, _(""), _("暫懸浮層開窗"));
SET_ACT_CENTER_ITEM_TEXT(N_MAIN_UP_BUTTON, _("⬆️ 增大主區容量"));
SET_ACT_CENTER_ITEM_TEXT(N_MAIN_DOWN_BUTTON, _("⬇️ 减小主區容量"));
SET_ACT_CENTER_ITEM_TEXT(TITLEBAR_TOGGLE_BUTTON, _("🗔 開關當前窗口標題欄"));
SET_ACT_CENTER_ITEM_TEXT(CLI_BORDER_TOGGLE_BUTTON, _("⬚ 開關當前窗口邊框"));
SET_ACT_CENTER_MENU_ITEM(N_MAIN_UP_BUTTON, NULL, _("⬆️"), _("增大主區容量"));
SET_ACT_CENTER_MENU_ITEM(N_MAIN_DOWN_BUTTON, NULL, _("⬇️"), _("减小主區容量"));
SET_ACT_CENTER_MENU_ITEM(TITLEBAR_TOGGLE_BUTTON, NULL, _("🗔"), _("開關當前窗口標題欄"));
SET_ACT_CENTER_MENU_ITEM(CLI_BORDER_TOGGLE_BUTTON, NULL, _(""), _("開關當前窗口邊框"));
SET_ACT_CENTER_MENU_ITEM(CLOSE_ALL_CLIENTS_BUTTON, NULL, _(""), _("關閉桌面所有窗口"));
SET_ACT_CENTER_MENU_ITEM(PRINT_WIN_BUTTON, NULL, _(""), _("當前窗口截圖"));
SET_ACT_CENTER_MENU_ITEM(PRINT_SCREEN_BUTTON, NULL, _("🖵"), _("全屏截圖"));
SET_ACT_CENTER_MENU_ITEM(FOCUS_MODE_BUTTON, NULL, _("👁️"), _("切換聚焦模式"));
SET_ACT_CENTER_ITEM_TEXT(CLOSE_ALL_CLIENTS_BUTTON, _("❎ 關閉桌面所有窗口"));
SET_ACT_CENTER_ITEM_TEXT(PRINT_WIN_BUTTON, _("✀ 當前窗口截圖"));
SET_ACT_CENTER_ITEM_TEXT(PRINT_SCREEN_BUTTON, _("🖵 全屏截圖"));
SET_ACT_CENTER_ITEM_TEXT(FOCUS_MODE_BUTTON, _("👁️ 切換聚焦模式"));
SET_ACT_CENTER_MENU_ITEM(COMPOSITOR_BUTTON, NULL, _("🪡"), _("開關合成器"));
SET_ACT_CENTER_MENU_ITEM(WALLPAPER_BUTTON, NULL, _("🌌"), _("切換壁紙"));
SET_ACT_CENTER_MENU_ITEM(COLOR_THEME_BUTTON, NULL, _("🎨"), _("切換顏色主題"));
SET_ACT_CENTER_MENU_ITEM(QUIT_WM_BUTTON, NULL, _(""), _("退出gwm"));
SET_ACT_CENTER_ITEM_TEXT(COMPOSITOR_BUTTON, _("🪡 開關合成器"));
SET_ACT_CENTER_ITEM_TEXT(WALLPAPER_BUTTON, _("🌌 切換壁紙"));
SET_ACT_CENTER_ITEM_TEXT(COLOR_THEME_BUTTON, _("🎨 切換顏色主題"));
SET_ACT_CENTER_ITEM_TEXT(QUIT_WM_BUTTON, _("❌ 退出gwm"));
SET_ACT_CENTER_ITEM_TEXT(LOGOUT_BUTTON, _("🚶 注銷"));
SET_ACT_CENTER_ITEM_TEXT(REBOOT_BUTTON, _("↻ 重啓"));
SET_ACT_CENTER_ITEM_TEXT(POWEROFF_BUTTON, _("⏻ 關機"));
SET_ACT_CENTER_ITEM_TEXT(RUN_BUTTON, _("🔍️ 運行"));
SET_ACT_CENTER_MENU_ITEM(LOGOUT_BUTTON, NULL, _("🚶"), _("注銷"));
SET_ACT_CENTER_MENU_ITEM(REBOOT_BUTTON, NULL, _(""), _("重啓"));
SET_ACT_CENTER_MENU_ITEM(POWEROFF_BUTTON, NULL, _(""), _("關機"));
SET_ACT_CENTER_MENU_ITEM(RUN_BUTTON, NULL, _("🔍️"), _("運行"));
}
/* 功能:設置客戶窗口菜單的文字
* gwm.h:Widget_type
/* 功能:設置客戶窗口菜單項。
* widget.h:Widget_id
*/
static void config_client_menu_item_text(void)
static void config_client_menu_item(void)
{
/* 客戶窗口菜單項類型 按鈕文字 */
SET_CLIENT_MENU_ITEM_TEXT(SHADE_BUTTON, _("卷起/放下"));
SET_CLIENT_MENU_ITEM_TEXT(VERT_MAX_BUTTON, _("縱向最大化"));
SET_CLIENT_MENU_ITEM_TEXT(HORZ_MAX_BUTTON, _("橫向最大化"));
SET_CLIENT_MENU_ITEM_TEXT(TOP_MAX_BUTTON, _("最大化至上半屏"));
SET_CLIENT_MENU_ITEM_TEXT(BOTTOM_MAX_BUTTON, _("最大化至下半屏"));
SET_CLIENT_MENU_ITEM_TEXT(LEFT_MAX_BUTTON, _("最大化至左半屏"));
SET_CLIENT_MENU_ITEM_TEXT(RIGHT_MAX_BUTTON, _("最大化至右半屏"));
SET_CLIENT_MENU_ITEM_TEXT(FULL_MAX_BUTTON, _("完全最大化"));
/* 客戶窗口菜單項類型 圖標名 符號 標籤 */
SET_CLIENT_MENU_ITEM(SHADE_BUTTON, NULL, NULL, _("卷起/放下"));
SET_CLIENT_MENU_ITEM(VERT_MAX_BUTTON, NULL, NULL, _("縱向最大化"));
SET_CLIENT_MENU_ITEM(HORZ_MAX_BUTTON, NULL, NULL, _("橫向最大化"));
SET_CLIENT_MENU_ITEM(TOP_MAX_BUTTON, NULL, NULL, _("最大化至上半屏"));
SET_CLIENT_MENU_ITEM(BOTTOM_MAX_BUTTON, NULL, NULL, _("最大化至下半屏"));
SET_CLIENT_MENU_ITEM(LEFT_MAX_BUTTON, NULL, NULL, _("最大化至左半屏"));
SET_CLIENT_MENU_ITEM(RIGHT_MAX_BUTTON, NULL, NULL, _("最大化至右半屏"));
SET_CLIENT_MENU_ITEM(FULL_MAX_BUTTON, NULL, NULL, _("完全最大化"));
}
/* 功能:設置構件功能提示。
* gwm.h:Widget_type
* widget.h:Widget_id
*
*/
static void config_tooltip(void)
{
const char **tooltip=cfg->tooltip;
/* 構件類型 構件功能提示文字 */
/* 構件標識 構件功能提示文字 */
tooltip[SECOND_BUTTON] = _("切換到次要區域");
tooltip[MAIN_BUTTON] = _("切換到主要區域");
tooltip[FIXED_BUTTON] = _("切換到固定區域");
@ -616,7 +678,7 @@ void config(void)
config_text_color();
config_title_button_text();
config_taskbar_button_text();
config_act_center_item_text();
config_client_menu_item_text();
config_act_center_item();
config_client_menu_item();
config_tooltip();
}

View File

@ -12,6 +12,11 @@
#ifndef CONFIG_H
#define CONFIG_H
typedef enum // 窗口聚焦模式
{
ENTER_FOCUS, CLICK_FOCUS,
} Focus_mode;
// 說明:尺寸單位均爲像素
typedef struct
{
@ -61,8 +66,12 @@ typedef struct
const char *text_color_name[COLOR_THEME_N][TEXT_COLOR_N]; // 構件顏色名
const char *title_button_text[TITLE_BUTTON_N]; // 窗口標題欄按鈕的標籤
const char *taskbar_button_text[TASKBAR_BUTTON_N]; // 任務欄按鈕的標籤
const char *act_center_item_text[ACT_CENTER_ITEM_N]; // 操作中心菜單項的標籤
const char *client_menu_item_text[CLIENT_MENU_ITEM_N]; // 客戶窗口菜單項的標籤
const char *act_center_item_icon[ACT_CENTER_ITEM_N]; // 操作中心菜單項的圖標名
const char *act_center_item_symbol[ACT_CENTER_ITEM_N]; // 操作中心菜單項的符號
const char *act_center_item_label[ACT_CENTER_ITEM_N]; // 操作中心菜單項的標籤
const char *client_menu_item_icon[CLIENT_MENU_ITEM_N]; // 客戶窗口菜單項的圖標名
const char *client_menu_item_symbol[CLIENT_MENU_ITEM_N]; // 客戶窗口菜單項的符號
const char *client_menu_item_label[CLIENT_MENU_ITEM_N]; // 客戶窗口菜單項的標籤
const char *cmd_entry_hint; // 運行輸入框的提示文字
const char *compositor; // 合成管理器命令
const Keybind *keybind; // 按鍵功能綁定。有的鍵盤同時按多個鍵會衝突,故組合鍵宜盡量少

View File

@ -23,7 +23,7 @@ void print_client_and_top_win(WM *wm)
for(unsigned int i=0; i<n; i++)
{
if((c=win_to_client(wm->clients, child[i])))
printf("client frame: %lx\n", c->frame);
printf("client frame: %lx\n", WIDGET_WIN(c->frame));
else
for(unsigned int j=0; j<TOP_WIN_TYPE_N; j++)
if(wm->top_wins[j] == child[i])
@ -99,9 +99,9 @@ void print_net_wm_state(Window win)
void print_place_info(Client *c)
{
printf(_("以下是%lx窗口的位置信息\n"), c->win);
printf(_("以下是%lx窗口的位置信息\n"), WIDGET_WIN(c));
printf("ox=%d, oy=%d, ow=%d, oh=%d, old_place_type=%d\n", c->ox, c->oy, c->ow, c->oh, c->old_place_type);
printf("x=%d, y=%d, w=%d, h=%d, place_type=%d\n", c->x, c->y, c->w, c->h, c->place_type);
printf("x=%d, y=%d, w=%d, h=%d, place_type=%d\n", WIDGET_X(c), WIDGET_Y(c), WIDGET_W(c), WIDGET_H(c), c->place_type);
}
void print_all_client_win(WM *wm)
@ -113,7 +113,7 @@ void print_all_client_win(WM *wm)
void print_client_win(Client *c)
{
printf("win=%lx (frame=%lx)\n", c->win, c->frame);
printf("win=%lx (frame=%lx)\n", WIDGET_WIN(c), WIDGET_WIN(c->frame));
}
void show_top_win(WM *wm)
@ -122,11 +122,11 @@ void show_top_win(WM *wm)
char *s[]={"DESKTOP_TOP", "BELOW_TOP", "NORMAL_TOP", "FLOAT_TOP",
"DOCK_TOP", "ABOVE_TOP", "FULLSCREEN_TOP"};
Str_fmt f={0, 0, w, h, CENTER_LEFT, false, false, 0xff0000,
get_text_color(CLASS_TEXT_COLOR)};
get_widget_fg(CLASS_TEXT_COLOR)};
for(size_t i=0; i<TOP_WIN_TYPE_N; i++)
{
XMoveResizeWindow(xinfo.display, wm->top_wins[i], i*w/2, taskbar->y-h, w, h);
XMoveResizeWindow(xinfo.display, wm->top_wins[i], i*w/2, WIDGET_Y(taskbar)-h, w, h);
XMapWindow(xinfo.display, wm->top_wins[i]);
draw_string(wm->top_wins[i], s[i], &f);
}

View File

@ -13,6 +13,8 @@
typedef enum op_type_tag { MOVE_TO_N, CHANGE_TO_N, ATTACH_TO_N, ATTACH_TO_ALL } Op_type;
static void hide_cur_desktop_clients(WM *wm);
static void show_cur_desktop_clients(WM *wm);
static void ready_to_desktop_n(WM *wm, Client *c, unsigned int n, Op_type op);
void init_desktop(WM *wm)
@ -34,43 +36,53 @@ unsigned int get_desktop_n(XEvent *e, Func_arg arg)
if(e->type == KeyPress)
return (arg.n>=0 && arg.n<=DESKTOP_N) ? arg.n : 1;
if(e->type == ButtonPress)
return WIDGET_INDEX(get_widget_type(e->xbutton.window), TASKBAR_BUTTON)+1;
return win_to_widget(e->xbutton.window)->id-TASKBAR_BUTTON_BEGIN+1;
return 1;
}
void focus_desktop_n(WM *wm, unsigned int n)
{
if(n == 0) // n=0表示所有虛擬桌面僅適用於attach_to_all_desktops
/* n=0表示所有虛擬桌面僅適用於attach_to_all_desktops */
if(n==0 || n==wm->cur_desktop)
return;
hide_cur_desktop_clients(wm);
wm->cur_desktop=n;
set_net_current_desktop(wm->cur_desktop-1);
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
{
if(is_on_cur_desktop(c))
{
if(c->icon)
XMapWindow(xinfo.display, c->icon->win);
else
XMapWindow(xinfo.display, c->frame);
}
else
{
if(c->icon)
XUnmapWindow(xinfo.display, c->icon->win);
else
XUnmapWindow(xinfo.display, c->frame);
}
}
set_net_current_desktop(n-1);
show_cur_desktop_clients(wm);
focus_client(wm, wm->cur_desktop, CUR_FOC_CLI(wm));
request_layout_update();
update_icon_area(wm->clients);
update_taskbar_buttons_bg();
set_all_net_client_list(wm->clients);
}
static void hide_cur_desktop_clients(WM *wm)
{
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
{
if(is_on_cur_desktop(c->desktop_mask))
{
if(is_iconic_client(c))
taskbar_del_cbutton(WIDGET_WIN(c));
else
hide_widget(WIDGET(c->frame));
}
}
}
static void show_cur_desktop_clients(WM *wm)
{
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
{
if(is_on_cur_desktop(c->desktop_mask))
{
if(is_iconic_client(c))
taskbar_add_cbutton(WIDGET_WIN(c));
else
show_widget(WIDGET(c->frame));
}
}
}
void move_to_desktop_n(WM *wm, Client *c, unsigned int n)
{
if(!n || n==wm->cur_desktop || c==wm->clients)

View File

@ -10,10 +10,19 @@
* ************************************************************************/
#include "gwm.h"
#include "misc.h"
#define ENTRY_EVENT_MASK (ButtonPressMask|KeyPressMask|ExposureMask)
struct _entry_tag // 輸入構件
{
Widget base;
wchar_t text[BUFSIZ]; // 構件上的文字
const char *hint; // 構件的提示文字
size_t cursor_offset; // 光標偏移字符數
XIC xic; // 輸入法句柄
Strings *(*complete)(Entry *, int *); // 補全函數
};
static int get_entry_cursor_x(Entry *entry);
static char *get_part_match_regex(Entry *entry);
static void complete_for_entry(Entry *entry, bool show);
@ -22,49 +31,53 @@ static Strings *get_cmd_completion_for_entry(Entry *entry, int *n);
Entry *cmd_entry=NULL; // 輸入命令並執行的構件
Entry *create_entry(Widget_type type, int x, int y, int w, int h, const char *hint, Strings *(*complete)(Entry *, int *))
Entry *create_entry(Widget_id id, Window parent, int x, int y, int w, int h, const char *hint, Strings *(*complete)(Entry *, int *))
{
Entry *entry=malloc_s(sizeof(Entry));
entry->x=x, entry->y=y, entry->w=w, entry->h=h;
entry->hint=hint, entry->complete=complete;
entry->win=create_widget_win(type, xinfo.root_win, x, y, w, h,
cfg->border_width, get_widget_color(CURRENT_BORDER_COLOR),
get_widget_color(ENTRY_COLOR));
XSelectInput(xinfo.display, entry->win, ENTRY_EVENT_MASK);
set_xic(entry->win, &entry->xic);
Widget_state state={.focus=1};
init_widget(WIDGET(entry), id, ENTRY_TYPE, state, parent, x, y, w, h);
entry->text[0]=L'\0', entry->hint=hint, entry->cursor_offset=0;
entry->complete=complete;
XSelectInput(xinfo.display, WIDGET_WIN(entry), ENTRY_EVENT_MASK);
set_xic(WIDGET_WIN(entry), &entry->xic);
return entry;
}
wchar_t *get_entry_text(Entry *entry)
{
return entry->text;
}
void show_entry(Entry *entry)
{
show_widget(WIDGET(entry));
entry->text[0]=L'\0', entry->cursor_offset=0;
XMapRaised(xinfo.display, entry->win);
update_entry_text(entry);
XGrabKeyboard(xinfo.display, entry->win, False,
update_entry_fg(entry);
XGrabKeyboard(xinfo.display, WIDGET_WIN(entry), False,
GrabModeAsync, GrabModeAsync, CurrentTime);
}
void update_entry_bg(Entry *entry)
{
update_win_bg(entry->win, get_widget_color(ENTRY_COLOR), None);
XSetWindowBorder(xinfo.display, entry->win,
update_widget_bg(WIDGET(entry));
XSetWindowBorder(xinfo.display, WIDGET_WIN(entry),
get_widget_color(CURRENT_BORDER_COLOR));
}
void update_entry_text(Entry *entry)
void update_entry_fg(Entry *entry)
{
int x=get_entry_cursor_x(entry);
bool empty = entry->text[0]==L'\0';
Str_fmt fmt={0, 0, entry->w, entry->h, CENTER_LEFT, true, false, 0,
get_text_color(empty ? HINT_TEXT_COLOR : ENTRY_TEXT_COLOR)};
Str_fmt fmt={0, 0, WIDGET_W(entry), WIDGET_H(entry), CENTER_LEFT, true, false, 0,
get_widget_fg(empty ? HINT_TEXT_COLOR : get_widget_fg_id(WIDGET(entry)))};
if(empty)
draw_string(entry->win, entry->hint, &fmt);
draw_string(WIDGET_WIN(entry), entry->hint, &fmt);
else
draw_wcs(entry->win, entry->text, &fmt);
draw_wcs(WIDGET_WIN(entry), entry->text, &fmt);
GC gc=XCreateGC(xinfo.display, entry->win, 0, NULL);
XDrawLine(xinfo.display, entry->win, gc, x, 0, x, entry->h);
GC gc=XCreateGC(xinfo.display, WIDGET_WIN(entry), 0, NULL);
XDrawLine(xinfo.display, WIDGET_WIN(entry), gc, x, 0, x, WIDGET_H(entry));
}
static int get_entry_cursor_x(Entry *entry)
@ -94,7 +107,7 @@ bool input_for_entry(Entry *entry, XKeyEvent *ke)
wmemmove(s, s+*i, no+1), *i=0;
else if(ks == XK_v)
XConvertSelection(xinfo.display, XA_PRIMARY, get_utf8_string_atom(),
None, entry->win, ke->time);
None, WIDGET_WIN(entry), ke->time);
}
else if(is_equal_modifier_mask(None, ke->state))
{
@ -120,7 +133,7 @@ bool input_for_entry(Entry *entry, XKeyEvent *ke)
wcsncpy(s+n1, keyname, n-n1-1), (*i)+=n2;
complete_for_entry(entry, true);
update_entry_text(entry);
update_entry_fg(entry);
return false;
}
@ -144,10 +157,11 @@ static void complete_for_entry(Entry *entry, bool show)
if(show)
{
Window win=xinfo.hint_win;
int i, bw=cfg->border_width, w=entry->w, h=entry->h, x=entry->x+bw,
y=entry->y+entry->h+2*bw, max=(xinfo.screen_height-y)/h;
int i, bw=cfg->border_width, w=WIDGET_W(entry), h=WIDGET_H(entry),
x=WIDGET_X(entry)+bw, y=WIDGET_Y(entry)+h+2*bw,
max=(xinfo.screen_height-y)/h;
Str_fmt fmt={0, 0, w, h, CENTER_LEFT, true, false, 0,
get_text_color(HINT_TEXT_COLOR)};
get_widget_fg(HINT_TEXT_COLOR)};
XMoveResizeWindow(xinfo.display, win, x, y, w, MIN(n, max)*h);
XMapWindow(xinfo.display, win);
@ -166,21 +180,20 @@ static void complete_for_entry(Entry *entry, bool show)
static void hide_entry(Entry *entry)
{
XUngrabKeyboard(xinfo.display, CurrentTime);
XUnmapWindow(xinfo.display, entry->win);
hide_widget(WIDGET(entry));
XUnmapWindow(xinfo.display, xinfo.hint_win);
}
void destroy_entry(Entry *entry)
{
XDestroyWindow(xinfo.display, entry->win);
if(entry->xic)
XDestroyIC(entry->xic);
free(entry);
destroy_widget(WIDGET(entry));
}
void paste_for_entry(Entry *entry)
{
char *p=(char *)get_prop(entry->win, get_utf8_string_atom(), NULL);
char *p=(char *)get_prop(WIDGET_WIN(entry), get_utf8_string_atom(), NULL);
wchar_t text[BUFSIZ];
int n=mbstowcs(text, p, BUFSIZ);
XFree(p);
@ -191,10 +204,10 @@ void paste_for_entry(Entry *entry)
wmemmove(dest, src, wcslen(entry->text)-entry->cursor_offset);
wcsncpy(src, text, n);
entry->cursor_offset += n;
update_entry_text(entry);
update_entry_fg(entry);
}
Entry *create_cmd_entry(Widget_type type)
Entry *create_cmd_entry(Widget_id id)
{
int sw=xinfo.screen_width, sh=xinfo.screen_height, bw=cfg->border_width,
x, y, w, h=get_font_height_by_pad(), pad=get_font_pad();
@ -203,7 +216,7 @@ Entry *create_cmd_entry(Widget_type type)
w += 2*pad, w = (w>=sw/4 && w<=sw-2*bw) ? w : sw/4;
x=(sw-w)/2-bw, y=(sh-h)/2-bw;
return create_entry(type, x, y, w, h, cfg->cmd_entry_hint,
return create_entry(id, xinfo.root_win, x, y, w, h, cfg->cmd_entry_hint,
get_cmd_completion_for_entry);
}

View File

@ -12,27 +12,18 @@
#ifndef ENTRY_H
#define ENTRY_H
typedef struct _entry_tag Entry; // 輸入構件
#define ENTRY(widget) ((Entry *)(widget))
struct _entry_tag
{
Window win; // 輸入構件的窗口
int x, y; // 坐標
int w, h; // 寬和高
wchar_t text[BUFSIZ]; // 構件上的文字
const char *hint; // 構件的提示文字
size_t cursor_offset; // 光標位置
XIC xic; // 輸入法句柄
Strings *(*complete)(Entry *, int *);
};
typedef struct _entry_tag Entry;
Entry *create_entry(Widget_type type, int x, int y, int w, int h, const char *hint, Strings *(*complete)(Entry *, int *));
Entry *create_entry(Widget_id id, Window parent, int x, int y, int w, int h, const char *hint, Strings *(*complete)(Entry *, int *));
wchar_t *get_entry_text(Entry *entry);
void show_entry(Entry *entry);
void update_entry_bg(Entry *entry);
void update_entry_text(Entry *entry);
void update_entry_fg(Entry *entry);
bool input_for_entry(Entry *entry, XKeyEvent *ke);
void destroy_entry(Entry *entry);
void paste_for_entry(Entry *entry);
Entry *create_cmd_entry(Widget_type type);
Entry *create_cmd_entry(Widget_id id);
#endif

View File

@ -341,7 +341,7 @@ Net_wm_state get_net_wm_state_mask(const long *full_act)
/* 判斷是否存在遵從EWMH標準的合成器 */
bool have_compositor(void)
{
return get_compositor() != None;
return get_compositor() != None;
}
/* 獲取遵從EWMH標準的合成器的ID它未必是真實的窗口 */

View File

@ -174,7 +174,7 @@ static WMFont *get_suitable_font(uint32_t codepoint)
if(XftCharExists(xinfo.display, font->xfont, codepoint))
return font;
for(int i=0; font_set->nfont; i++)
for(int i=0; i<font_set->nfont; i++)
{
if((font=load_font((char *)FcPatternFormat(font_set->fonts[i], fmt))))
{
@ -220,21 +220,25 @@ static void get_str_rect_by_fmt(const Str_fmt *f, const char *str, int *x, int *
void get_string_size(const char *str, int *w, int *h)
{
int width=0, max_asc=0, max_desc=0;
uint32_t codepoint;
XGlyphInfo info;
WMFont *font=NULL;
for(int len=0; *str; str+=len)
if(str)
{
len=get_utf8_codepoint(str, &codepoint);
if(len && (font=get_suitable_font(codepoint)))
uint32_t codepoint;
XGlyphInfo info;
WMFont *font=NULL;
for(int len=0; *str; str+=len)
{
XftTextExtentsUtf8(xinfo.display, font->xfont, (const FcChar8 *)str, len, &info);
width += info.xOff;
if(font->xfont->ascent > max_asc)
max_asc=font->xfont->ascent;
if(font->xfont->descent > max_desc)
max_desc=font->xfont->descent;
len=get_utf8_codepoint(str, &codepoint);
if(len && (font=get_suitable_font(codepoint)))
{
XftTextExtentsUtf8(xinfo.display, font->xfont, (const FcChar8 *)str, len, &info);
width += info.xOff;
if(font->xfont->ascent > max_asc)
max_asc=font->xfont->ascent;
if(font->xfont->descent > max_desc)
max_desc=font->xfont->descent;
}
}
}
if(w)

View File

@ -11,6 +11,7 @@
#include "gwm.h"
#include "mvresize.h"
#include "menu.h"
static bool is_valid_click(XEvent *oe, XEvent *ne);
@ -29,7 +30,7 @@ static bool is_grab_root_act(Pointer_act act)
bool get_valid_click(WM *wm, Pointer_act act, XEvent *oe, XEvent *ne)
{
if(act==CHOOSE && get_widget_type(oe->xbutton.window)==CLIENT_WIN)
if(act==CHOOSE && win_to_widget(oe->xbutton.window)->id==CLIENT_WIN)
return true;
Window win = is_grab_root_act(act) ? xinfo.root_win : oe->xbutton.window;
@ -57,7 +58,7 @@ void choose_client(WM *wm, XEvent *e, Func_arg arg)
{
Client *c=CUR_FOC_CLI(wm);
if(c->icon)
if(is_iconic_client(c))
deiconify_client(wm, c);
if(DESKTOP(wm)->cur_layout == PREVIEW)
@ -81,7 +82,7 @@ void clear_wm(WM *wm)
{
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
{
XReparentWindow(xinfo.display, c->win, xinfo.root_win, c->x, c->y);
XReparentWindow(xinfo.display, WIDGET_WIN(c), xinfo.root_win, WIDGET_X(c), WIDGET_Y(c));
del_client(wm, c, true);
}
XDestroyWindow(xinfo.display, xinfo.hint_win);
@ -115,15 +116,15 @@ void close_client(WM *wm, XEvent *e, Func_arg arg)
/* 刪除窗口會產生UnmapNotify事件處理該事件時再刪除框架 */
Client *c=CUR_FOC_CLI(wm);
if(c != wm->clients)
close_win(c->win);
close_win(WIDGET_WIN(c));
}
void close_all_clients(WM *wm, XEvent *e, Func_arg arg)
{
UNUSED(e), UNUSED(arg);
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
if(is_on_cur_desktop(c))
close_win(c->win);
if(is_on_cur_desktop(c->desktop_mask))
close_win(WIDGET_WIN(c));
}
/* 取得存儲次序上在當前客戶之前的客戶(或其亞組長)。因使用頭插法存儲客戶,
@ -176,7 +177,7 @@ void toggle_border_visibility(WM *wm, XEvent *e, Func_arg arg)
UNUSED(e), UNUSED(arg);
Client *c=CUR_FOC_CLI(wm);
c->border_w = c->border_w ? 0 : cfg->border_width;
XSetWindowBorderWidth(xinfo.display, c->frame, c->border_w);
set_widget_border_width(WIDGET(c->frame), c->border_w);
request_layout_update();
}
@ -188,14 +189,14 @@ void toggle_titlebar_visibility(WM *wm, XEvent *e, Func_arg arg)
if(c->titlebar_h)
{
create_titlebar(c);
XMapSubwindows(xinfo.display, c->frame);
show_widget(WIDGET(c->frame));
}
else
{
for(size_t i=0; i<TITLE_BUTTON_N; i++)
XDestroyWindow(xinfo.display, c->buttons[i]);
XDestroyWindow(xinfo.display, c->title_area);
XDestroyWindow(xinfo.display, c->logo);
destroy_button(c->frame->buttons[i]);
destroy_widget(c->frame->title_area);
destroy_button(c->frame->logo);
}
request_layout_update();
}
@ -253,9 +254,10 @@ void all_attach_to_desktop(WM *wm, XEvent *e, Func_arg arg)
all_attach_to_desktop_n(wm, get_desktop_n(e, arg));
}
void enter_and_run_cmd(WM *wm, XEvent *e, Func_arg arg)
void show_run_cmd_entry(WM *wm, XEvent *e, Func_arg arg)
{
UNUSED(wm), UNUSED(e), UNUSED(arg);
XRaiseWindow(xinfo.display, WIDGET_WIN(cmd_entry));
show_entry(cmd_entry);
}
@ -290,7 +292,7 @@ void print_win(WM *wm, XEvent *e, Func_arg arg)
UNUSED(e), UNUSED(arg);
Client *c=CUR_FOC_CLI(wm);
if(c != wm->clients)
print_area(c->frame, 0, 0, c->w, c->h);
print_area(WIDGET_WIN(c->frame), 0, 0, WIDGET_W(c), WIDGET_H(c));
}
void switch_color_theme(WM *wm, XEvent *e, Func_arg arg)
@ -303,8 +305,8 @@ void switch_color_theme(WM *wm, XEvent *e, Func_arg arg)
// 以下函數會產生Expose事件而處理Expose事件時會更新窗口的文字
// 內容及其顏色,故此處不必更新構件文字顏色。
update_taskbar_bg();
update_menu_bg(act_center, ACT_CENTER_ITEM_N);
update_menu_bg(client_menu, CLIENT_MENU_ITEM_N);
update_menu_bg(act_center);
update_menu_bg(client_menu);
update_entry_bg(cmd_entry);
update_win_bg(xinfo.hint_win, get_widget_color(HINT_WIN_COLOR), None);
update_clients_bg(wm);

View File

@ -45,7 +45,7 @@ void all_change_to_desktop(WM *wm, XEvent *e, Func_arg arg);
void attach_to_desktop(WM *wm, XEvent *e, Func_arg arg);
void attach_to_all_desktops(WM *wm, XEvent *e, Func_arg arg);
void all_attach_to_desktop(WM *wm, XEvent *e, Func_arg arg);
void enter_and_run_cmd(WM *wm, XEvent *e, Func_arg arg);
void show_run_cmd_entry(WM *wm, XEvent *e, Func_arg arg);
void switch_wallpaper(WM *wm, XEvent *e, Func_arg arg);
void print_screen(WM *wm, XEvent *e, Func_arg arg);
void print_win(WM *wm, XEvent *e, Func_arg arg);

View File

@ -33,15 +33,19 @@
#include <X11/Xft/Xft.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "font.h"
#include "widget.h"
#include "button.h"
#include "drawable.h"
#include "entry.h"
#include "ewmh.h"
#include "file.h"
#include "font.h"
#include "menu.h"
#include "icccm.h"
#include "image.h"
#include "prop.h"
#include "taskbar.h"
#define _(s) gettext(s)
@ -93,12 +97,6 @@ typedef struct // 與X相關的信息
Window hint_win; // 提示窗口
} Xinfo;
enum focus_mode_tag // 窗口聚焦模式
{
ENTER_FOCUS, CLICK_FOCUS,
};
typedef enum focus_mode_tag Focus_mode;
enum place_type_tag // 窗口的位置類型
{
FULLSCREEN_LAYER, ABOVE_LAYER, DOCK_LAYER, FLOAT_LAYER,
@ -107,13 +105,6 @@ enum place_type_tag // 窗口的位置類型
};
typedef enum place_type_tag Place_type;
enum top_win_type_tag // 窗口疊次序分層類型
{
DESKTOP_TOP, BELOW_TOP, NORMAL_TOP, FLOAT_TOP, DOCK_TOP, ABOVE_TOP,
FULLSCREEN_TOP, TOP_WIN_TYPE_N
};
typedef enum top_win_type_tag Top_win_type;
struct rectangle_tag // 矩形窗口或區域的坐標和尺寸
{
int x, y; // 坐標
@ -142,6 +133,12 @@ struct rule_tag // 窗口管理器的規則
};
typedef struct rule_tag Rule;
typedef enum // 窗口疊次序分層類型
{
DESKTOP_TOP, BELOW_TOP, NORMAL_TOP, FLOAT_TOP, DOCK_TOP, ABOVE_TOP,
FULLSCREEN_TOP, TOP_WIN_TYPE_N
} Top_win_type;
struct wm_tag // 窗口管理器相關信息
{
unsigned int cur_desktop; // 當前虛擬桌面編號從1開始編號
@ -197,7 +194,7 @@ typedef struct keybind_tag Keybind;
struct buttonbind_tag // 定位器按鈕功能綁定
{
Widget_type widget_type; // 要綁定的構件類型
Widget_id widget_id; // 要綁定的構件標識
unsigned int modifier; // 要綁定的鍵盤功能轉換鍵
unsigned int button; // 要綁定的定位器按鈕
void (*func)(WM *, XEvent *, Func_arg); // 要綁定的函數
@ -221,16 +218,13 @@ typedef struct delta_rect_tag Delta_rect;
#include "config.h"
#include "debug.h"
#include "desktop.h"
#include "entry.h"
#include "func.h"
#include "handler.h"
#include "init.h"
#include "layout.h"
#include "minimax.h"
#include "misc.h"
#include "mvresize.h"
#include "place.h"
#include "taskbar.h"
extern sig_atomic_t run_flag; // 程序運行標志
extern Xinfo xinfo;

View File

@ -10,12 +10,12 @@
* ************************************************************************/
#include "gwm.h"
#include "menu.h"
static void ignore_event(WM *wm, XEvent *e);
static void handle_button_press(WM *wm, XEvent *e);
static void unmap_for_click(Widget_type type);
static bool is_func_click(Widget_type type, const Buttonbind *b, XEvent *e);
static void focus_clicked_client(WM *wm, Window win);
static void unmap_for_click(Widget_id id);
static bool is_func_click(const Widget_id id, const Buttonbind *b, XEvent *e);
static void handle_client_message(WM *wm, XEvent *e);
static void change_net_wm_state(WM *wm, Client *c, long *full_act);
static void change_net_wm_state_for_modal(WM *wm, Client *c, long act);
@ -33,11 +33,9 @@ static void handle_config_request(WM *wm, XEvent *e);
static void config_managed_client(Client *c);
static void config_unmanaged_win(XConfigureRequestEvent *e);
static void handle_enter_notify(WM *wm, XEvent *e);
static void handle_pointer_hover(WM *wm, Window hover, Widget_type type);
static const char *get_tooltip(WM *wm, Window win, Widget_type type);
static void handle_pointer_hover(WM *wm, const Widget *widget);
static void handle_expose(WM *wm, XEvent *e);
static void update_title_area_fg(WM *wm, Client *c);
static void update_title_button_fg(WM *wm, Client *c, size_t index);
static void handle_focus_in(WM *wm, XEvent *e);
static void handle_focus_out(WM *wm, XEvent *e);
static void handle_key_press(WM *wm, XEvent *e);
@ -90,54 +88,47 @@ static void ignore_event(WM *wm, XEvent *e)
static void handle_button_press(WM *wm, XEvent *e)
{
Window win=e->xbutton.window;
Client *c=win_to_client(wm->clients, win),
*tmc = c ? get_top_transient_client(c->subgroup_leader, true) : NULL;
Widget_type type=get_widget_type(win);
Widget *widget=win_to_widget(win);
Widget_id id = widget ? widget->id : (win==xinfo.root_win ? ROOT_WIN : NON_WIDGET);
Client *c=win_to_client(wm->clients, id==CLIENT_ICON ? get_iconic_win(win) : win);
Client *tmc = c ? get_top_transient_client(c->subgroup_leader, true) : NULL;
for(const Buttonbind *b=cfg->buttonbind; b->func; b++)
{
if( is_func_click(type, b, e)
if( is_func_click(id, b, e)
&& (is_drag_func(b->func) || get_valid_click(wm, CHOOSE, e, NULL)))
{
if(type == CLIENT_WIN)
if(id == CLIENT_WIN)
XAllowEvents(xinfo.display, ReplayPointer, CurrentTime);
focus_clicked_client(wm, win);
if(c && c!=CUR_FOC_CLI(wm))
focus_client(wm, wm->cur_desktop, c);
if((DESKTOP(wm)->cur_layout==PREVIEW || !c || !tmc || c==tmc) && b->func)
b->func(wm, e, b->arg);
}
}
unmap_for_click(type);
unmap_for_click(id);
}
static void unmap_for_click(Widget_type type)
static void unmap_for_click(Widget_id id)
{
if(type != ACT_CENTER_ITEM)
XUnmapWindow(xinfo.display, act_center->win);
if(type != TITLE_LOGO)
XUnmapWindow(xinfo.display, client_menu->win);
if(type!=RUN_CMD_ENTRY && type!=RUN_BUTTON)
if(id != ACT_CENTER_ITEM)
hide_widget(WIDGET(act_center));
if(id != TITLE_LOGO)
hide_widget(WIDGET(client_menu));
if(id!=RUN_CMD_ENTRY && id!=RUN_BUTTON)
{
XUnmapWindow(xinfo.display, cmd_entry->win);
hide_widget(WIDGET(cmd_entry));
XUnmapWindow(xinfo.display, xinfo.hint_win);
}
}
static bool is_func_click(Widget_type type, const Buttonbind *b, XEvent *e)
static bool is_func_click(const Widget_id id, const Buttonbind *b, XEvent *e)
{
return (b->widget_type == type
return (b->widget_id == id
&& b->button == e->xbutton.button
&& is_equal_modifier_mask( b->modifier, e->xbutton.state));
}
static void focus_clicked_client(WM *wm, Window win)
{
Client *c=win_to_client(wm->clients, win);
if(c == NULL)
c=win_to_iconic_state_client(wm->clients, win);
if(c && c!=CUR_FOC_CLI(wm))
focus_client(wm, wm->cur_desktop, c);
}
static void handle_client_message(WM *wm, XEvent *e)
{
Window win=e->xclient.window;
@ -152,7 +143,7 @@ static void handle_client_message(WM *wm, XEvent *e)
{
if(is_spec_ewmh_atom(type, NET_ACTIVE_WINDOW))
activate_win(wm, win, e->xclient.data.l[0]);
else if(is_spec_ewmh_atom(type, NET_CLOSE_WINDOW))
if(is_spec_ewmh_atom(type, NET_CLOSE_WINDOW))
close_win(win);
else if(is_spec_ewmh_atom(type, NET_WM_DESKTOP))
change_desktop(wm, win, e->xclient.data.l[0]);
@ -187,7 +178,7 @@ static void change_net_wm_state(WM *wm, Client *c, long *full_act)
if(mask.attent) change_net_wm_state_for_attent(wm, c, act);
if(mask.focused) change_net_wm_state_for_focused(wm, c, act);
update_net_wm_state(c->win, c->win_state);
update_net_wm_state(WIDGET_WIN(c), c->win_state);
}
static void change_net_wm_state_for_modal(WM *wm, Client *c, long act)
@ -217,7 +208,7 @@ static void change_net_wm_state_for_skip_taskbar(WM *wm, Client *c, long act)
{
bool add=SHOULD_ADD_STATE(c, act, skip_taskbar);
if(add && c->icon)
if(add && is_iconic_client(c))
deiconify_client(wm, c);
c->win_state.skip_taskbar=add;
}
@ -263,7 +254,7 @@ static void change_net_wm_state_for_attent(WM *wm, Client *c, long act)
{
UNUSED(wm);
c->win_state.attent=SHOULD_ADD_STATE(c, act, attent);
update_taskbar_buttons_bg();
set_taskbar_attention(c->desktop_mask, !is_on_cur_desktop(c->desktop_mask));
}
static void change_net_wm_state_for_focused(WM *wm, Client *c, long act)
@ -285,13 +276,13 @@ static void activate_win(WM *wm, Window win, unsigned long src)
if(src == 2) // 源自分頁器
{
if(is_on_cur_desktop(c))
if(is_on_cur_desktop(c->desktop_mask))
focus_client(wm, wm->cur_desktop, c);
else
set_urgency(c, true);
set_urgency_hint(win, c->wm_hint, true);
}
else // 源自應用程序
set_attention(c, true);
set_state_attent(c, true);
}
static void change_desktop(WM *wm, Window win, unsigned int desktop)
@ -322,11 +313,11 @@ static void config_managed_client(Client *c)
{
XConfigureEvent ce=
{
.type=ConfigureNotify, .display=xinfo.display, .event=c->win,
.window=c->win, .x=c->x, .y=c->y, .width=c->w, .height=c->h,
.type=ConfigureNotify, .display=xinfo.display, .event=WIDGET_WIN(c),
.window=WIDGET_WIN(c), .x=WIDGET_X(c), .y=WIDGET_Y(c), .width=WIDGET_W(c), .height=WIDGET_H(c),
.border_width=0, .above=None, .override_redirect=False
};
XSendEvent(xinfo.display, c->win, False, StructureNotifyMask, (XEvent *)&ce);
XSendEvent(xinfo.display, WIDGET_WIN(c), False, StructureNotifyMask, (XEvent *)&ce);
}
static void config_unmanaged_win(XConfigureRequestEvent *e)
@ -343,33 +334,38 @@ static void handle_enter_notify(WM *wm, XEvent *e)
{
int x=e->xcrossing.x_root, y=e->xcrossing.y_root;
Window win=e->xcrossing.window;
Widget_type type=get_widget_type(win);
Client *c=win_to_client(wm->clients, win);
Pointer_act act=NO_OP;
Move_info m={x, y, 0, 0};
Widget *widget=win_to_widget(win);
if(cfg->focus_mode==ENTER_FOCUS && c)
focus_client(wm, wm->cur_desktop, c);
if( is_layout_adjust_area(wm, win, x)
&& get_clients_n(wm->clients, TILE_LAYER_MAIN, false, false, false))
act=ADJUST_LAYOUT_RATIO;
else if(IS_BUTTON(type))
update_win_bg(win, get_widget_color(type==CLOSE_BUTTON ?
ENTERED_CLOSE_BUTTON_COLOR : ENTERED_NORMAL_BUTTON_COLOR), None);
else if(type == CLIENT_FRAME)
set_cursor(win, ADJUST_LAYOUT_RATIO);
if(widget == NULL)
return;
if(widget->type == BUTTON_TYPE)
{
if(widget->id == CLOSE_BUTTON)
widget->state.warn=1;
widget->state.hot=1;
update_widget_bg(widget);
}
else if(widget->id == CLIENT_FRAME)
act=get_resize_act(c, &m);
else if(type == TITLE_AREA)
else if(widget->id == TITLE_AREA)
act=MOVE;
if(type != NON_WIDGET)
if(widget->id != NON_WIDGET)
set_cursor(win, act);
handle_pointer_hover(wm, win, type);
handle_pointer_hover(wm, widget);
}
static void handle_pointer_hover(WM *wm, Window hover, Widget_type type)
static void handle_pointer_hover(WM *wm, const Widget *widget)
{
const char *tooltip=get_tooltip(wm, hover, type);
if(!tooltip)
if(!widget->tooltip)
return;
XEvent ev;
@ -384,9 +380,9 @@ static void handle_pointer_hover(WM *wm, Window hover, Widget_type type)
{
XNextEvent(xinfo.display, &ev);
wm->event_handlers[ev.type](wm, &ev);
if(ev.type == MotionNotify && ev.xmotion.window==hover)
if(ev.type == MotionNotify && ev.xmotion.window==widget->win)
XUnmapWindow(xinfo.display, xinfo.hint_win), t=t0, done=false;
else if(ev.type==LeaveNotify && ev.xcrossing.window==hover)
else if(ev.type==LeaveNotify && ev.xcrossing.window==widget->win)
break;
}
else
@ -399,50 +395,32 @@ static void handle_pointer_hover(WM *wm, Window hover, Widget_type type)
{
t=t0;
if(!done)
update_hint_win_for_info(hover, tooltip), done=true;
update_hint_win_for_info(widget, widget->tooltip), done=true;
}
}
}
XUnmapWindow(xinfo.display, xinfo.hint_win);
}
static const char *get_tooltip(WM *wm, Window win, Widget_type type)
{
switch(type)
{
case CLIENT_ICON: return win_to_iconic_state_client(wm->clients, win)->icon->title_text;
case TITLE_AREA: return win_to_client(wm->clients, win)->title_text;
default: return cfg->tooltip[type];
}
}
static void handle_expose(WM *wm, XEvent *e)
{
if(e->xexpose.count)
return;
Window win=e->xexpose.window;
Widget_type type=get_widget_type(win);
Client *c=win_to_client(wm->clients, win);
Widget *widget=win_to_widget(win);
Client *c=NULL;
if(widget == NULL)
return;
if(type == CLIENT_ICON)
update_client_icon_fg(wm, win);
else if(IS_WIDGET_CLASS(type, TASKBAR_BUTTON))
update_taskbar_button_fg(type);
else if(IS_WIDGET_CLASS(type, ACT_CENTER_ITEM))
update_menu_item_fg(act_center, WIDGET_INDEX(type, ACT_CENTER_ITEM));
else if(IS_WIDGET_CLASS(type, CLIENT_MENU_ITEM))
update_menu_item_fg(client_menu, WIDGET_INDEX(type, CLIENT_MENU_ITEM));
else if(type == STATUS_AREA)
update_status_area_fg();
else if(type == TITLE_LOGO)
draw_icon(c->logo, c->image, c->class_name, c->titlebar_h);
else if(type == TITLE_AREA)
if(widget->id==TITLE_AREA && (c=win_to_client(wm->clients, win)))
update_title_area_fg(wm, c);
else if(IS_WIDGET_CLASS(type, TITLE_BUTTON))
update_title_button_fg(wm, c, WIDGET_INDEX(type, TITLE_BUTTON));
else if(type == RUN_CMD_ENTRY)
update_entry_text(cmd_entry);
else if(widget->type == BUTTON_TYPE)
update_button_fg(BUTTON(widget));
else if(widget->type == ENTRY_TYPE)
update_entry_fg(ENTRY(widget));
else if(widget->id == STATUSBAR)
update_statusbar_fg();
}
static void update_title_area_fg(WM *wm, Client *c)
@ -451,34 +429,27 @@ static void update_title_area_fg(WM *wm, Client *c)
return;
Rect r=get_title_area_rect(c);
Text_color id = (c==CUR_FOC_CLI(wm)) ?
Text_color_id id = (c==CUR_FOC_CLI(wm)) ?
CURRENT_TITLEBAR_TEXT_COLOR : NORMAL_TITLEBAR_TEXT_COLOR;
Str_fmt f={0, 0, r.w, r.h, CENTER, true, false, 0,
get_text_color(id)};
draw_string(c->title_area, c->title_text, &f);
}
static void update_title_button_fg(WM *wm, Client *c, size_t index)
{
if(c->titlebar_h <= 0)
return;
int w=cfg->title_button_width, h=get_font_height_by_pad();
Text_color id = (c==CUR_FOC_CLI(wm)) ?
CURRENT_TITLEBAR_TEXT_COLOR : NORMAL_TITLEBAR_TEXT_COLOR;
Str_fmt f={0, 0, w, h, CENTER, false, false, 0,
get_text_color(id)};
draw_string(c->buttons[index], cfg->title_button_text[index], &f);
get_widget_fg(id)};
draw_string(c->frame->title_area->win, c->title_text, &f);
}
static void handle_focus_in(WM *wm, XEvent *e)
{
Window win=e->xfocus.window;
Client *c=win_to_client(wm->clients, e->xfocus.window);
if(c && c->win_state.fullscreen && c->place_type!=FULLSCREEN_LAYER)
if(!c)
return;
if(c->win_state.fullscreen && c->place_type!=FULLSCREEN_LAYER)
{
c->x=c->y=0, c->w=xinfo.screen_width, c->h=xinfo.screen_height;
WIDGET_X(c)=WIDGET_Y(c)=0, WIDGET_W(c)=xinfo.screen_width, WIDGET_H(c)=xinfo.screen_height;
move_client(wm, c, NULL, FULLSCREEN_LAYER);
}
set_urgency_hint(win, c->wm_hint, false);
set_state_attent(c, false);
}
static void handle_focus_out(WM *wm, XEvent *e)
@ -490,7 +461,7 @@ static void handle_focus_out(WM *wm, XEvent *e)
static void handle_key_press(WM *wm, XEvent *e)
{
if(e->xkey.window == cmd_entry->win)
if(e->xkey.window == WIDGET_WIN(cmd_entry))
key_run_cmd(wm, &e->xkey);
else
{
@ -512,29 +483,26 @@ static void key_run_cmd(WM *wm, XKeyEvent *e)
return;
char cmd[BUFSIZ]={0};
wcstombs(cmd, cmd_entry->text, BUFSIZ);
wcstombs(cmd, get_entry_text(cmd_entry), BUFSIZ);
exec(wm, NULL, (Func_arg)SH_CMD(cmd));
}
static void handle_leave_notify(WM *wm, XEvent *e)
{
UNUSED(wm);
Window win=e->xcrossing.window;
Widget_type type=get_widget_type(win);
Client *c=win_to_client(wm->clients, win);
Widget *widget=win_to_widget(win);
if(widget == NULL)
return;
if(IS_WIDGET_CLASS(type, TASKBAR_BUTTON))
update_taskbar_button_bg(type);
else if(type == CLIENT_ICON)
if(widget->type == BUTTON_TYPE)
{
widget->state.hot=widget->state.warn=0;
update_widget_bg(widget);
}
else if(widget->id == CLIENT_ICON)
update_win_bg(win, get_widget_color(TASKBAR_COLOR), None);
else if(IS_MENU_ITEM(type))
update_win_bg(win, get_widget_color(MENU_COLOR), None);
else if(type == TITLE_LOGO)
update_win_bg(win, get_widget_color(c==CUR_FOC_CLI(wm) ?
CURRENT_TITLEBAR_COLOR : NORMAL_TITLEBAR_COLOR), None);
else if(IS_WIDGET_CLASS(type, TITLE_BUTTON))
update_win_bg(win, get_widget_color(c==CUR_FOC_CLI(wm) ?
CURRENT_TITLEBAR_COLOR : NORMAL_TITLEBAR_COLOR), None);
if(type != NON_WIDGET)
if(widget->id != NON_WIDGET)
set_cursor(win, NO_OP);
}
@ -569,8 +537,8 @@ static void handle_unmap_notify(WM *wm, XEvent *e)
XUnmapEvent *ue=&e->xunmap;
Client *c=win_to_client(wm->clients, ue->window);
if( c && ue->window==c->win
&& (ue->send_event|| ue->event==c->frame || ue->event==c->win))
if( c && ue->window==WIDGET_WIN(c)
&& (ue->send_event|| ue->event==WIDGET_WIN(c->frame) || ue->event==WIDGET_WIN(c)))
del_client(wm, c, false);
}
@ -581,7 +549,7 @@ static void handle_property_notify(WM *wm, XEvent *e)
Atom atom=e->xproperty.atom;
if(c && cfg->set_frame_prop)
copy_prop(c->frame, c->win);
copy_prop(WIDGET_WIN(c->frame), WIDGET_WIN(c));
if(atom == XA_WM_HINTS)
handle_wm_hints_notify(wm, win);
else if(atom==XA_WM_ICON_NAME || is_spec_ewmh_atom(atom, NET_WM_ICON_NAME))
@ -592,12 +560,17 @@ static void handle_property_notify(WM *wm, XEvent *e)
handle_wm_transient_for_notify(wm, win);
else if(c && is_spec_ewmh_atom(atom, NET_WM_ICON))
{
c->image=get_icon_image(c->win, c->wm_hint, c->class_hint.res_name,
Imlib_Image image=get_icon_image(WIDGET_WIN(c), c->class_hint.res_name,
cfg->icon_image_size, cfg->cur_icon_theme);
draw_image(c->image, c->logo, 0, 0, c->titlebar_h, c->titlebar_h);
if(c->icon)
draw_image(c->image, c->icon->win, 0, 0, c->titlebar_h, c->titlebar_h);
set_button_icon(c->frame->logo, image, c->class_hint.res_name, NULL);
if(is_iconic_client(c))
update_button_fg(BUTTON(win_to_widget(win)));
}
else if(c && is_spec_ewmh_atom(atom, NET_WM_STATE))
update_iconbar_by_state(win);
else if(is_spec_ewmh_atom(atom, NET_CURRENT_DESKTOP)
|| is_spec_gwm_atom(atom, GWM_CURRENT_LAYOUT))
update_taskbar_buttons_bg_by_chosen();
else if(is_spec_gwm_atom(atom, GWM_UPDATE_LAYOUT))
update_layout(wm);
}
@ -610,7 +583,9 @@ static void handle_wm_hints_notify(WM *wm, Window win)
XWMHints *oh=c->wm_hint, *nh=XGetWMHints(xinfo.display, win);
if(nh && has_focus_hint(nh) && (!oh || !has_focus_hint(oh)))
set_attention(c, true);
set_state_attent(c, true);
if(nh && nh->flags & XUrgencyHint)
set_taskbar_urgency(c->desktop_mask, !is_on_cur_desktop(c->desktop_mask));
update_taskbar_buttons_bg();
if(nh)
XFree(c->wm_hint), c->wm_hint=nh;
@ -621,12 +596,12 @@ static void handle_wm_icon_name_notify(WM *wm, Window win, Atom atom)
char *s=NULL;
Client *c=win_to_client(wm->clients, win);
if(!c || !c->icon || !(s=get_text_prop(c->win, atom)))
if(!c || !is_iconic_client(c) || !(s=get_text_prop(win, atom)))
return;
free(c->icon->title_text);
c->icon->title_text=s;
update_icon_area(wm->clients);
set_button_label(BUTTON(win_to_widget(win)), s);
free(s);
update_iconbar();
}
static void handle_wm_name_notify(WM *wm, Window win, Atom atom)
@ -638,17 +613,14 @@ static void handle_wm_name_notify(WM *wm, Window win, Atom atom)
return;
if(win == xinfo.root_win)
{
free(taskbar->status_text);
taskbar->status_text=s;
update_icon_status_area();
}
set_statusbar_label(s);
else
{
free(c->title_text);
c->title_text=s;
c->title_text=copy_string(s);
update_title_area_fg(wm, c);
}
free(s);
}
static void handle_wm_transient_for_notify(WM *wm, Window win)
@ -663,6 +635,6 @@ static void handle_selection_notify(WM *wm, XEvent *e)
UNUSED(wm);
Window win=e->xselection.requestor;
if( is_spec_icccm_atom(e->xselection.property, UTF8_STRING)
&& win==cmd_entry->win)
&& win==WIDGET_WIN(cmd_entry))
paste_for_entry(cmd_entry);
}

View File

@ -11,15 +11,25 @@
#include "gwm.h"
typedef struct image_node_tag
{
char *name;
Imlib_Image image;
struct image_node_tag *next;
} Image_node;
typedef struct // 存儲圖標主題規範所說的Per-Directory Keys的結構
{
int size, scale, max_size, min_size, threshold;
char type[10]; // char context[32]; 目前用不上
} Icon_dir_info;
static Imlib_Image get_icon_image_from_hint(const XWMHints *hint);
static Imlib_Image get_icon_image_from_prop(Window win);
static Imlib_Image get_icon_image_from_file(const char *name, int size, const char *theme);
static Imlib_Image search_icon_image(const char *name);
static Imlib_Image create_icon_image(Window win, const char *name, int size, const char *theme);
static void reg_image(const char *name, Imlib_Image image);
static Imlib_Image create_icon_image_from_hint(Window win);
static Imlib_Image create_icon_image_from_prop(Window win);
static Imlib_Image create_icon_image_from_file(const char *name, int size, const char *theme);
static char *find_icon(const char *name, int size, int scale, const char *theme, const char *context_dir);
static char *find_icon_helper(const char *name, int size, int scale, char *const *base_dirs, const char *theme, const char *context_dir);
static char *lookup_icon(const char *name, int size, int scale, char *const *base_dirs, const char *theme, const char *context_dir);
@ -38,6 +48,8 @@ static FILE *open_index_theme(const char *base_dir, const char *theme);
static size_t get_spec_char_num(const char *str, int ch);
static char **get_parent_themes(const char *base_dir, const char *theme);
static Image_node *image_list=NULL;
void draw_image(Imlib_Image image, Drawable d, int x, int y, int w, int h)
{
XClearArea(xinfo.display, d, x, y, w, h, False);
@ -47,32 +59,59 @@ void draw_image(Imlib_Image image, Drawable d, int x, int y, int w, int h)
imlib_render_image_on_drawable_at_size(x, y, w, h);
}
Imlib_Image get_icon_image(Window win, const XWMHints *hint, const char *name, int size, const char *theme)
Imlib_Image get_icon_image(Window win, const char *name, int size, const char *theme)
{
/* 根據加載效率依次嘗試 */
Imlib_Image image=NULL;
if( (image=get_icon_image_from_hint(hint))
|| (image=get_icon_image_from_prop(win))
|| (image=get_icon_image_from_file(name, size, theme)))
return image;
Imlib_Image image=search_icon_image(name);
return image ? image : create_icon_image(win, name, size, theme);
}
static Imlib_Image search_icon_image(const char *name)
{
for(Image_node *p=image_list; p; p=p->next)
if(strcmp(p->name, name) == 0)
return p->image;
return NULL;
}
static Imlib_Image get_icon_image_from_hint(const XWMHints *hint)
static Imlib_Image create_icon_image(Window win, const char *name, int size, const char *theme)
{
Imlib_Image image=NULL;
/* 根據加載效率依次嘗試 */
if( (image=create_icon_image_from_hint(win))
|| (image=create_icon_image_from_prop(win))
|| (image=create_icon_image_from_file(name, size, theme)))
{
reg_image(name, image);
return image;
}
return NULL;
}
static void reg_image(const char *name, Imlib_Image image)
{
Image_node *p=malloc_s(sizeof(Image_node));
p->name=copy_string(name), p->image=image, p->next=image_list, image_list=p;
}
static Imlib_Image create_icon_image_from_hint(Window win)
{
XWMHints *hint=XGetWMHints(xinfo.display, win);
if(!hint || !(hint->flags & IconPixmapHint))
return NULL;
int w, h;
Pixmap pixmap=hint->icon_pixmap, mask=hint->icon_mask;
XFree(hint);
if(!get_geometry(pixmap, NULL, NULL, &w, &h, NULL, NULL))
return NULL;
imlib_context_set_drawable(pixmap);
return imlib_create_image_from_drawable(mask, 0, 0, w, h, 0);
}
static Imlib_Image get_icon_image_from_prop(Window win)
static Imlib_Image create_icon_image_from_prop(Window win)
{
CARD32 *data=get_net_wm_icon(win);
if(!data)
@ -91,8 +130,11 @@ static Imlib_Image get_icon_image_from_prop(Window win)
return image;
}
static Imlib_Image get_icon_image_from_file(const char *name, int size, const char *theme)
static Imlib_Image create_icon_image_from_file(const char *name, int size, const char *theme)
{
if(!name || size<=0 || !theme)
return NULL;
char *fn=find_icon(name, size, 1, theme, "apps");
return fn ? imlib_load_image(fn) : NULL;
}

View File

@ -13,6 +13,6 @@
#define IMAGE_H
void draw_image(Imlib_Image image, Drawable d, int x, int y, int w, int h);
Imlib_Image get_icon_image(Window win, const XWMHints *hint, const char *name, int size, const char *theme);
Imlib_Image get_icon_image(Window win, const char *name, int size, const char *theme);
#endif

View File

@ -34,7 +34,6 @@ void init_wm(WM *wm)
xinfo.mod_map=XGetModifierMapping(xinfo.display);
xinfo.root_win=RootWindow(xinfo.display, xinfo.screen);
set_atoms();
set_gwm_widget_type(xinfo.root_win, ROOT_WIN);
XSelectInput(xinfo.display, xinfo.root_win, ROOT_EVENT_MASK);
set_visual_info();
create_refer_wins(wm);
@ -54,6 +53,8 @@ void init_wm(WM *wm)
set_ewmh(wm);
set_gwm_current_layout(DESKTOP(wm)->cur_layout);
taskbar=create_taskbar();
if(cfg->show_taskbar)
show_widget(WIDGET(taskbar));
cmd_entry=create_cmd_entry(RUN_CMD_ENTRY);
create_hint_win();
create_client_menu();
@ -66,8 +67,8 @@ static void create_refer_wins(WM *wm)
{
Window w=xinfo.root_win;
for(size_t i=0; i<TOP_WIN_TYPE_N; i++)
wm->top_wins[i]=create_widget_win(NON_WIDGET, w, -1, -1, 1, 1, 0, 0, 0);
wm->wm_check_win=create_widget_win(NON_WIDGET, w, -1, -1, 1, 1, 0, 0, 0);
wm->top_wins[i]=create_widget_win(w, -1, -1, 1, 1, 0, 0, 0);
wm->wm_check_win=create_widget_win(w, -1, -1, 1, 1, 0, 0, 0);
}
static void set_visual_info(void)
@ -99,7 +100,7 @@ static void set_ewmh(WM *wm)
set_net_desktop_geometry(xinfo.screen_width, xinfo.screen_height);
set_net_desktop_viewport(0, 0);
set_net_current_desktop(wm->cur_desktop-1);
set_net_desktop_names(&cfg->taskbar_button_text[DESKTOP_BUTTON_BEGIN], DESKTOP_N);
set_net_desktop_names(cfg->taskbar_button_text, DESKTOP_N);
set_net_workarea(wm->workarea.x, wm->workarea.y, wm->workarea.w, wm->workarea.h, DESKTOP_N);
set_net_supporting_wm_check(wm->wm_check_win, "gwm");
set_net_showing_desktop(false);

View File

@ -42,20 +42,20 @@ void update_layout(WM *wm)
case TILE: set_tile_layout(wm); break;
}
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
if(is_on_cur_desktop(c))
if(is_on_cur_desktop(c->desktop_mask))
move_resize_client(c, NULL);
}
static void fix_win_rect(WM *wm, Client *c)
{
XSizeHints hint=get_size_hint(c->win);
XSizeHints hint=get_size_hint(WIDGET_WIN(c));
fix_win_size(wm, c, &hint);
fix_win_pos(wm, c, &hint);
}
static void fix_win_size(WM *wm, Client *c, const XSizeHints *hint)
{
fix_win_size_by_hint(hint, &c->w, &c->h);
fix_win_size_by_hint(hint, &WIDGET_W(c), &WIDGET_H(c));
fix_win_size_by_workarea(wm, c);
}
@ -65,10 +65,10 @@ static void fix_win_size_by_workarea(WM *wm, Client *c)
return;
long ww=wm->workarea.w, wh=wm->workarea.h, bh=c->titlebar_h, bw=c->border_w;
if(c->w+2*bw > ww)
c->w=ww-2*bw;
if(c->h+bh+2*bw > wh)
c->h=wh-bh-2*bw;
if(WIDGET_W(c)+2*bw > ww)
WIDGET_W(c)=ww-2*bw;
if(WIDGET_H(c)+bh+2*bw > wh)
WIDGET_H(c)=wh-bh-2*bw;
}
static void fix_win_pos(WM *wm, Client *c, const XSizeHints *hint)
@ -81,7 +81,7 @@ static bool fix_win_pos_by_hint(Client *c, const XSizeHints *hint)
{
if(!c->owner && ((hint->flags & USPosition) || (hint->flags & PPosition)))
{
c->x=hint->x+c->border_w, c->y=hint->y+c->border_w+c->titlebar_h;
WIDGET_X(c)=hint->x+c->border_w, WIDGET_Y(c)=hint->y+c->border_w+c->titlebar_h;
return true;
}
return false;
@ -92,14 +92,14 @@ static void fix_win_pos_by_prop(WM *wm, Client *c)
if(c->owner)
set_transient_win_pos(c);
else if(c->win_type.dialog)
c->x=wm->workarea.x+(wm->workarea.w-c->w)/2,
c->y=wm->workarea.y+(wm->workarea.h-c->h)/2;
WIDGET_X(c)=wm->workarea.x+(wm->workarea.w-WIDGET_W(c))/2,
WIDGET_Y(c)=wm->workarea.y+(wm->workarea.h-WIDGET_H(c))/2;
}
static void set_transient_win_pos(Client *c)
{
c->x=c->owner->x+(c->owner->w-c->w)/2;
c->y=c->owner->y+(c->owner->h-c->h)/2;
WIDGET_X(c)=WIDGET_X(c->owner)+(WIDGET_W(c->owner)-WIDGET_W(c))/2;
WIDGET_Y(c)=WIDGET_Y(c->owner)+(WIDGET_H(c->owner)-WIDGET_H(c))/2;
}
static void fix_win_pos_by_workarea(WM *wm, Client *c)
@ -107,16 +107,16 @@ static void fix_win_pos_by_workarea(WM *wm, Client *c)
if(!c->win_type.normal)
return;
int w=c->w, h=c->h, bw=c->border_w, bh=c->titlebar_h, wx=wm->workarea.x,
int w=WIDGET_W(c), h=WIDGET_H(c), bw=c->border_w, bh=c->titlebar_h, wx=wm->workarea.x,
wy=wm->workarea.y, ww=wm->workarea.w, wh=wm->workarea.h;
if(c->x >= wx+ww-w-bw) // 窗口在工作區右邊出界
c->x=wx+ww-w-bw;
if(c->x < wx+bw) // 窗口在工作區左邊出界
c->x=wx+bw;
if(c->y >= wy+wh-bw-h) // 窗口在工作區下邊出界
c->y=wy+wh-bw-h;
if(c->y < wy+bw+bh) // 窗口在工作區上邊出界
c->y=wy+bw+bh;
if(WIDGET_X(c) >= wx+ww-w-bw) // 窗口在工作區右邊出界
WIDGET_X(c)=wx+ww-w-bw;
if(WIDGET_X(c) < wx+bw) // 窗口在工作區左邊出界
WIDGET_X(c)=wx+bw;
if(WIDGET_Y(c) >= wy+wh-bw-h) // 窗口在工作區下邊出界
WIDGET_Y(c)=wy+wh-bw-h;
if(WIDGET_Y(c) < wy+bw+bh) // 窗口在工作區上邊出界
WIDGET_Y(c)=wy+bw+bh;
}
static void set_preview_layout(WM *wm)
@ -143,7 +143,7 @@ static void set_rect_of_main_win_for_preview(WM *wm)
for(Client *c=wm->clients->prev; c!=wm->clients; c=c->prev)
{
if(is_on_cur_desktop(c) && !c->owner)
if(is_on_cur_desktop(c->desktop_mask) && !c->owner)
{
n--;
frame=(Rect){wx+(n%cols)*w+g, wy+(n/cols)*h+g, w-2*g, h-2*g};
@ -156,7 +156,7 @@ static void set_stack_layout(WM *wm)
{
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
{
if(is_on_cur_desktop(c) && !c->icon)
if(is_on_cur_desktop(c->desktop_mask) && !is_iconic_client(c))
{
if(is_win_state_max(c) || c->win_state.fullscreen)
fix_win_rect_by_state(wm, c);
@ -179,7 +179,7 @@ static void fix_place_type_for_tile(WM *wm)
int n=0, m=DESKTOP(wm)->n_main_max;
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
{
if(is_on_cur_desktop(c) && !c->icon && !c->owner)
if(is_on_cur_desktop(c->desktop_mask) && !is_iconic_client(c) && !c->owner)
{
if(c->place_type==TILE_LAYER_MAIN && ++n>m)
c->place_type=TILE_LAYER_SECOND;
@ -224,14 +224,14 @@ static void set_rect_of_transient_win_for_tiling(WM *wm)
{
XSizeHints hint;
for(Client *c=wm->clients->prev; c!=wm->clients; c=c->prev)
if(is_on_cur_desktop(c) && c->owner)
hint=get_size_hint(c->win), fix_win_pos(wm, c, &hint);
if(is_on_cur_desktop(c->desktop_mask) && c->owner)
hint=get_size_hint(WIDGET_WIN(c)), fix_win_pos(wm, c, &hint);
}
static void set_rect_of_float_win_for_tiling(WM *wm)
{
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
if(is_on_cur_desktop(c) && c->place_type==FLOAT_LAYER)
if(is_on_cur_desktop(c->desktop_mask) && c->place_type==FLOAT_LAYER)
fix_win_rect(wm, c);
}
@ -255,10 +255,10 @@ void update_titlebar_layout(WM *wm)
{
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
{
if(c->titlebar_h && is_on_cur_desktop(c))
if(c->titlebar_h && is_on_cur_desktop(c->desktop_mask))
{
Rect r=get_title_area_rect(c);
XResizeWindow(xinfo.display, c->title_area, r.w, r.h);
move_resize_widget(c->frame->title_area, r.x, r.y, r.w, r.h);
}
}
}
@ -299,24 +299,31 @@ void change_layout(WM *wm, XEvent *e, Func_arg arg)
if(*cl == PREVIEW)
restore_place_info_of_clients(wm->clients);
Display *d=xinfo.display;
if(*cl == PREVIEW)
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
if(is_on_cur_desktop(c) && c->icon)
XMapWindow(d, c->icon->win), XUnmapWindow(d, c->frame);
if(is_on_cur_desktop(c->desktop_mask) && is_iconic_client(c))
{
update_net_wm_state(WIDGET_WIN(c), c->win_state);
hide_widget(WIDGET(c->frame));
}
if(arg.layout == PREVIEW)
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
if(is_on_cur_desktop(c) && c->icon)
XMapWindow(d, c->frame), XUnmapWindow(d, c->icon->win);
if(is_on_cur_desktop(c->desktop_mask) && is_iconic_client(c))
{
c->win_state.hidden=0;
update_net_wm_state(WIDGET_WIN(c), c->win_state);
c->win_state.hidden=1;
show_widget(WIDGET(c->frame));
}
if(*cl==TILE && arg.layout==STACK)
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
if(is_on_cur_desktop(c) && is_normal_layer(c->place_type))
if(is_on_cur_desktop(c->desktop_mask) && is_normal_layer(c->place_type))
c->place_type=FLOAT_LAYER;
if(*cl==STACK && arg.layout==TILE)
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
if(is_on_cur_desktop(c) && c->place_type==FLOAT_LAYER)
if(is_on_cur_desktop(c->desktop_mask) && c->place_type==FLOAT_LAYER)
c->place_type=TILE_LAYER_MAIN;
*pl=*cl, *cl=arg.layout;

View File

@ -11,73 +11,82 @@
#include "gwm.h"
struct _menu_tag // 一級多行多列菜單
{
Widget base;
Button **items; // 菜單項
int n, col, row; // 菜單項數量、列數、行數
};
static bool is_null_strings(const char *strings[], int n);
Menu *act_center=NULL, *client_menu=NULL; // 操作中心, 客戶窗口菜單
Menu *create_menu(Widget_type menu_type, Widget_type item_type[], const char *item_text[], int n, int col)
Menu *create_menu(Widget_id id, Window parent, const char *icon_names[], const char *symbols[], const char *labels[], int n, int col)
{
Menu *menu=malloc_s(sizeof(Menu));
int w=0, maxw=0, sw=xinfo.screen_width, pad=get_font_pad();
for(int i=0; i<n; i++, maxw = w>maxw ? w : maxw)
get_string_size(item_text[i], &w, NULL);
w = ((maxw+2*pad)*col > sw) ? sw/col : maxw+2*pad;
int w, wi=0, wl=0, h=get_font_height_by_pad(), maxw=0, sw=xinfo.screen_width,
pad=get_font_pad(), row=(n+col-1)/col;
menu->n=n, menu->col=col, menu->row=(n+col-1)/col;
menu->x=menu->y=0, menu->w=w, menu->h=get_font_height_by_pad(), menu->pad=pad;
menu->bg=get_widget_color(MENU_COLOR);
menu->win=create_widget_win(menu_type, xinfo.root_win, 0, 0, w*col,
menu->h*menu->row, 0, 0, menu->bg);
menu->items=malloc_s(n*sizeof(Window));
if(!is_null_strings(icon_names, n) || !is_null_strings(symbols, n))
wi=h;
for(int i=0; i<n; i++, maxw = wl>maxw ? wl : maxw)
get_string_size(labels[i], &wl, NULL);
wl=maxw;
w = wi+wl+(wl ? 2*pad : 0);
if(w > sw)
w=sw/col;
init_widget(WIDGET(menu), id, UNUSED_TYPE, WIDGET_NORMAL_STATE,
parent, 0, 0, w*col, h*row);
menu->items=malloc_s(sizeof(Button *)*n);
for(int i=0; i<n; i++)
{
menu->items[i]=create_widget_win(item_type[i], menu->win, w*(i%col),
menu->h*(i/col), w, menu->h, 0, 0, menu->bg);
XSelectInput(xinfo.display, menu->items[i], BUTTON_EVENT_MASK);
menu->items[i]=create_button(id+i+1, WIDGET_NORMAL_STATE, WIDGET_WIN(menu), w*(i%col),
h*(i/col), w, h, labels[i]);
set_button_icon(menu->items[i], NULL, icon_names[i], symbols[i]);
set_button_align(menu->items[i], CENTER_LEFT);
}
XMapSubwindows(xinfo.display, menu->win);
menu->n=n, menu->col=col, menu->row=row;
return menu;
}
static bool is_null_strings(const char *strings[], int n)
{
for(int i=0; i<n; i++)
if(strings[i])
return false;
return true;
}
void show_menu(XEvent *e, Menu *menu, Window bind)
{
if(e->type == ButtonPress)
{
XButtonEvent *b=&e->xbutton;
set_pos_for_click(bind, b->x_root-b->x, &menu->x, &menu->y,
menu->w*menu->col, menu->h*menu->row);
}
XMoveWindow(xinfo.display, menu->win, menu->x, menu->y);
XMapRaised(xinfo.display, menu->win);
XMapWindow(xinfo.display, menu->win);
set_pos_for_click(bind, e->xbutton.x_root-e->xbutton.x,
&WIDGET_X(menu), &WIDGET_Y(menu), WIDGET_W(menu), WIDGET_H(menu));
move_resize_widget(WIDGET(menu), WIDGET_X(menu), WIDGET_Y(menu), WIDGET_W(menu), WIDGET_H(menu));
XRaiseWindow(xinfo.display, WIDGET_WIN(menu));
show_widget(WIDGET(menu));
}
void update_menu_bg(Menu *menu, int n)
void update_menu_bg(const Menu *menu)
{
unsigned long bg=get_widget_color(MENU_COLOR);
update_win_bg(menu->win, bg, None);
for(int i=0; i<n; i++)
update_win_bg(menu->items[i], bg, None);
}
void update_menu_item_fg(Menu *menu, int i)
{
const char *text=NULL;
if(menu == act_center)
text=cfg->act_center_item_text[i];
else if(menu == client_menu)
text=cfg->client_menu_item_text[i];
else
return;
Str_fmt fmt={0, 0, menu->w, menu->h, CENTER_LEFT, true, false, 0,
get_text_color(MENU_TEXT_COLOR)};
draw_string(menu->items[i], text, &fmt);
update_widget_bg(WIDGET(menu));
for(int i=0; i<menu->n; i++)
update_widget_bg(WIDGET(menu->items[i]));
}
void destroy_menu(Menu *menu)
{
XDestroyWindow(xinfo.display, menu->win);
vfree(menu->items, menu, NULL);
for(int i=0; i<menu->n; i++)
destroy_button(menu->items[i]);
free(menu->items);
XDestroyWindow(xinfo.display, WIDGET_WIN(menu));
free(menu);
}

View File

@ -12,20 +12,13 @@
#ifndef MENU_H
#define MENU_H
typedef struct // 一級多行多列菜單
{
Window win, *items; // 菜單窗口和菜單項
int n, col, row, w, h, pad; // 菜單項數量、列數、行數、寬度、高度、四周空白
int x, y; // 菜單窗口的坐標
unsigned long bg; // 菜單的背景色
} Menu;
typedef struct _menu_tag Menu;
extern Menu *act_center, *client_menu;
Menu *create_menu(Widget_type menu_type, Widget_type item_type[], const char *item_text[], int n, int col);
Menu *create_menu(Widget_id id, Window parent, const char *icon_names[], const char *symbols[], const char *labels[], int n, int col);
void show_menu(XEvent *e, Menu *menu, Window bind);
void update_menu_bg(Menu *menu, int n);
void update_menu_item_fg(Menu *menu, int i);
void update_menu_bg(const Menu *menu);
void destroy_menu(Menu *menu);
#endif

View File

@ -11,8 +11,6 @@
#include "gwm.h"
static void create_icon(Client *c);
static void del_icon(WM *wm, Client *c);
static void maximize_client(WM *wm, Client *c, Max_way way);
static void set_max_rect(WM *wm, Client *c, Max_way max_way);
static Client *get_icon_client_head(WM *wm);
@ -64,7 +62,7 @@ static void maximize_client(WM *wm, Client *c, Max_way max_way)
case RIGHT_MAX: c->win_state.rmax=1; break;
case FULL_MAX: c->win_state.vmax=c->win_state.hmax=1; break;
}
update_net_wm_state(c->win, c->win_state);
update_net_wm_state(WIDGET_WIN(c), c->win_state);
}
static void set_max_rect(WM *wm, Client *c, Max_way max_way)
@ -72,20 +70,20 @@ static void set_max_rect(WM *wm, Client *c, Max_way max_way)
int left_x, top_y, max_w, max_h, mid_x, mid_y, half_w, half_h;
get_max_rect(wm, c, &left_x, &top_y, &max_w, &max_h, &mid_x, &mid_y, &half_w, &half_h);
bool vmax=(c->h == max_h), hmax=(c->w == max_w), fmax=false;
bool vmax=(WIDGET_H(c) == max_h), hmax=(WIDGET_W(c) == max_w), fmax=false;
switch(max_way)
{
case VERT_MAX: if(hmax) fmax=true; else c->y=top_y, c->h=max_h; break;
case HORZ_MAX: if(vmax) fmax=true; else c->x=left_x, c->w=max_w; break;
case TOP_MAX: c->x=left_x, c->y=top_y, c->w=max_w, c->h=half_h; break;
case BOTTOM_MAX:c->x=left_x, c->y=mid_y, c->w=max_w, c->h=half_h; break;
case LEFT_MAX: c->x=left_x, c->y=top_y, c->w=half_w, c->h=max_h; break;
case RIGHT_MAX: c->x=mid_x, c->y=top_y, c->w=half_w, c->h=max_h; break;
case VERT_MAX: if(hmax) fmax=true; else WIDGET_Y(c)=top_y, WIDGET_H(c)=max_h; break;
case HORZ_MAX: if(vmax) fmax=true; else WIDGET_X(c)=left_x, WIDGET_W(c)=max_w; break;
case TOP_MAX: WIDGET_X(c)=left_x, WIDGET_Y(c)=top_y, WIDGET_W(c)=max_w, WIDGET_H(c)=half_h; break;
case BOTTOM_MAX:WIDGET_X(c)=left_x, WIDGET_Y(c)=mid_y, WIDGET_W(c)=max_w, WIDGET_H(c)=half_h; break;
case LEFT_MAX: WIDGET_X(c)=left_x, WIDGET_Y(c)=top_y, WIDGET_W(c)=half_w, WIDGET_H(c)=max_h; break;
case RIGHT_MAX: WIDGET_X(c)=mid_x, WIDGET_Y(c)=top_y, WIDGET_W(c)=half_w, WIDGET_H(c)=max_h; break;
case FULL_MAX: fmax=true; break;
default: return;
}
if(fmax)
c->x=left_x, c->y=top_y, c->w=max_w, c->h=max_h;
WIDGET_X(c)=left_x, WIDGET_Y(c)=top_y, WIDGET_W(c)=max_w, WIDGET_H(c)=max_h;
}
void get_max_rect(WM *wm, Client *c, int *left_x, int *top_y, int *max_w, int *max_h, int *mid_x, int *mid_y, int *half_w, int *half_h)
@ -114,7 +112,7 @@ void restore_client(WM *wm, Client *c)
c->win_state.rmax=0;
if(c->win_state.fullscreen)
c->win_state.fullscreen=0;
update_net_wm_state(c->win, c->win_state);
update_net_wm_state(WIDGET_WIN(c), c->win_state);
}
bool is_win_state_max(Client *c)
@ -139,7 +137,7 @@ void fix_win_rect_by_state(WM *wm, Client *c)
set_max_rect(wm, c, way);
}
else if(c->win_state.fullscreen)
c->x=c->y=0, c->w=xinfo.screen_width, c->h=xinfo.screen_height;
WIDGET_X(c)=WIDGET_Y(c)=0, WIDGET_W(c)=xinfo.screen_width, WIDGET_H(c)=xinfo.screen_height;
}
void iconify_client(WM *wm, Client *c)
@ -150,19 +148,14 @@ void iconify_client(WM *wm, Client *c)
move_client_node(wm, c, get_icon_client_head(wm), ANY_PLACE);
for(Client *ld=c->subgroup_leader, *p=ld; ld && p->subgroup_leader==ld; p=p->prev)
{
create_icon(p);
p->icon->title_text=get_icon_title_text(p->win, p->title_text);
update_win_bg(p->icon->win, get_widget_color(TASKBAR_COLOR), None);
update_icon_area(wm->clients);
XMapWindow(xinfo.display, p->icon->win);
XUnmapWindow(xinfo.display, p->frame);
if(p == DESKTOP(wm)->cur_focus_client)
p->win_state.hidden=1;
update_net_wm_state(WIDGET_WIN(p), p->win_state);
hide_widget(WIDGET(c->frame));
if(c == CUR_FOC_CLI(wm))
{
focus_client(wm, wm->cur_desktop, NULL);
update_frame_bg(wm, wm->cur_desktop, p);
update_frame_bg(wm, wm->cur_desktop, c);
}
p->win_state.hidden=1;
update_net_wm_state(p->win, p->win_state);
}
request_layout_update();
}
@ -170,21 +163,11 @@ void iconify_client(WM *wm, Client *c)
static Client *get_icon_client_head(WM *wm)
{
for(Client *c=wm->clients->next; c!=wm->clients; c=c->next)
if(is_on_cur_desktop(c) && c->icon)
if(is_on_cur_desktop(c->desktop_mask) && is_iconic_client(c))
return c->prev;
return wm->clients->prev;
}
void create_icon(Client *c)
{
Icon *i=c->icon=malloc_s(sizeof(Icon));
i->x=i->y=0, i->w=i->h=taskbar->h;
i->title_text=NULL; // 有的窗口映射時未設置圖標標題故應延後至縮微窗口時再設置title_text
i->win=create_widget_win(CLIENT_ICON, taskbar->icon_area, 0, 0, i->w, i->h,
0, 0, get_widget_color(TASKBAR_COLOR));
XSelectInput(xinfo.display, c->icon->win, ICON_WIN_EVENT_MASK);
}
void deiconify_client(WM *wm, Client *c)
{
if(!c)
@ -193,41 +176,28 @@ void deiconify_client(WM *wm, Client *c)
move_client_node(wm, c, NULL, c->place_type);
for(Client *ld=c->subgroup_leader, *p=ld; ld && p->subgroup_leader==ld; p=p->prev)
{
if(p->icon)
if(is_iconic_client(p))
{
del_icon(wm, p);
XMapWindow(xinfo.display, p->frame);
update_icon_area(wm->clients);
focus_client(wm, wm->cur_desktop, p);
p->win_state.hidden=0;
update_net_wm_state(p->win, p->win_state);
update_net_wm_state(WIDGET_WIN(p), p->win_state);
show_widget(WIDGET(c->frame));
focus_client(wm, wm->cur_desktop, c);
}
}
request_layout_update();
}
static void del_icon(WM *wm, Client *c)
{
if(c->icon)
{
XDestroyWindow(xinfo.display, c->icon->win);
vfree(c->icon->title_text, c->icon, NULL);
c->icon=NULL;
update_icon_area(wm->clients);
}
}
void iconify_all_clients(WM *wm)
{
for(Client *c=wm->clients->prev; c!=wm->clients; c=c->prev)
if(is_on_cur_desktop(c) && !c->icon)
if(is_on_cur_desktop(c->desktop_mask) && !is_iconic_client(c))
iconify_client(wm, c);
}
void deiconify_all_clients(WM *wm)
{
for(Client *c=wm->clients->prev; c!=wm->clients; c=c->prev)
if(is_on_cur_desktop(c) && c->icon)
if(is_on_cur_desktop(c->desktop_mask) && is_iconic_client(c))
deiconify_client(wm, c);
}
@ -284,7 +254,7 @@ void change_net_wm_state_for_hidden(WM *wm, Client *c, long act)
if(SHOULD_ADD_STATE(c, act, hidden))
iconify_client(wm, c);
else
deiconify_client(wm, c->icon ? c : NULL);
deiconify_client(wm, is_iconic_client(c) ? c : NULL);
}
void change_net_wm_state_for_fullscreen(WM *wm, Client *c, long act)
@ -298,7 +268,7 @@ void change_net_wm_state_for_fullscreen(WM *wm, Client *c, long act)
static void set_fullscreen(WM *wm, Client *c)
{
save_place_info_of_client(c);
c->x=c->y=0, c->w=xinfo.screen_width, c->h=xinfo.screen_height;
WIDGET_X(c)=WIDGET_Y(c)=0, WIDGET_W(c)=xinfo.screen_width, WIDGET_H(c)=xinfo.screen_height;
move_client(wm, c, NULL, FULLSCREEN_LAYER);
update_net_wm_state(c->win, c->win_state);
update_net_wm_state(WIDGET_WIN(c), c->win_state);
}

View File

@ -56,7 +56,7 @@ void clear_zombies(int signum)
char *copy_string(const char *s)
{
return strcpy(malloc_s(strlen(s)+1), s);
return s ? strcpy(malloc_s(strlen(s)+1), s) : NULL;
}
char *copy_strings(const char *s, ...) // 調用時須以NULL結尾
@ -133,3 +133,20 @@ bool is_match_button_release(XEvent *oe, XEvent *ne)
{
return (ne->type==ButtonRelease && ne->xbutton.button==oe->xbutton.button);
}
bool is_on_desktop_n(unsigned int n, unsigned int mask)
{
return (mask & get_desktop_mask(n));
}
bool is_on_cur_desktop(unsigned int mask)
{
unsigned int desktop;
return get_net_current_desktop(&desktop)
&& (mask & get_desktop_mask(desktop+1));
}
unsigned int get_desktop_mask(unsigned int desktop_n)
{
return 1<<(desktop_n-1);
}

View File

@ -12,6 +12,8 @@
#ifndef MISC_H
#define MISC_H
#include "misc.h"
typedef struct strings_tag // 字符串鏈表
{
char *str;
@ -32,5 +34,8 @@ int base_n_ceil(int x, int n);
char *get_title_text(Window win, const char *fallback);
char *get_icon_title_text(Window win, const char *fallback);
bool is_match_button_release(XEvent *oe, XEvent *ne);
bool is_on_desktop_n(unsigned int n, unsigned int mask);
bool is_on_cur_desktop(unsigned int mask);
unsigned int get_desktop_mask(unsigned int desktop_n);
#endif

View File

@ -74,7 +74,7 @@ Place_type get_dest_place_type_for_move(WM *wm, Client *c)
static Delta_rect get_key_delta_rect(Client *c, Direction dir)
{
XSizeHints hint=get_size_hint(c->win);
XSizeHints hint=get_size_hint(WIDGET_WIN(c));
int wi=hint.width_inc, hi=hint.height_inc;
Delta_rect dr[] =
@ -98,19 +98,19 @@ static Delta_rect get_key_delta_rect(Client *c, Direction dir)
void move_resize_client(Client *c, const Delta_rect *d)
{
if(d)
c->x+=d->dx, c->y+=d->dy, c->w+=d->dw, c->h+=d->dh;
WIDGET_X(c)+=d->dx, WIDGET_Y(c)+=d->dy, WIDGET_W(c)+=d->dw, WIDGET_H(c)+=d->dh;
Rect fr=get_frame_rect(c), tr=get_title_area_rect(c);
if(c->titlebar_h)
{
for(size_t i=0; i<TITLE_BUTTON_N; i++)
{
Rect br=get_button_rect(c, i);
XMoveWindow(xinfo.display, c->buttons[i], br.x, br.y);
move_resize_widget(WIDGET(c->frame->buttons[i]), br.x, br.y, br.w, br.h);
}
XResizeWindow(xinfo.display, c->title_area, tr.w, tr.h);
move_resize_widget(c->frame->title_area, tr.x, tr.y, tr.w, tr.h);
}
XMoveResizeWindow(xinfo.display, c->frame, fr.x, fr.y, fr.w, fr.h);
XMoveResizeWindow(xinfo.display, c->win, 0, c->titlebar_h, c->w, c->h);
move_resize_widget(WIDGET(c->frame), fr.x, fr.y, fr.w, fr.h);
XMoveResizeWindow(xinfo.display, WIDGET_WIN(c), 0, c->titlebar_h, WIDGET_W(c), WIDGET_H(c));
}
void pointer_move_resize_client(WM *wm, XEvent *e, bool resize)
@ -123,7 +123,7 @@ void pointer_move_resize_client(WM *wm, XEvent *e, bool resize)
if(layout==PREVIEW || !grab_pointer(xinfo.root_win, act))
return;
XSizeHints hint=get_size_hint(c->win);
XSizeHints hint=get_size_hint(WIDGET_WIN(c));
XEvent ev;
bool first=true;
@ -153,7 +153,7 @@ void pointer_move_resize_client(WM *wm, XEvent *e, bool resize)
static void do_valid_pointer_move_resize(Client *c, Move_info *m, Pointer_act act)
{
int dx=m->nx-m->ox, dy=m->ny-m->oy;
XSizeHints hint=get_size_hint(c->win);
XSizeHints hint=get_size_hint(WIDGET_WIN(c));
if(dx/get_width_inc(&hint)==0 && dy/get_height_inc(&hint)==0)
return;
@ -211,18 +211,18 @@ static bool get_move_resize_delta_rect(Client *c, Delta_rect *d, bool is_move)
static bool is_prefer_move(Client *c, Delta_rect *d)
{
return is_on_screen(c->x+d->dx, c->y+d->dy, c->w, c->h);
return is_on_screen(WIDGET_X(c)+d->dx, WIDGET_Y(c)+d->dy, WIDGET_W(c), WIDGET_H(c));
}
static bool fix_delta_rect(Client *c, Delta_rect *d)
{
int dw=d->dw, dh=d->dh;
XSizeHints hint=get_size_hint(c->win);
XSizeHints hint=get_size_hint(WIDGET_WIN(c));
fix_dw_by_width_hint(c->w, &hint, &dw);
fix_dh_by_height_hint(c->w, &hint, &dh);
fix_dw_by_width_hint(WIDGET_W(c), &hint, &dw);
fix_dh_by_height_hint(WIDGET_W(c), &hint, &dh);
if((!dw && !dh) || !is_prefer_size(c->w+dw, c->h+dh, &hint))
if((!dw && !dh) || !is_prefer_size(WIDGET_W(c)+dw, WIDGET_H(c)+dh, &hint))
return false;
d->dw=dw, d->dh=dh;
@ -262,17 +262,17 @@ static void fix_dh_by_height_hint(int h, XSizeHints *hint, int *dh)
static void update_hint_win_for_move_resize(Client *c)
{
char str[BUFSIZ];
XSizeHints hint=get_size_hint(c->win);
long col=get_win_col(c->w, &hint),
row=get_win_row(c->h, &hint);
XSizeHints hint=get_size_hint(WIDGET_WIN(c));
long col=get_win_col(WIDGET_W(c), &hint),
row=get_win_row(WIDGET_H(c), &hint);
sprintf(str, "(%d, %d) %ldx%ld", c->x, c->y, col, row);
sprintf(str, "(%d, %d) %ldx%ld", WIDGET_X(c), WIDGET_Y(c), col, row);
update_hint_win_for_info(None, str);
}
void update_win_state_for_move_resize(WM *wm, Client *c)
{
int x=c->x, y=c->y, w=c->w, h=c->h, left_x, top_y, max_w, max_h,
int x=WIDGET_X(c), y=WIDGET_Y(c), w=WIDGET_W(c), h=WIDGET_H(c), left_x, top_y, max_w, max_h,
mid_x, mid_y, half_w, half_h;
bool update=false;
Net_wm_state *s=&c->win_state;
@ -297,14 +297,14 @@ void update_win_state_for_move_resize(WM *wm, Client *c)
s->rmax=0, update=true;
if(update)
update_net_wm_state(c->win, c->win_state);
update_net_wm_state(WIDGET_WIN(c), c->win_state);
}
Pointer_act get_resize_act(Client *c, const Move_info *m)
{ // 窗口邊框寬度、標題欄調試、可調整尺寸區域的寬度、高度
// 以及窗口框架左、右橫坐標和上、下縱坐標
int bw=c->border_w, bh=c->titlebar_h, rw=c->w/4, rh=c->h/4,
lx=c->x-bw, rx=c->x+c->w+bw, ty=c->y-bh-bw, by=c->y+c->h+bw;
int bw=c->border_w, bh=c->titlebar_h, rw=WIDGET_W(c)/4, rh=WIDGET_H(c)/4,
lx=WIDGET_X(c)-bw, rx=WIDGET_X(c)+WIDGET_W(c)+bw, ty=WIDGET_Y(c)-bh-bw, by=WIDGET_Y(c)+WIDGET_H(c)+bw;
if(m->ox>=lx && m->ox<lx+bw+rw && m->oy>=ty && m->oy<ty+bw+rh)
return TOP_LEFT_RESIZE;
@ -337,8 +337,8 @@ void toggle_shade_client(WM *wm, XEvent *e, Func_arg arg)
void toggle_shade_client_mode(Client *c, bool shade)
{
if(shade && c->titlebar_h)
XResizeWindow(xinfo.display, c->frame, c->w, c->titlebar_h);
XResizeWindow(xinfo.display, WIDGET_WIN(c->frame), WIDGET_W(c), c->titlebar_h);
else if(!shade)
XResizeWindow(xinfo.display, c->frame, c->w, c->titlebar_h+c->h);
XResizeWindow(xinfo.display, WIDGET_WIN(c->frame), WIDGET_W(c), c->titlebar_h+WIDGET_H(c));
c->win_state.shaded=shade;
}

View File

@ -13,7 +13,7 @@
static const char *gwm_atom_names[GWM_ATOM_N]= // gwm自定義的標識符名稱
{
"GWM_CURRENT_LAYOUT", "GWM_UPDATE_LAYOUT", "GWM_WIDGET_TYPE",
"GWM_CURRENT_LAYOUT", "GWM_UPDATE_LAYOUT", "GWM_WIDGET_TYPE", "GWM_DESKTOP_MASK",
};
static Atom gwm_atoms[GWM_ATOM_N];
@ -38,8 +38,8 @@ Window get_transient_for(Window win)
unsigned char *get_prop(Window win, Atom prop, unsigned long *n)
{
int fmt;
unsigned long i, nitems=0, *m=(n ? n : &nitems), rest;
unsigned char *p=NULL, *result=NULL;;
unsigned long nitems=0, *m=(n ? n : &nitems), rest;
unsigned char *p=NULL;
Atom type;
/* 对于XGetWindowProperty把要接收的数据长度第5个参数设置得比实际长度
@ -49,24 +49,7 @@ unsigned char *get_prop(Window win, Atom prop, unsigned long *n)
|| !type || !fmt || !*m || !p)
return NULL;
result=malloc_s(*m*fmt/8+1);
/* 當fmt等於16時p以short int類型存儲特性當short int大於16位時
* fmt等於32時p以long類型存儲特性long
* 32 */
for(i=0; i<*m; i++)
{
switch(fmt)
{
case 8: result[i]=p[i]; break;
case 16: ((CARD16 *)result)[i]=((short int *)p)[i]; break;
case 32: ((CARD32 *)result)[i]=((long *)p)[i]; break;
default: free(result); return NULL;
}
}
result[*m*fmt/8]='\0';
XFree(p);
return result;
return p;
}
char *get_text_prop(Window win, Atom atom)
@ -97,6 +80,16 @@ bool get_cardinal_prop(Window win, Atom prop, CARD32 *result)
return true;
}
bool get_atom_prop(Window win, Atom prop, Atom *result)
{
Atom *p=(Atom *)get_prop(win, prop, NULL);
if(!p)
return false;
*result=*p;
XFree(p);
return true;
}
void replace_atom_prop(Window win, Atom prop, const Atom *values, int n)
{
XChangeProperty(xinfo.display, win, prop, XA_ATOM, 32, PropModeReplace,
@ -153,14 +146,14 @@ bool get_gwm_current_layout(int *cur_layout)
return flag;
}
void set_gwm_widget_type(Window win, long type)
void set_gwm_desktop_mask(Window win, long mask)
{
replace_cardinal_prop(win, gwm_atoms[GWM_WIDGET_TYPE], &type, 1);
replace_cardinal_prop(win, gwm_atoms[GWM_DESKTOP_MASK], &mask, 1);
}
bool get_gwm_widget_type(Window win, CARD32 *type)
bool get_gwm_desktop_mask(Window win, CARD32 *mask)
{
return get_cardinal_prop(win, gwm_atoms[GWM_WIDGET_TYPE], type);
return get_cardinal_prop(win, gwm_atoms[GWM_DESKTOP_MASK], mask);
}
void request_layout_update(void)

View File

@ -14,7 +14,7 @@
typedef enum // 與gwm自定義標識符名稱表(gwm_atom_names)相應的ID
{
GWM_CURRENT_LAYOUT, GWM_UPDATE_LAYOUT, GWM_WIDGET_TYPE, GWM_ATOM_N
GWM_CURRENT_LAYOUT, GWM_UPDATE_LAYOUT, GWM_WIDGET_TYPE, GWM_DESKTOP_MASK, GWM_ATOM_N
} GWM_atom_id;
bool is_spec_gwm_atom(Atom spec, GWM_atom_id id);
@ -23,14 +23,15 @@ Window get_transient_for(Window win);
unsigned char *get_prop(Window win, Atom prop, unsigned long *n);
char *get_text_prop(Window win, Atom atom);
bool get_cardinal_prop(Window win, Atom prop, CARD32 *result);
bool get_atom_prop(Window win, Atom prop, Atom *result);
void replace_atom_prop(Window win, Atom prop, const Atom *values, int n);
void replace_window_prop(Window win, Atom prop, const Window *wins, int n);
void replace_cardinal_prop(Window win, Atom prop, const long *values, int n);
void copy_prop(Window dest, Window src);
void set_gwm_current_layout(long cur_layout);
bool get_gwm_current_layout(int *cur_layout);
void set_gwm_widget_type(Window win, long type);
bool get_gwm_widget_type(Window win, CARD32 *type);
void set_gwm_desktop_mask(Window win, long mask);
bool get_gwm_desktop_mask(Window win, CARD32 *mask);
void request_layout_update(void);
#endif

View File

@ -11,182 +11,369 @@
#include "gwm.h"
typedef struct // 狀態欄
{
Widget base;
char *label;
} Statusbar;
typedef struct _cbutton_tag
{
Button *button;
Window cwin; // 縮微客戶窗口
struct _cbutton_tag *next;
} Cbutton;
typedef struct // 縮微窗口欄
{
Widget base;
Cbutton *cbuttons;
} Iconbar;
struct _taskbar_tag // 任務欄
{
Widget base;
int urgency_n[DESKTOP_N], attent_n[DESKTOP_N]; // 各桌面緊急、注意提示窗口數
Button *buttons[TASKBAR_BUTTON_N];
Iconbar *iconbar;
Statusbar *statusbar;
};
static void create_taskbar_buttons(void);
static bool is_chosen_taskbar_button(Widget_type type);
static void create_icon_area(void);
static void create_status_area(void);
static bool is_chosen_taskbar_button(Widget_id id);
static void create_iconbar(void);
static void create_statusbar(void);
static void create_act_center(void);
static Cbutton *create_cbutton(Window parent, int x, int y, int w, int h, Window cwin);
static void set_cbutton_icon(Cbutton *cbutton);
static void add_cbutton(Cbutton *node);
static void del_cbutton(Cbutton *node);
static void destroy_cbutton(Cbutton *cbutton);
static bool have_similar_cbutton(const Cbutton *cbutton);
static Cbutton *win_to_cbutton(Window cwin);
Taskbar *taskbar=NULL;
Taskbar *create_taskbar(void)
{
taskbar=malloc_s(sizeof(Taskbar));
memset(taskbar, 0, sizeof(Taskbar));
int w=xinfo.screen_width, h=get_font_height_by_pad(),
y=(cfg->taskbar_on_top ? 0 : xinfo.screen_height-h);
taskbar=malloc_s(sizeof(Taskbar));
init_widget(WIDGET(taskbar), TASKBAR, UNUSED_TYPE, WIDGET_NORMAL_STATE,
xinfo.root_win, 0, y, w, h);
XSelectInput(xinfo.display, WIDGET_WIN(taskbar), CROSSING_MASK);
taskbar->w=xinfo.screen_width, taskbar->h=get_font_height_by_pad();
taskbar->y=(cfg->taskbar_on_top ? 0 : xinfo.screen_height-taskbar->h);
taskbar->win=create_widget_win(TASKBAR, xinfo.root_win,
taskbar->x, taskbar->y, taskbar->w, taskbar->h, 0, 0,
get_widget_color(TASKBAR_COLOR));
XSelectInput(xinfo.display, taskbar->win, CROSSING_MASK);
create_taskbar_buttons();
create_status_area();
create_icon_area();
create_iconbar();
create_statusbar();
create_act_center();
XMapSubwindows(xinfo.display, taskbar->win);
if(cfg->show_taskbar)
XMapWindow(xinfo.display, taskbar->win);
return taskbar;
}
static void create_taskbar_buttons(void)
{
int w=cfg->taskbar_button_width, h=taskbar->h;
int w=cfg->taskbar_button_width, h=taskbar->base.h;
for(int i=0; i<TASKBAR_BUTTON_N; i++)
{
bool chosen=is_chosen_taskbar_button(TASKBAR_BUTTON_BEGIN+i);
unsigned long color=get_widget_color(chosen ? CHOSEN_BUTTON_COLOR : TASKBAR_COLOR);
taskbar->buttons[i]=create_widget_win(TASKBAR_BUTTON_BEGIN+i,
taskbar->win, w*i, 0, w, h, 0, 0, color);
XSelectInput(xinfo.display, taskbar->buttons[i], BUTTON_EVENT_MASK);
Widget_id id=TASKBAR_BUTTON_BEGIN+i;
Widget_state state={.chosen=is_chosen_taskbar_button(id)};
taskbar->buttons[i]=create_button(id, state, taskbar->base.win,
w*i, 0, w, h, cfg->taskbar_button_text[i]);
set_widget_tooltip(WIDGET(taskbar->buttons[i]), cfg->tooltip[id]);
}
}
static bool is_chosen_taskbar_button(Widget_type type)
static bool is_chosen_taskbar_button(Widget_id id)
{
unsigned int desk;
Layout lay;
unsigned int n, lay;
return ((get_net_current_desktop(&desk) && type==DESKTOP_BUTTON_BEGIN+desk)
|| (get_gwm_current_layout((int *)&lay) && type==LAYOUT_BUTTON_BEGIN+lay));
return (get_net_current_desktop(&n) && id==DESKTOP_BUTTON_BEGIN+n)
|| (get_gwm_current_layout((int *)&lay) && id==LAYOUT_BUTTON_BEGIN+lay);
}
static void create_icon_area(void)
static void create_iconbar(void)
{
int bw=cfg->taskbar_button_width*TASKBAR_BUTTON_N,
w=taskbar->w-bw-taskbar->status_area_w;
taskbar->icon_area=create_widget_win(ICON_AREA, taskbar->win,
bw, 0, w, taskbar->h, 0, 0, get_widget_color(TASKBAR_COLOR));
int bw=cfg->taskbar_button_width*TASKBAR_BUTTON_N, x=bw,
w=WIDGET_W(taskbar)-bw, h=WIDGET_H(taskbar);
taskbar->iconbar=malloc_s(sizeof(Iconbar));
init_widget(WIDGET(taskbar->iconbar), ICONBAR, UNUSED_TYPE,
WIDGET_STATE(taskbar), WIDGET_WIN(taskbar), x, 0, w, h);
taskbar->iconbar->cbuttons=NULL;
}
static void create_status_area(void)
static void create_statusbar(void)
{
taskbar->status_text=get_text_prop(xinfo.root_win, XA_WM_NAME);
if(!taskbar->status_text)
taskbar->status_text=copy_string("gwm");
get_string_size(taskbar->status_text, &taskbar->status_area_w, NULL);
if(taskbar->status_area_w > cfg->status_area_width_max)
taskbar->status_area_w=cfg->status_area_width_max;
else if(taskbar->status_area_w == 0)
taskbar->status_area_w=1;
taskbar->status_area=create_widget_win(STATUS_AREA, taskbar->win,
taskbar->w-taskbar->status_area_w, 0, taskbar->status_area_w,
taskbar->h, 0, 0, get_widget_color(TASKBAR_COLOR));
XSelectInput(xinfo.display, taskbar->status_area, ExposureMask);
int w=0;
char *p=get_text_prop(xinfo.root_win, XA_WM_NAME);
taskbar->statusbar=malloc_s(sizeof(Statusbar));
if(!p)
p=copy_string("gwm");
get_string_size(p, &w, NULL);
if(w > cfg->status_area_width_max)
w=cfg->status_area_width_max;
else if(w == 0)
w=1;
init_widget(WIDGET(taskbar->statusbar), STATUSBAR, UNUSED_TYPE,
WIDGET_STATE(taskbar), WIDGET_WIN(taskbar), WIDGET_W(taskbar)-w,
0, w, WIDGET_H(taskbar));
XSelectInput(xinfo.display, WIDGET_WIN(taskbar->statusbar), ExposureMask);
taskbar->statusbar->label=copy_string(p);
}
static void create_act_center(void)
{
Widget_type types[ACT_CENTER_ITEM_N];
for(int i=0; i<ACT_CENTER_ITEM_N; i++)
types[i]=ACT_CENTER_ITEM_BEGIN+i;
act_center=create_menu(ACT_CENTER, types, cfg->act_center_item_text,
ACT_CENTER_ITEM_N, cfg->act_center_col);
act_center=create_menu(ACT_CENTER, xinfo.root_win,
cfg->act_center_item_icon, cfg->act_center_item_symbol,
cfg->act_center_item_label, ACT_CENTER_ITEM_N, cfg->act_center_col);
}
void taskbar_add_cbutton(Window cwin)
{
int h=WIDGET_H(taskbar->iconbar), w=h;
Cbutton *c=create_cbutton(WIDGET_WIN(taskbar->iconbar), 0, 0, w, h, cwin);
add_cbutton(c);
update_iconbar();
show_button(c->button);
}
static Cbutton *create_cbutton(Window parent, int x, int y, int w, int h, Window cwin)
{
Cbutton *cbutton=malloc_s(sizeof(Cbutton));
char *icon_title=get_icon_title_text(cwin, "");
cbutton->button=create_button(CLIENT_ICON, WIDGET_NORMAL_STATE,
parent, x, y, w, h, icon_title);
set_button_align(cbutton->button, CENTER_LEFT);
cbutton->cwin=cwin;
cbutton->next=NULL;
set_cbutton_icon(cbutton);
set_widget_tooltip(WIDGET(cbutton), icon_title);
free(icon_title);
return cbutton;
}
static void set_cbutton_icon(Cbutton *cbutton)
{
XClassHint class_hint={NULL, NULL};
XGetClassHint(xinfo.display, cbutton->cwin, &class_hint);
Imlib_Image image=get_icon_image(cbutton->cwin, class_hint.res_name,
cfg->icon_image_size, cfg->cur_icon_theme);
set_button_icon(cbutton->button, image, class_hint.res_name, NULL);
XFree(class_hint.res_name), XFree(class_hint.res_class);
}
static void add_cbutton(Cbutton *node)
{
node->next=taskbar->iconbar->cbuttons;
taskbar->iconbar->cbuttons=node;
}
void taskbar_del_cbutton(Window cwin)
{
for(Cbutton *c=taskbar->iconbar->cbuttons; c; c=c->next)
{
if(c->cwin == cwin)
{
del_cbutton(c);
destroy_cbutton(c);
update_iconbar();
break;
}
}
}
static void del_cbutton(Cbutton *node)
{
for(Cbutton *prev=NULL, *p=taskbar->iconbar->cbuttons; p; prev=p, p=p->next)
{
if(p == node)
{
if(prev == NULL)
taskbar->iconbar->cbuttons=p->next;
else
prev->next=p->next;
break;
}
}
}
static void destroy_cbutton(Cbutton *cbutton)
{
destroy_button(cbutton->button);
free(cbutton);
}
Window get_iconic_win(Window button_win)
{
for(unsigned int i=0; i<DESKTOP_N; i++)
for(Cbutton *c=taskbar->iconbar->cbuttons; c; c=c->next)
if(WIDGET_WIN(c->button) == button_win)
return c->cwin;
return None;
}
void update_iconbar(void)
{
int x=0, w=0, h=WIDGET_H(taskbar->iconbar), wi=h, wl=0;
for(Cbutton *c=taskbar->iconbar->cbuttons; c; c=c->next)
{
Button *b=c->button;
if(have_similar_cbutton(c))
{
puts(get_button_label(b));
get_string_size(get_button_label(b), &wl, NULL);
w=MIN(wi+wl, cfg->icon_win_width_max);
}
else
w=WIDGET_W(b);
move_resize_widget(WIDGET(b), x, WIDGET_Y(b), w, WIDGET_H(b));
x+=w+cfg->icon_gap;
}
}
static bool have_similar_cbutton(const Cbutton *cbutton)
{
XClassHint ch={NULL, NULL}, ph;
if(!XGetClassHint(xinfo.display, cbutton->cwin, &ch))
return false;
bool same=false;
for(Cbutton *p=taskbar->iconbar->cbuttons; !same && p; p=p->next)
{
if(p!=cbutton && XGetClassHint(xinfo.display, p->cwin, &ph))
{
same = (strcmp(ph.res_class, ch.res_class) == 0
&& strcmp(ph.res_name, ch.res_name) == 0);
XFree(ph.res_class), XFree(ph.res_name);
}
}
XFree(ch.res_class), XFree(ch.res_name);
return same;
}
void update_iconbar_by_state(Window cwin)
{
Net_wm_state state=get_net_wm_state(cwin);
Cbutton *cbutton=win_to_cbutton(cwin);
if(cbutton)
{
if(!state.hidden)
taskbar_del_cbutton(cwin);
if(state.focused)
WIDGET_STATE(WIDGET(cbutton->button)).focus=1,
update_widget_bg(WIDGET(cbutton->button));
}
else if(state.hidden)
taskbar_add_cbutton(cwin);
}
static Cbutton *win_to_cbutton(Window cwin)
{
for(Cbutton *p=taskbar->iconbar->cbuttons; p; p=p->next)
if(p->cwin == cwin)
return p;
return NULL;
}
void update_taskbar_buttons_bg(void)
{
for(Widget_type t=TASKBAR_BUTTON_BEGIN; t<=TASKBAR_BUTTON_END; t++)
update_taskbar_button_bg(t);
for(int i=0; i<TASKBAR_BUTTON_N; i++)
update_widget_bg(WIDGET(taskbar->buttons[i]));
}
void update_taskbar_button_bg(Widget_type type)
void update_statusbar_fg(void)
{
Window win=taskbar->buttons[WIDGET_INDEX(type, TASKBAR_BUTTON)];
bool chosen=is_chosen_taskbar_button(type);
unsigned long color=get_widget_color(chosen ? CHOSEN_BUTTON_COLOR : TASKBAR_COLOR);
if(IS_WIDGET_CLASS(type, DESKTOP_BUTTON))
Statusbar *b=taskbar->statusbar;
XftColor fg=get_widget_fg(TASKBAR_TEXT_COLOR);
if(b->label)
{
unsigned int cur, desktop_n=WIDGET_INDEX(type, DESKTOP_BUTTON)+1;
if(get_net_current_desktop(&cur) && desktop_n!=cur)
{
if(taskbar->urgency_n[desktop_n-1])
color=get_widget_color(URGENCY_WIDGET_COLOR);
else if(taskbar->attent_n[desktop_n-1])
color=get_widget_color(ATTENTION_WIDGET_COLOR);
}
Str_fmt fmt={0, 0, WIDGET_W(b), WIDGET_H(b), CENTER, true, false, 0, fg};
draw_string(WIDGET_WIN(b), b->label, &fmt);
}
update_win_bg(win, color, None);
}
void update_taskbar_button_fg(Widget_type type)
void set_statusbar_label(const char *label)
{
size_t i=WIDGET_INDEX(type, TASKBAR_BUTTON);
Str_fmt fmt={0, 0, cfg->taskbar_button_width, taskbar->h, CENTER,
false, false, 0, get_text_color(TASKBAR_TEXT_COLOR)};
draw_string(taskbar->buttons[i], cfg->taskbar_button_text[i], &fmt);
}
int w=0, h=WIDGET_H(taskbar->statusbar);
void update_status_area_fg(void)
{
Str_fmt fmt={0, 0, taskbar->status_area_w, taskbar->h, CENTER_RIGHT,
false, false, 0, get_text_color(TASKBAR_TEXT_COLOR)};
draw_string(taskbar->status_area, taskbar->status_text, &fmt);
}
void update_icon_status_area(void)
{
int w, bw=cfg->taskbar_button_width*TASKBAR_BUTTON_N;
get_string_size(taskbar->status_text, &w, NULL);
free(taskbar->statusbar->label);
taskbar->statusbar->label=copy_string(label);
get_string_size(label, &w, NULL);
if(w > cfg->status_area_width_max)
w=cfg->status_area_width_max;
if(w != taskbar->status_area_w)
{
XMoveResizeWindow(xinfo.display, taskbar->status_area,
taskbar->w-w, 0, w, taskbar->h);
XMoveResizeWindow(xinfo.display, taskbar->icon_area,
bw, 0, taskbar->w-bw-w, taskbar->h);
}
taskbar->status_area_w=w;
update_status_area_fg();
}
void update_client_icon_fg(WM *wm, Window win)
{
Client *c=win_to_iconic_state_client(wm->clients, win);
if(!c)
return;
Icon *i=c->icon;
draw_icon(c->icon->win, c->image, c->class_name, taskbar->h);
if(i->show_text)
{
Str_fmt fmt={taskbar->h, 0, i->w-taskbar->h, i->h, CENTER,
false, false, 0, get_text_color(TASKBAR_TEXT_COLOR)};
draw_string(i->win, i->title_text, &fmt);
}
if(w != taskbar->statusbar->base.w)
move_resize_widget(WIDGET(taskbar->statusbar), taskbar->base.w-w, 0, w, h);
update_statusbar_fg();
}
void update_taskbar_bg(void)
{
unsigned long bg=get_widget_color(TASKBAR_COLOR);
update_taskbar_buttons_bg();
update_win_bg(taskbar->icon_area, bg, None);
update_widget_bg(WIDGET(taskbar->iconbar));
/* Xlib手冊說窗口收到Expose事件時會更新背景但事實上不知道爲何上邊的語句
* icon_area發送了Expose事件
* iconbar->win發送了Expose事件
* Expose事件並不會更新背景調 */
XClearWindow(xinfo.display, taskbar->icon_area);
update_win_bg(taskbar->status_area, bg, None);
XClearWindow(xinfo.display, taskbar->iconbar->base.win);
update_widget_bg(WIDGET(taskbar->statusbar));
}
void destroy_taskbar(Taskbar *taskbar)
{
XDestroyWindow(xinfo.display, taskbar->win);
vfree(taskbar->status_text, taskbar, NULL);
for(int i=0; i<TASKBAR_BUTTON_N; i++)
destroy_button(taskbar->buttons[i]);
destroy_widget(WIDGET(taskbar->iconbar));
free(taskbar->statusbar->label);
destroy_widget(WIDGET(taskbar->statusbar));
destroy_widget(WIDGET(taskbar));
}
void set_taskbar_urgency(unsigned int desktop_mask, bool urg)
{
unsigned int cur_desktop;
if(get_net_current_desktop(&cur_desktop))
return;
int incr = (urg ? 1 : -1);
for(unsigned int i=0; i<DESKTOP_N; i++)
if( (desktop_mask & get_desktop_mask(i+1) && i!=cur_desktop)
&& taskbar->urgency_n[i]+incr >= 0)
taskbar->urgency_n[i] += incr;
update_taskbar_buttons_bg();
}
void set_taskbar_attention(unsigned int desktop_mask, bool attent)
{
unsigned int cur_desktop;
if(get_net_current_desktop(&cur_desktop))
return;
int incr = attent ? 1 : -1;
for(unsigned int i=0; i<DESKTOP_N; i++)
if((desktop_mask & get_desktop_mask(i+1) && i!=cur_desktop)
&& taskbar->attent_n[i]+incr >= 0)
taskbar->attent_n[i] += incr;
update_taskbar_buttons_bg();
}
void update_taskbar_buttons_bg_by_chosen(void)
{
for(int i=0; i<TASKBAR_BUTTON_N; i++)
WIDGET_STATE(taskbar->buttons[i]).chosen=
is_chosen_taskbar_button(TASKBAR_BUTTON_BEGIN+i);
update_taskbar_buttons_bg();
}

View File

@ -12,27 +12,23 @@
#ifndef TASKBAR_H
#define TASKBAR_H
typedef struct // 窗口管理器的任務欄
{
/* 分別爲任務欄的窗口、按鈕、縮微區域、狀態區域 */
Window win, buttons[TASKBAR_BUTTON_N], icon_area, status_area;
// 分別爲存儲各桌面的發出緊急、注意提示的窗口數量的數組
int urgency_n[DESKTOP_N], attent_n[DESKTOP_N];
int x, y; // win的坐標
int w, h, status_area_w; // win的尺寸、按鈕的尺寸和狀態區域的寬度
char *status_text; // 狀態區域要顯示的文字
} Taskbar;
typedef struct _taskbar_tag Taskbar; // 任務欄
extern Taskbar *taskbar;
Taskbar *create_taskbar(void);
void taskbar_add_cbutton(Window cwin);
void taskbar_del_cbutton(Window cwin);
Window get_iconic_win(Window button_win);
void update_iconbar(void);
void update_iconbar_by_state(Window cwin);
void update_taskbar_buttons_bg(void);
void update_taskbar_button_bg(Widget_type type);
void update_taskbar_button_fg(Widget_type type);
void update_status_area_fg(void);
void update_icon_status_area(void);
void update_client_icon_fg(WM *wm, Window win);
void update_statusbar_fg(void);
void set_statusbar_label(const char *label);
void update_taskbar_bg(void);
void destroy_taskbar(Taskbar *taskbar);
void set_taskbar_urgency(unsigned int desktop_mask, bool urg);
void set_taskbar_attention(unsigned int desktop_mask, bool attent);
void update_taskbar_buttons_bg_by_chosen(void);
#endif

View File

@ -11,6 +11,15 @@
#include "gwm.h"
typedef struct widget_node_tag
{
Widget *widget;
struct widget_node_tag *next;
} Widget_node;
static void reg_widget(Widget *widget);
static void unreg_widget(Widget *widget);
static Widget_color_id get_widget_color_id(const Widget *widget);
static void alloc_widget_color(const char *color_name, XColor *color);
static void alloc_text_color(const char *color_name, XftColor *color);
static unsigned int get_num_lock_mask(void);
@ -20,6 +29,141 @@ static XColor widget_color[COLOR_THEME_N][WIDGET_COLOR_N]; // 構件顏色
static XftColor text_color[COLOR_THEME_N][TEXT_COLOR_N]; // 文本顏色
static Cursor cursors[POINTER_ACT_N]; // 光標
static Widget_node *widget_list=NULL;
static void reg_widget(Widget *widget)
{
Widget_node *p=malloc_s(sizeof(Widget_node));
p->widget=widget;
p->next=widget_list;
widget_list=p;
}
static void unreg_widget(Widget *widget)
{
for(Widget_node *prev=NULL, *p=widget_list; p; prev=p, p=p->next)
{
if(p->widget == widget)
{
if(prev == NULL)
widget_list=p->next;
else
prev->next=p->next;
free(p);
break;
}
}
}
Widget *win_to_widget(Window win)
{
for(Widget_node *p=widget_list; p; p=p->next)
if(p->widget->win == win)
return p->widget;
return NULL;
}
Widget *create_widget(Widget_id id, Widget_type type, Widget_state state, Window parent, int x, int y, int w, int h)
{
Widget *widget=malloc_s(sizeof(Widget));
init_widget(widget, id, type, state, parent, x, y, w, h);
return widget;
}
void init_widget(Widget *widget, Widget_id id, Widget_type type, Widget_state state, Window parent, int x, int y, int w, int h)
{
unsigned long bg;
widget->id=id;
widget->type=type;
widget->state=state;
widget->parent=parent;
bg=get_widget_color(get_widget_color_id(widget));
if(widget->id != CLIENT_WIN)
widget->win=create_widget_win(parent, x, y, w, h, 0, 0, bg);
widget->x=x, widget->y=y, widget->w=w, widget->h=h;
widget->tooltip=NULL;
XSelectInput(xinfo.display, widget->win, WIDGET_EVENT_MASK);
reg_widget(widget);
}
void set_widget_tooltip(Widget *widget, const char *tooltip)
{
widget->tooltip=copy_string(tooltip);
}
void set_widget_border_width(const Widget *widget, int width)
{
XSetWindowBorderWidth(xinfo.display, widget->win, width);
}
void set_widget_border_color(const Widget *widget, unsigned long pixel)
{
XSetWindowBorder(xinfo.display, widget->win, pixel);
}
void destroy_widget(Widget *widget)
{
unreg_widget(widget);
XDestroyWindow(xinfo.display, widget->win);
vfree(widget->tooltip, widget, NULL);
}
void show_widget(const Widget *widget)
{
XMapWindow(xinfo.display, widget->win);
XMapSubwindows(xinfo.display, widget->win);
}
void hide_widget(const Widget *widget)
{
XUnmapWindow(xinfo.display, widget->win);
}
void move_resize_widget(Widget *widget, int x, int y, int w, int h)
{
widget->x=x, widget->y=y, widget->w=w, widget->h=h;;
XMoveResizeWindow(xinfo.display, widget->win, x, y, w, h);
}
void update_widget_bg(const Widget *widget)
{
update_win_bg(widget->win, get_widget_color(get_widget_color_id(widget)), None);
}
static Widget_color_id get_widget_color_id(const Widget *widget)
{
if(widget->state.disable) return DISABLE_WIDGET_COLOR;
if(widget->state.warn) return WARN_WIDGET_COLOR;
if(widget->state.active) return ACTIVE_WIDGET_COLOR;
if(widget->state.hot) return HOT_WIDGET_COLOR;
if(widget->state.urgent) return URGENT_WIDGET_COLOR;
if(widget->state.attent) return ATTENT_WIDGET_COLOR;
if(widget->state.chosen) return CHOSEN_WIDGET_COLOR;
if(widget->state.focus) return FOCUS_WIDGET_COLOR;
return NORMAL_WIDGET_COLOR;
}
Widget_color_id get_widget_border_color_id(const Widget *widget)
{
return widget->state.focus ? CURRENT_BORDER_COLOR : NORMAL_BORDER_COLOR;
}
Text_color_id get_widget_fg_id(const Widget *widget)
{
if(widget->state.disable) return DISABLE_WIDGET_TEXT_COLOR;
if(widget->state.warn) return WARN_WIDGET_TEXT_COLOR;
if(widget->state.active) return ACTIVE_WIDGET_TEXT_COLOR;
if(widget->state.hot) return HOT_WIDGET_TEXT_COLOR;
if(widget->state.urgent) return URGENT_WIDGET_TEXT_COLOR;
if(widget->state.attent) return ATTENT_WIDGET_TEXT_COLOR;
if(widget->state.chosen) return CHOSEN_WIDGET_TEXT_COLOR;
if(widget->state.focus) return FOCUS_WIDGET_TEXT_COLOR;
return NORMAL_WIDGET_TEXT_COLOR;
}
static void alloc_widget_color(const char *color_name, XColor *color)
{
XParseColor(xinfo.display, xinfo.colormap, color_name, color);
@ -34,27 +178,27 @@ static void alloc_text_color(const char *color_name, XftColor *color)
void alloc_color(void)
{
for(Color_theme i=0; i<COLOR_THEME_N; i++)
for(Widget_color j=0; j<WIDGET_COLOR_N; j++)
for(Widget_color_id j=0; j<WIDGET_COLOR_N; j++)
alloc_widget_color(cfg->widget_color_name[i][j], &widget_color[i][j]);
for(Color_theme i=0; i<COLOR_THEME_N; i++)
for(Text_color j=0; j<TEXT_COLOR_N; j++)
for(Text_color_id j=0; j<TEXT_COLOR_N; j++)
alloc_text_color(cfg->text_color_name[i][j], &text_color[i][j]);
}
unsigned long get_widget_color(Widget_color wc)
unsigned long get_widget_color(Widget_color_id id)
{
float wo=cfg->widget_opacity[cfg->color_theme][wc];
unsigned long rgb=widget_color[cfg->color_theme][wc].pixel;
float wo=cfg->widget_opacity[cfg->color_theme][id];
unsigned long rgb=widget_color[cfg->color_theme][id].pixel;
return ((rgb & 0x00ffffff) | ((unsigned long)(0xff*wo))<<24);
}
XftColor get_text_color(Text_color color_id)
XftColor get_widget_fg(Text_color_id id)
{
return text_color[cfg->color_theme][color_id];
return text_color[cfg->color_theme][id];
}
Window create_widget_win(Widget_type type, Window parent, int x, int y, int w, int h, int border_w, unsigned long border_pixel, unsigned long bg_pixel)
Window create_widget_win(Window parent, int x, int y, int w, int h, int border_w, unsigned long border_pixel, unsigned long bg_pixel)
{
XSetWindowAttributes attr;
attr.colormap=xinfo.colormap;
@ -66,54 +210,32 @@ Window create_widget_win(Widget_type type, Window parent, int x, int y, int w, i
InputOutput, xinfo.visual,
CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect, &attr);
set_gwm_widget_type(win, type);
return win;
}
Widget_type get_widget_type(Window win)
{
CARD32 type;
return get_gwm_widget_type(win, &type) ? type : NON_WIDGET;
}
void update_hint_win_for_info(Window hover, const char *info)
void update_hint_win_for_info(const Widget *widget, const char *info)
{
int x, y, rx, ry, pad=get_font_pad(),
w=0, h=get_font_height_by_pad();
get_string_size(info, &w, NULL);
w+=pad*2;
if(hover)
if(widget)
{
Window r, c;
unsigned int m;
if(!XQueryPointer(xinfo.display, hover, &r, &c, &rx, &ry, &x, &y, &m))
if(!XQueryPointer(xinfo.display, widget->win, &r, &c, &rx, &ry, &x, &y, &m))
return;
set_pos_for_click(hover, rx, &x, &y, w, h);
set_pos_for_click(widget->win, rx, &x, &y, w, h);
}
else
x=(xinfo.screen_width-w)/2, y=(xinfo.screen_height-h)/2;
XMoveResizeWindow(xinfo.display, xinfo.hint_win, x, y, w, h);
XMapRaised(xinfo.display, xinfo.hint_win);
Str_fmt f={0, 0, w, h, CENTER, true, false, 0,
get_text_color(HINT_TEXT_COLOR)};
Str_fmt f={0, 0, w, h, CENTER, true, false, 0, get_widget_fg(HINT_TEXT_COLOR)};
draw_string(xinfo.hint_win, info, &f);
}
void draw_icon(Drawable d, Imlib_Image image, const char *name, int size)
{
if(image)
draw_image(image, d, 0, 0, size, size);
else
{
char s[2]={name[0], '\0'};
XftColor color=get_text_color(CLASS_TEXT_COLOR);
Str_fmt fmt={0, 0, size, size, CENTER, false, false, 0, color};
draw_string(d, s, &fmt);
}
}
void set_xic(Window win, XIC *ic)
{
if(xinfo.xim == NULL)
@ -141,18 +263,16 @@ KeySym look_up_key(XIC xic, XKeyEvent *e, wchar_t *keyname, size_t n)
void create_hint_win(void)
{
xinfo.hint_win=create_widget_win(HINT_WIN, xinfo.root_win, 0, 0, 1, 1, 0, 0,
xinfo.hint_win=create_widget_win(xinfo.root_win, 0, 0, 1, 1, 0, 0,
get_widget_color(HINT_WIN_COLOR));
XSelectInput(xinfo.display, xinfo.hint_win, ExposureMask);
}
void create_client_menu(void)
{
Widget_type types[CLIENT_MENU_ITEM_N];
for(int i=0; i<CLIENT_MENU_ITEM_N; i++)
types[i]=CLIENT_MENU_ITEM_BEGIN+i;
client_menu=create_menu(CLIENT_MENU, types, cfg->client_menu_item_text,
CLIENT_MENU_ITEM_N, 1);
client_menu=create_menu(CLIENT_MENU, xinfo.root_win,
cfg->client_menu_item_icon, cfg->client_menu_item_symbol,
cfg->client_menu_item_label, CLIENT_MENU_ITEM_N, 1);
}
void create_cursors(void)
@ -206,7 +326,7 @@ void grab_buttons(Window win)
XUngrabButton(xinfo.display, AnyButton, AnyModifier, win);
for(const Buttonbind *b=cfg->buttonbind; b->func; b++)
{
if(b->widget_type == CLIENT_WIN)
if(b->widget_id == CLIENT_WIN)
{
int m=is_equal_modifier_mask(0, b->modifier) ?
GrabModeSync : GrabModeAsync;

View File

@ -9,26 +9,48 @@
* <http://www.gnu.org/licenses/>。
* ************************************************************************/
#ifndef WIDGET_H
#define WIDGET_H
#ifndef __WIDGET_H
#define __WIDGET_H
typedef enum // 構件顏色類型
#include "gwm.h"
typedef enum // 構件顏色標識
{
NORMAL_BORDER_COLOR, CURRENT_BORDER_COLOR, NORMAL_TITLEBAR_COLOR,
CURRENT_TITLEBAR_COLOR, ENTERED_NORMAL_BUTTON_COLOR,
ENTERED_CLOSE_BUTTON_COLOR, CHOSEN_BUTTON_COLOR, MENU_COLOR, TASKBAR_COLOR,
ENTRY_COLOR, HINT_WIN_COLOR, URGENCY_WIDGET_COLOR, ATTENTION_WIDGET_COLOR,
ROOT_WIN_COLOR, WIDGET_COLOR_N
} Widget_color;
CURRENT_TITLEBAR_COLOR, DISABLE_WIDGET_COLOR, WARN_WIDGET_COLOR,
ACTIVE_WIDGET_COLOR, HOT_WIDGET_COLOR, URGENT_WIDGET_COLOR,
ATTENT_WIDGET_COLOR, CHOSEN_WIDGET_COLOR, FOCUS_WIDGET_COLOR,
NORMAL_WIDGET_COLOR, MENU_COLOR,
TASKBAR_COLOR, ENTRY_COLOR, HINT_WIN_COLOR, ROOT_WIN_COLOR,
typedef enum // 文本顏色類型
// NORMAL_BORDER_COLOR, CURRENT_BORDER_COLOR, NORMAL_TITLEBAR_COLOR,
// CURRENT_TITLEBAR_COLOR,
ENTERED_NORMAL_BUTTON_COLOR,
ENTERED_CLOSE_BUTTON_COLOR,
CHOSEN_BUTTON_COLOR, //MENU_COLOR, TASKBAR_COLOR,
//ENTRY_COLOR, HINT_WIN_COLOR,
URGENCY_WIDGET_COLOR, ATTENTION_WIDGET_COLOR,
//ROOT_WIN_COLOR,
WIDGET_COLOR_N
} Widget_color_id;
typedef enum // 文本顏色標識
{
NORMAL_TITLEBAR_TEXT_COLOR, CURRENT_TITLEBAR_TEXT_COLOR,
TASKBAR_TEXT_COLOR, CLASS_TEXT_COLOR, MENU_TEXT_COLOR,
ENTRY_TEXT_COLOR, HINT_TEXT_COLOR, TEXT_COLOR_N
} Text_color;
DISABLE_WIDGET_TEXT_COLOR, WARN_WIDGET_TEXT_COLOR,
ACTIVE_WIDGET_TEXT_COLOR, HOT_WIDGET_TEXT_COLOR,
URGENT_WIDGET_TEXT_COLOR, ATTENT_WIDGET_TEXT_COLOR,
CHOSEN_WIDGET_TEXT_COLOR, FOCUS_WIDGET_TEXT_COLOR,
NORMAL_WIDGET_TEXT_COLOR, NORMAL_TITLEBAR_TEXT_COLOR,
CURRENT_TITLEBAR_TEXT_COLOR, TASKBAR_TEXT_COLOR, CLASS_TEXT_COLOR,
MENU_TEXT_COLOR, ENTRY_TEXT_COLOR, HINT_TEXT_COLOR,
typedef enum // 構件類型
//NORMAL_TITLEBAR_TEXT_COLOR, CURRENT_TITLEBAR_TEXT_COLOR,
//TASKBAR_TEXT_COLOR, CLASS_TEXT_COLOR, MENU_TEXT_COLOR,
//ENTRY_TEXT_COLOR, HINT_TEXT_COLOR,
TEXT_COLOR_N
} Text_color_id;
typedef enum // 構件標識
{
ROOT_WIN, HINT_WIN, RUN_CMD_ENTRY,
@ -41,7 +63,7 @@ typedef enum // 構件類型
SHADE_BUTTON, VERT_MAX_BUTTON, HORZ_MAX_BUTTON, TOP_MAX_BUTTON,
BOTTOM_MAX_BUTTON, LEFT_MAX_BUTTON, RIGHT_MAX_BUTTON, FULL_MAX_BUTTON,
TASKBAR, ICON_AREA, CLIENT_ICON, STATUS_AREA,
TASKBAR, ICONBAR, CLIENT_ICON, STATUSBAR,
DESKTOP1_BUTTON, DESKTOP2_BUTTON, DESKTOP3_BUTTON,
PREVIEW_BUTTON, STACK_BUTTON, TILE_BUTTON, DESKTOP_BUTTON,
ACT_CENTER_ITEM,
@ -65,8 +87,13 @@ typedef enum // 構件類型
DESKTOP_BUTTON_BEGIN=DESKTOP1_BUTTON, DESKTOP_BUTTON_END=DESKTOP3_BUTTON,
ACT_CENTER_ITEM_BEGIN=HELP_BUTTON, ACT_CENTER_ITEM_END=RUN_BUTTON,
CLIENT_MENU_ITEM_BEGIN=SHADE_BUTTON, CLIENT_MENU_ITEM_END=FULL_MAX_BUTTON,
} Widget_type;
} Widget_id;
typedef enum // 構件類型
{
BUTTON_TYPE, ENTRY_TYPE, UNUSED_TYPE
} Widget_type;
typedef enum // 定位器操作類型
{
NO_OP, CHOOSE, MOVE, SWAP, CHANGE, TOP_RESIZE, BOTTOM_RESIZE, LEFT_RESIZE,
@ -74,34 +101,71 @@ typedef enum // 定位器操作類型
BOTTOM_RIGHT_RESIZE, ADJUST_LAYOUT_RATIO, POINTER_ACT_N
} Pointer_act;
typedef struct // 構件狀態
{
unsigned int disable : 1; // 禁用狀態,即此時按鈕不可用
unsigned int warn : 1; // 警告狀態,即鼠標懸浮於重要按鈕之上
unsigned int active : 1; // 激活狀態,即鼠標按下
unsigned int hot : 1; // 可用狀態,即鼠標懸浮於按鈕之上
unsigned int urgent : 1; // 緊急狀態,即有緊急消息
unsigned int attent : 1; // 關注狀態,即有需要關注的消息
unsigned int chosen : 1; // 選中狀態,即選中了此構件所表示的功能
unsigned int focus : 1; // 聚焦狀態,即構件具有鍵盤輸入的焦點
} Widget_state;
#define WIDGET_NORMAL_STATE ((Widget_state){0})
typedef struct
{
Widget_id id;
Widget_type type;
Widget_state state;
int x, y, w, h;
Window parent, win;
char *tooltip;
} Widget;
#define WIDGET_EVENT_MASK (ButtonPressMask|ExposureMask|CROSSING_MASK)
#define TITLE_BUTTON_N (TITLE_BUTTON_END-TITLE_BUTTON_BEGIN+1)
#define TASKBAR_BUTTON_N (TASKBAR_BUTTON_END-TASKBAR_BUTTON_BEGIN+1)
#define ACT_CENTER_ITEM_N (ACT_CENTER_ITEM_END-ACT_CENTER_ITEM_BEGIN+1)
#define CLIENT_MENU_ITEM_N (CLIENT_MENU_ITEM_END-CLIENT_MENU_ITEM_BEGIN+1)
#define DESKTOP_N (DESKTOP_BUTTON_END-DESKTOP_BUTTON_BEGIN+1)
#define WIDGET(p) ((Widget *)(p))
#define WIDGET_ID(p) (WIDGET(p)->id)
#define WIDGET_TYPE(p) (WIDGET(p)->type)
#define WIDGET_STATE(p) (WIDGET(p)->state)
#define WIDGET_X(p) (WIDGET(p)->x)
#define WIDGET_Y(p) (WIDGET(p)->y)
#define WIDGET_W(p) (WIDGET(p)->w)
#define WIDGET_H(p) (WIDGET(p)->h)
#define WIDGET_WIN(p) (WIDGET(p)->win)
#define WIDGET_TOOLTIP(p) (WIDGET(p)->tooltip)
#define WIDGET_INDEX(type_name, type_class) ((type_name) - type_class ## _BEGIN)
#define DESKTOP_BUTTON_N(n) (DESKTOP_BUTTON_BEGIN+n-1)
#define IS_WIDGET_CLASS(type_name, type_class) \
(type_class ## _BEGIN <= (type_name) && (type_name) <= type_class ## _END)
#define IS_BUTTON(type) \
( type==CLIENT_ICON || type==TITLE_LOGO \
|| IS_WIDGET_CLASS(type, TITLE_BUTTON) \
|| IS_WIDGET_CLASS(type, CLIENT_MENU_ITEM) \
|| IS_WIDGET_CLASS(type, TASKBAR_BUTTON) \
|| IS_WIDGET_CLASS(type, ACT_CENTER_ITEM))
#define IS_MENU_ITEM(type) \
( IS_WIDGET_CLASS(type, CLIENT_MENU_ITEM) \
|| IS_WIDGET_CLASS(type, ACT_CENTER_ITEM))
Widget *win_to_widget(Window win);
Widget *create_widget(Widget_id id, Widget_type type, Widget_state state, Window parent, int x, int y, int w, int h);
void init_widget(Widget *widget, Widget_id id, Widget_type type, Widget_state state, Window parent, int x, int y, int w, int h);
void set_widget_tooltip(Widget *widget, const char *tooltip);
void set_widget_border_width(const Widget *widget, int width);
void set_widget_border_color(const Widget *widget, unsigned long pixel);
void destroy_widget(Widget *widget);
void show_widget(const Widget *widget);
void hide_widget(const Widget *widget);
void move_resize_widget(Widget *widget, int x, int y, int w, int h);
void update_widget_bg(const Widget *widget);
Widget_color_id get_widget_border_color_id(const Widget *widget);
Text_color_id get_widget_fg_id(const Widget *widget);
void alloc_color(void);
unsigned long get_widget_color(Widget_color wc);
XftColor get_text_color(Text_color color_id);
Window create_widget_win(Widget_type type, Window parent, int x, int y, int w, int h, int border_w, unsigned long border_pixel, unsigned long bg_pixel);
Widget_type get_widget_type(Window win);
void update_hint_win_for_info(Window hover, const char *info);
void draw_icon(Drawable d, Imlib_Image image, const char *name, int size);
unsigned long get_widget_color(Widget_color_id id);
XftColor get_widget_fg(Text_color_id id);
Window create_widget_win(Window parent, int x, int y, int w, int h, int border_w, unsigned long border_pixel, unsigned long bg_pixel);
void update_hint_win_for_info(const Widget *widget, const char *info);
void set_xic(Window win, XIC *ic);
KeySym look_up_key(XIC xic, XKeyEvent *e, wchar_t *keyname, size_t n);
void create_hint_win(void);

View File

@ -21,10 +21,16 @@
cfg->title_button_text[WIDGET_INDEX(type, TITLE_BUTTON)]=text
#define SET_TASKBAR_BUTTON_TEXT(type, text) /* 設置任務欄按鈕文字 */ \
cfg->taskbar_button_text[WIDGET_INDEX(type, TASKBAR_BUTTON)]=text
#define SET_ACT_CENTER_ITEM_TEXT(type, text) /* 設置操作中心菜單項文字 */ \
cfg->act_center_item_text[WIDGET_INDEX(type, ACT_CENTER_ITEM)]=text
#define SET_CLIENT_MENU_ITEM_TEXT(type, text) /* 設置客戶窗口菜單項文字 */ \
cfg->client_menu_item_text[WIDGET_INDEX(type, CLIENT_MENU_ITEM)]=text
#define SET_ACT_CENTER_MENU_ITEM(id, icon, symbol, label) /* 設置操作中心菜單項圖標和標籤 */ \
cfg->act_center_item_icon[WIDGET_INDEX(id, ACT_CENTER_ITEM)]=icon, \
cfg->act_center_item_symbol[WIDGET_INDEX(id, ACT_CENTER_ITEM)]=symbol, \
cfg->act_center_item_label[WIDGET_INDEX(id, ACT_CENTER_ITEM)]=label
#define SET_CLIENT_MENU_ITEM(id, icon, symbol, label) /* 設置客戶窗口菜單項圖標和標籤 */ \
cfg->client_menu_item_icon[WIDGET_INDEX(id, CLIENT_MENU_ITEM)]=icon, \
cfg->client_menu_item_symbol[WIDGET_INDEX(id, CLIENT_MENU_ITEM)]=symbol, \
cfg->client_menu_item_label[WIDGET_INDEX(id, CLIENT_MENU_ITEM)]=label
/* 功能:設置應由窗口管理器去設定的定位器相關功能綁定。
*
@ -67,7 +73,7 @@
{LOGOUT_BUTTON, 0, Button1, exec, SH_CMD(LOGOUT)}, \
{REBOOT_BUTTON, 0, Button1, exec, SH_CMD("reboot")}, \
{POWEROFF_BUTTON, 0, Button1, exec, SH_CMD("poweroff")}, \
{RUN_BUTTON, 0, Button1, enter_and_run_cmd, {0}}, \
{RUN_BUTTON, 0, Button1, show_run_cmd_entry, {0}}, \
{TITLE_LOGO, 0, Button1, open_client_menu, {0}}, \
{VERT_MAX_BUTTON, 0, Button1, maximize, {.max_way=VERT_MAX}}, \
{HORZ_MAX_BUTTON, 0, Button1, maximize, {.max_way=HORZ_MAX}}, \