Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Window Focus/Visible Events #828

Merged
merged 3 commits into from
Jan 1, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dev
- Add `t.headset.debug` to enable additional messages from the VR runtime.
- Add `lovr.headset.getFeatures`.
- Add `Model:resetBlendShapes`.
- Add `lovr.system.isWindowVisible` and `lovr.system.isWindowFocused`.
- Add `lovr.system.wasMousePressed` and `lovr.system.wasMouseReleased`.
- Add `lovr.system.get/setClipboardText`.
- Add `KeyCode`s for numpad keys.
Expand Down Expand Up @@ -120,6 +121,8 @@ dev
- Change `Image:get/set/mapPixel` to support `r16f`, `rg16f`, and `rgba16f`.
- Change `Image:getPixel` to return 1 for alpha when the format doesn't have an alpha component.
- Change stack size of `state` stack (used with `Pass:push/pop`) from 4 to 8.
- Change `lovr.focus` and `lovr.visible` to also get called for window events.
- Change `lovr.focus` and `lovr.visible` to have an extra parameter for the display type.

### Fix

Expand Down
1 change: 1 addition & 0 deletions src/api/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ extern StringEntry lovrDefaultShader[];
extern StringEntry lovrDevice[];
extern StringEntry lovrDeviceAxis[];
extern StringEntry lovrDeviceButton[];
extern StringEntry lovrDisplayType[];
extern StringEntry lovrDrawMode[];
extern StringEntry lovrDrawStyle[];
extern StringEntry lovrEffect[];
Expand Down
18 changes: 13 additions & 5 deletions src/api/l_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
#include <stdlib.h>
#include <string.h>

StringEntry lovrDisplayType[] = {
[DISPLAY_HEADSET] = ENTRY("headset"),
[DISPLAY_WINDOW] = ENTRY("window"),
{ 0 }
};

StringEntry lovrEventType[] = {
[EVENT_QUIT] = ENTRY("quit"),
[EVENT_RESTART] = ENTRY("restart"),
Expand Down Expand Up @@ -198,15 +204,17 @@ static int nextEvent(lua_State* L) {
return 2;

case EVENT_VISIBLE:
lua_pushboolean(L, event.data.boolean.value);
return 2;
lua_pushboolean(L, event.data.visible.visible);
luax_pushenum(L, DisplayType, event.data.visible.display);
return 3;

case EVENT_FOCUS:
lua_pushboolean(L, event.data.boolean.value);
return 2;
lua_pushboolean(L, event.data.focus.focused);
luax_pushenum(L, DisplayType, event.data.focus.display);
return 3;

case EVENT_MOUNT:
lua_pushboolean(L, event.data.boolean.value);
lua_pushboolean(L, event.data.mount.mounted);
return 2;

case EVENT_RECENTER:
Expand Down
14 changes: 14 additions & 0 deletions src/api/l_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,18 @@ static int l_lovrSystemIsWindowOpen(lua_State* L) {
return 1;
}

static int l_lovrSystemIsWindowVisible(lua_State* L) {
bool visible = lovrSystemIsWindowVisible();
lua_pushboolean(L, visible);
return 1;
}

static int l_lovrSystemIsWindowFocused(lua_State* L) {
bool focused = lovrSystemIsWindowFocused();
lua_pushboolean(L, focused);
return 1;
}

static int l_lovrSystemGetWindowWidth(lua_State* L) {
uint32_t width, height;
lovrSystemGetWindowSize(&width, &height);
Expand Down Expand Up @@ -329,6 +341,8 @@ static const luaL_Reg lovrSystem[] = {
{ "requestPermission", l_lovrSystemRequestPermission },
{ "openWindow", l_lovrSystemOpenWindow },
{ "isWindowOpen", l_lovrSystemIsWindowOpen },
{ "isWindowVisible", l_lovrSystemIsWindowVisible },
{ "isWindowFocused", l_lovrSystemIsWindowFocused },
{ "getWindowWidth", l_lovrSystemGetWindowWidth },
{ "getWindowHeight", l_lovrSystemGetWindowHeight },
{ "getWindowDimensions", l_lovrSystemGetWindowDimensions },
Expand Down
4 changes: 4 additions & 0 deletions src/core/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ typedef enum {
} os_permission;

typedef void fn_quit(void);
typedef void fn_visible(bool visible);
typedef void fn_focus(bool focused);
typedef void fn_resize(uint32_t width, uint32_t height);
typedef void fn_key(os_button_action action, os_key key, uint32_t scancode, bool repeat);
Expand Down Expand Up @@ -173,6 +174,7 @@ void os_thread_detach(void);

void os_poll_events(void);
void os_on_quit(fn_quit* callback);
void os_on_visible(fn_visible* callback);
void os_on_focus(fn_focus* callback);
void os_on_resize(fn_resize* callback);
void os_on_key(fn_key* callback);
Expand All @@ -184,6 +186,8 @@ void os_on_permission(fn_permission* callback);

bool os_window_open(const os_window_config* config);
bool os_window_is_open(void);
bool os_window_is_visible(void);
bool os_window_is_focused(void);
void os_window_get_size(uint32_t* width, uint32_t* height);
float os_window_get_pixel_density(void);
void os_window_message_box(const char* message);
Expand Down
12 changes: 12 additions & 0 deletions src/core/os_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ void os_on_quit(fn_quit* callback) {
state.onQuit = callback;
}

void os_on_visible(fn_visible* callback) {
//
}

void os_on_focus(fn_focus* callback) {
//
}
Expand Down Expand Up @@ -358,6 +362,14 @@ bool os_window_is_open(void) {
return false;
}

bool os_window_is_visible(void) {
return false;
}

bool os_window_is_focused(void) {
return false;
}

void os_window_get_size(uint32_t* width, uint32_t* height) {
*width = *height = 0;
}
Expand Down
28 changes: 28 additions & 0 deletions src/core/os_glfw.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ bool os_window_is_open(void) {
return false;
}

bool os_window_is_visible(void) {
return false;
}

bool os_window_is_focused(void) {
return false;
}

void os_window_get_size(uint32_t* width, uint32_t* height) {
*width = *height = 0;
}
Expand Down Expand Up @@ -123,6 +131,7 @@ uintptr_t os_get_xcb_window(void) {
static struct {
GLFWwindow* window;
fn_quit* onQuitRequest;
fn_focus* onWindowVisible;
bjornbytes marked this conversation as resolved.
Show resolved Hide resolved
fn_focus* onWindowFocus;
fn_resize* onWindowResize;
fn_key* onKeyboardEvent;
Expand All @@ -144,6 +153,12 @@ static void onWindowClose(GLFWwindow* window) {
}
}

static void onWindowVisible(GLFWwindow* window, int minimized) {
if (glfwState.onWindowVisible) {
glfwState.onWindowVisible(!minimized);
}
}

static void onWindowFocus(GLFWwindow* window, int focused) {
if (glfwState.onWindowFocus) {
glfwState.onWindowFocus(focused);
Expand Down Expand Up @@ -390,6 +405,7 @@ bool os_window_open(const os_window_config* config) {
}

glfwSetWindowCloseCallback(glfwState.window, onWindowClose);
glfwSetWindowIconifyCallback(glfwState.window, onWindowVisible);
glfwSetWindowFocusCallback(glfwState.window, onWindowFocus);
glfwSetWindowSizeCallback(glfwState.window, onWindowResize);
glfwSetKeyCallback(glfwState.window, onKeyboardEvent);
Expand All @@ -406,6 +422,14 @@ bool os_window_is_open(void) {
return glfwState.window;
}

bool os_window_is_visible(void) {
return !glfwGetWindowAttrib(glfwState.window, GLFW_ICONIFIED);
}

bool os_window_is_focused(void) {
return glfwGetWindowAttrib(glfwState.window, GLFW_FOCUSED);
}

void os_window_get_size(uint32_t* width, uint32_t* height) {
*width = glfwState.width;
*height = glfwState.height;
Expand All @@ -426,6 +450,10 @@ void os_on_quit(fn_quit* callback) {
glfwState.onQuitRequest = callback;
}

void os_on_visible(fn_focus* callback) {
glfwState.onWindowVisible = callback;
}

void os_on_focus(fn_focus* callback) {
glfwState.onWindowFocus = callback;
}
Expand Down
25 changes: 25 additions & 0 deletions src/core/os_wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

static struct {
fn_quit* onQuitRequest;
fn_visible* onWindowVisible;
fn_focus* onWindowFocus;
fn_resize* onWindowResize;
fn_key* onKeyboardEvent;
Expand All @@ -32,6 +33,14 @@ static const char* onBeforeUnload(int type, const void* unused, void* userdata)
return NULL;
}

static EM_BOOL onVisibilityChanged(int type, const EmscriptenVisibilityChangeEvent* visibility, void* userdata) {
if (state.onWindowVisible) {
state.onWindowVisible(!visibility->hidden);
return true;
}
return false;
}

static EM_BOOL onFocusChanged(int type, const EmscriptenFocusEvent* data, void* userdata) {
if (state.onWindowFocus) {
state.onWindowFocus(type == EMSCRIPTEN_EVENT_FOCUS);
Expand Down Expand Up @@ -198,6 +207,7 @@ static EM_BOOL onKeyEvent(int type, const EmscriptenKeyboardEvent* data, void* u

bool os_init(void) {
emscripten_set_beforeunload_callback(NULL, onBeforeUnload);
emscripten_set_visibilitychange_callback(CANVAS, true, onVisibilityChanged);
emscripten_set_focus_callback(CANVAS, NULL, true, onFocusChanged);
emscripten_set_blur_callback(CANVAS, NULL, true, onFocusChanged);
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, true, onResize);
Expand All @@ -216,6 +226,7 @@ bool os_init(void) {

void os_destroy(void) {
emscripten_set_beforeunload_callback(NULL, NULL);
emscripten_set_visibilitychange_callback(CANVAS, true, NULL);
emscripten_set_focus_callback(CANVAS, NULL, true, NULL);
emscripten_set_blur_callback(CANVAS, NULL, true, NULL);
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, true, NULL);
Expand Down Expand Up @@ -330,6 +341,16 @@ bool os_window_is_open(void) {
return true;
}

bool os_window_is_visible(void) {
EmscriptenVisibilityChangeEvent visibility;
emscripten_get_visibility_status(&visibility);
return !visibility.hidden;
}

bool os_window_is_focused(void) {
return true;
}

void os_window_get_size(uint32_t* width, uint32_t* height) {
*width = state.width;
*height = state.height;
Expand All @@ -343,6 +364,10 @@ void os_on_quit(fn_quit* callback) {
state.onQuitRequest = callback;
}

void os_on_visible(fn_visible* callback) {
state.onWindowVisible = callback;
}

void os_on_focus(fn_focus* callback) {
state.onWindowFocus = callback;
}
Expand Down
23 changes: 20 additions & 3 deletions src/modules/event/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
struct Thread;
struct Variant;

typedef enum {
DISPLAY_HEADSET,
DISPLAY_WINDOW
} DisplayType;

typedef enum {
EVENT_QUIT,
EVENT_RESTART,
Expand Down Expand Up @@ -86,8 +91,18 @@ typedef struct {
} QuitEvent;

typedef struct {
bool value;
} BoolEvent;
bool visible;
DisplayType display;
} VisibleEvent;

typedef struct {
bool focused;
DisplayType display;
} FocusEvent;

typedef struct {
bool mounted;
} MountEvent;

typedef struct {
uint32_t width;
Expand Down Expand Up @@ -142,7 +157,9 @@ typedef struct {

typedef union {
QuitEvent quit;
BoolEvent boolean;
VisibleEvent visible;
FocusEvent focus;
MountEvent mount;
ResizeEvent resize;
KeyEvent key;
TextEvent text;
Expand Down
10 changes: 7 additions & 3 deletions src/modules/headset/headset_openxr.c
Original file line number Diff line number Diff line change
Expand Up @@ -3752,13 +3752,17 @@ static bool openxr_update(double* dt) {
bool wasVisible = state.sessionState >= XR_SESSION_STATE_VISIBLE;
bool isVisible = event->state >= XR_SESSION_STATE_VISIBLE;
if (wasVisible != isVisible) {
lovrEventPush((Event) { .type = EVENT_VISIBLE, .data.boolean.value = isVisible });
lovrEventPush((Event) { .type = EVENT_VISIBLE, .data.visible.visible = isVisible });
}

bool wasFocused = state.sessionState == XR_SESSION_STATE_FOCUSED;
bool isFocused = event->state == XR_SESSION_STATE_FOCUSED;
if (wasFocused != isFocused) {
lovrEventPush((Event) { .type = EVENT_FOCUS, .data.boolean.value = isFocused });
lovrEventPush((Event) {
.type = EVENT_FOCUS,
.data.focus.focused = isFocused,
.data.focus.display = DISPLAY_HEADSET
});
}

state.sessionState = event->state;
Expand All @@ -3780,7 +3784,7 @@ static bool openxr_update(double* dt) {
case XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT: {
XrEventDataUserPresenceChangedEXT* event = (XrEventDataUserPresenceChangedEXT*) &e;
state.mounted = event->isUserPresent;
lovrEventPush((Event) { .type = EVENT_MOUNT, .data.boolean.value = state.mounted });
lovrEventPush((Event) { .type = EVENT_MOUNT, .data.mount.mounted = state.mounted });
break;
}
default: break;
Expand Down
19 changes: 11 additions & 8 deletions src/modules/headset/headset_simulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ static struct {
float clipFar;
} state;

static void onFocus(bool focused) {
state.focused = focused;
lovrEventPush((Event) { .type = EVENT_FOCUS, .data.boolean = { focused } });
}

static bool simulator_init(HeadsetConfig* config) {
state.config = *config;
state.clipNear = .01f;
Expand All @@ -84,8 +79,7 @@ static bool simulator_init(HeadsetConfig* config) {
state.initialized = true;
}

state.focused = true;
os_on_focus(onFocus);
state.focused = os_window_is_focused();

return true;
}
Expand Down Expand Up @@ -500,7 +494,7 @@ static bool simulator_isVisible(void) {
}

static bool simulator_isFocused(void) {
return state.focused;
return os_window_is_focused();
}

static bool simulator_isMounted(void) {
Expand All @@ -513,6 +507,15 @@ static bool simulator_update(double* dt) {
return true;
}

if (os_window_is_focused() != state.focused) {
state.focused = !state.focused;
lovrEventPush((Event) {
.type = EVENT_FOCUS,
.data.focus.focused = state.focused,
.data.focus.display = DISPLAY_HEADSET
});
}

double t = os_get_time() - state.epoch;
state.dt = t - state.time;
state.time = t;
Expand Down
Loading
Loading