Merge pull request #472 from bebehei/fullscreen
Implement hiding on fullscreen
This commit is contained in:
commit
f80e6fc579
@ -2,6 +2,10 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- `fullscreen` rule to hide notifications when a fullscreen window is active
|
||||
|
||||
## 1.3.0 - 2018-01-05
|
||||
|
||||
### Added
|
||||
|
@ -594,8 +594,9 @@ Shell-like globing is supported.
|
||||
=item B<modifying>
|
||||
|
||||
The following attributes can be overridden: timeout, urgency, foreground,
|
||||
background, new_icon, set_transient, format where, as with the filtering attributes,
|
||||
each one corresponds to the respective notification attribute to be modified.
|
||||
background, new_icon, set_transient, format, fullscreen where,
|
||||
as with the filtering attributes, each one corresponds to the respective
|
||||
notification attribute to be modified.
|
||||
|
||||
As with filtering, to make a rule modify an attribute simply assign it in the
|
||||
rule definition.
|
||||
|
15
dunstrc
15
dunstrc
@ -279,7 +279,7 @@
|
||||
# override settings for certain messages.
|
||||
# Messages can be matched by "appname", "summary", "body", "icon", "category",
|
||||
# "msg_urgency" and you can override the "timeout", "urgency", "foreground",
|
||||
# "background", "new_icon" and "format".
|
||||
# "background", "new_icon" and "format", "fullscreen".
|
||||
# Shell-like globbing will get expanded.
|
||||
#
|
||||
# SCRIPTING
|
||||
@ -294,6 +294,19 @@
|
||||
# NOTE: It might be helpful to run dunst -print in a terminal in order
|
||||
# to find fitting options for rules.
|
||||
|
||||
# fullscreen values
|
||||
# show: show the notifications, regardless if there is a fullscreen window opened
|
||||
# delay: displays the new notification, if there is there is no fullscreen window active
|
||||
# If the notification is already drawn, it won't get undrawn.
|
||||
# pushback: same as delay, but when switching into fullscreen, the notification will get
|
||||
# withdrawn from screen again and will get delayed like a new notification
|
||||
|
||||
#[fullscreen_delay_everything]
|
||||
# fullscreen = delay
|
||||
#[fullscreen_show_critical]
|
||||
# msg_urgency = critical
|
||||
# fullscreen = show
|
||||
|
||||
#[espeak]
|
||||
# summary = "*"
|
||||
# script = dunst_espeak.sh
|
||||
|
@ -48,8 +48,12 @@ void wake_up(void)
|
||||
|
||||
static gboolean run(void *data)
|
||||
{
|
||||
queues_check_timeouts(x_is_idle());
|
||||
queues_update();
|
||||
LOG_D("RUN");
|
||||
|
||||
bool fullscreen = have_fullscreen_window();
|
||||
|
||||
queues_check_timeouts(x_is_idle(), fullscreen);
|
||||
queues_update(fullscreen);
|
||||
|
||||
static gint64 next_timeout = 0;
|
||||
|
||||
|
@ -28,6 +28,19 @@ static void notification_extract_urls(notification *n);
|
||||
static void notification_format_message(notification *n);
|
||||
static void notification_dmenu_string(notification *n);
|
||||
|
||||
/* see notification.h */
|
||||
const char *enum_to_string_fullscreen(enum behavior_fullscreen in)
|
||||
{
|
||||
switch (in) {
|
||||
case FS_SHOW: return "show";
|
||||
case FS_DELAY: return "delay";
|
||||
case FS_PUSHBACK: return "pushback";
|
||||
case FS_NULL: return "(null)";
|
||||
default:
|
||||
LOG_E("Enum behavior_fullscreen has wrong value.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* print a human readable representation
|
||||
* of the given notification to stdout.
|
||||
@ -49,6 +62,7 @@ void notification_print(notification *n)
|
||||
printf("\tfg: %s\n", n->colors[ColFG]);
|
||||
printf("\tbg: %s\n", n->colors[ColBG]);
|
||||
printf("\tframe: %s\n", n->colors[ColFrame]);
|
||||
printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen));
|
||||
printf("\tid: %d\n", n->id);
|
||||
if (n->urls) {
|
||||
char *urls = string_replace_all("\n", "\t\t\n", g_strdup(n->urls));
|
||||
@ -284,6 +298,8 @@ notification *notification_create(void)
|
||||
n->transient = false;
|
||||
n->progress = -1;
|
||||
|
||||
n->fullscreen = FS_SHOW;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,13 @@
|
||||
|
||||
#define DUNST_NOTIF_MAX_CHARS 5000
|
||||
|
||||
enum behavior_fullscreen {
|
||||
FS_NULL, //!< Invalid value
|
||||
FS_DELAY, //!< Delay the notification until leaving fullscreen mode
|
||||
FS_PUSHBACK, //!< When entering fullscreen mode, push the notification back to waiting
|
||||
FS_SHOW, //!< Show the message when in fullscreen mode
|
||||
};
|
||||
|
||||
/// Representing the urgencies according to the notification spec
|
||||
enum urgency {
|
||||
URG_NONE = -1, /**< Urgency not set (invalid) */
|
||||
@ -69,6 +76,7 @@ typedef struct _notification {
|
||||
bool first_render; /**< markup has been rendered before? */
|
||||
int dup_count; /**< amount of duplicate notifications stacked onto this */
|
||||
int displayed_height;
|
||||
enum behavior_fullscreen fullscreen; //!< The instruction what to do with it, when desktop enters fullscreen
|
||||
|
||||
/* derived fields */
|
||||
char *msg; /**< formatted message */
|
||||
@ -94,5 +102,14 @@ void notification_update_text_to_render(notification *n);
|
||||
void notification_do_action(notification *n);
|
||||
|
||||
const char *notification_urgency_to_string(enum urgency urgency);
|
||||
|
||||
/**
|
||||
* Return the string representation for fullscreen behavior
|
||||
*
|
||||
* @param in the #behavior_fullscreen enum value to represent
|
||||
* @return the string representation for `in`
|
||||
*/
|
||||
const char *enum_to_string_fullscreen(enum behavior_fullscreen in);
|
||||
|
||||
#endif
|
||||
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||
|
@ -551,4 +551,22 @@ const char *cmdline_create_usage(void)
|
||||
return usage_str;
|
||||
}
|
||||
|
||||
/* see option_parser.h */
|
||||
enum behavior_fullscreen parse_enum_fullscreen(const char *string, enum behavior_fullscreen def)
|
||||
{
|
||||
if (!string)
|
||||
return def;
|
||||
|
||||
if (strcmp(string, "show") == 0)
|
||||
return FS_SHOW;
|
||||
else if (strcmp(string, "delay") == 0)
|
||||
return FS_DELAY;
|
||||
else if (strcmp(string, "pushback") == 0)
|
||||
return FS_PUSHBACK;
|
||||
else {
|
||||
LOG_W("Unknown fullscreen value: '%s'\n", string);
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dunst.h"
|
||||
|
||||
int load_ini_file(FILE *);
|
||||
char *ini_get_path(const char *section, const char *key, const char *def);
|
||||
char *ini_get_string(const char *section, const char *key, const char *def);
|
||||
@ -63,5 +65,17 @@ int option_get_bool(const char *ini_section,
|
||||
*/
|
||||
const char *next_section(const char *section);
|
||||
|
||||
/**
|
||||
* Parse the fullscreen behavior value of the given string
|
||||
*
|
||||
* @param string the string representation of #behavior_fullscreen.
|
||||
* The string must not contain any waste characters.
|
||||
* @param def value to return in case of errors
|
||||
*
|
||||
* @return the #behavior_fullscreen representation of `string`
|
||||
* @return `def` if `string` is invalid or `NULL`
|
||||
*/
|
||||
enum behavior_fullscreen parse_enum_fullscreen(const char *string, enum behavior_fullscreen def);
|
||||
|
||||
#endif
|
||||
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||
|
40
src/queues.c
40
src/queues.c
@ -284,12 +284,14 @@ void queues_history_push_all(void)
|
||||
}
|
||||
|
||||
/* see queues.h */
|
||||
void queues_check_timeouts(bool idle)
|
||||
void queues_check_timeouts(bool idle, bool fullscreen)
|
||||
{
|
||||
/* nothing to do */
|
||||
if (displayed->length == 0)
|
||||
return;
|
||||
|
||||
bool is_idle = fullscreen ? false : idle;
|
||||
|
||||
GList *iter = g_queue_peek_head_link(displayed);
|
||||
while (iter) {
|
||||
notification *n = iter->data;
|
||||
@ -302,7 +304,7 @@ void queues_check_timeouts(bool idle)
|
||||
iter = iter->next;
|
||||
|
||||
/* don't timeout when user is idle */
|
||||
if (idle && !n->transient) {
|
||||
if (is_idle && !n->transient) {
|
||||
n->start = g_get_monotonic_time();
|
||||
continue;
|
||||
}
|
||||
@ -320,7 +322,7 @@ void queues_check_timeouts(bool idle)
|
||||
}
|
||||
|
||||
/* see queues.h */
|
||||
void queues_update(void)
|
||||
void queues_update(bool fullscreen)
|
||||
{
|
||||
if (pause_displayed) {
|
||||
while (displayed->length > 0) {
|
||||
@ -330,26 +332,52 @@ void queues_update(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* move notifications back to queue, which are set to pushback */
|
||||
if (fullscreen) {
|
||||
GList *iter = g_queue_peek_head_link(displayed);
|
||||
while (iter) {
|
||||
notification *n = iter->data;
|
||||
GList *nextiter = iter->next;
|
||||
|
||||
if (n->fullscreen == FS_PUSHBACK){
|
||||
g_queue_delete_link(displayed, iter);
|
||||
g_queue_insert_sorted(waiting, n, notification_cmp_data, NULL);
|
||||
}
|
||||
|
||||
iter = nextiter;
|
||||
}
|
||||
}
|
||||
|
||||
/* move notifications from queue to displayed */
|
||||
while (waiting->length > 0) {
|
||||
GList *iter = g_queue_peek_head_link(waiting);
|
||||
while (iter) {
|
||||
notification *n = iter->data;
|
||||
GList *nextiter = iter->next;
|
||||
|
||||
if (displayed_limit > 0 && displayed->length >= displayed_limit) {
|
||||
/* the list is full */
|
||||
break;
|
||||
}
|
||||
|
||||
notification *n = g_queue_pop_head(waiting);
|
||||
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
if (fullscreen
|
||||
&& (n->fullscreen == FS_DELAY || n->fullscreen == FS_PUSHBACK)) {
|
||||
iter = nextiter;
|
||||
continue;
|
||||
}
|
||||
|
||||
n->start = g_get_monotonic_time();
|
||||
|
||||
if (!n->redisplayed && n->script) {
|
||||
notification_run_script(n);
|
||||
}
|
||||
|
||||
g_queue_delete_link(waiting, iter);
|
||||
g_queue_insert_sorted(displayed, n, notification_cmp_data, NULL);
|
||||
|
||||
iter = nextiter;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,8 +125,10 @@ void queues_history_push_all(void);
|
||||
*
|
||||
* @param idle the program's idle status. Important to calculate the
|
||||
* timeout for transient notifications
|
||||
* @param fullscreen the desktop's fullscreen status. Important to
|
||||
* calculate the timeout for transient notifications
|
||||
*/
|
||||
void queues_check_timeouts(bool idle);
|
||||
void queues_check_timeouts(bool idle, bool fullscreen);
|
||||
|
||||
/**
|
||||
* Move inserted notifications from waiting queue to displayed queue
|
||||
@ -135,8 +137,11 @@ void queues_check_timeouts(bool idle);
|
||||
*
|
||||
* @post Call wake_up() to synchronize the queues with the UI
|
||||
* (which closes old and shows new notifications on screen)
|
||||
*
|
||||
* @param fullscreen the desktop's fullscreen status. Important to
|
||||
* move notifications to the right queue
|
||||
*/
|
||||
void queues_update(void);
|
||||
void queues_update(bool fullscreen);
|
||||
|
||||
/**
|
||||
* Calculate the distance to the next event, when an element in the
|
||||
|
@ -16,6 +16,8 @@ void rule_apply(rule_t *r, notification *n)
|
||||
n->timeout = r->timeout;
|
||||
if (r->urgency != URG_NONE)
|
||||
n->urgency = r->urgency;
|
||||
if (r->fullscreen != FS_NULL)
|
||||
n->fullscreen = r->fullscreen;
|
||||
if (r->history_ignore != -1)
|
||||
n->history_ignore = r->history_ignore;
|
||||
if (r->set_transient != -1)
|
||||
@ -69,6 +71,7 @@ void rule_init(rule_t *r)
|
||||
r->msg_urgency = URG_NONE;
|
||||
r->timeout = -1;
|
||||
r->urgency = URG_NONE;
|
||||
r->fullscreen = FS_NULL;
|
||||
r->markup = MARKUP_NULL;
|
||||
r->new_icon = NULL;
|
||||
r->history_ignore = false;
|
||||
|
@ -30,6 +30,7 @@ typedef struct _rule_t {
|
||||
char *bg;
|
||||
const char *format;
|
||||
const char *script;
|
||||
enum behavior_fullscreen fullscreen;
|
||||
} rule_t;
|
||||
|
||||
extern GSList *rules;
|
||||
|
@ -684,6 +684,15 @@ void load_settings(char *cmdline_config_path)
|
||||
r->history_ignore = ini_get_bool(cur_section, "history_ignore", r->history_ignore);
|
||||
r->match_transient = ini_get_bool(cur_section, "match_transient", r->match_transient);
|
||||
r->set_transient = ini_get_bool(cur_section, "set_transient", r->set_transient);
|
||||
{
|
||||
char *c = ini_get_string(
|
||||
cur_section,
|
||||
"fullscreen", NULL
|
||||
);
|
||||
|
||||
r->fullscreen = parse_enum_fullscreen(c, r->fullscreen);
|
||||
g_free(c);
|
||||
}
|
||||
r->script = ini_get_path(cur_section, "script", NULL);
|
||||
}
|
||||
|
||||
|
@ -146,6 +146,8 @@ void screen_check_event(XEvent event)
|
||||
{
|
||||
if (event.type == randr_event_base + RRScreenChangeNotify)
|
||||
randr_update();
|
||||
else
|
||||
LOG_D("XEvent: Ignored '%d'", event.type);
|
||||
}
|
||||
|
||||
void xinerama_update(void)
|
||||
@ -186,6 +188,89 @@ void screen_update_fallback(void)
|
||||
screens[0].dim.h = DisplayHeight(xctx.dpy, screen);
|
||||
}
|
||||
|
||||
/* see screen.h */
|
||||
bool have_fullscreen_window(void)
|
||||
{
|
||||
return window_is_fullscreen(get_focused_window());
|
||||
}
|
||||
|
||||
/**
|
||||
* X11 ErrorHandler to mainly discard BadWindow parameter error
|
||||
*/
|
||||
static int XErrorHandlerFullscreen(Display *display, XErrorEvent *e)
|
||||
{
|
||||
/* Ignore BadWindow errors. Window may have been gone */
|
||||
if (e->error_code == BadWindow) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char err_buf[BUFSIZ];
|
||||
XGetErrorText(display, e->error_code, err_buf, BUFSIZ);
|
||||
fputs(err_buf, stderr);
|
||||
fputs("\n", stderr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* see screen.h */
|
||||
bool window_is_fullscreen(Window window)
|
||||
{
|
||||
bool fs = false;
|
||||
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
Atom has_wm_state = XInternAtom(xctx.dpy, "_NET_WM_STATE", True);
|
||||
if (has_wm_state == None){
|
||||
return false;
|
||||
}
|
||||
|
||||
XFlush(xctx.dpy);
|
||||
XSetErrorHandler(XErrorHandlerFullscreen);
|
||||
|
||||
Atom actual_type_return;
|
||||
int actual_format_return;
|
||||
unsigned long bytes_after_return;
|
||||
unsigned char *prop_to_return;
|
||||
unsigned long n_items;
|
||||
int result = XGetWindowProperty(
|
||||
xctx.dpy,
|
||||
window,
|
||||
has_wm_state,
|
||||
0, /* long_offset */
|
||||
sizeof(window), /* long_length */
|
||||
false, /* delete */
|
||||
AnyPropertyType, /* req_type */
|
||||
&actual_type_return,
|
||||
&actual_format_return,
|
||||
&n_items,
|
||||
&bytes_after_return,
|
||||
&prop_to_return);
|
||||
|
||||
XFlush(xctx.dpy);
|
||||
XSync(xctx.dpy, false);
|
||||
XSetErrorHandler(NULL);
|
||||
|
||||
if (result == Success) {
|
||||
for(int i = 0; i < n_items; i++) {
|
||||
char *atom = XGetAtomName(xctx.dpy, ((Atom*)prop_to_return)[i]);
|
||||
|
||||
if (atom) {
|
||||
if(0 == strcmp("_NET_WM_STATE_FULLSCREEN", atom))
|
||||
fs = true;
|
||||
XFree(atom);
|
||||
if(fs)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prop_to_return)
|
||||
XFree(prop_to_return);
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the screen on which the Window
|
||||
* should be displayed.
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define DUNST_SCREEN_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh))
|
||||
|
||||
@ -27,5 +28,24 @@ void screen_check_event(XEvent event);
|
||||
screen_info *get_active_screen(void);
|
||||
double get_dpi_for_screen(screen_info *scr);
|
||||
|
||||
/**
|
||||
* Find the currently focused window and check if it's in
|
||||
* fullscreen mode
|
||||
*
|
||||
* @see window_is_fullscreen()
|
||||
* @see get_focused_window()
|
||||
*
|
||||
* @return `true` if the focused window is in fullscreen mode
|
||||
*/
|
||||
bool have_fullscreen_window(void);
|
||||
|
||||
/**
|
||||
* Check if window is in fullscreen mode
|
||||
*
|
||||
* @param window the x11 window object
|
||||
* @return `true` if `window` is in fullscreen mode
|
||||
*/
|
||||
bool window_is_fullscreen(Window window);
|
||||
|
||||
#endif
|
||||
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
||||
|
17
src/x11/x.c
17
src/x11/x.c
@ -60,6 +60,7 @@ typedef struct _colored_layout {
|
||||
} colored_layout;
|
||||
|
||||
cairo_ctx_t cairo_ctx;
|
||||
static bool fullscreen_last = false;
|
||||
|
||||
/* FIXME refactor setup teardown handlers into one setup and one teardown */
|
||||
static void x_shortcut_setup_error_handler(void);
|
||||
@ -848,10 +849,13 @@ gboolean x_mainloop_fd_check(GSource *source)
|
||||
*/
|
||||
gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
|
||||
{
|
||||
bool fullscreen_now;
|
||||
XEvent ev;
|
||||
unsigned int state;
|
||||
while (XPending(xctx.dpy) > 0) {
|
||||
XNextEvent(xctx.dpy, &ev);
|
||||
LOG_D("XEvent: processing '%d'", ev.type);
|
||||
|
||||
switch (ev.type) {
|
||||
case Expose:
|
||||
if (ev.xexpose.count == 0 && xctx.visible) {
|
||||
@ -908,13 +912,20 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, gpointer
|
||||
wake_up();
|
||||
break;
|
||||
case PropertyNotify:
|
||||
fullscreen_now = have_fullscreen_window();
|
||||
|
||||
if (fullscreen_now != fullscreen_last) {
|
||||
fullscreen_last = fullscreen_now;
|
||||
wake_up();
|
||||
} else if ( settings.f_mode != FOLLOW_NONE
|
||||
/* Ignore PropertyNotify, when we're still on the
|
||||
* same screen. PropertyNotify is only neccessary
|
||||
* to detect a focus change to another screen
|
||||
*/
|
||||
if( settings.f_mode != FOLLOW_NONE
|
||||
&& get_active_screen()->scr != xctx.cur_screen)
|
||||
wake_up();
|
||||
&& xctx.visible
|
||||
&& get_active_screen()->scr != xctx.cur_screen) {
|
||||
x_win_draw();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
screen_check_event(ev);
|
||||
|
Loading…
x
Reference in New Issue
Block a user