Programmatically setting the Mac menubar title - macos

How do I change the application title in the Mac menu bar programmatically (after starting the application)?
I know that I can set it before running the program via CFBundleName in the Info.plist file. However, I need to change it after initializing the application. Manipulating my own Info.plist also won't work.
There is no official API to do so, but in this discussion someone hinted that there is a secret function call that changes the bundle name / menubar title:
"There is SPI you can use if you look hard enough around for it, but
I'm not going to point anybody to it unless they can justify why they
need to use it :-)"
I think Java uses something similar, too. So what's the secret API?

OK, I've found a way. This is the code in Python (taken from here). It could use some cleaning and some error handling, but it works. The key is the undocumented CPSSetProcessName from ApplicationServices.
def _osx_set_process_name(app_title):
""" Change OSX application title """
from ctypes import cdll, c_int, pointer, Structure
from ctypes.util import find_library
app_services = cdll.LoadLibrary(find_library("ApplicationServices"))
if app_services.CGMainDisplayID() == 0:
print "cannot run without OS X window manager"
else:
class ProcessSerialNumber(Structure):
_fields_ = [("highLongOfPSN", c_int),
("lowLongOfPSN", c_int)]
psn = ProcessSerialNumber()
psn_p = pointer(psn)
if ( (app_services.GetCurrentProcess(psn_p) < 0) or
(app_services.SetFrontProcess(psn_p) < 0) ):
print "cannot run without OS X gui process"
print "setting process name"
app_services.CPSSetProcessName(psn_p, app_title)
return False
If you call it right away, it changes the process name in the Activity Monitor. I had to call it after a small timeout for some reason to also change the Menubar name:
import gobject
gobject.timeout_add(100, _osx_set_process_name, "MyTitle")
Note that if you combine this with an .app package you can get a really nice system integration of a python app. While you can change the Icon, the Finder display name, ..., all methods I tried leave the CFBundleName (the one in the Menu bar) to "Python". (This answer for example only changes the long name (displayed over dock icons). There are plenty others that almost work.)
While this answer gives the intended result, it's not very elegant. I'd appreciate some insight into why I need the timeout... I think Python or pygtk changes the process name itself when I first import gtk or run the main loop.

Related

How to implement a dock icon notification indicator with Electron in OS X?

I don't actually know the thing's name, I am talking about the red dot on the right top corner of app icon.
I'll have to make some assumptions here because I don't own a Mac to test this with. I believe that those red dots on the corner of an app icon are referred to as badges. In Electron's App module there are methods to get/set the badge along with other dock features. Check out http://electron.atom.io/docs/v0.30.0/api/app/ for more information. Here are the relevant methods:
app.dock.setBadge(text)
text String Sets the string to be displayed in the dock’s badging
area.
Note: This API is only available on Mac.
app.dock.getBadge()
Returns the badge string of the dock.
Note: This API is only available on Mac.
My guess is the code to produce the dot that you see in the example from Slack that you provided would look something like this:
var app = require('app');
app.dock.setBadge('.');
you can also try this
app.setBadgeCount(numberOfNotifiations)
What I usually do is simply increase the current badge count by 1, like so:
app.setBadgeCount(app.getBadgeCount() + 1)
see https://electron.atom.io/docs/all/#appsetbadgecountcount-linux-macos

How do I set program title and icon in Clutter toolkit?

I have recently been learning how to program with the Clutter GUI toolkit. One thing I haven't been able to figure out is how to set the programs title and icon for the window manager.
As illustrated in the image below, Gnome Shell says that the program name is "Unknown" and that the program does not have an icon.
So, how do I do this?
you cannot do this from Clutter: the windowing system API inside Clutter only allows basic operations.
if you want proper integration in a windowing system you should use Clutter-GTK, and embed a ClutterStage into a Gtk application.
In theory, you can do that in this way:
let stage = Clutter.Stage.get_default ();
let gdkWind = ClutterGdk.get_stage_window (stage);
// The list most containt icons in different sizes.
let list = [GdkPixbuf.Pixbuf.new_from_file("test.png")];
gdkWind.set_icon_list(list);
//The next line not work
gdkWind.set_title("This title is not added");
In practice, you only will can load the icon and the windows title, but not the task bar title for the windows. The set_title won't work as Gdk.Window reference say it will (https://people.gnome.org/~gcampagna/docs/Gdk-3.0/Gdk.Window.set_title.html). Is then a Clutter issue, because is not a GDK "special case". But well is not working.

Building a gui app using wxPython

Am building a gui app using wxpython,i have created two separate windows in two different files,i.e app1.py and app2.py,I want to open the 2nd window(app2.py) using a button click on first window(app1.py). How do i achieve this. It would be great if someone can help,Thanks!!
I am assuming you're using wxPython's definition of "window" (i.e. anything that is actually viewable in the GUI), not the regular definition of "separate box with stuff in it and an X button in the corner" (which wxPython calls a "frame")
When I was writing my first wxPython GUI I was faced with a similar probem. I wanted actions in one panel to affect the data shown in another. My first solution was to write methods that blindly passed the request to the panel's parent until it reached the top level (my "main frame", if you will). This worked, but obviously it's a terrible solution.
My second solution was to use wxPython Events, just like catching button presses for a wx.Panel. My idea was I would create a button in one frame and bind wx.EVT_BUTTON with that button's ID in another. I made custom Events and CommandEvents. While trying to implement this solution I discovered that do not propogate and that CommandEvents will only propogate through the parents. So, if left uncaught a CommandEvent will eventually hit your "main frame" but it will never hit the second panel unless that panel happens to be a parent of where the Event came from. Obviously, this won't work for you since the parent can't be hidden but a child be visible. Plus it would leave your main frame cluttered with code and methods to delegate commands.
Finally, I found the answer! wx.lib.pubsub! Basically, you bind the button press in app1.py, just like normal. Now, in the handler you use pubsub to publish a custom message. Next, in the init for app2.py, you use pubsub to subscribe to your custom message (I like having a "message.py" where I declare all my messages as constants). When you subscribe to a message you assign a handler method, just like for events.\
Read this: http://wiki.wxpython.org/WxLibPubSub
Since you said you wanted the window to APPEAR, maybe in the init method for app2.py you call the Hide() method then when you receive the message, call Show().
When I implemented this in my application I was using wxPython2.8. I am now using 2.9 so I don't know if this is still necessary but I found that I need the top import in order to call pubsub.subscribe() and pubsub.sendMessage(). I kept getting errors otherwise. I can't remember how I figured this out, I think I saw it in a code sample and added it in a desperate attempt to make my code work. I suggest you read the documentation I linked above and try to implement your code WITHOUT that import first.
import wx
from wx.lib.pubsub import setupkwargs #I need this to force pubsub to work. I don't know why.
from wx.lib.pubsub import pub
ID_MYBUTTON = wx.NewId()
class App1(wx.Panel):
def __init__(self, parent):
wx.Panel.__init___(self, parent)
button = wx.Button(self, ID_MYBUTTON, "Show App2")
self.Bind(wx.EVT_BUTTON, self.handleButton, id=ID_MYBUTTON
def handleButton(self, event):
pubsub.sendMessage("mybutton.pressed") #send the message
class App2(wx.Window):
def __init__(self, parent):
wx.Window.__init__(self, parent)
self.Hide() #I don't want to be seen yet
pubsub.subscribe(self.gotMessage, "mybutton.pressed") #listen for the message
def gotMessage(self):
self.Show() #Now I want to be seen!
-----EDIT-----
I found this SO question that might help: Creating child frames of main frame in wxPython
Please tell us in detail what you're trying to do? wxPython also has "dialogs" which would be better than a frame if all you're doing is showing the user a message or asking for a bit more information. http://wxpython.org/docs/api/wx.Dialog-class.html
It really depends on what you're trying to accomplish. We can't help you unless you explain what problem you're trying to solve.
-----EDIT AGIAN-----
It's looking like the person asking the question did indeed want a wx.Dialog. For a tutorial, see http://zetcode.com/wxpython/dialogs/ Also see Python WX - Returning user input from wx Dialog

child QMainWindow title bar disappeared on Mac OS X (add more description)

I develop a program on mac OS X using Qt 4.8 as the title.
Now I'm facing a problem that I spent a lot of time on it but still cannot solve.
I have a QWidget (called A) which will open a QMainWindow (called B) after some operation.
When B is opened, I need A to be blocked by B, so I set A as B's parent and set the window modality of B to Qt::WindowModal.
On other platform, it works as what I thought, however, when it comes to mac, B doesn't have its own title bar, it just popped up and attached to the title bar of A. And also, the close button on the title bar of A is grey-out, which means I cannot close B by the button, I need to use an exit QAction on QMenu to close it.
When I set B's parent to 0(NULL) instead of B, then it has independent title bar just as on windows or linux, that's what I want. However it lost the property that B blocked by A.
I tried to set the windows flags such as Qt::CustomizeWindowHint and so on, but no one works.
Is there any way to keep the hierarchal relationship between A and B, and gives B an independent title bar on Mac? Thanks for everyone's help :)
ps. I tried on small program and found that this situation only happened on WindowModal (NonModal and ApplicationModal works fine)
The behavior you are describing is known as sheets on Mac OS X. As you suspected, there is a value for the window flags enum that specifies if the window is to be a sheet. Based on the documentation, it appears that calling setWindowModality() on OS X may default the window to being a sheet -- which is probably what most developers would want for most dialogs. You might try testing for and explicitly removing that flag after setting the modality and see if that helps. Alternately, you may want to check which flags are set, and see if that leads to a solution.

How do I change the icon of my Shoes App?

I was wondering if it was possible to change the my Shoes app's icon? I imagine its style-oriented, but I haven't been able to find anything on it.
Is this possible?
You can do it in Green Shoes, but you have to go under the hood a bit. Here's some very simple code I wrote for SciRuby:
class Shoes
class App
def icon filename=nil
filename.nil? ? win.icon : win.icon = filename
end
class << self
def default_icon= filename
Gtk::Window.set_default_icon(filename)
end
end
end
end
The second method is optional; you can use it to set the icon for your whole app, I think. The first method sets the icon for the current window, and you would use it like so:
DIR = Pathname.new(__FILE__).realpath.dirname.to_s
ICON_PATH = File.join(DIR, '..', 'static', 'my-icon.png')
# ...
Shoes.app :title => "My App" do
icon ICON_PATH
end
And for the default:
Shoes::App.default_icon = ICON_PATH
I use a 128x128 png file. I tried a 500x500 one and it didn't work properly. In the code above, ICON_PATH, from the root of your project directory, should be ./static/my-icon.png.
You may also need to require "gtk2" somewhere for the default_icon= method.
I don't believe this is possible from within Shoes. This is based on extensive searching, both online and in the source code.
However, there are a couple things external to Shoes that work. One is to simply change the file #{DIR}/static/shoes-icon.png, which is where the runtime pulls its icon from. The other is to change the hardcoded value in the file libshoes.so (or your OS's equivalent); you could use a hex editor, or any other editor that wouldn't mess the file up. Note that for the hardcoded editing to work without crashing, you have to replace the hardcoded string with something of the same length.
Use IcoFx. _why himself suggested this utility on the mailing list. You will find the instruction in the tutorial section of the icoFX website.
So far, I am not sure that this is actually possible. in OS X, I was able to modify the package contents to change what the plist is pointing to in terms of icons. However, when the application runs, it uses the Shoes' runtime icon.
I have no clue how you'd do this on Windows.

Resources