mirror of https://git.code.sf.net/p/gsmwm/code
* 發布第2.9.0版;
* 修復get_suitable_font函數的邏輯缺陷; * 修復操作中心圖標不對齊的缺陷; * 修復set_ewmh函數的數組越界的缺陷; * 修復get_prop函數的邏輯缺陷; * 使用按鈕構件代替按鈕窗口; * 使用面向對象思想重構界面部分; * 爲了更加模塊化而重構代碼; * 微調界面配色。
This commit is contained in:
parent
7051a9bd1b
commit
a3a00eba5b
11
ChangeLog
11
ChangeLog
|
@ -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
6
NEWS
|
@ -9,6 +9,12 @@
|
|||
* <http://www.gnu.org/licenses/>。
|
||||
* ************************************************************************/
|
||||
|
||||
第2.9.0版:
|
||||
* 修復在某些情況下崩潰的缺陷;
|
||||
* 修復操作中心圖標不對齊的缺陷;
|
||||
* 修復任務欄按鈕提示色異常的缺陷;
|
||||
* 微調界面配色。
|
||||
|
||||
第2.8.3版:
|
||||
* 更好的兼容第三方任務欄。
|
||||
|
||||
|
|
3
TODO
3
TODO
|
@ -9,6 +9,9 @@
|
|||
* <http://www.gnu.org/licenses/>。
|
||||
* ************************************************************************/
|
||||
|
||||
第2.9.0版的下一步的開發計劃:
|
||||
* 實現界面自動配色功能。
|
||||
|
||||
第2.8.3版的下一步的開發計劃:
|
||||
* 代碼重構。
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
./" <http://www.gnu.org/licenses/>。
|
||||
./" ************************************************************************/
|
||||
|
||||
.TH gwm 1 2024年2月 "gwm 2.8.3" gwm
|
||||
.TH gwm 1 2024年4月 "gwm 2.9.0" gwm
|
||||
.
|
||||
.SH 名称
|
||||
.B
|
||||
|
@ -34,7 +34,7 @@ gwm把物理屏幕虚拟为多个逻辑屏幕,即所谓的虚拟桌面。在
|
|||
.PP
|
||||
预览模式是所有窗口平均分配工作区域空间的布局模式。若在该模式下选中窗口,则切换至上一布局模式,选中的窗口变成当前窗口,其余窗口保持在前一布局模式中位置。若在前一布局模式为平铺模式,则选中的窗口移动至主区域顶部。
|
||||
.PP
|
||||
gwm为所有窗口分别重设父窗口,该父窗口还包括边框、标题栏,这两者统称窗口框架。重设父窗口之前的原窗口范围称为非框架区域。其中,标题栏从左至右依次设置标题区域、按钮。标题区域用于显示窗口的标题,以及提供移动窗口的功能。按钮用于实现特定的功能,按钮的数量随基本窗口布局模式而异。在平铺模式下,各按钮的文字从左至右依次为:◁、▼、▷、△、—、◲、🗙。在堆叠模式下,不显示◁、▼、▷、△按钮。在预览模式下,仅显示🗙按钮。
|
||||
gwm为所有窗口分别重设父窗口,该父窗口还包括边框、标题栏,这两者统称窗口框架。重设父窗口之前的原窗口范围称为非框架区域。其中,标题栏从左至右依次设置程序标识按钮、标题区域、其他按钮。程序标识按钮用于实现下拉菜单功能。标题区域用于显示窗口的标题,以及提供移动窗口的功能。其他按钮用于实现特定的功能,按钮的数量随基本窗口布局模式而异。在平铺模式下,各按钮的文字从左至右依次为:◁、▼、▷、△、—、◲、🗙。在堆叠模式下,不显示◁、▼、▷、△按钮。在预览模式下,仅显示🗙按钮。
|
||||
.
|
||||
.SH 选项
|
||||
无。
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
./" <http://www.gnu.org/licenses/>。
|
||||
./" ************************************************************************/
|
||||
|
||||
.TH gwm 1 2024年2月 "gwm 2.8.3" gwm
|
||||
.TH gwm 1 2024年4月 "gwm 2.9.0" gwm
|
||||
.
|
||||
.SH 名稱
|
||||
.B
|
||||
|
@ -34,7 +34,7 @@ gwm把物理屏幕虛擬爲多個邏輯屏幕,即所謂的虛擬桌面。在
|
|||
.PP
|
||||
預覽模式是所有窗口平均分配工作區域空間的布局模式。若在該模式下選中窗口,則切換至上一布局模式,選中的窗口變成當前窗口,其餘窗口保持在前一布局模式中位置。若在前一布局模式爲平鋪模式,則選中的窗口移動至主區域頂部。
|
||||
.PP
|
||||
gwm爲所有窗口分別重設父窗口,該父窗口還包括邊框、標題欄,這兩者統稱窗口框架。重設父窗口之前的原窗口範圍稱爲非框架區域。其中,標題欄從左至右依次設置標題區域、按鈕。標題區域用於顯示窗口的標題,以及提供移動窗口的功能。按鈕用於實現特定的功能,按鈕的數量隨基本窗口布局模式而異。在平鋪模式下,各按鈕的文字從左至右依次爲:◁、▼、▷、△、—、◲、🗙。在堆疊模式下,不顯示◁、▼、▷、△按鈕。在預覽模式下,僅顯示🗙按鈕。
|
||||
gwm爲所有窗口分別重設父窗口,該父窗口還包括邊框、標題欄,這兩者統稱窗口框架。重設父窗口之前的原窗口範圍稱爲非框架區域。其中,標題欄從左至右依次設置程序標識按鈕、標題區域、其他按鈕。程序標識按鈕用於實現下拉菜單功能。標題區域用於顯示窗口的標題,以及提供移動窗口的功能。其他按鈕用於實現特定的功能,按鈕的數量隨基本窗口布局模式而異。在平鋪模式下,各按鈕的文字從左至右依次爲:◁、▼、▷、△、—、◲、🗙。在堆疊模式下,不顯示◁、▼、▷、△按鈕。在預覽模式下,僅顯示🗙按鈕。
|
||||
.
|
||||
.SH 選項
|
||||
無。
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* *************************************************************************
|
||||
* button.h:與button.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
|
290
src/client.c
290
src/client.c
|
@ -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(_("錯誤:查詢窗口清單失敗!"));
|
||||
|
|
32
src/client.h
32
src/client.h
|
@ -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);
|
||||
|
|
184
src/config.c
184
src/config.c
|
@ -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_color。顏色名詳見rgb.txt(此文件的位
|
||||
* 說明:構件顏色號的定義詳見gwm.h:Widget_color_id。顏色名詳見rgb.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_color;不透明度取值範圍爲0~1.0(下同)。
|
||||
* 說明:構件顏色號的定義詳見gwm.h:Widget_color_id;不透明度取值範圍爲0~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();
|
||||
}
|
||||
|
|
13
src/config.h
13
src/config.h
|
@ -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; // 按鍵功能綁定。有的鍵盤同時按多個鍵會衝突,故組合鍵宜盡量少
|
||||
|
|
12
src/debug.c
12
src/debug.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
79
src/entry.c
79
src/entry.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
21
src/entry.h
21
src/entry.h
|
@ -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
|
||||
|
|
|
@ -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,它未必是真實的窗口 */
|
||||
|
|
30
src/font.c
30
src/font.c
|
@ -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)
|
||||
|
|
32
src/func.c
32
src/func.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
30
src/gwm.h
30
src/gwm.h
|
@ -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;
|
||||
|
|
248
src/handler.c
248
src/handler.c
|
@ -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);
|
||||
}
|
||||
|
|
70
src/image.c
70
src/image.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
79
src/layout.c
79
src/layout.c
|
@ -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;
|
||||
|
|
101
src/menu.c
101
src/menu.c
|
@ -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);
|
||||
}
|
||||
|
|
13
src/menu.h
13
src/menu.h
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
19
src/misc.c
19
src/misc.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
43
src/prop.c
43
src/prop.c
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
421
src/taskbar.c
421
src/taskbar.c
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
204
src/widget.c
204
src/widget.c
|
@ -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;
|
||||
|
|
132
src/widget.h
132
src/widget.h
|
@ -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);
|
||||
|
|
16
src/wm_cfg.h
16
src/wm_cfg.h
|
@ -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}}, \
|
||||
|
|
Loading…
Reference in New Issue