prevent windows from opening offscreen

Need help with a script? This is the place to discuss how to get your code running!

prevent windows from opening offscreen

Postby taroface » Fri Oct 06, 2017 8:38 am

There must be an obvious solution to this, but I can't find it in search...

How would one detect that most/all of a window has opened offscreen, and automatically adjust its position to place its edge at the border? I don't want to default to using screenLoc as I don't want too many windows to pile up there.

Thanks for any help...!
taroface
 
Posts: 9
Joined: Sun Jul 30, 2017 2:02 pm

Re: prevent windows from opening offscreen

Postby codegreen » Fri Oct 06, 2017 10:21 am

Depending on whether you want to move your wd if it's mostly or just partially offscreen (and assuming it will actually fit), one of these should help:

Code: Select all
on openWindow
  if not windowIsMostlyVisible() then pinWindow
  -- if not wdIsCompletelyVisible() then pinWindow
end openWindow

function windowIsMostlyVisible
  local sr = the screenRect
  if vis of menuBar then add 45 to item 2 of sr
  return the loc of this wd = pinRect(sr, the loc of this wd)
end windowIsMostlyVisible

function wdIsCompletelyVisible
  local sr = the screenRect, tl = the topLeft of this wd, br = the botRight of this wd
  if vis of menuBar then add 45 to item 2 of sr
  return tl = pinRect(sr, tl) and br = pinRect(sr, br)
end wdIsCompletelyVisible

on pinWindow
  local sr = the screenRect
  if vis of menuBar then add 45 to item 2 of sr
  enum l = item 1 of sr, t = item 2 of sr, r = item 3 of sr, b = item 4 of sr
  hide this wd
  if the left of this wd < l then set the left of this wd to l + 1
  if the top of this wd < t then set the top of this wd to t + 1
  if the right of this wd > r then set the right of this wd to r - 1
  if the bottom of this wd > b then set the bottom of this wd to b - 1
  show this wd
end pinWindow

If you have multiple monitors and you want to change the top 'pin' value depending on whether the window is on a monitor that has a menu bar, I think that might require an external...

-Mark
codegreen
 
Posts: 1556
Joined: Mon Jul 14, 2008 11:03 pm

Re: prevent windows from opening offscreen

Postby codegreen » Fri Oct 06, 2017 2:27 pm

Some minor tweaks to the above:

Code: Select all
on pinWindow
  local sr = availableBounds()
  enum l = item 1 of sr, t = item 2 of sr, r = item 3 of sr, b = item 4 of sr
  hide this wd
  if the left of this wd < l then set the left of this wd to l + 1
  if the top of this wd < t then set the top of this wd to t + 1
  if the right of this wd > r then set the right of this wd to r - 1
  if the bottom of this wd > b then set the bottom of this wd to b - 1
  show this wd
end pinWindow

function windowIsMostlyVisible
  return the loc of this wd = pinRect(availableBounds(), the loc of this wd)
end windowIsMostlyVisible

function wdIsCompletelyVisible
  local r = availableBounds(), tl = the topLeft of this wd, br = the botRight of this wd
  return tl = pinRect(r, tl) and br = pinRect(r, br)
end wdIsCompletelyVisible

function availableBounds
  local r = the screenRect
  add iif(vis of menuBar and screenRect(1) = r, 43, 22) to item 2 of r
  return r
end availableBounds

It should now properly position standard windows on all displays (whether they contain the menu bar or not). If your client has no title bar, you'll want to adjust availableBounds accordingly. You could add a function easily enough automate that calculation based on the window type too if you feel frisky...

HTH,
-Mark
codegreen
 
Posts: 1556
Joined: Mon Jul 14, 2008 11:03 pm

Re: prevent windows from opening offscreen

Postby codegreen » Fri Oct 06, 2017 3:01 pm

Or even better:

Code: Select all
on pinWindow
  local sr = the maximumRect of this wd
  enum l = item 1 of sr, t = item 2 of sr, r = item 3 of sr, b = item 4 of sr
  hide this wd
  if the left of this wd < l then set the left of this wd to l
  if the top of this wd < t then set the top of this wd to t
  if the right of this wd > r then set the right of this wd to r
  if the bottom of this wd > b then set the bottom of this wd to b
  show this wd
end pinWindow

function windowIsMostlyVisible
  return the loc of this wd = pinRect(the maximumRect of this wd, the loc of this wd)
end windowIsMostlyVisible

function wdIsCompletelyVisible
  local r = the maximumRect of this wd, tl = the topLeft of this wd, ¬
    br = the botRight of this wd
  return tl = pinRect(r, tl) and br = pinRect(r, br)
end wdIsCompletelyVisible

I totally forgot that handy property existed...

:oops:
-Mark
codegreen
 
Posts: 1556
Joined: Mon Jul 14, 2008 11:03 pm

Re: prevent windows from opening offscreen

Postby codegreen » Fri Oct 06, 2017 4:12 pm

This is all well and good I suppose, but it still feels too clever by half for something xtalk scripters might commonly need to do (i.e., constrain a window to the screen). And it doesn't even account for the obvious edge case of a window being too big to fit without resizing...

So I just added a command to automate it all:

Code: Select all
  constrain <wdDesc> [to [main] monitor|screen [<index>]]

This breaks down to four forms:

Code: Select all
  constrain <wdDesc>

  constrain <wdDesc> to monitor|screen

  constrain <wdDesc> to main monitor|screen

  constrain <wdDesc> to monitor|screen <monitorNumber>

The device specifier is optional, but you can add to monitor|screen for readability even if you just want the default. If none is supplied, the device that contains the largest portion of the window (or if the window is completely offscreen, the one with the menu bar) is used.

You can specify the target device using either main or its one-based index (i.e., monitor <N>).

The window's structure widths (which vary by OS version) are automatically accounted for. If the window is too big to fit, it will be resized.

If the window is already contained entirely on one display, the command does nothing.

The target window must be open for this all to work. If it's not then no script error is thrown, but the command is ignored and the result is set to "Window not open."

HTH,
-Mark
codegreen
 
Posts: 1556
Joined: Mon Jul 14, 2008 11:03 pm

Re: prevent windows from opening offscreen

Postby taroface » Mon Oct 09, 2017 3:07 pm

Amazing, thank you very much! I’ll try this out soon :)
taroface
 
Posts: 9
Joined: Sun Jul 30, 2017 2:02 pm

Re: prevent windows from opening offscreen

Postby taroface » Sun Feb 11, 2018 2:54 pm

Mark, thanks again for your help on this.

I wasn’t clear on how to implement the last snippets you posted, so I tried the others. On window open, they are returning “Expected a boolean/long integer” error messages, and not consistently (sometimes it works; sometimes it throws an error). Do you have any idea why this might be happening?

Also, the code doesn’t seem to be working with the existing code I use to position windows when they are opened, i.e. “set the topLeft of wd X to the loc of wd Y”. It only works when I escape those specific lines. Let me know if you have ideas for a workaround!
taroface
 
Posts: 9
Joined: Sun Jul 30, 2017 2:02 pm

Re: prevent windows from opening offscreen

Postby codegreen » Tue Feb 13, 2018 7:35 am

taroface wrote: On window open, they are returning “Expected a boolean/long integer” error messages, and not consistently (sometimes it works; sometimes it throws an error). Do you have any idea why this might be happening?

My guess is you're trying to run the script in 4.7x rather than a 4.8 beta. For that you'd need a few minor tweaks (since 4.7 doesn't support initializing local variables in their declaration):

Code: Select all
on openWindow
  if not wdIsCompletelyVisible() then pinWindow
  --  if not windowIsMostlyVisible() then pinWindow
end openWindow

on pinWindow
  put the maximumRect of this wd into sr
  enum l = item 1 of sr, t = item 2 of sr, r = item 3 of sr, b = item 4 of sr
  hide this wd
  if the left of this wd < l then set the left of this wd to l
  if the top of this wd < t then set the top of this wd to t
  if the right of this wd > r then set the right of this wd to r
  if the bottom of this wd > b then set the bottom of this wd to b
  show this wd
end pinWindow

function windowIsMostlyVisible
  return the loc of this wd = pinRect(the maximumRect of this wd, the loc of this wd)
end windowIsMostlyVisible

function wdIsCompletelyVisible
  put the maximumRect of this wd into r
  put the topLeft of this wd into tl
  put the botRight of this wd into br
  return tl = pinRect(r, tl) and br = pinRect(r, br)
end wdIsCompletelyVisible

For future reference, when errors you don't understand pop up like this try opening the message box (Command-M), entering trace on, and repeating whatever threw the error. This should drop you into the Tracer at (or at least near) the line responsible. Even if you don't grok what it means, posting a screen shot will help others here figure out what's happening.

Of course you don't really need to put these properties into local variables before banging them together (though it may be slightly faster and/or more legible). For your purposes these should work just as well:

Code: Select all
on pinWindow
  hide this wd
  if the left of this wd < item 1 of the maximumRect of this wd
  then set the left of this wd to item 1 of the maximumRect of this wd
  if the top of this wd < item 2 of the maximumRect of this wd
  then set the top of this wd to item 2 of the maximumRect of this wd
  if the right of this wd > item 3 of the maximumRect of this wd
  then set the right of this wd to item 3 of the maximumRect of this wd
  if the bottom of this wd > item 4 of the maximumRect of this wd
  then set the bottom of this wd to item 4 of the maximumRect of this wd
  show this wd
end pinWindow

function wdIsCompletelyVisible
  return topLeft of this wd = pinRect(maximumRect of this wd, topLeft of this wd) ¬
    and botRight of this wd = pinRect(maximumRect of this wd, botRight of this wd)
end wdIsCompletelyVisible

Also, the code doesn’t seem to be working with the existing code I use to position windows when they are opened, i.e. “set the topLeft of wd X to the loc of wd Y”. It only works when I escape those specific lines.

Not quite sure what you mean there...

-Mark
codegreen
 
Posts: 1556
Joined: Mon Jul 14, 2008 11:03 pm


Return to Scripting in SuperTalk

Who is online

Users browsing this forum: No registered users and 1 guest