Window-Manager

覆蓋 KDE 中任意視窗的視窗標題並設置自定義視窗標題

  • February 17, 2021

在這裡使用 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如果有新手找到這個答案並且不知道如何使用它,請問我,我會引導你完成它。^^

編輯:我對其進行了更新,以便您可以在命令行中使用-tfortitle_i_want-wfor開關來使用它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

引用自:https://unix.stackexchange.com/questions/22561