1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2024-11-25 13:55:34 -05:00

[Window] Issue 1406 fix the broken close-on-delete (#1421)

* [1406] Add watcher for new/removed windows and reload based on that.
* [1406] Add a small timeout before reloading to avoid reloading several times in a row.
* [1406] close rofi if you receive a destroy window on rofi.
This commit is contained in:
Dave Davenport 2021-09-03 13:53:43 +02:00 committed by GitHub
parent ec83fb6efb
commit 4d0eaf1463
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 14 deletions

View file

@ -40,6 +40,8 @@
extern Mode window_mode; extern Mode window_mode;
extern Mode window_mode_cd; extern Mode window_mode_cd;
void window_client_handle_signal(xcb_window_t win, gboolean create);
#endif // WINDOW_MODE #endif // WINDOW_MODE
/** @}*/ /** @}*/
#endif // ROFI_DIALOG_WINDOW_H #endif // ROFI_DIALOG_WINDOW_H

View file

@ -147,7 +147,7 @@ typedef struct {
unsigned int title_len; unsigned int title_len;
unsigned int role_len; unsigned int role_len;
GRegex *window_regex; GRegex *window_regex;
} ModeModePrivateData; } WindowModePrivateData;
winlist *cache_client = NULL; winlist *cache_client = NULL;
@ -236,6 +236,9 @@ static void winlist_free(winlist *l) {
* @returns -1 if failed, index is successful. * @returns -1 if failed, index is successful.
*/ */
static int winlist_find(winlist *l, xcb_window_t w) { static int winlist_find(winlist *l, xcb_window_t w) {
if (l == NULL) {
return -1;
}
// iterate backwards. Theory is: windows most often accessed will be // iterate backwards. Theory is: windows most often accessed will be
// nearer the end. Testing with kcachegrind seems to support this... // nearer the end. Testing with kcachegrind seems to support this...
int i; int i;
@ -305,7 +308,7 @@ static int client_has_window_type(client *c, xcb_atom_t type) {
return 0; return 0;
} }
static client *window_client(ModeModePrivateData *pd, xcb_window_t win) { static client *window_client(WindowModePrivateData *pd, xcb_window_t win) {
if (win == XCB_WINDOW_NONE) { if (win == XCB_WINDOW_NONE) {
return NULL; return NULL;
} }
@ -378,9 +381,35 @@ static client *window_client(ModeModePrivateData *pd, xcb_window_t win) {
g_free(attr); g_free(attr);
return c; return c;
} }
guint window_reload_timeout = 0;
static gboolean window_client_reload(G_GNUC_UNUSED void *data) {
window_reload_timeout = 0;
if (window_mode.private_data) {
window_mode._destroy(&window_mode);
window_mode._init(&window_mode);
}
if (window_mode_cd.private_data) {
window_mode._destroy(&window_mode_cd);
window_mode._init(&window_mode_cd);
}
if (window_mode.private_data || window_mode_cd.private_data) {
rofi_view_reload();
}
return G_SOURCE_REMOVE;
}
void window_client_handle_signal(xcb_window_t win, gboolean create) {
// g_idle_add_full(G_PRIORITY_HIGH_IDLE, window_client_reload, NULL, NULL);
if (window_reload_timeout > 0) {
g_source_remove(window_reload_timeout);
window_reload_timeout = 0;
}
window_reload_timeout = g_timeout_add(100, window_client_reload, NULL);
}
static int window_match(const Mode *sw, rofi_int_matcher **tokens, static int window_match(const Mode *sw, rofi_int_matcher **tokens,
unsigned int index) { unsigned int index) {
ModeModePrivateData *rmpd = (ModeModePrivateData *)mode_get_private_data(sw); WindowModePrivateData *rmpd =
(WindowModePrivateData *)mode_get_private_data(sw);
int match = 1; int match = 1;
const winlist *ids = (winlist *)rmpd->ids; const winlist *ids = (winlist *)rmpd->ids;
// Want to pull directly out of cache, X calls are not thread safe. // Want to pull directly out of cache, X calls are not thread safe.
@ -466,8 +495,8 @@ static void window_mode_parse_fields() {
} }
static unsigned int window_mode_get_num_entries(const Mode *sw) { static unsigned int window_mode_get_num_entries(const Mode *sw) {
const ModeModePrivateData *pd = const WindowModePrivateData *pd =
(const ModeModePrivateData *)mode_get_private_data(sw); (const WindowModePrivateData *)mode_get_private_data(sw);
return pd->ids ? pd->ids->len : 0; return pd->ids ? pd->ids->len : 0;
} }
@ -492,7 +521,8 @@ static const char *_window_name_list_entry(const char *str, uint32_t length,
return &str[offset]; return &str[offset];
} }
static void _window_mode_load_data(Mode *sw, unsigned int cd) { static void _window_mode_load_data(Mode *sw, unsigned int cd) {
ModeModePrivateData *pd = (ModeModePrivateData *)mode_get_private_data(sw); WindowModePrivateData *pd =
(WindowModePrivateData *)mode_get_private_data(sw);
// find window list // find window list
xcb_window_t curr_win_id; xcb_window_t curr_win_id;
int found = 0; int found = 0;
@ -640,7 +670,7 @@ static void _window_mode_load_data(Mode *sw, unsigned int cd) {
} }
static int window_mode_init(Mode *sw) { static int window_mode_init(Mode *sw) {
if (mode_get_private_data(sw) == NULL) { if (mode_get_private_data(sw) == NULL) {
ModeModePrivateData *pd = g_malloc0(sizeof(*pd)); WindowModePrivateData *pd = g_malloc0(sizeof(*pd));
pd->window_regex = g_regex_new("{[-\\w]+(:-?[0-9]+)?}", 0, 0, NULL); pd->window_regex = g_regex_new("{[-\\w]+(:-?[0-9]+)?}", 0, 0, NULL);
mode_set_private_data(sw, (void *)pd); mode_set_private_data(sw, (void *)pd);
_window_mode_load_data(sw, FALSE); _window_mode_load_data(sw, FALSE);
@ -652,7 +682,7 @@ static int window_mode_init(Mode *sw) {
} }
static int window_mode_init_cd(Mode *sw) { static int window_mode_init_cd(Mode *sw) {
if (mode_get_private_data(sw) == NULL) { if (mode_get_private_data(sw) == NULL) {
ModeModePrivateData *pd = g_malloc0(sizeof(*pd)); WindowModePrivateData *pd = g_malloc0(sizeof(*pd));
pd->window_regex = g_regex_new("{[-\\w]+(:-?[0-9]+)?}", 0, 0, NULL); pd->window_regex = g_regex_new("{[-\\w]+(:-?[0-9]+)?}", 0, 0, NULL);
mode_set_private_data(sw, (void *)pd); mode_set_private_data(sw, (void *)pd);
_window_mode_load_data(sw, TRUE); _window_mode_load_data(sw, TRUE);
@ -696,7 +726,8 @@ static inline int act_on_window(xcb_window_t window) {
static ModeMode window_mode_result(Mode *sw, int mretv, static ModeMode window_mode_result(Mode *sw, int mretv,
G_GNUC_UNUSED char **input, G_GNUC_UNUSED char **input,
unsigned int selected_line) { unsigned int selected_line) {
ModeModePrivateData *rmpd = (ModeModePrivateData *)mode_get_private_data(sw); WindowModePrivateData *rmpd =
(WindowModePrivateData *)mode_get_private_data(sw);
ModeMode retv = MODE_EXIT; ModeMode retv = MODE_EXIT;
if ((mretv & (MENU_OK))) { if ((mretv & (MENU_OK))) {
if (mretv & MENU_CUSTOM_ACTION) { if (mretv & MENU_CUSTOM_ACTION) {
@ -750,6 +781,13 @@ static ModeMode window_mode_result(Mode *sw, int mretv,
&(xcb->ewmh), xcb->screen_nbr, rmpd->ids->array[selected_line], &(xcb->ewmh), xcb->screen_nbr, rmpd->ids->array[selected_line],
XCB_CURRENT_TIME, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER); XCB_CURRENT_TIME, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER);
xcb_flush(xcb->connection); xcb_flush(xcb->connection);
ThemeWidget *wid = rofi_config_find_widget(sw->name, NULL, TRUE);
Property *p =
rofi_theme_find_property(wid, P_BOOLEAN, "close-on-delete", TRUE);
if (p && p->type == P_BOOLEAN && p->value.b == FALSE) {
return RELOAD_DIALOG;
}
} else if ((mretv & MENU_CUSTOM_INPUT) && *input != NULL && } else if ((mretv & MENU_CUSTOM_INPUT) && *input != NULL &&
*input[0] != '\0') { *input[0] != '\0') {
GError *error = NULL; GError *error = NULL;
@ -776,7 +814,8 @@ static ModeMode window_mode_result(Mode *sw, int mretv,
} }
static void window_mode_destroy(Mode *sw) { static void window_mode_destroy(Mode *sw) {
ModeModePrivateData *rmpd = (ModeModePrivateData *)mode_get_private_data(sw); WindowModePrivateData *rmpd =
(WindowModePrivateData *)mode_get_private_data(sw);
if (rmpd != NULL) { if (rmpd != NULL) {
winlist_free(rmpd->ids); winlist_free(rmpd->ids);
x11_cache_free(); x11_cache_free();
@ -787,7 +826,7 @@ static void window_mode_destroy(Mode *sw) {
} }
} }
struct arg { struct arg {
const ModeModePrivateData *pd; const WindowModePrivateData *pd;
client *c; client *c;
}; };
@ -852,7 +891,7 @@ static gboolean helper_eval_cb(const GMatchInfo *info, GString *str,
} }
return FALSE; return FALSE;
} }
static char *_generate_display_string(const ModeModePrivateData *pd, static char *_generate_display_string(const WindowModePrivateData *pd,
client *c) { client *c) {
struct arg d = {pd, c}; struct arg d = {pd, c};
char *res = g_regex_replace_eval(pd->window_regex, config.window_format, -1, char *res = g_regex_replace_eval(pd->window_regex, config.window_format, -1,
@ -863,7 +902,7 @@ static char *_generate_display_string(const ModeModePrivateData *pd,
static char *_get_display_value(const Mode *sw, unsigned int selected_line, static char *_get_display_value(const Mode *sw, unsigned int selected_line,
int *state, G_GNUC_UNUSED GList **list, int *state, G_GNUC_UNUSED GList **list,
int get_entry) { int get_entry) {
ModeModePrivateData *rmpd = mode_get_private_data(sw); WindowModePrivateData *rmpd = mode_get_private_data(sw);
client *c = window_client(rmpd, rmpd->ids->array[selected_line]); client *c = window_client(rmpd, rmpd->ids->array[selected_line]);
if (c == NULL) { if (c == NULL) {
return get_entry ? g_strdup("Window has vanished") : NULL; return get_entry ? g_strdup("Window has vanished") : NULL;
@ -980,8 +1019,11 @@ static cairo_surface_t *get_net_wm_icon(xcb_window_t xid,
} }
static cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line, static cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,
int size) { int size) {
ModeModePrivateData *rmpd = mode_get_private_data(sw); WindowModePrivateData *rmpd = mode_get_private_data(sw);
client *c = window_client(rmpd, rmpd->ids->array[selected_line]); client *c = window_client(rmpd, rmpd->ids->array[selected_line]);
if (c == NULL) {
return NULL;
}
if (config.window_thumbnail && c->thumbnail_checked == FALSE) { if (config.window_thumbnail && c->thumbnail_checked == FALSE) {
c->icon = x11_helper_get_screenshot_surface_window(c->window, size); c->icon = x11_helper_get_screenshot_surface_window(c->window, size);
c->thumbnail_checked = TRUE; c->thumbnail_checked = TRUE;

View file

@ -63,6 +63,9 @@
#include "xcb.h" #include "xcb.h"
#include <libsn/sn.h> #include <libsn/sn.h>
#include "dialogs/window.h"
#include "mode.h"
#include <rofi.h> #include <rofi.h>
/** Minimal randr preferred for running rofi (1.5) (Major version number) */ /** Minimal randr preferred for running rofi (1.5) (Major version number) */
@ -1083,6 +1086,22 @@ static void main_loop_x11_event_handler_view(xcb_generic_event_t *event) {
} }
break; break;
} }
case XCB_DESTROY_NOTIFY: {
xcb_window_t win = ((xcb_destroy_notify_event_t *)event)->window;
if (win != rofi_view_get_window()) {
window_client_handle_signal(win, FALSE);
} else {
g_main_loop_quit(xcb->main_loop);
}
break;
}
case XCB_CREATE_NOTIFY: {
xcb_window_t win = ((xcb_create_notify_event_t *)event)->window;
if (win != rofi_view_get_window()) {
window_client_handle_signal(win, TRUE);
}
break;
}
case XCB_EXPOSE: case XCB_EXPOSE:
rofi_view_frame_callback(); rofi_view_frame_callback();
break; break;
@ -1484,6 +1503,11 @@ gboolean display_setup(GMainLoop *main_loop, NkBindings *bindings) {
return FALSE; return FALSE;
} }
uint32_t val[] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY};
xcb_change_window_attributes(xcb->connection, xcb_stuff_get_root_window(),
XCB_CW_EVENT_MASK, val);
// startup not. // startup not.
xcb->sndisplay = xcb->sndisplay =
sn_xcb_display_new(xcb->connection, error_trap_push, error_trap_pop); sn_xcb_display_new(xcb->connection, error_trap_push, error_trap_pop);