diff --git a/src/include/event-adapter.h b/src/include/event-adapter.h index 8a05a44..f870331 100644 --- a/src/include/event-adapter.h +++ b/src/include/event-adapter.h @@ -2,7 +2,6 @@ #include #include -#include #include "types.h" @@ -115,8 +114,15 @@ typedef struct focus_in_event_t { xcb_window_t window; } focus_in_event_t; +typedef enum property_state_t { + property_new_value = 0, + property_delete = 1 +} property_state_t; typedef struct property_notify_event_t { event_type_t type; + xcb_window_t window; + uint32_t xcb_atom; + property_state_t state; } property_notify_event_t; typedef struct client_message_event_t { diff --git a/src/include/xcb.h b/src/include/xcb.h index 6f2222c..4d5550e 100644 --- a/src/include/xcb.h +++ b/src/include/xcb.h @@ -103,7 +103,9 @@ typedef enum atom_t { atom_wm_protocols, atom_wm_delete, atom_wm_take_focus, + atom_net_wm_name, } atom_t; +xcb_atom_t get_xcb_atom(atom_t atom); bool send_event(xcb_window_t window, atom_t atom); typedef enum wm_state_t { wm_state_withdrawn = 0, diff --git a/src/main.c b/src/main.c index 2992d9c..12f5538 100644 --- a/src/main.c +++ b/src/main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "action.h" #include "config.h" @@ -44,6 +45,7 @@ static void expose(expose_event_t *event); static void motion_notify(motion_notify_event_t *event); static void enter_notify(enter_notify_event_t *event); static void focus_in(focus_in_event_t *event); +static void property_notify(property_notify_event_t *event); static void manage_window(xcb_window_t window); static void unmanage_client(client_t *client, bool destroyed); static void update_client_list(void); @@ -473,6 +475,7 @@ void xcb_event_handler(generic_event_t *event, void *user_data) { EVENT(EVENT_TYPE_MOTION_NOTIFY, motion_notify); EVENT(EVENT_TYPE_ENTER_NOTIFY, enter_notify); EVENT(EVENT_TYPE_FOCUS_IN, focus_in); + EVENT(EVENT_TYPE_PROPERTY_NOTIFY, property_notify); #undef EVENT @@ -579,6 +582,32 @@ void focus_in(focus_in_event_t *event) { } } +void property_notify(property_notify_event_t *event) { + if (event->state == property_delete) return; + + client_t *c = get_client_of_window(event->window); + if (!c) return; + switch (event->xcb_atom) { + case XCB_ATOM_WM_TRANSIENT_FOR: { + xcb_window_t transient_for; + if (!c->floating && + ((transient_for = get_transient_window_for(event->window)) != + WINDOW_NONE) && + (c->floating = (get_client_of_window(transient_for) != NULL))) { + arrange(c->monitor); + } + break; + } + default: + break; + } + if (event->xcb_atom == XCB_ATOM_WM_NAME || + event->xcb_atom == get_xcb_atom(atom_net_wm_name)) { + update_client_name(c); + if (c->tags & c->monitor->selected_tags) draw_monitor_bar(c->monitor); + } +} + void manage_window(xcb_window_t window) { window_geometry_t *geometry = get_window_geometry(window); client_t *c = ecalloc(1, sizeof(client_t)); @@ -874,17 +903,6 @@ gboolean handle_xcb_event(GIOChannel *channel, GIOCondition condition, } void cleanup(void) { - clean_pango_context(); - - free_wallpaper_config(wallpaper_config); - wallpaper_config = NULL; - - free(color_set); - color_set = NULL; - - free(font_family); - font_family = NULL; - monitor_t *m = monitors; client_t *c = m->clients; while (m) { @@ -902,6 +920,17 @@ void cleanup(void) { } monitors = NULL; + clean_pango_context(); + + free_wallpaper_config(wallpaper_config); + wallpaper_config = NULL; + + free(color_set); + color_set = NULL; + + free(font_family); + font_family = NULL; + destroy_event_adapter(adapter); adapter = NULL; diff --git a/src/xcb/event.c b/src/xcb/event.c index c61c1ca..3694dc7 100644 --- a/src/xcb/event.c +++ b/src/xcb/event.c @@ -104,9 +104,15 @@ static void convert_event(xcb_generic_event_t *xcb_event, event->focus_in.type = EVENT_TYPE_FOCUS_IN; event->focus_in.window = ev->event; } break; - case XCB_PROPERTY_NOTIFY: - event->type = EVENT_TYPE_PROPERTY_NOTIFY; + case XCB_PROPERTY_NOTIFY: { + xcb_property_notify_event_t *ev = + (xcb_property_notify_event_t *)xcb_event; + event->property_notify.type = EVENT_TYPE_PROPERTY_NOTIFY; + event->property_notify.window = ev->window; + event->property_notify.xcb_atom = ev->atom; + event->property_notify.state = ev->state; break; + } case XCB_CLIENT_MESSAGE: event->type = EVENT_TYPE_CLIENT_MESSAGE; break; diff --git a/src/xcb/wm-extension.c b/src/xcb/wm-extension.c index 1e7ff6c..95d8d2c 100644 --- a/src/xcb/wm-extension.c +++ b/src/xcb/wm-extension.c @@ -25,6 +25,7 @@ static atom_map_t atom_map[] = { {.atom = atom_wm_protocols, .name = "WM_PROTOCOLS"}, {.atom = atom_wm_delete, .name = "WM_DELETE_WINDOW"}, {.atom = atom_wm_take_focus, .name = "WM_TAKE_FOCUS"}, + {.atom = atom_net_wm_name, .name = "_NET_WM_NAME"}, }; void init_icccm_extension(void) { @@ -97,6 +98,11 @@ void clean_ewmh_extension(void) { } } +xcb_atom_t get_xcb_atom(atom_t atom) { + if (atom < 0 || atom >= LENGTH(atom_map)) return XCB_ATOM_NONE; + return atom_map[atom].xcb_atom; +} + bool send_event(xcb_window_t window, atom_t atom) { if (atom < 0 || atom >= LENGTH(atom_map)) return false;