OK people, there is a good, pleasant and correct solution without any problems.
First, I want to explain why the Windows GUI process goes into the background when wx.Frame.Show (MyFrame, False) is called.
A very short explanation and skipping details is what Windows considers Window and the application to be the same.
those. The main element of the MS Windows application is your main GUI window.
So, when this window is hidden, the application no longer has a GUI and continues to run in the background.
Mac OS X considers the application your application, and any windows you choose for this are its children, so to speak.
This allows you to launch the application without displaying any windows, except for the menu bar, from which you can select the action that then created the desired window.
It is very convenient for editors, where you can have several files that open immediately, each in its own window, and when you close the last one, you can still open a new one or create an empty one, etc. etc.
Therefore, the main element of the Mac OS X application is the application itself, so it remains open after the last window is logically hidden. Destroying its menu bar will also not help. The application name will remain present in the Dock in both the application switcher and Force Quit. You can switch to it and do nothing .: D But, fortunately, the Mac provides us with a feature to put it in the background. And this function is already mentioned by setApplicationActivationPolicy () from the NSApp object.
The problem was naming it in the Python AppKit, which is NSApp.setActivationPolicy_ (). To complicate matters, it is not available directly from the Python interactive shell, but it must be called from at least the imported module.
Why? I have no idea. In any case, here is a complete example to run the application in the background, which will work on Mac and Windows.
I have not tried this on Linux, which combines the behavior of Mac and Windows with regard to the application, so is it enough to hide the window, which is not yet visible.
Feel free to try and submit editing to make the example more cross-platform.
Example:
""" This app will show you small window with the randomly generated code that will confirm that reopened window is still the same app returned from background, and the button allowing you to send it to background. After you send it to background, wait 8 seconds and application will return to foreground again. Too prove that the application is continuing its work in the background, the app will call wx.Bell() every second. You should hear the sound while app is in the foreground and when it is in background too. Merry Christmas and a happy New Year! """ import wx import random, sys if sys.platform=="darwin": from AppKit import NSBundle, NSApp, NSAutoreleasePool, NSApplicationActivationPolicyRegular, NSApplicationActivationPolicyProhibited # Use Info.plist values to know whether our process started as daemon # Also, change this dict in case anyone is later checking it (eg some module) # Note: Changing this dict doesn't change Info.plist file info = NSBundle.mainBundle().infoDictionary() def SendToBackground (): # Change info, just in case someone checks it later info["LSUIElement"] = "1" NSApp.setActivationPolicy_(NSApplicationActivationPolicyProhibited) def ReturnToForeground (): # Change info, just in case someone checks it later info["LSUIElement"] = "0" NSApp.setActivationPolicy_(NSApplicationActivationPolicyRegular) else: # Simulate Mac OS X App - Info.plist info = {"LSUIElement": "0"} # Assume non background at startup # If programmer chose not to display GUI at startup then she/he should change this before calling ReturnToForeground() # To preserve consistency and allow correct IsDaemon() answer def SendToBackground (): info["LSUIElement"] = "1" def ReturnToForeground (): info["LSUIElement"] = "0" def IsDaemon (): return info["LSUIElement"]=="1" class Interface (wx.Frame): def __init__ (self): wx.Frame.__init__(self, None, -1, "Test", pos=(100, 100), size=(100, 100)) wx.StaticText(self, -1, "Test code: "+str(random.randint(1000, 10000)), pos=(10, 10), size=(80, 20)) b = wx.Button(self, -1, "DAEMONIZE ME", size=(80, 20), pos=(10, 50)) wx.EVT_BUTTON(self, b.GetId(), self.OnDaemonize) self.belltimer = wx.Timer(self) wx.EVT_TIMER(self, self.belltimer.GetId(), self.OnBellTimer) self.belltimer.Start(1000) # On Mac OS X, you wouldn't be able to quit the app without the menu bar: if sys.platform=="darwin": self.SetMenuBar(wx.MenuBar()) self.Show() def OnBellTimer (self, e): wx.Bell() def OnDaemonize (self, e): self.Show(False) SendToBackground() self.timer = wx.Timer(self) wx.EVT_TIMER(self, self.timer.GetId(), self.OnExorcize) self.timer.Start(8000) def OnExorcize (self, e): self.timer.Stop() ReturnToForeground() self.Show() self.Raise() app = wx.App() i = Interface() app.MainLoop()
Of course, this example can be run from the terminal or using the CLI window. In this case, the terminal control over your program will remain open until the application appears and disappears.
To complete the GUI daemon, you must run it using pythonw (on Windows) or run it from the daemontest.pyw file,
and on Mac you should use:
% nohup python daemontest.py &
either link it to py2app or use the Python launcher that comes with the python.org version of Python to run daemontest.py without a terminal.
Note. This example suffers from the same flaw in Mac OS X that is mentioned in the links that I put in my question. I mean the problem of incorrect focus and the menu bar, which does not appear immediately when the application comes from the background. The user must switch and return to the newly received application for it to work correctly. Hope someone solves this. And so on. This is pretty annoying.
One more note. If there are threads in your program, pause them during the demo and exile. Especially if they are communicating with another application using Apple events. To be honest, something about wx.Timers needs to be done too. If you are not careful, you may have problems with the non-existent NSAutoreleasePool and / or SegmentationFault after the program terminates.