# "Always on top" (inc. when Screen Saver is running)



## texanpenguin (Jan 31, 2006)

I don't yet know how feasible the idea is for someone like me who hasn't got the world's most fantastic working knowledge of Cocoa, but I've got a little app I'm dying to be made, and, since noone else has made it, I'm seeing what it would involve to take it upon myself.


All I want the app to do is get the number of unread non-junk mail messages from Mail (I can do that with AppleScript), then display the number in a large red star (as though the little red mail-count on the icon had grown). The star would be freely movable (click+drag anywhere on the face), and would open Mail with a double-click.

That much of the program seems OK (*seems* OK ), but the hard thing to find is how to make some program float above all windows, and, even better, over the screensaver. There's a program, iAlert, which already does this (so it's possible), but it's expanded into something far too complex for what I'm interested in.

The point of the program would be to be able to quickly gauge how many new Mail messages I have, even when my (very useful) screensaver is running, or when I'm a long distance away from the screen.


So what's the best way to approach the development? Cocoa? Is it possible to do it in AppleScript Studio? I'd like it to be hidden from the Dock too, but I can do that myself.


----------



## fryke (Jan 31, 2006)

Hm. I have no idea, sorry.  But an additional wish for such a thing. Or rather: A different approach. Could a _screensaver_ be used to display the new messages? Can a screensaver use AppleScript or rather interact with other applications?


----------



## Mikuro (Jan 31, 2006)

A screensaver is just a Cocoa class, so you can do practically anything you can do in Cocoa (as long as it doesn't require user input, of course....although there might even be ways around that). So yeah, a screensaver could use AppleScript to grab info from another app. But then that would mean anyone who wanted to use it wouldn't have their choice of screensaver! 

I've never done this myself, but I think it could be done with Cocoa by tweaking your window's level. Screensavers use NSScreenSaverWindowLevel, which I think is the highest. I'm not sure what would happen if there were two windows with that level assigned to them. I'd bet you can set up a window using NSScreenSaverWindowLevel in such a way that it would float over an actual screensaver. But I don't know off the top of my head. (The first thing I would try is to have it periodically call [myWindow setLevel: NSScreenSaverWindowLevel] in the hopes that it would pop it above any newly-created windows of that level.)

I don't think AppleScript Studio gives you the level of control you'd need, but I've never used AppleScript Studio, so I could be mistaken.

If it can be done at all, I imagine it can be done in Cocoa.


----------



## fryke (Jan 31, 2006)

Hm... Since I'm using the simple Apple-logo user name screensaver, I'd appreciate a version of it which would have the red-star with unread-messages (if possible not only the ones in the inbox even!). That'd be so great, it could've been Apple's idea.


----------



## texanpenguin (Jan 31, 2006)

I've got a screensaver which does this already .

It's called "IconSticker" (it's on VT), and it displays the OmniWeb, Mail, and Proteus Dock icons on top of any screensaver of your choosing.

The comments insinuate that it doesn't work on Panther (because it can't copy the install receipt across in the installation I think), but if you ignore the error, and restart Mail, it's all good. I removed the Omniweb plugin, too.

It's nifty, and works (you have to restart Mail for that to happen though ), but it shows the whole Mail icon, and the icon is only visible in screensaver mode.


Thanks to Mikuro for his help; I know it's possible (the iAlert developer added that functionality like five releases ago at my request, but the program doesn't quite do what I'd like).
It makes sense that NSScreenSaverWindowLevel might work (or else cause wacky clipping issues). If two windows are set to the same level normally, what precedence is given? And if I'm using a constant checking sort of program, might that not stop the screensaver from ever actually activating?


----------



## fryke (Jan 31, 2006)

Wow. Just solved my problem. Iconstick is great - and does exactly what I want. Move on, my problem's solved.


----------



## Mikuro (Jan 31, 2006)

texanpenguin said:
			
		

> It makes sense that NSScreenSaverWindowLevel might work (or else cause wacky clipping issues). If two windows are set to the same level normally, what precedence is given?


I had thought that precedence would be given to the latest window that was assigned by that level. I had been misled by this snippet from Apple's NSWindow documentation:


> - (void)setLevelint)newLevel
> [...]
> Each level in the list groups windows within it in front of those in all preceding groups. Floating windows, for example, appear in front of all normal-level windows. *When a window enters a new level, its ordered in front of all its peers in that level.*


(Emphasis mine.) I don't know what they mean by that last part, but it seems that it does NOT apply here. I just tested it.

But I came across another solution in my tests. It seems that you can go beyond NSScreenSaverWindowLevel, even though there are no defined constants for higher levels. NSScreenSaverWindowLevel is defined as 1000. If I do [myWindow setLevel:2002], then it'll float above the screensaver. I don't understand why it needs to be 2002, but it does. You'd think anything higher than 1000 would do it, but apparently not. 2002 is the lowest number that works (at least for me). *shrug* Go figure. (It's worth noting that this clearly shows that I don't understand this completely, so I can't guarantee that this won't make your computer explode.)

Edit: Even 2002 doesn't seem to work after I changed some seemingly-inconsequential bits of code. But 2003 does. Again I *shrug*



> And if I'm using a constant checking sort of program, might that not stop the screensaver from ever actually activating?


I doubt it. AFAIK, the only thing that'll stop a screensaver from activating is user input (i.e., action from the mouse, keyboard, or other such device input). Programs should be able to do whatever they want in the background. I know it'll come up when I have downloads coming in or iTunes playing music.


----------



## texanpenguin (Feb 1, 2006)

Yes, but it won't start with DVD Player or VLC playing files. I wasn't sure if it was a consequence of those programs explicitly disabling the screensaver from starting, or if it was just a screensaver behaviour that came with video playback (or similar).

Thanks for your help, again. As a matter of interest, did you really try every window level from 1001 to 2002 before finding one that worked? Or was it pot luck?

I just personally would have given up if 1001 didn't work .


----------



## lurk (Feb 1, 2006)

There is an API for disabling the screen saver that DVD Player and the like use.


----------



## Mikuro (Feb 1, 2006)

texanpenguin said:
			
		

> Thanks for your help, again. As a matter of interest, did you really try every window level from 1001 to 2002 before finding one that worked? Or was it pot luck?
> 
> I just personally would have given up if 1001 didn't work .


Haha, no. First I tried 10000, which worked. Then I wanted to bring it down as much as I could. 1001 didn't work, 2000 didn't work, 3000 did, 2100 did, etc. I just HAD to figure out exactly where the threshold was.


----------

