Merge pull request #781 from fwSmit/wayland-2

Add wayland support
This commit is contained in:
Nikos Tsipinakis 2021-01-18 20:28:16 +02:00 committed by GitHub
commit 77bfbc4f7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 5401 additions and 80 deletions

View File

@ -33,6 +33,14 @@ $(error "Failed to query $(PKG_CONFIG) for package 'systemd'!")
endif endif
endif endif
ifneq (0,${WAYLAND})
DATA_DIR_WAYLAND_PROTOCOLS ?= $(shell $(PKG_CONFIG) wayland-protocols --variable=pkgdatadir)
DATA_DIR_WAYLAND_PROTOCOLS := ${DATA_DIR_WAYLAND_PROTOCOLS}
ifeq (,${DATA_DIR_WAYLAND_PROTOCOLS})
$(warning "Failed to query $(PKG_CONFIG) for package 'wayland-protocols'!")
endif
endif
LIBS := $(shell $(PKG_CONFIG) --libs ${pkg_config_packs}) LIBS := $(shell $(PKG_CONFIG) --libs ${pkg_config_packs})
INCS := $(shell $(PKG_CONFIG) --cflags ${pkg_config_packs}) INCS := $(shell $(PKG_CONFIG) --cflags ${pkg_config_packs})
@ -45,7 +53,14 @@ endif
CFLAGS := ${DEFAULT_CPPFLAGS} ${CPPFLAGS} ${DEFAULT_CFLAGS} ${CFLAGS} ${INCS} -MMD -MP CFLAGS := ${DEFAULT_CPPFLAGS} ${CPPFLAGS} ${DEFAULT_CFLAGS} ${CFLAGS} ${INCS} -MMD -MP
LDFLAGS := ${DEFAULT_LDFLAGS} ${LDFLAGS} ${LIBS} LDFLAGS := ${DEFAULT_LDFLAGS} ${LDFLAGS} ${LIBS}
ifeq (0,${WAYLAND})
# without wayland support
SRC := $(sort $(shell ${FIND} src/ -not \( -path src/wayland -prune \) -name '*.c'))
else
# with Wayland support
SRC := $(sort $(shell ${FIND} src/ -name '*.c')) SRC := $(sort $(shell ${FIND} src/ -name '*.c'))
endif
OBJ := ${SRC:.c=.o} OBJ := ${SRC:.c=.o}
TEST_SRC := $(sort $(shell ${FIND} test/ -name '*.c')) TEST_SRC := $(sort $(shell ${FIND} test/ -name '*.c'))
TEST_OBJ := $(TEST_SRC:.c=.o) TEST_OBJ := $(TEST_SRC:.c=.o)
@ -118,7 +133,7 @@ docs/dunstctl.1: docs/dunstctl.pod
doc-doxygen: doc-doxygen:
${DOXYGEN} docs/internal/Doxyfile ${DOXYGEN} docs/internal/Doxyfile
.PHONY: service service-dbus service-systemd .PHONY: service service-dbus service-systemd wayland-protocols
service: service-dbus service: service-dbus
service-dbus: service-dbus:
@${SED} "s|##PREFIX##|$(PREFIX)|" org.knopwob.dunst.service.in > org.knopwob.dunst.service @${SED} "s|##PREFIX##|$(PREFIX)|" org.knopwob.dunst.service.in > org.knopwob.dunst.service
@ -128,7 +143,20 @@ service-systemd:
@${SED} "s|##PREFIX##|$(PREFIX)|" dunst.systemd.service.in > dunst.systemd.service @${SED} "s|##PREFIX##|$(PREFIX)|" dunst.systemd.service.in > dunst.systemd.service
endif endif
.PHONY: clean clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run ifneq (0,${WAYLAND})
wayland-protocols: src/wayland/protocols/wlr-layer-shell-unstable-v1.xml
mkdir -p src/wayland/protocols
wayland-scanner private-code ${DATA_DIR_WAYLAND_PROTOCOLS}/stable/xdg-shell/xdg-shell.xml src/wayland/protocols/xdg-shell.h
wayland-scanner client-header ${DATA_DIR_WAYLAND_PROTOCOLS}/stable/xdg-shell/xdg-shell.xml src/wayland/protocols/xdg-shell-client-header.h
wayland-scanner client-header ${DATA_DIR_WAYLAND_PROTOCOLS}/unstable/xdg-output/xdg-output-unstable-v1.xml src/wayland/protocols/xdg-output-unstable-v1-client-header.h
wayland-scanner private-code ${DATA_DIR_WAYLAND_PROTOCOLS}/unstable/xdg-output/xdg-output-unstable-v1.xml src/wayland/protocols/xdg-output-unstable-v1.h
wayland-scanner client-header src/wayland/protocols/wlr-layer-shell-unstable-v1.xml src/wayland/protocols/wlr-layer-shell-unstable-v1-client-header.h
wayland-scanner private-code src/wayland/protocols/wlr-layer-shell-unstable-v1.xml src/wayland/protocols/wlr-layer-shell-unstable-v1.h
wayland-scanner client-header src/wayland/protocols/idle.xml src/wayland/protocols/idle-client-header.h
wayland-scanner private-code src/wayland/protocols/idle.xml src/wayland/protocols/idle.h
endif
.PHONY: clean clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run clean-wayland-protocols
clean: clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run clean: clean-dunst clean-dunstify clean-doc clean-tests clean-coverage clean-coverage-run
clean-dunst: clean-dunst:
@ -158,6 +186,9 @@ clean-coverage-run:
${FIND} . -type f -name '*.gcov' -delete ${FIND} . -type f -name '*.gcov' -delete
${FIND} . -type f -name '*.gcda' -delete ${FIND} . -type f -name '*.gcda' -delete
clean-wayland-protocols:
rm -f src/wayland/protocols/*.h
.PHONY: install install-dunst install-dunstctl install-doc \ .PHONY: install install-dunst install-dunstctl install-doc \
install-service install-service-dbus install-service-systemd \ install-service install-service-dbus install-service-systemd \
uninstall uninstall-dunstctl \ uninstall uninstall-dunstctl \

View File

@ -26,6 +26,8 @@ Dunst has a number of build dependencies that must be present before attempting
- pango/cairo - pango/cairo
- libgtk-3-dev - libgtk-3-dev
- libnotify (for dunstify only) - libnotify (for dunstify only)
- wayland-client (can build without, see [make parameters](#make-parameters))
- wayland-protocols (optional, for recompiling protocols)
### Building ### Building
@ -38,11 +40,13 @@ sudo make install
### Make parameters ### Make parameters
- `DESTDIR=<PATH>`: Set the destination directory of the installation. (Default: `/`)
- `PREFIX=<PATH>`: Set the prefix of the installation. (Default: `/usr/local`) - `PREFIX=<PATH>`: Set the prefix of the installation. (Default: `/usr/local`)
- `BINDIR=<PATH>`: Set the `dunst` executable's path (Default: `${PREFIX}/bin`) - `BINDIR=<PATH>`: Set the `dunst` executable's path (Default: `${PREFIX}/bin`)
- `DATADIR=<PATH>`: Set the path for shared files. (Default: `${PREFIX}/share`) - `DATADIR=<PATH>`: Set the path for shared files. (Default: `${PREFIX}/share`)
- `MANDIR=<PATH>`: Set the prefix of the manpage. (Default: `${DATADIR}/man`) - `MANDIR=<PATH>`: Set the prefix of the manpage. (Default: `${DATADIR}/man`)
- `SYSTEMD=(0|1)`: Enable/Disable the systemd unit. (Default: detected via `pkg-config`) - `SYSTEMD=(0|1)`: Enable/Disable the systemd unit. (Default: detected via `pkg-config`)
- `WAYLAND=(0|1)`: Enable/Disable wayland support. (Default: 1)
- `SERVICEDIR_SYSTEMD=<PATH>`: The path to put the systemd user service file. Unused, if `SYSTEMD=0`. (Default: detected via `pkg-config`) - `SERVICEDIR_SYSTEMD=<PATH>`: The path to put the systemd user service file. Unused, if `SYSTEMD=0`. (Default: detected via `pkg-config`)
- `SERVICEDIR_DBUS=<PATH>`: The path to put the dbus service file. (Default: detected via `pkg-config`) - `SERVICEDIR_DBUS=<PATH>`: The path to put the dbus service file. (Default: detected via `pkg-config`)

View File

@ -48,6 +48,9 @@ struct settings defaults = {
.notification_height = 0, /* if notification height < font height and padding, it will be raised */ .notification_height = 0, /* if notification height < font height and padding, it will be raised */
.corner_radius = 0, .corner_radius = 0,
.force_xinerama = false,
.force_xwayland = false,
.separator_height = 2, /* height of the separator line between two notifications */ .separator_height = 2, /* height of the separator line between two notifications */
.padding = 0, .padding = 0,
.h_padding = 0, /* horizontal padding */ .h_padding = 0, /* horizontal padding */
@ -122,6 +125,8 @@ struct settings defaults = {
.progress_bar_frame_width = 1, .progress_bar_frame_width = 1,
.progress_bar = true, .progress_bar = true,
.layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
}; };
struct rule default_rules[] = { struct rule default_rules[] = {

View File

@ -20,14 +20,23 @@ VALGRIND ?= valgrind
# if you don't want to use systemd albeit installed # if you don't want to use systemd albeit installed
#SYSTEMD ?= 0 #SYSTEMD ?= 0
# Disable dependency on wayland. This will force dunst to use
# xwayland on wayland compositors
# You can also use "make WAYLAND=0" to build without wayland
# WAYLAND ?= 0
ifneq (0, ${WAYLAND})
ENABLE_WAYLAND= -DENABLE_WAYLAND
endif
# uncomment to disable parsing of dunstrc # uncomment to disable parsing of dunstrc
# or use "CFLAGS=-DSTATIC_CONFIG make" to build # or use "CFLAGS=-DSTATIC_CONFIG make" to build
#STATIC= -DSTATIC_CONFIG # Warning: This is deprecated behavior #STATIC= -DSTATIC_CONFIG # Warning: This is deprecated behavior
# flags # flags
DEFAULT_CPPFLAGS = -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\" DEFAULT_CPPFLAGS = -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\"
DEFAULT_CFLAGS = -g --std=gnu99 -pedantic -Wall -Wno-overlength-strings -Os ${STATIC} DEFAULT_CFLAGS = -g --std=gnu99 -pedantic -Wall -Wno-overlength-strings -Os ${STATIC} ${ENABLE_WAYLAND}
DEFAULT_LDFLAGS = -lm DEFAULT_LDFLAGS = -lm -lrt
CPPFLAGS_DEBUG := -DDEBUG_BUILD CPPFLAGS_DEBUG := -DDEBUG_BUILD
CFLAGS_DEBUG := -O0 CFLAGS_DEBUG := -O0
@ -41,11 +50,16 @@ pkg_config_packs := gio-2.0 \
xinerama \ xinerama \
xext \ xext \
"xrandr >= 1.5" \ "xrandr >= 1.5" \
xscrnsaver xscrnsaver \
# dunstify also needs libnotify # dunstify also needs libnotify
pkg_config_packs += libnotify pkg_config_packs += libnotify
ifneq (0,${WAYLAND})
pkg_config_packs += wayland-client
endif
ifneq (,$(findstring STATIC_CONFIG,$(CFLAGS))) ifneq (,$(findstring STATIC_CONFIG,$(CFLAGS)))
$(warning STATIC_CONFIG is deprecated behavior. It will get removed in future releases) $(warning STATIC_CONFIG is deprecated behavior. It will get removed in future releases)
endif endif

View File

@ -82,6 +82,10 @@ starts at 0. See the B<follow> setting.
Defines where the notifications should be placed in a multi-monitor setup. All Defines where the notifications should be placed in a multi-monitor setup. All
values except I<none> override the B<monitor> setting. values except I<none> override the B<monitor> setting.
On Wayland there is no difference between mouse and keyboard focus. When either
of the is used, the compositor will choose an output. This will generally be
the output last interacted with.
=over 4 =over 4
=item B<none> =item B<none>
@ -264,7 +268,27 @@ Set to 0 to disable.
A client can mark a notification as transient to bypass this setting and timeout A client can mark a notification as transient to bypass this setting and timeout
anyway. Use a rule with 'set_transient = no' to disable this behavior. anyway. Use a rule with 'set_transient = no' to disable this behavior.
Note: this doesn't work on wayland yet. Note: this doesn't work on xwayland.
=item B<layer> (Wayland only)
One of bottom, top or overlay.
Place dunst notifications on the selected layer. Using overlay
will cause notifications to be displayed above fullscreen windows, though
this may also occur at top depending on your compositor.
In Wayland, Notifications won't be delayed when in fullscreen (like when
setting B<fullscreen> to pushback in X11). This is a Wayland limitation.
The bottom layer is below all windows and above the background.
Default: overlay
=item B<force_xwayland> (values: [true/false], default: false) (Wayland only)
Force the use of X11 output, even on a wayland compositor. This setting
has no effect when not using a Wayland compositor.
=item B<font> (default: "Monospace 8") =item B<font> (default: "Monospace 8")
@ -497,7 +521,7 @@ Do not display log messages, which have lower precedence than specified
verbosity. This won't affect printing notifications on the terminal. Use verbosity. This won't affect printing notifications on the terminal. Use
the '-print' option for this. the '-print' option for this.
=item B<force_xinerama> (values: [true/false], default: false) =item B<force_xinerama> (values: [true/false], default: false) (X11 only)
Use the Xinerama extension instead of RandR for multi-monitor support. This Use the Xinerama extension instead of RandR for multi-monitor support. This
setting is provided for compatibility with older nVidia drivers that do not setting is provided for compatibility with older nVidia drivers that do not
@ -552,7 +576,7 @@ the notification sent before the user defined timeout.
=back =back
=head2 Shortcut section B<DEPRECATED SEE DUNSTCTL> =head2 Shortcut section B<DEPRECATED SEE DUNSTCTL> (X11 only)
Keyboard shortcuts are defined in the following format: "Modifier+key" where the Keyboard shortcuts are defined in the following format: "Modifier+key" where the
modifier is one of ctrl,mod1,mod2,mod3,mod4 and key is any keyboard key. modifier is one of ctrl,mod1,mod2,mod3,mod4 and key is any keyboard key.
@ -662,6 +686,29 @@ Past notifications are redisplayed in a first-in-last-out order, meaning that
pressing the history key once will bring up the most recent notification that pressing the history key once will bring up the most recent notification that
had been closed/timed out. had been closed/timed out.
=head1 WAYLAND
Dunst has Wayland support since version 1.6.0. Because the Wayland protocol
is more focused on security, some things that are possible in X11 are not
possible in Wayland. Those differences are reflected in the configuration.
The main things that change are that dunst on Wayland cannot use global
hotkeys (they are deprecated anyways, use dunstctl) and it cannot detect
if an application is fullscreen. If you want to see notifications when in
fullscreen, set B<layer = overlay> in the global options.
Note that the same limitations exist when using xwayland.
If something doesn't quite work in Wayland, please file a bug report. In the
mean time, you can try if the X11 output does work on wayland. Use
B<force_xwayland = true> for that.
If you have your dunst notifications on the same side of your display as your
status bar, you might notice that your notifications appear a bit higher or
lower than on X11. This is because the notification cannot be placed on top of
your status bar. The notifications are placed relative to your status bar,
making them appear higher or lower by the height of your status bar. We cannot
do anything about that behavior, so you will need to change your B<geometry>
variable accordingly.
=head1 RULES =head1 RULES
Rules allow the conditional modification of notifications. They are defined by Rules allow the conditional modification of notifications. They are defined by
@ -774,7 +821,7 @@ Equivalent to the C<format> setting.
The frame color color of the notification. See COLORS for possible values. The frame color color of the notification. See COLORS for possible values.
=item C<fullscreen> =item C<fullscreen> (X11 only)
One of show, delay, or pushback. One of show, delay, or pushback.
@ -789,6 +836,10 @@ Or pushback which is equivalent to delay with the difference that already
existing notifications are paused and hidden until the focus to the fullscreen existing notifications are paused and hidden until the focus to the fullscreen
window is lost. window is lost.
See B<layer> to change fullscreen behavior in Wayland
Default: show
=item C<new_icon> =item C<new_icon>
Updates the icon of the notification, it should be a path to a valid image. Updates the icon of the notification, it should be a path to a valid image.

10
dunstrc
View File

@ -247,6 +247,16 @@
# user defined timeout. # user defined timeout.
ignore_dbusclose = false ignore_dbusclose = false
### Wayland ###
# These settings are Wayland-specific. They have no effect when using X11
# Uncomment this if you want to let notications appear under fullscreen
# applications (default: overlay)
# layer = top
# Set this to true to use X11 output on Wayland.
force_xwayland = false
### Legacy ### Legacy
# Use the Xinerama extension instead of RandR for multi-monitor support. # Use the Xinerama extension instead of RandR for multi-monitor support.

View File

@ -560,6 +560,27 @@ void signal_notification_closed(struct notification *n, enum reason reason)
if (err) { if (err) {
LOG_W("Unable to close notification: %s", err->message); LOG_W("Unable to close notification: %s", err->message);
g_error_free(err); g_error_free(err);
} else {
char* reason_string;
switch (reason) {
case REASON_TIME:
reason_string="time";
break;
case REASON_USER:
reason_string="user";
break;
case REASON_SIG:
reason_string="signal";
break;
case REASON_UNDEF:
reason_string="undfined";
break;
default:
reason_string="unknown";
}
LOG_D("Queues: Closing notification for reason: %s", reason_string);
} }
} }

View File

@ -48,7 +48,7 @@ PangoFontDescription *pango_fdesc;
void draw_setup(void) void draw_setup(void)
{ {
const struct output *out = output_create(); const struct output *out = output_create(settings.force_xwayland);
output = out; output = out;
out->init(); out->init();

View File

@ -9,7 +9,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <X11/Xlib.h>
#include "dbus.h" #include "dbus.h"
#include "draw.h" #include "draw.h"
@ -57,6 +56,7 @@ static gboolean run(void *data);
void wake_up(void) void wake_up(void)
{ {
LOG_D("Waking up");
run(NULL); run(NULL);
} }
@ -86,6 +86,8 @@ static gboolean run(void *data)
gint64 sleep = queues_get_next_datachange(now); gint64 sleep = queues_get_next_datachange(now);
gint64 timeout_at = now + sleep; gint64 timeout_at = now + sleep;
LOG_D("Sleeping for %li ms", sleep/1000);
if (sleep >= 0) { if (sleep >= 0) {
if (next_timeout < now || timeout_at < next_timeout) { if (next_timeout < now || timeout_at < next_timeout) {
g_timeout_add(sleep/1000, run, NULL); g_timeout_add(sleep/1000, run, NULL);

67
src/input.c Normal file
View File

@ -0,0 +1,67 @@
#include "input.h"
#include "log.h"
#include "settings.h"
#include "queues.h"
#include <stddef.h>
#include <linux/input-event-codes.h>
void input_handle_click(unsigned int button, bool button_down, int mouse_x, int mouse_y){
LOG_I("Pointer handle button %i: %i", button, button_down);
if (button_down) {
// make sure it only reacts on button release
return;
}
enum mouse_action *acts;
switch (button) {
case BTN_LEFT:
acts = settings.mouse_left_click;
break;
case BTN_MIDDLE:
acts = settings.mouse_middle_click;
break;
case BTN_RIGHT:
acts = settings.mouse_right_click;
break;
default:
LOG_W("Unsupported mouse button: '%d'", button);
return;
}
for (int i = 0; acts[i]; i++) {
enum mouse_action act = acts[i];
if (act == MOUSE_CLOSE_ALL) {
queues_history_push_all();
return;
}
if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT) {
int y = settings.separator_height;
struct notification *n = NULL;
int first = true;
for (const GList *iter = queues_get_displayed(); iter;
iter = iter->next) {
n = iter->data;
if (mouse_y > y && mouse_y < y + n->displayed_height)
break;
y += n->displayed_height + settings.separator_height;
if (first)
y += settings.frame_width;
}
if (n) {
if (act == MOUSE_CLOSE_CURRENT) {
n->marked_for_closure = REASON_USER;
} else {
notification_do_action(n);
}
}
}
}
wake_up();
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

18
src/input.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef DUNST_INPUT_H
#define DUNST_INPUT_H
#include <stdbool.h>
/**
* Handle incoming mouse click events
*
* @param button code, A linux input event code
* @param button_down State of the button
* @param mouse_x X-position of the mouse, relative to the window
* @param mouse_y Y-position of the mouse, relative to the window
*
*/
void input_handle_click(unsigned int button, bool button_down, int mouse_x, int mouse_y);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -189,6 +189,18 @@ bool string_parse_urgency(const char *s, enum urgency *ret)
return false; return false;
} }
bool string_parse_layer(const char *s, enum zwlr_layer_shell_v1_layer *ret)
{
ASSERT_OR_RET(STR_FULL(s), false);
ASSERT_OR_RET(ret, false);
STRING_PARSE_RET("bottom", ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM);
STRING_PARSE_RET("top", ZWLR_LAYER_SHELL_V1_LAYER_TOP);
STRING_PARSE_RET("overlay", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY);
return false;
}
struct section *new_section(const char *name) struct section *new_section(const char *name)
{ {
for (int i = 0; i < section_count; i++) { for (int i = 0; i < section_count; i++) {

View File

@ -20,6 +20,7 @@ bool string_parse_mouse_action(const char *s, enum mouse_action *ret);
bool string_parse_mouse_action_list(char **s, enum mouse_action **ret); bool string_parse_mouse_action_list(char **s, enum mouse_action **ret);
bool string_parse_sepcolor(const char *s, struct separator_color_data *ret); bool string_parse_sepcolor(const char *s, struct separator_color_data *ret);
bool string_parse_urgency(const char *s, enum urgency *ret); bool string_parse_urgency(const char *s, enum urgency *ret);
bool string_parse_layer(const char *s, enum zwlr_layer_shell_v1_layer *ret);
int load_ini_file(FILE *); int load_ini_file(FILE *);
char *ini_get_path(const char *section, const char *key, const char *def); char *ini_get_path(const char *section, const char *key, const char *def);

View File

@ -3,9 +3,12 @@
#include "log.h" #include "log.h"
#include "x11/x.h" #include "x11/x.h"
#include "x11/screen.h" #include "x11/screen.h"
/* #include "wayland/wl.h" */ // Not yet
const bool is_running_wayland(void){ #ifdef ENABLE_WAYLAND
#include "wayland/wl.h"
#endif
const bool is_running_wayland(void) {
char* wayland_display = getenv("WAYLAND_DISPLAY"); char* wayland_display = getenv("WAYLAND_DISPLAY");
return !(wayland_display == NULL); return !(wayland_display == NULL);
} }
@ -30,33 +33,40 @@ const struct output output_x11 = {
have_fullscreen_window have_fullscreen_window
}; };
/* const struct output output_wl = { */ #ifdef ENABLE_WAYLAND
/* wl_init, */ const struct output output_wl = {
/* wl_deinit, */ wl_init,
wl_deinit,
/* wl_win_create, */ wl_win_create,
/* wl_win_destroy, */ wl_win_destroy,
/* wl_win_show, */ wl_win_show,
/* wl_win_hide, */ wl_win_hide,
/* wl_display_surface, */ wl_display_surface,
/* wl_win_visible, */ wl_win_visible,
/* wl_win_get_context, */ wl_win_get_context,
/* wl_get_active_screen, */ wl_get_active_screen,
/* wl_is_idle, */ wl_is_idle,
/* wl_have_fullscreen_window */ wl_have_fullscreen_window
/* }; */ };
#endif
const struct output* output_create(void) const struct output* output_create(bool force_xwayland)
{ {
if (is_running_wayland()) { #ifdef ENABLE_WAYLAND
LOG_I("System is running wayland"); if (!force_xwayland && is_running_wayland()) {
} else{ LOG_I("Using Wayland output");
LOG_I("System is running X11"); return &output_wl;
} } else {
LOG_I("Using X11 output");
return &output_x11; return &output_x11;
}
#else
return &output_x11;
#endif
} }
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -47,7 +47,7 @@ struct output {
bool (*have_fullscreen_window)(void); bool (*have_fullscreen_window)(void);
}; };
const struct output* output_create(void); const struct output* output_create(bool force_xwayland);
const bool is_running_wayland(void); const bool is_running_wayland(void);

View File

@ -144,8 +144,7 @@ static bool queues_notification_is_finished(struct notification *n, struct dunst
bool is_idle = status.fullscreen ? false : status.idle; bool is_idle = status.fullscreen ? false : status.idle;
/* don't timeout when user is idle */ /* don't timeout when user is idle */
/* NOTE: Idle is not working on wayland */ if (is_idle && !n->transient) {
if (is_idle && !n->transient && !is_running_wayland()) {
n->start = time_monotonic_now(); n->start = time_monotonic_now();
return false; return false;
} }

View File

@ -13,6 +13,7 @@
#include "rules.h" #include "rules.h"
#include "utils.h" #include "utils.h"
#include "x11/x.h" #include "x11/x.h"
#include "output.h"
#include "../config.h" #include "../config.h"
@ -118,6 +119,12 @@ void load_settings(char *cmdline_config_path)
"Force the use of the Xinerama extension" "Force the use of the Xinerama extension"
); );
settings.force_xwayland = option_get_bool(
"global",
"force_xwayland", "-force_xwayland", false,
"Force the use of the xwayland output"
);
settings.font = option_get_string( settings.font = option_get_string(
"global", "global",
"font", "-font/-fn", defaults.font, "font", "-font/-fn", defaults.font,
@ -209,6 +216,22 @@ void load_settings(char *cmdline_config_path)
"Don't timeout notifications if user is longer idle than threshold" "Don't timeout notifications if user is longer idle than threshold"
); );
#ifndef ENABLE_WAYLAND
if (is_running_wayland()){
/* We are using xwayland now. Setting force_xwayland to make sure
* the idle workaround below is activated */
settings.force_xwayland = true;
}
#endif
if (settings.force_xwayland && is_running_wayland()) {
if (settings.idle_threshold > 0)
LOG_W("Using xwayland. Disabling idle.");
/* There is no way to detect if the user is idle
* on xwayland, so turn this feature off */
settings.idle_threshold = 0;
}
settings.monitor = option_get_int( settings.monitor = option_get_int(
"global", "global",
"monitor", "-mon/-monitor", defaults.monitor, "monitor", "-mon/-monitor", defaults.monitor,
@ -486,6 +509,22 @@ void load_settings(char *cmdline_config_path)
} }
{
char *c = option_get_string(
"global",
"layer", "-layer", "overlay",
"Select the layer where notifications should be placed"
);
if (!string_parse_layer(c, &settings.layer)) {
if (c)
LOG_W("Unknown layer: '%s'", c);
settings.layer = defaults.layer;
}
g_free(c);
}
settings.min_icon_size = option_get_int( settings.min_icon_size = option_get_int(
"global", "global",
"min_icon_size", "-min_icon_size", defaults.min_icon_size, "min_icon_size", "-min_icon_size", defaults.min_icon_size,

View File

@ -4,6 +4,10 @@
#include <stdbool.h> #include <stdbool.h>
#ifdef ENABLE_WAYLAND
#include "wayland/protocols/wlr-layer-shell-unstable-v1-client-header.h"
#endif
#include "markup.h" #include "markup.h"
#include "notification.h" #include "notification.h"
#include "x11/x.h" #include "x11/x.h"
@ -15,6 +19,16 @@ enum vertical_alignment { VERTICAL_TOP, VERTICAL_CENTER, VERTICAL_BOTTOM };
enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM }; enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM };
enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD }; enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD };
enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL }; enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL };
#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
// Needed for compiling without wayland dependency
enum zwlr_layer_shell_v1_layer {
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0,
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1,
ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3,
};
#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */
struct separator_color_data { struct separator_color_data {
enum separator_color type; enum separator_color type;
@ -88,6 +102,7 @@ struct settings {
struct keyboard_shortcut history_ks; struct keyboard_shortcut history_ks;
struct keyboard_shortcut context_ks; struct keyboard_shortcut context_ks;
bool force_xinerama; bool force_xinerama;
bool force_xwayland;
int corner_radius; int corner_radius;
enum mouse_action *mouse_left_click; enum mouse_action *mouse_left_click;
enum mouse_action *mouse_middle_click; enum mouse_action *mouse_middle_click;
@ -97,6 +112,7 @@ struct settings {
int progress_bar_max_width; int progress_bar_max_width;
int progress_bar_frame_width; int progress_bar_frame_width;
bool progress_bar; bool progress_bar;
enum zwlr_layer_shell_v1_layer layer;
}; };
extern struct settings settings; extern struct settings settings;

View File

@ -0,0 +1,192 @@
/*
* libgwater-wayland - Wayland GSource
*
* Copyright © 2014-2017 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#ifdef G_LOG_DOMAIN
#undef G_LOG_DOMAIN
#endif /* G_LOG_DOMAIN */
#define G_LOG_DOMAIN "GWaterWayland"
#include <errno.h>
#include <glib.h>
#include <wayland-client.h>
#include "libgwater-wayland.h"
struct _GWaterWaylandSource {
GSource source;
gboolean display_owned;
struct wl_display *display;
gpointer fd;
int error;
};
static gboolean
_g_water_wayland_source_prepare(GSource *source, gint *timeout)
{
GWaterWaylandSource *self = (GWaterWaylandSource *)source;
*timeout = 0;
if ( wl_display_prepare_read(self->display) != 0 )
return TRUE;
else if ( wl_display_flush(self->display) < 0 )
{
self->error = errno;
return TRUE;
}
*timeout = -1;
return FALSE;
}
static gboolean
_g_water_wayland_source_check(GSource *source)
{
GWaterWaylandSource *self = (GWaterWaylandSource *)source;
if ( self->error > 0 )
return TRUE;
GIOCondition revents;
revents = g_source_query_unix_fd(source, self->fd);
if ( revents & G_IO_IN )
{
if ( wl_display_read_events(self->display) < 0 )
self->error = errno;
}
else
wl_display_cancel_read(self->display);
return ( revents > 0 );
}
static gboolean
_g_water_wayland_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
GWaterWaylandSource *self = (GWaterWaylandSource *)source;
GIOCondition revents;
revents = g_source_query_unix_fd(source, self->fd);
if ( ( self->error > 0 ) || ( revents & (G_IO_ERR | G_IO_HUP) ) )
{
errno = self->error;
self->error = 0;
if ( callback != NULL )
return callback(user_data);
return G_SOURCE_REMOVE;
}
if ( wl_display_dispatch_pending(self->display) < 0 )
{
if ( callback != NULL )
return callback(user_data);
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}
static void
_g_water_wayland_source_finalize(GSource *source)
{
GWaterWaylandSource *self = (GWaterWaylandSource *)source;
if ( self->display_owned )
wl_display_disconnect(self->display);
}
static GSourceFuncs _g_water_wayland_source_funcs = {
.prepare = _g_water_wayland_source_prepare,
.check = _g_water_wayland_source_check,
.dispatch = _g_water_wayland_source_dispatch,
.finalize = _g_water_wayland_source_finalize,
};
GWaterWaylandSource *
g_water_wayland_source_new(GMainContext *context, const gchar *name)
{
struct wl_display *display;
GWaterWaylandSource *self;
display = wl_display_connect(name);
if ( display == NULL )
return NULL;
self = g_water_wayland_source_new_for_display(context, display);
self->display_owned = TRUE;
return self;
}
GWaterWaylandSource *
g_water_wayland_source_new_for_display(GMainContext *context, struct wl_display *display)
{
g_return_val_if_fail(display != NULL, NULL);
GSource *source;
GWaterWaylandSource *self;
source = g_source_new(&_g_water_wayland_source_funcs, sizeof(GWaterWaylandSource));
self = (GWaterWaylandSource *)source;
self->display = display;
self->fd = g_source_add_unix_fd(source, wl_display_get_fd(self->display), G_IO_IN | G_IO_ERR | G_IO_HUP);
g_source_attach(source, context);
return self;
}
void
g_water_wayland_source_free(GWaterWaylandSource *self)
{
GSource * source = (GSource *)self;
g_return_if_fail(self != NULL);
g_source_destroy(source);
g_source_unref(source);
}
void
g_water_wayland_source_set_error_callback(GWaterWaylandSource *self, GSourceFunc callback, gpointer user_data, GDestroyNotify destroy_notify)
{
g_return_if_fail(self != NULL);
g_source_set_callback((GSource *)self, callback, user_data, destroy_notify);
}
struct wl_display *
g_water_wayland_source_get_display(GWaterWaylandSource *self)
{
g_return_val_if_fail(self != NULL, NULL);
return self->display;
}

View File

@ -0,0 +1,42 @@
/*
* libgwater-wayland - Wayland GSource
*
* Copyright © 2014-2017 Quentin "Sardem FF7" Glidic
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef __G_WATER_WAYLAND_H__
#define __G_WATER_WAYLAND_H__
G_BEGIN_DECLS
typedef struct _GWaterWaylandSource GWaterWaylandSource;
GWaterWaylandSource *g_water_wayland_source_new(GMainContext *context, const gchar *name);
GWaterWaylandSource *g_water_wayland_source_new_for_display(GMainContext *context, struct wl_display *display);
void g_water_wayland_source_free(GWaterWaylandSource *self);
void g_water_wayland_source_set_error_callback(GWaterWaylandSource *self, GSourceFunc callback, gpointer user_data, GDestroyNotify destroy_notify);
struct wl_display *g_water_wayland_source_get_display(GWaterWaylandSource *source);
G_END_DECLS
#endif /* __G_WATER_WAYLAND_H__ */

150
src/wayland/pool-buffer.c Normal file
View File

@ -0,0 +1,150 @@
#define _POSIX_C_SOURCE 200112L
#include <cairo/cairo.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <wayland-client.h>
#include <string.h>
#include "pool-buffer.h"
static void randname(char *buf) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i) {
buf[i] = 'A'+(r&15)+(r&16)*2;
r >>= 5;
}
}
static int anonymous_shm_open(void) {
char name[] = "/dunst-XXXXXX";
int retries = 100;
do {
randname(name + strlen(name) - 6);
--retries;
// shm_open guarantees that O_CLOEXEC is set
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
static int create_shm_file(off_t size) {
int fd = anonymous_shm_open();
if (fd < 0) {
return fd;
}
if (ftruncate(fd, size) < 0) {
close(fd);
return -1;
}
return fd;
}
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
struct pool_buffer *buffer = data;
buffer->busy = false;
}
static const struct wl_buffer_listener buffer_listener = {
.release = buffer_handle_release,
};
static struct pool_buffer *create_buffer(struct wl_shm *shm,
struct pool_buffer *buf, int32_t width, int32_t height) {
const enum wl_shm_format wl_fmt = WL_SHM_FORMAT_ARGB8888;
const cairo_format_t cairo_fmt = CAIRO_FORMAT_ARGB32;
uint32_t stride = cairo_format_stride_for_width(cairo_fmt, width);
size_t size = stride * height;
void *data = NULL;
if (size > 0) {
int fd = create_shm_file(size);
if (fd == -1) {
return NULL;
}
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
close(fd);
return NULL;
}
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
buf->buffer =
wl_shm_pool_create_buffer(pool, 0, width, height, stride, wl_fmt);
wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
wl_shm_pool_destroy(pool);
close(fd);
}
buf->data = data;
buf->size = size;
buf->width = width;
buf->height = height;
buf->surface = cairo_image_surface_create_for_data(data, cairo_fmt, width,
height, stride);
buf->cairo = cairo_create(buf->surface);
buf->pango = pango_cairo_create_context(buf->cairo);
return buf;
}
void finish_buffer(struct pool_buffer *buffer) {
if (buffer->buffer) {
wl_buffer_destroy(buffer->buffer);
}
if (buffer->cairo) {
cairo_destroy(buffer->cairo);
}
if (buffer->surface) {
cairo_surface_destroy(buffer->surface);
}
if (buffer->pango) {
g_object_unref(buffer->pango);
}
if (buffer->data) {
munmap(buffer->data, buffer->size);
}
memset(buffer, 0, sizeof(struct pool_buffer));
}
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
struct pool_buffer pool[static 2], uint32_t width, uint32_t height) {
struct pool_buffer *buffer = NULL;
for (size_t i = 0; i < 2; ++i) {
if (pool[i].busy) {
continue;
}
buffer = &pool[i];
}
if (!buffer) {
return NULL;
}
if (buffer->width != width || buffer->height != height) {
finish_buffer(buffer);
}
if (!buffer->buffer) {
if (!create_buffer(shm, buffer, width, height)) {
return NULL;
}
}
return buffer;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

26
src/wayland/pool-buffer.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef DUNST_POOL_BUFFER_H
#define DUNST_POOL_BUFFER_H
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <stdbool.h>
#include <stdint.h>
#include <wayland-client.h>
struct pool_buffer {
struct wl_buffer *buffer;
cairo_surface_t *surface;
cairo_t *cairo;
PangoContext *pango;
uint32_t width, height;
void *data;
size_t size;
bool busy;
};
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
struct pool_buffer pool[static 2], uint32_t width, uint32_t height);
void finish_buffer(struct pool_buffer *buffer);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -0,0 +1,233 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef IDLE_CLIENT_PROTOCOL_H
#define IDLE_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_idle The idle protocol
* @section page_ifaces_idle Interfaces
* - @subpage page_iface_org_kde_kwin_idle - User idle time manager
* - @subpage page_iface_org_kde_kwin_idle_timeout -
* @section page_copyright_idle Copyright
* <pre>
*
* Copyright (C) 2015 Martin Gräßlin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* </pre>
*/
struct org_kde_kwin_idle;
struct org_kde_kwin_idle_timeout;
struct wl_seat;
/**
* @page page_iface_org_kde_kwin_idle org_kde_kwin_idle
* @section page_iface_org_kde_kwin_idle_desc Description
*
* This interface allows to monitor user idle time on a given seat. The interface
* allows to register timers which trigger after no user activity was registered
* on the seat for a given interval. It notifies when user activity resumes.
*
* This is useful for applications wanting to perform actions when the user is not
* interacting with the system, e.g. chat applications setting the user as away, power
* management features to dim screen, etc..
* @section page_iface_org_kde_kwin_idle_api API
* See @ref iface_org_kde_kwin_idle.
*/
/**
* @defgroup iface_org_kde_kwin_idle The org_kde_kwin_idle interface
*
* This interface allows to monitor user idle time on a given seat. The interface
* allows to register timers which trigger after no user activity was registered
* on the seat for a given interval. It notifies when user activity resumes.
*
* This is useful for applications wanting to perform actions when the user is not
* interacting with the system, e.g. chat applications setting the user as away, power
* management features to dim screen, etc..
*/
extern const struct wl_interface org_kde_kwin_idle_interface;
/**
* @page page_iface_org_kde_kwin_idle_timeout org_kde_kwin_idle_timeout
* @section page_iface_org_kde_kwin_idle_timeout_api API
* See @ref iface_org_kde_kwin_idle_timeout.
*/
/**
* @defgroup iface_org_kde_kwin_idle_timeout The org_kde_kwin_idle_timeout interface
*/
extern const struct wl_interface org_kde_kwin_idle_timeout_interface;
#define ORG_KDE_KWIN_IDLE_GET_IDLE_TIMEOUT 0
/**
* @ingroup iface_org_kde_kwin_idle
*/
#define ORG_KDE_KWIN_IDLE_GET_IDLE_TIMEOUT_SINCE_VERSION 1
/** @ingroup iface_org_kde_kwin_idle */
static inline void
org_kde_kwin_idle_set_user_data(struct org_kde_kwin_idle *org_kde_kwin_idle, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) org_kde_kwin_idle, user_data);
}
/** @ingroup iface_org_kde_kwin_idle */
static inline void *
org_kde_kwin_idle_get_user_data(struct org_kde_kwin_idle *org_kde_kwin_idle)
{
return wl_proxy_get_user_data((struct wl_proxy *) org_kde_kwin_idle);
}
static inline uint32_t
org_kde_kwin_idle_get_version(struct org_kde_kwin_idle *org_kde_kwin_idle)
{
return wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_idle);
}
/** @ingroup iface_org_kde_kwin_idle */
static inline void
org_kde_kwin_idle_destroy(struct org_kde_kwin_idle *org_kde_kwin_idle)
{
wl_proxy_destroy((struct wl_proxy *) org_kde_kwin_idle);
}
/**
* @ingroup iface_org_kde_kwin_idle
*/
static inline struct org_kde_kwin_idle_timeout *
org_kde_kwin_idle_get_idle_timeout(struct org_kde_kwin_idle *org_kde_kwin_idle, struct wl_seat *seat, uint32_t timeout)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) org_kde_kwin_idle,
ORG_KDE_KWIN_IDLE_GET_IDLE_TIMEOUT, &org_kde_kwin_idle_timeout_interface, NULL, seat, timeout);
return (struct org_kde_kwin_idle_timeout *) id;
}
/**
* @ingroup iface_org_kde_kwin_idle_timeout
* @struct org_kde_kwin_idle_timeout_listener
*/
struct org_kde_kwin_idle_timeout_listener {
/**
* Triggered when there has not been any user activity in the requested idle time interval
*
*
*/
void (*idle)(void *data,
struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout);
/**
* Triggered on the first user activity after an idle event
*
*
*/
void (*resumed)(void *data,
struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout);
};
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
static inline int
org_kde_kwin_idle_timeout_add_listener(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout,
const struct org_kde_kwin_idle_timeout_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) org_kde_kwin_idle_timeout,
(void (**)(void)) listener, data);
}
#define ORG_KDE_KWIN_IDLE_TIMEOUT_RELEASE 0
#define ORG_KDE_KWIN_IDLE_TIMEOUT_SIMULATE_USER_ACTIVITY 1
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
#define ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
#define ORG_KDE_KWIN_IDLE_TIMEOUT_RESUMED_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
#define ORG_KDE_KWIN_IDLE_TIMEOUT_RELEASE_SINCE_VERSION 1
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
#define ORG_KDE_KWIN_IDLE_TIMEOUT_SIMULATE_USER_ACTIVITY_SINCE_VERSION 1
/** @ingroup iface_org_kde_kwin_idle_timeout */
static inline void
org_kde_kwin_idle_timeout_set_user_data(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) org_kde_kwin_idle_timeout, user_data);
}
/** @ingroup iface_org_kde_kwin_idle_timeout */
static inline void *
org_kde_kwin_idle_timeout_get_user_data(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
return wl_proxy_get_user_data((struct wl_proxy *) org_kde_kwin_idle_timeout);
}
static inline uint32_t
org_kde_kwin_idle_timeout_get_version(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
return wl_proxy_get_version((struct wl_proxy *) org_kde_kwin_idle_timeout);
}
/** @ingroup iface_org_kde_kwin_idle_timeout */
static inline void
org_kde_kwin_idle_timeout_destroy(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
wl_proxy_destroy((struct wl_proxy *) org_kde_kwin_idle_timeout);
}
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
static inline void
org_kde_kwin_idle_timeout_release(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
wl_proxy_marshal((struct wl_proxy *) org_kde_kwin_idle_timeout,
ORG_KDE_KWIN_IDLE_TIMEOUT_RELEASE);
wl_proxy_destroy((struct wl_proxy *) org_kde_kwin_idle_timeout);
}
/**
* @ingroup iface_org_kde_kwin_idle_timeout
*/
static inline void
org_kde_kwin_idle_timeout_simulate_user_activity(struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout)
{
wl_proxy_marshal((struct wl_proxy *) org_kde_kwin_idle_timeout,
ORG_KDE_KWIN_IDLE_TIMEOUT_SIMULATE_USER_ACTIVITY);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,68 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright (C) 2015 Martin Gräßlin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface org_kde_kwin_idle_timeout_interface;
extern const struct wl_interface wl_seat_interface;
static const struct wl_interface *idle_types[] = {
&org_kde_kwin_idle_timeout_interface,
&wl_seat_interface,
NULL,
};
static const struct wl_message org_kde_kwin_idle_requests[] = {
{ "get_idle_timeout", "nou", idle_types + 0 },
};
WL_PRIVATE const struct wl_interface org_kde_kwin_idle_interface = {
"org_kde_kwin_idle", 1,
1, org_kde_kwin_idle_requests,
0, NULL,
};
static const struct wl_message org_kde_kwin_idle_timeout_requests[] = {
{ "release", "", idle_types + 0 },
{ "simulate_user_activity", "", idle_types + 0 },
};
static const struct wl_message org_kde_kwin_idle_timeout_events[] = {
{ "idle", "", idle_types + 0 },
{ "resumed", "", idle_types + 0 },
};
WL_PRIVATE const struct wl_interface org_kde_kwin_idle_timeout_interface = {
"org_kde_kwin_idle_timeout", 1,
2, org_kde_kwin_idle_timeout_requests,
2, org_kde_kwin_idle_timeout_events,
};

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="idle">
<copyright><![CDATA[
Copyright (C) 2015 Martin Gräßlin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]></copyright>
<interface name="org_kde_kwin_idle" version="1">
<description summary="User idle time manager">
This interface allows to monitor user idle time on a given seat. The interface
allows to register timers which trigger after no user activity was registered
on the seat for a given interval. It notifies when user activity resumes.
This is useful for applications wanting to perform actions when the user is not
interacting with the system, e.g. chat applications setting the user as away, power
management features to dim screen, etc..
</description>
<request name="get_idle_timeout">
<arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/>
<arg name="seat" type="object" interface="wl_seat"/>
<arg name="timeout" type="uint" summary="The idle timeout in msec"/>
</request>
</interface>
<interface name="org_kde_kwin_idle_timeout" version="1">
<request name="release" type="destructor">
<description summary="release the timeout object"/>
</request>
<request name="simulate_user_activity">
<description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/>
</request>
<event name="idle">
<description summary="Triggered when there has not been any user activity in the requested idle time interval"/>
</event>
<event name="resumed">
<description summary="Triggered on the first user activity after an idle event"/>
</event>
</interface>
</protocol>

View File

@ -0,0 +1,559 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol
* @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces
* - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop
* - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface
* @section page_copyright_wlr_layer_shell_unstable_v1 Copyright
* <pre>
*
* Copyright © 2017 Drew DeVault
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, 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.
* </pre>
*/
struct wl_output;
struct wl_surface;
struct xdg_popup;
struct zwlr_layer_shell_v1;
struct zwlr_layer_surface_v1;
/**
* @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1
* @section page_iface_zwlr_layer_shell_v1_desc Description
*
* Clients can use this interface to assign the surface_layer role to
* wl_surfaces. Such surfaces are assigned to a "layer" of the output and
* rendered with a defined z-depth respective to each other. They may also be
* anchored to the edges and corners of a screen and specify input handling
* semantics. This interface should be suitable for the implementation of
* many desktop shell components, and a broad number of other applications
* that interact with the desktop.
* @section page_iface_zwlr_layer_shell_v1_api API
* See @ref iface_zwlr_layer_shell_v1.
*/
/**
* @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface
*
* Clients can use this interface to assign the surface_layer role to
* wl_surfaces. Such surfaces are assigned to a "layer" of the output and
* rendered with a defined z-depth respective to each other. They may also be
* anchored to the edges and corners of a screen and specify input handling
* semantics. This interface should be suitable for the implementation of
* many desktop shell components, and a broad number of other applications
* that interact with the desktop.
*/
extern const struct wl_interface zwlr_layer_shell_v1_interface;
/**
* @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1
* @section page_iface_zwlr_layer_surface_v1_desc Description
*
* An interface that may be implemented by a wl_surface, for surfaces that
* are designed to be rendered as a layer of a stacked desktop-like
* environment.
*
* Layer surface state (size, anchor, exclusive zone, margin, interactivity)
* is double-buffered, and will be applied at the time wl_surface.commit of
* the corresponding wl_surface is called.
* @section page_iface_zwlr_layer_surface_v1_api API
* See @ref iface_zwlr_layer_surface_v1.
*/
/**
* @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface
*
* An interface that may be implemented by a wl_surface, for surfaces that
* are designed to be rendered as a layer of a stacked desktop-like
* environment.
*
* Layer surface state (size, anchor, exclusive zone, margin, interactivity)
* is double-buffered, and will be applied at the time wl_surface.commit of
* the corresponding wl_surface is called.
*/
extern const struct wl_interface zwlr_layer_surface_v1_interface;
#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM
#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM
enum zwlr_layer_shell_v1_error {
/**
* wl_surface has another role
*/
ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0,
/**
* layer value is invalid
*/
ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1,
/**
* wl_surface has a buffer attached or committed
*/
ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2,
};
#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */
#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
/**
* @ingroup iface_zwlr_layer_shell_v1
* available layers for surfaces
*
* These values indicate which layers a surface can be rendered in. They
* are ordered by z depth, bottom-most first. Traditional shell surfaces
* will typically be rendered between the bottom and top layers.
* Fullscreen shell surfaces are typically rendered at the top layer.
* Multiple surfaces can share a single layer, and ordering within a
* single layer is undefined.
*/
enum zwlr_layer_shell_v1_layer {
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0,
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1,
ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3,
};
#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */
#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE 0
/**
* @ingroup iface_zwlr_layer_shell_v1
*/
#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void
zwlr_layer_shell_v1_set_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_shell_v1, user_data);
}
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void *
zwlr_layer_shell_v1_get_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_shell_v1);
}
static inline uint32_t
zwlr_layer_shell_v1_get_version(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1);
}
/** @ingroup iface_zwlr_layer_shell_v1 */
static inline void
zwlr_layer_shell_v1_destroy(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
{
wl_proxy_destroy((struct wl_proxy *) zwlr_layer_shell_v1);
}
/**
* @ingroup iface_zwlr_layer_shell_v1
*
* Create a layer surface for an existing surface. This assigns the role of
* layer_surface, or raises a protocol error if another role is already
* assigned.
*
* Creating a layer surface from a wl_surface which has a buffer attached
* or committed is a client error, and any attempts by a client to attach
* or manipulate a buffer prior to the first layer_surface.configure call
* must also be treated as errors.
*
* You may pass NULL for output to allow the compositor to decide which
* output to use. Generally this will be the one that the user most
* recently interacted with.
*
* Clients can specify a namespace that defines the purpose of the layer
* surface.
*/
static inline struct zwlr_layer_surface_v1 *
zwlr_layer_shell_v1_get_layer_surface(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, struct wl_surface *surface, struct wl_output *output, uint32_t layer, const char *namespace)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zwlr_layer_shell_v1,
ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE, &zwlr_layer_surface_v1_interface, NULL, surface, output, layer, namespace);
return (struct zwlr_layer_surface_v1 *) id;
}
#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
enum zwlr_layer_surface_v1_error {
/**
* provided surface state is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0,
/**
* size is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1,
/**
* anchor bitfield is invalid
*/
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2,
};
#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */
#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
enum zwlr_layer_surface_v1_anchor {
/**
* the top edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1,
/**
* the bottom edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2,
/**
* the left edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4,
/**
* the right edge of the anchor rectangle
*/
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8,
};
#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */
/**
* @ingroup iface_zwlr_layer_surface_v1
* @struct zwlr_layer_surface_v1_listener
*/
struct zwlr_layer_surface_v1_listener {
/**
* suggest a surface change
*
* The configure event asks the client to resize its surface.
*
* Clients should arrange their surface for the new states, and
* then send an ack_configure request with the serial sent in this
* configure event at some point before committing the new surface.
*
* The client is free to dismiss all but the last configure event
* it received.
*
* The width and height arguments specify the size of the window in
* surface-local coordinates.
*
* The size is a hint, in the sense that the client is free to
* ignore it if it doesn't resize, pick a smaller size (to satisfy
* aspect ratio or resize in steps of NxM pixels). If the client
* picks a smaller size and is anchored to two opposite anchors
* (e.g. 'top' and 'bottom'), the surface will be centered on this
* axis.
*
* If the width or height arguments are zero, it means the client
* should decide its own window dimension.
*/
void (*configure)(void *data,
struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
uint32_t serial,
uint32_t width,
uint32_t height);
/**
* surface should be closed
*
* The closed event is sent by the compositor when the surface
* will no longer be shown. The output may have been destroyed or
* the user may have asked for it to be removed. Further changes to
* the surface will be ignored. The client should destroy the
* resource after receiving this event, and create a new surface if
* they so choose.
*/
void (*closed)(void *data,
struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1);
};
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
static inline int
zwlr_layer_surface_v1_add_listener(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
const struct zwlr_layer_surface_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zwlr_layer_surface_v1,
(void (**)(void)) listener, data);
}
#define ZWLR_LAYER_SURFACE_V1_SET_SIZE 0
#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR 1
#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE 2
#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN 3
#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY 4
#define ZWLR_LAYER_SURFACE_V1_GET_POPUP 5
#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE 6
#define ZWLR_LAYER_SURFACE_V1_DESTROY 7
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1
/**
* @ingroup iface_zwlr_layer_surface_v1
*/
#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1
/** @ingroup iface_zwlr_layer_surface_v1 */
static inline void
zwlr_layer_surface_v1_set_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_surface_v1, user_data);
}
/** @ingroup iface_zwlr_layer_surface_v1 */
static inline void *
zwlr_layer_surface_v1_get_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_surface_v1);
}
static inline uint32_t
zwlr_layer_surface_v1_get_version(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Sets the size of the surface in surface-local coordinates. The
* compositor will display the surface centered with respect to its
* anchors.
*
* If you pass 0 for either value, the compositor will assign it and
* inform you of the assignment in the configure event. You must set your
* anchor to opposite edges in the dimensions you omit; not doing so is a
* protocol error. Both values are 0 by default.
*
* Size is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_size(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t width, uint32_t height)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_SIZE, width, height);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the compositor anchor the surface to the specified edges
* and corners. If two orthoginal edges are specified (e.g. 'top' and
* 'left'), then the anchor point will be the intersection of the edges
* (e.g. the top left corner of the output); otherwise the anchor point
* will be centered on that edge, or in the center if none is specified.
*
* Anchor is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_anchor(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t anchor)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_ANCHOR, anchor);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the compositor avoids occluding an area of the surface
* with other surfaces. The compositor's use of this information is
* implementation-dependent - do not assume that this region will not
* actually be occluded.
*
* A positive value is only meaningful if the surface is anchored to an
* edge, rather than a corner. The zone is the number of surface-local
* coordinates from the edge that are considered exclusive.
*
* Surfaces that do not wish to have an exclusive zone may instead specify
* how they should interact with surfaces that do. If set to zero, the
* surface indicates that it would like to be moved to avoid occluding
* surfaces with a positive excluzive zone. If set to -1, the surface
* indicates that it would not like to be moved to accomodate for other
* surfaces, and the compositor should extend it all the way to the edges
* it is anchored to.
*
* For example, a panel might set its exclusive zone to 10, so that
* maximized shell surfaces are not shown on top of it. A notification
* might set its exclusive zone to 0, so that it is moved to avoid
* occluding the panel, but shell surfaces are shown underneath it. A
* wallpaper or lock screen might set their exclusive zone to -1, so that
* they stretch below or over the panel.
*
* The default value is 0.
*
* Exclusive zone is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_exclusive_zone(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t zone)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE, zone);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Requests that the surface be placed some distance away from the anchor
* point on the output, in surface-local coordinates. Setting this value
* for edges you are not anchored to has no effect.
*
* The exclusive zone includes the margin.
*
* Margin is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_margin(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t top, int32_t right, int32_t bottom, int32_t left)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_MARGIN, top, right, bottom, left);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* Set to 1 to request that the seat send keyboard events to this layer
* surface. For layers below the shell surface layer, the seat will use
* normal focus semantics. For layers above the shell surface layers, the
* seat will always give exclusive keyboard focus to the top-most layer
* which has keyboard interactivity set to true.
*
* Layer surfaces receive pointer, touch, and tablet events normally. If
* you do not want to receive them, set the input region on your surface
* to an empty region.
*
* Events is double-buffered, see wl_surface.commit.
*/
static inline void
zwlr_layer_surface_v1_set_keyboard_interactivity(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t keyboard_interactivity)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY, keyboard_interactivity);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* This assigns an xdg_popup's parent to this layer_surface. This popup
* should have been created via xdg_surface::get_popup with the parent set
* to NULL, and this request must be invoked before committing the popup's
* initial state.
*
* See the documentation of xdg_popup for more details about what an
* xdg_popup is and how it is used.
*/
static inline void
zwlr_layer_surface_v1_get_popup(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, struct xdg_popup *popup)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_GET_POPUP, popup);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* When a configure event is received, if a client commits the
* surface in response to the configure event, then the client
* must make an ack_configure request sometime before the commit
* request, passing along the serial of the configure event.
*
* If the client receives multiple configure events before it
* can respond to one, it only has to ack the last configure event.
*
* A client is not required to commit immediately after sending
* an ack_configure request - it may even ack_configure several times
* before its next surface commit.
*
* A client may send multiple ack_configure requests before committing, but
* only the last request sent before a commit indicates which configure
* event the client really is responding to.
*/
static inline void
zwlr_layer_surface_v1_ack_configure(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t serial)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE, serial);
}
/**
* @ingroup iface_zwlr_layer_surface_v1
*
* This request destroys the layer surface.
*/
static inline void
zwlr_layer_surface_v1_destroy(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwlr_layer_surface_v1,
ZWLR_LAYER_SURFACE_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwlr_layer_surface_v1);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,91 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2017 Drew DeVault
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface zwlr_layer_surface_v1_interface;
static const struct wl_interface *wlr_layer_shell_unstable_v1_types[] = {
NULL,
NULL,
NULL,
NULL,
&zwlr_layer_surface_v1_interface,
&wl_surface_interface,
&wl_output_interface,
NULL,
NULL,
&xdg_popup_interface,
};
static const struct wl_message zwlr_layer_shell_v1_requests[] = {
{ "get_layer_surface", "no?ous", wlr_layer_shell_unstable_v1_types + 4 },
};
WL_PRIVATE const struct wl_interface zwlr_layer_shell_v1_interface = {
"zwlr_layer_shell_v1", 1,
1, zwlr_layer_shell_v1_requests,
0, NULL,
};
static const struct wl_message zwlr_layer_surface_v1_requests[] = {
{ "set_size", "uu", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_anchor", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_exclusive_zone", "i", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_margin", "iiii", wlr_layer_shell_unstable_v1_types + 0 },
{ "set_keyboard_interactivity", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "get_popup", "o", wlr_layer_shell_unstable_v1_types + 9 },
{ "ack_configure", "u", wlr_layer_shell_unstable_v1_types + 0 },
{ "destroy", "", wlr_layer_shell_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_layer_surface_v1_events[] = {
{ "configure", "uuu", wlr_layer_shell_unstable_v1_types + 0 },
{ "closed", "", wlr_layer_shell_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_layer_surface_v1_interface = {
"zwlr_layer_surface_v1", 1,
8, zwlr_layer_surface_v1_requests,
2, zwlr_layer_surface_v1_events,
};

View File

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_layer_shell_unstable_v1">
<copyright>
Copyright © 2017 Drew DeVault
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, 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="zwlr_layer_shell_v1" version="1">
<description summary="create surfaces that are layers of the desktop">
Clients can use this interface to assign the surface_layer role to
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
rendered with a defined z-depth respective to each other. They may also be
anchored to the edges and corners of a screen and specify input handling
semantics. This interface should be suitable for the implementation of
many desktop shell components, and a broad number of other applications
that interact with the desktop.
</description>
<request name="get_layer_surface">
<description summary="create a layer_surface from a surface">
Create a layer surface for an existing surface. This assigns the role of
layer_surface, or raises a protocol error if another role is already
assigned.
Creating a layer surface from a wl_surface which has a buffer attached
or committed is a client error, and any attempts by a client to attach
or manipulate a buffer prior to the first layer_surface.configure call
must also be treated as errors.
You may pass NULL for output to allow the compositor to decide which
output to use. Generally this will be the one that the user most
recently interacted with.
Clients can specify a namespace that defines the purpose of the layer
surface.
</description>
<arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
<arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
<arg name="namespace" type="string" summary="namespace for the layer surface"/>
</request>
<enum name="error">
<entry name="role" value="0" summary="wl_surface has another role"/>
<entry name="invalid_layer" value="1" summary="layer value is invalid"/>
<entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
</enum>
<enum name="layer">
<description summary="available layers for surfaces">
These values indicate which layers a surface can be rendered in. They
are ordered by z depth, bottom-most first. Traditional shell surfaces
will typically be rendered between the bottom and top layers.
Fullscreen shell surfaces are typically rendered at the top layer.
Multiple surfaces can share a single layer, and ordering within a
single layer is undefined.
</description>
<entry name="background" value="0"/>
<entry name="bottom" value="1"/>
<entry name="top" value="2"/>
<entry name="overlay" value="3"/>
</enum>
</interface>
<interface name="zwlr_layer_surface_v1" version="1">
<description summary="layer metadata interface">
An interface that may be implemented by a wl_surface, for surfaces that
are designed to be rendered as a layer of a stacked desktop-like
environment.
Layer surface state (size, anchor, exclusive zone, margin, interactivity)
is double-buffered, and will be applied at the time wl_surface.commit of
the corresponding wl_surface is called.
</description>
<request name="set_size">
<description summary="sets the size of the surface">
Sets the size of the surface in surface-local coordinates. The
compositor will display the surface centered with respect to its
anchors.
If you pass 0 for either value, the compositor will assign it and
inform you of the assignment in the configure event. You must set your
anchor to opposite edges in the dimensions you omit; not doing so is a
protocol error. Both values are 0 by default.
Size is double-buffered, see wl_surface.commit.
</description>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</request>
<request name="set_anchor">
<description summary="configures the anchor point of the surface">
Requests that the compositor anchor the surface to the specified edges
and corners. If two orthoginal edges are specified (e.g. 'top' and
'left'), then the anchor point will be the intersection of the edges
(e.g. the top left corner of the output); otherwise the anchor point
will be centered on that edge, or in the center if none is specified.
Anchor is double-buffered, see wl_surface.commit.
</description>
<arg name="anchor" type="uint" enum="anchor"/>
</request>
<request name="set_exclusive_zone">
<description summary="configures the exclusive geometry of this surface">
Requests that the compositor avoids occluding an area of the surface
with other surfaces. The compositor's use of this information is
implementation-dependent - do not assume that this region will not
actually be occluded.
A positive value is only meaningful if the surface is anchored to an
edge, rather than a corner. The zone is the number of surface-local
coordinates from the edge that are considered exclusive.
Surfaces that do not wish to have an exclusive zone may instead specify
how they should interact with surfaces that do. If set to zero, the
surface indicates that it would like to be moved to avoid occluding
surfaces with a positive excluzive zone. If set to -1, the surface
indicates that it would not like to be moved to accomodate for other
surfaces, and the compositor should extend it all the way to the edges
it is anchored to.
For example, a panel might set its exclusive zone to 10, so that
maximized shell surfaces are not shown on top of it. A notification
might set its exclusive zone to 0, so that it is moved to avoid
occluding the panel, but shell surfaces are shown underneath it. A
wallpaper or lock screen might set their exclusive zone to -1, so that
they stretch below or over the panel.
The default value is 0.
Exclusive zone is double-buffered, see wl_surface.commit.
</description>
<arg name="zone" type="int"/>
</request>
<request name="set_margin">
<description summary="sets a margin from the anchor point">
Requests that the surface be placed some distance away from the anchor
point on the output, in surface-local coordinates. Setting this value
for edges you are not anchored to has no effect.
The exclusive zone includes the margin.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="top" type="int"/>
<arg name="right" type="int"/>
<arg name="bottom" type="int"/>
<arg name="left" type="int"/>
</request>
<request name="set_keyboard_interactivity">
<description summary="requests keyboard events">
Set to 1 to request that the seat send keyboard events to this layer
surface. For layers below the shell surface layer, the seat will use
normal focus semantics. For layers above the shell surface layers, the
seat will always give exclusive keyboard focus to the top-most layer
which has keyboard interactivity set to true.
Layer surfaces receive pointer, touch, and tablet events normally. If
you do not want to receive them, set the input region on your surface
to an empty region.
Events is double-buffered, see wl_surface.commit.
</description>
<arg name="keyboard_interactivity" type="uint"/>
</request>
<request name="get_popup">
<description summary="assign this layer_surface as an xdg_popup parent">
This assigns an xdg_popup's parent to this layer_surface. This popup
should have been created via xdg_surface::get_popup with the parent set
to NULL, and this request must be invoked before committing the popup's
initial state.
See the documentation of xdg_popup for more details about what an
xdg_popup is and how it is used.
</description>
<arg name="popup" type="object" interface="xdg_popup"/>
</request>
<request name="ack_configure">
<description summary="ack a configure event">
When a configure event is received, if a client commits the
surface in response to the configure event, then the client
must make an ack_configure request sometime before the commit
request, passing along the serial of the configure event.
If the client receives multiple configure events before it
can respond to one, it only has to ack the last configure event.
A client is not required to commit immediately after sending
an ack_configure request - it may even ack_configure several times
before its next surface commit.
A client may send multiple ack_configure requests before committing, but
only the last request sent before a commit indicates which configure
event the client really is responding to.
</description>
<arg name="serial" type="uint" summary="the serial from the configure event"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the layer_surface">
This request destroys the layer surface.
</description>
</request>
<event name="configure">
<description summary="suggest a surface change">
The configure event asks the client to resize its surface.
Clients should arrange their surface for the new states, and then send
an ack_configure request with the serial sent in this configure event at
some point before committing the new surface.
The client is free to dismiss all but the last configure event it
received.
The width and height arguments specify the size of the window in
surface-local coordinates.
The size is a hint, in the sense that the client is free to ignore it if
it doesn't resize, pick a smaller size (to satisfy aspect ratio or
resize in steps of NxM pixels). If the client picks a smaller size and
is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
surface will be centered on this axis.
If the width or height arguments are zero, it means the client should
decide its own window dimension.
</description>
<arg name="serial" type="uint"/>
<arg name="width" type="uint"/>
<arg name="height" type="uint"/>
</event>
<event name="closed">
<description summary="surface should be closed">
The closed event is sent by the compositor when the surface will no
longer be shown. The output may have been destroyed or the user may
have asked for it to be removed. Further changes to the surface will be
ignored. The client should destroy the resource after receiving this
event, and create a new surface if they so choose.
</description>
</event>
<enum name="error">
<entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
<entry name="invalid_size" value="1" summary="size is invalid"/>
<entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
</enum>
<enum name="anchor" bitfield="true">
<entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
<entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
<entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
<entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
</enum>
</interface>
</protocol>

View File

@ -0,0 +1,409 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_xdg_output_unstable_v1 The xdg_output_unstable_v1 protocol
* Protocol to describe output regions
*
* @section page_desc_xdg_output_unstable_v1 Description
*
* This protocol aims at describing outputs in a way which is more in line
* with the concept of an output on desktop oriented systems.
*
* Some information are more specific to the concept of an output for
* a desktop oriented system and may not make sense in other applications,
* such as IVI systems for example.
*
* Typically, the global compositor space on a desktop system is made of
* a contiguous or overlapping set of rectangular regions.
*
* Some of the information provided in this protocol might be identical
* to their counterparts already available from wl_output, in which case
* the information provided by this protocol should be preferred to their
* equivalent in wl_output. The goal is to move the desktop specific
* concepts (such as output location within the global compositor space,
* the connector name and types, etc.) out of the core wl_output protocol.
*
* Warning! The protocol described in this file is experimental and
* backward incompatible changes may be made. Backward compatible
* changes may be added together with the corresponding interface
* version bump.
* Backward incompatible changes are done by bumping the version
* number in the protocol and interface names and resetting the
* interface version. Once the protocol is to be declared stable,
* the 'z' prefix and the version number in the protocol and
* interface names are removed and the interface version number is
* reset.
*
* @section page_ifaces_xdg_output_unstable_v1 Interfaces
* - @subpage page_iface_zxdg_output_manager_v1 - manage xdg_output objects
* - @subpage page_iface_zxdg_output_v1 - compositor logical output region
* @section page_copyright_xdg_output_unstable_v1 Copyright
* <pre>
*
* Copyright © 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
* </pre>
*/
struct wl_output;
struct zxdg_output_manager_v1;
struct zxdg_output_v1;
/**
* @page page_iface_zxdg_output_manager_v1 zxdg_output_manager_v1
* @section page_iface_zxdg_output_manager_v1_desc Description
*
* A global factory interface for xdg_output objects.
* @section page_iface_zxdg_output_manager_v1_api API
* See @ref iface_zxdg_output_manager_v1.
*/
/**
* @defgroup iface_zxdg_output_manager_v1 The zxdg_output_manager_v1 interface
*
* A global factory interface for xdg_output objects.
*/
extern const struct wl_interface zxdg_output_manager_v1_interface;
/**
* @page page_iface_zxdg_output_v1 zxdg_output_v1
* @section page_iface_zxdg_output_v1_desc Description
*
* An xdg_output describes part of the compositor geometry.
*
* This typically corresponds to a monitor that displays part of the
* compositor space.
*
* For objects version 3 onwards, after all xdg_output properties have been
* sent (when the object is created and when properties are updated), a
* wl_output.done event is sent. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
* @section page_iface_zxdg_output_v1_api API
* See @ref iface_zxdg_output_v1.
*/
/**
* @defgroup iface_zxdg_output_v1 The zxdg_output_v1 interface
*
* An xdg_output describes part of the compositor geometry.
*
* This typically corresponds to a monitor that displays part of the
* compositor space.
*
* For objects version 3 onwards, after all xdg_output properties have been
* sent (when the object is created and when properties are updated), a
* wl_output.done event is sent. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
*/
extern const struct wl_interface zxdg_output_v1_interface;
#define ZXDG_OUTPUT_MANAGER_V1_DESTROY 0
#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT 1
/**
* @ingroup iface_zxdg_output_manager_v1
*/
#define ZXDG_OUTPUT_MANAGER_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_manager_v1
*/
#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT_SINCE_VERSION 1
/** @ingroup iface_zxdg_output_manager_v1 */
static inline void
zxdg_output_manager_v1_set_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_manager_v1, user_data);
}
/** @ingroup iface_zxdg_output_manager_v1 */
static inline void *
zxdg_output_manager_v1_get_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_manager_v1);
}
static inline uint32_t
zxdg_output_manager_v1_get_version(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1);
}
/**
* @ingroup iface_zxdg_output_manager_v1
*
* Using this request a client can tell the server that it is not
* going to use the xdg_output_manager object anymore.
*
* Any objects already created through this instance are not affected.
*/
static inline void
zxdg_output_manager_v1_destroy(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
{
wl_proxy_marshal((struct wl_proxy *) zxdg_output_manager_v1,
ZXDG_OUTPUT_MANAGER_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zxdg_output_manager_v1);
}
/**
* @ingroup iface_zxdg_output_manager_v1
*
* This creates a new xdg_output object for the given wl_output.
*/
static inline struct zxdg_output_v1 *
zxdg_output_manager_v1_get_xdg_output(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, struct wl_output *output)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zxdg_output_manager_v1,
ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT, &zxdg_output_v1_interface, NULL, output);
return (struct zxdg_output_v1 *) id;
}
/**
* @ingroup iface_zxdg_output_v1
* @struct zxdg_output_v1_listener
*/
struct zxdg_output_v1_listener {
/**
* position of the output within the global compositor space
*
* The position event describes the location of the wl_output
* within the global compositor space.
*
* The logical_position event is sent after creating an xdg_output
* (see xdg_output_manager.get_xdg_output) and whenever the
* location of the output changes within the global compositor
* space.
* @param x x position within the global compositor space
* @param y y position within the global compositor space
*/
void (*logical_position)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
int32_t x,
int32_t y);
/**
* size of the output in the global compositor space
*
* The logical_size event describes the size of the output in the
* global compositor space.
*
* For example, a surface without any buffer scale, transformation
* nor rotation set, with the size matching the logical_size will
* have the same size as the corresponding output when displayed.
*
* Most regular Wayland clients should not pay attention to the
* logical size and would rather rely on xdg_shell interfaces.
*
* Some clients such as Xwayland, however, need this to configure
* their surfaces in the global compositor space as the compositor
* may apply a different scale from what is advertised by the
* output scaling property (to achieve fractional scaling, for
* example).
*
* For example, for a wl_output mode 3840×2160 and a scale factor
* 2:
*
* - A compositor not scaling the surface buffers will advertise a
* logical size of 3840×2160,
*
* - A compositor automatically scaling the surface buffers will
* advertise a logical size of 1920×1080,
*
* - A compositor using a fractional scale of 1.5 will advertise a
* logical size to 2560×1620.
*
* For example, for a wl_output mode 1920×1080 and a 90 degree
* rotation, the compositor will advertise a logical size of
* 1080x1920.
*
* The logical_size event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output) and whenever the logical size
* of the output changes, either as a result of a change in the
* applied scale or because of a change in the corresponding output
* mode(see wl_output.mode) or transform (see wl_output.transform).
* @param width width in global compositor space
* @param height height in global compositor space
*/
void (*logical_size)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
int32_t width,
int32_t height);
/**
* all information about the output have been sent
*
* This event is sent after all other properties of an xdg_output
* have been sent.
*
* This allows changes to the xdg_output properties to be seen as
* atomic, even if they happen via multiple events.
*
* For objects version 3 onwards, this event is deprecated.
* Compositors are not required to send it anymore and must send
* wl_output.done instead.
*/
void (*done)(void *data,
struct zxdg_output_v1 *zxdg_output_v1);
/**
* name of this output
*
* Many compositors will assign names to their outputs, show them
* to the user, allow them to be configured by name, etc. The
* client may wish to know this name as well to offer the user
* similar behaviors.
*
* The naming convention is compositor defined, but limited to
* alphanumeric characters and dashes (-). Each name is unique
* among all wl_output globals, but if a wl_output global is
* destroyed the same name may be reused later. The names will also
* remain consistent across sessions with the same hardware and
* software configuration.
*
* Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc.
* However, do not assume that the name is a reflection of an
* underlying DRM connector, X11 connection, etc.
*
* The name event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output). This event is only sent once
* per xdg_output, and the name does not change over the lifetime
* of the wl_output global.
* @param name output name
* @since 2
*/
void (*name)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
const char *name);
/**
* human-readable description of this output
*
* Many compositors can produce human-readable descriptions of
* their outputs. The client may wish to know this description as
* well, to communicate the user for various purposes.
*
* The description is a UTF-8 string with no convention defined for
* its contents. Examples might include 'Foocorp 11" Display' or
* 'Virtual X11 output via :1'.
*
* The description event is sent after creating an xdg_output (see
* xdg_output_manager.get_xdg_output) and whenever the description
* changes. The description is optional, and may not be sent at
* all.
*
* For objects of version 2 and lower, this event is only sent once
* per xdg_output, and the description does not change over the
* lifetime of the wl_output global.
* @param description output description
* @since 2
*/
void (*description)(void *data,
struct zxdg_output_v1 *zxdg_output_v1,
const char *description);
};
/**
* @ingroup iface_zxdg_output_v1
*/
static inline int
zxdg_output_v1_add_listener(struct zxdg_output_v1 *zxdg_output_v1,
const struct zxdg_output_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zxdg_output_v1,
(void (**)(void)) listener, data);
}
#define ZXDG_OUTPUT_V1_DESTROY 0
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_LOGICAL_POSITION_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_LOGICAL_SIZE_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DONE_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_NAME_SINCE_VERSION 2
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION 2
/**
* @ingroup iface_zxdg_output_v1
*/
#define ZXDG_OUTPUT_V1_DESTROY_SINCE_VERSION 1
/** @ingroup iface_zxdg_output_v1 */
static inline void
zxdg_output_v1_set_user_data(struct zxdg_output_v1 *zxdg_output_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_v1, user_data);
}
/** @ingroup iface_zxdg_output_v1 */
static inline void *
zxdg_output_v1_get_user_data(struct zxdg_output_v1 *zxdg_output_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_v1);
}
static inline uint32_t
zxdg_output_v1_get_version(struct zxdg_output_v1 *zxdg_output_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1);
}
/**
* @ingroup iface_zxdg_output_v1
*
* Using this request a client can tell the server that it is not
* going to use the xdg_output object anymore.
*/
static inline void
zxdg_output_v1_destroy(struct zxdg_output_v1 *zxdg_output_v1)
{
wl_proxy_marshal((struct wl_proxy *) zxdg_output_v1,
ZXDG_OUTPUT_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zxdg_output_v1);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,78 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface zxdg_output_v1_interface;
static const struct wl_interface *xdg_output_unstable_v1_types[] = {
NULL,
NULL,
&zxdg_output_v1_interface,
&wl_output_interface,
};
static const struct wl_message zxdg_output_manager_v1_requests[] = {
{ "destroy", "", xdg_output_unstable_v1_types + 0 },
{ "get_xdg_output", "no", xdg_output_unstable_v1_types + 2 },
};
WL_PRIVATE const struct wl_interface zxdg_output_manager_v1_interface = {
"zxdg_output_manager_v1", 3,
2, zxdg_output_manager_v1_requests,
0, NULL,
};
static const struct wl_message zxdg_output_v1_requests[] = {
{ "destroy", "", xdg_output_unstable_v1_types + 0 },
};
static const struct wl_message zxdg_output_v1_events[] = {
{ "logical_position", "ii", xdg_output_unstable_v1_types + 0 },
{ "logical_size", "ii", xdg_output_unstable_v1_types + 0 },
{ "done", "", xdg_output_unstable_v1_types + 0 },
{ "name", "2s", xdg_output_unstable_v1_types + 0 },
{ "description", "2s", xdg_output_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zxdg_output_v1_interface = {
"zxdg_output_v1", 3,
1, zxdg_output_v1_requests,
5, zxdg_output_v1_events,
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 3,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 3,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 3,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 3,
14, xdg_toplevel_requests,
2, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 3,
3, xdg_popup_requests,
3, xdg_popup_events,
};

672
src/wayland/wl.c Normal file
View File

@ -0,0 +1,672 @@
#define _POSIX_C_SOURCE 200112L
#include "wl.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <linux/input-event-codes.h>
#include <string.h>
#include "protocols/xdg-shell-client-header.h"
#include "protocols/xdg-shell.h"
#include "protocols/wlr-layer-shell-unstable-v1-client-header.h"
#include "protocols/wlr-layer-shell-unstable-v1.h"
#include "protocols/idle-client-header.h"
#include "protocols/idle.h"
#include "pool-buffer.h"
#include "../log.h"
#include "../settings.h"
#include "../queues.h"
#include "../input.h"
#include "libgwater-wayland.h"
struct window_wl {
cairo_surface_t *c_surface;
cairo_t * c_ctx;
GWaterWaylandSource *esrc;
};
struct wl_ctx {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shm *shm;
struct zwlr_layer_shell_v1 *layer_shell;
struct wl_seat *seat;
struct wl_list outputs;
struct wl_surface *surface;
struct dunst_output *surface_output;
struct zwlr_layer_surface_v1 *layer_surface;
struct dunst_output *layer_surface_output;
struct wl_callback *frame_callback;
struct org_kde_kwin_idle *idle_handler;
struct org_kde_kwin_idle_timeout *idle_timeout;
bool configured;
bool dirty;
bool is_idle;
bool has_idle_monitor;
struct {
struct wl_pointer *wl_pointer;
int32_t x, y;
} pointer;
struct dimensions cur_dim;
int32_t width, height;
struct pool_buffer buffers[2];
struct pool_buffer *current_buffer;
};
struct dunst_output {
uint32_t global_name;
char *name;
struct wl_output *wl_output;
struct wl_list link;
uint32_t scale;
uint32_t subpixel; // TODO do something with it
};
struct wl_ctx ctx;
static void noop() {
// This space intentionally left blank
}
void set_dirty();
static void output_handle_geometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y, int32_t phy_width, int32_t phy_height,
int32_t subpixel, const char *make, const char *model,
int32_t transform) {
//TODO
struct dunst_output *output = data;
output->subpixel = subpixel;
}
static void output_handle_scale(void *data, struct wl_output *wl_output,
int32_t factor) {
struct dunst_output *output = data;
output->scale = factor;
}
static const struct wl_output_listener output_listener = {
.geometry = output_handle_geometry,
.mode = noop,
.done = noop,
.scale = output_handle_scale,
};
static void create_output( struct wl_output *wl_output, uint32_t global_name) {
struct dunst_output *output = g_malloc0(sizeof(struct dunst_output));
if (output == NULL) {
LOG_E("allocation failed");
return;
}
static int number = 0;
LOG_I("New output found - id %i", number);
output->global_name = global_name;
output->wl_output = wl_output;
// TODO: Fix this
output->scale = 1;
wl_list_insert(&ctx.outputs, &output->link);
wl_output_set_user_data(wl_output, output);
wl_output_add_listener(wl_output, &output_listener, output);
number++;
}
static void destroy_output(struct dunst_output *output) {
if (ctx.surface_output == output) {
ctx.surface_output = NULL;
}
if (ctx.layer_surface_output == output) {
ctx.layer_surface_output = NULL;
}
wl_list_remove(&output->link);
wl_output_destroy(output->wl_output);
free(output->name);
free(output);
}
// FIXME: Snipped touch handling
static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
ctx.pointer.x = wl_fixed_to_int(surface_x);
ctx.pointer.y = wl_fixed_to_int(surface_y);
}
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button,
uint32_t button_state) {
input_handle_click(button, button_state, ctx.pointer.x, ctx.pointer.y);
}
static const struct wl_pointer_listener pointer_listener = {
.enter = noop,
.leave = noop,
.motion = pointer_handle_motion,
.button = pointer_handle_button,
.axis = noop,
};
// FIXME snipped touch listener
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
uint32_t capabilities) {
if (ctx.pointer.wl_pointer != NULL) {
wl_pointer_release(ctx.pointer.wl_pointer);
ctx.pointer.wl_pointer = NULL;
}
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
ctx.pointer.wl_pointer = wl_seat_get_pointer(wl_seat);
wl_pointer_add_listener(ctx.pointer.wl_pointer,
&pointer_listener, ctx.seat);
LOG_I("Adding pointer");
}
}
static const struct wl_seat_listener seat_listener = {
.capabilities = seat_handle_capabilities,
.name = noop,
};
static void surface_handle_enter(void *data, struct wl_surface *surface,
struct wl_output *wl_output) {
// Don't bother keeping a list of outputs, a layer surface can only be on
// one output a a time
ctx.surface_output = wl_output_get_user_data(wl_output);
set_dirty();
}
static void surface_handle_leave(void *data, struct wl_surface *surface,
struct wl_output *wl_output) {
ctx.surface_output = NULL;
}
static const struct wl_surface_listener surface_listener = {
.enter = surface_handle_enter,
.leave = surface_handle_leave,
};
static void schedule_frame_and_commit();
static void send_frame();
static void layer_surface_handle_configure(void *data,
struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t width, uint32_t height) {
ctx.configured = true;
ctx.width = width;
ctx.height = height;
// not needed as it is set somewhere else
/* zwlr_layer_surface_v1_set_size(surface, width, height); */
zwlr_layer_surface_v1_ack_configure(surface, serial);
send_frame();
}
static void layer_surface_handle_closed(void *data,
struct zwlr_layer_surface_v1 *surface) {
LOG_I("Destroying layer");
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
ctx.layer_surface = NULL;
wl_surface_destroy(ctx.surface);
ctx.surface = NULL;
if (ctx.frame_callback) {
wl_callback_destroy(ctx.frame_callback);
ctx.frame_callback = NULL;
ctx.dirty = true;
}
if (ctx.configured) {
ctx.configured = false;
ctx.width = ctx.height = 0;
ctx.dirty = true;
}
if (ctx.dirty) {
schedule_frame_and_commit();
}
}
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = layer_surface_handle_configure,
.closed = layer_surface_handle_closed,
};
static void idle_start (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
ctx.is_idle = true;
LOG_I("User went idle");
}
static void idle_stop (void *data, struct org_kde_kwin_idle_timeout *org_kde_kwin_idle_timeout) {
ctx.is_idle = false;
LOG_I("User isn't idle anymore");
}
static const struct org_kde_kwin_idle_timeout_listener idle_timeout_listener = {
.idle = idle_start,
.resumed = idle_stop,
};
static void add_seat_to_idle_handler(struct wl_seat *seat) {
if (!ctx.idle_handler){
return;
}
uint32_t timeout_ms = settings.idle_threshold/1000;
ctx.idle_timeout = org_kde_kwin_idle_get_idle_timeout(ctx.idle_handler, seat, timeout_ms);
org_kde_kwin_idle_timeout_add_listener(ctx.idle_timeout, &idle_timeout_listener, 0);
ctx.has_idle_monitor = true;
}
static void handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version) {
if (strcmp(interface, wl_compositor_interface.name) == 0) {
ctx.compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 4);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
ctx.shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1);
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
ctx.layer_shell = wl_registry_bind(registry, name,
&zwlr_layer_shell_v1_interface, 1);
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
ctx.seat = wl_registry_bind(registry, name, &wl_seat_interface, 3);
wl_seat_add_listener(ctx.seat, &seat_listener, ctx.seat);
add_seat_to_idle_handler(ctx.seat);
} else if (strcmp(interface, wl_output_interface.name) == 0) {
struct wl_output *output =
wl_registry_bind(registry, name, &wl_output_interface, 3);
create_output(output, name);
} else if (strcmp(interface, org_kde_kwin_idle_interface.name) == 0 &&
version >= ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE_SINCE_VERSION) {
ctx.idle_handler = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, 1);
}
}
static void handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name) {
struct dunst_output *output, *tmp;
wl_list_for_each_safe(output, tmp, &ctx.outputs, link) {
if (output->global_name == name) {
destroy_output(output);
break;
}
}
}
static const struct wl_registry_listener registry_listener = {
.global = handle_global,
.global_remove = handle_global_remove,
};
bool init_wayland() {
wl_list_init(&ctx.outputs);
//wl_list_init(&ctx.seats);
ctx.display = wl_display_connect(NULL);
if (ctx.display == NULL) {
LOG_E("failed to create display");
return false;
}
ctx.registry = wl_display_get_registry(ctx.display);
wl_registry_add_listener(ctx.registry, &registry_listener, NULL);
wl_display_roundtrip(ctx.display);
if (ctx.compositor == NULL) {
LOG_E("compositor doesn't support wl_compositor");
return false;
}
if (ctx.shm == NULL) {
LOG_E("compositor doesn't support wl_shm");
return false;
}
if (ctx.layer_shell == NULL) {
LOG_E("compositor doesn't support zwlr_layer_shell_v1");
return false;
}
if (ctx.seat == NULL) {
LOG_W("no seat was found, so dunst cannot see input");
} else {
if (ctx.idle_handler == NULL) {
LOG_I("compositor doesn't support org_kde_kwin_idle_interface");
}
else if (ctx.idle_timeout == NULL) {
// something went wrong in setting the timeout
LOG_W("couldn't set idle timeout");
}
}
return true;
}
void finish_wayland() {
if (ctx.layer_surface != NULL) {
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
}
if (ctx.surface != NULL) {
wl_surface_destroy(ctx.surface);
}
finish_buffer(&ctx.buffers[0]);
finish_buffer(&ctx.buffers[1]);
struct dunst_output *output, *output_tmp;
wl_list_for_each_safe(output, output_tmp, &ctx.outputs, link) {
destroy_output(output);
}
if (ctx.seat) {
wl_pointer_release(ctx.pointer.wl_pointer);
wl_seat_release(ctx.seat);
ctx.seat = NULL;
}
zwlr_layer_shell_v1_destroy(ctx.layer_shell);
wl_compositor_destroy(ctx.compositor);
wl_shm_destroy(ctx.shm);
wl_registry_destroy(ctx.registry);
wl_display_disconnect(ctx.display);
org_kde_kwin_idle_destroy(ctx.idle_handler);
org_kde_kwin_idle_timeout_release(ctx.idle_timeout);
}
static struct dunst_output *get_configured_output() {
struct dunst_output *output;
switch (settings.f_mode){
case FOLLOW_NONE: ; // this semicolon is neccesary
int n = 0;
int target_monitor = settings.monitor;
wl_list_for_each(output, &ctx.outputs, link) {
if (n == target_monitor)
return output;
n++;
}
LOG_W("Monitor %i doesn't exist, using focused monitor", settings.monitor);
return NULL;
case FOLLOW_MOUSE:
// fallthrough
case FOLLOW_KEYBOARD:
// fallthrough
default:
return NULL;
}
}
static void schedule_frame_and_commit();
// Draw and commit a new frame.
static void send_frame() {
int scale = 1;
struct dunst_output *output = get_configured_output();
int height = ctx.cur_dim.h;
int width = ctx.cur_dim.w;
// There are two cases where we want to tear down the surface: zero
// notifications (height = 0) or moving between outputs.
if (height == 0 || ctx.layer_surface_output != output) {
if (ctx.layer_surface != NULL) {
zwlr_layer_surface_v1_destroy(ctx.layer_surface);
ctx.layer_surface = NULL;
}
if (ctx.surface != NULL) {
wl_surface_destroy(ctx.surface);
ctx.surface = NULL;
}
ctx.width = ctx.height = 0;
ctx.surface_output = NULL;
ctx.configured = false;
}
// If there are no notifications, there's no point in recreating the
// surface right now.
if (height == 0) {
ctx.dirty = false;
return;
}
// If we've made it here, there is something to draw. If the surface
// doesn't exist (this is the first notification, or we moved to a
// different output), we need to create it.
if (ctx.layer_surface == NULL) {
struct wl_output *wl_output = NULL;
ctx.layer_surface_output = output;
ctx.surface = wl_compositor_create_surface(ctx.compositor);
wl_surface_add_listener(ctx.surface, &surface_listener, NULL);
if (settings.frame_color)
ctx.layer_surface = zwlr_layer_shell_v1_get_layer_surface(
ctx.layer_shell, ctx.surface, wl_output,
settings.layer, "notifications");
zwlr_layer_surface_v1_add_listener(ctx.layer_surface,
&layer_surface_listener, NULL);
// Because we're creating a new surface, we aren't going to draw
// anything into it during this call. We don't know what size the
// surface will be until we've asked the compositor for what we want
// and it has responded with what it actually gave us. We also know
// that the height we would _like_ to draw (greater than zero, or we
// would have bailed already) is different from our ctx.height
// (which has to be zero here), so we can fall through to the next
// block to let it set the size for us.
}
assert(ctx.layer_surface);
// We now want to resize the surface if it isn't the right size. If the
// surface is brand new, it doesn't even have a size yet. If it already
// exists, we might need to resize if the list of notifications has changed
// since the last time we drew.
if (ctx.height != height || ctx.width != width) {
struct dimensions dim = ctx.cur_dim;
// Set window size
LOG_D("Window dimensions %ix%i", dim.w, dim.h);
LOG_D("Window position %ix%i", dim.x, dim.y);
zwlr_layer_surface_v1_set_size(ctx.layer_surface,
dim.w, dim.h);
// TODO Do this only once
uint32_t anchor = 0;
if (settings.geometry.negative_x) {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
} else {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
}
if (settings.geometry.negative_y) {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
} else {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
}
// Put the window at the right position
zwlr_layer_surface_v1_set_anchor(ctx.layer_surface,
anchor);
zwlr_layer_surface_v1_set_margin(ctx.layer_surface,
abs(settings.geometry.y), // top
abs(settings.geometry.x), // right
abs(settings.geometry.y), // bottom
abs(settings.geometry.x));// left
wl_surface_commit(ctx.surface);
// Now we're going to bail without drawing anything. This gives the
// compositor a chance to create the surface and tell us what size we
// were actually granted, which may be smaller than what we asked for
// depending on the screen size and layout of other layer surfaces.
// This information is provided in layer_surface_handle_configure,
// which will then call send_frame again. When that call happens, the
// layer surface will exist and the height will hopefully match what
// we asked for. That means we won't return here, and will actually
// draw into the surface down below.
// TODO: If the compositor doesn't send a configure with the size we
// requested, we'll enter an infinite loop. We need to keep track of
// the fact that a request was sent separately from what height we are.
wl_display_roundtrip(ctx.display);
return;
}
assert(ctx.configured);
// Yay we can finally draw something!
wl_surface_set_buffer_scale(ctx.surface, scale);
wl_surface_damage_buffer(ctx.surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_attach(ctx.surface, ctx.current_buffer->buffer, 0, 0);
ctx.current_buffer->busy = true;
// Schedule a frame in case the state becomes dirty again
schedule_frame_and_commit();
ctx.dirty = false;
}
static void frame_handle_done(void *data, struct wl_callback *callback,
uint32_t time) {
wl_callback_destroy(ctx.frame_callback);
ctx.frame_callback = NULL;
// Only draw again if we need to
if (ctx.dirty) {
send_frame();
}
}
static const struct wl_callback_listener frame_listener = {
.done = frame_handle_done,
};
static void schedule_frame_and_commit() {
if (ctx.frame_callback) {
return;
}
if (ctx.surface == NULL) {
// We don't yet have a surface, create it immediately
send_frame();
return;
}
ctx.frame_callback = wl_surface_frame(ctx.surface);
wl_callback_add_listener(ctx.frame_callback, &frame_listener, NULL);
wl_surface_commit(ctx.surface);
}
void set_dirty() {
if (ctx.dirty) {
return;
}
ctx.dirty = true;
schedule_frame_and_commit();
}
void wl_init(void) {
init_wayland();
}
void wl_deinit(void) {
}
window wl_win_create(void) {
struct window_wl *win = g_malloc0(sizeof(struct window_wl));
win->esrc = g_water_wayland_source_new_for_display(NULL, ctx.display);
return win;
}
void wl_win_destroy(window winptr) {
struct window_wl *win = (struct window_wl*)winptr;
g_water_wayland_source_free(win->esrc);
// FIXME: Dealloc everything
g_free(win);
}
void wl_win_show(window win) {
}
void wl_win_hide(window win) {
LOG_I("Wayland: Hiding window");
ctx.cur_dim.h = 0;
set_dirty();
wl_display_roundtrip(ctx.display);
}
void wl_display_surface(cairo_surface_t *srf, window winptr, const struct dimensions* dim) {
/* struct window_wl *win = (struct window_wl*)winptr; */
ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, dim->w, dim->h);
cairo_t *c = ctx.current_buffer->cairo;
cairo_save(c);
cairo_set_source_surface(c, srf, 0, 0);
cairo_rectangle(c, 0, 0, dim->w, dim->h);
cairo_fill(c);
cairo_restore(c);
ctx.cur_dim = *dim;
set_dirty();
wl_display_roundtrip(ctx.display);
}
bool wl_win_visible(window win) {
return true;
}
cairo_t* wl_win_get_context(window winptr) {
struct window_wl *win = (struct window_wl*)winptr;
ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, 500, 500);
win->c_surface = ctx.current_buffer->surface;
win->c_ctx = ctx.current_buffer->cairo;
return win->c_ctx;
}
const struct screen_info* wl_get_active_screen(void) {
// TODO Screen size detection
static struct screen_info scr = {
.w = 1920,
.h = 1080,
.x = 0,
.y = 0,
.id = 0,
.mmh = 500
};
return &scr;
}
bool wl_is_idle(void) {
LOG_I("Idle status queried: %i", ctx.is_idle);
// When the user doesn't have a seat, or their compositor doesn't support the idle
// protocol, we'll assume that they are not idle.
if (settings.idle_threshold == 0 || ctx.has_idle_monitor == false) {
return false;
} else {
return ctx.is_idle;
}
}
bool wl_have_fullscreen_window(void) {
return false;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

28
src/wayland/wl.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef DUNST_WL_H
#define DUNST_WL_H
#include <stdbool.h>
#include <cairo.h>
#include <glib.h>
#include "../output.h"
void wl_init(void);
void wl_deinit(void);
window wl_win_create(void);
void wl_win_destroy(window);
void wl_win_show(window);
void wl_win_hide(window);
void wl_display_surface(cairo_surface_t *srf, window win, const struct dimensions*);
bool wl_win_visible(window);
cairo_t* wl_win_get_context(window);
const struct screen_info* wl_get_active_screen(void);
bool wl_is_idle(void);
bool wl_have_fullscreen_window(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -19,6 +19,7 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xresource.h> #include <X11/Xresource.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <linux/input-event-codes.h>
#include "../dbus.h" #include "../dbus.h"
#include "../draw.h" #include "../draw.h"
@ -30,6 +31,7 @@
#include "../queues.h" #include "../queues.h"
#include "../settings.h" #include "../settings.h"
#include "../utils.h" #include "../utils.h"
#include "../input.h"
#include "screen.h" #include "screen.h"
@ -403,62 +405,47 @@ bool x_is_idle(void)
return xctx.screensaver_info->idle > settings.idle_threshold / 1000; return xctx.screensaver_info->idle > settings.idle_threshold / 1000;
} }
/*
* Convert x button code to linux event code
* Returns 0 if button is not recognized.
*/
static unsigned int x_mouse_button_to_linux_event_code(unsigned int x_button)
{
switch (x_button) {
case Button1:
return BTN_LEFT;
case Button2:
return BTN_MIDDLE;
case Button3:
return BTN_RIGHT;
default:
LOG_W("Unsupported mouse button: '%d'", x_button);
return 0;
}
}
/* TODO move to x_mainloop_* */ /* TODO move to x_mainloop_* */
/* /*
* Handle incoming mouse click events * Handle incoming mouse click events
*/ */
static void x_handle_click(XEvent ev) static void x_handle_click(XEvent ev)
{ {
enum mouse_action *acts; unsigned int linux_code = x_mouse_button_to_linux_event_code(ev.xbutton.button);
switch (ev.xbutton.button) { if (linux_code == 0) {
case Button1:
acts = settings.mouse_left_click;
break;
case Button2:
acts = settings.mouse_middle_click;
break;
case Button3:
acts = settings.mouse_right_click;
break;
default:
LOG_W("Unsupported mouse button: '%d'", ev.xbutton.button);
return; return;
} }
for (int i = 0; acts[i]; i++) { bool button_state;
enum mouse_action act = acts[i]; if(ev.type == ButtonRelease) {
if (act == MOUSE_CLOSE_ALL) { button_state = false; // button is up
queues_history_push_all();
return;
}
if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT) {
int y = settings.separator_height;
struct notification *n = NULL;
int first = true;
for (const GList *iter = queues_get_displayed(); iter;
iter = iter->next) {
n = iter->data;
if (ev.xbutton.y > y && ev.xbutton.y < y + n->displayed_height)
break;
y += n->displayed_height + settings.separator_height;
if (first)
y += settings.frame_width;
}
if (n) {
if (act == MOUSE_CLOSE_CURRENT) {
n->marked_for_closure = REASON_USER;
} else { } else {
notification_do_action(n); // this shouldn't happen, because this function
} // is only called when it'a a ButtonRelease event
} button_state = true; // button is down
}
} }
wake_up(); input_handle_click(linux_code, button_state, ev.xbutton.x, ev.xbutton.y);
} }
void x_free(void) void x_free(void)
@ -777,6 +764,7 @@ void x_win_show(window winptr)
*/ */
void x_win_hide(window winptr) void x_win_hide(window winptr)
{ {
LOG_I("X11: Hiding window");
struct window_x11 *win = (struct window_x11*)winptr; struct window_x11 *win = (struct window_x11*)winptr;
ASSERT_OR_RET(win->visible,); ASSERT_OR_RET(win->visible,);