Compare commits

...

6 Commits

Author SHA1 Message Date
f979e5738f Windows notify
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 56s
2025-07-16 20:21:07 -04:00
2291ee6215 Linux notify
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m33s
2025-07-14 19:47:09 -04:00
edcd5a7fca Add MouseButton::PinchIn and PinchOut, ideally will be superceded by TouchWhiz Gestures (LOL)
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m29s
2025-07-14 15:39:59 -05:00
82e4ae39a9 Update Window.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m43s
2025-07-14 15:55:00 -04:00
93707dbd71 Remove need expose windows.h
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 7m6s
2025-07-14 04:51:15 -04:00
1f8bd9b6c2 Fix breaking change on linux due to inclusion of Windows header.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m33s
2025-07-13 18:14:48 -05:00
9 changed files with 138 additions and 35 deletions

View File

@@ -46,14 +46,17 @@ file(GLOB_RECURSE HEADERS "include/logger/*.h" "include/logger/*.hpp")
if(UNIX AND NOT APPLE)
file(GLOB_RECURSE SOURCES "src/types/*.cpp" "src/platform/linux/*.cpp" "src/platform/shared/*.cpp" "src/ReWindow/*.cpp" )
find_package(PkgConfig REQUIRED)
pkg_check_modules(DBUS REQUIRED dbus-1)
include_directories("include" ${DBUS_INCLUDE_DIRS})
endif()
if(WIN32)
file(GLOB_RECURSE SOURCES "src/types/*.cpp" "src/platform/windows/*.cpp" "src/platform/shared/*.cpp" "src/ReWindow/*.cpp")
include_directories("include")
endif()
include_directories("include")
if(UNIX)
add_library(ReWindow SHARED ${SOURCES})
endif()
@@ -68,7 +71,7 @@ target_include_directories(ReWindow PUBLIC ${Event_SOURCE_DIR}/include)
set_target_properties(ReWindow PROPERTIES LINKER_LANGUAGE CXX)
if(UNIX AND NOT APPLE)
target_link_libraries(ReWindow PUBLIC X11 Event jlog)
target_link_libraries(ReWindow PUBLIC X11 Event jlog ${DBUS_LIBRARIES})
target_link_libraries(ReWindow PUBLIC)
add_executable(ReWindowDemo main.cpp)
target_link_libraries(ReWindowDemo PUBLIC ReWindow)

View File

@@ -25,8 +25,8 @@ A library which allows easily creating and managing a window and it's events acr
Install dependencies
```bash
Fedora/RHEL: dnf install cmake make gcc-g++ libX11 libX11-devel mesa-libGL-devel vulkan-loader-devel
Ubuntu/Debian: apt-get install cmake make gcc g++ libx11-6 libx11-dev libgl-dev libvulkan-dev libxrandr-dev
Fedora/RHEL: dnf install cmake make gcc-g++ libX11 libX11-devel mesa-libGL-devel vulkan-loader-devel dbus-devel
Ubuntu/Debian: apt-get install cmake make gcc g++ libx11-6 libx11-dev libgl-dev libvulkan-dev libxrandr-dev libdbus-1-dev
```
Clone the repository

View File

@@ -35,6 +35,9 @@ namespace MouseButtons
static const MouseButton Mouse5 ("5", 9);
static const MouseButton Unimplemented ("?", 0);
static const MouseButton PinchIn ("+", 6);
static const MouseButton PinchOut("-", 7);
/// NOTE: IsMouseButtonDown will not return correctly for the mouse-wheel-buttons, because the action is effectively instantaneous.
static const MouseButton MWheelUp ("U", 4);
/// NOTE: IsMouseButtonDown will not return correctly for the mouse-wheel-buttons, because the action is effectively instantaneous.

View File

@@ -1,15 +1,15 @@
#pragma once
#include <cstdint>
#include <vector>
#include <Event.h>
#include <queue>
#include <map>
#include <thread>
#include <filesystem>
#include <Event.h>
#include <ReWindow/types/Key.h>
#include <ReWindow/types/Cursors.h>
#include <ReWindow/types/MouseButton.h>
#include <ReWindow/types/WindowEvents.h>
#include <queue>
#include <Windows.h>
namespace ReWindow {
@@ -46,10 +46,11 @@ public:
/// RWindow is a class implementation of a platform-independent window abstraction.
/// This library also provides abstractions for user-input devices, and their interaction with the window.
class ReWindow::RWindow {
protected:
class Platform;
friend class Platform;
Platform* platform;
inline static RWindow* extant;
int width = 640;
@@ -239,9 +240,6 @@ public:
/// Returns the vertical length of this window, in pixels.
[[nodiscard]] int GetHeight() const;
/// This is unfortunately here because of the poor design of windows. Maybe once interfaces are done this won't be required anymore.
void SetSizeWithoutEvent(const std::pair<int, int>& size);
/// Tells the underlying window manager to destroy this window and drop the handle.
/// The window, in theory, can not be re-opened after this.
void DestroyOSWindowHandle();
@@ -334,12 +332,7 @@ public:
/// Updates internals to account for the latest calculated frame time.
void UpdateFrameTiming(float frame_time);
#ifdef WIN32
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#endif
protected:
/// These unfortunately *have* to be public because of the poor design of the windows event loop.
void processKeyRelease(Key key);
void processKeyPress(Key key);
/// @note This will be invoked **before** the window-close procedure begins.
@@ -352,6 +345,7 @@ protected:
void processFocusOut();
void processMouseMove(const std::pair<int, int>& last_pos, const std::pair<int, int>& new_pos);
void processMouseWheel(int scrolls);
void SetSizeWithoutEvent(const std::pair<int, int>& size);
/// Virtual functions which *must* be overridden based on the Renderer.
public:
@@ -378,6 +372,13 @@ public:
/// @note If the window is already in focus when this is called nothing happens.
void Flash();
/// Sends a notification to the operating system notification area.
/// @param title The notification title.
/// @param content The actual text of the notification.
/// @param icon The path to the icon to be displayed on the notification, Empty for none.
/// @note On Windows, icon must be a .ico
bool Notify(const std::string& title, const std::string& content, const std::filesystem::path& icon = "");
/// @returns True if we are definitely running on a software renderer.
/// @note For some APIs this isn't typically possible.
[[nodiscard]] virtual bool SoftwareRendered() { return false; }

View File

@@ -48,6 +48,7 @@ int main() {
auto* window = new MyWindow("Test Window", 600, 480);
Logger::Debug(std::format("New window '{}' created. width={} height={}", window->GetTitle(), window->GetWidth(), window->GetHeight()));
window->Notify("Hello", "Test notification.");
if (window->Open())
Logger::Debug(std::format("Opened window '{}'", window->GetTitle()));
@@ -73,6 +74,5 @@ int main() {
if (window->IsFocused())
window->SetCursorCenter();
}
delete window;
}

View File

@@ -1 +1 @@
Main:new("Install build dependencies", "apt-get install -yq libx11-6 libx11-dev libgl-dev libvulkan-dev")
Main:new("Install build dependencies", "apt-get install -yq libx11-6 libx11-dev libgl-dev libvulkan-dev libdbus-1-dev")

View File

@@ -1,10 +1,13 @@
#include <cstring>
#include <thread>
#include <ReWindow/types/Window.h>
#include <ReWindow/types/Cursors.h>
#include <ReWindow/Logger.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <thread>
#include <dbus/dbus.h>
class ReWindow::RWindow::Platform {
public:
@@ -29,6 +32,65 @@ public:
using namespace ReWindow;
bool RWindow::Notify(const std::string& title, const std::string& content, const std::filesystem::path& icon) {
DBusError db_error;
dbus_error_init(&db_error);
DBusConnection* db_connection = dbus_bus_get(DBUS_BUS_SESSION, &db_error);
if (!db_connection) {
dbus_error_free(&db_error);
return false;
}
DBusMessage* db_message = dbus_message_new_method_call(
"org.freedesktop.Notifications",
"/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
"Notify"
);
if (!db_message)
return false;
const char* sender = this->title.c_str();
uint32_t replaces_id = 0;
const char* app_icon = icon.c_str();
const char* summary = title.c_str();
const char* body = content.c_str();
const char** actions = nullptr;
DBusMessageIter db_args;
dbus_message_iter_init_append(db_message, &db_args);
dbus_message_iter_append_basic(&db_args, DBUS_TYPE_STRING, &sender);
dbus_message_iter_append_basic(&db_args, DBUS_TYPE_UINT32, &replaces_id);
dbus_message_iter_append_basic(&db_args, DBUS_TYPE_STRING, &app_icon);
dbus_message_iter_append_basic(&db_args, DBUS_TYPE_STRING, &summary);
dbus_message_iter_append_basic(&db_args, DBUS_TYPE_STRING, &body);
DBusMessageIter db_actions_array_iterator;
dbus_message_iter_open_container(&db_args, DBUS_TYPE_ARRAY, "s", &db_actions_array_iterator);
dbus_message_iter_close_container(&db_args, &db_actions_array_iterator);
dbus_message_iter_open_container(&db_args, DBUS_TYPE_ARRAY, "{sv}", &db_actions_array_iterator);
dbus_message_iter_close_container(&db_args, &db_actions_array_iterator);
int32_t notif_timeout = 5000;
dbus_message_iter_append_basic(&db_args, DBUS_TYPE_INT32, &notif_timeout);
DBusMessage* db_reply = dbus_connection_send_with_reply_and_block(db_connection, db_message, -1, &db_error);
dbus_message_unref(db_message);
if (!db_reply) {
dbus_error_free(&db_error);
return false;
}
dbus_message_unref(db_reply);
return true;
}
void RWindow::SetSize(const std::pair<int, int>& size) {
this->SetSize(size.first, size.second);
}

View File

@@ -3,7 +3,6 @@
#include <ReWindow/types/Window.h>
#include <ReWindow/Logger.h>
class ReWindow::RWindow::Platform {
public:
HINSTANCE hInstance;
@@ -11,13 +10,47 @@ public:
HDC hdc;
std::pair<int, int> window_size_before_fullscreen;
std::pair<int, int> window_position_before_fullscreen;
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
using namespace ReWindow;
// TODO get rid of this.
bool local_focused = true;
bool local_toggling_cursor_focused = false;
// TODO destroy n_data after it's no longer shown. Destroying it early causes the notification to come from explorer.
bool RWindow::Notify(const std::string& title, const std::string& content, const std::filesystem::path& icon) {
NOTIFYICONDATA n_data = {};
HICON n_icon = nullptr;
if (!icon.empty()) {
n_icon = (HICON) LoadImageW(
nullptr,
icon.c_str(),
IMAGE_ICON,
0, 0,
LR_LOADFROMFILE | LR_DEFAULTSIZE
);
if (!n_icon)
return false;
}
n_data.cbSize = sizeof(NOTIFYICONDATA);
n_data.hWnd = platform->hwnd;
n_data.uID = 1;
n_data.uFlags = NIF_INFO | NIF_ICON | NIF_MESSAGE | NIF_TIP;
n_data.uCallbackMessage = WM_USER + 1;
n_data.hIcon = n_icon;
lstrcpy(n_data.szTip, title.c_str());
lstrcpy(n_data.szInfo, content.c_str());
lstrcpy(n_data.szInfoTitle, title.c_str());
n_data.dwInfoFlags = NIIF_USER;
Shell_NotifyIcon(NIM_ADD, &n_data);
Shell_NotifyIcon(NIM_MODIFY, &n_data);
//Shell_NotifyIcon(NIM_DELETE, &n_data);
return true;
}
void RWindow::SetSize(int newWidth, int newHeight) {
if (!resizable)
@@ -41,7 +74,7 @@ void RWindow::SetSize(int newWidth, int newHeight) {
void RWindow::SetCursorFocused(bool state) {
local_toggling_cursor_focused = state;
toggling_cursor_focus = state;
if (state)
cursor_focused = true;
@@ -49,7 +82,7 @@ void RWindow::SetCursorFocused(bool state) {
else if (!state && cursor_focused) {
ClipCursor(nullptr);
cursor_focused = false;
local_toggling_cursor_focused = false;
toggling_cursor_focus = false;
}
}
@@ -92,10 +125,9 @@ void RWindow::PollEvents() {
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
TranslateMessage(&msg),
DispatchMessage(&msg);
focused = local_focused;
}
LRESULT CALLBACK RWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
LRESULT CALLBACK RWindow::Platform::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
auto* window = reinterpret_cast<RWindow*>( GetWindowLongPtr(hwnd, GWLP_USERDATA) );
switch (uMsg) {
case WM_CLOSE: {
@@ -119,10 +151,10 @@ LRESULT CALLBACK RWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
case WM_SETFOCUS: {
window->processFocusIn();
local_focused = true;
window->focused = true;
if (window->GetCursorFocused())
local_toggling_cursor_focused = true;
window->toggling_cursor_focus = true;
// Cancels window flashing.
// TODO check if we're flashing before this.
@@ -136,9 +168,9 @@ LRESULT CALLBACK RWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
if (window->GetCursorFocused()) {
ClipCursor(nullptr);
local_toggling_cursor_focused = true;
window->toggling_cursor_focus = true;
}
local_focused = false;
window->focused = false;
}
case WM_SETCURSOR: {
@@ -226,7 +258,7 @@ LRESULT CALLBACK RWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
//This is the same as "Motion Notify" in the X Window System.
case WM_MOUSEMOVE: {
if (local_toggling_cursor_focused) {
if (window->toggling_cursor_focus) {
RECT rect;
if (GetClientRect(hwnd, &rect)) {
POINT top_left = { rect.left, rect.top };
@@ -236,7 +268,7 @@ LRESULT CALLBACK RWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
RECT clip_rect = { top_left.x, top_left.y, bottom_right.x, bottom_right.y };
if (ClipCursor(&clip_rect))
local_toggling_cursor_focused = false;
window->toggling_cursor_focus = false;
}
}
}
@@ -415,7 +447,7 @@ bool OpenGLWindow::Open() {
platform->hInstance = GetModuleHandle(nullptr);
WNDCLASS wc = { };
wc.lpfnWndProc = RWindow::WindowProc;
wc.lpfnWndProc = RWindow::Platform::WindowProc;
wc.hInstance = platform->hInstance;
wc.lpszClassName = "RWindowClass";
RegisterClass(&wc);

View File

@@ -25,6 +25,8 @@ MouseButton GetMouseButtonFromXButton(unsigned int button) {
//case 4: return MouseButtons::MWheelUp;
//case 5: return MouseButtons::MWheelDown;
//For *whatever* reason. These aren't in X.h
case 6: return MouseButtons::PinchIn;
case 7: return MouseButtons::PinchOut;
case 8: return MouseButtons::Mouse4;
case 9: return MouseButtons::Mouse5;
default: {