2424
2525log = logging .getLogger ( __package__ )
2626
27- font = ('Courier' , 14 )
28- font_small = ('Courier' , 10 )
29- font_bold = ('Courier' , 16 , 'bold italic' )
27+
28+ disp_points = 14 # if sys.platform == 'darwin' else 9
29+ font = ('Courier' , disp_points + 0 )
30+ font_small = ('Courier' , disp_points - 4 )
31+ font_bold = ('Courier' , disp_points + 2 , 'bold italic' )
3032
3133I_kwds = dict (
3234 change_submits = True ,
@@ -638,13 +640,64 @@ def update_seed_recovered( window, values, details, passphrase=None ):
638640 return f"Recovered Seed { recohex !r} doesn't match expected: { window ['-SEED-' ].get ()!r} "
639641
640642
643+ def user_name_full ():
644+ full_name = None
645+ if sys .platform == 'darwin' :
646+ command = [ '/usr/sbin/scutil' ]
647+ command_input = "show State:/Users/ConsoleUser"
648+ elif sys .platform == 'win32' :
649+ command = [ 'net' , 'user' , os .environ ['USERNAME' ] ]
650+ command_input = None
651+ else : # assume *nix
652+ command = [ 'getent' , 'passwd' , os .environ ['USER' ] ]
653+ command_input = None
654+
655+ subproc = subprocess .run (
656+ command ,
657+ input = command_input ,
658+ capture_output = True ,
659+ encoding = 'UTF-8' ,
660+ )
661+ assert subproc .returncode == 0 and subproc .stdout , \
662+ f"{ ' ' .join ( command )!r} command failed, or no output returned"
663+
664+ if sys .platform == 'darwin' :
665+ for li in subproc .stdout .split ( '\n ' ):
666+ if 'kCGSessionLongUserNameKey' in li :
667+ # eg.: " kCGSessionLongUserNameKey : Perry Kundert"
668+ full_name = li .split ( ':' )[1 ].strip ()
669+ break
670+ elif sys .platform == 'win32' :
671+ for li in subproc .stdout .split ( '\n ' ):
672+ if li .startswith ( 'Full Name' ):
673+ # eg.: "Full Name IEUser"
674+ full_name = li [9 :].strip ()
675+ break
676+ else :
677+ # getent="perry:x:1002:1004:Perry Kundert,,,:/home/perry:/bin/bash"
678+ # >>> getent.split(':')
679+ # ['perry', 'x', '1002', '1004', 'Perry Kundert,,,', '/home/perry', '/bin/bash']
680+ pwents = subproc .stdout .split ( ':' )
681+ assert len ( pwents ) > 4 , \
682+ f"Unrecognized passwd entry: { li } "
683+ gecos = pwents [4 ]
684+ full_name = gecos .split ( ',' )[0 ] # Discard ...,building,room,phone,...
685+
686+ assert full_name , \
687+ "User's full name not found"
688+ log .info ( f"Current user's full name: { full_name !r} " )
689+ return full_name
690+
691+
641692def app (
642693 names = None ,
643694 group = None ,
644695 threshold = None ,
645696 cryptocurrency = None ,
646697 edit = None ,
647698 passphrase = None ,
699+ scaling = None ,
700+ no_titlebar = False ,
648701):
649702 """Convert sequence of group specifications into standard { "<group>": (<needs>, <size>) ... }"""
650703
@@ -677,24 +730,9 @@ def app(
677730 #
678731 # If no name(s) supplied, try to get the User's full name.
679732 #
680- if not names and sys . platform == 'darwin' :
733+ if not names :
681734 try :
682- scutil = subprocess .run (
683- [ '/usr/sbin/scutil' ],
684- input = "show State:/Users/ConsoleUser" ,
685- capture_output = True ,
686- encoding = 'UTF-8' ,
687- )
688- print ( repr ( scutil ))
689- assert scutil .returncode == 0 and scutil .stdout , \
690- "'scutil' command failed, or no output returned"
691- for li in scutil .stdout .split ( '\n ' ):
692- if 'kCGSessionLongUserNameKey' in li :
693- # eg.: " kCGSessionLongUserNameKey : Perry Kundert"
694- full_name = li .split ( ':' )[1 ].strip ()
695- log .info ( f"Current user's full name: { full_name !r} " )
696- names = [ full_name ]
697- break
735+ names = [ user_name_full () ]
698736 except Exception as exc :
699737 logging .exception ( f"Failed to discover user full name: { exc } " )
700738
@@ -739,7 +777,10 @@ def app(
739777 window ['-GROUPS-F-' ].expand ( expand_x = True )
740778 else :
741779 window = sg .Window (
742- f"{ ', ' .join ( names or [ 'SLIP-39' ] )} Mnemonic Cards" , layout , grab_anywhere = True ,
780+ f"{ ', ' .join ( names or [ 'SLIP-39' ] )} Mnemonic Cards" , layout ,
781+ grab_anywhere = True ,
782+ no_titlebar = no_titlebar ,
783+ scaling = scaling ,
743784 )
744785 timeout = 0 # First time through w/ new window, refresh immediately
745786
@@ -1050,6 +1091,11 @@ def main( argv=None ):
10501091 ap .add_argument ( '--passphrase' ,
10511092 default = None ,
10521093 help = "Encrypt the master secret w/ this passphrase, '-' reads it from stdin (default: None/'')" )
1094+ ap .add_argument ( '-s' , '--scaling' ,
1095+ default = 1 , type = float ,
1096+ help = "Scaling for display (eg. 1.5, 0.5 for high-resolution displays), if not automatically detected" )
1097+ ap .add_argument ( '--no-titlebar' , default = False , action = 'store_true' ,
1098+ help = "Avoid displaying a title bar and border on main window" )
10531099 ap .add_argument ( 'names' , nargs = "*" ,
10541100 help = "Account names to produce" )
10551101 args = ap .parse_args ( argv )
@@ -1061,6 +1107,12 @@ def main( argv=None ):
10611107 if args .verbose :
10621108 logging .getLogger ().setLevel ( log_cfg ['level' ] )
10631109
1110+ if sys .platform == 'win32' :
1111+ # Establishes a common baseline size on macOS and Windows, as long as
1112+ # SetProcessDpiAwareness( 1 ) is set, and scaling == 1.0. Ignored on macOS.
1113+ from ctypes import windll
1114+ windll .shcore .SetProcessDpiAwareness (1 )
1115+
10641116 try :
10651117 app (
10661118 names = args .names ,
@@ -1069,6 +1121,8 @@ def main( argv=None ):
10691121 cryptocurrency = args .cryptocurrency ,
10701122 edit = args .path ,
10711123 passphrase = args .passphrase ,
1124+ no_titlebar = args .no_titlebar ,
1125+ scaling = args .scaling ,
10721126 )
10731127 except Exception as exc :
10741128 log .exception ( f"Failed running App: { exc } " )
0 commit comments