XWindows SetCursorCenter & SetCursorFocused
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m50s
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m50s
This commit is contained in:
@@ -61,6 +61,8 @@ protected:
|
||||
bool focused = true;
|
||||
bool vsync = false;
|
||||
bool cursor_visible = true;
|
||||
bool cursor_focused = false;
|
||||
bool toggling_cursor_focus = false;
|
||||
bool closing = false;
|
||||
bool key_repeat = false;
|
||||
|
||||
@@ -194,7 +196,6 @@ public:
|
||||
void Close();
|
||||
/// Closes the window immediately, potentially without allowing finalization to occur.
|
||||
void ForceClose();
|
||||
void ForceCloseAndTerminateProgram();
|
||||
|
||||
/** Display a small window with some text and an "OK" button.
|
||||
* I tried un-defining the macro, Calling it in a lambda,
|
||||
@@ -203,7 +204,7 @@ public:
|
||||
* It just wouldn't let me name it MessageBox - Redacted. */
|
||||
|
||||
/// @note Execution of the parent window is stopped while the message box is up.
|
||||
void UniqueFunctionNameForMessageBoxBecauseMicrosoftUsesMacros(const std::string& title, const std::string& message);
|
||||
void DialogOK(const std::string& title, const std::string& message);
|
||||
|
||||
/// Sets whether or not to make the window fullscreen.
|
||||
/// @note This is implemented per-OS, and as such, it simply requests the OS to do what we want. No guarantee about follow-through can be given.
|
||||
@@ -278,13 +279,17 @@ public:
|
||||
|
||||
void SetCursorCustomIcon() const;
|
||||
|
||||
void SetCursorLocked();
|
||||
/// @returns Where the cursor was just before we teleported it to the center.
|
||||
/// @note This is useful for 3D games.
|
||||
std::pair<int, int> SetCursorCenter();
|
||||
|
||||
void SetCursorCenter();
|
||||
/// Tells the operating system to not allow the cursor to go off our window.
|
||||
/// @note This is useful for 3D games.
|
||||
// TODO recreate this behavior on Windows. On X-Windows, The cursor is focused on the next mouse movement because of an X11 timing issue.
|
||||
void SetCursorFocused(bool state);
|
||||
|
||||
void RestoreCursorFromLastCenter(); // Feels nicer for users
|
||||
|
||||
/// Hides the cursor when it's inside of our window. Useful for 3D game camera.
|
||||
/// Hides the cursor when it's inside of our window.
|
||||
/// @note This is useful for 3D games.
|
||||
void SetCursorVisible(bool cursor_enable);
|
||||
|
||||
bool GetCursorVisible();
|
||||
|
11
main.cpp
11
main.cpp
@@ -69,10 +69,10 @@ int main() {
|
||||
window->SetFullscreen(false);
|
||||
window->SetVsyncEnabled(true);
|
||||
window->SetResizable(true);
|
||||
window->SetCursorVisible(false);
|
||||
window->SetKeyRepeatEnabled(true);
|
||||
window->UniqueFunctionNameForMessageBoxBecauseMicrosoftUsesMacros("MessageBox", "Generic message from a ReWindow MessageBox.");
|
||||
|
||||
//window->SetCursorVisible(true);
|
||||
window->SetKeyRepeatEnabled(false);
|
||||
//window->DialogOK("MessageBox", "Generic message from a ReWindow MessageBox.");
|
||||
window->SetCursorFocused(true);
|
||||
|
||||
Logger::Debug(std::format("Window '{}' flags: IN_FOCUS={} FULLSCREEN={} RESIZEABLE={} VSYNC={} KEY_REPEAT={} QUIT={}",
|
||||
window->GetTitle(), window->IsFocused(), window->IsFullscreen(),
|
||||
@@ -83,7 +83,8 @@ int main() {
|
||||
window->OnMouseButtonDownEvent += [&] (MouseButtonDownEvent e) { jlog::Debug(e.Button.Mnemonic + std::to_string(e.Button.ButtonIndex)); };
|
||||
window->OnMouseWheelEvent += [&, window] (MouseWheelEvent e) { std::cout << window->GetMouseWheelPersistent() << std::endl; };
|
||||
|
||||
while (!window->IsClosing())
|
||||
while (!window->IsClosing()) {
|
||||
window->ManagedRefresh();
|
||||
}
|
||||
delete window;
|
||||
}
|
@@ -77,8 +77,7 @@ void OpenGLWindow::SwapBuffers() {
|
||||
}
|
||||
|
||||
void OpenGLWindow::SetVsyncEnabled(bool state) {
|
||||
PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT;
|
||||
glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) OpenGL::glXGetProcAddressARB((const GLubyte *) "glXSwapIntervalEXT");
|
||||
auto glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) OpenGL::glXGetProcAddressARB((const GLubyte *) "glXSwapIntervalEXT");
|
||||
glXSwapIntervalEXT(platform->display, platform->window, state);
|
||||
}
|
||||
|
||||
@@ -228,6 +227,7 @@ OpenGLWindow::OpenGLWindow(const std::string& title, int width, int height, uint
|
||||
|
||||
bool OpenGLWindow::SoftwareRendered() {
|
||||
std::string renderer((const char*) OpenGL::glGetString(GL_RENDERER));
|
||||
|
||||
if (renderer.find("llvmpipe"))
|
||||
return true;
|
||||
if (renderer.find("softpipe"))
|
||||
|
@@ -53,6 +53,22 @@ platform = new Platform();
|
||||
extant = this;
|
||||
}
|
||||
|
||||
void RWindow::SetCursorFocused(bool state) {
|
||||
toggling_cursor_focus = state;
|
||||
|
||||
if (!state && cursor_focused) {
|
||||
XUngrabPointer(platform->display, CurrentTime);
|
||||
cursor_focused = state;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<int, int> RWindow::SetCursorCenter() {
|
||||
auto current_pos = GetAccurateMouseCoordinates();
|
||||
XWarpPointer(platform->display, None, platform->window, 0, 0, 0, 0, width / 2, height / 2);
|
||||
return current_pos;
|
||||
}
|
||||
|
||||
RWindow::RWindow(const std::string& wTitle, int wWidth, int wHeight, bool wFullscreen, bool wResizable, bool wVsync)
|
||||
: title(wTitle), width(wWidth), height(wHeight), fullscreen_mode(wFullscreen), resizable(wResizable), vsync(wVsync)
|
||||
{ platform = new Platform(); extant = this; }
|
||||
@@ -65,7 +81,7 @@ void RWindow::Raise() {
|
||||
XRaiseWindow(platform->display, platform->window);
|
||||
}
|
||||
|
||||
void RWindow::UniqueFunctionNameForMessageBoxBecauseMicrosoftUsesMacros(const std::string& window_title, const std::string& message) {
|
||||
void RWindow::DialogOK(const std::string& window_title, const std::string& message) {
|
||||
int padding = 10;
|
||||
|
||||
XFontStruct* font = XLoadQueryFont(platform->display, "6x13");
|
||||
@@ -82,7 +98,7 @@ void RWindow::UniqueFunctionNameForMessageBoxBecauseMicrosoftUsesMacros(const st
|
||||
WhitePixel(platform->display, platform->defaultScreen));
|
||||
|
||||
XStoreName(platform->display, window, window_title.c_str());
|
||||
XSelectInput(platform->display, window, ExposureMask | ButtonPressMask);
|
||||
XSelectInput(platform->display, window, ExposureMask | ButtonPressMask | StructureNotifyMask);
|
||||
|
||||
// No resizing.
|
||||
XSizeHints hints;
|
||||
@@ -91,19 +107,13 @@ void RWindow::UniqueFunctionNameForMessageBoxBecauseMicrosoftUsesMacros(const st
|
||||
hints.min_height = hints.max_height = dimensions.second;
|
||||
XSetWMNormalHints(platform->display, window, &hints);
|
||||
|
||||
Atom wm_delete_window = XInternAtom(platform->display, "WM_DELETE_WINDOW", False);
|
||||
XSetWMProtocols(platform->display, window, &wm_delete_window, 1);
|
||||
|
||||
XMapWindow(platform->display, window);
|
||||
GC gc = XCreateGC(platform->display, window, 0, nullptr);
|
||||
XSetForeground(platform->display, gc, BlackPixel(platform->display, platform->defaultScreen));
|
||||
|
||||
|
||||
/* TODO positioning the window to be in the center of the parent window doesn't always work.
|
||||
if (platform->window) {
|
||||
XWindowAttributes parent_window_attributes;
|
||||
XGetWindowAttributes(platform->display, platform->window, &parent_window_attributes);
|
||||
XMoveWindow(platform->display, window, (parent_window_attributes.width - dimensions.first) / 2, (parent_window_attributes.height - dimensions.second) / 2);
|
||||
}
|
||||
*/
|
||||
|
||||
XEvent event;
|
||||
while (true) {
|
||||
XNextEvent(platform->display, &event);
|
||||
@@ -114,10 +124,19 @@ void RWindow::UniqueFunctionNameForMessageBoxBecauseMicrosoftUsesMacros(const st
|
||||
XDrawRectangle(platform->display, window, gc, button_pos.first, button_pos.second, button_size.first, button_size.second);
|
||||
}
|
||||
|
||||
else if (event.type == ButtonPress)
|
||||
if (event.xbutton.x >= button_pos.first && event.xbutton.x <= button_pos.first + button_size.first
|
||||
&& event.xbutton.y >= button_pos.second && event.xbutton.y <= button_pos.second + button_size.second)
|
||||
else if (event.type == ClientMessage) {
|
||||
if (event.xclient.message_type == XInternAtom(platform->display, "WM_PROTOCOLS", False) &&
|
||||
static_cast<Atom>(event.xclient.data.l[0]) == wm_delete_window)
|
||||
break;
|
||||
}
|
||||
|
||||
else if (event.type == ButtonPress) {
|
||||
if (event.xbutton.x >= button_pos.first && event.xbutton.x <= button_pos.first + button_size.first
|
||||
&& event.xbutton.y >= button_pos.second && event.xbutton.y <= button_pos.second + button_size.second)
|
||||
break;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
XFreeFont(platform->display, font);
|
||||
@@ -133,6 +152,7 @@ void RWindow::Lower()
|
||||
void RWindow::DestroyOSWindowHandle() {
|
||||
// Turn key repeat back on.
|
||||
XAutoRepeatOn(platform->display);
|
||||
XFlush(platform->display);
|
||||
|
||||
Logger::Debug(std::format("Destroying sub-windows for window '{}'", this->title));
|
||||
XDestroySubwindows(platform->display, platform->window);
|
||||
@@ -143,8 +163,6 @@ void RWindow::DestroyOSWindowHandle() {
|
||||
XCloseDisplay(platform->display);
|
||||
}
|
||||
|
||||
//void RWindow::
|
||||
|
||||
void RWindow::SetCursorVisible(bool cursor_enable) {
|
||||
cursor_visible = cursor_enable;
|
||||
if (platform->invisible_cursor == 0) {
|
||||
@@ -193,6 +211,13 @@ void RWindow::PollEvents() {
|
||||
XAutoRepeatOff(platform->display);
|
||||
else
|
||||
XAutoRepeatOn(platform->display);
|
||||
XFlush(platform->display);
|
||||
|
||||
|
||||
if (cursor_focused) {
|
||||
cursor_focused = false;
|
||||
SetCursorFocused(true);
|
||||
}
|
||||
|
||||
if (platform->wm_hints) {
|
||||
platform->wm_hints->flags &= ~XUrgencyHint;
|
||||
@@ -209,9 +234,22 @@ void RWindow::PollEvents() {
|
||||
focused = true;
|
||||
}
|
||||
|
||||
if (platform->xev.type == UnmapNotify) {
|
||||
if (cursor_focused) {
|
||||
SetCursorFocused(false);
|
||||
cursor_focused = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (platform->xev.type == FocusOut) {
|
||||
Logger::Debug(std::format("Event '{}'", "FocusOut"));
|
||||
XAutoRepeatOn(platform->display);
|
||||
XFlush(platform->display);
|
||||
|
||||
if (cursor_focused) {
|
||||
SetCursorFocused(false);
|
||||
cursor_focused = true;
|
||||
}
|
||||
|
||||
if (!cursor_visible)
|
||||
XUndefineCursor(platform->display, platform->window);
|
||||
@@ -268,9 +306,27 @@ void RWindow::PollEvents() {
|
||||
Logger::Debug(std::format("Event '{}'", "Expose"));
|
||||
}
|
||||
|
||||
// NOTE: This event is functionally useless, as it only informs of the very beginning and end of a mouse movement.
|
||||
if (platform->xev.type == MotionNotify) {
|
||||
Logger::Debug(std::format("Event '{}'", "MotionNotify"));
|
||||
|
||||
if (toggling_cursor_focus) {
|
||||
XWindowAttributes attrs;
|
||||
XGetWindowAttributes(platform->display, platform->window, &attrs);
|
||||
|
||||
if (attrs.map_state == IsViewable) {
|
||||
int result = XGrabPointer
|
||||
(
|
||||
platform->display, platform->window, True,
|
||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
|
||||
GrabModeAsync, GrabModeAsync, platform->window, None, CurrentTime
|
||||
);
|
||||
|
||||
if (result == GrabSuccess) {
|
||||
toggling_cursor_focus = false;
|
||||
cursor_focused = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (platform->xev.type == ConfigureNotify) {
|
||||
|
@@ -256,11 +256,6 @@ bool RWindow::IsFocused() const {
|
||||
DestroyOSWindowHandle();
|
||||
}
|
||||
|
||||
void RWindow::ForceCloseAndTerminateProgram() {
|
||||
ForceClose();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
bool MouseState::IsDown(const MouseButton &btn) const {
|
||||
if (btn == MouseButtons::Left) return Buttons.LMB;
|
||||
if (btn == MouseButtons::Right) return Buttons.RMB;
|
||||
|
@@ -270,7 +270,7 @@ vsync(wVsync) {
|
||||
platform = new Platform();
|
||||
}
|
||||
|
||||
void RWindow::UniqueFunctionNameForMessageBoxBecauseMicrosoftUsesMacros(const std::string& title, const std::string& message_box_text) {
|
||||
void RWindow::DialogOK(const std::string& title, const std::string& message_box_text) {
|
||||
MessageBox(nullptr, message_box_text.c_str(), title.c_str(), MB_OK);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user