• Running Tk in a cron job

    From Alan Grunwald@nospam.nurdglaw@gmail.com to comp.lang.tcl on Mon Aug 3 12:37:55 2026
    From Newsgroup: comp.lang.tcl

    Hi,

    I have a Tcl script that has a GUI front-end. It also has a non-
    interactive mode (by running with a "-nogui" flag).

    If -nogui is present, then the script does [wm withdraw .] very early in startup so the GUI is never displayed.

    I would now like to run non-interactively as a cron job. In this case,
    the system displays the error

    no display name and no $DISPLAY environment variable

    I've tried to execute

    DISPLAY=localhost:0.0 wish9.0 &

    interactively but it complains that it can't connect to localhost:0.0.
    Same with localhost:1.0.

    How do I work around this?

    For information, I'm running on Linux Mint 22.3. The script does some
    web scraping and runs chrome in a subprocess, so I guess I'm going to
    need a DISPLAY at some point.

    Many thanks,
    Alan

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Robert Heller@heller@deepsoft.com to comp.lang.tcl on Mon Aug 3 13:02:03 2026
    From Newsgroup: comp.lang.tcl

    This is probably not going to work.
    What you need to do is structure your program something like this: #!/usr/bin/tclsh
    # note: tclsh, not wish above!
    if [is_GUI_interactive] {
    package require Tk
    # build the GUI here...
    } else {
    # non-interactive (no GUI) code here
    }
    The "package require Tk" will cause a "fatal" error if the DISPLAY
    envireonment variable is not defined -- the program will "crash" with an
    error.
    Unless and until "package require Tk happens, the program will be well behaved in cron's environment.
    The wish executable does an effective "package require Tk" as the first step
    of its main() function -- the wish ececutable is directly linked to libtk.so and its init code (its "main()") does the rest of what package require Tk
    does -- create the "." toplevel, etc. Doing a withdraw of . is already too late. The call the opens the X11 display has already crashed as DISPLAY is not defined (and it is not in the cron environment).
    Yes, it is perfectly possible to create a script that is both CLI safe and
    also has a GUI interface.
    Have a look at https://github.com/RobertPHeller/ModelRRSystem/blob/master/trunk/Scripts/LCC/OpenLCB_Logic.tcl
    for an example of this. This is a program that is both meant to run as a daemon (with no interaction) and with a GUI for interactive configuration purposes.
    At Mon, 3 Aug 2026 12:37:55 +0100 Alan Grunwald <nospam.nurdglaw@gmail.com> wrote:

    Hi,

    I have a Tcl script that has a GUI front-end. It also has a non-
    interactive mode (by running with a "-nogui" flag).

    If -nogui is present, then the script does [wm withdraw .] very early in startup so the GUI is never displayed.

    I would now like to run non-interactively as a cron job. In this case,
    the system displays the error

    no display name and no $DISPLAY environment variable

    I've tried to execute

    DISPLAY=localhost:0.0 wish9.0 &

    interactively but it complains that it can't connect to localhost:0.0.
    Same with localhost:1.0.

    How do I work around this?

    For information, I'm running on Linux Mint 22.3. The script does some
    web scraping and runs chrome in a subprocess, so I guess I'm going to
    need a DISPLAY at some point.

    Many thanks,
    Alan



    --
    Robert Heller -- Cell: 413-658-7953 GV: 978-633-5364
    Deepwoods Software -- Custom Software Services
    http://www.deepsoft.com/ -- Linux Administration Services
    heller@deepsoft.com -- Webhosting Services
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Alan Grunwald@nospam.nurdglaw@gmail.com to comp.lang.tcl on Mon Aug 3 16:44:24 2026
    From Newsgroup: comp.lang.tcl

    On 03/08/2026 14:02, Robert Heller wrote:
    This is probably not going to work.

    What you need to do is structure your program something like this:

    #!/usr/bin/tclsh
    # note: tclsh, not wish above!

    if [is_GUI_interactive] {
    package require Tk
    # build the GUI here...
    } else {
    # non-interactive (no GUI) code here
    }

    The "package require Tk" will cause a "fatal" error if the DISPLAY envireonment variable is not defined -- the program will "crash" with an error.

    Unless and until "package require Tk happens, the program will be well behaved
    in cron's environment.

    The wish executable does an effective "package require Tk" as the first step of its main() function -- the wish ececutable is directly linked to libtk.so and its init code (its "main()") does the rest of what package require Tk does -- create the "." toplevel, etc. Doing a withdraw of . is already too late. The call the opens the X11 display has already crashed as DISPLAY is not
    defined (and it is not in the cron environment).

    Yes, it is perfectly possible to create a script that is both CLI safe and also has a GUI interface.

    Have a look at https://github.com/RobertPHeller/ModelRRSystem/blob/master/trunk/Scripts/LCC/OpenLCB_Logic.tcl
    for an example of this. This is a program that is both meant to run as a daemon (with no interaction) and with a GUI for interactive configuration purposes.

    At Mon, 3 Aug 2026 12:37:55 +0100 Alan Grunwald <nospam.nurdglaw@gmail.com> wrote:


    Hi,

    I have a Tcl script that has a GUI front-end. It also has a non-
    interactive mode (by running with a "-nogui" flag).

    If -nogui is present, then the script does [wm withdraw .] very early in
    startup so the GUI is never displayed.

    I would now like to run non-interactively as a cron job. In this case,
    the system displays the error

    no display name and no $DISPLAY environment variable

    I've tried to execute

    DISPLAY=calhost:0.0 wish9.0 &

    interactively but it complains that it can't connect to localhost:0.0.
    Same with localhost:1.0.

    How do I work around this?

    For information, I'm running on Linux Mint 22.3. The script does some
    web scraping and runs chrome in a subprocess, so I guess I'm going to
    need a DISPLAY at some point.

    Many thanks,
    Alan




    Thanks Robert,

    The plot, I regret to say, thickens...

    My code is all wrapped into a class, which derives from a homebrew
    library class that is itself derived from another homebrew library class.

    Say application - library - superlibrary. Both library and superlibrary
    are defined within a single package, say libraryPkg

    The script currently looks like this:

    package require libraryPkg

    oo::define application {
    .
    .
    .
    }

    set app [application new[
    if {[lindex argv 0] eq "-nogui"} {
    wm withdraw .
    $app nogui
    exit
    }

    I don't think it's possible - certainly not trivial - to swap things
    around so that Tk is required only after I've detected that -nogui
    wasn't specified.

    Apologies - I oversimplified slightly in the original message - I
    actually run via tclsh, and libraryPkg requires Tk when it, itself is required.

    I have a nagging suspicion that I will need to have a display available
    when I start chromedriver, or rather when it starts chrome.

    If all this is insurmountable, I guess I'll need to go away and rework
    the code from scratch :-(


    Alan
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Robert Heller@heller@deepsoft.com to comp.lang.tcl on Mon Aug 3 17:55:54 2026
    From Newsgroup: comp.lang.tcl

    At Mon, 3 Aug 2026 16:44:24 +0100 Alan Grunwald <nospam.nurdglaw@gmail.com> wrote:

    On 03/08/2026 14:02, Robert Heller wrote:
    This is probably not going to work.

    What you need to do is structure your program something like this:

    #!/usr/bin/tclsh
    # note: tclsh, not wish above!

    if [is_GUI_interactive] {
    package require Tk
    # build the GUI here...
    } else {
    # non-interactive (no GUI) code here
    }

    The "package require Tk" will cause a "fatal" error if the DISPLAY envireonment variable is not defined -- the program will "crash" with an error.

    Unless and until "package require Tk happens, the program will be well behaved
    in cron's environment.

    The wish executable does an effective "package require Tk" as the first step
    of its main() function -- the wish ececutable is directly linked to libtk.so
    and its init code (its "main()") does the rest of what package require Tk does -- create the "." toplevel, etc. Doing a withdraw of . is already too late. The call the opens the X11 display has already crashed as DISPLAY is not
    defined (and it is not in the cron environment).

    Yes, it is perfectly possible to create a script that is both CLI safe and also has a GUI interface.

    Have a look at https://github.com/RobertPHeller/ModelRRSystem/blob/master/trunk/Scripts/LCC/OpenLCB_Logic.tcl
    for an example of this. This is a program that is both meant to run as a daemon (with no interaction) and with a GUI for interactive configuration purposes.

    At Mon, 3 Aug 2026 12:37:55 +0100 Alan Grunwald <nospam.nurdglaw@gmail.com> wrote:


    Hi,

    I have a Tcl script that has a GUI front-end. It also has a non-
    interactive mode (by running with a "-nogui" flag).

    If -nogui is present, then the script does [wm withdraw .] very early in >> startup so the GUI is never displayed.

    I would now like to run non-interactively as a cron job. In this case,
    the system displays the error

    no display name and no $DISPLAY environment variable

    I've tried to execute

    DISPLAY=calhost:0.0 wish9.0 &

    interactively but it complains that it can't connect to localhost:0.0.
    Same with localhost:1.0.

    How do I work around this?

    For information, I'm running on Linux Mint 22.3. The script does some
    web scraping and runs chrome in a subprocess, so I guess I'm going to
    need a DISPLAY at some point.

    Many thanks,
    Alan




    Thanks Robert,

    The plot, I regret to say, thickens...

    My code is all wrapped into a class, which derives from a homebrew
    library class that is itself derived from another homebrew library class.

    Say application - library - superlibrary. Both library and superlibrary
    are defined within a single package, say libraryPkg

    The script currently looks like this:

    package require libraryPkg

    oo::define application {
    .
    .
    .
    }

    set app [application new[
    if {[lindex argv 0] eq "-nogui"} {
    wm withdraw .
    $app nogui
    exit
    }

    I don't think it's possible - certainly not trivial - to swap things
    around so that Tk is required only after I've detected that -nogui
    wasn't specified.

    Apologies - I oversimplified slightly in the original message - I
    actually run via tclsh, and libraryPkg requires Tk when it, itself is required.
    This is almost always a mistake for any package where a non-GUI useage might make sense. A "package require Tk" should always be put off and conditionally invoked. Or else the package can be said to be a "GUI always" package. If
    you have control of the package consider breaking it into two packages: one package that contains the pure "computional" code (eg data structure, file-io, and all of the bits that don't relate to the GUI and than have a separate package that implements the GUI elements (which would likely do a package require on the first package). You really should never have any sort of giant mega package, but really a number separate smaller packages, each with one self-contained chunk of code -- eg a logical "functional" unit.

    I have a nagging suspicion that I will need to have a display available
    when I start chromedriver, or rather when it starts chrome.

    If all this is insurmountable, I guess I'll need to go away and rework
    the code from scratch :-(
    There is a virtual X11 server tool (a X11 server with no actual hardware
    -- screen, mouse, keyboard), at one point I needed to invesigate that to be able to use libreoffice to convert .docx files to .pdf, becasie libreoffice at one point wa "agressive" GUI (even with a commandline option "--headless"). I have since founnd pandoc, a purely command line program thay can (amoungst
    many other things can convert .docx to .pdf from the command line with out resorting to a GUI). (I complained about libreoffice's "broken" --headless option -- at first the libreoffice devs were hostile to the idea of using libreoffice in a non-GUI envirement, but I believe current versions of libreoffice now behave as I had "expected"...)


    Alan


    --
    Robert Heller -- Cell: 413-658-7953 GV: 978-633-5364
    Deepwoods Software -- Custom Software Services
    http://www.deepsoft.com/ -- Linux Administration Services
    heller@deepsoft.com -- Webhosting Services
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Alan Grunwald@nospam.nurdglaw@gmail.com to comp.lang.tcl on Wed Aug 5 07:30:15 2026
    From Newsgroup: comp.lang.tcl

    On 03/08/2026 18:55, Robert Heller wrote:
    At Mon, 3 Aug 2026 16:44:24 +0100 Alan Grunwald <nospam.nurdglaw@gmail.com> wrote:


    On 03/08/2026 14:02, Robert Heller wrote:
    This is probably not going to work.

    What you need to do is structure your program something like this:

    #!/usr/bin/tclsh
    # note: tclsh, not wish above!

    if [is_GUI_interactive] {
    package require Tk
    # build the GUI here...
    } else {
    # non-interactive (no GUI) code here
    }

    The "package require Tk" will cause a "fatal" error if the DISPLAY
    envireonment variable is not defined -- the program will "crash" with an >>> error.

    Unless and until "package require Tk happens, the program will be well behaved
    in cron's environment.

    The wish executable does an effective "package require Tk" as the first step
    of its main() function -- the wish ececutable is directly linked to libtk.so
    and its init code (its "main()") does the rest of what package require Tk >>> does -- create the "." toplevel, etc. Doing a withdraw of . is already too >>> late. The call the opens the X11 display has already crashed as DISPLAY is not
    defined (and it is not in the cron environment).

    Yes, it is perfectly possible to create a script that is both CLI safe and >>> also has a GUI interface.

    Have a look at
    https://github.com/RobertPHeller/ModelRRSystem/blob/master/trunk/Scripts/LCC/OpenLCB_Logic.tcl
    for an example of this. This is a program that is both meant to run as a >>> daemon (with no interaction) and with a GUI for interactive configuration >>> purposes.

    At Mon, 3 Aug 2026 12:37:55 +0100 Alan Grunwald <nospam.nurdglaw@gmail.com> wrote:


    Hi,

    I have a Tcl script that has a GUI front-end. It also has a non-
    interactive mode (by running with a "-nogui" flag).

    If -nogui is present, then the script does [wm withdraw .] very early in >>>> startup so the GUI is never displayed.

    I would now like to run non-interactively as a cron job. In this case, >>>> the system displays the error

    no display name and no $DISPLAY environment variable

    I've tried to execute

    DISPLAY|elhost:0.0 wish9.0 &

    interactively but it complains that it can't connect to localhost:0.0. >>>> Same with localhost:1.0.

    How do I work around this?

    For information, I'm running on Linux Mint 22.3. The script does some
    web scraping and runs chrome in a subprocess, so I guess I'm going to
    need a DISPLAY at some point.

    Many thanks,
    Alan




    Thanks Robert,

    The plot, I regret to say, thickens...

    My code is all wrapped into a class, which derives from a homebrew
    library class that is itself derived from another homebrew library class.

    Say application - library - superlibrary. Both library and superlibrary
    are defined within a single package, say libraryPkg

    The script currently looks like this:

    package require libraryPkg

    oo::define application {
    .
    .
    .
    }

    set app [application new[
    if {[lindex argv 0] eq "-nogui"} {
    wm withdraw .
    $app nogui
    exit
    }

    I don't think it's possible - certainly not trivial - to swap things
    around so that Tk is required only after I've detected that -nogui
    wasn't specified.

    Apologies - I oversimplified slightly in the original message - I
    actually run via tclsh, and libraryPkg requires Tk when it, itself is
    required.

    This is almost always a mistake for any package where a non-GUI useage might make sense. A "package require Tk" should always be put off and conditionally
    invoked. Or else the package can be said to be a "GUI always" package. If you have control of the package consider breaking it into two packages: one package that contains the pure "computional" code (eg data structure, file-io,
    and all of the bits that don't relate to the GUI and than have a separate package that implements the GUI elements (which would likely do a package require on the first package). You really should never have any sort of giant
    mega package, but really a number separate smaller packages, each with one self-contained chunk of code -- eg a logical "functional" unit.


    I have a nagging suspicion that I will need to have a display available
    when I start chromedriver, or rather when it starts chrome.

    If all this is insurmountable, I guess I'll need to go away and rework
    the code from scratch :-(

    There is a virtual X11 server tool (a X11 server with no actual hardware
    -- screen, mouse, keyboard), at one point I needed to invesigate that to be able to use libreoffice to convert .docx files to .pdf, becasie libreoffice at
    one point wa "agressive" GUI (even with a commandline option "--headless"). I
    have since founnd pandoc, a purely command line program thay can (amoungst many other things can convert .docx to .pdf from the command line with out resorting to a GUI). (I complained about libreoffice's "broken" --headless option -- at first the libreoffice devs were hostile to the idea of using libreoffice in a non-GUI envirement, but I believe current versions of libreoffice now behave as I had "expected"...)



    Alan



    You're absolutely right Robert, and it's advice I am surprised to find I hadn't followed 9 years ago when I first write the script. The problem
    has only just surfaced because until a month or two ago, I was running
    Windows on the desktop machine and the script ran perfectly happily
    under the task scheduler.

    Once you pointed out my design error it wasn't too hard to write a
    headless script that is "real close" to working when started by cron :-)

    Thanks again,


    Alan
    --- Synchronet 3.22a-Linux NewsLink 1.2