summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Davenport <DaveDavenport@users.noreply.github.com>2021-09-03 13:53:43 +0200
committerGitHub <noreply@github.com>2021-09-03 13:53:43 +0200
commit4d0eaf14631a0ef429cba002e63acc15fcfebc32 (patch)
treedd350438bbdb0868bb12f155faf5ade906fccf46
parentec83fb6efbe2471f873679879d75c044457b4f31 (diff)
[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.
-rw-r--r--include/dialogs/window.h2
-rw-r--r--source/dialogs/window.c70
-rw-r--r--source/xcb.c24
3 files changed, 82 insertions, 14 deletions
diff --git a/include/dialogs/window.h b/include/dialogs/window.h
index c25c1368..145628b3 100644
--- a/include/dialogs/window.h
+++ b/include/dialogs/window.h
@@ -40,6 +40,8 @@
extern Mode window_mode;
extern Mode window_mode_cd;
+
+void window_client_handle_signal(xcb_window_t win, gboolean create);
#endif // WINDOW_MODE
/** @}*/
#endif // ROFI_DIALOG_WINDOW_H
diff --git a/source/dialogs/window.c b/source/dialogs/window.c
index d1d9cd63..fd393172 100644
--- a/source/dialogs/window.c
+++ b/source/dialogs/window.c
@@ -147,7 +147,7 @@ typedef struct {
unsigned int title_len;
unsigned int role_len;
GRegex *window_regex;
-} ModeModePrivateData;
+} WindowModePrivateData;
winlist *cache_client = NULL;
@@ -236,6 +236,9 @@ static void winlist_free(winlist *l) {
* @returns -1 if failed, index is successful.
*/
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
// nearer the end. Testing with kcachegrind seems to support this...
int i;
@@ -305,7 +308,7 @@ static int client_has_window_type(client *c, xcb_atom_t type) {
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) {
return NULL;
}
@@ -378,9 +381,35 @@ static client *window_client(ModeModePrivateData *pd, xcb_window_t win) {
g_free(attr);
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,
unsigned int index) {
- ModeModePrivateData *rmpd = (ModeModePrivateData *)mode_get_private_data(sw);
+ WindowModePrivateData *rmpd =
+ (WindowModePrivateData *)mode_get_private_data(sw);
int match = 1;
const winlist *ids = (winlist *)rmpd->ids;
// 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) {
- const ModeModePrivateData *pd =
- (const ModeModePrivateData *)mode_get_private_data(sw);
+ const WindowModePrivateData *pd =
+ (const WindowModePrivateData *)mode_get_private_data(sw);
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];
}
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
xcb_window_t curr_win_id;
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) {
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);
mode_set_private_data(sw, (void *)pd);
_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) {
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);
mode_set_private_data(sw, (void *)pd);
_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,
G_GNUC_UNUSED char **input,
unsigned int selected_line) {
- ModeModePrivateData *rmpd = (ModeModePrivateData *)mode_get_private_data(sw);
+ WindowModePrivateData *rmpd =
+ (WindowModePrivateData *)mode_get_private_data(sw);
ModeMode retv = MODE_EXIT;
if ((mretv & (MENU_OK))) {
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_CURRENT_TIME, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER);
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 &&
*input[0] != '\0') {
GError *error = NULL;
@@ -776,7 +814,8 @@ static ModeMode window_mode_result(Mode *sw, int mretv,
}
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) {
winlist_free(rmpd->ids);
x11_cache_free();
@@ -787,7 +826,7 @@ static void window_mode_destroy(Mode *sw) {
}
}
struct arg {
- const ModeModePrivateData *pd;
+ const WindowModePrivateData *pd;
client *c;
};
@@ -852,7 +891,7 @@ static gboolean helper_eval_cb(const GMatchInfo *info, GString *str,
}
return FALSE;
}
-static char *_generate_display_string(const ModeModePrivateData *pd,
+static char *_generate_display_string(const WindowModePrivateData *pd,
client *c) {
struct arg d = {pd, c};
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,
int *state, G_GNUC_UNUSED GList **list,
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]);
if (c == 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,
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]);
+ if (c == NULL) {
+ return NULL;
+ }
if (config.window_thumbnail && c->thumbnail_checked == FALSE) {
c->icon = x11_helper_get_screenshot_surface_window(c->window, size);
c->thumbnail_checked = TRUE;
diff --git a/source/xcb.c b/source/xcb.c
index 6a4ae45c..c2bf52b8 100644
--- a/source/xcb.c
+++ b/source/xcb.c
@@ -63,6 +63,9 @@
#include "xcb.h"
#include <libsn/sn.h>
+#include "dialogs/window.h"
+#include "mode.h"
+
#include <rofi.h>
/** 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;
}
+ 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:
rofi_view_frame_callback();
break;
@@ -1484,6 +1503,11 @@ gboolean display_setup(GMainLoop *main_loop, NkBindings *bindings) {
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.
xcb->sndisplay =
sn_xcb_display_new(xcb->connection, error_trap_push, error_trap_pop);