123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- # -----------------------------------------------------------------------------
- # Copyright (c) 2005-2021, PyInstaller Development Team.
- #
- # Distributed under the terms of the GNU General Public License (version 2
- # or later) with exception for distributing the bootloader.
- #
- # The full license is in the file COPYING.txt, distributed with this software.
- #
- # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
- # -----------------------------------------------------------------------------
- """
- Templates for the splash screen tcl script.
- """
- from PyInstaller.compat import is_cygwin, is_darwin, is_win
- ipc_script = r"""
- proc _ipc_server {channel clientaddr clientport} {
- # This function is called if a new client connects to
- # the server. This creates a channel, which calls
- # _ipc_caller if data was send trough the connection
- set client_name [format <%s:%d> $clientaddr $clientport]
- chan configure $channel \
- -buffering none \
- -encoding utf-8 \
- -eofchar \x04 \
- -translation cr
- chan event $channel readable [list _ipc_caller $channel $client_name]
- }
- proc _ipc_caller {channel client_name} {
- # This function is called if a command was sent through
- # the tcp connection. The current implementation supports
- # two commands: update_text and exit, although exit
- # is implemented to be called if the connection gets
- # closed (from python) or the character 0x04 was received
- chan gets $channel cmd
- if {[chan eof $channel]} {
- # This is entered if either the connection was closed
- # or the char 0x04 was send
- chan close $channel
- exit
- } elseif {![chan blocked $channel]} {
- # RPC methods
- # update_text command
- if {[string match "update_text*" $cmd]} {
- global status_text
- set first [expr {[string first "(" $cmd] + 1}]
- set last [expr {[string last ")" $cmd] - 1}]
- set status_text [string range $cmd $first $last]
- }
- # Implement other procedures here
- }
- }
- # By setting the port to 0 the os will assign a free port
- set server_socket [socket -server _ipc_server -myaddr localhost 0]
- set server_port [fconfigure $server_socket -sockname]
- # This environment variable is shared between the python and the tcl
- # interpreter and publishes the port the tcp server socket is available
- set env(_PYIBoot_SPLASH) [lindex $server_port 2]
- """
- image_script = r"""
- # The variable $_image_data, which holds the data for the splash
- # image is created by the bootloader.
- image create photo splash_image
- splash_image put $_image_data
- # delete the variable, because the image now holds the data
- unset _image_data
- proc canvas_text_update {canvas tag _var - -} {
- # This function is rigged to be called if the a variable
- # status_text gets changed. This updates the text on
- # the canvas
- upvar $_var var
- $canvas itemconfigure $tag -text $var
- }
- """
- splash_canvas_setup = r"""
- package require Tk
- set image_width [image width splash_image]
- set image_height [image height splash_image]
- set display_width [winfo screenwidth .]
- set display_height [winfo screenheight .]
- set x_position [expr {int(0.5*($display_width - $image_width))}]
- set y_position [expr {int(0.5*($display_height - $image_height))}]
- # Toplevel frame in which all widgets should be positioned
- frame .root
- # Configure the canvas on which the splash
- # screen will be drawn
- canvas .root.canvas \
- -width $image_width \
- -height $image_height \
- -borderwidth 0 \
- -highlightthickness 0
- # Draw the image into the canvas, filling it.
- .root.canvas create image \
- [expr {$image_width / 2}] \
- [expr {$image_height / 2}] \
- -image splash_image
- """
- splash_canvas_text = r"""
- # Create a text on the canvas, which tracks the local
- # variable status_text. status_text is changed via C to
- # update the progress on the splash screen.
- # We cannot use the default label, because it has a
- # default background, which cannot be turned transparent
- .root.canvas create text \
- %(pad_x)d \
- %(pad_y)d \
- -fill %(color)s \
- -justify center \
- -font myFont \
- -tag vartext \
- -anchor sw
- trace variable status_text w \
- [list canvas_text_update .root.canvas vartext]
- set status_text "%(default_text)s"
- """
- splash_canvas_default_font = r"""
- font create myFont {*}[font actual TkDefaultFont]
- font configure myFont -size %(font_size)d
- """
- splash_canvas_custom_font = r"""
- font create myFont -family %(font)s -size %(font_size)d
- """
- if is_win or is_cygwin:
- transparent_setup = r"""
- # If the image is transparent, the background will be filled
- # with magenta. The magenta background is later replaced with transparency.
- # Here is the limitation of this implementation, that only
- # sharp transparent image corners are possible
- wm attributes . -transparentcolor magenta
- .root.canvas configure -background magenta
- """
- elif is_darwin:
- # This is untested, but should work following: https://stackoverflow.com/a/44296157/5869139
- transparent_setup = r"""
- wm attributes . -transparent 1
- . configure -background systemTransparent
- .root.canvas configure -background systemTransparent
- """
- else:
- # For Linux there is no common way to create a transparent window
- transparent_setup = r""
- align_windows = r"""
- # Position all widget in the window
- pack .root
- grid .root.canvas -column 0 -row 0 -columnspan 1 -rowspan 2
- # Set position and mode of the window
- wm overrideredirect . 1
- wm geometry . +${x_position}+${y_position}
- wm attributes . -topmost 1
- raise .
- """
- def build_script(text_options=None):
- """
- This function builds the tcl script for the splash screen.
- """
- # Order is important!
- script = [
- ipc_script,
- image_script,
- splash_canvas_setup,
- ]
- if text_options:
- # If the default font is used we need a different syntax
- if text_options['font'] == "TkDefaultFont":
- script.append(splash_canvas_default_font % text_options)
- else:
- script.append(splash_canvas_custom_font % text_options)
- script.append(splash_canvas_text % text_options)
- script.append(transparent_setup)
- script.append(align_windows)
- return '\n'.join(script)
|