mirror of
https://github.com/i3/i3.git
synced 2026-02-04 18:45:24 +00:00
Fix i3bar workspace buttons for primary screen (#6564)
git bisect:c7344095ecis the first bad commit ```c7344095ec(HEAD) Fix leak sanitizer memleaks (#6520) i3bar/src/ipc.c | 5 +++-- i3bar/src/workspaces.c | 58 +++++++++++++++++++++++++++++++++------------------------- i3bar/src/xcb.c | 1 + include/libi3.h | 10 ++++------ src/config_directives.c | 1 + src/config_parser.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------ src/load_layout.c | 2 +- src/restore_layout.c | 4 ++++ 8 files changed, 96 insertions(+), 70 deletions(-) ``` To handle race conditions in the test, I tested with: ```diff diff --git a/i3bar/src/workspaces.c b/i3bar/src/workspaces.c index d712750d..0c481d18 100644 --- a/i3bar/src/workspaces.c +++ b/i3bar/src/workspaces.c @@ -286,6 +286,8 @@ void parse_workspaces_json(const unsigned char *json, const size_t size) { } } + sleep(1); + yajl_free(handle); FREE(params.cur_key); } ``` fixes https://github.com/i3/i3/issues/6560
This commit is contained in:
@ -19,6 +19,7 @@ struct workspaces_json_params {
|
||||
struct ws_head *workspaces;
|
||||
i3_ws *workspaces_walk;
|
||||
char *cur_key;
|
||||
bool need_output;
|
||||
bool parsing_rect;
|
||||
};
|
||||
|
||||
@ -160,6 +161,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, const s
|
||||
TAILQ_INSERT_TAIL(ws->output->workspaces, ws, tailq);
|
||||
}
|
||||
|
||||
params->need_output = false;
|
||||
FREE(output_name);
|
||||
FREE(params->cur_key);
|
||||
|
||||
@ -181,6 +183,7 @@ static int workspaces_start_map_cb(void *params_) {
|
||||
new_workspace->num = -1;
|
||||
|
||||
params->workspaces_walk = new_workspace;
|
||||
params->need_output = true;
|
||||
params->parsing_rect = false;
|
||||
} else {
|
||||
params->parsing_rect = true;
|
||||
@ -202,6 +205,15 @@ static int workspaces_end_map_cb(void *params_) {
|
||||
return 1; /* workspace already assigned to output */
|
||||
}
|
||||
|
||||
/* If we processed the output field but didn't find the output, the
|
||||
* workspace belongs to an output this bar instance doesn't manage. */
|
||||
if (!params->need_output) {
|
||||
I3STRING_FREE(ws->name);
|
||||
FREE(ws->canonical_name);
|
||||
FREE(params->workspaces_walk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ws->name || SLIST_EMPTY(outputs)) { /* Invalid state */
|
||||
I3STRING_FREE(ws->name);
|
||||
FREE(ws->canonical_name);
|
||||
@ -209,7 +221,7 @@ static int workspaces_end_map_cb(void *params_) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle no output case */
|
||||
/* Handle no output case - fallback to primary */
|
||||
ws->output = get_output_by_name("primary");
|
||||
if (ws->output == NULL) {
|
||||
ws->output = SLIST_FIRST(outputs);
|
||||
|
||||
1
release-notes/bugfixes/2-i3bar-primary-workspace-button
Normal file
1
release-notes/bugfixes/2-i3bar-primary-workspace-button
Normal file
@ -0,0 +1 @@
|
||||
fix i3bar workspace buttons showing up in primary screen
|
||||
147
testcases/t/555-i3bar-workspace-output-assignment.t
Normal file
147
testcases/t/555-i3bar-workspace-output-assignment.t
Normal file
@ -0,0 +1,147 @@
|
||||
#!perl
|
||||
# vim:ts=4:sw=4:expandtab
|
||||
#
|
||||
# Please read the following documents before working on tests:
|
||||
# • https://build.i3wm.org/docs/testsuite.html
|
||||
# (or docs/testsuite)
|
||||
#
|
||||
# • https://build.i3wm.org/docs/lib-i3test.html
|
||||
# (alternatively: perldoc ./testcases/lib/i3test.pm)
|
||||
#
|
||||
# • https://build.i3wm.org/docs/ipc.html
|
||||
# (or docs/ipc)
|
||||
#
|
||||
# • https://i3wm.org/downloads/modern_perl_a4.pdf
|
||||
# (unless you are already familiar with Perl)
|
||||
#
|
||||
# Verify that i3bar only shows correct workspace buttons in each output.
|
||||
# Ticket: #6560
|
||||
# Bug still in: 4.25-6-g0e2e8290
|
||||
use File::Temp qw(tempdir);
|
||||
use i3test i3_autostart => 0;
|
||||
use i3test::Util qw(slurp);
|
||||
use i3test::XTEST;
|
||||
use POSIX qw(mkfifo);
|
||||
|
||||
################################################################################
|
||||
# Test that a bar configured for primary output only shows workspaces from that
|
||||
# output, not from other outputs.
|
||||
################################################################################
|
||||
|
||||
# Create temp files for i3bar PID and exit signaling
|
||||
my $tmpdir = tempdir(CLEANUP => 1);
|
||||
my $pidfile = "$tmpdir/i3bar.pid";
|
||||
my $exitfifo = "$tmpdir/fifo";
|
||||
my $logfile = "$tmpdir/i3bar.log";
|
||||
mkfifo("$exitfifo", 0600) or BAIL_OUT "Could not create FIFO: $!";
|
||||
|
||||
# Create a wrapper script that tracks i3bar's PID and signals when it exits
|
||||
my $scriptfile = "$tmpdir/i3bar-wrapper.sh";
|
||||
open(my $scriptfh, '>', $scriptfile) or BAIL_OUT "Cannot create wrapper: $!";
|
||||
print $scriptfh <<"EOF";
|
||||
#!/bin/sh
|
||||
echo "---- DEBUG: i3bar wrapper ----"
|
||||
cat "$scriptfile"
|
||||
echo '---- DEBUG: i3bar wrapper ----'
|
||||
# Use tee so that the logs also end up in the testsuite log file.
|
||||
(i3bar -V "\$@" 2>&1 | tee "$logfile") &
|
||||
echo \$! > "$pidfile"
|
||||
wait
|
||||
echo done > "$exitfifo"
|
||||
EOF
|
||||
close($scriptfh);
|
||||
chmod 0755, $scriptfile;
|
||||
|
||||
my $config = <<"EOT";
|
||||
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||
|
||||
fake-outputs 1024x768+0+0P,1024x768+1024+0
|
||||
workspace 1 output fake-1 # primary
|
||||
workspace 2 output fake-0 # nonprimary
|
||||
|
||||
bar {
|
||||
i3bar_command $scriptfile
|
||||
output primary
|
||||
}
|
||||
EOT
|
||||
|
||||
my $pid = launch_with_config($config);
|
||||
|
||||
my $i3 = i3(get_socket_path());
|
||||
$i3->connect()->recv;
|
||||
my $cv = AnyEvent->condvar;
|
||||
my $timer = AnyEvent->timer(after => 1, interval => 0, cb => sub { $cv->send(0) });
|
||||
$i3->subscribe({
|
||||
window => sub {
|
||||
my ($event) = @_;
|
||||
if ($event->{change} eq 'new') {
|
||||
if (defined($event->{container}->{window_properties}->{class}) &&
|
||||
$event->{container}->{window_properties}->{class} eq 'i3bar') {
|
||||
$cv->send($event->{container});
|
||||
}
|
||||
}
|
||||
},
|
||||
})->recv;
|
||||
|
||||
sub i3bar_present {
|
||||
my ($nodes) = @_;
|
||||
|
||||
for my $node (@{$nodes}) {
|
||||
my $props = $node->{window_properties};
|
||||
if (defined($props) && $props->{class} eq 'i3bar') {
|
||||
return $node->{window};
|
||||
}
|
||||
}
|
||||
|
||||
return 0 if !@{$nodes};
|
||||
|
||||
my @children = (map { @{$_->{nodes}} } @{$nodes},
|
||||
map { @{$_->{'floating_nodes'}} } @{$nodes});
|
||||
|
||||
return i3bar_present(\@children);
|
||||
}
|
||||
|
||||
my $i3bar_window = i3bar_present($i3->get_tree->recv->{nodes});
|
||||
if ($i3bar_window) {
|
||||
ok(1, 'i3bar present');
|
||||
} else {
|
||||
my $con = $cv->recv;
|
||||
ok($con, 'i3bar appeared');
|
||||
$i3bar_window = $con->{window};
|
||||
}
|
||||
|
||||
diag('i3bar window = ' . $i3bar_window);
|
||||
xtest_sync_with_i3;
|
||||
xtest_sync_with($i3bar_window);
|
||||
|
||||
# The actual test
|
||||
cmd 'workspace 1';
|
||||
my $win1 = open_window;
|
||||
cmd 'workspace 2';
|
||||
my $win2 = open_window;
|
||||
|
||||
# Kill i3bar gracefully BEFORE exiting i3 to ensure buffers are flushed
|
||||
# (if i3 exits first, i3bar gets SIGPIPE and buffers are lost)
|
||||
open(my $pidfh, '<', $pidfile) or BAIL_OUT "Cannot read i3bar PID: $!";
|
||||
my $bar_pid = <$pidfh>;
|
||||
close($pidfh);
|
||||
chomp($bar_pid);
|
||||
kill('TERM', $bar_pid);
|
||||
|
||||
# Wait for i3bar to exit by reading from the FIFO (blocks until wrapper writes)
|
||||
open(my $fifofh, '<', $exitfifo) or BAIL_OUT "Cannot open FIFO: $!";
|
||||
my $result = <$fifofh>;
|
||||
close($fifofh);
|
||||
ok(defined($result), 'i3bar ended');
|
||||
|
||||
exit_gracefully($pid);
|
||||
|
||||
my $log = slurp($logfile);
|
||||
|
||||
my @ws2_draws = ($log =~ /Drawing button for WS 2 at/g);
|
||||
ok(scalar(@ws2_draws) > 0, "Workspace 2 (on primary) is drawn in the bar");
|
||||
|
||||
my @ws1_draws = ($log =~ /Drawing button for WS 1 at/g);
|
||||
is(scalar(@ws1_draws), 0, "Workspace 1 (on non-primary) should NOT be drawn on primary bar");
|
||||
|
||||
done_testing;
|
||||
Reference in New Issue
Block a user