From fec96c85a4d71f20d3de9791163a9a1f932c8e48 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Thu, 18 Jan 2024 12:05:13 +0100 Subject: window: Moving around directories --- modules/window/.nix/derivation.nix | 8 +- modules/window/SConscript | 38 ----- modules/window/backends.h | 10 -- modules/window/c++/SConscript | 38 +++++ modules/window/c++/backends.h | 10 ++ modules/window/c++/device.h | 18 +++ modules/window/c++/linux_xcb.h | 5 + modules/window/c++/video_mode.h | 11 ++ modules/window/c++/window.h | 79 ++++++++++ modules/window/c++/xcb.cpp | 290 +++++++++++++++++++++++++++++++++++++ modules/window/c++/xcb.h | 105 ++++++++++++++ modules/window/device.h | 18 --- modules/window/linux_xcb.h | 5 - modules/window/video_mode.h | 11 -- modules/window/window.h | 79 ---------- modules/window/xcb.cpp | 290 ------------------------------------- modules/window/xcb.h | 105 -------------- 17 files changed, 563 insertions(+), 557 deletions(-) delete mode 100644 modules/window/SConscript delete mode 100644 modules/window/backends.h create mode 100644 modules/window/c++/SConscript create mode 100644 modules/window/c++/backends.h create mode 100644 modules/window/c++/device.h create mode 100644 modules/window/c++/linux_xcb.h create mode 100644 modules/window/c++/video_mode.h create mode 100644 modules/window/c++/window.h create mode 100644 modules/window/c++/xcb.cpp create mode 100644 modules/window/c++/xcb.h delete mode 100644 modules/window/device.h delete mode 100644 modules/window/linux_xcb.h delete mode 100644 modules/window/video_mode.h delete mode 100644 modules/window/window.h delete mode 100644 modules/window/xcb.cpp delete mode 100644 modules/window/xcb.h (limited to 'modules/window') diff --git a/modules/window/.nix/derivation.nix b/modules/window/.nix/derivation.nix index 67a682c..2b15505 100644 --- a/modules/window/.nix/derivation.nix +++ b/modules/window/.nix/derivation.nix @@ -28,7 +28,13 @@ in stdenv.mkDerivation { forstio.codec xorg.libX11 xorg.libxcb - ]; + ]; + + doCheck = true; + checkPhase = '' + scons test + ./bin/tests + ''; outputs = ["out" "dev"]; } diff --git a/modules/window/SConscript b/modules/window/SConscript deleted file mode 100644 index bd830b9..0000000 --- a/modules/window/SConscript +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/false - -import os -import os.path -import glob - - -Import('env') - -dir_path = Dir('.').abspath - -# Environment for base library -window_env = env.Clone(); - -window_env.sources = sorted(glob.glob(dir_path + "/*.cpp")) -window_env.headers = sorted(glob.glob(dir_path + "/*.h")) - -env.sources += window_env.sources; -env.headers += window_env.headers; - -## Shared lib -objects_shared = [] -window_env.add_source_files(objects_shared, window_env.sources, shared=True); -window_env.library_shared = window_env.SharedLibrary('#build/forstio-window', [objects_shared]); - -## Static lib -objects_static = [] -window_env.add_source_files(objects_static, window_env.sources, shared=False); -window_env.library_static = window_env.StaticLibrary('#build/forstio-window', [objects_static]); - -# Set Alias -env.Alias('library_window', [window_env.library_shared, window_env.library_static]); - -env.targets += ['library_window']; - -# Install -env.Install('$prefix/lib/', [window_env.library_shared, window_env.library_static]); -env.Install('$prefix/include/forstio/window/', [window_env.headers]); diff --git a/modules/window/backends.h b/modules/window/backends.h deleted file mode 100644 index e129037..0000000 --- a/modules/window/backends.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace saw { -namespace gfx { -namespace backend { -struct linux_xcb {}; -struct wasm {}; -} -} -} diff --git a/modules/window/c++/SConscript b/modules/window/c++/SConscript new file mode 100644 index 0000000..10d88c6 --- /dev/null +++ b/modules/window/c++/SConscript @@ -0,0 +1,38 @@ +#!/bin/false + +import os +import os.path +import glob + + +Import('env') + +dir_path = Dir('.').abspath + +# Environment for base library +window_env = env.Clone(); + +window_env.sources = sorted(glob.glob(dir_path + "/*.cpp")) +window_env.headers = sorted(glob.glob(dir_path + "/*.h")) + +env.sources += window_env.sources; +env.headers += window_env.headers; + +## Shared lib +objects_shared = [] +window_env.add_source_files(objects_shared, window_env.sources, shared=True); +env.library_shared = window_env.SharedLibrary('#build/forstio-window', [objects_shared]); + +## Static lib +objects_static = [] +window_env.add_source_files(objects_static, window_env.sources, shared=False); +env.library_static = window_env.StaticLibrary('#build/forstio-window', [objects_static]); + +# Set Alias +env.Alias('library_window', [env.library_shared, env.library_static]); + +env.targets += ['library_window']; + +# Install +env.Install('$prefix/lib/', [env.library_shared, env.library_static]); +env.Install('$prefix/include/forstio/window/', [window_env.headers]); diff --git a/modules/window/c++/backends.h b/modules/window/c++/backends.h new file mode 100644 index 0000000..e129037 --- /dev/null +++ b/modules/window/c++/backends.h @@ -0,0 +1,10 @@ +#pragma once + +namespace saw { +namespace gfx { +namespace backend { +struct linux_xcb {}; +struct wasm {}; +} +} +} diff --git a/modules/window/c++/device.h b/modules/window/c++/device.h new file mode 100644 index 0000000..6a28cd5 --- /dev/null +++ b/modules/window/c++/device.h @@ -0,0 +1,18 @@ +#pragma once + +#include "window.h" + +#include +#include +#include +#include + +#include +#include + +namespace saw { +namespace gfx { +template +class device; +} +} diff --git a/modules/window/c++/linux_xcb.h b/modules/window/c++/linux_xcb.h new file mode 100644 index 0000000..65ff94d --- /dev/null +++ b/modules/window/c++/linux_xcb.h @@ -0,0 +1,5 @@ +#pragma once + +#ifdef SAW_UNIX_XCB +#include "xcb.h" +#endif diff --git a/modules/window/c++/video_mode.h b/modules/window/c++/video_mode.h new file mode 100644 index 0000000..a8f1695 --- /dev/null +++ b/modules/window/c++/video_mode.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace saw { +class video_mode { +public: + size_t width = 64; + size_t height = 64; +}; +} // namespace saw diff --git a/modules/window/c++/window.h b/modules/window/c++/window.h new file mode 100644 index 0000000..0e8d051 --- /dev/null +++ b/modules/window/c++/window.h @@ -0,0 +1,79 @@ +#pragma once + +#include "video_mode.h" + +#include +#include +#include + +#include +#include + +namespace saw { +namespace gfx { +namespace schema { +using namespace saw::schema; +using WindowResize = Struct< + Member, + Member +>; +using WindowEvents = Union< + Member +>; +} + +template +class window; +} +} + +#include "linux_xcb.h" + +/** +namespace saw { +class window { +public: + class event { + public: + struct resize { + size_t width; + size_t height; + }; + + struct keyboard { + uint32_t key; + uint32_t scan; + bool pressed; + bool repeat; + }; + + struct mouse { + uint16_t button_mask; + bool pressed; + uint32_t x; + uint32_t y; + }; + + struct mouse_move { + uint32_t x; + uint32_t y; + }; + }; + + using variant_event = std::variant; + + virtual ~window() = default; + + virtual void show() = 0; + virtual void hide() = 0; + + virtual const video_mode &get_video_mode() const = 0; + virtual const std::string_view title() const = 0; + + virtual void resize(size_t width, size_t height) = 0; + + virtual conveyor on_event() = 0; +}; +} // namespace saw +*/ diff --git a/modules/window/c++/xcb.cpp b/modules/window/c++/xcb.cpp new file mode 100644 index 0000000..1b804ba --- /dev/null +++ b/modules/window/c++/xcb.cpp @@ -0,0 +1,290 @@ +#ifndef SAW_UNIX_XCB +#error "XCB is not supported" +#endif + +#include "xcb.h" + +namespace saw { +namespace gfx { +device::device(::Display* disp, int screen, xcb_connection_t *xcb_connection, xcb_screen_t *xcb_screen, own&& an): + display_{disp}, screen_{screen}, xcb_connection_{xcb_connection}, xcb_screen_{xcb_screen}, async_notifier_{std::move(an)}, + async_conveyor_{async_notifier_->read_ready() + .then([this]() { handle_events(); }) + .sink()} {} + +device::~device(){ + if (display_) { + xcb_flush(xcb_connection_); + ::XCloseDisplay(display_); + } +} + +void device::xcb_window_was_destroyed(xcb_window_t window_id){ + windows_.erase(window_id); +} + +void device::handle_events(){ + while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection_)) { + pending_events_.push_back(event); + } + for (size_t i = 0; i < pending_events_.size(); ++i) { + xcb_generic_event_t *event = pending_events_.at(i); + switch (event->response_type & ~0x80) { + case XCB_MOTION_NOTIFY: { + xcb_motion_notify_event_t *motion = + reinterpret_cast(event); + auto find = windows_.find(motion->event); + if (find != windows_.end()) { + assert(find->second); + find->second->mouse_move_event(motion->event_x, + motion->event_y); + } + } break; + case XCB_EXPOSE: { + xcb_expose_event_t *expose = + reinterpret_cast(event); + auto find = windows_.find(expose->window); + if (find != windows_.end()) { + assert(find->second); + find->second->resize_event(static_cast(expose->x), + static_cast(expose->y), + static_cast(expose->width), + static_cast(expose->height)); + } + } break; + case XCB_BUTTON_RELEASE: { + xcb_button_release_event_t *button = + reinterpret_cast(event); + auto find = windows_.find(button->event); + if (find != windows_.end()) { + assert(find->second); + find->second->mouse_event(button->event_x, button->event_y, + button->detail, false); + } + } break; + case XCB_BUTTON_PRESS: { + xcb_button_press_event_t *button = + reinterpret_cast(event); + auto find = windows_.find(button->event); + if (find != windows_.end()) { + assert(find->second); + find->second->mouse_event(button->event_x, button->event_y, + button->detail, true); + } + } break; + case XCB_KEY_RELEASE: { + xcb_key_release_event_t *key = + reinterpret_cast(event); + + bool repeat = false; + /* + * Peek into future events + */ + for (size_t j = i + 1; j < pending_events_.size(); ++j) { + xcb_generic_event_t *f_ev = pending_events_.at(j); + + if ((f_ev->response_type & ~0x80) == XCB_KEY_PRESS) { + xcb_key_press_event_t *f_key = + reinterpret_cast(f_ev); + + if (key->detail == f_key->detail && + key->event == f_key->event) { + auto iterator = pending_events_.begin() + j; + assert(iterator != pending_events_.end()); + free(*iterator); + pending_events_.erase(iterator); + repeat = true; + break; + } + } + } + + auto find = windows_.find(key->event); + if (find != windows_.end()) { + assert(find->second); + find->second->keyboard_event(key->event_x, key->event_y, + key->detail, repeat, repeat); + } + } break; + case XCB_KEY_PRESS: { + xcb_key_press_event_t *key = + reinterpret_cast(event); + auto find = windows_.find(key->event); + if (find != windows_.end()) { + assert(find->second); + find->second->keyboard_event(key->event_x, key->event_y, + key->detail, true, false); + } + } break; + default: + break; + } + } + + for (xcb_generic_event_t *event : pending_events_) { + free(event); + } + pending_events_.clear(); +} + +own> device::create_xcb_window(const video_mode &vid_mode, + std::string_view title_view, + int visual_id) { + assert(xcb_screen_); + assert(xcb_connection_); + + xcb_colormap_t xcb_colormap = xcb_generate_id(xcb_connection_); + xcb_window_t xcb_window = xcb_generate_id(xcb_connection_); + + xcb_create_colormap(xcb_connection_, XCB_COLORMAP_ALLOC_NONE, xcb_colormap, + xcb_screen_->root, visual_id); + + uint32_t eventmask = + XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | + XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | + XCB_EVENT_MASK_BUTTON_MOTION; + uint32_t valuelist[] = {eventmask, xcb_colormap, 0}; + uint32_t valuemask = XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; + + xcb_create_window(xcb_connection_, XCB_COPY_FROM_PARENT, xcb_window, + xcb_screen_->root, 0, 0, vid_mode.width, + vid_mode.height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, + visual_id, valuemask, valuelist); + + xcb_change_property(xcb_connection_, XCB_PROP_MODE_REPLACE, xcb_window, + XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, title_view.size(), + title_view.data()); + + xcb_flush(xcb_connection_); + auto win = heap>(*this, xcb_window, xcb_colormap, + vid_mode, title_view); + // Insert into map + windows_[xcb_window] = win.get(); + + return win; +} + +own> device::create_window(const video_mode& vid_mode, std::string_view title_view){ + assert(xcb_screen_); + return create_xcb_window(vid_mode, title_view, xcb_screen_->root_visual); +} + +void device::flush(){ + assert(xcb_connection_); + xcb_flush(xcb_connection_); +} + +error_or>> create_xcb_device(io_provider& provider){ + ::Display *display = ::XOpenDisplay(nullptr); + if (!display) { + /// @todo log errors + return make_error(); + } + + int screen = ::XDefaultScreen(display); + + xcb_connection_t *xcb_connection = ::XGetXCBConnection(display); + if (!xcb_connection) { + /// @todo log errors + ::XCloseDisplay(display); + return make_error(); + } + + int fd = xcb_get_file_descriptor(xcb_connection); + + own fd_wrapped = provider.wrap_input_fd(fd); + if (!fd_wrapped) { + ::XCloseDisplay(display); + return make_error(); + } + + ::XSetEventQueueOwner(display, XCBOwnsEventQueue); + + xcb_screen_iterator_t screen_iter = + xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)); + for (int screen_i = screen; screen_iter.rem && screen_i > 0; + --screen_i, xcb_screen_next(&screen_iter)) + ; + + xcb_screen_t *xcb_screen = screen_iter.data; + + return heap>(display, screen, xcb_connection, xcb_screen, std::move(fd_wrapped)); +} + +window::window(device& dev_, xcb_window_t xcb_win, xcb_colormap_t xcb_colormap_, const video_mode& vid_mode_, const std::string_view& title_view_): + device_{&dev_}, + xcb_window_{xcb_win}, + xcb_colormap_{xcb_colormap_}, + video_mode_{vid_mode_}, + window_title_{title_view_} +{} + +window::~window(){ + assert(device_); + device_->xcb_window_was_destroyed(xcb_window_); + xcb_destroy_window(device_->xcb_connection_, xcb_window_); + device_->flush(); +} + +void window::show(){ + assert(device_->xcb_connection_); + xcb_map_window(device_->xcb_connection_, xcb_window_); +} + +void window::hide(){ + assert(device_->xcb_connection_); + xcb_unmap_window(device_->xcb_connection_, xcb_window_); +} + +const video_mode& window::get_video_mode() const { + return video_mode_; +} + +const std::string_view window::get_title() const { + return window_title_; +} + +void window::resize(uint64_t w, uint64_t h){ + const uint32_t values[2] = { + static_cast(w), + static_cast(h) + }; + + xcb_configure_window(device_->xcb_connection_, xcb_window_, + XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, + values); + + video_mode_.width = w; + video_mode_.height = h; +} + +conveyor> window::on_event() { + auto caf = new_conveyor_and_feeder>(); + event_feeder = std::move(caf.feeder); + return std::move(caf.conveyor); +} + +void window::resize_event(uint64_t x, uint64_t y, uint64_t width, uint64_t height){ + /// @todo implement + assert(false); +} +void window::mouse_event(int16_t x, int16_t y, uint16_t state, bool pressed){ + /// @todo implement + assert(false); +} +void window::mouse_move_event(int16_t x, int16_t y){ + /// @todo implement + assert(false); +} +void window::keyboard_event(int16_t x, int16_t y, uint32_t keycode, bool pressed, bool repeat){ + /// @todo implement + assert(false); +} + +xcb_window_t window::get_xcb_window_handle() const{ + return xcb_window_; +} + +} +} diff --git a/modules/window/c++/xcb.h b/modules/window/c++/xcb.h new file mode 100644 index 0000000..a2a9b0b --- /dev/null +++ b/modules/window/c++/xcb.h @@ -0,0 +1,105 @@ +#pragma once + +#ifndef SAW_UNIX_XCB +#error "XCB is not supported" +#endif + +#include "backends.h" +#include "device.h" +#include "window.h" + +#include + +#include +#include + +namespace saw { +namespace gfx { +template +class window; + +template +class device; + +template<> +class device final { +private: + ::Display *display_; + int screen_; + + xcb_connection_t *xcb_connection_; + xcb_screen_t *xcb_screen_; + + own async_notifier_; + conveyor_sink async_conveyor_; + + std::map *> windows_; + + std::vector pending_events_; + + friend class window; +public: + own> create_xcb_window(const video_mode& vid_mod, std::string_view title_view, int visual_id); + void xcb_window_was_destroyed(xcb_window_t window_id); +public: + device(::Display *display, int screen, xcb_connection_t *xcb_connection, + xcb_screen_t *xcb_screen, own && an); + + ~device(); + + void handle_events(); + + own> create_window(const video_mode& vid_mod, std::string_view title_view); + + void flush(); + + // XCB specific info for other classes + ::Display* get_xcb_display() { + return display_; + } + + int get_xcb_screen() const { + return screen_; + } +}; + +error_or>> create_xcb_device(io_provider& provider); + +template<> +class window final { +private: + device *device_; + + xcb_window_t xcb_window_; + xcb_colormap_t xcb_colormap_; + + video_mode video_mode_; + std::string window_title_; + + own>> event_feeder = nullptr; +public: + window(device& dev_, xcb_window_t xcb_win, xcb_colormap_t xcb_colormap_, const video_mode& vid_mode_, const std::string_view& title_view_); + + ~window(); + + void show(); + void hide(); + + const video_mode& get_video_mode() const; + + const std::string_view get_title() const; + + void resize(uint64_t width, uint64_t height); + + conveyor> on_event(); + + void resize_event(uint64_t x, uint64_t y, uint64_t width, uint64_t height); + void mouse_event(int16_t x, int16_t y, uint16_t state, bool pressed); + void mouse_move_event(int16_t x, int16_t y); + void keyboard_event(int16_t x, int16_t y, uint32_t keycode, bool pressed, bool repeat); + + // XCB specific things + xcb_window_t get_xcb_window_handle() const; +}; +} +} diff --git a/modules/window/device.h b/modules/window/device.h deleted file mode 100644 index 6a28cd5..0000000 --- a/modules/window/device.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "window.h" - -#include -#include -#include -#include - -#include -#include - -namespace saw { -namespace gfx { -template -class device; -} -} diff --git a/modules/window/linux_xcb.h b/modules/window/linux_xcb.h deleted file mode 100644 index 65ff94d..0000000 --- a/modules/window/linux_xcb.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#ifdef SAW_UNIX_XCB -#include "xcb.h" -#endif diff --git a/modules/window/video_mode.h b/modules/window/video_mode.h deleted file mode 100644 index a8f1695..0000000 --- a/modules/window/video_mode.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -namespace saw { -class video_mode { -public: - size_t width = 64; - size_t height = 64; -}; -} // namespace saw diff --git a/modules/window/window.h b/modules/window/window.h deleted file mode 100644 index 0e8d051..0000000 --- a/modules/window/window.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include "video_mode.h" - -#include -#include -#include - -#include -#include - -namespace saw { -namespace gfx { -namespace schema { -using namespace saw::schema; -using WindowResize = Struct< - Member, - Member ->; -using WindowEvents = Union< - Member ->; -} - -template -class window; -} -} - -#include "linux_xcb.h" - -/** -namespace saw { -class window { -public: - class event { - public: - struct resize { - size_t width; - size_t height; - }; - - struct keyboard { - uint32_t key; - uint32_t scan; - bool pressed; - bool repeat; - }; - - struct mouse { - uint16_t button_mask; - bool pressed; - uint32_t x; - uint32_t y; - }; - - struct mouse_move { - uint32_t x; - uint32_t y; - }; - }; - - using variant_event = std::variant; - - virtual ~window() = default; - - virtual void show() = 0; - virtual void hide() = 0; - - virtual const video_mode &get_video_mode() const = 0; - virtual const std::string_view title() const = 0; - - virtual void resize(size_t width, size_t height) = 0; - - virtual conveyor on_event() = 0; -}; -} // namespace saw -*/ diff --git a/modules/window/xcb.cpp b/modules/window/xcb.cpp deleted file mode 100644 index 1b804ba..0000000 --- a/modules/window/xcb.cpp +++ /dev/null @@ -1,290 +0,0 @@ -#ifndef SAW_UNIX_XCB -#error "XCB is not supported" -#endif - -#include "xcb.h" - -namespace saw { -namespace gfx { -device::device(::Display* disp, int screen, xcb_connection_t *xcb_connection, xcb_screen_t *xcb_screen, own&& an): - display_{disp}, screen_{screen}, xcb_connection_{xcb_connection}, xcb_screen_{xcb_screen}, async_notifier_{std::move(an)}, - async_conveyor_{async_notifier_->read_ready() - .then([this]() { handle_events(); }) - .sink()} {} - -device::~device(){ - if (display_) { - xcb_flush(xcb_connection_); - ::XCloseDisplay(display_); - } -} - -void device::xcb_window_was_destroyed(xcb_window_t window_id){ - windows_.erase(window_id); -} - -void device::handle_events(){ - while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection_)) { - pending_events_.push_back(event); - } - for (size_t i = 0; i < pending_events_.size(); ++i) { - xcb_generic_event_t *event = pending_events_.at(i); - switch (event->response_type & ~0x80) { - case XCB_MOTION_NOTIFY: { - xcb_motion_notify_event_t *motion = - reinterpret_cast(event); - auto find = windows_.find(motion->event); - if (find != windows_.end()) { - assert(find->second); - find->second->mouse_move_event(motion->event_x, - motion->event_y); - } - } break; - case XCB_EXPOSE: { - xcb_expose_event_t *expose = - reinterpret_cast(event); - auto find = windows_.find(expose->window); - if (find != windows_.end()) { - assert(find->second); - find->second->resize_event(static_cast(expose->x), - static_cast(expose->y), - static_cast(expose->width), - static_cast(expose->height)); - } - } break; - case XCB_BUTTON_RELEASE: { - xcb_button_release_event_t *button = - reinterpret_cast(event); - auto find = windows_.find(button->event); - if (find != windows_.end()) { - assert(find->second); - find->second->mouse_event(button->event_x, button->event_y, - button->detail, false); - } - } break; - case XCB_BUTTON_PRESS: { - xcb_button_press_event_t *button = - reinterpret_cast(event); - auto find = windows_.find(button->event); - if (find != windows_.end()) { - assert(find->second); - find->second->mouse_event(button->event_x, button->event_y, - button->detail, true); - } - } break; - case XCB_KEY_RELEASE: { - xcb_key_release_event_t *key = - reinterpret_cast(event); - - bool repeat = false; - /* - * Peek into future events - */ - for (size_t j = i + 1; j < pending_events_.size(); ++j) { - xcb_generic_event_t *f_ev = pending_events_.at(j); - - if ((f_ev->response_type & ~0x80) == XCB_KEY_PRESS) { - xcb_key_press_event_t *f_key = - reinterpret_cast(f_ev); - - if (key->detail == f_key->detail && - key->event == f_key->event) { - auto iterator = pending_events_.begin() + j; - assert(iterator != pending_events_.end()); - free(*iterator); - pending_events_.erase(iterator); - repeat = true; - break; - } - } - } - - auto find = windows_.find(key->event); - if (find != windows_.end()) { - assert(find->second); - find->second->keyboard_event(key->event_x, key->event_y, - key->detail, repeat, repeat); - } - } break; - case XCB_KEY_PRESS: { - xcb_key_press_event_t *key = - reinterpret_cast(event); - auto find = windows_.find(key->event); - if (find != windows_.end()) { - assert(find->second); - find->second->keyboard_event(key->event_x, key->event_y, - key->detail, true, false); - } - } break; - default: - break; - } - } - - for (xcb_generic_event_t *event : pending_events_) { - free(event); - } - pending_events_.clear(); -} - -own> device::create_xcb_window(const video_mode &vid_mode, - std::string_view title_view, - int visual_id) { - assert(xcb_screen_); - assert(xcb_connection_); - - xcb_colormap_t xcb_colormap = xcb_generate_id(xcb_connection_); - xcb_window_t xcb_window = xcb_generate_id(xcb_connection_); - - xcb_create_colormap(xcb_connection_, XCB_COLORMAP_ALLOC_NONE, xcb_colormap, - xcb_screen_->root, visual_id); - - uint32_t eventmask = - XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | - XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | - XCB_EVENT_MASK_BUTTON_MOTION; - uint32_t valuelist[] = {eventmask, xcb_colormap, 0}; - uint32_t valuemask = XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; - - xcb_create_window(xcb_connection_, XCB_COPY_FROM_PARENT, xcb_window, - xcb_screen_->root, 0, 0, vid_mode.width, - vid_mode.height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, - visual_id, valuemask, valuelist); - - xcb_change_property(xcb_connection_, XCB_PROP_MODE_REPLACE, xcb_window, - XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, title_view.size(), - title_view.data()); - - xcb_flush(xcb_connection_); - auto win = heap>(*this, xcb_window, xcb_colormap, - vid_mode, title_view); - // Insert into map - windows_[xcb_window] = win.get(); - - return win; -} - -own> device::create_window(const video_mode& vid_mode, std::string_view title_view){ - assert(xcb_screen_); - return create_xcb_window(vid_mode, title_view, xcb_screen_->root_visual); -} - -void device::flush(){ - assert(xcb_connection_); - xcb_flush(xcb_connection_); -} - -error_or>> create_xcb_device(io_provider& provider){ - ::Display *display = ::XOpenDisplay(nullptr); - if (!display) { - /// @todo log errors - return make_error(); - } - - int screen = ::XDefaultScreen(display); - - xcb_connection_t *xcb_connection = ::XGetXCBConnection(display); - if (!xcb_connection) { - /// @todo log errors - ::XCloseDisplay(display); - return make_error(); - } - - int fd = xcb_get_file_descriptor(xcb_connection); - - own fd_wrapped = provider.wrap_input_fd(fd); - if (!fd_wrapped) { - ::XCloseDisplay(display); - return make_error(); - } - - ::XSetEventQueueOwner(display, XCBOwnsEventQueue); - - xcb_screen_iterator_t screen_iter = - xcb_setup_roots_iterator(xcb_get_setup(xcb_connection)); - for (int screen_i = screen; screen_iter.rem && screen_i > 0; - --screen_i, xcb_screen_next(&screen_iter)) - ; - - xcb_screen_t *xcb_screen = screen_iter.data; - - return heap>(display, screen, xcb_connection, xcb_screen, std::move(fd_wrapped)); -} - -window::window(device& dev_, xcb_window_t xcb_win, xcb_colormap_t xcb_colormap_, const video_mode& vid_mode_, const std::string_view& title_view_): - device_{&dev_}, - xcb_window_{xcb_win}, - xcb_colormap_{xcb_colormap_}, - video_mode_{vid_mode_}, - window_title_{title_view_} -{} - -window::~window(){ - assert(device_); - device_->xcb_window_was_destroyed(xcb_window_); - xcb_destroy_window(device_->xcb_connection_, xcb_window_); - device_->flush(); -} - -void window::show(){ - assert(device_->xcb_connection_); - xcb_map_window(device_->xcb_connection_, xcb_window_); -} - -void window::hide(){ - assert(device_->xcb_connection_); - xcb_unmap_window(device_->xcb_connection_, xcb_window_); -} - -const video_mode& window::get_video_mode() const { - return video_mode_; -} - -const std::string_view window::get_title() const { - return window_title_; -} - -void window::resize(uint64_t w, uint64_t h){ - const uint32_t values[2] = { - static_cast(w), - static_cast(h) - }; - - xcb_configure_window(device_->xcb_connection_, xcb_window_, - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - values); - - video_mode_.width = w; - video_mode_.height = h; -} - -conveyor> window::on_event() { - auto caf = new_conveyor_and_feeder>(); - event_feeder = std::move(caf.feeder); - return std::move(caf.conveyor); -} - -void window::resize_event(uint64_t x, uint64_t y, uint64_t width, uint64_t height){ - /// @todo implement - assert(false); -} -void window::mouse_event(int16_t x, int16_t y, uint16_t state, bool pressed){ - /// @todo implement - assert(false); -} -void window::mouse_move_event(int16_t x, int16_t y){ - /// @todo implement - assert(false); -} -void window::keyboard_event(int16_t x, int16_t y, uint32_t keycode, bool pressed, bool repeat){ - /// @todo implement - assert(false); -} - -xcb_window_t window::get_xcb_window_handle() const{ - return xcb_window_; -} - -} -} diff --git a/modules/window/xcb.h b/modules/window/xcb.h deleted file mode 100644 index a2a9b0b..0000000 --- a/modules/window/xcb.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#ifndef SAW_UNIX_XCB -#error "XCB is not supported" -#endif - -#include "backends.h" -#include "device.h" -#include "window.h" - -#include - -#include -#include - -namespace saw { -namespace gfx { -template -class window; - -template -class device; - -template<> -class device final { -private: - ::Display *display_; - int screen_; - - xcb_connection_t *xcb_connection_; - xcb_screen_t *xcb_screen_; - - own async_notifier_; - conveyor_sink async_conveyor_; - - std::map *> windows_; - - std::vector pending_events_; - - friend class window; -public: - own> create_xcb_window(const video_mode& vid_mod, std::string_view title_view, int visual_id); - void xcb_window_was_destroyed(xcb_window_t window_id); -public: - device(::Display *display, int screen, xcb_connection_t *xcb_connection, - xcb_screen_t *xcb_screen, own && an); - - ~device(); - - void handle_events(); - - own> create_window(const video_mode& vid_mod, std::string_view title_view); - - void flush(); - - // XCB specific info for other classes - ::Display* get_xcb_display() { - return display_; - } - - int get_xcb_screen() const { - return screen_; - } -}; - -error_or>> create_xcb_device(io_provider& provider); - -template<> -class window final { -private: - device *device_; - - xcb_window_t xcb_window_; - xcb_colormap_t xcb_colormap_; - - video_mode video_mode_; - std::string window_title_; - - own>> event_feeder = nullptr; -public: - window(device& dev_, xcb_window_t xcb_win, xcb_colormap_t xcb_colormap_, const video_mode& vid_mode_, const std::string_view& title_view_); - - ~window(); - - void show(); - void hide(); - - const video_mode& get_video_mode() const; - - const std::string_view get_title() const; - - void resize(uint64_t width, uint64_t height); - - conveyor> on_event(); - - void resize_event(uint64_t x, uint64_t y, uint64_t width, uint64_t height); - void mouse_event(int16_t x, int16_t y, uint16_t state, bool pressed); - void mouse_move_event(int16_t x, int16_t y); - void keyboard_event(int16_t x, int16_t y, uint32_t keycode, bool pressed, bool repeat); - - // XCB specific things - xcb_window_t get_xcb_window_handle() const; -}; -} -} -- cgit v1.2.3