river-status support

This commit is contained in:
bluepython508
2025-03-17 15:10:28 +00:00
parent a5e4b682fe
commit b31915e6a6
10 changed files with 433 additions and 5 deletions

3
.gitignore vendored
View File

@@ -4,3 +4,6 @@ protocol/*.h
riverguile riverguile
/result /result
/.direnv /.direnv
/.cache
protocol/*.html
/compile_commands.json

View File

@@ -24,10 +24,12 @@ OBJ=src/riverguile.o $\
src/load-script.o $\ src/load-script.o $\
protocol/river-layout-v3.o $\ protocol/river-layout-v3.o $\
protocol/ext-idle-notify-v1.o $\ protocol/ext-idle-notify-v1.o $\
protocol/river-control-unstable-v1.o protocol/river-control-unstable-v1.o $\
protocol/river-status-unstable-v1.o
GEN=protocol/river-layout-v3.c protocol/river-layout-v3.h $\ GEN=protocol/river-layout-v3.c protocol/river-layout-v3.h $\
protocol/ext-idle-notify-v1.c protocol/ext-idle-notify-v1.h $\ protocol/ext-idle-notify-v1.c protocol/ext-idle-notify-v1.h $\
protocol/river-control-unstable-v1.c protocol/river-control-unstable-v1.h protocol/river-control-unstable-v1.c protocol/river-control-unstable-v1.h $\
protocol/river-status-unstable-v1.c protocol/river-status-unstable-v1.h
all: riverguile all: riverguile

View File

@@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="river_status_unstable_v1">
<copyright>
Copyright 2020 The River Developers
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</copyright>
<interface name="zriver_status_manager_v1" version="4">
<description summary="manage river status objects">
A global factory for objects that receive status information specific
to river. It could be used to implement, for example, a status bar.
</description>
<request name="destroy" type="destructor">
<description summary="destroy the river_status_manager object">
This request indicates that the client will not use the
river_status_manager object any more. Objects that have been created
through this instance are not affected.
</description>
</request>
<request name="get_river_output_status">
<description summary="create an output status object">
This creates a new river_output_status object for the given wl_output.
</description>
<arg name="id" type="new_id" interface="zriver_output_status_v1"/>
<arg name="output" type="object" interface="wl_output"/>
</request>
<request name="get_river_seat_status">
<description summary="create a seat status object">
This creates a new river_seat_status object for the given wl_seat.
</description>
<arg name="id" type="new_id" interface="zriver_seat_status_v1"/>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
</interface>
<interface name="zriver_output_status_v1" version="4">
<description summary="track output tags and focus">
This interface allows clients to receive information about the current
windowing state of an output.
</description>
<request name="destroy" type="destructor">
<description summary="destroy the river_output_status object">
This request indicates that the client will not use the
river_output_status object any more.
</description>
</request>
<event name="focused_tags">
<description summary="focused tags of the output">
Sent once binding the interface and again whenever the tag focus of
the output changes.
</description>
<arg name="tags" type="uint" summary="32-bit bitfield"/>
</event>
<event name="view_tags">
<description summary="tag state of an output's views">
Sent once on binding the interface and again whenever the tag state
of the output changes.
</description>
<arg name="tags" type="array" summary="array of 32-bit bitfields"/>
</event>
<event name="urgent_tags" since="2">
<description summary="tags of the output with an urgent view">
Sent once on binding the interface and again whenever the set of
tags with at least one urgent view changes.
</description>
<arg name="tags" type="uint" summary="32-bit bitfield"/>
</event>
<event name="layout_name" since="4">
<description summary="name of the layout">
Sent once on binding the interface should a layout name exist and again
whenever the name changes.
</description>
<arg name="name" type="string" summary="layout name"/>
</event>
<event name="layout_name_clear" since="4">
<description summary="name of the layout">
Sent when the current layout name has been removed without a new one
being set, for example when the active layout generator disconnects.
</description>
</event>
</interface>
<interface name="zriver_seat_status_v1" version="3">
<description summary="track seat focus">
This interface allows clients to receive information about the current
focus of a seat. Note that (un)focused_output events will only be sent
if the client has bound the relevant wl_output globals.
</description>
<request name="destroy" type="destructor">
<description summary="destroy the river_seat_status object">
This request indicates that the client will not use the
river_seat_status object any more.
</description>
</request>
<event name="focused_output">
<description summary="the seat focused an output">
Sent on binding the interface and again whenever an output gains focus.
</description>
<arg name="output" type="object" interface="wl_output"/>
</event>
<event name="unfocused_output">
<description summary="the seat unfocused an output">
Sent whenever an output loses focus.
</description>
<arg name="output" type="object" interface="wl_output"/>
</event>
<event name="focused_view">
<description summary="information on the focused view">
Sent once on binding the interface and again whenever the focused
view or a property thereof changes. The title may be an empty string
if no view is focused or the focused view did not set a title.
</description>
<arg name="title" type="string" summary="title of the focused view"/>
</event>
<event name="mode" since="3">
<description summary="the active mode changed">
Sent once on binding the interface and again whenever a new mode
is entered (e.g. with riverctl enter-mode foobar).
</description>
<arg name="name" type="string" summary="name of the mode"/>
</event>
</interface>
</protocol>

View File

@@ -4,12 +4,22 @@
#include <libguile.h> #include <libguile.h>
#include <string.h> #include <string.h>
#include "libguile/bitvectors.h"
#include "libguile/boolean.h"
#include "libguile/foreign-object.h"
#include "libguile/list.h"
#include "libguile/numbers.h"
#include "libguile/pairs.h"
#include "libguile/scm.h"
#include "libguile/strings.h"
#include "libguile/symbols.h"
#include "riverguile.h" #include "riverguile.h"
#include "output.h" #include "output.h"
#include "seat.h" #include "seat.h"
#include "river-control-unstable-v1.h" #include "river-control-unstable-v1.h"
#include "call-new-output-handler.h" #include "call-new-output-handler.h"
#include "wayland-util.h"
/** /**
* ISO C forbids casting a function pointer to a void pointer because on some * ISO C forbids casting a function pointer to a void pointer because on some
@@ -246,6 +256,83 @@ error:
return SCM_UNSPECIFIED; return SCM_UNSPECIFIED;
} }
static SCM output_t;
static SCM scm_str(const char *chars) {
if (chars != NULL)
return scm_from_utf8_string(chars);
return scm_from_utf8_string("");
}
static SCM bitvector_tags(uint32_t tags) {
SCM bitvector = scm_c_make_bitvector(32, SCM_BOOL_F);
for (int i = 0; i < 32; i++) {
if ((tags & (1 << i)) != 0)
scm_c_bitvector_set_bit_x(bitvector, i);
}
return bitvector;
}
static SCM output_for(struct Output *output) {
SCM output_scm = scm_make_foreign_object_0(output_t);
scm_foreign_object_set_x(output_scm, 0, scm_from_int(output->name));
scm_foreign_object_set_x(output_scm, 1,
bitvector_tags(output->tags.focused_tags));
SCM view_tags = SCM_EOL;
for (ssize_t i = output->tags.view_tags_len - 1; i >= 0; i--)
view_tags = scm_cons(bitvector_tags(*(output->tags.view_tags + i)), view_tags);
scm_foreign_object_set_x(output_scm, 2, view_tags);
scm_foreign_object_set_x(output_scm, 3,
bitvector_tags(output->tags.urgent_tags));
scm_foreign_object_set_x(output_scm, 4, scm_str(output->tags.layout_name));
return output_scm;
}
static SCM outputs(void) {
SCM lst = SCM_EOL;
struct Output *output, *tmp_o;
wl_list_for_each_safe(output, tmp_o, &context.outputs, link)
lst = scm_cons(output_for(output), lst);
return scm_reverse_x(lst, SCM_EOL);
}
static SCM seat_t;
// Assumes there's only one seat available
static SCM seat(void) {
struct Seat *seat;
// Take the first seat
wl_list_for_each(seat, &context.seats, link)
break;
struct Output *output = NULL;
if ( seat->status.focused_output != NULL )
wl_list_for_each(output, &context.outputs, link)
if ( output->wl_output == seat->status.focused_output )
break;
return scm_make_foreign_object_3(
seat_t,
output != NULL ? output_for(output) : SCM_BOOL_F,
scm_str(seat->status.focused_view_title),
scm_str(seat->status.mode));
}
#define getters(X) \
X(output_t, output_name, "output-name", 0) \
X(output_t, output_focused_tags, "output-focused-tags", 1) \
X(output_t, output_view_tags, "output-view-tags", 2) \
X(output_t, output_urgent_tags, "output-urgent-tags", 3) \
X(output_t, output_layout_name, "output-layout-name", 4) \
X(seat_t, seat_focused_output, "seat-focused-output", 0) \
X(seat_t, seat_focused_view_title, "seat-focused-view-title", 1) \
X(seat_t, seat_mode, "seat-mode", 2)
#define X(t, c, scm, i) static SCM c (SCM output) { scm_assert_foreign_object_type(t, output); return scm_foreign_object_ref(output, i); }
getters(X)
#undef X
static void *load_script_inner (void *data) static void *load_script_inner (void *data)
{ {
const char *path = (char *)data; const char *path = (char *)data;
@@ -265,6 +352,30 @@ void *load_script (void *data)
scm_c_define_gsubr_fix("install-handler", 2, 0, 0, install_handler); scm_c_define_gsubr_fix("install-handler", 2, 0, 0, install_handler);
scm_c_define_gsubr_fix("riverctl", 1, 0, 1, riverctl); scm_c_define_gsubr_fix("riverctl", 1, 0, 1, riverctl);
output_t = scm_make_foreign_object_type(
scm_from_utf8_symbol("output"),
scm_list_5(scm_from_utf8_symbol("name"),
scm_from_utf8_symbol("focused-tags"),
scm_from_utf8_symbol("view-tags"),
scm_from_utf8_symbol("urgent-tags"),
scm_from_utf8_symbol("layout")),
NULL);
seat_t = scm_make_foreign_object_type(
scm_from_utf8_symbol("seat"),
scm_list_3(scm_from_utf8_symbol("focused-output"),
scm_from_utf8_symbol("focused-view-title"),
scm_from_utf8_symbol("mode")),
NULL);
scm_c_define_gsubr_fix("outputs", 0, 0, 0, outputs);
scm_c_define_gsubr_fix("seat", 0, 0, 0, seat);
#define X(t, c, scm, i) scm_c_define_gsubr_fix(scm, 1, 0, 0, c);
getters(X)
#undef X
/* Continuation barrier causes stack unwind on exceptions to stop here. /* Continuation barrier causes stack unwind on exceptions to stop here.
* Otherwise the entire stack created by scm_with_guile() would be * Otherwise the entire stack created by scm_with_guile() would be
* unwound. This makes responding to exceptions nicer. * unwound. This makes responding to exceptions nicer.

View File

@@ -7,11 +7,13 @@
#include "river-layout-v3.h" #include "river-layout-v3.h"
#include "river-status-unstable-v1.h"
#include "riverguile.h" #include "riverguile.h"
#include "output.h" #include "output.h"
#include "call-layout-demand-handler.h" #include "call-layout-demand-handler.h"
#include "call-user-command-handler.h" #include "call-user-command-handler.h"
#include "call-new-output-handler.h" #include "call-new-output-handler.h"
#include "wayland-util.h"
static void layout_handle_layout_demand (void *data, struct river_layout_v3 *river_layout_v3, static void layout_handle_layout_demand (void *data, struct river_layout_v3 *river_layout_v3,
uint32_t view_count, uint32_t width, uint32_t height, uint32_t tags, uint32_t serial) uint32_t view_count, uint32_t width, uint32_t height, uint32_t tags, uint32_t serial)
@@ -95,6 +97,50 @@ void output_configure_layout (struct Output *output)
river_layout_v3_add_listener(output->layout, &layout_listener, output); river_layout_v3_add_listener(output->layout, &layout_listener, output);
} }
void output_set_focused_tags(void *data, struct zriver_output_status_v1 *output, uint32_t tags) {
((struct Output *) data)->tags.focused_tags = tags;
}
void output_set_urgent_tags(void *data, struct zriver_output_status_v1 *output, uint32_t tags) {
((struct Output *) data)->tags.urgent_tags = tags;
}
void output_set_view_tags(void *data, struct zriver_output_status_v1 *output, struct wl_array *tags) {
struct Output *output_ = data;
if (output_->tags.view_tags != NULL)
free(output_->tags.view_tags);
output_->tags.view_tags_len = tags->size;
output_->tags.view_tags = calloc(tags->size, 1);
assert(output_->tags.view_tags != NULL);
memcpy(output_->tags.view_tags, tags->data, tags->size);
}
void output_set_layout_name(void *data, struct zriver_output_status_v1 *output, const char *name) {
struct Output *output_ = data;
if (output_->tags.layout_name != NULL)
free(output_->tags.layout_name);
output_->tags.layout_name = calloc(1, strlen(name) + 1);
assert(output_->tags.layout_name != NULL);
strcpy(output_->tags.layout_name, name);
}
void output_clear_layout_name(void *data, struct zriver_output_status_v1 *output) {
struct Output *output_ = data;
if (output_->tags.layout_name != NULL)
free(output_->tags.layout_name);
output_->tags.layout_name = NULL;
}
static const struct zriver_output_status_v1_listener status_listener = {
.focused_tags = output_set_focused_tags,
.urgent_tags = output_set_urgent_tags,
.view_tags = output_set_view_tags,
.layout_name = output_set_layout_name,
.layout_name_clear = output_clear_layout_name,
};
struct Output *output_create (struct wl_output *wl_output, uint32_t name) struct Output *output_create (struct wl_output *wl_output, uint32_t name)
{ {
struct Output *output = calloc(1, sizeof(struct Output)); struct Output *output = calloc(1, sizeof(struct Output));
@@ -131,11 +177,23 @@ struct Output *output_create (struct wl_output *wl_output, uint32_t name)
return output; return output;
} }
void output_status_init(struct Output* output) {
output->status = zriver_status_manager_v1_get_river_output_status(context.status_manager, output->wl_output);
zriver_output_status_v1_add_listener(output->status, &status_listener, output);
}
void output_destroy (struct Output *output) void output_destroy (struct Output *output)
{ {
if ( output->layout != NULL ) if ( output->layout != NULL )
river_layout_v3_destroy(output->layout); river_layout_v3_destroy(output->layout);
if ( output->tags.view_tags != NULL )
free(output->tags.view_tags);
if ( output->tags.layout_name != NULL )
free(output->tags.layout_name);
if ( output->status != NULL )
zriver_output_status_v1_destroy(output->status);
assert(output->wl_output != NULL); assert(output->wl_output != NULL);
wl_output_destroy(output->wl_output); wl_output_destroy(output->wl_output);
free(output); free(output);

View File

@@ -2,15 +2,28 @@
#define RIVERGUILE_OUTPUT_H #define RIVERGUILE_OUTPUT_H
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "river-layout-v3.h" #include "river-layout-v3.h"
#include "river-status-unstable-v1.h"
struct OutputTags {
uint32_t focused_tags;
uint32_t *view_tags;
size_t view_tags_len;
uint32_t urgent_tags;
char *layout_name;
};
struct Output struct Output
{ {
struct wl_list link; struct wl_list link;
struct wl_output *wl_output; struct wl_output *wl_output;
struct river_layout_v3 *layout; struct river_layout_v3 *layout;
struct zriver_output_status_v1 *status;
uint32_t name; uint32_t name;
/* Tags for the next user command. Due to backwards compatability, the /* Tags for the next user command. Due to backwards compatability, the
@@ -19,10 +32,14 @@ struct Output
* guaranteed to be received. * guaranteed to be received.
*/ */
uint32_t user_command_tags; uint32_t user_command_tags;
struct OutputTags tags;
}; };
struct Output *output_create (struct wl_output *wl_output, uint32_t name); struct Output *output_create (struct wl_output *wl_output, uint32_t name);
void output_destroy (struct Output *output); void output_destroy (struct Output *output);
void output_status_init(struct Output* output);
void output_configure_layout (struct Output *output); void output_configure_layout (struct Output *output);
#endif #endif

View File

@@ -1,3 +1,4 @@
#include "wayland-client-core.h"
#include <ctype.h> #include <ctype.h>
#include <signal.h> #include <signal.h>
#include <stdbool.h> #include <stdbool.h>
@@ -21,6 +22,7 @@
#include "river-layout-v3.h" #include "river-layout-v3.h"
#include "ext-idle-notify-v1.h" #include "ext-idle-notify-v1.h"
#include "river-control-unstable-v1.h" #include "river-control-unstable-v1.h"
#include "river-status-unstable-v1.h"
#include "load-script.h" #include "load-script.h"
#include "call-exit-handler.h" #include "call-exit-handler.h"
@@ -66,6 +68,12 @@ static void registry_handle_global (void *data, struct wl_registry *registry,
registry, name, &ext_idle_notifier_v1_interface, 1 registry, name, &ext_idle_notifier_v1_interface, 1
); );
} }
else if ( strcmp(interface, zriver_status_manager_v1_interface.name) == 0 )
{
context.status_manager = wl_registry_bind(
registry, name, &zriver_status_manager_v1_interface, 4
);
}
else if ( strcmp(interface, wl_output_interface.name) == 0 ) else if ( strcmp(interface, wl_output_interface.name) == 0 )
{ {
struct wl_output *wl_output = wl_registry_bind( struct wl_output *wl_output = wl_registry_bind(
@@ -135,7 +143,8 @@ static const struct wl_callback_listener sync_callback_listener = {
static void sync_handle_done (void *data, struct wl_callback *wl_callback, uint32_t other_data) static void sync_handle_done (void *data, struct wl_callback *wl_callback, uint32_t other_data)
{ {
static int i = 0; static int i = 0;
if ( i == 1 ) i++;
if ( i > 2 )
{ {
assert(context.mode == ONESHOT); assert(context.mode == ONESHOT);
context.loop = false; context.loop = false;
@@ -145,6 +154,22 @@ static void sync_handle_done (void *data, struct wl_callback *wl_callback, uint3
wl_callback_destroy(wl_callback); wl_callback_destroy(wl_callback);
context.sync_callback = NULL; context.sync_callback = NULL;
if (i == 1) {
struct Output *output;
wl_list_for_each(output, &context.outputs, link) {
output_status_init(output);
}
struct Seat *seat;
wl_list_for_each(seat, &context.seats, link) {
seat_status_init(seat);
}
context.sync_callback = wl_display_sync(context.wl_display);
wl_callback_add_listener(context.sync_callback, &sync_callback_listener, NULL);
return;
}
/* Load the script after connecting to the server and binding interfaces /* Load the script after connecting to the server and binding interfaces
* to allow calling Wayland requests from it. * to allow calling Wayland requests from it.
*/ */
@@ -171,8 +196,6 @@ static void sync_handle_done (void *data, struct wl_callback *wl_callback, uint3
/* Oneshot mode. Sync again so we are sure that all commands /* Oneshot mode. Sync again so we are sure that all commands
* have been send, then exit. * have been send, then exit.
*/ */
assert(i == 0);
i++;
context.sync_callback = wl_display_sync(context.wl_display); context.sync_callback = wl_display_sync(context.wl_display);
wl_callback_add_listener(context.sync_callback, &sync_callback_listener, NULL); wl_callback_add_listener(context.sync_callback, &sync_callback_listener, NULL);
fputs("INFO: No handlers installed: Riverguile will exit.\n", stderr); fputs("INFO: No handlers installed: Riverguile will exit.\n", stderr);
@@ -381,6 +404,8 @@ int main (int argc, char *argv[])
river_layout_manager_v3_destroy(context.layout_manager); river_layout_manager_v3_destroy(context.layout_manager);
if ( context.river_control != NULL ) if ( context.river_control != NULL )
zriver_control_v1_destroy(context.river_control); zriver_control_v1_destroy(context.river_control);
if ( context.status_manager != NULL )
zriver_status_manager_v1_destroy(context.status_manager);
if ( context.sync_callback != NULL ) if ( context.sync_callback != NULL )
wl_callback_destroy(context.sync_callback); wl_callback_destroy(context.sync_callback);
if ( context.wl_registry != NULL ) if ( context.wl_registry != NULL )

View File

@@ -5,6 +5,7 @@
#include <wayland-client.h> #include <wayland-client.h>
#include <libguile.h> #include <libguile.h>
#include "river-status-unstable-v1.h"
#include "seat.h" #include "seat.h"
enum Riverguile_mode enum Riverguile_mode
@@ -37,6 +38,7 @@ struct Context
struct river_layout_manager_v3 *layout_manager; struct river_layout_manager_v3 *layout_manager;
struct ext_idle_notifier_v1 *idle_notifier; struct ext_idle_notifier_v1 *idle_notifier;
struct zriver_control_v1 *river_control; struct zriver_control_v1 *river_control;
struct zriver_status_manager_v1 *status_manager;
struct wl_list seats; struct wl_list seats;
struct wl_list outputs; struct wl_list outputs;

View File

@@ -7,9 +7,11 @@
#include "ext-idle-notify-v1.h" #include "ext-idle-notify-v1.h"
#include "river-status-unstable-v1.h"
#include "riverguile.h" #include "riverguile.h"
#include "seat.h" #include "seat.h"
#include "call-idle-handler.h" #include "call-idle-handler.h"
#include "wayland-client-protocol.h"
static void idle_notification_handle_idled (void *data, static void idle_notification_handle_idled (void *data,
struct ext_idle_notification_v1 *ext_idle_notification_v1) struct ext_idle_notification_v1 *ext_idle_notification_v1)
@@ -90,6 +92,43 @@ static void idle_destroy (struct Idle *idle)
free(idle); free(idle);
} }
void seat_focused_output(void *seat, struct zriver_seat_status_v1 *status_, struct wl_output *output) {
struct SeatStatus *status = &((struct Seat *)seat)->status;
status->focused_output = output;
}
void seat_unfocused_output(void *seat, struct zriver_seat_status_v1 *status_, struct wl_output *output) {
struct SeatStatus *status = &((struct Seat *)seat)->status;
status->focused_output = NULL;
}
void seat_focused_view(void *seat, struct zriver_seat_status_v1 *status_, const char *title) {
struct SeatStatus *status = &((struct Seat *)seat)->status;
if (status->focused_view_title != NULL)
free(status->focused_view_title);
status->focused_view_title = calloc(1, strlen(title) + 1);
assert(status->focused_view_title != NULL);
strcpy(status->focused_view_title, title);
}
void seat_mode(void *seat, struct zriver_seat_status_v1 *status_, const char *mode) {
struct SeatStatus *status = &((struct Seat *)seat)->status;
if (status->mode != NULL)
free(status->mode);
status->mode = calloc(1, strlen(mode) + 1);
assert(status->mode!= NULL);
strcpy(status->mode, mode);
}
static const struct zriver_seat_status_v1_listener seat_status_listener = {
.focused_output = seat_focused_output,
.unfocused_output = seat_unfocused_output,
.focused_view = seat_focused_view,
.mode = seat_mode
};
struct Seat *seat_create (struct wl_seat *wl_seat, uint32_t name) struct Seat *seat_create (struct wl_seat *wl_seat, uint32_t name)
{ {
struct Seat *seat = calloc(1, sizeof(struct Seat)); struct Seat *seat = calloc(1, sizeof(struct Seat));
@@ -107,6 +146,11 @@ struct Seat *seat_create (struct wl_seat *wl_seat, uint32_t name)
return seat; return seat;
} }
void seat_status_init(struct Seat *seat) {
seat->status_monitor = zriver_status_manager_v1_get_river_seat_status(context.status_manager, seat->wl_seat);
zriver_seat_status_v1_add_listener(seat->status_monitor, &seat_status_listener, seat);
}
void seat_destroy (struct Seat *seat) void seat_destroy (struct Seat *seat)
{ {
struct Idle *idle, *tmp_i; struct Idle *idle, *tmp_i;
@@ -116,6 +160,14 @@ void seat_destroy (struct Seat *seat)
idle_destroy(idle); idle_destroy(idle);
} }
if (seat->status.focused_output != NULL)
free(seat->status.focused_view_title);
if (seat->status.mode != NULL)
free(seat->status.mode);
if ( seat->status_monitor != NULL )
zriver_seat_status_v1_destroy(seat->status_monitor);
assert(seat->wl_seat != NULL); assert(seat->wl_seat != NULL);
wl_seat_destroy(seat->wl_seat); wl_seat_destroy(seat->wl_seat);
free(seat); free(seat);

View File

@@ -4,14 +4,23 @@
#include <stdbool.h> #include <stdbool.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <libguile.h> #include <libguile.h>
#include "river-status-unstable-v1.h"
struct SeatStatus {
struct wl_output *focused_output;
char *focused_view_title;
char *mode;
};
struct Seat struct Seat
{ {
struct wl_list link; struct wl_list link;
struct wl_seat *wl_seat; struct wl_seat *wl_seat;
struct zriver_seat_status_v1 *status_monitor;
uint32_t name; uint32_t name;
struct wl_list idles; struct wl_list idles;
struct SeatStatus status;
}; };
struct Idle struct Idle
@@ -24,6 +33,7 @@ struct Idle
}; };
struct Seat *seat_create (struct wl_seat *wl_seat, uint32_t name); struct Seat *seat_create (struct wl_seat *wl_seat, uint32_t name);
void seat_status_init(struct Seat *seat);
void seat_destroy (struct Seat *seat); void seat_destroy (struct Seat *seat);
bool seat_add_idle (struct Seat *seat, SCM proc, uint32_t ms); bool seat_add_idle (struct Seat *seat, SCM proc, uint32_t ms);