How to change the OSX menubar in wxPython without any opened window? - python

I am writing a wxPython application that remains open after closing all of its windows - so you can still drag & drop new files onto the OSX dock icon (I do this with myApp.SetExitOnFrameDelete(False)).
Unfortunately if I close all the windows, the OSX menubar will only contain a "Help" menu. I would like to add at least a File/Open menu item, or just keep the menubar of the main window. Is this somehow possible in wxPython?
In fact, I would be happy with a non-wxPython hack as well (for example, setting the menu in pyobjc, but running the rest of the GUI in wxPython). wxPython development in OSX is such a hack anyway ;)
UPDATE: I managed to solve this problem using the tip from Lyndsey Ferguson. Here's what I have done:
On startup I create a window which I show and hide immediately. I set its position to (-10000,-10000) so that it does not flicker on the screen (aargh, what a dirty hack!)
I create an empty EVT_CLOSE event handler in that window so that it cannot be closed.
It seems that destroying a window resets the OSX menu, but hiding does not... So when the last window is closed, I need to show and hide this window again (hiding is necessary so that the user cannot switch to this window using the Window menu or Cmd-`)
Yeah, this is really ugly... I will be very grateful if someone comes up with a prettier solution.
UPDATE 2: Actually it can be solved in a much easier way: if we do not close the last window, only hide it. And ensure that it does not respond to menu events anymore.

Nowadays you can use wx.MenuBar.MacSetCommonMenuBar() to set the menu bar (which you have to create) that should be used when no windows are open.
If you just want a default macOS menu bar to be used (with the application and Window menus already there), this appears to be the minimal code:
menubar = wx.MenuBar()
wx.MenuBar.MacSetCommonMenuBar(menubar)
This will let your app respond to Command+Q out-of-the-box, too.
The wx.MenuItem IDs wx.ID_ABOUT and wx.ID_EXIT are special as menu items with those IDs are moved to the macOS Application menu. The docs actually refer to the application menu as the "Apple" menu (e.g. the menu described in the wx.MenuBar.OSXGetAppleMenu() function's docs is the application menu), possibly for historical reasons.

Can you create a hidden window that is offscreen somewhere? It is a hack, but I remember having to do a lot of hacks to make my wxPython-based application work correctly on Mac OS X.
Note:You'll have to disable the close button and set up that hidden window so that it doesn't show up in the Window menu.
Aside:Have you considered factoring out your GUI portion of your Python application and using PyObjC on Mac OS X? You'll get more native behaviours...

Related

Python/Tkinter - How Would I Make a Window More "Important" Than Other Application Windows

I'd like to know how I can have my window as a priority over other application windows.
For instance, even if my window was on top of an existing application window, and I happened to click on the existing application window, I don't want my window to hide behind the existing window, I want it to stay visible (in the foreground) at all times. Is this possible?
(Using overrideredirect, by the way)
For windows you can use topmost
root.wm_attributes("-topmost", 1)

PyGTK Window always on top of all 'always on top` windows

I created a PyGTK application which needs to be always on top. The transparent window redirects mouse clicks to the window below and therefore gets out of focus once you click into an underlaying window. This is the intended behaviour. In fact it should just show a little image that's always above everything.
This works well unless you use something like the libreoffice fullscreen presentation. The presentation window is marked as always on top as well and hence my window goes into the background. Even if I take it to front using Alt+Tab and then click onto the underlaying libreoffice slide (which is neccessary) my window goes into the background again.
This is a really specific question and the solution should work on both Linux and Windows. I have no idea what I should do. I just found many questions on how to have a windows always on top but none of them covering my problem.
Long story short: How can I put my window always on top of every window that is always on top as well?
Simple Answer: You can use 'Always on Top' in windows with by using AutoHotKey scripts.
Follow these steps:
Install AutoHotKey
Create a new AHK scripts following the images
Add this code ^SPACE:: Winset, Alwaysontop, , A
Next, double-click your script to run it. You’ll know it’s running
because a green “H” logo appears in your system tray to let you know
it’s running as a background process.
Now press Ctrl+Space to set any currently active window to be always
on top. Press Ctrl+Space again set the window to no longer be always
on top.

Open a pyglet window without taking focus

My python application launches a subprocess that creates a pyglet window. When the pyglet window opens, it is in front of all other windows, and takes keyboard focus. I'd like my pyglet window to open in the background, and not take focus. Is this possible?
Stripped-down version of the code I'm using:
import pyglet
pyglet.window.Window()
pyglet.app.run()
I'm using Windows 7, in case that makes a difference..
Reversing focus is OS specific:
pyglet does not provide OS specific window control. So most likely you will have to use an ad-hoc trick for quick&dirty solutions or try to approach it with extensions like pywin32 using Windows API and/or COM to list through the stack of taskbar applications to reverse stealing of focus. You can also try to create your own window (container - which you can manipulate) first - in order to delegate its context to pyglet.
Delaying stealing of focus
On the other hand if according to your program logic you just want to delay actual showing of you application you can play with visibility:
import pyglet
w = pyglet.window.Window()
w.set_visible(False)
pyglet.app.run()
So if you don't want to play with delegation of window context, you can probably do the following:
start your application w/o showing the window
find the focus of the current active window by getting its handle/id
show your window
give back the focus to the previous window
The above assumes working with windows API. I think MSDN had examples on focus changing.. If you know PID of your current window (main application) this should simplify the step 2.
I am thinking this might be more of a windows / window manager issue than your app - will something like this http://pcsupport.about.com/od/windowsxp/ht/stealingfocus02.htm help ??

How to move application window to current workspace?

My application has "Bring to current desktop" option in indicator menu. Now, moving windows across workspaces is nice and easy if you are not using Compiz.
My question is how could I bring application window to current desktop. Application is written in Python and GTK+. I tried using Present method of gtk.Window but then window grabs focus and nothing else happens (window is not actually presented to user). I also tried playing with wnck, but that method works only when Compiz is not running.
Any idea?

NSWindow launched from statusItem menuItem does not appear as active window

I have a statusItem application written in PyObjC. The statusItem has a menuItem which is supposed to launch a new window when it is clicked:
# Create statusItem
statusItem = NSStatusBar.systemStatusBar().statusItemWithLength_(NSVariableStatusItemLength)
statusItem.setHighlightMode_(TRUE)
statusItem.setEnabled_(TRUE)
statusItem.retain()
# Create menuItem
menu = NSMenu.alloc().init()
menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Preferences', 'launchPreferences:', '')
menu.addItem_(menuitem)
statusItem.setMenu_(menu)
The launchPreferences: method is:
def launchPreferences_(self, notification):
preferences = Preferences.alloc().initWithWindowNibName_('Preferences')
preferences.showWindow_(self)
Preferences is an NSWindowController class:
class Preferences(NSWindowController):
When I run the application in XCode (Build & Go), this works fine. However, when I run the built .app file externally from XCode, the statusItem and menuItem appear as expected but when I click on the Preferences menuItem the window does not appear. I have verified that the launchPreferences code is running by checking console output.
Further, if I then double click the .app file again, the window appears but if I change the active window away by clicking, for example, on a Finder window, the preferences window disappears. This seems to me to be something to do with the active window.
Update 1
I have tried these two answers but neither work. If I add in to the launchPreferences method:
preferences.makeKeyAndOrderFront_()
or
preferences.setLevel_(NSNormalWindowLevel)
then I just get an error:
'Preferences' object has no attribute
You need to send the application an activateIgnoringOtherApps: message and then send the window makeKeyAndOrderFront:.
In Objective-C this would be:
[NSApp activateIgnoringOtherApps:YES];
[[self window] makeKeyAndOrderFront:self];
I have no idea of PyObjC, never used that, but if this was Objective-C code, I'd say you should call makeKeyAndOrderFront: on the window object if you want it to become the very first front window. A newly created window needs to be neither key, nor front, unless you make it either or like in this case, both.
The other issue that worries me is that you say the window goes away (gets invisible) when it's not active anymore. This sounds like your window is no real window. Have you accidentally set it to be a "Utility Window" in Interface Builder? Could you try to manually set the window level, using setLevel: to NSNormalWindowLevel before the window is displayed on screen for the first time whether it still goes away when becoming inactive?

Categories