Closed Bug 42557 Opened 24 years ago Closed 21 years ago

`Always on Top' and `Always on Bottom' options for windows


(Core :: XUL, enhancement, P3)






(Reporter: jhrussell, Assigned: danm.moz)




(2 files, 1 obsolete file)

Feature: Hit one of two tiny buttons (or menu items, whichever) called (for now) 
"Anchor in front" and "Anchor in back", which let you lock a window either to 
stay in front, or in back, of all other windows.

For example, when you have Navigator up and maximized, and want to drag a 
hyperlink into a mail message, you often can't because you can't get both 
onscreen at the same time if one window is maximized. If you could lock the 
Navigator in back of other windows, then you could drag a hyperlink to any other 
window onscreen because the browser window would stay in back of all other 
windows, even if you selected another window from your taskbar (in Windows that 
is) unless the second window was maximized, too. The "Anchor in back" feature 
could kind of be associated with an artificial Active Desktop, which sort of 
allows the same thing, but only in Windows (and Active Desktop sucks, as we all 
know well).
No time for new features in this cycle, moving to future.
Target Milestone: --- → Future
Bug 55690 asks the question: how to add keyboard shortcuts that open a new
window in back of the current window instead of in front of it when you click a
link on a Web page. Once 55690 is solved, the question only remains: How to tell
tell a window to stay in back? I realize this bug doesn't have much to do with
56690, link in back, but I think the first step of THIS bug would be to tell a
window to go in back, and then how to stay there, and that 55690 will probably
solve half of the problem for THIS bug.

Once we figure out how to tell a Mozilla window to stay in back of at least all
other Mozilla windows, we can hook it up to any keyboard shortcut we like, as in
Depends on: 56690
Sorry for the two e-mails, but it dawned on me that this feature doesn't need to
have two buttons, just one, Anchor-in-back. Anchor-in-front is redundant --
that's what windows do by default, open in front and stay in front when they're
active. This bug actually should require merely the following:

1. Send window in back of all mozilla windows.

2. Make it stay in back of all mozilla windows via button or keyboard shortcut,
i.e. to Anchor a window.

3. Allow a reversal command/undepress a button, whichever or both.
Summary: Features "Anchor in front" and "Anchor in back", which allow the user to lock a window in front of all other windows (Anchor in front), or in back of all other windows (Anchor in back). → `Always on Top' and `Always on Bottom' options for windows
No longer depends on: 56690
Assignee: trudelle → ben
Hey, cool idea. I like this. I'm going to take this enhancement/bug for now (with 
no hope of working on it immediately -- gonna have to leave it futured). If we 
end up implementing it, it'll be a collaboration between several people, at least 
Ben and myself, anyway. Note also as Kovu mentions above the related bug 56690, 
currently claimed by Blake.
Er, was that your ghost speaking, or did you really intend to take the bug.
-> danm, cc: ben  (as opposed to -> ben, cc: '').
Assignee: ben → danm
Oh. Bug Activity is telling me I had assigned this to Ben. Har. That was not what 
I'd intended. Assigned to me and Ben cc:ed is better. Thanks masked arbitrator!
Is this feature dead? I think it would be quite cool. For instance, I leave my
MozMail window shrunken down to where all I can see is the inbox. I would like
to be able to lock it on top of all other windows so I can see when I get new mail.
Well ... depends on what you mean by "dead." I think it'd be a cool feature,
too. But I won't have time to work on it in the foreseeable future (where
foreseeable ::= two months), thus the "futured" milestone. Doesn't mean someone
else can't run with it, though.
I think this bug is invalid. It's something that, if present, should be provided
by the window manager for every window, not individual programs for some windows
and not others.
It would also be nice if the JavaScript Console and the Bookmark Manager had an
'always on top' option. I suspect it would be useful for tweaking various
Preferences too.

Leaving it 'to the window manager' might work for a few lucky WM/GUI agnostics
in the avant-garde of the Linux Desktop Experience, but for the rest of us it
might not be possible, practical or politic to, ahem, switch. And even if your
platform and resources support a WM-level solution, there's no guarantee it can
deliver the fine-grained control requested in this thread and other discussions
(see below).

As this bug report seems to have lost interest in 'always on top', please advise
as to whether this request should be forked into another bug or taken (back) to
a newsgroup / wishlist / water-cooler.

Alternatively, it could also be handled by an XUL extension.

I'm assuming that the "I don't have a spare year to spend getting up to speed on
Mozilla internals" defence is less compelling these days - thanks to
XUL/XBL/JavaScript and already existing preferences (documented and otherwise).

If so, I'm happy to set up a Window Preferences project on mozdev.
One could then configure different (open-on-top (default), popup-on-change,
always-on-top, never-on-top, open-in-the-background - any more?) persistent
policies on a per-window basis.

If, on the other hand, this would still require changes that can only be
implemented in the core, or it's so dependent on changes to Mozilla that a
separate project would be more or less redundant, then please let me know so
that I can start saving up/RTFS :-)
  My forseeable future is experiencing Lorentzian distraction.

  Here's what I think you have to do.
  (1) Get signoff on a UI change! It's probably just a little pushpin icon
somewhere off in a corner. But UI is contentious. Be prepared to defend
yourself. Start with mail to It might be more palatable
if you planned to implement the UI part as an (optional) extension.
  (2) Back end implementation. This is largely done. Windows already (largely!)
know how to support the alwaysRaised and alwaysLowered features. You
just want to hook in to that code. I said "largely." This is well supported on
Windows, and it's supported on the Mac though with perhaps an occasional visual
glitch. It's not supported at all on *nix.
  The Windows implementation relies on some handy hooks the OS gives us. The
Mac's implementation is hand-spun and may be adaptable to *nix. Nicest of course
would be to have OS help but I expect the window manager menagerie issue, which
is what stopped us from doing *nix when we implemented the other two, will put a
hurt on that. Regardless, it's Mozilla internals you need to modify.
  (3) Hook up 1 and 2. You'll have to expose the back end implementation to
script and be careful not to compromise the security system, which doesn't allow
content script to control window layering without permission. (Meaning, the
script exposure will have to be through a component, not a property of the
window object, which is what you wanted, anyway.)

  The main technical challenge is implementing window layering on *nix.
*** Bug 189321 has been marked as a duplicate of this bug. ***
Blocks: 216426
Target Milestone: Future → mozilla1.6alpha
The back-end part of the implementation of this feature. I'll make a simple UI
later, and I plan to package it as an extension, rather than fogging up the
base browser UI with it. This patch does these things:

makes the nsIXULWindow::zLevel property writeable
adds top/bottom capability to nsIWidget::PlaceBehind
makes case of zLevel methods and variables consistent
reduces duplicate code in nsWindowMediator
Attachment #132080 - Flags: review?(
While we're waiting, I've made these tweaks to the original patch (we're not
prepared to cancel the z-level change, and I'm swapping in Brendan's Elegant
Comma Operator).

@@ -234,4 +234,3 @@
     // step through all windows, back to front
-    windows->HasMoreElements(&more);
-    for ( ; more; windows->HasMoreElements(&more)) {
+    while (windows->HasMoreElements(&more), more) {
       nsCOMPtr<nsISupports> nextWindow;
@@ -271,3 +270,3 @@
       if (event) {
-        event->InitEvent(NS_LITERAL_STRING("windowZLevel"),
                          PR_TRUE, PR_TRUE);
+        event->InitEvent(NS_LITERAL_STRING("windowZLevel"),
                          PR_TRUE, PR_FALSE);
         PRBool noDefault;
@@ -1966,4 +1965,3 @@
   PRBool more;
-  windowEnumerator->HasMoreElements(&more);
-  for ( ; more; windowEnumerator->HasMoreElements(&more)) {
+  while (windowEnumerator->HasMoreElements(&more), more) {
     PRUint32 nextZ; // z-level of nextWindow
Comment on attachment 132080 [details] [diff] [review]
make nsIXULWindow::zLevel property mutable

>+  // disallow user script
>+  nsCOMPtr<nsIScriptSecurityManager> secMan =
>+  if (!secMan)
>+    return NS_ERROR_FAILURE;
>+  PRBool inChrome;
>+  if (NS_FAILED(secMan->SubjectPrincipalIsSystem(&inChrome)) || !inChrome)
>+    return NS_ERROR_FAILURE;

I can't actually see the point of this. Unless I'm missing something, the only
way to get to set the zlevel is through this convoluted sequence of statements:
const Interfaces = Components.interfaces;
var ifreq = aWin.QueryInterface(Interfaces.nsIInterfaceRequestor);
var webnav = ifreq.getInterface(Interfaces.nsIWebNavigation);
var dsti = webnav.QueryInterface(Interfaces.nsIDocShellTreeItem);
var treeowner = dsti.treeOwner;
ifreq = treeowner.QueryInterface(Interfaces.nsIInterfaceRequestor);
var xulwin = ifreq.getInterface(Components.interfaces.nsIXULWindow);
xulwin.zlevel = zlevel;

IIRC only chrome can do this. Also the bad news was that when I tried to alter
the zlevel it didn't appear to have any effect :-(
Been talking with Neil. This patch is much like the first but instead of
tweaking nsWindowMediator::CalculateZLevel to be able to handle a list with
out-of-order elements I've added a new method nsIWindowMediator::CorrectZOrder.
Changed from the first patch are:

nsIWindowMediator.idl -- wasn't in previous patch
nsWindowMediator.cpp,h -- a bit more minor cleanup. also:
  UpdateWindowTimeStamp: more duplicate code coalesced
  CalculateZPosition: now largely unchanged, but duplicate code coalesced
		      and see mCorrectingZOrder
  SetZPosition: same as CalculateZPosition
  CorrectZOrder: new method
  SetZLevel: much simpler. that was the point of this version of the patch.

also see comment 14. Also, from comment 15, we've worked out what the problem
was with the patch seemingly not working for Neil. And the system script check
is still in there. It's almost certainly unnecessary but it makes me feel
better. I'm ready to remove it if someone with an authoritative demeanour tells
me that content script can never, ever get to this method.
Attachment #132080 - Attachment is obsolete: true
Attachment #132545 - Flags: review?(
Attachment #132080 - Flags: review?(
Now you've done it. Got bored waiting to check in the second patch. I also
intend to check this patch in. It's arguably an extension of the above patch.
This was Neil's idea: it supports a persistent zlevel XUL window attribute.
Doesn't hook it up. Just makes it work if someone cares to hook it up in the
XUL. This is a patch on top of the above patch, it's not a whole new patch.

This also cleans up the process of restoring persistent attributes as a new XUL
window is created and should reduce Txul times noticeably.
Comment on attachment 132545 [details] [diff] [review]
make nsIXULWindow::zLevel property mutable

For completeness (although I still don't really like the sorting algorithm but
the one checked in is better than the one here).
Attachment #132545 - Flags: review?( → review+
(Rather modified versions of) the two patches have been checked in for a couple
of days. Any trunk build 20031007 or later will include them. I've noticed no
bugs filed that would seem to be caused by them. No doubt that's largely because
most of the code is difficult to exercise without a UI. Still this bug seems
closeable. That only took three years.

A UI for this enhancement is available as an extension. Search or
for "Window Layers."
Closed: 21 years ago
Resolution: --- → FIXED
Good work, DanM. Thanks for taking the time to implement this cool feature. :)

Question: Because there's no UI in Moz, is this feature even going to be noticed
by users? I'd also like to make sure the Firebird and Thunderbird folks hear
about it for possible inclusion into those apps.
I've added localstore.rdf entries to force a normal level help window :-)
Kovu: thanks! As features go, I figure this one is in the class of things
that'll be very popular with a very small set of people. I think you're right,
most folks will probably never discover it. But it doesn't seem like it deserves
to be part of the base UI. It is mentioned in the two extensions websites. You
have to know where to look for it but it's not unadvertised.

Neil: So that was your secret plan all along! It makes an ungainly kind of
preference, but I'm glad you're getting mileage from it.
DanM: I disagree. The reason I filed this bug was because I couldn't drag links
from my browser into an e-mail message. Draggable links are useful; you can use
them in AOL because the AOL app has its own subwindows; we could accomplish the
same thing by calling this feature "Web top" or something like that;
View-->Webtop ???
> Neil: So that was your secret plan all along! It makes an ungainly kind of
> preference, but I'm glad you're getting mileage from it.
Well, it will be less ungainly once I figure out how to make SetZLevel
automatically update the attribute on the document element.
Kovu: Clearly you're in the group of people who likes the feature. I still have
this feeling it's a small group. Personally I can't justify a built-in UI. If
you'd like a built-in UI, file an enhancement bug against Mozilla XP Apps and,
um, Firebird General, I guess. You'll have to be convincing. If it's accepted,
and hopefully it won't take as much time as it did for me to write the
back-end!, I'll be happy to shut down my then-redundant extension.

I'm glad you mentioned mail messages. Just found bug 222042.

Neil: SetZLevel should update the attribute on the <window> element if that
element's |persist| attribute contains the magic string "zlevel". I suppose if
you've found something that doesn't work as advertised, there's room for even
more new bugs.
No, it works fine! I didn't twig that it checked for persist first.
function toggleZLevel(menuitem) {
  const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceReqestor;
  var webnav = window.getInterface(Components.interfaces.nsIWebNavigation);
  var dsti = webnav.QueryInterface(Components.interfaces.nsIDocShellTreeItem);
  var ifreq = dsti.treeOwner.QueryInterface(nsIInterfaceRequestor);
  var xulwin = ifreq.getInterface(Components.interfaces.nsIXULWindow);
  if (xulwin.zLevel > xulwin.normalZ) {
    xulwin.zLevel = xulwin.normalZ;
    menuitem.setAttribute("checked", "false");
  } else {
    xulwin.zLevel = xulwin.raisedZ;
    menuitem.setAttribute("checked", "true");
This commit have adde two "might be used uninitialized" warnings on brad TBox:

+ `PRInt32 screenRight' might be used uninitialized in this function
+ `PRInt32 screenBottom' might be used uninitialized in this function
I've checked in a change to calm the querulous compiler. Thanks for pointing
that out, Aleksey.
You need to log in before you can comment on or make changes to this bug.