1
0
Fork 0
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:
Yuxuan Shui 2024-08-09 03:15:46 +01:00
parent 9918c89364
commit 6ae1e7e7dd
No known key found for this signature in database
GPG key ID: D3A4405BE6CC17F4
7 changed files with 49 additions and 183 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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)) {

View file

@ -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);
}
}
/**