24
24
25
25
log = logging .getLogger ( __package__ )
26
26
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' )
30
32
31
33
I_kwds = dict (
32
34
change_submits = True ,
@@ -638,13 +640,64 @@ def update_seed_recovered( window, values, details, passphrase=None ):
638
640
return f"Recovered Seed { recohex !r} doesn't match expected: { window ['-SEED-' ].get ()!r} "
639
641
640
642
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
+
641
692
def app (
642
693
names = None ,
643
694
group = None ,
644
695
threshold = None ,
645
696
cryptocurrency = None ,
646
697
edit = None ,
647
698
passphrase = None ,
699
+ scaling = None ,
700
+ no_titlebar = False ,
648
701
):
649
702
"""Convert sequence of group specifications into standard { "<group>": (<needs>, <size>) ... }"""
650
703
@@ -677,24 +730,9 @@ def app(
677
730
#
678
731
# If no name(s) supplied, try to get the User's full name.
679
732
#
680
- if not names and sys . platform == 'darwin' :
733
+ if not names :
681
734
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 () ]
698
736
except Exception as exc :
699
737
logging .exception ( f"Failed to discover user full name: { exc } " )
700
738
@@ -739,7 +777,10 @@ def app(
739
777
window ['-GROUPS-F-' ].expand ( expand_x = True )
740
778
else :
741
779
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 ,
743
784
)
744
785
timeout = 0 # First time through w/ new window, refresh immediately
745
786
@@ -1050,6 +1091,11 @@ def main( argv=None ):
1050
1091
ap .add_argument ( '--passphrase' ,
1051
1092
default = None ,
1052
1093
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" )
1053
1099
ap .add_argument ( 'names' , nargs = "*" ,
1054
1100
help = "Account names to produce" )
1055
1101
args = ap .parse_args ( argv )
@@ -1061,6 +1107,12 @@ def main( argv=None ):
1061
1107
if args .verbose :
1062
1108
logging .getLogger ().setLevel ( log_cfg ['level' ] )
1063
1109
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
+
1064
1116
try :
1065
1117
app (
1066
1118
names = args .names ,
@@ -1069,6 +1121,8 @@ def main( argv=None ):
1069
1121
cryptocurrency = args .cryptocurrency ,
1070
1122
edit = args .path ,
1071
1123
passphrase = args .passphrase ,
1124
+ no_titlebar = args .no_titlebar ,
1125
+ scaling = args .scaling ,
1072
1126
)
1073
1127
except Exception as exc :
1074
1128
log .exception ( f"Failed running App: { exc } " )
0 commit comments