Skip to content

Commit

Permalink
Window visible and focus events/getters;
Browse files Browse the repository at this point in the history
  • Loading branch information
bjornbytes committed Dec 31, 2024
1 parent 2b9e5e9 commit 854a890
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 19 deletions.
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
8 changes: 8 additions & 0 deletions src/core/os_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,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;
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

0 comments on commit 854a890

Please sign in to comment.