Skip to content

Commit

Permalink
Merge pull request #2007 from pupil-labs/cu-72t9b7
Browse files Browse the repository at this point in the history
Ensure windows are visible when recovering a session
  • Loading branch information
papr committed Sep 10, 2020
2 parents 008d906 + 8a85c53 commit 91cb5f1
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 5 deletions.
9 changes: 8 additions & 1 deletion pupil_src/launchables/eye.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,15 @@ def toggle_general_settings(collapsed):
width, height = session_settings.get("window_size", default_window_size)

main_window = glfw.glfwCreateWindow(width, height, title, None, None)
window_pos = session_settings.get("window_position", window_position_default)

window_position_manager = gl_utils.WindowPositionManager()
window_pos = window_position_manager.new_window_position(
window=main_window,
default_position=window_position_default,
previous_position=session_settings.get("window_position", None),
)
glfw.glfwSetWindowPos(main_window, window_pos[0], window_pos[1])

glfw.glfwMakeContextCurrent(main_window)
cygl.utils.init()

Expand Down
18 changes: 16 additions & 2 deletions pupil_src/launchables/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,13 +356,20 @@ def get_dt():
width += icon_bar_width
width, height = session_settings.get("window_size", (width, height))

window_pos = session_settings.get("window_position", window_position_default)
window_name = f"Pupil Player: {meta_info.recording_name} - {rec_dir}"

glfw.glfwInit()
glfw.glfwWindowHint(glfw.GLFW_SCALE_TO_MONITOR, glfw.GLFW_TRUE)
main_window = glfw.glfwCreateWindow(width, height, window_name, None, None)

window_position_manager = gl_utils.WindowPositionManager()
window_pos = window_position_manager.new_window_position(
window=main_window,
default_position=window_position_default,
previous_position=session_settings.get("window_position", None),
)
glfw.glfwSetWindowPos(main_window, window_pos[0], window_pos[1])

glfw.glfwMakeContextCurrent(main_window)
cygl.utils.init()
g_pool.main_window = main_window
Expand Down Expand Up @@ -836,7 +843,6 @@ def on_drop(window, count, paths):
)
session_settings.clear()
w, h = session_settings.get("window_size", (1280, 720))
window_pos = session_settings.get("window_position", window_position_default)

glfw.glfwInit()
glfw.glfwWindowHint(glfw.GLFW_SCALE_TO_MONITOR, glfw.GLFW_TRUE)
Expand All @@ -845,7 +851,15 @@ def on_drop(window, count, paths):
glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, 1)

glfw.glfwMakeContextCurrent(window)

window_position_manager = gl_utils.WindowPositionManager()
window_pos = window_position_manager.new_window_position(
window=window,
default_position=window_position_default,
previous_position=session_settings.get("window_position", None),
)
glfw.glfwSetWindowPos(window, window_pos[0], window_pos[1])

glfw.glfwSetDropCallback(window, on_drop)

glfont = fontstash.Context()
Expand Down
9 changes: 8 additions & 1 deletion pupil_src/launchables/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,8 +514,15 @@ def handle_notifications(noti):
if hide_ui:
glfw.glfwWindowHint(glfw.GLFW_VISIBLE, 0) # hide window
main_window = glfw.glfwCreateWindow(width, height, "Pupil Capture - World")
window_pos = session_settings.get("window_position", window_position_default)

window_position_manager = gl_utils.WindowPositionManager()
window_pos = window_position_manager.new_window_position(
window=main_window,
default_position=window_position_default,
previous_position=session_settings.get("window_position", None),
)
glfw.glfwSetWindowPos(main_window, window_pos[0], window_pos[1])

glfw.glfwMakeContextCurrent(main_window)
cygl.utils.init()
g_pool.main_window = main_window
Expand Down
1 change: 1 addition & 0 deletions pupil_src/shared_modules/gl_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@

from .utils import *
from .trackball import *
from .window_position_manager import WindowPositionManager
85 changes: 85 additions & 0 deletions pupil_src/shared_modules/gl_utils/window_position_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""
(*)~---------------------------------------------------------------------------
Pupil - eye tracking platform
Copyright (C) 2012-2020 Pupil Labs
Distributed under the terms of the GNU
Lesser General Public License (LGPL v3.0).
See COPYING and COPYING.LESSER for license details.
---------------------------------------------------------------------------~(*)
"""
import logging
import platform
import typing as T

import glfw


class WindowPositionManager:
def __init__(self):
pass

@staticmethod
def new_window_position(
window,
default_position: T.Tuple[int, int],
previous_position: T.Optional[T.Tuple[int, int]],
) -> T.Tuple[int, int]:

if previous_position is None:
return default_position

os_name = platform.system()

if os_name == "Darwin":
# The OS handle re-positioning windows with invalid positions
return previous_position

elif os_name == "Linux":
# The OS handle re-positioning windows with invalid positions
return previous_position

elif os_name == "Windows":

def validate_previous_position(monitor) -> bool:
return _will_window_be_visible_in_monitor(
window=window,
monitor=monitor,
window_position=previous_position,
)

if any(validate_previous_position(m) for m in glfw.glfwGetMonitors()):
return previous_position
else:
return default_position

else:
raise NotImplementedError(f"Unsupported system: {os_name}")


def _will_window_be_visible_in_monitor(
window, monitor, window_position, min_visible_width=30, min_visible_height=20
) -> bool:
# Get the current window size and edges, and monitor rect
window_size = glfw.glfwGetWindowSize(window)
window_edges = glfw.glfwGetWindowFrameSize(window)
monitor_rect = glfw.glfwGetMonitorWorkarea(monitor)

# Calculate what the title bar rect would be
# if the proposed `window_position` would be the actual window position
title_bar_rect = glfw._Rectangle(
x=window_position[0] - window_edges.left,
y=window_position[1] - window_edges.top,
width=window_size[0] + window_edges.left + window_edges.right,
height=window_edges.top,
)

# Calculate the part of the title bar that is visible in the monitor, if any
visible_rect = title_bar_rect.intersection(monitor_rect)

# Return true if the visible title bar rect is big enough
return (
visible_rect is not None
and min_visible_width <= visible_rect.width
and min_visible_height <= visible_rect.height
)
80 changes: 80 additions & 0 deletions pupil_src/shared_modules/glfw.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
from ctypes.util import find_library

import logging
import typing as T

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -424,6 +425,7 @@ class GLFWmonitor(Structure):
glfwGetPrimaryMonitor = _glfw.glfwGetPrimaryMonitor
glfwGetPrimaryMonitor.restype = POINTER(GLFWmonitor)
# glfwGetMonitorPos = _glfw.glfwGetMonitorPos
# glfwGetMonitorWorkarea = _glfw.glfwGetMonitorWorkarea
# glfwGetMonitorPhysicalSize = _glfw.glfwGetMonitorPhysicalSize
glfwGetMonitorName = _glfw.glfwGetMonitorName
glfwGetMonitorName.restype = c_char_p
Expand All @@ -450,6 +452,7 @@ class GLFWmonitor(Structure):
glfwSetWindowSizeLimits = _glfw.glfwSetWindowSizeLimits
glfwSetWindowSize = _glfw.glfwSetWindowSize
# glfwGetFramebufferSize = _glfw.glfwGetFramebufferSize
# glfwGetWindowFrameSize = _glfw.glfwGetWindowFrameSize
glfwIconifyWindow = _glfw.glfwIconifyWindow
glfwRestoreWindow = _glfw.glfwRestoreWindow
glfwShowWindow = _glfw.glfwShowWindow
Expand Down Expand Up @@ -517,6 +520,37 @@ class GLFWmonitor(Structure):
__py_callbacks__ = {}


class _Margins(T.NamedTuple):
left: int
top: int
right: int
bottom: int


class _Rectangle(T.NamedTuple):
x: int
y: int
width: int
height: int

def intersection(self, other: "_Rectangle") -> T.Optional["_Rectangle"]:
in_min_x = max(self.x, other.x)
in_min_y = max(self.y, other.y)

in_max_x = min(self.x + self.width, other.x + other.width)
in_max_y = min(self.y + self.height, other.y + other.height)

if in_min_x < in_max_x and in_min_y < in_max_y:
return _Rectangle(
x=in_min_x,
y=in_min_y,
width=in_max_x - in_min_x,
height=in_max_y - in_min_y,
)
else:
return None


def glfwGetError():
_glfwGetError = _glfw.glfwGetError
_glfwGetError.argtypes = [POINTER(c_char_p)]
Expand Down Expand Up @@ -624,6 +658,17 @@ def glfwGetFramebufferSize(window):
return width.value, height.value


def glfwGetWindowFrameSize(window) -> _Margins:
""""""
left, top, right, bottom = c_int(0), c_int(0), c_int(0), c_int(0)
_glfw.glfwGetWindowFrameSize(
window, byref(left), byref(top), byref(right), byref(bottom)
)
return _Margins(
left=left.value, top=top.value, right=right.value, bottom=bottom.value
)


def glfwGetMonitors():
count = c_int(0)
_glfw.glfwGetMonitors.restype = POINTER(POINTER(GLFWmonitor))
Expand Down Expand Up @@ -656,6 +701,16 @@ def glfwGetMonitorPos(monitor):
return xpos.value, ypos.value


def glfwGetMonitorWorkarea(monitor) -> _Rectangle:
xpos, ypos, width, height = c_int(0), c_int(0), c_int(0), c_int(0)
_glfw.glfwGetMonitorWorkarea(
monitor, byref(xpos), byref(ypos), byref(width), byref(height)
)
return _Rectangle(
x=xpos.value, y=ypos.value, width=width.value, height=height.value
)


def glfwGetMonitorPhysicalSize(monitor):
width, height = c_int(0), c_int(0)
_glfw.glfwGetMonitorPhysicalSize(monitor, byref(width), byref(height))
Expand Down Expand Up @@ -761,3 +816,28 @@ def get_framebuffer_scale(window) -> float:
def window_coordinate_to_framebuffer_coordinate(window, x, y, cached_scale=None):
scale = cached_scale or get_framebuffer_scale(window)
return x * scale, y * scale


def get_window_content_rect(window) -> _Rectangle:
x, y = glfwGetWindowPos(window)
w, h = glfwGetWindowSize(window)
return _Rectangle(x=x, y=y, width=w, height=h)


def get_window_frame_rect(window) -> _Rectangle:
content_rect = get_window_content_rect(window)
frame_edges = glfwGetWindowFrameSize(window)
return _Rectangle(
x=content_rect.x - frame_edges.left,
y=content_rect.y - frame_edges.top,
width=content_rect.width + frame_edges.left + frame_edges.right,
height=content_rect.height + frame_edges.top + frame_edges.bottom,
)


def get_window_title_bar_rect(window) -> _Rectangle:
frame_rect = get_window_frame_rect(window)
frame_edges = glfwGetWindowFrameSize(window)
return _Rectangle(
x=frame_rect.x, y=frame_rect.y, width=frame_rect.width, height=frame_edges.top
)
10 changes: 9 additions & 1 deletion pupil_src/shared_modules/service_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(
self,
g_pool,
window_size=window_size_default,
window_position=window_position_default,
window_position=None,
gui_scale=1.0,
ui_config={},
):
Expand All @@ -53,7 +53,15 @@ def __init__(
if g_pool.hide_ui:
glfw.glfwWindowHint(glfw.GLFW_VISIBLE, 0) # hide window
main_window = glfw.glfwCreateWindow(*window_size, "Pupil Service")

window_position_manager = gl_utils.WindowPositionManager()
window_position = window_position_manager.new_window_position(
window=main_window,
default_position=window_position_default,
previous_position=window_position,
)
glfw.glfwSetWindowPos(main_window, *window_position)

glfw.glfwMakeContextCurrent(main_window)
cygl.utils.init()
g_pool.main_window = main_window
Expand Down

0 comments on commit 91cb5f1

Please sign in to comment.