mirror of
https://github.com/yshui/picom.git
synced 2025-04-07 17:44:04 -04:00
inspect: merge inspect into picom
I realized it's probably not a good idea to have a different code path handling window creation etc. just for picom-inspect. I found a not-so-hacky way of doing picom-inspect inside the compositor, also helps with code reuse. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
9918c89364
commit
6ae1e7e7dd
7 changed files with 49 additions and 183 deletions
9
src/c2.c
9
src/c2.c
|
@ -1801,7 +1801,7 @@ c2_match_once_leaf_string(struct atom *atoms, const struct win *w, const c2_l_t
|
|||
* For internal use.
|
||||
*/
|
||||
static inline bool
|
||||
c2_match_once_leaf(struct c2_state *state, const struct win *w, const c2_l_t *leaf) {
|
||||
c2_match_once_leaf(const struct c2_state *state, const struct win *w, const c2_l_t *leaf) {
|
||||
assert(leaf);
|
||||
|
||||
const xcb_window_t wid =
|
||||
|
@ -1845,7 +1845,8 @@ c2_match_once_leaf(struct c2_state *state, const struct win *w, const c2_l_t *le
|
|||
*
|
||||
* @return true if matched, false otherwise.
|
||||
*/
|
||||
static bool c2_match_once(struct c2_state *state, const struct win *w, const c2_ptr_t cond) {
|
||||
static bool
|
||||
c2_match_once(const struct c2_state *state, const struct win *w, const c2_ptr_t cond) {
|
||||
bool result = false;
|
||||
|
||||
if (cond.isbranch) {
|
||||
|
@ -1931,8 +1932,8 @@ bool c2_match(struct c2_state *state, const struct win *w, const c2_lptr_t *cond
|
|||
}
|
||||
|
||||
/// Match a window against the first condition in a condition linked list.
|
||||
bool c2_match_one(struct c2_state *state, const struct win *w, const c2_lptr_t *condlst,
|
||||
void **pdata) {
|
||||
bool c2_match_one(const struct c2_state *state, const struct win *w,
|
||||
const c2_lptr_t *condlst, void **pdata) {
|
||||
if (!condlst) {
|
||||
return false;
|
||||
}
|
||||
|
|
4
src/c2.h
4
src/c2.h
|
@ -52,8 +52,8 @@ void c2_window_state_update(struct c2_state *state, struct c2_window_state *wind
|
|||
|
||||
bool c2_match(struct c2_state *state, const struct win *w, const c2_lptr_t *condlst,
|
||||
void **pdata);
|
||||
bool c2_match_one(struct c2_state *state, const struct win *w, const c2_lptr_t *condlst,
|
||||
void **pdata);
|
||||
bool c2_match_one(const struct c2_state *state, const struct win *w,
|
||||
const c2_lptr_t *condlst, void **pdata);
|
||||
|
||||
bool c2_list_postprocess(struct c2_state *state, xcb_connection_t *c, c2_lptr_t *list);
|
||||
typedef bool (*c2_list_foreach_cb_t)(const c2_lptr_t *cond, void *data);
|
||||
|
|
|
@ -241,6 +241,7 @@ typedef struct options {
|
|||
bool print_diagnostics;
|
||||
/// Render to a separate window instead of taking over the screen
|
||||
bool debug_mode;
|
||||
xcb_window_t inspect_win;
|
||||
// === General ===
|
||||
/// Use the legacy backends?
|
||||
bool use_legacy_backends;
|
||||
|
|
188
src/inspect.c
188
src/inspect.c
|
@ -11,92 +11,15 @@
|
|||
|
||||
#include "inspect.h"
|
||||
|
||||
#include "atom.h"
|
||||
#include "backend/backend.h"
|
||||
#include "c2.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "options.h"
|
||||
#include "utils/misc.h"
|
||||
#include "wm/defs.h"
|
||||
#include "wm/win.h"
|
||||
#include "x.h"
|
||||
|
||||
static struct win *
|
||||
setup_window(struct x_connection *c, struct atom *atoms, struct options *options,
|
||||
struct wm *wm, struct c2_state *state, xcb_window_t target) {
|
||||
// Pretend we are the compositor, and build up the window state
|
||||
auto cursor = wm_find(wm, target);
|
||||
if (cursor == NULL) {
|
||||
log_fatal("Could not find window %#010x", target);
|
||||
wm_free(wm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
auto toplevel = wm_ref_toplevel_of(wm, cursor);
|
||||
BUG_ON_NULL(toplevel);
|
||||
struct win *w = ccalloc(1, struct win);
|
||||
w->state = WSTATE_MAPPED;
|
||||
w->tree_ref = toplevel;
|
||||
log_debug("Toplevel is %#010x", wm_ref_win_id(toplevel));
|
||||
log_debug("Client is %#010x", win_client_id(w, true));
|
||||
win_update_wintype(c, atoms, w);
|
||||
win_update_frame_extents(c, atoms, w, win_client_id(w, /*fallback_to_self=*/true),
|
||||
options->frame_opacity);
|
||||
// TODO(yshui) get leader
|
||||
win_update_name(c, atoms, w);
|
||||
win_update_class(c, atoms, w);
|
||||
win_update_role(c, atoms, w);
|
||||
|
||||
auto geometry_reply = XCB_AWAIT(xcb_get_geometry, c->c, win_id(w));
|
||||
w->g = (struct win_geometry){
|
||||
.x = geometry_reply->x,
|
||||
.y = geometry_reply->y,
|
||||
.width = geometry_reply->width,
|
||||
.height = geometry_reply->height,
|
||||
};
|
||||
free(geometry_reply);
|
||||
|
||||
auto shape_info = xcb_get_extension_data(c->c, &xcb_shape_id);
|
||||
win_on_win_size_change(w, options->shadow_offset_x, options->shadow_offset_y,
|
||||
options->shadow_radius);
|
||||
win_update_bounding_shape(c, w, shape_info->present, options->detect_rounded_corners);
|
||||
win_update_prop_fullscreen(c, atoms, w);
|
||||
|
||||
// Determine if the window is focused
|
||||
xcb_window_t wid = XCB_NONE;
|
||||
bool exists;
|
||||
if (options->use_ewmh_active_win) {
|
||||
wid_get_prop_window(c, c->screen_info->root, atoms->a_NET_ACTIVE_WINDOW,
|
||||
&exists);
|
||||
} else {
|
||||
// Determine the currently focused window so we can apply appropriate
|
||||
// opacity on it
|
||||
xcb_get_input_focus_reply_t *reply =
|
||||
xcb_get_input_focus_reply(c->c, xcb_get_input_focus(c->c), NULL);
|
||||
|
||||
if (reply) {
|
||||
wid = reply->focus;
|
||||
free(reply);
|
||||
}
|
||||
}
|
||||
if (wid == win_id(w) || wid == win_client_id(w, /*fallback_to_self=*/false)) {
|
||||
w->is_focused = true;
|
||||
}
|
||||
|
||||
auto attributes_reply = XCB_AWAIT(xcb_get_window_attributes, c->c, win_id(w));
|
||||
w->a = *attributes_reply;
|
||||
w->pictfmt = x_get_pictform_for_visual(c, w->a.visual);
|
||||
free(attributes_reply);
|
||||
|
||||
c2_window_state_init(state, &w->c2_state);
|
||||
c2_window_state_update(state, &w->c2_state, c->c,
|
||||
win_client_id(w, /*fallback_to_self=*/true), win_id(w));
|
||||
return w;
|
||||
}
|
||||
|
||||
xcb_window_t select_window(struct x_connection *c) {
|
||||
xcb_window_t inspect_select_window(struct x_connection *c) {
|
||||
xcb_font_t font = x_new_id(c);
|
||||
xcb_cursor_t cursor = x_new_id(c);
|
||||
const char font_name[] = "cursor";
|
||||
|
@ -153,12 +76,12 @@ xcb_window_t select_window(struct x_connection *c) {
|
|||
}
|
||||
|
||||
struct c2_match_state {
|
||||
struct c2_state *state;
|
||||
struct win *w;
|
||||
const struct c2_state *state;
|
||||
const struct win *w;
|
||||
bool print_value;
|
||||
};
|
||||
|
||||
bool c2_match_once_and_log(const c2_lptr_t *cond, void *data) {
|
||||
static bool c2_match_once_and_log(const c2_lptr_t *cond, void *data) {
|
||||
struct c2_match_state *state = data;
|
||||
void *rule_data = NULL;
|
||||
printf(" %s ... ", c2_lptr_to_str(cond));
|
||||
|
@ -174,98 +97,38 @@ bool c2_match_once_and_log(const c2_lptr_t *cond, void *data) {
|
|||
|
||||
#define BOLD(str) "\033[1m" str "\033[0m"
|
||||
|
||||
int inspect_main(int argc, char **argv, const char *config_file) {
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
if (!dpy) {
|
||||
log_fatal("Can't open display");
|
||||
return 1;
|
||||
}
|
||||
struct x_connection c;
|
||||
x_connection_init(&c, dpy);
|
||||
|
||||
xcb_prefetch_extension_data(c.c, &xcb_shape_id);
|
||||
|
||||
struct options options;
|
||||
if (!parse_config(&options, config_file)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Parse all of the rest command line options
|
||||
options.backend = backend_find("dummy");
|
||||
if (!get_cfg(&options, argc, argv)) {
|
||||
log_fatal("Failed to get configuration, usually mean you have specified "
|
||||
"invalid options.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto atoms = init_atoms(c.c);
|
||||
auto state = c2_state_new(atoms);
|
||||
options_postprocess_c2_lists(state, &c, &options);
|
||||
|
||||
struct wm *wm = wm_new();
|
||||
|
||||
wm_import_start(wm, &c, atoms, c.screen_info->root, NULL);
|
||||
// Process events until the window tree is consistent
|
||||
while (x_has_pending_requests(&c)) {
|
||||
auto ev = x_poll_for_event(&c);
|
||||
if (ev == NULL) {
|
||||
continue;
|
||||
}
|
||||
switch (ev->response_type) {
|
||||
case XCB_CREATE_NOTIFY:;
|
||||
auto create = (xcb_create_notify_event_t *)ev;
|
||||
auto parent = wm_find(wm, create->parent);
|
||||
wm_import_start(wm, &c, atoms,
|
||||
((xcb_create_notify_event_t *)ev)->window, parent);
|
||||
break;
|
||||
case XCB_DESTROY_NOTIFY:
|
||||
wm_destroy(wm, ((xcb_destroy_notify_event_t *)ev)->window);
|
||||
break;
|
||||
case XCB_REPARENT_NOTIFY:;
|
||||
auto reparent = (xcb_reparent_notify_event_t *)ev;
|
||||
wm_reparent(wm, reparent->window, reparent->parent);
|
||||
break;
|
||||
default:
|
||||
// Ignore ConfigureNotify and CirculateNotify, because we don't
|
||||
// use stacking order for window rules.
|
||||
break;
|
||||
}
|
||||
free(ev);
|
||||
}
|
||||
|
||||
auto target = select_window(&c);
|
||||
log_info("Target window: %#x", target);
|
||||
auto w = setup_window(&c, atoms, &options, wm, state, target);
|
||||
void inspect_dump_window(const struct c2_state *state, const struct options *opts,
|
||||
const struct win *w) {
|
||||
struct c2_match_state match_state = {
|
||||
.state = state,
|
||||
.w = w,
|
||||
};
|
||||
printf("Checking " BOLD("transparent-clipping-exclude") ":\n");
|
||||
c2_list_foreach(options.transparent_clipping_blacklist, c2_match_once_and_log,
|
||||
c2_list_foreach(opts->transparent_clipping_blacklist, c2_match_once_and_log,
|
||||
&match_state);
|
||||
printf("Checking " BOLD("shadow-exclude") ":\n");
|
||||
c2_list_foreach(options.shadow_blacklist, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->shadow_blacklist, c2_match_once_and_log, &match_state);
|
||||
printf("Checking " BOLD("fade-exclude") ":\n");
|
||||
c2_list_foreach(options.fade_blacklist, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->fade_blacklist, c2_match_once_and_log, &match_state);
|
||||
printf("Checking " BOLD("clip-shadow-above") ":\n");
|
||||
c2_list_foreach(options.shadow_clip_list, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->shadow_clip_list, c2_match_once_and_log, &match_state);
|
||||
printf("Checking " BOLD("focus-exclude") ":\n");
|
||||
c2_list_foreach(options.focus_blacklist, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->focus_blacklist, c2_match_once_and_log, &match_state);
|
||||
printf("Checking " BOLD("invert-color-include") ":\n");
|
||||
c2_list_foreach(options.invert_color_list, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->invert_color_list, c2_match_once_and_log, &match_state);
|
||||
printf("Checking " BOLD("blur-background-exclude") ":\n");
|
||||
c2_list_foreach(options.blur_background_blacklist, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->blur_background_blacklist, c2_match_once_and_log, &match_state);
|
||||
printf("Checking " BOLD("unredir-if-possible-exclude") ":\n");
|
||||
c2_list_foreach(options.unredir_if_possible_blacklist, c2_match_once_and_log,
|
||||
c2_list_foreach(opts->unredir_if_possible_blacklist, c2_match_once_and_log,
|
||||
&match_state);
|
||||
printf("Checking " BOLD("rounded-corners-exclude") ":\n");
|
||||
c2_list_foreach(options.rounded_corners_blacklist, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->rounded_corners_blacklist, c2_match_once_and_log, &match_state);
|
||||
|
||||
match_state.print_value = true;
|
||||
printf("Checking " BOLD("opacity-rule") ":\n");
|
||||
c2_list_foreach(options.opacity_rules, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->opacity_rules, c2_match_once_and_log, &match_state);
|
||||
printf("Checking " BOLD("corner-radius-rule") ":\n");
|
||||
c2_list_foreach(options.corner_radius_rules, c2_match_once_and_log, &match_state);
|
||||
c2_list_foreach(opts->corner_radius_rules, c2_match_once_and_log, &match_state);
|
||||
|
||||
printf("\nHere are some rule(s) that match this window:\n");
|
||||
if (w->name != NULL) {
|
||||
|
@ -292,21 +155,4 @@ int inspect_main(int argc, char **argv, const char *config_file) {
|
|||
printf(" bounding_shaped\n");
|
||||
}
|
||||
printf(" border_width = %d\n", w->g.border_width);
|
||||
|
||||
pixman_region32_fini(&w->bounding_shape);
|
||||
free(w->name);
|
||||
free(w->class_instance);
|
||||
free(w->class_general);
|
||||
free(w->role);
|
||||
c2_window_state_destroy(state, &w->c2_state);
|
||||
free(w);
|
||||
|
||||
wm_free(wm);
|
||||
|
||||
log_deinit_tls();
|
||||
c2_state_free(state);
|
||||
destroy_atoms(atoms);
|
||||
options_destroy(&options);
|
||||
XCloseDisplay(c.dpy);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3,5 +3,11 @@
|
|||
|
||||
#pragma once
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
struct x_connection;
|
||||
struct c2_state;
|
||||
struct options;
|
||||
struct win;
|
||||
int inspect_main(int argc, char **argv, const char *config_file);
|
||||
xcb_window_t inspect_select_window(struct x_connection *c);
|
||||
void inspect_dump_window(const struct c2_state *state, const struct options *opts,
|
||||
const struct win *w);
|
||||
|
|
14
src/picom.c
14
src/picom.c
|
@ -2193,6 +2193,15 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const char *basename = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
|
||||
|
||||
if (strcmp(basename, "picom-inspect") == 0) {
|
||||
ps->o.backend = backend_find("dummy");
|
||||
ps->o.print_diagnostics = false;
|
||||
ps->o.dbus = false;
|
||||
ps->o.inspect_win = inspect_select_window(&ps->c);
|
||||
}
|
||||
|
||||
ps->window_options_default = win_options_from_config(&ps->o);
|
||||
|
||||
if (ps->o.window_shader_fg) {
|
||||
|
@ -2734,11 +2743,6 @@ int PICOM_MAIN(int argc, char **argv) {
|
|||
return exit_code;
|
||||
}
|
||||
|
||||
char *exe_name = basename(argv[0]);
|
||||
if (strcmp(exe_name, "picom-inspect") == 0) {
|
||||
return inspect_main(argc, argv, config_file);
|
||||
}
|
||||
|
||||
int pfds[2];
|
||||
if (need_fork) {
|
||||
if (pipe2(pfds, O_CLOEXEC)) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "dbus.h"
|
||||
#include "inspect.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
|
@ -1115,6 +1116,13 @@ void win_on_factor_change(session_t *ps, struct win *w) {
|
|||
(win_client_id(w, /*fallback_to_self=*/false) == ps->debug_window))) {
|
||||
w->options.paint = TRI_FALSE;
|
||||
}
|
||||
|
||||
if ((ps->o.inspect_win != XCB_NONE && win_id(w) == ps->o.inspect_win) ||
|
||||
ps->o.inspect_monitor) {
|
||||
inspect_dump_window(ps->c2_state, &ps->o, w);
|
||||
printf("\n");
|
||||
quit(ps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue