[SOLVED] How to hide (and show again) the Console window from my program (Linux) lazarus / 32-Linux ---------------------------------------------------------------------- Hartmut · 2022-02-11 15:17 I've written a console program which does most of it's job in the background (something like a server). What I want is:  - when I start this program in a Terminal, it displays a couple of messages (which should be readable in the Console window for 20 seconds)  - after 20 seconds the Console window shall disappear (shall become invisible including it's entry in the TaskBar)  - when some error condition occurs, the program should be able to show the Console window again, so that error messages can be read. On Windows all this is very easy: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses Windows; begin  ShowWindow(GetConsoleWindow, SW_HIDE); // hide the console window  ShowWindow(GetConsoleWindow, SW_Show); // unhide the console windowwhich was a hint from taazz (thanks again). Does someone know, how this can be achieved in Linux? I have Ubuntu 18.04 with KDE Desktop. Thanks in advance. ---------------------------------------------------------------------- rvk · 2022-02-11 15:31 Quote from: Hartmut on February 11, 2022, 04:17:30 pm - when I start this program in a Terminal, it displays a couple of messages (which should be readable in the Console window for 20 seconds)  - after 20 seconds the Console window shall disappear (shall become invisible including it's entry in the TaskBar)  - when some error condition occurs, the program should be able to show the Console window again, so that error messages can be read. Why start the program in a terminal in that case? If you want to control the console you shouldn't start it in a terminal. I would hate for a program to just 'take over' my terminal. In my case my SSH session would be terminated (see, you don't know what 'terminal' is actually opened). So you need to think really hard if you really want to do it that way. Better would be to open your own terminal session and output there. That session you may control. ---------------------------------------------------------------------- Hartmut · 2022-02-11 16:42 Quote from: rvk on February 11, 2022, 04:31:54 pmI would hate for a program to just 'take over' my terminal. In my case my SSH session would be terminated (see, you don't know what 'terminal' is actually opened). So you need to think really hard if you really want to do it that way. Even if you wouldn't like it for your case: could you explain how it can be done? QuoteBetter would be to open your own terminal session and output there. That session you may control. Thank you for that idea. That could be another option. Do you know, how my program can open a terminal session (I'm a bloody beginner to that stuff) and output there via write() and writeln()? Which of the both options is easier to achieve? ---------------------------------------------------------------------- rvk · 2022-02-12 10:01 Quote after 20 seconds the Console window shall disappearThe only 'terminal' this would not be a problem is one in a GUI environment. For any other terminal (like SSH or console only systems) this would definitely pose a real problem. Because you can't hide that. It's not even controlled by Linux itself (for example if I start putty I just get a SSH session). So first you need to determine what you are really trying to accomplish. As I see it now, you want to show some progress and hide that window after 20 seconds. In that case you should just go for a GUI program. You can open a window, show your messages and hide it after 20 seconds. Because it's just another program, you can show that window without any problem after it gets additional errors. But if you need to program something without GUI, and you also need it to run in a terminal/SSH/console without GUI, you can't do what you want. You can only just show the messages and fork yourself to the background. The simplest way would be to start it with & at the end. You still can output text to the standard output but you can't control whether the user closes the terminal or keeps it open. There are possibilities to write your program as a service but that a bit more advanced (https://wiki.lazarus.freepascal.org/Daemons_and_Services). The benefits of a GUI application is that you can also start it from the desktop directly (no need for terminal). If you want to open a second terminal then you could just run bash or sh (and remember the pid so you could control it) but it is much easier to just use a GUI-app. Quote it's job in the background (something like a server).But if you need to write some server, you need to look at the link above about daemons and services. But in that case you need to stop thinking about the terminal and messages. You could signal a potentially running GUI about your progress, but I don't have any experience with that (I run headless systems). Maybe if you tell us something about your program and users, we could suggest a better way to do this. ---------------------------------------------------------------------- dbannon · 2022-02-12 10:52 I think I would make a GUI app that shows the user those messages via, say, TNotifier or libnotify and let the user interact, if they want to, via the System Tray Icon. Hiding console apps and them having them reappear just does not make sense. https://wiki.freepascal.org/libnotify https://wiki.freepascal.org/How_to_use_a_TrayIcon https://github.com/tomboy-notes/tomboy- ng/blob/master/source/notifier.pas TPopup Davo EDIT: added a couple of more links ---------------------------------------------------------------------- Hartmut · 2022-02-12 17:13 As I said I have written a Console Program, which is nearly finished. Switching everything into a GUI program or a daemon is not an option. Quote from: rvk on February 12, 2022, 11:01:53 amThe simplest way would be to start it with & at the end. I tried this but:  - I only see a PID, not the output of my program  - the program seems not to run really How shall this suggestion help me? QuoteIf you want to open a second terminal then you could just run bash or sh (and remember the pid so you could control it) I don't see the benefits of a second terminal, as long as I can't hide the 1st terminal. Quote from: rvk on February 11, 2022, 04:31:54 pmBetter would be to open your own terminal session and output there. That session you may control.  - How can my program open it's own terminal?  - How can it control the visibility of that window? Quote from: dbannon on February 12, 2022, 11:52:36 amI think I would make a GUI app that shows the user those messages via, say, TNotifier or libnotify and let the user interact, if they want to, via the System Tray Icon. Thanks for your posting. I know TTrayIcon and TPopupNotifier and use them in GUI programs. But in this case I want to stay with this nearly finished console program. Can you help me with this? ---------------------------------------------------------------------- rvk · 2022-02-12 19:25 Quote from: Hartmut on February 12, 2022, 06:13:15 pm - How can my program open it's own terminal?You can run sh or bash. But your program won't run standard in that. It will run in the terminal in which you opened it. You could start your program itself again with sh or bash (i.e. "sh your_program" and exit the current version). You could also use fork but then you still don't have your own window. Quote from: Hartmut on February 12, 2022, 06:13:15 pm - How can it control the visibility of that window? You could look at wmctrl or xdotool. You could do that with the version you have now. https://superuser.com/questions/186748/how-to-hide-or- minimize-x11-window-from-console https://stackoverflow.com/questions/26704195/programmatically-hide- show-a-window-in-linux But not that that will only work with a terminal in a GUI you openen. It doesn't work when the program is started via a SSH session for example. ---------------------------------------------------------------------- rvk · 2022-02-12 22:35 PS. If you don't want to use wmctrl or xdotool and want to minimize a window directly from your program via API, you need to look into XIconifyWindow. It's already defined in the X11 library xlib. I'm not sure how to use it but maybe someone else has experience with this. from xlib.pp Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function XIconifyWindow(para1:PDisplay; para2:TWindow; para3:cint):TStatus;cdecl;external libX11; https://wiki.lazarus.freepascal.org/X11 How to minimize a X11 Window: https://forum.lazarus.freepascal.org/index.php?topic=53704.0 Quote from: rsz on August 04, 2021, 11:06:23 amTake a look at how xdotool does it. It uses the XIconifyWindow function to minimize any window. Source: https://github.com/jordansissel/xdotool/blob/c3a3bf29120f295ca aec5d401d77956860a82363/xdo.c#L1965 So the function you are looking for is XIconifyWindow: https://tronche.com/gui/x/xlib/ICC/client-to-window- manager/XIconifyWindow.html ---------------------------------------------------------------------- Warfley · 2022-02-13 03:06 First, the code you have shown does not always work on Windows. If you start it from the new Windows terminal (which is standard on windows 11) it does not work (in fact, it creates a new zombie window, that the user has to close manually). Under Linux it get's even worse. People use different display servers, window Managers and terminal emulators. So while this seems sensible for a normal floating window manager like common with KDE or gnone, what about tiling WM like i3? If you there hide a window, this will reorganize and resize all other windows, and when it is then shown again this will again reorganize all other windows and after that the position and sizes of all windows will be differently. But window managers aside, one of the big differences between Windows and Linux is how console applications are started. On Windows it is usally double click, which opens the default terminal emulator executing the program. Here your application has a single console window, which is why what you are trying to do is not that bad (that said, as soon as someone uses the new Windows Terminal, this also fails as said earlier). On Linux this is not the case. Double clicking on a console Application does not open a new terminal window, in fact, it will most probably just be executed silently in the background. To use a command line program you need to explicitly call it from a terminal. So your application does not get a new fresh window but is loaded into a window that is already opend by the user. Also most terminal emulators for Linux support tabs, so what is really common on Linux, is that the user will have 1 or 2 Terminal windows always open, with multiple tabs. I for example use mostly Yakuake on KDE, which is a Terminal emulator that is always open, and is attached to an edge of the screen, and when pressing a hotkey it enters the screen from that edge and overlays all other applications until you leave the terminal (so basically the workflow is, press hotkey, type command, view results, leave terminal). And after a while I will have multiple tabs open sometimes with long running tasks (e.g. having always an HTOP open is usefull). If you would in that case just hide my terminal, you would basically hide my complete yakuake, with multiple tabs open, denying access to them. I do not need to tell you that this is a terrible idea. And I don't even want to know what happens when the Terminal emulator is part of the window manager like when you use emacs as window manager (I do actually know people who use this). In the best case, this would just hide the WM and thereby all open windows, or in the worst case (but as I know emacs as WM more probably) just crash emacs, requiring a complete restart of all open applications. Generally speaking, people do not like it when an application crashes their whole system. Then, if you want to do this, you need to interface the display server. On Linux there are currently two common display server, X11 and Wayland. So you need to check which is active and need to implement the functionality accordingly. Lastly, Linux is not a graphical system like Windows is. In many cases there simply are no windows that you could hide. SSH was already mentioned here, but there are also virtual terminals like tmux or screen sessions, or simply running Linux in Server mode without a Desktop to begin with. In fact, in Linux a terminal can be opend by multiple terminal emulators. You can have two windows showing the same terminal session. Not only that, but you can also interlace different programs on the same terminal, so that they share the same output. So there isn't even a 1-1 relationship between a terminal and a program, but rather an n-n relationship where arbitrary many programs could share arbitrary many terminals. I had a time where I had a my shell configured such that it would automatically start a TMUX session, so for me during that period, your approach simply could never work. You should not assume anything about the underlying graphical and window systems when writing a console application. This is just not what console applications are designed for. Anything you do under these assumptions will only work in a limited capacity, as seen even the windows example fails when someone is using the new Windows Terminal, rather than the old command line processor. So to sum this all up, you can't. At least not in general, and even in specifics it is probably a very bad idea. The thing is, command line programs are simply not intendet to do anything like that. This isn't that hard, but it is annyoing and something you need to keep in mind So what I think would be the best option (aside from starting from the beginning as a GUI application) is you could basically create a GUI application that emulates the terminal functionality (basically by providing a custom readln and writeln function, as well as other functions you might be using like video unit or so), and just execute your console program in a thread which is then calling these new functions rather than the console based functions ---------------------------------------------------------------------- dbannon · 2022-02-13 04:06 Nicely put Warfley. Summed it up well. I repeat - https://wiki.freepascal.org/libnotify https://wiki.freepascal.org/How_to_use_a_TrayIcon https://github.com/tomboy-notes/tomboy- ng/blob/master/source/notifier.pas Davo ---------------------------------------------------------------------- Hartmut · 2022-02-13 16:28 I have a solution: Quote from: rvk on February 12, 2022, 08:25:15 pmYou could look at wmctrl or xdotool. You could do that with the version you have now. Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i wmctrl -r -b add,shaded,skip_taskbarhides the console window including it's entry in the taskbar Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i wmctrl -r -b remove,shaded,skip_taskbarmakes both visible again. Great! Exactly what I wanted. Thanks to rvk for this suggestion and all who tried to help me. But there is 1 question / little problem left: how to identify the right window surely? I want to write a common sulution, which I easily can use for different programs. I could identify the right window by it's name (as in above example), but that could be tricky, if more similar windows names exist. Better (100% sure) would be to use the "WindowID" identified by its PID, which can be displayed like this: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i hg6@i3300:~$ wmctrl -l -p0x01e0000e -1 1379     N/A Arbeitsfläche — Plasma0x01e00016 -1 1379     N/A Arbeitsfläche — Plasma0x0340000b  0 1495     N/A Krusader0x01e0001c -1 1379     N/A Plasma0x06000006  0 3197     N/A hg6 : gmx — Konsole0x06c00006  0 5473     N/A hg6 : man — Konsole0x06e00006  0 5540     N/A hg6 : bash — Konsole0x07000006  0 5663     N/A hg6 : bgtask — Konsole         0x07200006  0 6031     N/A hg6 : man — Konsole0x06a00035  0 8060   i3300 Lazarus-IDE v2.0.10 r63526 - bgtask0x06a0003d  0 8060   i3300 Nachrichten0x06a00a67  0 8060   i3300 Quelltexteditor In above example column 1 is the "WindowID" and column3 the PID. Column 5 are the Windows names. Unfortunately in my case the PID in column 3 (5663) is not the PID of my program (see line #9), but it is the PID of the Terminal program "Konsole" (KDE) in which my program is running. So my question is: when I have the PID of my program (found by system.GetProcessID()), how can I find out the PID of the Terminal Konsole, in which my program is running (that I can find it in above list)? I assume, that there could be something like a father/child relationship. Is that possible? Or is there another (better) way for my program, to find out it's own "WindowID"? Thanks in advance. ---------------------------------------------------------------------- MarkMLl · 2022-02-13 18:20 Reading through, I think you would be better with the (GNU) Screen program (as suggested by Warfley). MarkMLl ---------------------------------------------------------------------- rvk · 2022-02-13 18:22 Quote from: Hartmut on February 13, 2022, 05:28:32 pmSo my question is: when I have the PID of my program (found by system.GetProcessID()), how can I find out the PID of the Terminal Konsole, in which my program is running (that I can find it in above list)? I assume, that there could be something like a father/child relationship. Is that possible? Or is there another (better) way for my program, to find out it's own "WindowID"? You could run ps -o ppid= to get the parent(s) pid. You'll need to step back through them to get to the correct one for the actual terminal. There could be several layers in between (depending on the system and if the terminal program has sub processes). But like Warfley explained very clearly... only do this for your own system so you know what to expect. If it was my system, that program wouldn't come near it... or it would be deleted instantly (bad design choices and such  ). ---------------------------------------------------------------------- Warfley · 2022-02-13 21:36 To get the pid you can look at what processes have the filedescriptor associated to the pseudoterminal open. The terminal emulator interacts with the terminal through the terminal pseudo file. With the command line you can easiely check this with the command "tty". Example from my linux: Code: Bash  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i $> tty/dev/pts/1You can then check which processes have that file open at which handle. If it is handle 0, 1 or 2, it is open as their standard in standard err or standard out, meaning those are themselves command line applications running on the same Terminal. If it is on another file handle, that is greater than 2, it could still be a process that just uses it for I/O (for example could you access the pseudo terminals to send messages to all open terminal sessions), but it could also be the terminal emulator. This can be done with the terminal command lsof: Code: Bash  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i $> lsof $(tty)COMMAND   PID       USER    FD    TYPE DEVICE SIZE/OFF NODE NAMEyakuake 1664 frederic    21u    CHR   136,1         0t0      4 /dev/pts/1zsh       1672 frederic      0u    CHR   136,1         0t0    4 /dev/pts/1zsh       1672 frederic      1u    CHR   136,1         0t0      4 /dev/pts/1zsh       1672 frederic      2u    CHR   136,1       0t0      4 /dev/pts/1zsh       1672 frederic    10u    CHR   136,1         0t0      4 /dev/pts/1lsof      1700 frederic      0u    CHR   136,1         0t0      4 /dev/pts/1lsof      1700 frederic      1u    CHR   136,1         0t0      4 /dev/pts/1lsof      1700 frederic      2u    CHR   136,1         0t0      4 /dev/pts/1Here you can see that both my shell and lsof have the terminal opend as console applications for stdin stdout and stderr. Besides this both my shell (zsh) and my terminal emulator yakuake have the file open seperately. The shell does so to control the terminal (for managing multi processes with Ctrl + Z, fg and bg) and my terminal emulator. So what you could do is simply do this, filter all the ones out where the file descriptor is 0-2 and the shells (which you can detect as those that have the file open as well as having 0-2 also connected to the terminal), and what is left is most probably the terminal emulator. Most probably it will also be the one with the lowest PID (but this might not be guaranteed). This is probably the most reliable method you can get. That said, it is not very reliable at all, because this is what happens when doing the same from a tmux session: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i lsof $(tty)COMMAND   PID       USER    FD    TYPE DEVICE SIZE/OFF NODE NAMEbash      1800 frederic      0u    CHR   136,2         0t0      5 /dev/pts/2bash      1800 frederic      1u    CHR   136,2         0t0    5 /dev/pts/2bash      1800 frederic      2u    CHR   136,2         0t0      5 /dev/pts/2bash      1800 frederic   255u    CHR   136,2       0t0      5 /dev/pts/2lsof      1811 frederic      0u    CHR   136,2         0t0      5 /dev/pts/2lsof      1811 frederic      1u    CHR   136,2         0t0      5 /dev/pts/2lsof      1811 frederic      2u    CHR   136,2         0t0      5 /dev/pts/2As you can see there is no terminal emulator, not even tmux itself is listed (you probably would need to be root to see that). But as I already said in my earlier post, tmux makes your endeavor pretty much completely impossible to begin with. Also the parent process method does not work with tmux, because then the tmux server is the parent of the process, and the tmux clients can connect to the server as visual interface. So as soon as tmux is involved (or screen, docker or any other similar program), there is no way to associate the terminal that is showing the program with the one which actually hosts the program Besides this, you should be aware that wmctrl is an X11 utility and will not work under wayland. Wayland now is the default display server for Fedora and Red Hat, Ubuntu, Debian and Manjaro Gnome. So basically pretty much all major Gnome based distributions use Wayland by default. So even in the limited capabilities that such an approach can even work, and is not immediately removed by the user because it disrupts their whole system, it will not work on a very large share of Linux systems anyway (I think GNOME might even make up a majority of Desktop Environments) ---------------------------------------------------------------------- Hartmut · 2022-02-15 16:48 Thanks again to rvk and Warfley for the new informations. Now I have 2 good possibilities to find out the correct PID.