win: track windows with a hash table
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
3935e97e69
commit
a68903b9ef
|
@ -43,6 +43,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, meso
|
||||||
* libGL (optional, disable with the `-Dopengl=false` meson configure flag)
|
* libGL (optional, disable with the `-Dopengl=false` meson configure flag)
|
||||||
* libpcre (optional, disable with the `-Dregex=false` meson configure flag)
|
* libpcre (optional, disable with the `-Dregex=false` meson configure flag)
|
||||||
* libev
|
* libev
|
||||||
|
* uthash
|
||||||
|
|
||||||
To build the documents, you need `asciidoc`
|
To build the documents, you need `asciidoc`
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@ if get_option('sanitize')
|
||||||
endif
|
endif
|
||||||
add_global_arguments('-fsanitize='+','.join(sanitizers), language: 'c')
|
add_global_arguments('-fsanitize='+','.join(sanitizers), language: 'c')
|
||||||
add_global_link_arguments('-fsanitize='+','.join(sanitizers), language: 'c')
|
add_global_link_arguments('-fsanitize='+','.join(sanitizers), language: 'c')
|
||||||
|
if cc.has_argument('-fno-sanitize=unsigned-integer-overflow')
|
||||||
|
add_global_arguments('-fno-sanitize=unsigned-integer-overflow', language: 'c')
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('modularize')
|
if get_option('modularize')
|
||||||
|
|
44
src/common.h
44
src/common.h
|
@ -49,6 +49,7 @@
|
||||||
#include <xcb/sync.h>
|
#include <xcb/sync.h>
|
||||||
#include <xcb/xinerama.h>
|
#include <xcb/xinerama.h>
|
||||||
|
|
||||||
|
#include "uthash_extra.h"
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
// libGL
|
// libGL
|
||||||
#include "backend/gl/glx.h"
|
#include "backend/gl/glx.h"
|
||||||
|
@ -389,8 +390,10 @@ typedef struct session {
|
||||||
int n_expose;
|
int n_expose;
|
||||||
|
|
||||||
// === Window related ===
|
// === Window related ===
|
||||||
/// Linked list of all windows.
|
/// A hash table of all windows.
|
||||||
win *list;
|
win *windows;
|
||||||
|
/// Windows in their stacking order
|
||||||
|
win *window_stack;
|
||||||
/// Pointer to <code>win</code> of current active window. Used by
|
/// Pointer to <code>win</code> of current active window. Used by
|
||||||
/// EWMH <code>_NET_ACTIVE_WINDOW</code> focus detection. In theory,
|
/// EWMH <code>_NET_ACTIVE_WINDOW</code> focus detection. In theory,
|
||||||
/// it's more reliable to store the window ID directly here, just in
|
/// it's more reliable to store the window ID directly here, just in
|
||||||
|
@ -732,43 +735,6 @@ static inline xcb_window_t get_tgt_window(session_t *ps) {
|
||||||
return ps->overlay != XCB_NONE ? ps->overlay : ps->root;
|
return ps->overlay != XCB_NONE ? ps->overlay : ps->root;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a window from window id in window linked list of the session.
|
|
||||||
*/
|
|
||||||
static inline win *find_win(session_t *ps, xcb_window_t id) {
|
|
||||||
if (!id)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
win *w;
|
|
||||||
|
|
||||||
for (w = ps->list; w; w = w->next) {
|
|
||||||
if (w->id == id && w->state != WSTATE_DESTROYING) {
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find out the WM frame of a client window using existing data.
|
|
||||||
*
|
|
||||||
* @param id window ID
|
|
||||||
* @return struct win object of the found window, NULL if not found
|
|
||||||
*/
|
|
||||||
static inline win *find_toplevel(session_t *ps, xcb_window_t id) {
|
|
||||||
if (!id)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (win *w = ps->list; w; w = w->next) {
|
|
||||||
if (w->client_win == id && w->state != WSTATE_DESTROYING) {
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if current backend uses GLX.
|
* Check if current backend uses GLX.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
#include "uthash_extra.h"
|
||||||
|
|
||||||
/// Get session_t pointer from a pointer to a member of session_t
|
/// Get session_t pointer from a pointer to a member of session_t
|
||||||
#define session_ptr(ptr, member) \
|
#define session_ptr(ptr, member) \
|
||||||
|
@ -419,7 +420,7 @@ static void handle_root_flags(session_t *ps) {
|
||||||
static win *paint_preprocess(session_t *ps, bool *fade_running) {
|
static win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||||
// XXX need better, more general name for `fade_running`. It really
|
// XXX need better, more general name for `fade_running`. It really
|
||||||
// means if fade is still ongoing after the current frame is rendered
|
// means if fade is still ongoing after the current frame is rendered
|
||||||
win *t = NULL, *next = NULL;
|
win *t = NULL;
|
||||||
*fade_running = false;
|
*fade_running = false;
|
||||||
|
|
||||||
// Fading step calculation
|
// Fading step calculation
|
||||||
|
@ -436,8 +437,7 @@ static win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||||
ps->fade_time += steps * ps->o.fade_delta;
|
ps->fade_time += steps * ps->o.fade_delta;
|
||||||
|
|
||||||
// First, let's process fading
|
// First, let's process fading
|
||||||
for (win *w = ps->list; w; w = next) {
|
WIN_STACK_ITER(ps, w) {
|
||||||
next = w->next;
|
|
||||||
const winmode_t mode_old = w->mode;
|
const winmode_t mode_old = w->mode;
|
||||||
const bool was_painted = w->to_paint;
|
const bool was_painted = w->to_paint;
|
||||||
const double opacity_old = w->opacity;
|
const double opacity_old = w->opacity;
|
||||||
|
@ -490,15 +490,12 @@ static win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||||
// Track whether it's the highest window to paint
|
// Track whether it's the highest window to paint
|
||||||
bool is_highest = true;
|
bool is_highest = true;
|
||||||
bool reg_ignore_valid = true;
|
bool reg_ignore_valid = true;
|
||||||
for (win *w = ps->list; w; w = next) {
|
WIN_STACK_ITER(ps, w) {
|
||||||
__label__ skip_window;
|
__label__ skip_window;
|
||||||
bool to_paint = true;
|
bool to_paint = true;
|
||||||
// w->to_paint remembers whether this window is painted last time
|
// w->to_paint remembers whether this window is painted last time
|
||||||
const bool was_painted = w->to_paint;
|
const bool was_painted = w->to_paint;
|
||||||
|
|
||||||
// In case calling the fade callback function destroys this window
|
|
||||||
next = w->next;
|
|
||||||
|
|
||||||
// Destroy reg_ignore if some window above us invalidated it
|
// Destroy reg_ignore if some window above us invalidated it
|
||||||
if (!reg_ignore_valid) {
|
if (!reg_ignore_valid) {
|
||||||
rc_region_unref(&w->reg_ignore);
|
rc_region_unref(&w->reg_ignore);
|
||||||
|
@ -672,7 +669,7 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) {
|
||||||
win **prev = NULL, **prev_old = NULL;
|
win **prev = NULL, **prev_old = NULL;
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (prev = &ps->list; *prev; prev = &(*prev)->next) {
|
for (prev = &ps->window_stack; *prev; prev = &(*prev)->next) {
|
||||||
if ((*prev)->id == new_above && (*prev)->state != WSTATE_DESTROYING) {
|
if ((*prev)->id == new_above && (*prev)->state != WSTATE_DESTROYING) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
@ -685,7 +682,7 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (prev_old = &ps->list; *prev_old; prev_old = &(*prev_old)->next) {
|
for (prev_old = &ps->window_stack; *prev_old; prev_old = &(*prev_old)->next) {
|
||||||
if ((*prev_old) == w) {
|
if ((*prev_old) == w) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -713,8 +710,7 @@ static void restack_win(session_t *ps, win *w, xcb_window_t new_above) {
|
||||||
|
|
||||||
/// Free up all the images and deinit the backend
|
/// Free up all the images and deinit the backend
|
||||||
static void destroy_backend(session_t *ps) {
|
static void destroy_backend(session_t *ps) {
|
||||||
for (win *w = ps->list, *next; w; w = next) {
|
WIN_STACK_ITER(ps, w) {
|
||||||
next = w->next;
|
|
||||||
// Wrapping up fading in progress
|
// Wrapping up fading in progress
|
||||||
win_skip_fading(ps, &w);
|
win_skip_fading(ps, &w);
|
||||||
|
|
||||||
|
@ -760,7 +756,9 @@ static bool initialize_backend(session_t *ps) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (win *w = ps->list; w; w = w->next) {
|
// window_stack shouldn't include window that's not in the hash table at
|
||||||
|
// this point. Since there cannot be any fading windows.
|
||||||
|
HASH_ITER2(ps->windows, w) {
|
||||||
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
||||||
if (!win_bind_image(ps, w)) {
|
if (!win_bind_image(ps, w)) {
|
||||||
w->flags |= WIN_FLAGS_IMAGE_ERROR;
|
w->flags |= WIN_FLAGS_IMAGE_ERROR;
|
||||||
|
@ -800,8 +798,8 @@ void configure_root(session_t *ps, int width, int height) {
|
||||||
ps->damage = ps->damage_ring + ps->ndamage - 1;
|
ps->damage = ps->damage_ring + ps->ndamage - 1;
|
||||||
|
|
||||||
// Invalidate reg_ignore from the top
|
// Invalidate reg_ignore from the top
|
||||||
rc_region_unref(&ps->list->reg_ignore);
|
rc_region_unref(&ps->window_stack->reg_ignore);
|
||||||
ps->list->reg_ignore_valid = false;
|
ps->window_stack->reg_ignore_valid = false;
|
||||||
|
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
// GLX root change callback
|
// GLX root change callback
|
||||||
|
@ -846,7 +844,6 @@ void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
||||||
restack_win(ps, w, ce->above_sibling);
|
restack_win(ps, w, ce->above_sibling);
|
||||||
} else {
|
} else {
|
||||||
restack_win(ps, w, ce->above_sibling);
|
restack_win(ps, w, ce->above_sibling);
|
||||||
|
|
||||||
bool factor_change = false;
|
bool factor_change = false;
|
||||||
win_extents(w, &damage);
|
win_extents(w, &damage);
|
||||||
|
|
||||||
|
@ -897,7 +894,7 @@ void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ce->place == PlaceOnTop) {
|
if (ce->place == PlaceOnTop) {
|
||||||
new_above = ps->list->id;
|
new_above = ps->window_stack->id;
|
||||||
} else {
|
} else {
|
||||||
new_above = XCB_NONE;
|
new_above = XCB_NONE;
|
||||||
}
|
}
|
||||||
|
@ -1017,13 +1014,15 @@ void opts_init_track_focus(session_t *ps) {
|
||||||
|
|
||||||
if (!ps->o.use_ewmh_active_win) {
|
if (!ps->o.use_ewmh_active_win) {
|
||||||
// Start listening to FocusChange events
|
// Start listening to FocusChange events
|
||||||
for (win *w = ps->list; w; w = w->next)
|
HASH_ITER2(ps->windows, w) {
|
||||||
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
|
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
||||||
xcb_change_window_attributes(
|
xcb_change_window_attributes(
|
||||||
ps->c, w->id, XCB_CW_EVENT_MASK,
|
ps->c, w->id, XCB_CW_EVENT_MASK,
|
||||||
(const uint32_t[]){
|
(const uint32_t[]){
|
||||||
determine_evmask(ps, w->id, WIN_EVMODE_FRAME)});
|
determine_evmask(ps, w->id, WIN_EVMODE_FRAME)});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Recheck focus
|
// Recheck focus
|
||||||
recheck_focus(ps);
|
recheck_focus(ps);
|
||||||
|
@ -1687,7 +1686,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||||
.size_expose = 0,
|
.size_expose = 0,
|
||||||
.n_expose = 0,
|
.n_expose = 0,
|
||||||
|
|
||||||
.list = NULL,
|
.windows = NULL,
|
||||||
.active_win = NULL,
|
.active_win = NULL,
|
||||||
.active_leader = XCB_NONE,
|
.active_leader = XCB_NONE,
|
||||||
|
|
||||||
|
@ -2125,15 +2124,15 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||||
add_win(ps, children[i], i ? children[i - 1] : XCB_NONE);
|
add_win(ps, children[i], i ? children[i - 1] : XCB_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (win *i = ps->list; i; i = i->next) {
|
HASH_ITER2(ps->windows, w) {
|
||||||
if (i->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
||||||
map_win(ps, i);
|
map_win(ps, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(reply);
|
free(reply);
|
||||||
log_trace("Initial stack:");
|
log_trace("Initial stack:");
|
||||||
for (win *c = ps->list; c; c = c->next) {
|
for (win *c = ps->window_stack; c; c = c->next) {
|
||||||
log_trace("%#010x \"%s\"", c->id, c->name);
|
log_trace("%#010x \"%s\"", c->id, c->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2183,22 +2182,17 @@ static void session_destroy(session_t *ps) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Free window linked list
|
// Free window linked list
|
||||||
{
|
|
||||||
win *next = NULL;
|
|
||||||
win *list = ps->list;
|
|
||||||
ps->list = NULL;
|
|
||||||
|
|
||||||
for (win *w = list; w; w = next) {
|
|
||||||
next = w->next;
|
|
||||||
|
|
||||||
|
WIN_STACK_ITER(ps, w) {
|
||||||
if (w->state != WSTATE_DESTROYING) {
|
if (w->state != WSTATE_DESTROYING) {
|
||||||
win_ev_stop(ps, w);
|
win_ev_stop(ps, w);
|
||||||
|
HASH_DEL(ps->windows, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_win_res(ps, w);
|
free_win_res(ps, w);
|
||||||
free(w);
|
free(w);
|
||||||
}
|
}
|
||||||
}
|
ps->window_stack = NULL;
|
||||||
|
|
||||||
// Free blacklists
|
// Free blacklists
|
||||||
free_wincondlst(&ps->o.shadow_blacklist);
|
free_wincondlst(&ps->o.shadow_blacklist);
|
||||||
|
|
14
src/dbus.c
14
src/dbus.c
|
@ -26,6 +26,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
#include "uthash_extra.h"
|
||||||
|
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
|
|
||||||
|
@ -465,11 +466,10 @@ static bool cdbus_apdarg_string(session_t *ps, DBusMessage *msg, const void *dat
|
||||||
static bool cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
|
static bool cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
|
||||||
// Get the number of wids we are to include
|
// Get the number of wids we are to include
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
for (win *w = ps->list; w; w = w->next) {
|
HASH_ITER2(ps->windows, w) {
|
||||||
if (w->state != WSTATE_DESTROYING) {
|
assert(w->state != WSTATE_DESTROYING);
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!count) {
|
if (!count) {
|
||||||
// Nothing to append
|
// Nothing to append
|
||||||
|
@ -480,17 +480,13 @@ static bool cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data)
|
||||||
auto arr = ccalloc(count, cdbus_window_t);
|
auto arr = ccalloc(count, cdbus_window_t);
|
||||||
|
|
||||||
// Build the array
|
// Build the array
|
||||||
{
|
|
||||||
cdbus_window_t *pcur = arr;
|
cdbus_window_t *pcur = arr;
|
||||||
for (win *w = ps->list; w; w = w->next) {
|
HASH_ITER2(ps->windows, w) {
|
||||||
if (w->state != WSTATE_DESTROYING) {
|
assert(w->state != WSTATE_DESTROYING);
|
||||||
*pcur = w->id;
|
*pcur = w->id;
|
||||||
++pcur;
|
++pcur;
|
||||||
assert(pcur <= arr + count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert(pcur == arr + count);
|
assert(pcur == arr + count);
|
||||||
}
|
|
||||||
|
|
||||||
// Append arguments
|
// Append arguments
|
||||||
if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, CDBUS_TYPE_WINDOW, &arr,
|
if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, CDBUS_TYPE_WINDOW, &arr,
|
||||||
|
|
|
@ -23,6 +23,10 @@ foreach i : required_package
|
||||||
base_deps += [dependency(i, required: true)]
|
base_deps += [dependency(i, required: true)]
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
|
if not cc.has_header('uthash.h')
|
||||||
|
error('Dependency uthash not found')
|
||||||
|
endif
|
||||||
|
|
||||||
deps = []
|
deps = []
|
||||||
|
|
||||||
if get_option('config_file')
|
if get_option('config_file')
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
#include "uthash_extra.h"
|
||||||
|
|
||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
|
|
||||||
|
@ -220,8 +221,9 @@ void glx_destroy(session_t *ps) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Free all GLX resources of windows
|
// Free all GLX resources of windows
|
||||||
for (win *w = ps->list; w; w = w->next)
|
WIN_STACK_ITER(ps, w) {
|
||||||
free_win_res_glx(ps, w);
|
free_win_res_glx(ps, w);
|
||||||
|
}
|
||||||
|
|
||||||
// Free GLSL shaders/programs
|
// Free GLSL shaders/programs
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <uthash.h>
|
||||||
|
|
||||||
|
#define HASH_ITER2(head, el) \
|
||||||
|
for (__typeof__(head) el = (head), __tmp = el != NULL ? el->hh.next : NULL; \
|
||||||
|
el != NULL; el = __tmp, __tmp = el != NULL ? el->hh.next : NULL)
|
72
src/win.c
72
src/win.c
|
@ -25,6 +25,7 @@
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "uthash_extra.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "x.h"
|
#include "x.h"
|
||||||
|
|
||||||
|
@ -56,8 +57,9 @@
|
||||||
* Clear leader cache of all windows.
|
* Clear leader cache of all windows.
|
||||||
*/
|
*/
|
||||||
static inline void clear_cache_win_leaders(session_t *ps) {
|
static inline void clear_cache_win_leaders(session_t *ps) {
|
||||||
for (win *w = ps->list; w; w = w->next)
|
for (win *w = ps->window_stack; w; w = w->next) {
|
||||||
w->cache_leader = XCB_NONE;
|
w->cache_leader = XCB_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wid_set_opacity_prop(session_t *ps, xcb_window_t wid, opacity_t val) {
|
static inline void wid_set_opacity_prop(session_t *ps, xcb_window_t wid, opacity_t val) {
|
||||||
|
@ -79,10 +81,12 @@ static inline void group_update_focused(session_t *ps, xcb_window_t leader) {
|
||||||
if (!leader)
|
if (!leader)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (win *w = ps->list; w; w = w->next) {
|
HASH_ITER2(ps->windows, w) {
|
||||||
if (win_get_leader(ps, w) == leader && w->state != WSTATE_DESTROYING)
|
assert(w->state != WSTATE_DESTROYING);
|
||||||
|
if (win_get_leader(ps, w) == leader) {
|
||||||
win_update_focused(ps, w);
|
win_update_focused(ps, w);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -97,11 +101,12 @@ static inline bool group_is_focused(session_t *ps, xcb_window_t leader) {
|
||||||
if (!leader)
|
if (!leader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (win *w = ps->list; w; w = w->next) {
|
HASH_ITER2(ps->windows, w) {
|
||||||
if (win_get_leader(ps, w) == leader && w->state != WSTATE_DESTROYING &&
|
assert(w->state != WSTATE_DESTROYING);
|
||||||
win_is_focused_real(ps, w))
|
if (win_get_leader(ps, w) == leader && win_is_focused_real(ps, w)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1022,15 +1027,16 @@ void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev) {
|
||||||
// Find window insertion point
|
// Find window insertion point
|
||||||
win **p = NULL;
|
win **p = NULL;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
for (p = &ps->list; *p; p = &(*p)->next) {
|
for (p = &ps->window_stack; *p; p = &(*p)->next) {
|
||||||
if ((*p)->id == prev && (*p)->state != WSTATE_DESTROYING)
|
if ((*p)->id == prev && (*p)->state != WSTATE_DESTROYING)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p = &ps->list;
|
p = &ps->window_stack;
|
||||||
}
|
}
|
||||||
new->next = *p;
|
new->next = *p;
|
||||||
*p = new;
|
*p = new;
|
||||||
|
HASH_ADD_INT(ps->windows, id, new);
|
||||||
|
|
||||||
#ifdef CONFIG_DBUS
|
#ifdef CONFIG_DBUS
|
||||||
// Send D-Bus signal
|
// Send D-Bus signal
|
||||||
|
@ -1414,7 +1420,7 @@ void win_update_frame_extents(session_t *ps, win *w, xcb_window_t client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool win_is_region_ignore_valid(session_t *ps, const win *w) {
|
bool win_is_region_ignore_valid(session_t *ps, const win *w) {
|
||||||
for (win *i = ps->list; w; w = w->next) {
|
WIN_STACK_ITER(ps, i) {
|
||||||
if (i == w)
|
if (i == w)
|
||||||
break;
|
break;
|
||||||
if (!i->reg_ignore_valid)
|
if (!i->reg_ignore_valid)
|
||||||
|
@ -1481,7 +1487,7 @@ static void finish_destroy_win(session_t *ps, win **_w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
log_trace("Trying to destroy (%#010x)", w->id);
|
log_trace("Trying to destroy (%#010x)", w->id);
|
||||||
for (prev = &ps->list; *prev; prev = &(*prev)->next) {
|
for (prev = &ps->window_stack; *prev; prev = &(*prev)->next) {
|
||||||
if (w == *prev) {
|
if (w == *prev) {
|
||||||
log_trace("Found (%#010x \"%s\")", w->id, w->name);
|
log_trace("Found (%#010x \"%s\")", w->id, w->name);
|
||||||
*prev = w->next;
|
*prev = w->next;
|
||||||
|
@ -1495,7 +1501,7 @@ static void finish_destroy_win(session_t *ps, win **_w) {
|
||||||
// Drop w from all prev_trans to avoid accessing freed memory in
|
// Drop w from all prev_trans to avoid accessing freed memory in
|
||||||
// repair_win()
|
// repair_win()
|
||||||
// TODO there can only be one prev_trans pointing to w
|
// TODO there can only be one prev_trans pointing to w
|
||||||
for (win *w2 = ps->list; w2; w2 = w2->next) {
|
for (win *w2 = ps->window_stack; w2; w2 = w2->next) {
|
||||||
if (w == w2->prev_trans) {
|
if (w == w2->prev_trans) {
|
||||||
w2->prev_trans = NULL;
|
w2->prev_trans = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1545,6 +1551,15 @@ void unmap_win(session_t *ps, win **_w, bool destroy) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (destroy) {
|
||||||
|
// Delete destroyed window from the hash table, so future window with the
|
||||||
|
// same window id won't confuse us.
|
||||||
|
// Keep the window in the window stack, since we might still need to
|
||||||
|
// render it (fading out). Window will be removed from the stack when
|
||||||
|
// fading finishes.
|
||||||
|
HASH_DEL(ps->windows, w);
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(w->state == WSTATE_UNMAPPED) || w->a._class == XCB_WINDOW_CLASS_INPUT_ONLY) {
|
if (unlikely(w->state == WSTATE_UNMAPPED) || w->a._class == XCB_WINDOW_CLASS_INPUT_ONLY) {
|
||||||
if (unlikely(!destroy)) {
|
if (unlikely(!destroy)) {
|
||||||
log_warn("Unmapping an already unmapped window %#010x %s twice",
|
log_warn("Unmapping an already unmapped window %#010x %s twice",
|
||||||
|
@ -1811,3 +1826,38 @@ void map_win_by_id(session_t *ps, xcb_window_t id) {
|
||||||
|
|
||||||
map_win(ps, w);
|
map_win(ps, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a window from window id in window linked list of the session.
|
||||||
|
*/
|
||||||
|
win *find_win(session_t *ps, xcb_window_t id) {
|
||||||
|
if (!id) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
win *w = NULL;
|
||||||
|
HASH_FIND_INT(ps->windows, &id, w);
|
||||||
|
assert(w == NULL || w->state != WSTATE_DESTROYING);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find out the WM frame of a client window using existing data.
|
||||||
|
*
|
||||||
|
* @param id window ID
|
||||||
|
* @return struct win object of the found window, NULL if not found
|
||||||
|
*/
|
||||||
|
win *find_toplevel(session_t *ps, xcb_window_t id) {
|
||||||
|
if (!id) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HASH_ITER2(ps->windows, w) {
|
||||||
|
assert(w->state != WSTATE_DESTROYING);
|
||||||
|
if (w->client_win == id) {
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
10
src/win.h
10
src/win.h
|
@ -7,20 +7,25 @@
|
||||||
#include <xcb/render.h>
|
#include <xcb/render.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
#include "uthash_extra.h"
|
||||||
|
|
||||||
// FIXME shouldn't need this
|
// FIXME shouldn't need this
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "backend/backend.h"
|
||||||
#include "c2.h"
|
#include "c2.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "backend/backend.h"
|
|
||||||
#include "x.h"
|
#include "x.h"
|
||||||
|
|
||||||
|
#define WIN_STACK_ITER(ps, w) \
|
||||||
|
for (win *w = ps->window_stack, *next; w ? (next = w->next, true) : false; w = next)
|
||||||
|
|
||||||
typedef struct session session_t;
|
typedef struct session session_t;
|
||||||
typedef struct _glx_texture glx_texture_t;
|
typedef struct _glx_texture glx_texture_t;
|
||||||
|
|
||||||
|
@ -285,6 +290,7 @@ struct win {
|
||||||
/// Textures and FBO background blur use.
|
/// Textures and FBO background blur use.
|
||||||
glx_blur_cache_t glx_blur_cache;
|
glx_blur_cache_t glx_blur_cache;
|
||||||
#endif
|
#endif
|
||||||
|
UT_hash_handle hh;
|
||||||
};
|
};
|
||||||
|
|
||||||
void win_release_image(backend_t *base, win *w);
|
void win_release_image(backend_t *base, win *w);
|
||||||
|
@ -392,6 +398,8 @@ void win_ev_stop(session_t *ps, const win *w);
|
||||||
/// Skip the current in progress fading of window,
|
/// Skip the current in progress fading of window,
|
||||||
/// transition the window straight to its end state
|
/// transition the window straight to its end state
|
||||||
void win_skip_fading(session_t *ps, win **_w);
|
void win_skip_fading(session_t *ps, win **_w);
|
||||||
|
win *find_win(session_t *ps, xcb_window_t id);
|
||||||
|
win *find_toplevel(session_t *ps, xcb_window_t id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the leader of a window.
|
* Get the leader of a window.
|
||||||
|
|
Loading…
Reference in New Issue