覆蓋 KDE 中任意視窗的視窗標題並設置自定義視窗標題
在這裡使用 KDE,但也可能有適用於其他桌面環境的解決方案。我經常處理很多很多視窗。大多數視窗包含許多選項卡(例如,帶有許多選項卡的 Dolphin 視窗,或 Firefox、Konsole 等)。視窗標題將根據我目前的選項卡而改變(這在大多數情況下很有幫助),但是當使用這麼多視窗時,我想對它們進行一些組織並能夠手動重命名視窗,覆蓋應用程序給出的視窗標題。我可能將一個 Firefox 視窗命名為“研究”,將另一個 Firefox 視窗命名為“文件”,以便能夠輕鬆區分我用來組織和分組不同選項卡的視窗。
理想情況下,我可以點擊視窗標題欄並輕鬆為其指定自定義名稱,但我會選擇一個稍微麻煩一些的解決方案,只要它有效。
我已經嘗試過
wmctrl -r :SELECT: -T "Research"
,但這只能暫時起作用(當應用程序更改標題時,例如在切換選項卡時,標題會恢復)。
我有這個完全相同的問題。
所以我編寫了一個綁定到熱鍵的 shell 腳本。
當我按下熱鍵時,它會獲取目前活動視窗(具有焦點的視窗)的視窗 ID。
然後它會為您提供一個彈出對話框,您可以在其中輸入您希望該視窗具有的標題。
然後,每次該視窗更改其名稱時,它都會將其更改回您想要的標題。
要使用該腳本,您需要:
fish
外殼(我用 fish 而不是 bash 寫的,因為 bash 讓我頭疼)
kdialog
- 將腳本綁定到熱鍵的某種方式
(我使用
xbindkeys
,因為要讓它工作我所要做的就是添加:
"[PATH TO SCRIPT]/[NAME OF SCRIPT]" Mod4 + t
(即視窗鍵 + t)
到 my
/home/o1/.xbindkeysrc
)感謝這個傢伙,他給了我關於魔法 xprop 東西的資訊。
(就像一年前一樣,直到今天我才開始寫劇本。xD)
PS如果有新手找到這個答案並且不知道如何使用它,請問我,我會引導你完成它。^^
編輯:我對其進行了更新,以便您可以在命令行中使用
-t
fortitle_i_want
和-w
for開關來使用它window_id
。這是腳本:
#!/usr/local/bin/fish # this block is so you can use it from the command line with -t and -w if test "$argv" != "" -a (math (count $argv)%2 == 0) for i in (seq 1 (count $argv)) if test $argv[$i] = '-t' set title_i_want $argv[(math 1 + $i)] else if test $argv[$i] = '-w' set window_id $argv[(math 1 + $i)] end end if not test $window_id echo "YOU DIDN'T ENTER A `window_id` WITH `-w`, SO MAKE SURE THE WINDOW YOU WANT HAS FOCUS TWO SECONDS FROM NOW!" sleep 2 end end # get the id of the currently focused window if not test $window_id set window_id (xprop -root _NET_ACTIVE_WINDOW | grep -P -o "0x\w+") end # get the title to force on that window if not test $title_i_want set title_i_want (kdialog --title "entitled" --inputbox "type the title you want and hit enter. to stop renaming, just enter nothing and hit esc") end # this bit is needed for a kludge that allows window renaming set has_renamed_before "FALSE" set interrupt_message "WAIT WAIT I WANT A TURN BLOO BLOO BLEE BLUH BLOO" # hopefully i never want to actually use that as a title xD xprop -f _NET_WM_NAME 8u -set _NET_WM_NAME $interrupt_message -id $window_id # take the output of xprop # pipe it into a while loop # everytime it outputs a new line # stuff it into a variable named "current_title" xprop -spy _NET_WM_NAME -id $window_id | while read current_title # cut off extraneous not-the-title bits of that string set current_title (echo $current_title | grep -P -o '(?<=_NET_WM_NAME\(UTF8_STRING\) = ").*(?="\z)') # if the current title is the interrupt message # AND # this script has renamed the window at least once before # then we wanna let the new name take over if test $current_title = $interrupt_message -a $has_renamed_before = "TRUE" exit # if title_i_want is an empty string, exit else if test $title_i_want = "" xprop -f _NET_WM_NAME 8u -set _NET_WM_NAME "WIDNOW WILL START RENAMING ITSELF AS NORMAL" -id $window_id exit # otherwise just change the title to what i want else if test $current_title != $title_i_want xprop -f _NET_WM_NAME 8u -set _NET_WM_NAME "$title_i_want" -id $window_id set has_renamed_before "TRUE" end end
編輯:我實際上不再使用這個 Fish 腳本了;
我用 Ruby 重寫了它:
#!/usr/bin/env ruby # -*- coding: utf-8 -*- require 'trollop' opts = Trollop.options do opt :title_i_want, "title_i_want", default: "" opt :bluh, "write to bluh", default: nil opt :copy_title, "copy_title", default: nil # TODO - AUTO OPTION opt :auto, "auto", default: nil end title_i_want = opts[:title_i_want] def get_current_wid `xprop -root _NET_ACTIVE_WINDOW`[/0x\w+/] end def with_current_title wid, &block IO.popen("xprop -spy _NET_WM_NAME _NET_WM_ICON_NAME -id #{wid}") do |io| loop do line = io.gets exit if line.nil? line = line.strip # cut off extraneous not-the-title bits of that string current_title = line[/(?:_NET_WM_(?:ICON_)?NAME\(UTF8_STRING\) = ")(.*)("$)/, 1] block.call current_title unless current_title.nil? end end end def get_current_title wid IO.popen("xprop _NET_WM_NAME _NET_WM_ICON_NAME -id #{wid}") do |io| line = io.gets.strip # cut off extraneous not-the-title bits of that string current_title = line[/(?:_NET_WM_(?:ICON_)?NAME\(UTF8_STRING\) = ")(.*)("$)/, 1] return current_title unless current_title.nil? end end if opts[:copy_title] # require "muflax" p 1 wid = get_current_wid `echo -n '#{get_current_title wid}(WID: #{wid})'|xclip -selection c` exit end if opts[:bluh] require "muflax" loop do # p 1 #db wid = get_current_wid # p 2 #db File.open "bluh", "a+" do |f| f.puts get_current_title wid end while wid == get_current_wid # puts "..." #db sleep 1 end end exit end #> 1A - from terminal - give title_i_want if not title_i_want.empty? #> 1A.1 - get current wid - assume it's the terminal_wid terminal_wid = get_current_wid #> 1A.2 - wait for wid to change while get_current_wid == terminal_wid puts "focus the window you want to title «#{title_i_want}»..." sleep 1 end #> 1A.3 - set new wid to target TWID TWID = get_current_wid #> 1B - from hotkey (or just sleeping) - no give title_i_want else #> 1B.1 - set current wid to target TWID TWID = get_current_wid #> 1B.2 - get title_i_want (with kdialog) #> 1B.2.1 - default to current title with_current_title TWID do |current_title| # v :current_title #db default_title = current_title sublime_match = / (?<beginning>.*?) # beginning might be... # path # untitled, find results, other useless junk # 𝌆 dired (?<dirty>\s•)? # dirty? (?:\s\(\.?(?<projname>[^()]*)\))? # project name, preceded by "." (i name them that way), and in rkaks (sublime does that) # or, sans dot, it's the dir, if the window was opened as a dir (?<issub>\s-\sSublime\sText\s2\s\(UNREGISTERED\)) # garbage at the end that marks it as a sublime window /x =~ current_title #if it's a sublime window... if sublime_match dummy = beginning.split("/") if dummy.length > 1 taildir = dummy[-2] end /𝌆 (?<direddir>.*)/ =~ beginning default_title = if projname ; projname elsif taildir ; taildir elsif direddir ; direddir else ; beginning end end if opts[:auto] title_i_want = default_title else title_i_want = `kdialog --title "entitled" --inputbox "type the title you want and hit enter.\nto stop renaming,\njust enter nothing and hit esc" '#{default_title}'`.chomp end break end end # v :terminal_wid #db # v :TWID #db # v :ARGV #db # v :title_i_want #db def set_title wid, title `xprop -f _NET_WM_NAME 8u -set _NET_WM_NAME "#{title}" -id #{wid}` `xprop -f _NET_WM_ICON_NAME 8u -set _NET_WM_ICON_NAME "#{title}" -id #{wid}` end #> 2 - apply title to TWID #> 2.1 - allow de-naming #> 2.2 - allow renaming # this bit is needed for a kludge that allows window renaming has_renamed_before = false interrupt_message = "WAIT WAIT I WANT A TURN BLOO BLOO BLEE BLUH BLOO" # hopefully i never want to actually use that as a title xD `xprop -f _NET_WM_NAME 8u -set _NET_WM_NAME '#{interrupt_message}' -id #{TWID}` with_current_title TWID do |current_title| # if title_i_want is an empty string, exit if title_i_want.empty? # p 1 #db set_title TWID, "WINDOW WILL START RENAMING ITSELF AS NORMAL" exit # if the current title is the interrupt message # AND # this script has renamed the window at least once before # then we wanna let the new name take over elsif current_title == interrupt_message and has_renamed_before # p 2 #db exit # otherwise just change the title to what i want elsif current_title != title_i_want # p 3 #db set_title TWID, title_i_want has_renamed_before = true end end