summaryrefslogtreecommitdiff
path: root/src/canvas/x11/window/x11.cpp
diff options
context:
space:
mode:
authorpants <niklasjo2004@gmail.com>2026-09-21 14:18:06 -0700
committerpants <niklasjo2004@gmail.com>2026-09-21 14:18:06 -0700
commit83d5ba42f8a98fc0df177efef4333f74a0481f61 (patch)
tree6f1fcff64ec9adb2fc51a7cfcc451eb22a103fb3 /src/canvas/x11/window/x11.cpp
Diffstat (limited to 'src/canvas/x11/window/x11.cpp')
-rw-r--r--src/canvas/x11/window/x11.cpp119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/canvas/x11/window/x11.cpp b/src/canvas/x11/window/x11.cpp
new file mode 100644
index 0000000..c32c715
--- /dev/null
+++ b/src/canvas/x11/window/x11.cpp
@@ -0,0 +1,119 @@
+// Display images inside a terminal
+// Copyright (C) 2023 JustKidding
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+#include "x11.hpp"
+#include "dimensions.hpp"
+
+#include <string_view>
+
+#include <xcb/xcb.h>
+
+constexpr std::string_view win_name = "ueberzugpp";
+
+X11Window::X11Window(xcb_connection_t *connection, xcb_screen_t *screen, xcb_window_t window, xcb_window_t parent,
+ std::shared_ptr<Image> image)
+ : connection(connection),
+ screen(screen),
+ window(window),
+ parent(parent),
+ gc(xcb_generate_id(connection)),
+ image(std::move(image))
+{
+ logger = spdlog::get("X11");
+ create();
+ change_title();
+}
+
+void X11Window::create()
+{
+ const uint32_t value_mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
+ struct xcb_create_window_value_list_t value_list;
+ value_list.background_pixel = screen->black_pixel;
+ value_list.border_pixel = screen->black_pixel;
+ value_list.event_mask = XCB_EVENT_MASK_EXPOSURE;
+ value_list.colormap = screen->default_colormap;
+
+ const auto dimensions = image->dimensions();
+ const auto xcoord = static_cast<int16_t>(dimensions.xpixels() + dimensions.padding_horizontal);
+ const auto ycoord = static_cast<int16_t>(dimensions.ypixels() + dimensions.padding_vertical);
+ xcb_create_window_aux(connection, screen->root_depth, window, this->parent, xcoord, ycoord, image->width(),
+ image->height(), 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask,
+ &value_list);
+
+ xcb_create_gc(connection, gc, window, 0, nullptr);
+ logger->debug("Created child window {} at ({},{}) with parent {}", window, xcoord, ycoord, parent);
+}
+
+void X11Window::change_title()
+{
+ const int bits_in_char = 8;
+ xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, bits_in_char,
+ win_name.size(), win_name.data());
+}
+
+void X11Window::show()
+{
+ if (visible) {
+ return;
+ }
+ visible = true;
+ xcb_map_window(connection, window);
+ xcb_flush(connection);
+}
+
+void X11Window::hide()
+{
+ if (!visible) {
+ return;
+ }
+ visible = false;
+ xcb_unmap_window(connection, window);
+ xcb_flush(connection);
+}
+
+void X11Window::draw()
+{
+ if (!xcb_image) {
+ return;
+ }
+ xcb_image_put(connection, window, gc, xcb_image.get(), 0, 0, 0);
+}
+
+void X11Window::generate_frame()
+{
+ xcb_image.reset(xcb_image_create_native(connection, image->width(), image->height(), XCB_IMAGE_FORMAT_Z_PIXMAP,
+ screen->root_depth, nullptr, 0, nullptr));
+ xcb_image->data = const_cast<unsigned char *>(image->data());
+ send_expose_event();
+}
+
+X11Window::~X11Window()
+{
+ xcb_destroy_window(connection, window);
+ xcb_free_gc(connection, gc);
+ xcb_flush(connection);
+}
+
+void X11Window::send_expose_event()
+{
+ const int event_size = 32;
+ std::array<char, event_size> buffer;
+ auto *event = reinterpret_cast<xcb_expose_event_t *>(buffer.data());
+ event->response_type = XCB_EXPOSE;
+ event->window = window;
+ xcb_send_event(connection, 0, window, XCB_EVENT_MASK_EXPOSURE, reinterpret_cast<char *>(event));
+ xcb_flush(connection);
+}