river-status support
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,3 +4,6 @@ protocol/*.h
|
|||||||
riverguile
|
riverguile
|
||||||
/result
|
/result
|
||||||
/.direnv
|
/.direnv
|
||||||
|
/.cache
|
||||||
|
protocol/*.html
|
||||||
|
/compile_commands.json
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -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
|
||||||
|
|
||||||
|
|||||||
148
protocol/river-status-unstable-v1.xml
Normal file
148
protocol/river-status-unstable-v1.xml
Normal 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>
|
||||||
@@ -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.
|
||||||
|
|||||||
58
src/output.c
58
src/output.c
@@ -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);
|
||||||
|
|||||||
17
src/output.h
17
src/output.h
@@ -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
|
||||||
|
|||||||
@@ -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 )
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
52
src/seat.c
52
src/seat.c
@@ -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);
|
||||||
|
|||||||
10
src/seat.h
10
src/seat.h
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user