Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ad2b0a5fa | ||
|
|
d96315ca66 | ||
|
|
f836d93761 | ||
|
|
5ca1534ba3 | ||
|
|
46fe232306 |
@@ -3,3 +3,6 @@ target_link_libraries(scene_demo PRIVATE wlrootspp)
|
|||||||
|
|
||||||
add_executable(tinywl tinywl.cpp)
|
add_executable(tinywl tinywl.cpp)
|
||||||
target_link_libraries(tinywl PRIVATE wlrootspp)
|
target_link_libraries(tinywl PRIVATE wlrootspp)
|
||||||
|
|
||||||
|
add_executable(testWM testwm.cpp)
|
||||||
|
target_link_libraries(testWM PRIVATE wlrootspp)
|
||||||
|
|||||||
@@ -0,0 +1,349 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||||
|
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
|
#include "wlr/display.hpp"
|
||||||
|
#include "wlr/backend.hpp"
|
||||||
|
#include "wlr/compositor.hpp"
|
||||||
|
#include "wlr/output.hpp"
|
||||||
|
#include "wlr/xdg_shell.hpp"
|
||||||
|
#include "wlr/seat.hpp"
|
||||||
|
#include "wlr/scene.hpp"
|
||||||
|
#include "wlr/node.hpp"
|
||||||
|
|
||||||
|
struct ToplevelState {
|
||||||
|
wlr::XdgSurface xdg;
|
||||||
|
wlr::Tree tree;
|
||||||
|
bool mapped = false;
|
||||||
|
int gx = 0, gy = 0, gw = 0, gh = 0;
|
||||||
|
std::string title;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Server {
|
||||||
|
wlr::Display display;
|
||||||
|
wlr::Backend backend{display};
|
||||||
|
wlr::Renderer renderer{wlr_renderer_autocreate(backend.raw())};
|
||||||
|
wlr::Allocator allocator{wlr_allocator_autocreate(backend.raw(), renderer.raw())};
|
||||||
|
wlr::Compositor compositor{display, renderer};
|
||||||
|
wlr::XdgShell xdg_shell{display};
|
||||||
|
wlr::Seat seat{display, "seat0"};
|
||||||
|
wlr::Cursor cursor;
|
||||||
|
wlr::OutputLayout layout{display};
|
||||||
|
wlr::Scene scene;
|
||||||
|
wlr::Tree root{wlr_scene_tree_create(scene.root())};
|
||||||
|
|
||||||
|
std::vector<struct wlr_scene_output*> outputs;
|
||||||
|
std::vector<ToplevelState*> toplevels;
|
||||||
|
ToplevelState* focused = nullptr;
|
||||||
|
struct wlr_keyboard* keyboard = nullptr;
|
||||||
|
wlr::SignalSink key_sink;
|
||||||
|
wl_event_source* scheduler_source = nullptr;
|
||||||
|
const char* socket_name = nullptr;
|
||||||
|
|
||||||
|
uint32_t mod = WLR_MODIFIER_ALT;
|
||||||
|
std::string terminal = "kitty";
|
||||||
|
int caps = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Server* S = nullptr;
|
||||||
|
|
||||||
|
static void relayout() {
|
||||||
|
struct wlr_box b = S->layout.box();
|
||||||
|
int n = 0;
|
||||||
|
for (auto* t : S->toplevels)
|
||||||
|
if (t->mapped) n++;
|
||||||
|
if (n == 0)
|
||||||
|
return;
|
||||||
|
if (n == 1) {
|
||||||
|
for (auto* t : S->toplevels) {
|
||||||
|
if (!t->mapped) continue;
|
||||||
|
t->gx = b.x; t->gy = b.y; t->gw = b.width; t->gh = b.height;
|
||||||
|
t->tree.set_position(b.x, b.y);
|
||||||
|
wlr::Toplevel(t->xdg.toplevel()).set_size(b.width, b.height);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int mw = b.width / 2;
|
||||||
|
int i = 0;
|
||||||
|
for (auto* t : S->toplevels) {
|
||||||
|
if (!t->mapped) continue;
|
||||||
|
if (i == 0) {
|
||||||
|
t->gx = b.x; t->gy = b.y; t->gw = mw; t->gh = b.height;
|
||||||
|
t->tree.set_position(b.x, b.y);
|
||||||
|
wlr::Toplevel(t->xdg.toplevel()).set_size(mw, b.height);
|
||||||
|
} else {
|
||||||
|
int sh = b.height / (n - 1);
|
||||||
|
t->gx = b.x + mw; t->gy = b.y + (i - 1) * sh; t->gw = b.width - mw; t->gh = sh;
|
||||||
|
t->tree.set_position(t->gx, t->gy);
|
||||||
|
wlr::Toplevel(t->xdg.toplevel()).set_size(b.width - mw, sh);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void focus(ToplevelState* t) {
|
||||||
|
if (S->focused == t)
|
||||||
|
return;
|
||||||
|
if (S->focused)
|
||||||
|
wlr::Toplevel(S->focused->xdg.toplevel()).set_activated(false);
|
||||||
|
S->focused = t;
|
||||||
|
if (!t) {
|
||||||
|
S->seat.keyboard_notify_enter(nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wlr::Toplevel(t->xdg.toplevel()).set_activated(true);
|
||||||
|
t->tree.raise_to_top();
|
||||||
|
S->seat.keyboard_notify_enter(t->xdg.surface());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cycle_focus(int dir) {
|
||||||
|
std::vector<ToplevelState*> vis;
|
||||||
|
for (auto* t : S->toplevels)
|
||||||
|
if (t->mapped) vis.push_back(t);
|
||||||
|
if (vis.empty())
|
||||||
|
return;
|
||||||
|
int idx = 0;
|
||||||
|
for (size_t i = 0; i < vis.size(); i++)
|
||||||
|
if (vis[i] == S->focused) idx = (int)i;
|
||||||
|
idx = (idx + dir + (int)vis.size()) % (int)vis.size();
|
||||||
|
focus(vis[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spawn() {
|
||||||
|
pid_t p = fork();
|
||||||
|
if (p == 0) {
|
||||||
|
if (S->socket_name)
|
||||||
|
setenv("WAYLAND_DISPLAY", S->socket_name, 1);
|
||||||
|
execlp(S->terminal.c_str(), S->terminal.c_str(), nullptr);
|
||||||
|
_exit(127);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_key(void* data) {
|
||||||
|
auto* ev = static_cast<struct wlr_keyboard_key_event*>(data);
|
||||||
|
if (ev->state != WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
|
if (S->focused)
|
||||||
|
S->seat.keyboard_notify_key(ev->time_msec, ev->keycode, ev->state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct wlr_keyboard* kb = S->keyboard;
|
||||||
|
if (!kb) {
|
||||||
|
if (S->focused)
|
||||||
|
S->seat.keyboard_notify_key(ev->time_msec, ev->keycode, ev->state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t mods = wlr_keyboard_get_modifiers(kb);
|
||||||
|
xkb_keysym_t sym = xkb_state_key_get_one_sym(kb->xkb_state, ev->keycode + 8);
|
||||||
|
if (mods & S->mod) {
|
||||||
|
if (sym == XKB_KEY_Return) { spawn(); return; }
|
||||||
|
if (sym == XKB_KEY_q) { if (S->focused) wlr::Toplevel(S->focused->xdg.toplevel()).close(); return; }
|
||||||
|
if (sym == XKB_KEY_j) { cycle_focus(1); return; }
|
||||||
|
if (sym == XKB_KEY_k) { cycle_focus(-1); return; }
|
||||||
|
if (sym == XKB_KEY_Tab) { cycle_focus(1); return; }
|
||||||
|
}
|
||||||
|
if (S->focused)
|
||||||
|
S->seat.keyboard_notify_key(ev->time_msec, ev->keycode, ev->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_motion(void* data) {
|
||||||
|
auto* ev = static_cast<struct wlr_pointer_motion_event*>(data);
|
||||||
|
S->seat.pointer_notify_motion(ev->time_msec, S->cursor.raw()->x, S->cursor.raw()->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_button(void* data) {
|
||||||
|
auto* ev = static_cast<struct wlr_pointer_button_event*>(data);
|
||||||
|
S->seat.pointer_notify_button(ev->time_msec, ev->button, ev->state);
|
||||||
|
if (ev->state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
|
double cx = S->cursor.raw()->x, cy = S->cursor.raw()->y;
|
||||||
|
for (int i = (int)S->toplevels.size() - 1; i >= 0; i--) {
|
||||||
|
ToplevelState* t = S->toplevels[i];
|
||||||
|
if (t->mapped && cx >= t->gx && cx < t->gx + t->gw &&
|
||||||
|
cy >= t->gy && cy < t->gy + t->gh) {
|
||||||
|
focus(t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_axis(void* data) {
|
||||||
|
auto* ev = static_cast<struct wlr_pointer_axis_event*>(data);
|
||||||
|
S->seat.pointer_notify_axis(ev->time_msec, ev->orientation, ev->delta, ev->delta_discrete, ev->source);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_frame(void*) {
|
||||||
|
S->seat.pointer_notify_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_new_toplevel(void* data) {
|
||||||
|
auto* t = static_cast<struct wlr_xdg_toplevel*>(data);
|
||||||
|
ToplevelState* tn = new ToplevelState{
|
||||||
|
wlr::XdgSurface{t->base},
|
||||||
|
wlr::Tree(wlr_scene_xdg_surface_create(S->root.raw(), t->base)),
|
||||||
|
};
|
||||||
|
S->toplevels.push_back(tn);
|
||||||
|
|
||||||
|
tn->xdg.on_map([tn](void*) {
|
||||||
|
tn->mapped = true;
|
||||||
|
relayout();
|
||||||
|
focus(tn);
|
||||||
|
});
|
||||||
|
tn->xdg.on_unmap([tn](void*) {
|
||||||
|
tn->mapped = false;
|
||||||
|
relayout();
|
||||||
|
if (S->focused == tn)
|
||||||
|
cycle_focus(1);
|
||||||
|
});
|
||||||
|
tn->xdg.on_destroy([tn](void*) {
|
||||||
|
auto it = std::find(S->toplevels.begin(), S->toplevels.end(), tn);
|
||||||
|
if (it != S->toplevels.end())
|
||||||
|
S->toplevels.erase(it);
|
||||||
|
if (S->focused == tn)
|
||||||
|
S->focused = nullptr;
|
||||||
|
if (tn->tree)
|
||||||
|
wlr_scene_node_destroy(&tn->tree.raw()->node);
|
||||||
|
delete tn;
|
||||||
|
relayout();
|
||||||
|
});
|
||||||
|
|
||||||
|
wlr::Toplevel(t).on_set_title([tn](void* d) {
|
||||||
|
const char* s = static_cast<struct wlr_xdg_toplevel*>(d)->title;
|
||||||
|
tn->title = s ? s : "";
|
||||||
|
});
|
||||||
|
|
||||||
|
wl_event_loop_add_idle(S->display.event_loop(),
|
||||||
|
[](void* d) {
|
||||||
|
auto* s = static_cast<struct wlr_xdg_surface*>(d);
|
||||||
|
if (s->initialized)
|
||||||
|
wlr_xdg_surface_schedule_configure(s);
|
||||||
|
}, t->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_new_output(void* data) {
|
||||||
|
auto* o = static_cast<struct wlr_output*>(data);
|
||||||
|
wlr::Output out(o);
|
||||||
|
out.set_preferred_mode();
|
||||||
|
wlr_output_init_render(o, S->allocator.raw(), S->renderer.raw());
|
||||||
|
wlr_output_create_global(o, S->display.raw());
|
||||||
|
struct wlr_scene_output* so = wlr_scene_output_create(S->scene.raw(), o);
|
||||||
|
wlr_scene_output_set_position(so, 0, 0);
|
||||||
|
S->outputs.push_back(so);
|
||||||
|
S->layout.add_auto_output(o);
|
||||||
|
wl_event_source_timer_update(S->scheduler_source, 0);
|
||||||
|
static bool spawned = false;
|
||||||
|
if (!spawned) {
|
||||||
|
spawned = true;
|
||||||
|
spawn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_new_input(void* data) {
|
||||||
|
auto* dev = static_cast<struct wlr_input_device*>(data);
|
||||||
|
if (dev->type == WLR_INPUT_DEVICE_KEYBOARD) {
|
||||||
|
struct wlr_keyboard* kb = wlr_keyboard_from_input_device(dev);
|
||||||
|
wlr::Keyboard k(kb);
|
||||||
|
k.set_default_keymap();
|
||||||
|
S->keyboard = kb;
|
||||||
|
S->seat.set_keyboard(k);
|
||||||
|
S->key_sink.connect(&kb->events.key, on_key);
|
||||||
|
S->caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||||
|
} else {
|
||||||
|
S->cursor.attach_input_device(dev);
|
||||||
|
if (dev->type == WLR_INPUT_DEVICE_POINTER)
|
||||||
|
S->caps |= WL_SEAT_CAPABILITY_POINTER;
|
||||||
|
else if (dev->type == WLR_INPUT_DEVICE_TOUCH)
|
||||||
|
S->caps |= WL_SEAT_CAPABILITY_TOUCH;
|
||||||
|
}
|
||||||
|
S->seat.set_capabilities((uint32_t)S->caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void commit_outputs() {
|
||||||
|
for (struct wlr_scene_output* so : S->outputs)
|
||||||
|
wlr_scene_output_commit(so, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int frame_tick(void* data) {
|
||||||
|
(void)data;
|
||||||
|
commit_outputs();
|
||||||
|
wl_event_source_timer_update(S->scheduler_source, 16);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_config() {
|
||||||
|
const char* home = getenv("HOME");
|
||||||
|
std::string path = std::string(home ? home : "") + "/.config/testwm/testwm.conf";
|
||||||
|
if (getenv("TESTWM_CONFIG"))
|
||||||
|
path = getenv("TESTWM_CONFIG");
|
||||||
|
std::ifstream f(path);
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(f, line)) {
|
||||||
|
line.erase(0, line.find_first_not_of(" \t"));
|
||||||
|
if (line.empty() || line[0] == '#')
|
||||||
|
continue;
|
||||||
|
auto eq = line.find('=');
|
||||||
|
if (eq == std::string::npos)
|
||||||
|
continue;
|
||||||
|
std::string k = line.substr(0, eq), v = line.substr(eq + 1);
|
||||||
|
k.erase(k.find_last_not_of(" \t") + 1);
|
||||||
|
v.erase(0, v.find_first_not_of(" \t"));
|
||||||
|
v.erase(v.find_last_not_of(" \t") + 1);
|
||||||
|
if (k == "terminal") S->terminal = v;
|
||||||
|
else if (k == "modifier") S->mod = (v == "super" || v == "win" || v == "logo") ? WLR_MODIFIER_LOGO : WLR_MODIFIER_ALT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Server server;
|
||||||
|
S = &server;
|
||||||
|
|
||||||
|
load_config();
|
||||||
|
|
||||||
|
if (!S->renderer.init_wl_display(S->display))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
S->cursor.attach_output_layout(S->layout.raw());
|
||||||
|
S->cursor.on_motion(on_motion);
|
||||||
|
S->cursor.on_button(on_button);
|
||||||
|
S->cursor.on_axis(on_axis);
|
||||||
|
S->cursor.on_frame(on_frame);
|
||||||
|
|
||||||
|
float bg_color[4] = {0.08f, 0.08f, 0.12f, 1.0f};
|
||||||
|
wlr::Rect bg(wlr_scene_rect_create(S->scene.root(), 4096, 4096, bg_color));
|
||||||
|
(void)bg;
|
||||||
|
|
||||||
|
S->backend.on_new_output(on_new_output);
|
||||||
|
S->backend.on_new_input(on_new_input);
|
||||||
|
S->xdg_shell.on_new_toplevel(on_new_toplevel);
|
||||||
|
|
||||||
|
S->scheduler_source = wl_event_loop_add_timer(S->display.event_loop(), frame_tick, nullptr);
|
||||||
|
|
||||||
|
const char* socket = S->display.add_socket_auto();
|
||||||
|
S->socket_name = socket;
|
||||||
|
if (!socket)
|
||||||
|
return 1;
|
||||||
|
fprintf(stderr,
|
||||||
|
"testWM: WAYLAND_DISPLAY=%s\n"
|
||||||
|
"testWM: bindings: Alt+Enter spawn '%s', Alt+Q close, Alt+J/Alt+K cycle focus, click to focus\n",
|
||||||
|
socket, S->terminal.c_str());
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
if (!S->backend.start())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
S->display.run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wlr/util/box.h>
|
||||||
|
|
||||||
|
#include "wlr/wlr.hpp"
|
||||||
|
|
||||||
|
namespace wlr {
|
||||||
|
|
||||||
|
class Geometry {
|
||||||
|
public:
|
||||||
|
Geometry() = default;
|
||||||
|
Geometry(int x, int y, int w, int h) : m_box{x, y, w, h} {}
|
||||||
|
explicit Geometry(const struct wlr_box& b) : m_box(b) {}
|
||||||
|
|
||||||
|
struct wlr_box* raw() { return &m_box; }
|
||||||
|
const struct wlr_box* raw() const { return &m_box; }
|
||||||
|
|
||||||
|
int x() const { return m_box.x; }
|
||||||
|
int y() const { return m_box.y; }
|
||||||
|
int width() const { return m_box.width; }
|
||||||
|
int height() const { return m_box.height; }
|
||||||
|
|
||||||
|
void set(int x, int y, int w, int h) {
|
||||||
|
m_box.x = x; m_box.y = y; m_box.width = w; m_box.height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(double px, double py) const {
|
||||||
|
return wlr_box_contains_point(&m_box, px, py);
|
||||||
|
}
|
||||||
|
bool intersects(const Geometry& o) const {
|
||||||
|
struct wlr_box dest;
|
||||||
|
return wlr_box_intersection(&dest, &m_box, &o.m_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct wlr_box m_box{};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pixman.h>
|
||||||
|
|
||||||
|
#include "wlr/wlr.hpp"
|
||||||
|
|
||||||
|
namespace wlr {
|
||||||
|
|
||||||
|
struct Box {
|
||||||
|
int x = 0, y = 0, width = 0, height = 0;
|
||||||
|
pixman_box32 to_box() const { return {x, y, x + width, y + height}; }
|
||||||
|
static Box from_box(pixman_box32 b) {
|
||||||
|
return {b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Color {
|
||||||
|
float r = 1.0f, g = 1.0f, b = 1.0f, a = 1.0f;
|
||||||
|
void apply(float out[4]) const {
|
||||||
|
out[0] = r; out[1] = g; out[2] = b; out[3] = a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CornerRadii {
|
||||||
|
uint16_t top_left = 0, top_right = 0, bottom_right = 0, bottom_left = 0;
|
||||||
|
|
||||||
|
CornerRadii() = default;
|
||||||
|
CornerRadii(uint16_t all) : top_left(all), top_right(all), bottom_right(all), bottom_left(all) {}
|
||||||
|
CornerRadii(uint16_t tl, uint16_t tr, uint16_t br, uint16_t bl)
|
||||||
|
: top_left(tl), top_right(tr), bottom_right(br), bottom_left(bl) {}
|
||||||
|
|
||||||
|
fx_corner_radii raw() const {
|
||||||
|
return fx_corner_radii{top_left, top_right, bottom_right, bottom_left};
|
||||||
|
}
|
||||||
|
static CornerRadii from_radii(fx_corner_radii r) {
|
||||||
|
return {r.top_left, r.top_right, r.bottom_right, r.bottom_left};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
+19
-11
@@ -4,7 +4,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "wlr/wlr.hpp"
|
#include "wlr/wlr.hpp"
|
||||||
#include "wlr/scene.hpp"
|
#include "wlr/color.hpp"
|
||||||
|
|
||||||
namespace wlr {
|
namespace wlr {
|
||||||
|
|
||||||
@@ -36,16 +36,6 @@ protected:
|
|||||||
struct wlr_scene_node* m_node;
|
struct wlr_scene_node* m_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Tree : public Node {
|
|
||||||
public:
|
|
||||||
Tree(struct wlr_scene_tree* tree) : Node(&tree->node), m_tree(tree) {}
|
|
||||||
struct wlr_scene_tree* raw() const { return m_tree; }
|
|
||||||
void reparent(Node& n) { wlr_scene_node_reparent(n.raw(), m_tree); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct wlr_scene_tree* m_tree;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Rect : public Node {
|
class Rect : public Node {
|
||||||
public:
|
public:
|
||||||
Rect(struct wlr_scene_rect* rect) : Node(&rect->node), m_rect(rect) {}
|
Rect(struct wlr_scene_rect* rect) : Node(&rect->node), m_rect(rect) {}
|
||||||
@@ -127,4 +117,22 @@ private:
|
|||||||
struct wlr_scene_surface* m_surface;
|
struct wlr_scene_surface* m_surface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Tree : public Node {
|
||||||
|
public:
|
||||||
|
Tree(struct wlr_scene_tree* tree) : Node(&tree->node), m_tree(tree) {}
|
||||||
|
struct wlr_scene_tree* raw() const { return m_tree; }
|
||||||
|
void reparent(Node& n) { wlr_scene_node_reparent(n.raw(), m_tree); }
|
||||||
|
|
||||||
|
Tree add_tree() { return Tree{wlr_scene_tree_create(m_tree)}; }
|
||||||
|
Rect add_rect(int w, int h, const Color& c) {
|
||||||
|
float col[4]; c.apply(col);
|
||||||
|
return Rect{wlr_scene_rect_create(m_tree, w, h, col)};
|
||||||
|
}
|
||||||
|
Buffer add_buffer() { return Buffer{wlr_scene_buffer_create(m_tree, nullptr)}; }
|
||||||
|
Surface add_surface(struct wlr_surface* s) { return Surface{wlr_scene_surface_create(m_tree, s)}; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct wlr_scene_tree* m_tree;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ public:
|
|||||||
const char* make() const { return m_output->make; }
|
const char* make() const { return m_output->make; }
|
||||||
const char* model() const { return m_output->model; }
|
const char* model() const { return m_output->model; }
|
||||||
|
|
||||||
|
int width() const { return m_output->width; }
|
||||||
|
int height() const { return m_output->height; }
|
||||||
|
enum wl_output_transform transform() const { return m_output->transform; }
|
||||||
|
struct wlr_output_mode* current_mode() const { return m_output->current_mode; }
|
||||||
|
|
||||||
struct wlr_output_mode* preferred_mode() const {
|
struct wlr_output_mode* preferred_mode() const {
|
||||||
return wlr_output_preferred_mode(m_output);
|
return wlr_output_preferred_mode(m_output);
|
||||||
}
|
}
|
||||||
@@ -32,6 +37,15 @@ public:
|
|||||||
wlr_output_state_finish(&state);
|
wlr_output_state_finish(&state);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
bool set_mode(struct wlr_output_mode* mode) {
|
||||||
|
if (!mode) return false;
|
||||||
|
struct wlr_output_state state;
|
||||||
|
wlr_output_state_init(&state);
|
||||||
|
wlr_output_state_set_mode(&state, mode);
|
||||||
|
bool ok = wlr_output_commit_state(m_output, &state);
|
||||||
|
wlr_output_state_finish(&state);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct wlr_output* m_output;
|
struct wlr_output* m_output;
|
||||||
|
|||||||
+10
-32
@@ -1,10 +1,11 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pixman.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "wlr/wlr.hpp"
|
#include "wlr/wlr.hpp"
|
||||||
|
#include "wlr/color.hpp"
|
||||||
|
#include "wlr/node.hpp"
|
||||||
|
|
||||||
namespace wlr {
|
namespace wlr {
|
||||||
|
|
||||||
@@ -36,39 +37,16 @@ public:
|
|||||||
void set_blur_saturation(float saturation) { wlr_scene_set_blur_saturation(m_scene, saturation); }
|
void set_blur_saturation(float saturation) { wlr_scene_set_blur_saturation(m_scene, saturation); }
|
||||||
struct wlr_scene_tree* root() { return &m_scene->tree; }
|
struct wlr_scene_tree* root() { return &m_scene->tree; }
|
||||||
|
|
||||||
|
Tree add_tree() { return Tree{wlr_scene_tree_create(&m_scene->tree)}; }
|
||||||
|
Rect add_rect(int w, int h, const Color& c) {
|
||||||
|
float col[4]; c.apply(col);
|
||||||
|
return Rect{wlr_scene_rect_create(&m_scene->tree, w, h, col)};
|
||||||
|
}
|
||||||
|
Buffer add_buffer() { return Buffer{wlr_scene_buffer_create(&m_scene->tree, nullptr)}; }
|
||||||
|
Surface add_surface(struct wlr_surface* s) { return Surface{wlr_scene_surface_create(&m_scene->tree, s)}; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct wlr_scene* m_scene;
|
struct wlr_scene* m_scene;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Box {
|
|
||||||
int x = 0, y = 0, width = 0, height = 0;
|
|
||||||
pixman_box32 to_box() const { return {x, y, x + width, y + height}; }
|
|
||||||
static Box from_box(pixman_box32 b) {
|
|
||||||
return {b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Color {
|
|
||||||
float r = 1.0f, g = 1.0f, b = 1.0f, a = 1.0f;
|
|
||||||
void apply(float out[4]) const {
|
|
||||||
out[0] = r; out[1] = g; out[2] = b; out[3] = a;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CornerRadii {
|
|
||||||
uint16_t top_left = 0, top_right = 0, bottom_right = 0, bottom_left = 0;
|
|
||||||
|
|
||||||
CornerRadii() = default;
|
|
||||||
CornerRadii(uint16_t all) : top_left(all), top_right(all), bottom_right(all), bottom_left(all) {}
|
|
||||||
CornerRadii(uint16_t tl, uint16_t tr, uint16_t br, uint16_t bl)
|
|
||||||
: top_left(tl), top_right(tr), bottom_right(br), bottom_left(bl) {}
|
|
||||||
|
|
||||||
fx_corner_radii raw() const {
|
|
||||||
return fx_corner_radii{top_left, top_right, bottom_right, bottom_left};
|
|
||||||
}
|
|
||||||
static CornerRadii from_radii(fx_corner_radii r) {
|
|
||||||
return {r.top_left, r.top_right, r.bottom_right, r.bottom_left};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,17 @@ public:
|
|||||||
}
|
}
|
||||||
void warp(double x, double y) { wlr_cursor_warp(m_cursor, nullptr, x, y); }
|
void warp(double x, double y) { wlr_cursor_warp(m_cursor, nullptr, x, y); }
|
||||||
|
|
||||||
|
void on_motion(std::function<void(void*)> cb) { m_motion.connect(&m_cursor->events.motion, std::move(cb)); }
|
||||||
|
void on_button(std::function<void(void*)> cb) { m_button.connect(&m_cursor->events.button, std::move(cb)); }
|
||||||
|
void on_axis(std::function<void(void*)> cb) { m_axis.connect(&m_cursor->events.axis, std::move(cb)); }
|
||||||
|
void on_frame(std::function<void(void*)> cb) { m_frame.connect(&m_cursor->events.frame, std::move(cb)); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct wlr_cursor* m_cursor;
|
struct wlr_cursor* m_cursor;
|
||||||
|
SignalSink m_motion;
|
||||||
|
SignalSink m_button;
|
||||||
|
SignalSink m_axis;
|
||||||
|
SignalSink m_frame;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Keyboard {
|
class Keyboard {
|
||||||
@@ -71,6 +80,16 @@ public:
|
|||||||
void keyboard_notify_key(uint32_t time, uint32_t keycode, enum wl_keyboard_key_state state) {
|
void keyboard_notify_key(uint32_t time, uint32_t keycode, enum wl_keyboard_key_state state) {
|
||||||
wlr_seat_keyboard_notify_key(m_seat, time, keycode, state);
|
wlr_seat_keyboard_notify_key(m_seat, time, keycode, state);
|
||||||
}
|
}
|
||||||
|
void keyboard_notify_enter(struct wlr_surface* surface,
|
||||||
|
uint32_t* keycodes = nullptr, size_t num_keycodes = 0,
|
||||||
|
struct wlr_keyboard_modifiers* modifiers = nullptr) {
|
||||||
|
wlr_seat_keyboard_notify_enter(m_seat, surface, keycodes, num_keycodes, modifiers);
|
||||||
|
}
|
||||||
|
void keyboard_clear_focus() { wlr_seat_keyboard_clear_focus(m_seat); }
|
||||||
|
void pointer_notify_enter(struct wlr_surface* surface, double sx, double sy) {
|
||||||
|
wlr_seat_pointer_notify_enter(m_seat, surface, sx, sy);
|
||||||
|
}
|
||||||
|
void pointer_clear_focus() { wlr_seat_pointer_clear_focus(m_seat); }
|
||||||
void pointer_notify_motion(uint32_t time, double sx, double sy) {
|
void pointer_notify_motion(uint32_t time, double sx, double sy) {
|
||||||
wlr_seat_pointer_notify_motion(m_seat, time, sx, sy);
|
wlr_seat_pointer_notify_motion(m_seat, time, sx, sy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ extern "C" {
|
|||||||
#include <wlr/types/wlr_pointer.h>
|
#include <wlr/types/wlr_pointer.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_xdg_shell.h>
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
|
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
|
#include <wlr/util/box.h>
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/render/allocator.h>
|
#include <wlr/render/allocator.h>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "wlr/wlr.hpp"
|
||||||
|
#include "wlr/display.hpp"
|
||||||
|
#include "wlr/signals.hpp"
|
||||||
|
#include "wlr/xdg_shell.hpp"
|
||||||
|
|
||||||
|
namespace wlr {
|
||||||
|
|
||||||
|
class XdgToplevelDecoration {
|
||||||
|
public:
|
||||||
|
enum Mode { None = 0, ClientSide = 1, ServerSide = 2 };
|
||||||
|
|
||||||
|
XdgToplevelDecoration(struct wlr_xdg_toplevel_decoration_v1* d) : m_dec(d) {}
|
||||||
|
struct wlr_xdg_toplevel_decoration_v1* raw() const { return m_dec; }
|
||||||
|
explicit operator bool() const { return m_dec != nullptr; }
|
||||||
|
|
||||||
|
Mode current_mode() const { return static_cast<Mode>(m_dec->current.mode); }
|
||||||
|
Mode requested_mode() const { return static_cast<Mode>(m_dec->requested_mode); }
|
||||||
|
void set_mode(Mode m) {
|
||||||
|
wlr_xdg_toplevel_decoration_v1_set_mode(m_dec,
|
||||||
|
static_cast<enum wlr_xdg_toplevel_decoration_v1_mode>(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
Toplevel toplevel() const { return Toplevel{m_dec->toplevel}; }
|
||||||
|
|
||||||
|
void on_request_mode(std::function<void(void*)> cb) {
|
||||||
|
m_request.connect(&m_dec->events.request_mode, std::move(cb));
|
||||||
|
}
|
||||||
|
void on_destroy(std::function<void(void*)> cb) {
|
||||||
|
m_destroy.connect(&m_dec->events.destroy, std::move(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct wlr_xdg_toplevel_decoration_v1* m_dec;
|
||||||
|
SignalSink m_request;
|
||||||
|
SignalSink m_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
class XdgDecorationManager {
|
||||||
|
public:
|
||||||
|
XdgDecorationManager(Display& d)
|
||||||
|
: m_mgr(wlr_xdg_decoration_manager_v1_create(d.raw())) {}
|
||||||
|
struct wlr_xdg_decoration_manager_v1* raw() const { return m_mgr; }
|
||||||
|
explicit operator bool() const { return m_mgr != nullptr; }
|
||||||
|
|
||||||
|
void on_new_toplevel_decoration(std::function<void(void*)> cb) {
|
||||||
|
m_new.connect(&m_mgr->events.new_toplevel_decoration, std::move(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct wlr_xdg_decoration_manager_v1* m_mgr;
|
||||||
|
SignalSink m_new;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ public:
|
|||||||
uint32_t set_size(int w, int h) { return wlr_xdg_toplevel_set_size(m_toplevel, w, h); }
|
uint32_t set_size(int w, int h) { return wlr_xdg_toplevel_set_size(m_toplevel, w, h); }
|
||||||
uint32_t set_activated(bool activated) { return wlr_xdg_toplevel_set_activated(m_toplevel, activated); }
|
uint32_t set_activated(bool activated) { return wlr_xdg_toplevel_set_activated(m_toplevel, activated); }
|
||||||
uint32_t set_maximized(bool maximized) { return wlr_xdg_toplevel_set_maximized(m_toplevel, maximized); }
|
uint32_t set_maximized(bool maximized) { return wlr_xdg_toplevel_set_maximized(m_toplevel, maximized); }
|
||||||
|
void close() { wlr_xdg_toplevel_send_close(m_toplevel); }
|
||||||
|
|
||||||
void on_request_move(std::function<void(void*)> cb) {
|
void on_request_move(std::function<void(void*)> cb) {
|
||||||
m_requestMove.connect(&m_toplevel->events.request_move, std::move(cb));
|
m_requestMove.connect(&m_toplevel->events.request_move, std::move(cb));
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
#include "wlr/node.hpp"
|
#include "wlr/node.hpp"
|
||||||
|
#include "wlr/box.hpp"
|
||||||
|
#include "wlr/xdg_decoration.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <wlr/version.h>
|
#include <wlr/version.h>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user