[haiku] Re: Full-screen and multi-monitor handling, related: I haven't used Haiku, but from what i have seen, this is my atempt to make Haiku R2 compitable to other OSs when released

  • From: "Cyan" <cyanh256@xxxxxxxxxxxx>
  • To: haiku@xxxxxxxxxxxxx
  • Date: Sun, 21 Dec 2008 23:17:50 GMT

"Jonas Sundström" <jonas@xxxxxxxxxxx> wrote:

> Are you guys maybe over-engineering this a little?
>
> It may be that I haven't grasped the full contents
> of your discussion, but I believe that the BWindow
> Zoom code I posted shows that there's no need to 
> change anything about the app_server to make Zoom
> not overlap Deskbar.

Well, I'm a big fan of keeping things as simple as they possibly
can be, from the user's point of view, the application programmer's
point of view, and the API designer's point of view.

But adding some kind of special-case specifically for the Deskbar
doesn't really seem to solve the core issue here -- which is windows
overlapping into "forbidden" areas of the screen.
There are already quite a few launcher-type applications on Bebits,
and several users have multi-monitor configurations, potentially
with unequal sized monitors. Something that can handle forbidden
areas of the screen in a general sense as easily as possible would
be pretty desirable, I think!


From a more immediate standpoint, I've been thinking about 
implementing an application for R5 and Haiku which sits in the
background watching for new windows being opened and zoomed.
Upon detecting either condition, the window will be moved/clipped to
avoid forbidden areas of the screen.

The original motive for writing it is to make things more convenient
right now on a multi-monitor system, but as the topic of windows
overlapping the Deskbar was also brought up, it seems like this would
also solve that problem simultaneously.


> If people want to add other Deskbar-ish components
> and want other apps to not overlap these, there's 
> scripting support in BWindow, which any application
> is free to use to tell another overlapping application
> not to do so. ("hey, don't cover me")

Hmm, could you provide some examples of how this might be used?

Specifically, could it solve the overlapping problem for multiple
forbidden rectangles without any changes to applications, aside from
Deskbar and other launcher apps?



"André Braga" <meianoite@xxxxxxxxx> wrote:

> And it would solve my main grip against Mac OS and OSs using the
> concept of a zoom button in general. It makes sense to *maximise*
> the browser window, g'dammit :)

Heh, I never run browsers maximized, even on a single monitor!
A lot of sites use fixed-width designs which leaves lots of white
space at the edges if you're above their "recommended resolution",
plus there's no room for extra windows then.

I know a lot of people do though, so solving the overlap problem
would be beneficial there.


It would be nice to have a choice between fit-to-document and
zoom-to-largest-possible-size, especially in the case of a browser;
some users will expect the latter, but personally I'd always use
the former. Neither Firefox nor NetPositive support fit-to-document,
which means I spend a lot of time twiddling the width of the window
from site to site.

I'm not sure it should be a three-state mechanism like you described
though -- the main reason is this: When you perform a
fit-to-document, the window always expands rightwards and downwards
(which is good), leaving the zoom button in exactly the same place --
below the mouse.
If the zoom wasn't desired, the user can simply click it again
without performing any mouse movement.

When performing a zoom-to-largest-possible-size, the window may
expand leftwards and upwards as well, moving the tab and thus
the zoom button. Therefore the mouse needs to travel -- possibly
many thousands of pixels -- in order to reach the zoom button again.

I find this a *huge* problem under Windows where the tiny maximize
button is crammed within just a couple of pixels of the close button:
attempt to close the window, and it suddenly expands to exceed your
field of vision, leaving the mouse stranded somewhere in the middle
and the user in a state of panic. =P

(Mac OS- or GEM-style "zoom animations" could help with easing the
shock, but still, zooming a window to the maximum possible size can
be a highly surprising operation).


One solution might be to move the mouse along with the window tab,
so it retains its relative position. However I think that'd really
violate the principle of least surprise for some users. And there'd
still be an element of surprise in that it's difficult to tell what
state you've left a window in (e.g., click zoom, it expands slightly,
click it again, it restores, make a cup of tea, come back and click
zoom again and it's suddenly full-screen -- and the tea is on the
floor).


How about using the secondary mouse button (aka ctrl+click) on the
zoom button for performing zoom-to-largest-possible-size, and
defaulting to fit-to-document? We already use the secondary button
for sending a window to the background, so it might not be that
surprising?

Alternatively perhaps a double-click could work? That's also already
familiar (from hiding a window), and the first click could perform
fit-to-document without rendering the second click uncatchable
(because the tab doesn't move).



> Because your definition forbids that the legal areas overlap. Mine 
> basically mandates it :)

Aah, okay, that's the key difference here. Using legal rectangles
requires a different algorithm to the one I had in mind, which was
simply this:

1) Expand the window leftwards until it hits an illegal area,
2) Expand the window upwards until it hits an illegal area,
3) Expand the window rightwards until it hits an illegal area,
4) Expand the window downwards until it hits an illegal area.

A priority setting -- B_MAXIMUM_HORIZONTAL or B_MAXIMUM_VERTICAL --
is passed to the expansion function (or if not provided, defaults to
a system-wide value) to decide whether to flip stages 1<->2 and
3<->4, perhaps also B_MAXIMUM_BOTH to make horizontal and vertical
expansion happen simultaneously.
The purpose being to give the application a choice of which axis is
more important to maximise, if any.


Using overlapping legal areas, here's a proposed alternative
algorithm:


1) Scan through the list of legal rectangles, picking the one which
   has the largest overlapping area with the window.
   In the (likely) event of there being several equal candidates
   (usually rectangles which contain the window in its entirety),
   return all of those rectangles.

2) Out of those, choose the rectangle which provides either the most:
   a) Increase in total area,
   b) Horizontal expansion in pixels,
   c) Vertical expansion in pixels,
   depending on the setting supplied to the expansion function --
   B_MAXIMUM_AREA, B_MAXIMUM_HORIZONTAL, B_MAXIMUM_VERTICAL, or
   B_USE_SYSTEM_DEFAULT.
   Additionally, these constants could form a bitfield, where more
   than one is permitted, e.g.:
   B_MAXIMUM_AREA | B_MAXIMUM_HORIZONTAL would favour the area and
   horizontal expansion roughly equally.

3) If multiple results qualify equally, pick the top-left-most
   rectangle, which could be calculated as:
   BRect.top + BRect.left.


(2) gets a bit confusing with regard to how to sort the rectangles
in terms of desirability regarding area vs. horizontal/vertical
expansion figures. Here's a proposed algorithm for doing that, but
I've not tested it and it's probably far from perfect:

float calculate_desirability(
    float current_x_size,
    float current_y_size,
    float target_rect_x_size,
    float target_rect_y_size,
    uint8 mode
    ) {

    float total, old_area, new_area;
    float area_gained, x_gained, y_gained;

    old_area = current_x_size * current_y_size;
    new_area = target_rect_x_size * target_rect_y_size;
    area_gained = new_area - old_area;

    x_gained = target_rect_x_size - current_x_size;
    y_gained = target_rect_y_size - current_y_size;
    x_gained *= x_gained;
    y_gained *= y_gained;

    total = 0;

    if( mode & B_USE_SYSTEM_DEFAULT ) mode = get_system_default();

    if( mode & B_MAXIMUM_HORIZONTAL ) total += x_gained;
    else if( mode & B_MAXIMUM_VERTICAL ) total += y_gained;
    else if( mode & B_MAXIMUM_AREA ) total += area_gained;
    else return(0);

    return(total);
}


The target rectangle is therefore the one which yields the most
positive return value from this function (out of those rectangles
selected by criteria #1).


Zooming-to-fit (as opposed to zooming-to-fill-total-area) would be
much the same algorithm, except the rectangles are clipped to the
window's current top-left position before passing to the above
function (to account for the fact that we're only expanding
rightwards and downwards).



> I have grown used to it already, but people are often surprised by
> the lack of a maximise button.

In some ways this can be an advantage -- it forces the user to think
in a less destructive manner! ("apps belong full-screen")
Though I think this can be provided non-destructively as long as
it's treated as a secondary feature; e.g. double-click the zoom
button...


> Right; but users should never have to pay this price. This
> algorithm should only kick in for events that result in automatic
> window placement, like a new window being spawned or the zoom
> button being activated on an existing one. Under no circumnstances
> it shall kick in as a result of explicit window placement or
> resizing done by the user.

Agreed. The only area of confusion is what happens when the user
moves the Deskbar -- users of MS Windows might expect windows to be
relocated to adhere to that platform's rule of never allowing
windows to overlap the start bar. But then again if we're allowing
the users to explicitly overlap windows with the Deskbar (as we
should), then I suppose it makes sense not to perform any automatic
clipping when they move the Deskbar.

One question though: what happens when the user has "stay on top"
selected for the Deskbar, and they drag the Deskbar so it overlaps
some windows? Should the now-partially-obscured windows remain in
their existing locations?



> I'm still not sure what would the POLA-friendly behaviour of moving 
> a window to a screen with smaller legal areas than the window
> currently occupies be. Or any other action that modify the
> available areas, actually.

Hmm, I would think something like this:

- Moving a window onto a monitor which can't accommodate it should
  just cause the window to become overscanned: the user will notice
  this, move the window back and perform the adjustments 
  automatically for the programmer. ;)
  This is pretty much what happens already with workspaces under
  BeOS, and it's in-keeping with the principles of spatial
  orientation -- if the user has a large monitor next to a small
  monitor (lined up at the bottom edge), then it behaves simply like
  a massive monitor with duct tape stuck across the top-right of the
  screen, and therefore shouldn't interact with the window during
  dragging (though the mouse shouldn't be allowed to enter that
  area).

- Changing the monitor settings so that the resolution is lowered,
  or a previously-visible area of the desktop becomes invisible
  should force the windows to be moved/resized to avoid them becoming
  lost or unresizable.


That's pretty much all I have to add at the moment; I'll get around
to writing that app at some point, which can serve as a test platform
if anyone has any other ideas for zoom algorithms.

Thanks for the input, as always!

Other related posts: