This repository has been archived by the owner on Nov 1, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 341
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
315 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
#define _POSIX_C_SOURCE 199309L | ||
#include <string.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <time.h> | ||
#include <inttypes.h> | ||
#include <unistd.h> | ||
#include <sys/mman.h> | ||
#include <wayland-server.h> | ||
#include <wlr/backend.h> | ||
#include <wlr/backend/session.h> | ||
#include <wlr/render.h> | ||
#include <wlr/render/matrix.h> | ||
#include <wlr/render/gles2.h> | ||
#include <wlr/types/wlr_output.h> | ||
#include <wlr/types/wlr_surface.h> | ||
#include <wlr/types/wlr_wl_shell.h> | ||
#include <wlr/types/wlr_xdg_shell_v6.h> | ||
#include <wlr/types/wlr_seat.h> | ||
#include <wlr/types/wlr_data_device_manager.h> | ||
#include <wlr/types/wlr_gamma_control.h> | ||
#include <wlr/types/wlr_screenshooter.h> | ||
#include "wlr/types/wlr_compositor.h" | ||
#include <wlr/xwayland.h> | ||
#include <xkbcommon/xkbcommon.h> | ||
#include <wlr/util/log.h> | ||
#include "shared.h" | ||
|
||
// TODO: move to common header? | ||
int os_create_anonymous_file(off_t size); | ||
|
||
struct sample_state { | ||
struct wlr_renderer *renderer; | ||
struct wlr_compositor *wlr_compositor; | ||
struct wlr_wl_shell *wl_shell; | ||
struct wlr_seat *wl_seat; | ||
struct wlr_xdg_shell_v6 *xdg_shell; | ||
struct wlr_data_device_manager *data_device_manager; | ||
struct wl_resource *focus; | ||
struct wl_listener keyboard_bound; | ||
struct wlr_xwayland *xwayland; | ||
struct wlr_gamma_control_manager *gamma_control_manager; | ||
struct wlr_screenshooter *screenshooter; | ||
int keymap_fd; | ||
size_t keymap_size; | ||
uint32_t serial; | ||
}; | ||
|
||
/* | ||
* Convert timespec to milliseconds | ||
*/ | ||
static inline int64_t timespec_to_msec(const struct timespec *a) { | ||
return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; | ||
} | ||
|
||
static void output_frame_handle_surface(struct sample_state *sample, | ||
struct wlr_output *wlr_output, struct timespec *ts, | ||
struct wl_resource *_res) { | ||
struct wlr_surface *surface = wl_resource_get_user_data(_res); | ||
float matrix[16]; | ||
float transform[16]; | ||
wlr_surface_flush_damage(surface); | ||
if (surface->texture->valid) { | ||
wlr_matrix_translate(&transform, 200, 200, 0); | ||
wlr_surface_get_matrix(surface, &matrix, | ||
&wlr_output->transform_matrix, &transform); | ||
wlr_render_with_matrix(sample->renderer, surface->texture, &matrix); | ||
|
||
struct wlr_frame_callback *cb, *cnext; | ||
wl_list_for_each_safe(cb, cnext, &surface->frame_callback_list, link) { | ||
wl_callback_send_done(cb->resource, timespec_to_msec(ts)); | ||
wl_resource_destroy(cb->resource); | ||
} | ||
} | ||
} | ||
static void handle_output_frame(struct output_state *output, struct timespec *ts) { | ||
struct compositor_state *state = output->compositor; | ||
struct sample_state *sample = state->data; | ||
struct wlr_output *wlr_output = output->output; | ||
|
||
wlr_output_make_current(wlr_output); | ||
wlr_renderer_begin(sample->renderer, wlr_output); | ||
|
||
struct wlr_wl_shell_surface *wl_shell_surface; | ||
wl_list_for_each(wl_shell_surface, &sample->wl_shell->surfaces, link) { | ||
output_frame_handle_surface(sample, wlr_output, ts, wl_shell_surface->surface); | ||
} | ||
struct wlr_xdg_surface_v6 *xdg_surface; | ||
wl_list_for_each(xdg_surface, &sample->xdg_shell->surfaces, link) { | ||
output_frame_handle_surface(sample, wlr_output, ts, xdg_surface->surface); | ||
} | ||
struct wlr_x11_window *x11_window; | ||
wl_list_for_each(x11_window, &sample->xwayland->displayable_windows, link) { | ||
output_frame_handle_surface(sample, wlr_output, ts, x11_window->surface); | ||
} | ||
|
||
wlr_renderer_end(sample->renderer); | ||
wlr_output_swap_buffers(wlr_output); | ||
} | ||
|
||
static void handle_keyboard_key(struct keyboard_state *keyboard, uint32_t keycode, | ||
xkb_keysym_t sym, enum wlr_key_state key_state) { | ||
struct compositor_state *state = keyboard->compositor; | ||
struct sample_state *sample = state->data; | ||
|
||
struct wl_resource *res = NULL; | ||
struct wlr_seat_handle *seat_handle = NULL; | ||
wl_list_for_each(res, &sample->wlr_compositor->surfaces, link) { | ||
break; | ||
} | ||
|
||
if (res) { | ||
seat_handle = wlr_seat_handle_for_client(sample->wl_seat, | ||
wl_resource_get_client(res)); | ||
} | ||
|
||
if (res != sample->focus && seat_handle && seat_handle->keyboard) { | ||
struct wl_array keys; | ||
wl_array_init(&keys); | ||
wl_keyboard_send_enter(seat_handle->keyboard, ++sample->serial, res, &keys); | ||
sample->focus = res; | ||
} | ||
|
||
if (seat_handle && seat_handle->keyboard) { | ||
uint32_t depressed = xkb_state_serialize_mods(keyboard->xkb_state, | ||
XKB_STATE_MODS_DEPRESSED); | ||
uint32_t latched = xkb_state_serialize_mods(keyboard->xkb_state, | ||
XKB_STATE_MODS_LATCHED); | ||
uint32_t locked = xkb_state_serialize_mods(keyboard->xkb_state, | ||
XKB_STATE_MODS_LOCKED); | ||
uint32_t group = xkb_state_serialize_layout(keyboard->xkb_state, | ||
XKB_STATE_LAYOUT_EFFECTIVE); | ||
wl_keyboard_send_modifiers(seat_handle->keyboard, ++sample->serial, depressed, | ||
latched, locked, group); | ||
wl_keyboard_send_key(seat_handle->keyboard, ++sample->serial, 0, keycode, key_state); | ||
} | ||
} | ||
|
||
static void handle_keyboard_bound(struct wl_listener *listener, void *data) { | ||
struct wlr_seat_handle *handle = data; | ||
struct sample_state *state = wl_container_of(listener, state, keyboard_bound); | ||
|
||
wl_keyboard_send_keymap(handle->keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, | ||
state->keymap_fd, state->keymap_size); | ||
|
||
if (wl_resource_get_version(handle->keyboard) >= 2) { | ||
wl_keyboard_send_repeat_info(handle->keyboard, 25, 600); | ||
} | ||
} | ||
|
||
int main() { | ||
struct sample_state state = { 0 }; | ||
struct compositor_state compositor = { 0, | ||
.data = &state, | ||
.output_frame_cb = handle_output_frame, | ||
}; | ||
compositor_init(&compositor); | ||
|
||
state.renderer = wlr_gles2_renderer_create(compositor.backend); | ||
if (!state.renderer) { | ||
wlr_log(L_ERROR, "Could not start compositor, OOM"); | ||
exit(EXIT_FAILURE); | ||
} | ||
wl_display_init_shm(compositor.display); | ||
state.wlr_compositor = wlr_compositor_create(compositor.display, state.renderer); | ||
state.wl_shell = wlr_wl_shell_create(compositor.display); | ||
state.xdg_shell = wlr_xdg_shell_v6_create(compositor.display); | ||
state.data_device_manager = wlr_data_device_manager_create(compositor.display); | ||
state.gamma_control_manager = wlr_gamma_control_manager_create(compositor.display); | ||
state.screenshooter = wlr_screenshooter_create(compositor.display); | ||
|
||
state.wl_seat = wlr_seat_create(compositor.display, "seat0"); | ||
state.keyboard_bound.notify = handle_keyboard_bound; | ||
wl_signal_add(&state.wl_seat->events.keyboard_bound, &state.keyboard_bound); | ||
wlr_seat_set_capabilities(state.wl_seat, WL_SEAT_CAPABILITY_KEYBOARD | ||
| WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH); | ||
|
||
struct keyboard_state *kbstate; | ||
wl_list_for_each(kbstate, &compositor.keyboards, link) { | ||
char *keymap = xkb_keymap_get_as_string(kbstate->keymap, | ||
XKB_KEYMAP_FORMAT_TEXT_V1); | ||
state.keymap_size = strlen(keymap); | ||
state.keymap_fd = os_create_anonymous_file(state.keymap_size); | ||
void *ptr = mmap(NULL, state.keymap_size, | ||
PROT_READ | PROT_WRITE, | ||
MAP_SHARED, state.keymap_fd, 0); | ||
strcpy(ptr, keymap); | ||
free(keymap); | ||
break; | ||
} | ||
state.xwayland = wlr_xwayland_create(compositor.display, state.wlr_compositor); | ||
|
||
compositor.keyboard_key_cb = handle_keyboard_key; | ||
|
||
wl_display_run(compositor.display); | ||
|
||
wlr_xwayland_destroy(state.xwayland); | ||
close(state.keymap_fd); | ||
wlr_seat_destroy(state.wl_seat); | ||
wlr_screenshooter_destroy(state.screenshooter); | ||
wlr_gamma_control_manager_destroy(state.gamma_control_manager); | ||
wlr_data_device_manager_destroy(state.data_device_manager); | ||
wlr_xdg_shell_v6_destroy(state.xdg_shell); | ||
wlr_wl_shell_destroy(state.wl_shell); | ||
wlr_compositor_destroy(state.wlr_compositor); | ||
wlr_renderer_destroy(state.renderer); | ||
compositor_fini(&compositor); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#ifndef _WLR_SCREENSHOOTER_H | ||
#define _WLR_SCREENSHOOTER_H | ||
#include <wayland-server.h> | ||
|
||
struct wlr_screenshooter { | ||
struct wl_global *wl_global; | ||
|
||
void *data; | ||
}; | ||
|
||
struct wlr_screenshot { | ||
struct wl_resource *resource; | ||
struct wl_resource *output; | ||
|
||
void* data; | ||
}; | ||
|
||
struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display); | ||
void wlr_screenshooter_destroy(struct wlr_screenshooter *screenshooter); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<protocol name="orbital_screenshooter"> | ||
|
||
<interface name="orbital_screenshooter" version="1"> | ||
<request name="shoot"> | ||
<arg name="id" type="new_id" interface="orbital_screenshot"/> | ||
<arg name="output" type="object" interface="wl_output"/> | ||
<arg name="buffer" type="object" interface="wl_buffer"/> | ||
</request> | ||
</interface> | ||
|
||
<interface name="orbital_screenshot" version="1"> | ||
<event name="done"> | ||
</event> | ||
</interface> | ||
|
||
</protocol> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#include <assert.h> | ||
#include <stdlib.h> | ||
#include <wayland-server.h> | ||
#include <wlr/types/wlr_screenshooter.h> | ||
#include <wlr/types/wlr_output.h> | ||
#include <wlr/util/log.h> | ||
#include "screenshooter-protocol.h" | ||
|
||
static void screenshooter_shoot(struct wl_client *client, | ||
struct wl_resource *_screenshooter, uint32_t id, | ||
struct wl_resource *_output, struct wl_resource *_buffer) { | ||
struct wlr_screenshot *screenshot; | ||
if (!(screenshot = calloc(1, sizeof(struct wlr_screenshot)))) { | ||
return; | ||
} | ||
screenshot->output = _output; | ||
screenshot->resource = wl_resource_create(client, | ||
&orbital_screenshot_interface, wl_resource_get_version(_screenshooter), id); | ||
wlr_log(L_DEBUG, "new screenshot %p (res %p)", screenshot, screenshot->resource); | ||
wl_resource_set_implementation(screenshot->resource, NULL, screenshot, NULL); | ||
// TODO: orbital_screenshot_send_done(screenshot->resource); | ||
} | ||
|
||
static struct orbital_screenshooter_interface screenshooter_impl = { | ||
.shoot = screenshooter_shoot, | ||
}; | ||
|
||
static void screenshooter_bind(struct wl_client *wl_client, | ||
void *_screenshooter, uint32_t version, uint32_t id) { | ||
struct wlr_screenshooter *screenshooter = _screenshooter; | ||
assert(wl_client && screenshooter); | ||
if (version > 1) { | ||
wlr_log(L_ERROR, "Client requested unsupported screenshooter version, disconnecting"); | ||
wl_client_destroy(wl_client); | ||
return; | ||
} | ||
struct wl_resource *wl_resource = wl_resource_create(wl_client, | ||
&orbital_screenshooter_interface, version, id); | ||
wl_resource_set_implementation(wl_resource, &screenshooter_impl, | ||
screenshooter, NULL); | ||
} | ||
|
||
struct wlr_screenshooter *wlr_screenshooter_create(struct wl_display *display) { | ||
struct wlr_screenshooter *screenshooter = | ||
calloc(1, sizeof(struct wlr_screenshooter)); | ||
if (!screenshooter) { | ||
return NULL; | ||
} | ||
struct wl_global *wl_global = wl_global_create(display, | ||
&orbital_screenshooter_interface, 1, screenshooter, screenshooter_bind); | ||
if (!wl_global) { | ||
free(screenshooter); | ||
return NULL; | ||
} | ||
screenshooter->wl_global = wl_global; | ||
return screenshooter; | ||
} | ||
|
||
void wlr_screenshooter_destroy(struct wlr_screenshooter *screenshooter) { | ||
if (!screenshooter) { | ||
return; | ||
} | ||
// TODO: this segfault (wl_display->registry_resource_list is not init) | ||
// wl_global_destroy(screenshooter->wl_global); | ||
free(screenshooter); | ||
} |