Create abstract output and fix wayland bug

This commit adds an output struct which abstracts the X11 specific
functions and makes it possible to easily create a drop-in wayland
output.

It also fixes a bug in wayland where notifications won't disappear.
This is because wayland doesn't give access to user input when a
client is not in focus. This way it seems like the user is always
idle. The idle functionality is now disabled in Wayland until proper
support is added.
This commit is contained in:
fwsmit 2020-11-15 14:23:50 +01:00
parent 3001f79fc3
commit 58d215ddfe
11 changed files with 196 additions and 75 deletions

View File

@ -238,6 +238,8 @@ Set to 0 to disable.
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.
Note: this doesn't work on wayland yet.
=item B<font> (default: "Monospace 8")
Defines the font or font set used. Optionally set the size as a decimal number

View File

@ -1,7 +1,6 @@
#include "draw.h"
#include <assert.h>
#include <cairo.h>
#include <math.h>
#include <pango/pango-attributes.h>
#include <pango/pangocairo.h>
@ -10,6 +9,7 @@
#include <pango/pango-types.h>
#include <stdlib.h>
#include <inttypes.h>
#include <glib.h>
#include "dunst.h"
#include "icon.h"
@ -17,7 +17,15 @@
#include "markup.h"
#include "notification.h"
#include "queues.h"
#include "x11/x.h"
#include "output.h"
#include "settings.h"
struct color {
double r;
double g;
double b;
double a;
};
struct colored_layout {
PangoLayout *l;
@ -30,7 +38,8 @@ struct colored_layout {
const struct notification *n;
};
struct window_x11 *win;
const struct output *output;
window win;
PangoFontDescription *pango_fdesc;
@ -38,9 +47,12 @@ PangoFontDescription *pango_fdesc;
void draw_setup(void)
{
x_setup();
const struct output *out = output_create();
output = out;
out->init();
win = out->win_create();
win = x_win_create();
pango_fdesc = pango_font_description_from_string(settings.font);
}
@ -170,7 +182,7 @@ static struct dimensions calculate_dimensions(GSList *layouts)
{
struct dimensions dim = { 0 };
struct screen_info *scr = get_active_screen();
const struct screen_info *scr = output->get_active_screen();
if (have_dynamic_width()) {
/* dynamic width */
dim.w = 0;
@ -250,10 +262,10 @@ static struct dimensions calculate_dimensions(GSList *layouts)
static PangoLayout *layout_create(cairo_t *c)
{
struct screen_info *screen = get_active_screen();
const struct screen_info *screen = output->get_active_screen();
PangoContext *context = pango_cairo_create_context(c);
pango_cairo_context_set_resolution(context, screen_dpi_get(screen));
pango_cairo_context_set_resolution(context, screen->dpi);
PangoLayout *layout = pango_layout_new(context);
@ -664,7 +676,7 @@ static struct dimensions layout_render(cairo_surface_t *srf,
*/
static void calc_window_pos(int width, int height, int *ret_x, int *ret_y)
{
struct screen_info *scr = get_active_screen();
const struct screen_info *scr = output->get_active_screen();
if (ret_x) {
if (settings.geometry.negative_x) {
@ -687,7 +699,7 @@ void draw(void)
{
assert(queues_length_displayed() > 0);
GSList *layouts = create_layouts(x_win_get_context(win));
GSList *layouts = create_layouts(output->win_get_context(win));
struct dimensions dim = calculate_dimensions(layouts);
@ -705,7 +717,7 @@ void draw(void)
}
calc_window_pos(dim.w, dim.h, &dim.x, &dim.y);
x_display_surface(image_surface, win, &dim);
output->display_surface(image_surface, win, &dim);
cairo_surface_destroy(image_surface);
g_slist_free_full(layouts, free_colored_layout);
@ -713,7 +725,7 @@ void draw(void)
void draw_deinit(void)
{
x_win_destroy(win);
x_free();
output->win_destroy(win);
output->deinit();
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -1,8 +1,12 @@
#ifndef DUNST_DRAW_H
#define DUNST_DRAW_H
#include "x11/x.h"
extern struct window_x11 *win; // Temporary
#include <stdbool.h>
#include <cairo.h>
#include "output.h"
extern window win; // Temporary
extern const struct output *output;
void draw_setup(void);

View File

@ -20,8 +20,7 @@
#include "queues.h"
#include "settings.h"
#include "utils.h"
#include "x11/screen.h"
#include "x11/x.h"
#include "output.h"
GMainLoop *mainloop = NULL;
@ -67,8 +66,8 @@ static gboolean run(void *data)
LOG_D("RUN");
dunst_status(S_FULLSCREEN, have_fullscreen_window());
dunst_status(S_IDLE, x_is_idle());
dunst_status(S_FULLSCREEN, output->have_fullscreen_window());
dunst_status(S_IDLE, output->is_idle());
queues_update(status);
@ -77,9 +76,9 @@ static gboolean run(void *data)
if (active) {
// Call draw before showing the window to avoid flickering
draw();
x_win_show(win);
output->win_show(win);
} else {
x_win_hide(win);
output->win_hide(win);
}
if (active) {

62
src/output.c Normal file
View File

@ -0,0 +1,62 @@
#include "output.h"
#include "log.h"
#include "x11/x.h"
#include "x11/screen.h"
/* #include "wayland/wl.h" */ // Not yet
const bool is_running_wayland(void){
char* wayland_display = getenv("WAYLAND_DISPLAY");
return !(wayland_display == NULL);
}
const struct output output_x11 = {
x_setup,
x_free,
x_win_create,
x_win_destroy,
x_win_show,
x_win_hide,
x_display_surface,
x_win_visible,
x_win_get_context,
get_active_screen,
x_is_idle,
have_fullscreen_window
};
/* const struct output output_wl = { */
/* wl_init, */
/* wl_deinit, */
/* wl_win_create, */
/* wl_win_destroy, */
/* wl_win_show, */
/* wl_win_hide, */
/* wl_display_surface, */
/* wl_win_visible, */
/* wl_win_get_context, */
/* wl_get_active_screen, */
/* wl_is_idle, */
/* wl_have_fullscreen_window */
/* }; */
const struct output* output_create(void)
{
if (is_running_wayland()) {
LOG_I("System is running wayland");
} else{
LOG_I("System is running X11");
}
return &output_x11;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

55
src/output.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef DUNST_OUTPUT_H
#define DUNST_OUTPUT_H
#include <stdbool.h>
#include <glib.h>
#include <cairo.h>
typedef gpointer window;
struct dimensions {
int x;
int y;
int w;
int h;
int corner_radius;
};
struct screen_info {
int id;
int x;
int y;
unsigned int h;
unsigned int mmh;
unsigned int w;
int dpi;
};
struct output {
void (*init)(void);
void (*deinit)(void);
window (*win_create)(void);
void (*win_destroy)(window);
void (*win_show)(window);
void (*win_hide)(window);
void (*display_surface)(cairo_surface_t *srf, window win, const struct dimensions*);
bool (*win_visible)(window);
cairo_t* (*win_get_context)(window);
const struct screen_info* (*get_active_screen)(void);
bool (*is_idle)(void);
bool (*have_fullscreen_window)(void);
};
const struct output* output_create(void);
const bool is_running_wayland(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -25,6 +25,7 @@
#include "notification.h"
#include "settings.h"
#include "utils.h"
#include "output.h" // For checking if wayland is active.
/* notification lists */
static GQueue *waiting = NULL; /**< all new notifications get into here */
@ -143,7 +144,8 @@ static bool queues_notification_is_finished(struct notification *n, struct dunst
bool is_idle = status.fullscreen ? false : status.idle;
/* don't timeout when user is idle */
if (is_idle && !n->transient) {
/* NOTE: Idle is not working on wayland */
if (is_idle && !n->transient && !is_running_wayland()) {
n->start = time_monotonic_now();
return false;
}

View File

@ -69,12 +69,12 @@ static double screen_dpi_get_from_xft(void)
return screen_dpi_xft_cache;
}
static double screen_dpi_get_from_monitor(struct screen_info *scr)
static double screen_dpi_get_from_monitor(const struct screen_info *scr)
{
return (double)scr->h * 25.4 / (double)scr->mmh;
}
double screen_dpi_get(struct screen_info *scr)
double screen_dpi_get(const struct screen_info *scr)
{
if ( ! settings.force_xinerama
&& settings.per_monitor_dpi)
@ -156,6 +156,7 @@ void randr_update(void)
screens[i].w = m[i].width;
screens[i].h = m[i].height;
screens[i].mmh = m[i].mheight;
screens[i].dpi = screen_dpi_get(&screens[i]);
}
XRRFreeMonitors(m);
@ -300,7 +301,7 @@ bool window_is_fullscreen(Window window)
* Select the screen on which the Window
* should be displayed.
*/
struct screen_info *get_active_screen(void)
const struct screen_info *get_active_screen(void)
{
int ret = 0;
bool force_follow_mouse = false;

View File

@ -7,21 +7,12 @@
#define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh))
struct screen_info {
int id;
int x;
int y;
unsigned int h;
unsigned int mmh;
unsigned int w;
};
void init_screens(void);
void screen_dpi_xft_cache_purge(void);
bool screen_check_event(XEvent *ev);
struct screen_info *get_active_screen(void);
double screen_dpi_get(struct screen_info *scr);
const struct screen_info *get_active_screen(void);
double screen_dpi_get(const struct screen_info *scr);
/**
* Find the currently focused window and check if it's in

View File

@ -67,8 +67,10 @@ static int x_shortcut_tear_down_error_handler(void);
static void setopacity(Window win, unsigned long opacity);
static void x_handle_click(XEvent ev);
static void x_win_move(struct window_x11 *win, int x, int y, int width, int height)
static void x_win_move(window winptr, int x, int y, int width, int height)
{
struct window_x11 *win = (struct window_x11*)winptr;
/* move and resize */
if (x != win->dim.x || y != win->dim.y) {
XMoveWindow(xctx.dpy, win->xwin, x, y);
@ -126,8 +128,9 @@ static void x_win_corners_shape(struct window_x11 *win, const int rad)
win->xwin, ShapeNotifyMask);
}
static void x_win_corners_unshape(struct window_x11 *win)
static void x_win_corners_unshape(window winptr)
{
struct window_x11 *win = (struct window_x11*)winptr;
XRectangle rect = {
.x = 0,
.y = 0,
@ -153,8 +156,9 @@ static bool x_win_composited(struct window_x11 *win)
}
}
void x_display_surface(cairo_surface_t *srf, struct window_x11 *win, const struct dimensions *dim)
void x_display_surface(cairo_surface_t *srf, window winptr, const struct dimensions *dim)
{
struct window_x11 *win = (struct window_x11*)winptr;
x_win_move(win, dim->x, dim->y, dim->w, dim->h);
cairo_xlib_surface_set_size(win->root_surface, dim->w, dim->h);
@ -173,14 +177,14 @@ void x_display_surface(cairo_surface_t *srf, struct window_x11 *win, const struc
}
bool x_win_visible(struct window_x11 *win)
bool x_win_visible(window winptr)
{
return win->visible;
return ((struct window_x11*)winptr)->visible;
}
cairo_t* x_win_get_context(struct window_x11 *win)
cairo_t* x_win_get_context(window winptr)
{
return win->c_ctx;
return ((struct window_x11*)win)->c_ctx;
}
static void setopacity(Window win, unsigned long opacity)
@ -278,7 +282,7 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, gpointer
struct window_x11 *win = ((struct x11_source*) source)->win;
bool fullscreen_now;
struct screen_info *scr;
const struct screen_info *scr;
XEvent ev;
unsigned int state;
while (XPending(xctx.dpy) > 0) {
@ -641,7 +645,7 @@ GSource* x_win_reg_source(struct window_x11 *win)
/*
* Setup the window
*/
struct window_x11 *x_win_create(void)
window x_win_create(void)
{
struct window_x11 *win = g_malloc0(sizeof(struct window_x11));
@ -671,7 +675,7 @@ struct window_x11 *x_win_create(void)
ExposureMask | KeyPressMask | VisibilityChangeMask |
ButtonReleaseMask | FocusChangeMask| StructureNotifyMask;
struct screen_info *scr = get_active_screen();
const struct screen_info *scr = get_active_screen();
win->xwin = XCreateWindow(xctx.dpy,
root,
scr->x,
@ -713,11 +717,13 @@ struct window_x11 *x_win_create(void)
}
XSelectInput(xctx.dpy, root, root_event_mask);
return win;
return (window)win;
}
void x_win_destroy(struct window_x11 *win)
void x_win_destroy(window winptr)
{
struct window_x11 *win = (struct window_x11*)winptr;
g_source_destroy(win->esrc);
g_source_unref(win->esrc);
@ -731,8 +737,10 @@ void x_win_destroy(struct window_x11 *win)
/*
* Show the window and grab shortcuts.
*/
void x_win_show(struct window_x11 *win)
void x_win_show(window winptr)
{
struct window_x11 *win = (struct window_x11*)winptr;
/* window is already mapped or there's nothing to show */
if (win->visible)
return;
@ -763,8 +771,9 @@ void x_win_show(struct window_x11 *win)
/*
* Hide the window and ungrab unused keyboard_shortcuts
*/
void x_win_hide(struct window_x11 *win)
void x_win_hide(window winptr)
{
struct window_x11 *win = (struct window_x11*)winptr;
ASSERT_OR_RET(win->visible,);
x_shortcut_ungrab(&settings.close_ks);

View File

@ -11,6 +11,8 @@
#include <X11/X.h>
#include <X11/Xlib.h>
#include "../output.h"
#include "screen.h"
struct keyboard_shortcut {
@ -24,42 +26,24 @@ struct keyboard_shortcut {
// Cyclical dependency
#include "../settings.h"
struct window_x11;
struct dimensions {
int x;
int y;
int w;
int h;
int corner_radius;
};
struct x_context {
Display *dpy;
XScreenSaverInfo *screensaver_info;
};
struct color {
double r;
double g;
double b;
double a;
};
extern struct x_context xctx;
/* window */
struct window_x11 *x_win_create(void);
void x_win_destroy(struct window_x11 *win);
window x_win_create(void);
void x_win_destroy(window);
void x_win_show(struct window_x11 *win);
void x_win_hide(struct window_x11 *win);
void x_win_show(window);
void x_win_hide(window);
void x_display_surface(cairo_surface_t *srf, struct window_x11 *win, const struct dimensions *dim);
void x_display_surface(cairo_surface_t *srf, window, const struct dimensions *dim);
bool x_win_visible(struct window_x11 *win);
cairo_t* x_win_get_context(struct window_x11 *win);
bool x_win_visible(window);
cairo_t* x_win_get_context(window);
/* X misc */
bool x_is_idle(void);