titlestack.pl revision a5ae21e4
1a5ae21e4Smrg#!/usr/bin/env perl 2a5ae21e4Smrg# $XTermId: titlestack.pl,v 1.29 2019/09/20 00:50:10 tom Exp $ 3a5ae21e4Smrg# ----------------------------------------------------------------------------- 4a5ae21e4Smrg# this file is part of xterm 5a5ae21e4Smrg# 6a5ae21e4Smrg# Copyright 2019 by Thomas E. Dickey 7a5ae21e4Smrg# 8a5ae21e4Smrg# All Rights Reserved 9a5ae21e4Smrg# 10a5ae21e4Smrg# Permission is hereby granted, free of charge, to any person obtaining a 11a5ae21e4Smrg# copy of this software and associated documentation files (the 12a5ae21e4Smrg# "Software"), to deal in the Software without restriction, including 13a5ae21e4Smrg# without limitation the rights to use, copy, modify, merge, publish, 14a5ae21e4Smrg# distribute, sublicense, and/or sell copies of the Software, and to 15a5ae21e4Smrg# permit persons to whom the Software is furnished to do so, subject to 16a5ae21e4Smrg# the following conditions: 17a5ae21e4Smrg# 18a5ae21e4Smrg# The above copyright notice and this permission notice shall be included 19a5ae21e4Smrg# in all copies or substantial portions of the Software. 20a5ae21e4Smrg# 21a5ae21e4Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22a5ae21e4Smrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23a5ae21e4Smrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24a5ae21e4Smrg# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 25a5ae21e4Smrg# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26a5ae21e4Smrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27a5ae21e4Smrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28a5ae21e4Smrg# 29a5ae21e4Smrg# Except as contained in this notice, the name(s) of the above copyright 30a5ae21e4Smrg# holders shall not be used in advertising or otherwise to promote the 31a5ae21e4Smrg# sale, use or other dealings in this Software without prior written 32a5ae21e4Smrg# authorization. 33a5ae21e4Smrg# ----------------------------------------------------------------------------- 34a5ae21e4Smrg# Test the title-stack and title-mode options of xterm. 35a5ae21e4Smrg 36a5ae21e4Smrg# TODO: add test for arbitrary x property 37a5ae21e4Smrg# TODO: allow -g and -v options to toggle interactively 38a5ae21e4Smrg 39a5ae21e4Smrguse strict; 40a5ae21e4Smrguse warnings; 41a5ae21e4Smrg 42a5ae21e4Smrguse Getopt::Std; 43a5ae21e4Smrguse Encode qw(decode encode); 44a5ae21e4Smrguse Term::ReadKey; 45a5ae21e4Smrguse I18N::Langinfo qw(langinfo CODESET); 46a5ae21e4Smrg 47a5ae21e4Smrgour $target = ""; 48a5ae21e4Smrg 49a5ae21e4Smrgour $encoding = lc( langinfo( CODESET() ) ); 50a5ae21e4Smrgour $wm_name; 51a5ae21e4Smrgour ( $opt_b, $opt_g, $opt_v, $opt_8 ); 52a5ae21e4Smrg 53a5ae21e4Smrgour @titlestack; # stack of title-strings, using current encoding 54a5ae21e4Smrgour @item_stack; # selector used when doing a push 55a5ae21e4Smrgour @mode_stack; # titleModes in effect when titlestack was loaded 56a5ae21e4Smrgour $SP; # stack-pointer 57a5ae21e4Smrgour $TM; # current titleModes, in various combinations 58a5ae21e4Smrg 59a5ae21e4Smrgour $utf8_sample = 0; 60a5ae21e4Smrg 61a5ae21e4Smrgour $CSI = "\x1b["; 62a5ae21e4Smrgour $OSC = "\x1b]"; 63a5ae21e4Smrgour $ST = "\x1b\\"; 64a5ae21e4Smrg 65a5ae21e4Smrgsub SendHEX() { return ( $TM & 1 ) ? 1 : 0; } 66a5ae21e4Smrgsub ReadHEX() { return ( $TM & 2 ) ? 1 : 0; } 67a5ae21e4Smrgsub SendUTF8() { return ( $TM & 4 ) ? 1 : 0; } 68a5ae21e4Smrgsub ReadUTF8() { return ( $TM & 8 ) ? 1 : 0; } 69a5ae21e4Smrg 70a5ae21e4Smrgsub to_hex($) { 71a5ae21e4Smrg my $value = shift; 72a5ae21e4Smrg my $result = ""; 73a5ae21e4Smrg my $n; 74a5ae21e4Smrg 75a5ae21e4Smrg for ( $n = 0 ; $n < length($value) ; ++$n ) { 76a5ae21e4Smrg $result .= sprintf( "%02X", ord substr( $value, $n, 1 ) ); 77a5ae21e4Smrg } 78a5ae21e4Smrg return $result; 79a5ae21e4Smrg} 80a5ae21e4Smrg 81a5ae21e4Smrgsub from_hex($) { 82a5ae21e4Smrg my $value = shift; 83a5ae21e4Smrg my $result = ""; 84a5ae21e4Smrg if ( $value =~ /^[[:xdigit:]]+$/ and ( length($value) % 2 ) == 0 ) { 85a5ae21e4Smrg my $octets = ""; 86a5ae21e4Smrg for ( my $n = 0 ; $n < length($value) ; $n += 2 ) { 87a5ae21e4Smrg my $pair = substr( $value, $n, 2 ); 88a5ae21e4Smrg my $data = hex $pair; 89a5ae21e4Smrg $octets .= chr($data); 90a5ae21e4Smrg } 91a5ae21e4Smrg $result = decode( &ReadUTF8 ? "utf-8" : "iso-8859-1", $octets ); 92a5ae21e4Smrg } 93a5ae21e4Smrg else { 94a5ae21e4Smrg $result = $value; 95a5ae21e4Smrg } 96a5ae21e4Smrg return $result; 97a5ae21e4Smrg} 98a5ae21e4Smrg 99a5ae21e4Smrgsub show_string($) { 100a5ae21e4Smrg my $value = shift; 101a5ae21e4Smrg my $n; 102a5ae21e4Smrg my $octets = 103a5ae21e4Smrg encode( ( ( $encoding eq "utf-8" ) ? "utf-8" : "iso-8859-1" ), $value ); 104a5ae21e4Smrg 105a5ae21e4Smrg my $result = ""; 106a5ae21e4Smrg for ( $n = 0 ; $n < length($octets) ; $n += 1 ) { 107a5ae21e4Smrg my $c = ord substr( $octets, $n, 1 ); 108a5ae21e4Smrg if ( $c == ord '\\' ) { 109a5ae21e4Smrg $result .= "\\\\"; 110a5ae21e4Smrg } 111a5ae21e4Smrg elsif ( $c == 0x1b ) { 112a5ae21e4Smrg $result .= "\\E"; 113a5ae21e4Smrg } 114a5ae21e4Smrg elsif ( $c == 0x7f ) { 115a5ae21e4Smrg $result .= "^?"; 116a5ae21e4Smrg } 117a5ae21e4Smrg elsif ( $c == 32 ) { 118a5ae21e4Smrg $result .= "\\s"; 119a5ae21e4Smrg } 120a5ae21e4Smrg elsif ( $c < 32 ) { 121a5ae21e4Smrg $result .= sprintf( "^%c", $c + 64 ); 122a5ae21e4Smrg } 123a5ae21e4Smrg elsif ( $c > 128 ) { 124a5ae21e4Smrg $result .= sprintf( "\\%03o", $c ); 125a5ae21e4Smrg } 126a5ae21e4Smrg else { 127a5ae21e4Smrg $result .= chr($c); 128a5ae21e4Smrg } 129a5ae21e4Smrg } 130a5ae21e4Smrg 131a5ae21e4Smrg printf "%s\r\n", $result; 132a5ae21e4Smrg} 133a5ae21e4Smrg 134a5ae21e4Smrgsub send_command($) { 135a5ae21e4Smrg my $command = shift; 136a5ae21e4Smrg if ($opt_v) { 137a5ae21e4Smrg printf "send: "; 138a5ae21e4Smrg &show_string($command); 139a5ae21e4Smrg } 140a5ae21e4Smrg print STDERR encode( &SendUTF8 ? "utf-8" : "iso-8859-1", $command ); 141a5ae21e4Smrg} 142a5ae21e4Smrg 143a5ae21e4Smrgsub get_reply($) { 144a5ae21e4Smrg my $command = shift; 145a5ae21e4Smrg my $reply = ""; 146a5ae21e4Smrg 147a5ae21e4Smrg &send_command($command); 148a5ae21e4Smrg my $start = time; 149a5ae21e4Smrg while (1) { 150a5ae21e4Smrg my $test = ReadKey 1; 151a5ae21e4Smrg last if not defined $test; 152a5ae21e4Smrg last if ( time > ( $start + 1 ) ); 153a5ae21e4Smrg 154a5ae21e4Smrg $reply .= $test; 155a5ae21e4Smrg } 156a5ae21e4Smrg if ($opt_v) { 157a5ae21e4Smrg printf "read: "; 158a5ae21e4Smrg &show_string($reply); 159a5ae21e4Smrg } 160a5ae21e4Smrg return $reply; 161a5ae21e4Smrg} 162a5ae21e4Smrg 163a5ae21e4Smrgsub get_title($) { 164a5ae21e4Smrg my $icon = shift; 165a5ae21e4Smrg my $reply = &get_reply( sprintf( "%s%dt", $CSI, $icon ? 20 : 21 ) ); 166a5ae21e4Smrg my $prefix = $icon ? "L" : "l"; 167a5ae21e4Smrg 168a5ae21e4Smrg if ( $opt_8 and ( $reply =~ /^$CSI/ ) ) { 169a5ae21e4Smrg $reply =~ s/^${CSI}//; 170a5ae21e4Smrg $reply =~ s/${ST}$//; 171a5ae21e4Smrg } 172a5ae21e4Smrg else { 173a5ae21e4Smrg $reply =~ s/^\x1b//; 174a5ae21e4Smrg $reply =~ s/^[\[\]]//; 175a5ae21e4Smrg if ( index( $reply, $ST ) >= 0 ) { 176a5ae21e4Smrg $reply =~ s/\x1b\\$//; 177a5ae21e4Smrg } 178a5ae21e4Smrg else { 179a5ae21e4Smrg $reply =~ s/\007$//; 180a5ae21e4Smrg } 181a5ae21e4Smrg } 182a5ae21e4Smrg if ( $reply =~ /^$prefix/ ) { 183a5ae21e4Smrg $reply =~ s/^$prefix//; 184a5ae21e4Smrg if (&ReadHEX) { 185a5ae21e4Smrg $reply = &from_hex($reply); 186a5ae21e4Smrg } 187a5ae21e4Smrg } 188a5ae21e4Smrg else { 189a5ae21e4Smrg $reply = "?" . $reply; 190a5ae21e4Smrg } 191a5ae21e4Smrg return $reply; 192a5ae21e4Smrg} 193a5ae21e4Smrg 194a5ae21e4Smrgsub raw() { 195a5ae21e4Smrg ReadMode 'ultra-raw', 'STDIN'; # allow single-character inputs 196a5ae21e4Smrg} 197a5ae21e4Smrg 198a5ae21e4Smrgsub cooked() { 199a5ae21e4Smrg ReadMode 'normal'; 200a5ae21e4Smrg} 201a5ae21e4Smrg 202a5ae21e4Smrgsub read_cmd($) { 203a5ae21e4Smrg my $command = shift; 204a5ae21e4Smrg my @result; 205a5ae21e4Smrg if ( open( my $fp, "$command |" ) ) { 206a5ae21e4Smrg binmode( $fp, ":utf8" ) if ( $encoding eq "utf-8" ); 207a5ae21e4Smrg @result = <$fp>; 208a5ae21e4Smrg close($fp); 209a5ae21e4Smrg chomp @result; 210a5ae21e4Smrg } 211a5ae21e4Smrg return @result; 212a5ae21e4Smrg} 213a5ae21e4Smrg 214a5ae21e4Smrgsub which_modes($) { 215a5ae21e4Smrg my $modes = shift; 216a5ae21e4Smrg my $result = ""; 217a5ae21e4Smrg if ( $modes & 3 ) { 218a5ae21e4Smrg $result .= "put" if ( ( $modes & 3 ) == 1 ); 219a5ae21e4Smrg $result .= "get" if ( ( $modes & 3 ) == 2 ); 220a5ae21e4Smrg $result .= "p/q" if ( ( $modes & 3 ) == 3 ); 221a5ae21e4Smrg $result .= " hex"; 222a5ae21e4Smrg } 223a5ae21e4Smrg if ( $modes & 12 ) { 224a5ae21e4Smrg $modes /= 4; 225a5ae21e4Smrg $result .= "," unless ( $result eq "" ); 226a5ae21e4Smrg $result .= "put" if ( ( $modes & 3 ) == 1 ); 227a5ae21e4Smrg $result .= "get" if ( ( $modes & 3 ) == 2 ); 228a5ae21e4Smrg $result .= "p/q" if ( ( $modes & 3 ) == 3 ); 229a5ae21e4Smrg $result .= " utf"; 230a5ae21e4Smrg } 231a5ae21e4Smrg $result = "default" if ( $result eq "" ); 232a5ae21e4Smrg return $result; 233a5ae21e4Smrg} 234a5ae21e4Smrg 235a5ae21e4Smrgsub which_tmode($$) { 236a5ae21e4Smrg my $set = shift; 237a5ae21e4Smrg my $mode = shift; 238a5ae21e4Smrg my $result = ""; 239a5ae21e4Smrg $result = "set window/icon labels using hexadecimal" if ( $mode == 0 ); 240a5ae21e4Smrg $result = "query window/icon labels using hexadecimal" if ( $mode == 1 ); 241a5ae21e4Smrg $result = "set window/icon labels using UTF-8" if ( $mode == 2 ); 242a5ae21e4Smrg $result = "query window/icon labels using UTF-8" if ( $mode == 3 ); 243a5ae21e4Smrg $result = "do not " . $result if ( $set == 0 and $result ne "" ); 244a5ae21e4Smrg return $result; 245a5ae21e4Smrg} 246a5ae21e4Smrg 247a5ae21e4Smrgsub get_tmode($) { 248a5ae21e4Smrg my $set = shift; 249a5ae21e4Smrg my $help = 0; 250a5ae21e4Smrg my $result = "?"; 251a5ae21e4Smrg while ( $result !~ /^[0123]$/ ) { 252a5ae21e4Smrg $result = ReadKey 0; 253a5ae21e4Smrg if ( $result eq "q" ) { 254a5ae21e4Smrg $result = -1; 255a5ae21e4Smrg last; 256a5ae21e4Smrg } 257a5ae21e4Smrg elsif ( $result eq "?" and not $help ) { 258a5ae21e4Smrg for my $n ( 0 .. 3 ) { 259a5ae21e4Smrg printf "\r\n\t%s = %s", $n, &which_tmode( $set, $n ); 260a5ae21e4Smrg } 261a5ae21e4Smrg printf "\r\n\t:"; 262a5ae21e4Smrg $help = 1; 263a5ae21e4Smrg } 264a5ae21e4Smrg } 265a5ae21e4Smrg if ( $result >= 0 ) { 266a5ae21e4Smrg printf "[%s]\r\n\t:", &which_tmode( $set, $result ); 267a5ae21e4Smrg } 268a5ae21e4Smrg return $result; 269a5ae21e4Smrg} 270a5ae21e4Smrg 271a5ae21e4Smrgsub which_item($) { 272a5ae21e4Smrg my $code = shift; 273a5ae21e4Smrg my $result = ""; 274a5ae21e4Smrg $result = "both" if ( $code == 0 ); 275a5ae21e4Smrg $result = "icon" if ( $code == 1 ); 276a5ae21e4Smrg $result = "name" if ( $code == 2 ); 277a5ae21e4Smrg return $result; 278a5ae21e4Smrg} 279a5ae21e4Smrg 280a5ae21e4Smrgsub which_selector($) { 281a5ae21e4Smrg my $code = shift; 282a5ae21e4Smrg my $result = ""; 283a5ae21e4Smrg $result = "both titles" if ( $code == 0 ); 284a5ae21e4Smrg $result = "icon title" if ( $code == 1 ); 285a5ae21e4Smrg $result = "window title" if ( $code == 2 ); 286a5ae21e4Smrg return $result; 287a5ae21e4Smrg} 288a5ae21e4Smrg 289a5ae21e4Smrgsub get_selector() { 290a5ae21e4Smrg my $result = "?"; 291a5ae21e4Smrg my $help = 0; 292a5ae21e4Smrg printf "\t:"; 293a5ae21e4Smrg while ( $result !~ /^[012]$/ ) { 294a5ae21e4Smrg $result = ReadKey 0; 295a5ae21e4Smrg if ( $result eq "q" ) { 296a5ae21e4Smrg $result = -1; 297a5ae21e4Smrg last; 298a5ae21e4Smrg } 299a5ae21e4Smrg elsif ( $result eq "l" ) { 300a5ae21e4Smrg $result = 2; 301a5ae21e4Smrg } 302a5ae21e4Smrg elsif ( $result eq "L" ) { 303a5ae21e4Smrg $result = 1; 304a5ae21e4Smrg } 305a5ae21e4Smrg elsif ( $result eq "?" and not $help ) { 306a5ae21e4Smrg for my $n ( 0 .. 2 ) { 307a5ae21e4Smrg printf "\r\n\t%d = %s", $n, &which_selector($n); 308a5ae21e4Smrg } 309a5ae21e4Smrg printf "\r\n\t:"; 310a5ae21e4Smrg $help = 1; 311a5ae21e4Smrg } 312a5ae21e4Smrg } 313a5ae21e4Smrg if ( $result >= 0 ) { 314a5ae21e4Smrg printf "[%s]\r\n\t:", &which_selector($result); 315a5ae21e4Smrg } 316a5ae21e4Smrg return $result; 317a5ae21e4Smrg} 318a5ae21e4Smrg 319a5ae21e4Smrgsub display_info() { 320a5ae21e4Smrg 321a5ae21e4Smrg # use xprop to get properties 322a5ae21e4Smrg my $command = "xprop"; 323a5ae21e4Smrg if ( $ENV{WINDOWID} ) { 324a5ae21e4Smrg my $windowid = $ENV{WINDOWID}; 325a5ae21e4Smrg $command .= " -id " . $windowid if ( $windowid ne "" ); 326a5ae21e4Smrg } 327a5ae21e4Smrg else { 328a5ae21e4Smrg printf "...xprop\r\n"; 329a5ae21e4Smrg } 330a5ae21e4Smrg my @props = &read_cmd($command); 331a5ae21e4Smrg for my $n ( 0 .. $#props ) { 332a5ae21e4Smrg printf "\t%s\r\n", $props[$n] 333a5ae21e4Smrg if ( index( $props[$n], "WM_NAME(" ) >= 0 334a5ae21e4Smrg or index( $props[$n], "WM_ICON_NAME(" ) >= 0 ); 335a5ae21e4Smrg } 336a5ae21e4Smrg 337a5ae21e4Smrg # use escape sequences to get corresponding information 338a5ae21e4Smrg printf "... Icon title:%s\r\n", &get_title(1); 339a5ae21e4Smrg printf "... Window title:%s\r\n", &get_title(0); 340a5ae21e4Smrg 341a5ae21e4Smrg # show title-stack (and modes used for each level) 342a5ae21e4Smrg printf "... Modes[%s]\r\n", &which_modes($TM); 343a5ae21e4Smrg printf "... Stack(%d):\r\n", $SP; 344a5ae21e4Smrg for my $n ( 0 .. $SP ) { 345a5ae21e4Smrg printf "\t%d [%s:%s]%s\r\n", $n, &which_item( $item_stack[$n] ), 346a5ae21e4Smrg &which_modes( $mode_stack[$n] ), $titlestack[$n]; 347a5ae21e4Smrg } 348a5ae21e4Smrg} 349a5ae21e4Smrg 350a5ae21e4Smrgsub set_titlemode($) { 351a5ae21e4Smrg my $set = shift; 352a5ae21e4Smrg my $opts = ""; 353a5ae21e4Smrg my $opt; 354a5ae21e4Smrg printf "\t:"; 355a5ae21e4Smrg while ( ( $opt = &get_tmode($set) ) >= 0 ) { 356a5ae21e4Smrg $TM |= ( 1 << $opt ) if ($set); 357a5ae21e4Smrg $TM &= ~( 1 << $opt ) unless ($set); 358a5ae21e4Smrg $opts .= ";" unless ( $opts eq "" ); 359a5ae21e4Smrg $opts .= $opt; 360a5ae21e4Smrg } 361a5ae21e4Smrg if ( $opts ne "" ) { 362a5ae21e4Smrg &send_command( sprintf( "%s>%s%s", $CSI, $opts, $set ? "t" : "T" ) ); 363a5ae21e4Smrg } 364a5ae21e4Smrg} 365a5ae21e4Smrg 366a5ae21e4Smrgsub utf8_sample($) { 367a5ae21e4Smrg my $item = shift; 368a5ae21e4Smrg my $last = 4; 369a5ae21e4Smrg my $text; 370a5ae21e4Smrg if ( ( $item % $last ) == 0 ) { 371a5ae21e4Smrg my $chars = "THE QUICK BROWN FOX\nJUMPED OVER THE LAZY DOG"; 372a5ae21e4Smrg $text = ""; 373a5ae21e4Smrg for my $n ( 0 .. length($chars) ) { 374a5ae21e4Smrg my $chr = substr( $chars, $n, 1 ); 375a5ae21e4Smrg if ( $chr eq " " ) { 376a5ae21e4Smrg $chr = " "; 377a5ae21e4Smrg } 378a5ae21e4Smrg elsif ( ord($chr) < 32 ) { 379a5ae21e4Smrg 380a5ae21e4Smrg # leave control characters as-is 381a5ae21e4Smrg } 382a5ae21e4Smrg else { 383a5ae21e4Smrg $chr = chr( 0xff00 + ord($chr) - 32 ); 384a5ae21e4Smrg } 385a5ae21e4Smrg $text .= $chr; 386a5ae21e4Smrg } 387a5ae21e4Smrg } 388a5ae21e4Smrg elsif ( ( $item % $last ) == 1 ) { 389a5ae21e4Smrg $text = chr(0x442) . chr(0x435) . chr(0x441) . chr(0x442); 390a5ae21e4Smrg } 391a5ae21e4Smrg elsif ( ( $item % $last ) == 2 ) { 392a5ae21e4Smrg for my $chr ( 0x391 .. 0x3a9 ) { 393a5ae21e4Smrg $text .= chr($chr); 394a5ae21e4Smrg } 395a5ae21e4Smrg } 396a5ae21e4Smrg elsif ( ( $item % $last ) == 3 ) { 397a5ae21e4Smrg for my $chr ( 0x3b1 .. 0x3c9 ) { 398a5ae21e4Smrg $text .= chr($chr); 399a5ae21e4Smrg } 400a5ae21e4Smrg } 401a5ae21e4Smrg return $text; 402a5ae21e4Smrg} 403a5ae21e4Smrg 404a5ae21e4Smrgsub set_titletext() { 405a5ae21e4Smrg my $opt = &get_selector; 406a5ae21e4Smrg if ( $opt >= 0 ) { 407a5ae21e4Smrg my $text; 408a5ae21e4Smrg if ($opt_g) { 409a5ae21e4Smrg 410a5ae21e4Smrg if (&SendUTF8) { 411a5ae21e4Smrg $text = &utf8_sample( $utf8_sample++ ); 412a5ae21e4Smrg } 413a5ae21e4Smrg else { 414a5ae21e4Smrg # ugly code, but mapping the a/e/i/o/u uppercase accented 415a5ae21e4Smrg # characters that repeat. 416a5ae21e4Smrg my $a_chars = chr(192) . chr(193) . chr(194) . chr(196); 417a5ae21e4Smrg my $e_chars = ""; 418a5ae21e4Smrg my $i_chars = " "; 419a5ae21e4Smrg my $o_chars = chr(210) . chr(211) . chr(212) . chr(214); 420a5ae21e4Smrg my $u_chars = ""; 421a5ae21e4Smrg my $gap = " " . chr(215) . " "; 422a5ae21e4Smrg for my $chr ( 0 .. 3 ) { 423a5ae21e4Smrg $e_chars .= chr( $chr + 200 ); 424a5ae21e4Smrg $i_chars .= chr( $chr + 204 ) . " "; 425a5ae21e4Smrg $u_chars .= chr( $chr + 217 ); 426a5ae21e4Smrg } 427a5ae21e4Smrg $text = 428a5ae21e4Smrg $a_chars 429a5ae21e4Smrg . $gap 430a5ae21e4Smrg . $e_chars 431a5ae21e4Smrg . $gap 432a5ae21e4Smrg . $i_chars 433a5ae21e4Smrg . $gap 434a5ae21e4Smrg . $o_chars 435a5ae21e4Smrg . $gap 436a5ae21e4Smrg . $u_chars; 437a5ae21e4Smrg } 438a5ae21e4Smrg printf "%s\r\n", $text; 439a5ae21e4Smrg } 440a5ae21e4Smrg else { 441a5ae21e4Smrg &cooked; 442a5ae21e4Smrg $text = ReadLine 0; 443a5ae21e4Smrg chomp $text; 444a5ae21e4Smrg &raw; 445a5ae21e4Smrg } 446a5ae21e4Smrg $titlestack[$SP] = $text; 447a5ae21e4Smrg $item_stack[$SP] = $opt; 448a5ae21e4Smrg $mode_stack[$SP] = $TM; 449a5ae21e4Smrg if (&SendHEX) { 450a5ae21e4Smrg my $octets = 451a5ae21e4Smrg encode( ( &SendUTF8 ? "utf-8" : "iso-8859-1" ), $text ); 452a5ae21e4Smrg $text = &to_hex($octets); 453a5ae21e4Smrg } 454a5ae21e4Smrg &send_command( sprintf( "%s%s;%s%s", $OSC, $opt, $text, $ST ) ); 455a5ae21e4Smrg } 456a5ae21e4Smrg} 457a5ae21e4Smrg 458a5ae21e4Smrgsub save_title() { 459a5ae21e4Smrg my $opt = &get_selector; 460a5ae21e4Smrg if ( $opt >= 0 ) { 461a5ae21e4Smrg &send_command( sprintf( "%s22;%st", $CSI, $opt ) ); 462a5ae21e4Smrg ++$SP; 463a5ae21e4Smrg $titlestack[$SP] = $titlestack[ $SP - 1 ]; 464a5ae21e4Smrg $item_stack[$SP] = $opt; 465a5ae21e4Smrg $mode_stack[$SP] = $mode_stack[ $SP - 1 ]; 466a5ae21e4Smrg } 467a5ae21e4Smrg} 468a5ae21e4Smrg 469a5ae21e4Smrgsub restore_title($) { 470a5ae21e4Smrg my $set = shift; 471a5ae21e4Smrg my $opt = &get_selector unless ($set); 472a5ae21e4Smrg if ( $opt >= 0 and $SP > 0 ) { 473a5ae21e4Smrg $opt = $item_stack[$SP] if ($set); 474a5ae21e4Smrg &send_command( sprintf( "%s23;%st", $CSI, $opt ) ); 475a5ae21e4Smrg $SP--; 476a5ae21e4Smrg } 477a5ae21e4Smrg} 478a5ae21e4Smrg 479a5ae21e4Smrgsub get_xprop($$) { 480a5ae21e4Smrg my $id = shift; 481a5ae21e4Smrg my $name = shift; 482a5ae21e4Smrg my @data = &read_cmd("xprop -id $id"); 483a5ae21e4Smrg my $prop = ""; 484a5ae21e4Smrg for my $n ( 0 .. $#data ) { 485a5ae21e4Smrg if ( $data[$n] =~ /$name\([^)]+\) =/ ) { 486a5ae21e4Smrg $prop = $data[$n]; 487a5ae21e4Smrg $prop =~ s/^[^=]*=\s*//; 488a5ae21e4Smrg $prop =~ s/"//g; 489a5ae21e4Smrg last; 490a5ae21e4Smrg } 491a5ae21e4Smrg } 492a5ae21e4Smrg return $prop; 493a5ae21e4Smrg} 494a5ae21e4Smrg 495a5ae21e4Smrgsub get_WM_NAME() { 496a5ae21e4Smrg $wm_name = "missing WM_NAME"; 497a5ae21e4Smrg my $supwin = `xprop -root '_NET_SUPPORTING_WM_CHECK'`; 498a5ae21e4Smrg if ( $supwin ne "" ) { 499a5ae21e4Smrg $supwin =~ s/^.*(0x[[:xdigit:]]+).*/$1/; 500a5ae21e4Smrg $wm_name = &get_xprop( $supwin, "_NET_WM_NAME" ); 501a5ae21e4Smrg $wm_name = "unknown" if ( $wm_name eq "" ); 502a5ae21e4Smrg printf "** using \"$wm_name\" window manager\n"; 503a5ae21e4Smrg } 504a5ae21e4Smrg} 505a5ae21e4Smrg 506a5ae21e4Smrgsub main::HELP_MESSAGE() { 507a5ae21e4Smrg printf STDERR <<EOF 508a5ae21e4SmrgUsage: $0 [options] 509a5ae21e4SmrgOptions: 510a5ae21e4Smrg -8 use 8-bit controls 511a5ae21e4Smrg -b use BEL rather than ST for terminating strings 512a5ae21e4Smrg -g generate title-strings rather than prompting 513a5ae21e4Smrg -v verbose 514a5ae21e4SmrgEOF 515a5ae21e4Smrg ; 516a5ae21e4Smrg exit 1; 517a5ae21e4Smrg} 518a5ae21e4Smrg 519a5ae21e4Smrg$Getopt::Std::STANDARD_HELP_VERSION = 1; 520a5ae21e4Smrg&getopts('bgv8') || &main::HELP_MESSAGE; 521a5ae21e4Smrg 522a5ae21e4Smrg$ST = "\007" if ($opt_b); 523a5ae21e4Smrg 524a5ae21e4Smrg$titlestack[ $SP = 0 ] = "unknown"; 525a5ae21e4Smrg$item_stack[$SP] = 0; 526a5ae21e4Smrg$mode_stack[$SP] = $TM = 0; 527a5ae21e4Smrg 528a5ae21e4Smrgbinmode( STDOUT, ":utf8" ) if ( $encoding eq "utf-8" ); 529a5ae21e4Smrgif ($opt_8) { 530a5ae21e4Smrg if ( $encoding eq "utf-8" ) { 531a5ae21e4Smrg undef $opt_8; 532a5ae21e4Smrg printf "...ignoring -8 option since locale uses %s\n", $encoding; 533a5ae21e4Smrg } 534a5ae21e4Smrg else { 535a5ae21e4Smrg printf STDERR "\x1b G"; 536a5ae21e4Smrg $CSI = "\x9b"; 537a5ae21e4Smrg $OSC = "\x9d"; 538a5ae21e4Smrg $ST = "\x9c"; 539a5ae21e4Smrg } 540a5ae21e4Smrg} 541a5ae21e4Smrg 542a5ae21e4Smrg&get_WM_NAME; 543a5ae21e4Smrg 544a5ae21e4Smrg&raw; 545a5ae21e4Smrg&raw; 546a5ae21e4Smrgwhile (1) { 547a5ae21e4Smrg my $cmd; 548a5ae21e4Smrg 549a5ae21e4Smrg printf "\r\nCommand (? for help):"; 550a5ae21e4Smrg $cmd = ReadKey 0; 551a5ae21e4Smrg if ( not $cmd ) { 552a5ae21e4Smrg sleep 1; 553a5ae21e4Smrg } 554a5ae21e4Smrg elsif ( $cmd eq "?" ) { 555a5ae21e4Smrg printf "\r\n? help," 556a5ae21e4Smrg . " d=display," 557a5ae21e4Smrg . " m/M=set/reset mode," 558a5ae21e4Smrg . " p=set title," 559a5ae21e4Smrg . " q=quit," 560a5ae21e4Smrg . " r=restore," 561a5ae21e4Smrg . " s=save\r\n"; 562a5ae21e4Smrg } 563a5ae21e4Smrg elsif ( $cmd eq "#" ) { 564a5ae21e4Smrg printf " ...comment\r\n\t#"; 565a5ae21e4Smrg &cooked; 566a5ae21e4Smrg ReadLine 0; 567a5ae21e4Smrg &raw; 568a5ae21e4Smrg } 569a5ae21e4Smrg elsif ( $cmd eq "!" ) { 570a5ae21e4Smrg printf " ...shell\r\n"; 571a5ae21e4Smrg &cooked; 572a5ae21e4Smrg system( $ENV{SHELL} ); 573a5ae21e4Smrg &raw; 574a5ae21e4Smrg } 575a5ae21e4Smrg elsif ( $cmd eq "d" ) { 576a5ae21e4Smrg printf " ...display\r\n"; 577a5ae21e4Smrg &display_info; 578a5ae21e4Smrg } 579a5ae21e4Smrg elsif ( $cmd eq "p" ) { 580a5ae21e4Smrg printf " ...set text\r\n"; 581a5ae21e4Smrg &set_titletext; 582a5ae21e4Smrg } 583a5ae21e4Smrg elsif ( $cmd eq "q" ) { 584a5ae21e4Smrg printf " ...quit\r\n"; 585a5ae21e4Smrg last; 586a5ae21e4Smrg } 587a5ae21e4Smrg elsif ( $cmd eq "s" ) { 588a5ae21e4Smrg printf " ...save title\r\n"; 589a5ae21e4Smrg &save_title; 590a5ae21e4Smrg } 591a5ae21e4Smrg elsif ( $cmd eq "r" ) { 592a5ae21e4Smrg printf " ...restore title\r\n"; 593a5ae21e4Smrg &restore_title(0); 594a5ae21e4Smrg } 595a5ae21e4Smrg elsif ( $cmd eq "m" ) { 596a5ae21e4Smrg printf " ...set title mode\r\n"; 597a5ae21e4Smrg &set_titlemode(1); 598a5ae21e4Smrg } 599a5ae21e4Smrg elsif ( $cmd eq "M" ) { 600a5ae21e4Smrg printf " ...reset title mode\r\n"; 601a5ae21e4Smrg &set_titlemode(0); 602a5ae21e4Smrg } 603a5ae21e4Smrg} 604a5ae21e4Smrg 605a5ae21e4Smrg# when unstacking here, just use the selector used for the push 606a5ae21e4Smrgwhile ( $SP > 0 ) { 607a5ae21e4Smrg &restore_title(1); 608a5ae21e4Smrg} 609a5ae21e4Smrg 610a5ae21e4Smrg&send_command( sprintf( "%s>T", $CSI ) ); # reset title-modes to default 611a5ae21e4Smrg 612a5ae21e4Smrg&cooked; 613a5ae21e4Smrg 614a5ae21e4Smrgprintf "\x1b F" if ($opt_8); 615