File: pygadgets-products/unzipped/windowicons.py

"""
[SA] shamelessly adapted (mostly stolen) from frigcal's code
"""

import os, sys
from tkinter import Tk, Toplevel, PhotoImage

RunningOnMac     = sys.platform.startswith('darwin')    # all Mac OS (X)
RunningOnWindows = sys.platform.startswith('win')       # all Windows
RunningOnLinux   = sys.platform.startswith('linux')     # all Linux


def trySetWindowIcon(window, icondir='icons', iconname='pygadgets', altprefix='../../'):
    """
    ----------------------------------------------------------------------
    Replace a Tk() or Toplevel() window's generic Tk icon with a custom
    icon for the client program.  This is inherently platform-specific: 

      Windows:
        uses '.ico' files and iconbitmap() in all Tks to set the 
        icon used for window borders and taskbar entries

      Linux: 
        uses '.gif' files and Tk 8.5+'s iconphoto() to set app-bar 
        icon; there may be additional options, not used here

      Mac:
        is not supported (icons on Mac require an app bundle), but 
        is ruled out explicitly to avoid a generic border icon

    Where applicable, the icon is applied to main window and all popup 
    windows, including dialogs (they are inherited in window trees).

    Note that the use of GIF files on Linux stems from limitations
    of Tk's PhotoImage(): PNGs work in Tk 8.6+ and most types work 
    with a third-party Pillow install, but Tk 8.5- is largely GIFs. 

    The altprefix is for bundling and structure differences.  PyGadgets
    spawns gadgets in its own folder for apps and source, and frozen 
    exes and executables run in a common install folder (all '.'), but 
    standalone source-code gadgets may run in their own folders (../..).

    Caveat: under Tk 8.6, the app-bar icon isn't currently set on Linux 
    for PyClock only (despite mutiple recoding attempts).  All other 
    gadgets do set their icon on Linux using the same image file and 
    identical code; this happens whether Pillow is used or not; the icon 
    file's pathname is valid; and the Tk call that sets icons for Linux 
    runs without exceptions.  TBD, but this seems a bug in Linux Tk 8.6.
    ----------------------------------------------------------------------
    """
    if not isinstance(window, (Tk, Toplevel)):
        print('Cannot set icon on non-toplevel widget')
        return 

    if not os.path.exists(icondir):
        icondir = altprefix + icondir   # e.g., not in '.': try other

    iconname += '.ico' if RunningOnWindows else '.gif'
    iconpath = os.path.join(icondir, iconname)
    iconpath = os.path.normpath(iconpath)

    try:
        if RunningOnWindows:
            # Windows (only?), all contexts
            window.iconbitmap(default=iconpath)     # this and all its children
            
        elif RunningOnLinux:
            # Linux (only?), Tk 8.5+, app bar
            imgobj = PhotoImage(file=iconpath)
            window.iconphoto(True, imgobj)          # arg1 is default= setting
            window._pygadgets_icon_image = imgobj   # save reference (required?)
            
        elif RunningOnMac or True:
            # Mac OS X: neither of the above work, use app bundles instead
            raise NotImplementedError

    except Exception as why:
        pass   # bad file or platform



[Home page] Books Code Blog Python Author Train Find ©M.Lutz