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:
parent
ec83fb6efb
commit
4d0eaf1463
3 changed files with 82 additions and 14 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
24
source/xcb.c
24
source/xcb.c
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue