Merge branch 'next' into master
This commit is contained in:
commit
1847938d4e
|
@ -1,18 +1,68 @@
|
||||||
Output of `i3 --moreversion 2>&- || i3 --version`:
|
<!--
|
||||||
|
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
|
||||||
|
-->
|
||||||
|
|
||||||
_REPLACE: i3 version output_
|
## I'm submitting a…
|
||||||
|
<!-- Please check one of the following options with "x" -->
|
||||||
|
<pre>
|
||||||
|
[ ] Bug
|
||||||
|
[ ] Feature Request
|
||||||
|
[ ] Documentation Request
|
||||||
|
[ ] Other (Please describe in detail)
|
||||||
|
</pre>
|
||||||
|
|
||||||
URL to a logfile as per https://i3wm.org/docs/debugging.html:
|
## Current Behavior
|
||||||
|
<!--
|
||||||
|
Describe the current behavior,
|
||||||
|
e.g., »When pressing Alt+j (focus left), the window above the current window is focused.«
|
||||||
|
-->
|
||||||
|
|
||||||
_REPLACE: URL to logfile_
|
## Expected Behavior
|
||||||
|
<!--
|
||||||
|
Describe the desired behavior you expect after mitigation of the issue,
|
||||||
|
e.g., »The window left next to the current window should be focused.«
|
||||||
|
-->
|
||||||
|
|
||||||
**What I did:**
|
## Reproduction Instructions
|
||||||
|
<!--
|
||||||
|
For bug reports, please provide detailed instructions on how the bug can be reproduced.
|
||||||
|
For feature requests you can remove this section.
|
||||||
|
|
||||||
_REPLACE: e.g. "I’m pressing Alt+j (focus left)"_
|
E.g., »Open three windows in a V[A H[B C]] layout on a new workspace«
|
||||||
|
-->
|
||||||
|
|
||||||
**What I saw:**
|
## Environment
|
||||||
|
<!--
|
||||||
|
Please include your exact i3 version.
|
||||||
|
Note that we only support the latest major release and the current development version. If you are using an older version of i3, please first update to the current release version and reproduce the issue there.
|
||||||
|
-->
|
||||||
|
Output of `i3 --moreversion 2>&-`:
|
||||||
|
<pre>
|
||||||
|
i3 version:
|
||||||
|
</pre>
|
||||||
|
|
||||||
_REPLACE: e.g. "i3 changed focus to the window ABOVE the current window"_
|
<!--
|
||||||
|
For bug reports, please include your (complete) i3 config with which the issue occurs. You can either paste the file directly or provide a link to a service such as pastebin.
|
||||||
|
|
||||||
**What I expected instead:**
|
If you would like to help debugging the issue, please try to reduce the config such that it is as close to the default config as possible while still reproducing the issue. This can help us bisect the root cause.
|
||||||
_REPLACE: e.g. "Focus should be on the window to the left"_
|
-->
|
||||||
|
<pre>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Providing a logfile can help us trace the root cause of an issue much quicker. You can learn how to generate the logfile here:
|
||||||
|
https://i3wm.org/docs/debugging.html
|
||||||
|
|
||||||
|
Providing the logfile is optional.
|
||||||
|
-->
|
||||||
|
<pre>
|
||||||
|
Logfile URL:
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please also answer the questions below to help us process your issue faster. If you have any other information to share, please add it here as well.
|
||||||
|
-->
|
||||||
|
<pre>
|
||||||
|
- Linux Distribution & Version:
|
||||||
|
- Are you using a compositor (e.g., xcompmgr or compton):
|
||||||
|
</pre>
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## I'm submitting a…
|
||||||
|
<!-- Please check one of the following options with "x" -->
|
||||||
|
<pre>
|
||||||
|
[x] Bug
|
||||||
|
[ ] Feature Request
|
||||||
|
[ ] Documentation Request
|
||||||
|
[ ] Other (Please describe in detail)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
## Current Behavior
|
||||||
|
<!--
|
||||||
|
Describe the current behavior,
|
||||||
|
e.g., »When pressing Alt+j (focus left), the window above the current window is focused.«
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
<!--
|
||||||
|
Describe the desired behavior you expect after mitigation of the issue,
|
||||||
|
e.g., »The window left next to the current window should be focused.«
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Reproduction Instructions
|
||||||
|
<!--
|
||||||
|
Please provide detailed instructions on how the bug can be reproduced.
|
||||||
|
E.g., »Open three windows in a V[A H[B C]] layout on a new workspace«
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
<!--
|
||||||
|
Please include your exact i3 version.
|
||||||
|
Note that we only support the latest major release and the current development version. If you are using an older version of i3, please first update to the current release version and reproduce the issue there.
|
||||||
|
-->
|
||||||
|
Output of `i3 --moreversion 2>&-`:
|
||||||
|
<pre>
|
||||||
|
i3 version:
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please include your (complete) i3 config with which the issue occurs. You can either paste the file directly or provide a link to a service such as pastebin.
|
||||||
|
|
||||||
|
If you would like to help debugging the issue, please try to reduce the config such that it is as close to the default config as possible while still reproducing the issue. This can help us bisect the root cause.
|
||||||
|
-->
|
||||||
|
<pre>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Providing a logfile can help us trace the root cause of an issue much quicker. You can learn how to generate the logfile here:
|
||||||
|
https://i3wm.org/docs/debugging.html
|
||||||
|
|
||||||
|
Providing the logfile is optional.
|
||||||
|
-->
|
||||||
|
<pre>
|
||||||
|
Logfile URL:
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please also answer the questions below to help us process your issue faster. If you have any other information to share, please add it here as well.
|
||||||
|
-->
|
||||||
|
<pre>
|
||||||
|
- Linux Distribution & Version:
|
||||||
|
- Are you using a compositor (e.g., xcompmgr or compton):
|
||||||
|
</pre>
|
|
@ -0,0 +1,47 @@
|
||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## I'm submitting a…
|
||||||
|
<!-- Please check one of the following options with "x" -->
|
||||||
|
<pre>
|
||||||
|
[ ] Bug
|
||||||
|
[x] Feature Request
|
||||||
|
[ ] Documentation Request
|
||||||
|
[ ] Other (Please describe in detail)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
## Current Behavior
|
||||||
|
<!--
|
||||||
|
Describe the current behavior,
|
||||||
|
e.g., »When pressing Alt+j (focus left), the window above the current window is focused.«
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Desired Behavior
|
||||||
|
<!--
|
||||||
|
Describe the desired behavior you expect after mitigation of the issue,
|
||||||
|
e.g., »The window left next to the current window should be focused.«
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
<!--
|
||||||
|
Please include your exact i3 version.
|
||||||
|
Note that we only support the latest major release and the current development version. If you are using an older version of i3, please first update to the current release version and reproduce the issue there.
|
||||||
|
-->
|
||||||
|
Output of `i3 --moreversion 2>&-`:
|
||||||
|
<pre>
|
||||||
|
i3 version:
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please also answer the questions below to help us process your issue faster. If you have any other information to share, please add it here as well.
|
||||||
|
-->
|
||||||
|
<pre>
|
||||||
|
- Linux Distribution & Version:
|
||||||
|
- Are you using a compositor (e.g., xcompmgr or compton):
|
||||||
|
</pre>
|
|
@ -35,7 +35,7 @@ install:
|
||||||
script:
|
script:
|
||||||
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-safe-wrappers.sh
|
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-safe-wrappers.sh
|
||||||
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-formatting.sh
|
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-formatting.sh
|
||||||
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 -e CC ${BASENAME} /bin/sh -c 'autoreconf -fi && mkdir -p build && cd build && (../configure || (cat config.log; false)) && make -j CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror"'
|
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 -e CC ${BASENAME} /bin/sh -c 'autoreconf -fi && mkdir -p build && cd build && (../configure || (cat config.log; false)) && make -j CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Wstrict-prototypes -Wmissing-prototypes -Werror"'
|
||||||
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-spelling.pl
|
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/check-spelling.pl
|
||||||
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 -e CC ${BASENAME} ./travis/run-tests.sh
|
- docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 -e CC ${BASENAME} ./travis/run-tests.sh
|
||||||
- ./travis/skip-pkg.sh || docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/debian-build.sh deb/debian-amd64/DIST
|
- ./travis/skip-pkg.sh || docker run -v $PWD:/usr/src/i3/ -w /usr/src/i3 ${BASENAME} ./travis/debian-build.sh deb/debian-amd64/DIST
|
||||||
|
|
|
@ -100,11 +100,12 @@ use constant TYPE_GET_VERSION => 7;
|
||||||
use constant TYPE_GET_BINDING_MODES => 8;
|
use constant TYPE_GET_BINDING_MODES => 8;
|
||||||
use constant TYPE_GET_CONFIG => 9;
|
use constant TYPE_GET_CONFIG => 9;
|
||||||
use constant TYPE_SEND_TICK => 10;
|
use constant TYPE_SEND_TICK => 10;
|
||||||
|
use constant TYPE_SYNC => 11;
|
||||||
|
|
||||||
our %EXPORT_TAGS = ( 'all' => [
|
our %EXPORT_TAGS = ( 'all' => [
|
||||||
qw(i3 TYPE_RUN_COMMAND TYPE_COMMAND TYPE_GET_WORKSPACES TYPE_SUBSCRIBE TYPE_GET_OUTPUTS
|
qw(i3 TYPE_RUN_COMMAND TYPE_COMMAND TYPE_GET_WORKSPACES TYPE_SUBSCRIBE TYPE_GET_OUTPUTS
|
||||||
TYPE_GET_TREE TYPE_GET_MARKS TYPE_GET_BAR_CONFIG TYPE_GET_VERSION
|
TYPE_GET_TREE TYPE_GET_MARKS TYPE_GET_BAR_CONFIG TYPE_GET_VERSION
|
||||||
TYPE_GET_BINDING_MODES TYPE_GET_CONFIG TYPE_SEND_TICK)
|
TYPE_GET_BINDING_MODES TYPE_GET_CONFIG TYPE_SEND_TICK TYPE_SYNC)
|
||||||
] );
|
] );
|
||||||
|
|
||||||
our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } );
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } );
|
||||||
|
@ -534,6 +535,19 @@ sub send_tick {
|
||||||
$self->message(TYPE_SEND_TICK, $payload);
|
$self->message(TYPE_SEND_TICK, $payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=head2 sync
|
||||||
|
|
||||||
|
Sends an i3 sync event. Requires i3 >= 4.16
|
||||||
|
|
||||||
|
=cut
|
||||||
|
sub sync {
|
||||||
|
my ($self, $payload) = @_;
|
||||||
|
|
||||||
|
$self->_ensure_connection;
|
||||||
|
|
||||||
|
$self->message(TYPE_SYNC, $payload);
|
||||||
|
}
|
||||||
|
|
||||||
=head2 command($content)
|
=head2 command($content)
|
||||||
|
|
||||||
Makes i3 execute the given command
|
Makes i3 execute the given command
|
||||||
|
|
46
DEPENDS
46
DEPENDS
|
@ -4,29 +4,29 @@
|
||||||
"min" means minimum required version
|
"min" means minimum required version
|
||||||
"lkgv" means last known good version
|
"lkgv" means last known good version
|
||||||
|
|
||||||
┌──────────────┬────────┬────────┬───────────────────────────────────────────────────────────┐
|
┌──────────────┬────────┬────────┬─────────────────────────────────────────────────────────────┐
|
||||||
│ dependency │ min. │ lkgv │ URL │
|
│ dependency │ min. │ lkgv │ URL │
|
||||||
├──────────────┼────────┼────────┼───────────────────────────────────────────────────────────┤
|
├──────────────┼────────┼────────┼─────────────────────────────────────────────────────────────┤
|
||||||
│ pkg-config │ 0.25 │ 0.29 │ https://pkgconfig.freedesktop.org/ │
|
│ pkg-config │ 0.25 │ 0.29 │ https://pkgconfig.freedesktop.org/ │
|
||||||
│ libxcb │ 1.1.93 │ 1.12 │ https://xcb.freedesktop.org/dist/ │
|
│ libxcb │ 1.1.93 │ 1.12 │ https://xcb.freedesktop.org/dist/ │
|
||||||
│ xcb-util │ 0.3.3 │ 0.4.1 │ https://xcb.freedesktop.org/dist/ │
|
│ xcb-util │ 0.3.3 │ 0.4.1 │ https://xcb.freedesktop.org/dist/ │
|
||||||
│ xkbcommon │ 0.4.0 │ 0.6.1 │ https://xkbcommon.org/ │
|
│ xkbcommon │ 0.4.0 │ 0.6.1 │ https://xkbcommon.org/ │
|
||||||
│ xkbcommon-x11│ 0.4.0 │ 0.6.1 │ https://xkbcommon.org/ │
|
│ xkbcommon-x11│ 0.4.0 │ 0.6.1 │ https://xkbcommon.org/ │
|
||||||
│ util-cursor³⁴│ 0.0.99 │ 0.1.3 │ https://xcb.freedesktop.org/dist/ │
|
│ util-cursor³⁴│ 0.0.99 │ 0.1.3 │ https://xcb.freedesktop.org/dist/ │
|
||||||
│ util-wm⁴ │ 0.3.8 │ 0.3.8 │ https://xcb.freedesktop.org/dist/ │
|
│ util-wm⁴ │ 0.3.8 │ 0.3.8 │ https://xcb.freedesktop.org/dist/ │
|
||||||
│ util-keysyms⁴│ 0.3.8 │ 0.4.0 │ https://xcb.freedesktop.org/dist/ │
|
│ util-keysyms⁴│ 0.3.8 │ 0.4.0 │ https://xcb.freedesktop.org/dist/ │
|
||||||
│ util-xrm⁴ │ 1.0.0 │ 1.0.0 │ https://github.com/Airblader/xcb-util-xrm │
|
│ util-xrm⁴ │ 1.0.0 │ 1.0.0 │ https://github.com/Airblader/xcb-util-xrm/ │
|
||||||
│ libev │ 4.0 │ 4.19 │ http://libev.schmorp.de/ │
|
│ libev │ 4.0 │ 4.19 │ http://libev.schmorp.de/ │
|
||||||
│ yajl │ 2.0.1 │ 2.1.0 │ https://lloyd.github.com/yajl/ │
|
│ yajl │ 2.0.1 │ 2.1.0 │ https://lloyd.github.com/yajl/ │
|
||||||
│ asciidoc │ 8.3.0 │ 8.6.9 │ http://www.methods.co.nz/asciidoc/ │
|
│ asciidoc │ 8.3.0 │ 8.6.9 │ http://www.methods.co.nz/asciidoc/ │
|
||||||
│ xmlto │ 0.0.23 │ 0.0.23 │ http://www.methods.co.nz/asciidoc/ │
|
│ xmlto │ 0.0.23 │ 0.0.23 │ http://www.methods.co.nz/asciidoc/ │
|
||||||
│ Pod::Simple² │ 3.22 │ 3.22 │ http://search.cpan.org/~dwheeler/Pod-Simple-3.23/ │
|
│ Pod::Simple² │ 3.22 │ 3.22 │ http://search.cpan.org/dist/Pod-Simple/ │
|
||||||
│ docbook-xml │ 4.5 │ 4.5 │ http://www.methods.co.nz/asciidoc/ │
|
│ docbook-xml │ 4.5 │ 4.5 │ http://www.methods.co.nz/asciidoc/ │
|
||||||
│ PCRE │ 8.12 │ 8.38 │ https://www.pcre.org/ │
|
│ PCRE │ 8.12 │ 8.38 │ https://www.pcre.org/ │
|
||||||
│ libsn¹ │ 0.10 │ 0.12 │ https://freedesktop.org/wiki/Software/startup-notification │
|
│ libsn¹ │ 0.10 │ 0.12 │ https://freedesktop.org/wiki/Software/startup-notification/ │
|
||||||
│ pango │ 1.30.0 | 1.40.1 │ http://www.pango.org/ │
|
│ pango │ 1.30.0 │ 1.40.1 │ http://www.pango.org/ │
|
||||||
│ cairo │ 1.14.4 │ 1.14.6 │ https://cairographics.org/ │
|
│ cairo │ 1.14.4 │ 1.14.6 │ https://cairographics.org/ │
|
||||||
└──────────────┴────────┴────────┴───────────────────────────────────────────────────────────┘
|
└──────────────┴────────┴────────┴─────────────────────────────────────────────────────────────┘
|
||||||
¹ libsn = libstartup-notification
|
¹ libsn = libstartup-notification
|
||||||
² Pod::Simple is a Perl module required for converting the testsuite
|
² Pod::Simple is a Perl module required for converting the testsuite
|
||||||
documentation to HTML. See https://michael.stapelberg.de/cpan/#Pod::Simple
|
documentation to HTML. See https://michael.stapelberg.de/cpan/#Pod::Simple
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
4.15-non-git
|
4.16-non-git
|
||||||
|
|
|
@ -118,7 +118,7 @@ EXTRA_DIST = \
|
||||||
I3_VERSION \
|
I3_VERSION \
|
||||||
LICENSE \
|
LICENSE \
|
||||||
PACKAGE-MAINTAINER \
|
PACKAGE-MAINTAINER \
|
||||||
RELEASE-NOTES-4.15 \
|
RELEASE-NOTES-4.16 \
|
||||||
generate-command-parser.pl \
|
generate-command-parser.pl \
|
||||||
parser-specs/commands.spec \
|
parser-specs/commands.spec \
|
||||||
parser-specs/config.spec \
|
parser-specs/config.spec \
|
||||||
|
@ -301,6 +301,7 @@ libi3_a_SOURCES = \
|
||||||
libi3/fake_configure_notify.c \
|
libi3/fake_configure_notify.c \
|
||||||
libi3/font.c \
|
libi3/font.c \
|
||||||
libi3/format_placeholders.c \
|
libi3/format_placeholders.c \
|
||||||
|
libi3/g_utf8_make_valid.c \
|
||||||
libi3/get_colorpixel.c \
|
libi3/get_colorpixel.c \
|
||||||
libi3/get_config_path.c \
|
libi3/get_config_path.c \
|
||||||
libi3/get_exe_path.c \
|
libi3/get_exe_path.c \
|
||||||
|
@ -357,10 +358,12 @@ i3_msg_i3_msg_SOURCES = \
|
||||||
|
|
||||||
i3_nagbar_i3_nagbar_CFLAGS = \
|
i3_nagbar_i3_nagbar_CFLAGS = \
|
||||||
$(AM_CFLAGS) \
|
$(AM_CFLAGS) \
|
||||||
|
$(LIBSN_CFLAGS) \
|
||||||
$(libi3_CFLAGS)
|
$(libi3_CFLAGS)
|
||||||
|
|
||||||
i3_nagbar_i3_nagbar_LDADD = \
|
i3_nagbar_i3_nagbar_LDADD = \
|
||||||
$(libi3_LIBS) \
|
$(libi3_LIBS) \
|
||||||
|
$(LIBSN_LIBS) \
|
||||||
$(XCB_UTIL_CURSOR_LIBS)
|
$(XCB_UTIL_CURSOR_LIBS)
|
||||||
|
|
||||||
i3_nagbar_i3_nagbar_SOURCES = \
|
i3_nagbar_i3_nagbar_SOURCES = \
|
||||||
|
@ -414,10 +417,12 @@ i3bar_i3bar_SOURCES = \
|
||||||
i3_config_wizard_i3_config_wizard_CFLAGS = \
|
i3_config_wizard_i3_config_wizard_CFLAGS = \
|
||||||
$(AM_CFLAGS) \
|
$(AM_CFLAGS) \
|
||||||
$(libi3_CFLAGS) \
|
$(libi3_CFLAGS) \
|
||||||
|
$(LIBSN_CFLAGS) \
|
||||||
$(XKBCOMMON_CFLAGS)
|
$(XKBCOMMON_CFLAGS)
|
||||||
|
|
||||||
i3_config_wizard_i3_config_wizard_LDADD = \
|
i3_config_wizard_i3_config_wizard_LDADD = \
|
||||||
$(libi3_LIBS) \
|
$(libi3_LIBS) \
|
||||||
|
$(LIBSN_LIBS) \
|
||||||
$(XCB_UTIL_KEYSYMS_LIBS) \
|
$(XCB_UTIL_KEYSYMS_LIBS) \
|
||||||
$(XKBCOMMON_LIBS)
|
$(XKBCOMMON_LIBS)
|
||||||
|
|
||||||
|
@ -521,6 +526,7 @@ i3_SOURCES = \
|
||||||
include/shmlog.h \
|
include/shmlog.h \
|
||||||
include/sighandler.h \
|
include/sighandler.h \
|
||||||
include/startup.h \
|
include/startup.h \
|
||||||
|
include/sync.h \
|
||||||
include/tree.h \
|
include/tree.h \
|
||||||
include/util.h \
|
include/util.h \
|
||||||
include/window.h \
|
include/window.h \
|
||||||
|
@ -562,6 +568,7 @@ i3_SOURCES = \
|
||||||
src/sd-daemon.c \
|
src/sd-daemon.c \
|
||||||
src/sighandler.c \
|
src/sighandler.c \
|
||||||
src/startup.c \
|
src/startup.c \
|
||||||
|
src/sync.c \
|
||||||
src/tree.c \
|
src/tree.c \
|
||||||
src/util.c \
|
src/util.c \
|
||||||
src/version.c \
|
src/version.c \
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
=====================================================
|
=====================================================
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/i3/i3.svg?branch=next)](https://travis-ci.org/i3/i3)
|
[![Build Status](https://travis-ci.org/i3/i3.svg?branch=next)](https://travis-ci.org/i3/i3)
|
||||||
[![Issue Stats](http://www.issuestats.com/github/i3/i3/badge/issue?style=flat)](http://www.issuestats.com/github/i3/i3)
|
[![Issue Stats](https://img.shields.io/github/issues/i3/i3.svg)](https://github.com/i3/i3/issues)
|
||||||
[![Pull Request Stats](http://www.issuestats.com/github/i3/i3/badge/pr?style=flat)](http://www.issuestats.com/github/i3/i3)
|
[![Pull Request Stats](https://img.shields.io/github/issues-pr/i3/i3.svg)](https://github.com/i3/i3/pulls)
|
||||||
|
|
||||||
i3 is a tiling window manager for X11.
|
i3 is a tiling window manager for X11.
|
||||||
|
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
|
|
||||||
┌────────────────────────────┐
|
|
||||||
│ Release notes for i3 v4.15 │
|
|
||||||
└────────────────────────────┘
|
|
||||||
|
|
||||||
This is i3 v4.15. This version is considered stable. All users of i3 are
|
|
||||||
strongly encouraged to upgrade.
|
|
||||||
|
|
||||||
Aside from a number of fixes and documentation improvements, a number of
|
|
||||||
commands have been extended to be more complete (e.g. “assign”, “resize”).
|
|
||||||
|
|
||||||
┌────────────────────────────┐
|
|
||||||
│ Changes in i3 v4.15 │
|
|
||||||
└────────────────────────────┘
|
|
||||||
|
|
||||||
• build: AnyEvent::I3 moved to the i3 repository, so that its main consumer,
|
|
||||||
the i3 testsuite, can use new features immediately (such as the tick event,
|
|
||||||
in this case).
|
|
||||||
• docs/hacking-howto: promote “using git / sending patches” and “how to
|
|
||||||
build?” sections
|
|
||||||
• docs/i3bar-protocol: document that pango markup only works with pango fonts
|
|
||||||
• docs/ipc: document focus, nodes, floating_nodes
|
|
||||||
• docs/ipc: urgent: complete the list of container types
|
|
||||||
• docs/ipc: document how to detect i3’s byte order in memory-safe languages
|
|
||||||
• docs/ipc: document the GET_CONFIG request
|
|
||||||
• docs/userguide: fix formatting issue
|
|
||||||
• docs/userguide: explain why Mod4 is usually preferred as a modifier
|
|
||||||
• docs/userguide: use more idiomatic english (full-size, so-called)
|
|
||||||
• docs/userguide: switch from removed goto command to focus
|
|
||||||
• docs/userguide: mention <criteria> in focus
|
|
||||||
• docs/userguide: remove outdated 2013 last-modified date
|
|
||||||
• dump-asy: add prerequisite checks
|
|
||||||
• dump-asy: fix warnings about empty container names
|
|
||||||
• i3-dump-log: enable shmlog on demand
|
|
||||||
• i3-sensible-terminal: add “kitty”, “guake”, “tilda”
|
|
||||||
• i3-sensible-editor: add “gvim”
|
|
||||||
• i3bar: add --release flag for bindsym in bar blocks
|
|
||||||
• i3bar: add relative coordinates in JSON for click events
|
|
||||||
• ipc: rename COMMAND to RUN_COMMAND for consistency
|
|
||||||
• ipc: implement tick event for less flaky tests
|
|
||||||
• ipc: add error reply to “focus <window_mode>”
|
|
||||||
• ipc: send success response for nop
|
|
||||||
• default config: add $mod+r to toggle resize mode
|
|
||||||
• default config: use variables for workspace names to avoid repetition
|
|
||||||
• introduce “assign <criteria> [→] [workspace] [number] <workspace>”
|
|
||||||
• introduce “assign <criteria> [→] output left|right|up|down|primary|<output>”
|
|
||||||
• introduce a “focus_wrapping” option (subsumes “force_focus_wrapping”)
|
|
||||||
• introduce percentage point resizing for floating containers:
|
|
||||||
“resize set <width> [px | ppt] <height> [px | ppt]”
|
|
||||||
• introduce “resize set <width> ppt <height> ppt” for tiling windows
|
|
||||||
• rename “new_window” and “new_float” to “default_border” and
|
|
||||||
“default_floating_border” (the old names keep working)
|
|
||||||
• output names (e.g. “DP2”) can now be used as synonyms for monitor names
|
|
||||||
(e.g. “Dell UP2414Q”).
|
|
||||||
• the “swap” command now works with fullscreen windows
|
|
||||||
• raise floating windows to top when they are focused programmatically
|
|
||||||
• _NET_ACTIVE_WINDOW: invalidate focus to force SetInputFocus call
|
|
||||||
• make focus handling consistent when changing focus between outputs
|
|
||||||
• round non-integer Xft.dpi values
|
|
||||||
• tiling resize: remove minimum size
|
|
||||||
|
|
||||||
┌────────────────────────────┐
|
|
||||||
│ Bugfixes │
|
|
||||||
└────────────────────────────┘
|
|
||||||
|
|
||||||
• i3bar: fix various memory leaks
|
|
||||||
• i3bar: fix crash when no status_command is provided
|
|
||||||
• fix uninitialized variables in init_dpi_end, tree_restore
|
|
||||||
• fix incorrectly set up signal handling
|
|
||||||
• fix “swap” debug log message
|
|
||||||
• fix crash when specifying invalid con_id for “swap”
|
|
||||||
• fix crash upon restart with window marks
|
|
||||||
• fix crash when config file does not end in a newline
|
|
||||||
• fix crash in append_layout
|
|
||||||
• fix crash in layout toggle command
|
|
||||||
• fix crash when switching monitors
|
|
||||||
• fix use-after-free in randr_init error path
|
|
||||||
• fix move accidentally moving windows across outputs
|
|
||||||
• fix crash when floating window is tiled while being resized
|
|
||||||
• fix out-of-bounds memory read
|
|
||||||
• fix memory leak when config conversion fails
|
|
||||||
• fix layout toggle split, which didn’t work until enabling tabbed/stack mode
|
|
||||||
once
|
|
||||||
• move XCB event handling into xcb_prepare_cb
|
|
||||||
• avert endless loop on unexpected EOF in ipc messages
|
|
||||||
• perform proper cleanup for signals with Term action
|
|
||||||
• don’t match containers in the scratchpad with criteria
|
|
||||||
• fix “workspace show” related issues
|
|
||||||
• fix config file conversion with long variable names
|
|
||||||
• fix config file conversion memory initialization
|
|
||||||
• prevent access of freed workspace in _workspace_show
|
|
||||||
• disable fullscreen when required when programmatically focusing windows
|
|
||||||
• free last_motion_notify
|
|
||||||
• don’t raise floating windows when focused because of focus_follows_mouse
|
|
||||||
• correctly set EWMH atoms when closing a workspace
|
|
||||||
• don’t raise floating windows when workspace is shown
|
|
||||||
• keep focus order when encapsulating workspaces
|
|
||||||
• validate layout files before loading
|
|
||||||
|
|
||||||
┌────────────────────────────┐
|
|
||||||
│ Thanks! │
|
|
||||||
└────────────────────────────┘
|
|
||||||
|
|
||||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
|
||||||
|
|
||||||
Alex Lu, Ben Creasy, Bennett Piater, Cast, chressie, clonejo, Dan Elkouby,
|
|
||||||
Daniel Mueller, DebianWall, Diki Ananta, Edward Betts, hwangcc23, Ingo Bürk,
|
|
||||||
Jan Alexander Steffens, Johannes Lange, Kent Fredric, livanh, Martin
|
|
||||||
T. H. Sandsmark, Michael Siegel, Orestis Floros, Pallav Agarwal, Pawel
|
|
||||||
S. Veselov, Pietro Cerutti, Theo Buehler, Thomas Praxl, Tyler Brazier,
|
|
||||||
Vladimir Panteleev, walker0643, Wes Roberts, xzfc
|
|
||||||
|
|
||||||
-- Michael Stapelberg, 2018-03-10
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
|
||||||
|
┌────────────────────────────┐
|
||||||
|
│ Release notes for i3 v4.16 │
|
||||||
|
└────────────────────────────┘
|
||||||
|
|
||||||
|
This is i3 v4.16. This version is considered stable. All users of i3 are
|
||||||
|
strongly encouraged to upgrade.
|
||||||
|
|
||||||
|
This release contains a number of assorted fixes and improvements across pretty
|
||||||
|
much all individual components of i3.
|
||||||
|
|
||||||
|
┌────────────────────────────┐
|
||||||
|
│ Changes in i3 v4.16 │
|
||||||
|
└────────────────────────────┘
|
||||||
|
|
||||||
|
• build: add conditionals for building docs/mans
|
||||||
|
• docs/i3bar-protocol: mention skipping blocks with empty full_text
|
||||||
|
• docs/ipc: add window_properties to tree node
|
||||||
|
• docs/layout-saving: clarify JSON non-compliance
|
||||||
|
• docs/userguide: clarify X resource value format
|
||||||
|
• docs/userguide: fix move_to_outputs link
|
||||||
|
• docs/userguide: link workspace_auto_back_and_forth from workspace
|
||||||
|
command
|
||||||
|
• docs/userguide: mention known issues for assign
|
||||||
|
• docs/userguide: use anchor for list_of_commands
|
||||||
|
• docs/userguide: add the default keybinding for focus parent
|
||||||
|
• man/*: fix title markers (for asciidoctor)
|
||||||
|
• man/i3-msg.man: add get_config and send_tick
|
||||||
|
• ipc: kill misbehaving subscribed clients instead of hanging
|
||||||
|
• ipc: introduce the sync IPC command for synchronization with i3bar
|
||||||
|
• ipc: scratchpad show now returns correct success
|
||||||
|
• ipc: send_tick now sets the already-documented “first” field
|
||||||
|
• i3bar-protocol: add modifiers to events sent by i3bar
|
||||||
|
• dump-asy: use Pod::Usage for --help and perldoc
|
||||||
|
• dump-asy: introduce -gv flag to disable opening ghostview
|
||||||
|
• dump-asy: introduce -save flag to store the rendered tree in a file
|
||||||
|
• dump-asy: add marks
|
||||||
|
• dump-asy: include floating containers
|
||||||
|
• i3bar: add --verbose flag
|
||||||
|
• i3bar: make modifier accept combinations (like floating_modifier)
|
||||||
|
• i3-config-wizard: add --modifier flag to allow for headless config
|
||||||
|
• i3-config-wizard: support startup notifications
|
||||||
|
• i3-msg: only print input + error position if they are set
|
||||||
|
• i3-msg: check replies also in quiet mode (-q)
|
||||||
|
• i3-msg: add support for the SUBSCRIBE message type
|
||||||
|
• i3-nagbar: support startup notifications
|
||||||
|
• i3-nagbar: add option for button that runs commands without a terminal
|
||||||
|
• i3-save-tree: exclude unsupported transient_for property
|
||||||
|
• i3-sensible-terminal: add alacritty
|
||||||
|
• i3-sensible-terminal: add hyper
|
||||||
|
• introduce strip_workspace_name alongside strip_workspace_numbers
|
||||||
|
• introduce title_align config directive
|
||||||
|
• “border toggle” now accepts an optional pixel argument
|
||||||
|
• “resize set” now interprets 0 as “no change”
|
||||||
|
• “resize set” now accepts the “width” and “height” keywords
|
||||||
|
• “resize” with pixel values now works for tiling containers
|
||||||
|
• the optional “absolute” method is now silently ignored in “move position”
|
||||||
|
commands, where it did not cause a visible difference anyway
|
||||||
|
• the _NET_WM_STATE_FOCUSED atom is now supported, resulting in e.g.
|
||||||
|
GTK applications displaying the correct window decoration
|
||||||
|
• moving fullscreen containers now moves them across outputs
|
||||||
|
• floating windows can now be used with a geometry of e.g. +1+1, i.e.
|
||||||
|
their top-left corner can be outside any output as long as the window
|
||||||
|
is contained partially by one
|
||||||
|
• prefer floating fullscreen containers when switching focus
|
||||||
|
• moving containers to an active workspace no longer changes focus
|
||||||
|
• the rename workspace command no longer confuses directions (e.g. “left”)
|
||||||
|
with output names
|
||||||
|
• prefer $XDG_CONFIG_HOME/i3/config over ~/.i3/config
|
||||||
|
• allow multiple assignments of workspaces to output
|
||||||
|
• respect maximum size in WM_NORMAL_HINTS
|
||||||
|
• reject requests for WM_STATE_ICONIC, which avoids e.g. wine
|
||||||
|
applications being stuck in paused state
|
||||||
|
• a number of code refactorings and cleanups, some of which tool-assisted
|
||||||
|
|
||||||
|
┌────────────────────────────┐
|
||||||
|
│ Bugfixes │
|
||||||
|
└────────────────────────────┘
|
||||||
|
|
||||||
|
• build: fix static linking
|
||||||
|
• i3bar: fix various memory leaks
|
||||||
|
• i3bar: fix crash when no status_command is provided
|
||||||
|
• i3bar: fix chopping the first character on the very left when using the
|
||||||
|
full width of the output
|
||||||
|
• i3bar: fix relative_x and width properties of click events
|
||||||
|
• i3bar: fix the tray disappearing in some cases when using "tray_output"
|
||||||
|
• fix various memory leaks and memory correctness issues
|
||||||
|
• refocus focused window on FOCUS_IN events for the root window. This
|
||||||
|
fixes incorrect behavior with steam and some tk apps
|
||||||
|
• fix focus bugs when moving unfocused containers
|
||||||
|
• fix incorrect urgent window state edge case
|
||||||
|
• moving an unfocused container from inside a split container to another
|
||||||
|
workspace doesn’t focus siblings
|
||||||
|
• toggling and killing floating windows now maintains focus order
|
||||||
|
• don’t incorrectly focus siblings when scrolling on window decorations
|
||||||
|
• fix crash when moving a container to a marked workspace
|
||||||
|
• fix swap when first is behind a fullscreen window
|
||||||
|
• fix crash when renaming an existing workspace to a name assigned to the
|
||||||
|
focused output
|
||||||
|
• reframe swallowed windows if depth doesn’t match
|
||||||
|
• use detectable autorepeat so that --release bindings are run only when
|
||||||
|
the key is actually released (and not when it is repeated)
|
||||||
|
• fix border artifacts when moving windows
|
||||||
|
• correctly handle bindings for the same mod key with and without --release
|
||||||
|
• reset B_UPON_KEYRELEASE_IGNORE_MODS bindings when switching modes
|
||||||
|
• fix height offset calculation in pango text drawing
|
||||||
|
• fix detection of libiconv on OpenBSD
|
||||||
|
• free workspace assignments on reload
|
||||||
|
• fix mouse position at startup with multiple outputs
|
||||||
|
• no longer allow dragging global fullscreen floating containers
|
||||||
|
• fix rendering artifacts with global fullscreen containers
|
||||||
|
• fix disabling floating for scratchpad windows
|
||||||
|
• fix a crash when renaming an unfocused empty workspace matching an
|
||||||
|
assignment
|
||||||
|
• ensure containers have a size of at least 1px after resize
|
||||||
|
• permit invalid UTF-8 in layout JSON files (e.g. for window titles)
|
||||||
|
• correct invalid UTF-8 characters in window and container titles
|
||||||
|
• fix a crash when moving to a child of a floating container
|
||||||
|
• fix a crash when matching __focused__ with no window open
|
||||||
|
• fix no_focus when only using floating windows
|
||||||
|
• fix max_aspect calculation
|
||||||
|
• moving an unfocused container from another output now maintains
|
||||||
|
the correct focus order
|
||||||
|
• don’t change focus order when swapping containers
|
||||||
|
• correctly update _NET_CURRENT_DESKTOP when moving containers between outputs
|
||||||
|
using the directional move command
|
||||||
|
• don’t produce move events after attempting to directionally move a container
|
||||||
|
towards a direction it can’t go
|
||||||
|
• fix sticky focus when switching to workspace on different output
|
||||||
|
|
||||||
|
|
||||||
|
┌────────────────────────────┐
|
||||||
|
│ Thanks! │
|
||||||
|
└────────────────────────────┘
|
||||||
|
|
||||||
|
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||||
|
|
||||||
|
Adrian Cybulski, Aestek, Alan Barr, Andriy Yablonskyy, Cassandra Fox,
|
||||||
|
Christian Duerr, Dan Elkouby, downzer0, Elouan Martinet, Felix Buehler,
|
||||||
|
Gravemind, Harry Lawrence, Hritik Vijay, hwangcc23, Ingo Bürk, Joona, Klorax,
|
||||||
|
lasers, Łukasz Adamczak, Martin, Michael Stapelberg, Oliver Graff,
|
||||||
|
Orestis Floros, Soumya, Takashi Iwai, Thomas Fischer, Todd Walton, Tony
|
||||||
|
Crisci, Uli Schlachter, Vivien Didelot
|
||||||
|
|
||||||
|
-- Michael Stapelberg, 2018-11-04
|
34
configure.ac
34
configure.ac
|
@ -2,7 +2,7 @@
|
||||||
# Run autoreconf -fi to generate a configure script from this file.
|
# Run autoreconf -fi to generate a configure script from this file.
|
||||||
|
|
||||||
AC_PREREQ([2.69])
|
AC_PREREQ([2.69])
|
||||||
AC_INIT([i3], [4.15], [https://github.com/i3/i3/issues])
|
AC_INIT([i3], [4.16], [https://github.com/i3/i3/issues])
|
||||||
# For AX_EXTEND_SRCDIR
|
# For AX_EXTEND_SRCDIR
|
||||||
AX_ENABLE_BUILDDIR
|
AX_ENABLE_BUILDDIR
|
||||||
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall no-dist-gzip dist-bzip2])
|
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall no-dist-gzip dist-bzip2])
|
||||||
|
@ -81,9 +81,10 @@ AC_SEARCH_LIBS([floor], [m], , [AC_MSG_FAILURE([cannot find the required floor()
|
||||||
# libev does not ship with a pkg-config file :(.
|
# libev does not ship with a pkg-config file :(.
|
||||||
AC_SEARCH_LIBS([ev_run], [ev], , [AC_MSG_FAILURE([cannot find the required ev_run() function despite trying to link with -lev])])
|
AC_SEARCH_LIBS([ev_run], [ev], , [AC_MSG_FAILURE([cannot find the required ev_run() function despite trying to link with -lev])])
|
||||||
|
|
||||||
AC_SEARCH_LIBS([shm_open], [rt])
|
AC_SEARCH_LIBS([shm_open], [rt], [], [], [-pthread])
|
||||||
|
|
||||||
AC_SEARCH_LIBS([iconv_open], [iconv], , [AC_MSG_FAILURE([cannot find the required iconv_open() function despite trying to link with -liconv])])
|
AC_SEARCH_LIBS([iconv_open], [iconv], ,
|
||||||
|
AC_SEARCH_LIBS([libiconv_open], [iconv], , [AC_MSG_FAILURE([cannot find the required iconv_open() function despite trying to link with -liconv])]))
|
||||||
|
|
||||||
AX_PTHREAD
|
AX_PTHREAD
|
||||||
|
|
||||||
|
@ -109,12 +110,27 @@ AC_PROG_MAKE_SET
|
||||||
AC_PROG_RANLIB
|
AC_PROG_RANLIB
|
||||||
AC_PROG_LN_S
|
AC_PROG_LN_S
|
||||||
|
|
||||||
AC_PATH_PROG([PATH_ASCIIDOC], [asciidoc])
|
AC_ARG_ENABLE(docs,
|
||||||
AC_PATH_PROG([PATH_XMLTO], [xmlto])
|
AS_HELP_STRING(
|
||||||
AC_PATH_PROG([PATH_POD2MAN], [pod2man])
|
[--disable-docs],
|
||||||
|
[disable building documentation]),
|
||||||
AM_CONDITIONAL([BUILD_MANS], [test x$PATH_ASCIIDOC != x && test x$PATH_XMLTO != x && test x$PATH_POD2MAN != x])
|
[ax_docs=$enableval],
|
||||||
AM_CONDITIONAL([BUILD_DOCS], [test x$PATH_ASCIIDOC != x])
|
[ax_docs=yes])
|
||||||
|
AC_ARG_ENABLE(mans,
|
||||||
|
AS_HELP_STRING(
|
||||||
|
[--disable-mans],
|
||||||
|
[disable building manual pages]),
|
||||||
|
[ax_mans=$enableval],
|
||||||
|
[ax_mans=yes])
|
||||||
|
AS_IF([test x$ax_docs = xyes || test x$ax_mans = xyes], [
|
||||||
|
AC_PATH_PROG([PATH_ASCIIDOC], [asciidoc])
|
||||||
|
])
|
||||||
|
AS_IF([test x$ax_mans = xyes], [
|
||||||
|
AC_PATH_PROG([PATH_XMLTO], [xmlto])
|
||||||
|
AC_PATH_PROG([PATH_POD2MAN], [pod2man])
|
||||||
|
])
|
||||||
|
AM_CONDITIONAL([BUILD_MANS], [test x$ax_mans = xyes && test x$PATH_ASCIIDOC != x && test x$PATH_XMLTO != x && test x$PATH_POD2MAN != x])
|
||||||
|
AM_CONDITIONAL([BUILD_DOCS], [test x$ax_docs = xyes && test x$PATH_ASCIIDOC != x])
|
||||||
|
|
||||||
AM_PROG_AR
|
AM_PROG_AR
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,35 @@
|
||||||
#!/usr/bin/env perl
|
#!/usr/bin/env perl
|
||||||
# vim:ts=4:sw=4:expandtab
|
# vim:ts=4:sw=4:expandtab
|
||||||
# renders the layout tree using asymptote
|
|
||||||
#
|
|
||||||
# ./dump-asy.pl
|
|
||||||
# will render the entire tree
|
|
||||||
# ./dump-asy.pl 'name'
|
|
||||||
# will render the tree starting from the node with the specified name,
|
|
||||||
# e.g. ./dump-asy.pl 2 will render workspace 2 and below
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
use Getopt::Long;
|
||||||
|
use Pod::Usage;
|
||||||
use AnyEvent::I3;
|
use AnyEvent::I3;
|
||||||
use File::Temp;
|
use File::Temp;
|
||||||
|
use File::Spec;
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use v5.10;
|
use v5.10;
|
||||||
use IPC::Cmd qw[can_run];
|
use IPC::Cmd qw[can_run];
|
||||||
|
|
||||||
|
my %options = (
|
||||||
|
gv => 1,
|
||||||
|
save => undef,
|
||||||
|
help => 0,
|
||||||
|
);
|
||||||
|
my $result = GetOptions(
|
||||||
|
"gv!" => \$options{gv},
|
||||||
|
"save=s" => \$options{save},
|
||||||
|
"help|?" => \$options{help},
|
||||||
|
);
|
||||||
|
|
||||||
|
pod2usage(-verbose => 2, -exitcode => 0) if $options{help};
|
||||||
|
|
||||||
# prerequisites check so we can be specific about failures caused
|
# prerequisites check so we can be specific about failures caused
|
||||||
# by not having these tools in the path
|
# by not having these tools in the path
|
||||||
can_run('asy') or die 'Please install asymptote';
|
can_run('asy') or die 'Please install asymptote';
|
||||||
can_run('gv') or die 'Please install gv';
|
can_run('gv') or die 'Please install gv' unless !$options{gv};
|
||||||
|
|
||||||
my $i3 = i3();
|
my $i3 = i3();
|
||||||
|
|
||||||
|
@ -37,7 +46,7 @@ sub dump_node {
|
||||||
|
|
||||||
my $o = ($n->{orientation} eq 'none' ? "u" : ($n->{orientation} eq 'horizontal' ? "h" : "v"));
|
my $o = ($n->{orientation} eq 'none' ? "u" : ($n->{orientation} eq 'horizontal' ? "h" : "v"));
|
||||||
my $w = (defined($n->{window}) ? $n->{window} : "N");
|
my $w = (defined($n->{window}) ? $n->{window} : "N");
|
||||||
my $na = ($n->{name} or "[Empty]");
|
my $na = ($n->{name} or ($n->{type} eq "floating_con" ? "[Floating con]" : "[Empty]"));
|
||||||
$na =~ s/#/\\#/g;
|
$na =~ s/#/\\#/g;
|
||||||
$na =~ s/\$/\\\$/g;
|
$na =~ s/\$/\\\$/g;
|
||||||
$na =~ s/&/\\&/g;
|
$na =~ s/&/\\&/g;
|
||||||
|
@ -47,14 +56,16 @@ sub dump_node {
|
||||||
if (!defined($n->{window})) {
|
if (!defined($n->{window})) {
|
||||||
$type = $n->{layout};
|
$type = $n->{layout};
|
||||||
}
|
}
|
||||||
my $name = qq|``$na'' ($type)|;
|
my $marks = $n->{marks} ? ' [' . join('][', @{$n->{marks}}) . ']' : '';
|
||||||
|
my $name = qq|``$na'' ($type)$marks|;
|
||||||
|
|
||||||
print $tmp "TreeNode n" . $n->{id} . " = makeNode(";
|
print $tmp "TreeNode n" . $n->{id} . " = makeNode(";
|
||||||
|
|
||||||
print $tmp "n" . $parent->{id} . ", " if defined($parent);
|
print $tmp "n" . $parent->{id} . ", " if defined($parent);
|
||||||
print $tmp "\"" . $name . "\");\n";
|
print $tmp "\"" . $name . "\");\n";
|
||||||
|
|
||||||
dump_node($_, $n) for @{$n->{nodes}};
|
dump_node($_, $n) for @{$n->{nodes}};
|
||||||
|
dump_node($_, $n) for @{$n->{floating_nodes}};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub find_node_with_name {
|
sub find_node_with_name {
|
||||||
|
@ -82,5 +93,60 @@ say $tmp "draw(n" . $root->{id} . ", (0, 0));";
|
||||||
close($tmp);
|
close($tmp);
|
||||||
my $rep = "$tmp";
|
my $rep = "$tmp";
|
||||||
$rep =~ s/asy$/eps/;
|
$rep =~ s/asy$/eps/;
|
||||||
my $tmp_dir = dirname($rep);
|
if ($options{gv}) {
|
||||||
system("cd $tmp_dir && asy $tmp && gv --scale=-1000 --noresize --widgetless $rep && rm $rep");
|
my $tmp_dir = dirname($rep);
|
||||||
|
$options{save} = File::Spec->rel2abs($options{save}) if $options{save};
|
||||||
|
chdir($tmp_dir);
|
||||||
|
} else {
|
||||||
|
$rep = basename($rep); # Output in current dir.
|
||||||
|
}
|
||||||
|
system("asy $tmp"); # Create the .eps file.
|
||||||
|
system("gv --scale=-1000 --noresize --widgetless $rep") if $options{gv};
|
||||||
|
if ($options{save}) {
|
||||||
|
system("mv $rep ${options{save}}");
|
||||||
|
} elsif ($options{gv}) {
|
||||||
|
system("rm $rep");
|
||||||
|
}
|
||||||
|
system("rm $tmp");
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
dump-asy.pl - Render the layout tree using asymptote
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
dump-asy.pl [workspace]
|
||||||
|
|
||||||
|
=head1 EXAMPLE
|
||||||
|
|
||||||
|
Render the entire tree, run:
|
||||||
|
|
||||||
|
./dump-asy.pl
|
||||||
|
|
||||||
|
Render the tree starting from the node with the specified name, run:
|
||||||
|
|
||||||
|
./dump-asy.pl 'name'
|
||||||
|
|
||||||
|
Render the entire tree, save in file 'file.eps' and show using gv, run:
|
||||||
|
|
||||||
|
./dump-asy.pl --save file.eps
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
=over 8
|
||||||
|
|
||||||
|
=item B<--gv>
|
||||||
|
|
||||||
|
=item B<--no-gv>
|
||||||
|
|
||||||
|
Enable or disable showing the result through gv. If disabled, an .eps file will
|
||||||
|
be saved in the current working directory. Enabled by default.
|
||||||
|
|
||||||
|
=item B<--save>
|
||||||
|
|
||||||
|
Save result using the specified file-name. If omitted, no file will be saved
|
||||||
|
when using '--gv' or a random name will be used when using '--no-gv'.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
i3-wm (4.15.1-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* New upstream release.
|
||||||
|
|
||||||
|
-- Michael Stapelberg <stapelberg@debian.org> Sat, 10 Mar 2018 17:27:26 +0100
|
||||||
|
|
||||||
i3-wm (4.15-1) unstable; urgency=medium
|
i3-wm (4.15-1) unstable; urgency=medium
|
||||||
|
|
||||||
* New upstream release.
|
* New upstream release.
|
||||||
|
|
|
@ -40,7 +40,7 @@ Description: metapackage (i3 window manager, screen locker, menu, statusbar)
|
||||||
|
|
||||||
Package: i3-wm
|
Package: i3-wm
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, x11-utils
|
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||||
Provides: x-window-manager
|
Provides: x-window-manager
|
||||||
Recommends: xfonts-base, fonts-dejavu-core, libanyevent-i3-perl (>= 0.12), libjson-xs-perl, rxvt-unicode | x-terminal-emulator
|
Recommends: xfonts-base, fonts-dejavu-core, libanyevent-i3-perl (>= 0.12), libjson-xs-perl, rxvt-unicode | x-terminal-emulator
|
||||||
Description: improved dynamic tiling window manager
|
Description: improved dynamic tiling window manager
|
||||||
|
|
|
@ -160,7 +160,8 @@ flood kicks.
|
||||||
|
|
||||||
== Debugging i3bar
|
== Debugging i3bar
|
||||||
|
|
||||||
To debug i3bar problems, add +verbose yes+ to all +bar {}+ blocks in your i3
|
To debug i3bar problems, use the +--verbose+ commandline parameter,
|
||||||
|
or add +verbose yes+ to all +bar {}+ blocks in your i3
|
||||||
config, reload your config and then restart all i3bar instances like this:
|
config, reload your config and then restart all i3bar instances like this:
|
||||||
|
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
|
|
|
@ -107,7 +107,7 @@ stop_signal::
|
||||||
processing.
|
processing.
|
||||||
The default value (if none is specified) is SIGSTOP.
|
The default value (if none is specified) is SIGSTOP.
|
||||||
cont_signal::
|
cont_signal::
|
||||||
Specify to i3bar the signal (as an integer)to send to continue your
|
Specify to i3bar the signal (as an integer) to send to continue your
|
||||||
processing.
|
processing.
|
||||||
The default value (if none is specified) is SIGCONT.
|
The default value (if none is specified) is SIGCONT.
|
||||||
click_events::
|
click_events::
|
||||||
|
@ -118,7 +118,8 @@ click_events::
|
||||||
|
|
||||||
full_text::
|
full_text::
|
||||||
The +full_text+ will be displayed by i3bar on the status line. This is the
|
The +full_text+ will be displayed by i3bar on the status line. This is the
|
||||||
only required key.
|
only required key. If +full_text+ is an empty string, the block will be
|
||||||
|
skipped.
|
||||||
short_text::
|
short_text::
|
||||||
Where appropriate, the +short_text+ (string) entry should also be
|
Where appropriate, the +short_text+ (string) entry should also be
|
||||||
provided. It will be used in case the status line needs to be shortened
|
provided. It will be used in case the status line needs to be shortened
|
||||||
|
@ -242,6 +243,9 @@ relative_x, relative_y::
|
||||||
of the block
|
of the block
|
||||||
width, height::
|
width, height::
|
||||||
Width and height (in px) of the block
|
Width and height (in px) of the block
|
||||||
|
modifiers::
|
||||||
|
An array of the modifiers active when the click occurred. The order in which
|
||||||
|
modifiers are listed is not guaranteed.
|
||||||
|
|
||||||
*Example*:
|
*Example*:
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
@ -249,6 +253,7 @@ width, height::
|
||||||
"name": "ethernet",
|
"name": "ethernet",
|
||||||
"instance": "eth0",
|
"instance": "eth0",
|
||||||
"button": 1,
|
"button": 1,
|
||||||
|
"modifiers": ["Shift", "Mod1"],
|
||||||
"x": 1320,
|
"x": 1320,
|
||||||
"y": 1400,
|
"y": 1400,
|
||||||
"relative_x": 12,
|
"relative_x": 12,
|
||||||
|
|
29
docs/ipc
29
docs/ipc
|
@ -65,6 +65,7 @@ to do that).
|
||||||
| 8 | +GET_BINDING_MODES+ | <<_binding_modes_reply,BINDING_MODES>> | Gets the names of all currently configured binding modes.
|
| 8 | +GET_BINDING_MODES+ | <<_binding_modes_reply,BINDING_MODES>> | Gets the names of all currently configured binding modes.
|
||||||
| 9 | +GET_CONFIG+ | <<_config_reply,CONFIG>> | Returns the last loaded i3 config.
|
| 9 | +GET_CONFIG+ | <<_config_reply,CONFIG>> | Returns the last loaded i3 config.
|
||||||
| 10 | +SEND_TICK+ | <<_tick_reply,TICK>> | Sends a tick event with the specified payload.
|
| 10 | +SEND_TICK+ | <<_tick_reply,TICK>> | Sends a tick event with the specified payload.
|
||||||
|
| 11 | +SYNC+ | <<_sync_reply,SYNC>> | Sends an i3 sync event with the specified random value to the specified window.
|
||||||
|======================================================
|
|======================================================
|
||||||
|
|
||||||
So, a typical message could look like this:
|
So, a typical message could look like this:
|
||||||
|
@ -327,6 +328,8 @@ window (integer)::
|
||||||
This field is set to null for split containers or otherwise empty
|
This field is set to null for split containers or otherwise empty
|
||||||
containers. This ID corresponds to what xwininfo(1) and other
|
containers. This ID corresponds to what xwininfo(1) and other
|
||||||
X11-related tools display (usually in hex).
|
X11-related tools display (usually in hex).
|
||||||
|
window_properties (map)::
|
||||||
|
X11 window properties title, instance, class, window_role and transient_for.
|
||||||
urgent (bool)::
|
urgent (bool)::
|
||||||
Whether this container (window, split container, floating container or
|
Whether this container (window, split container, floating container or
|
||||||
workspace) has the urgency hint set, directly or indirectly. All parent
|
workspace) has the urgency hint set, directly or indirectly. All parent
|
||||||
|
@ -422,6 +425,12 @@ JSON dump:
|
||||||
"width": 1280,
|
"width": 1280,
|
||||||
"height": 782
|
"height": 782
|
||||||
},
|
},
|
||||||
|
"window_properties": {
|
||||||
|
"class": "Evince",
|
||||||
|
"instance": "evince",
|
||||||
|
"title": "Properties",
|
||||||
|
"transient_for": 52428808
|
||||||
|
},
|
||||||
"floating_nodes": [],
|
"floating_nodes": [],
|
||||||
"nodes": [
|
"nodes": [
|
||||||
|
|
||||||
|
@ -654,6 +663,18 @@ events generated prior to the +SEND_TICK+ message (happened-before relation).
|
||||||
{ "success": true }
|
{ "success": true }
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
[[_sync_reply]]
|
||||||
|
=== SYNC reply
|
||||||
|
|
||||||
|
The reply is a map containing the "success" member. After the reply was
|
||||||
|
received, the https://i3wm.org/docs/testsuite.html#i3_sync[i3 sync message] was
|
||||||
|
responded to.
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
-------------------
|
||||||
|
{ "success": true }
|
||||||
|
-------------------
|
||||||
|
|
||||||
== Events
|
== Events
|
||||||
|
|
||||||
[[events]]
|
[[events]]
|
||||||
|
@ -672,6 +693,14 @@ program does not want to cope which such kinds of race conditions (an
|
||||||
event based library may not have a problem here), I suggest you create a
|
event based library may not have a problem here), I suggest you create a
|
||||||
separate connection to receive events.
|
separate connection to receive events.
|
||||||
|
|
||||||
|
If an event message needs to be sent and the socket is not writeable (write
|
||||||
|
returns EAGAIN, happens when the socket doesn't have enough buffer space for
|
||||||
|
writing new data) then i3 uses a queue system to store outgoing messages for
|
||||||
|
each client. This is combined with a timer: if the message queue for a client is
|
||||||
|
not empty and no data where successfully written in the past 10 seconds, the
|
||||||
|
connection is killed. Practically, this means that your client should try to
|
||||||
|
always read events from the socket to avoid having its connection closed.
|
||||||
|
|
||||||
=== Subscribing to events
|
=== Subscribing to events
|
||||||
|
|
||||||
By sending a message of type SUBSCRIBE with a JSON-encoded array as payload
|
By sending a message of type SUBSCRIBE with a JSON-encoded array as payload
|
||||||
|
|
|
@ -219,13 +219,15 @@ the window which matches any of the criteria. As an example:
|
||||||
|
|
||||||
A layout file as generated by +i3-save-tree(1)+ is not strictly valid JSON:
|
A layout file as generated by +i3-save-tree(1)+ is not strictly valid JSON:
|
||||||
|
|
||||||
1. Layout files contain multiple “JSON documents” on the top level, whereas the
|
1. Layout files contain multiple “JSON texts” at the top level. The JSON
|
||||||
JSON standard only allows precisely one “document” (array or hash).
|
standard doesn't prohibit this, but in practice most JSON parsers only
|
||||||
|
allow precisely one “text” per document/file, and will mark multiple texts
|
||||||
|
as invalid JSON.
|
||||||
|
|
||||||
2. Layout files contain comments which are not standardized, but understood by
|
2. Layout files contain comments which are not allowed by the JSON standard,
|
||||||
many parsers.
|
but are understood by many parsers.
|
||||||
|
|
||||||
Both deviations from the JSON standard are to make manual editing by humans
|
Both of these deviations from the norm are to make manual editing by humans
|
||||||
easier. In case you are writing a more elaborate tool for manipulating these
|
easier. In case you are writing a more elaborate tool for manipulating these
|
||||||
layouts, you can either use a JSON parser that supports these deviations (for
|
layouts, you can either use a JSON parser that supports these deviations (for
|
||||||
example libyajl), transform the layout file to a JSON-conforming file, or
|
example libyajl), transform the layout file to a JSON-conforming file, or
|
||||||
|
|
110
docs/userguide
110
docs/userguide
|
@ -245,9 +245,11 @@ you open a new terminal, it will open below the current one.
|
||||||
|
|
||||||
So, how can you open a new terminal window to the *right* of the current one?
|
So, how can you open a new terminal window to the *right* of the current one?
|
||||||
The solution is to use +focus parent+, which will focus the +Parent Container+ of
|
The solution is to use +focus parent+, which will focus the +Parent Container+ of
|
||||||
the current +Container+. In this case, you would focus the +Vertical Split
|
the current +Container+. In default configuration, use +$mod+a+ to navigate one
|
||||||
Container+ which is *inside* the horizontally oriented workspace. Thus, now new
|
+Container+ up the tree (you can repeat this multiple times until you get to the
|
||||||
windows will be opened to the right of the +Vertical Split Container+:
|
+Workspace Container+). In this case, you would focus the +Vertical Split Container+
|
||||||
|
which is *inside* the horizontally oriented workspace. Thus, now new windows will be
|
||||||
|
opened to the right of the +Vertical Split Container+:
|
||||||
|
|
||||||
image::tree-shot3.png["shot3",title="Focus parent, then open new terminal"]
|
image::tree-shot3.png["shot3",title="Focus parent, then open new terminal"]
|
||||||
|
|
||||||
|
@ -585,6 +587,16 @@ workspace_layout default|stacking|tabbed
|
||||||
workspace_layout tabbed
|
workspace_layout tabbed
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
=== Window title alignment
|
||||||
|
|
||||||
|
This option determines the window title's text alignment.
|
||||||
|
Default is +left+
|
||||||
|
|
||||||
|
*Syntax*:
|
||||||
|
---------------------------------------------
|
||||||
|
title_align left|center|right
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
=== Default border style for new windows
|
=== Default border style for new windows
|
||||||
|
|
||||||
This option determines which border style new windows will have. The default is
|
This option determines which border style new windows will have. The default is
|
||||||
|
@ -730,7 +742,8 @@ resource database to achieve an easily maintainable, consistent color theme
|
||||||
across many X applications.
|
across many X applications.
|
||||||
|
|
||||||
Defining a resource will load this resource from the resource database and
|
Defining a resource will load this resource from the resource database and
|
||||||
assign its value to the specified variable. A fallback must be specified in
|
assign its value to the specified variable. This is done verbatim and the value
|
||||||
|
must therefore be in the format that i3 uses. A fallback must be specified in
|
||||||
case the resource cannot be loaded from the database.
|
case the resource cannot be loaded from the database.
|
||||||
|
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
|
@ -754,14 +767,23 @@ set_from_resource $black i3wm.color0 #000000
|
||||||
|
|
||||||
To automatically make a specific window show up on a specific workspace, you
|
To automatically make a specific window show up on a specific workspace, you
|
||||||
can use an *assignment*. You can match windows by using any criteria,
|
can use an *assignment*. You can match windows by using any criteria,
|
||||||
see <<command_criteria>>. It is recommended that you match on window classes
|
see <<command_criteria>>. The difference between +assign+ and
|
||||||
(and instances, when appropriate) instead of window titles whenever possible
|
+for_window <criteria> move to workspace+ is that the former will only be
|
||||||
because some applications first create their window, and then worry about
|
executed when the application maps the window (mapping means actually displaying
|
||||||
setting the correct title. Firefox with Vimperator comes to mind. The window
|
it on the screen) but the latter will be executed whenever a window changes its
|
||||||
starts up being named Firefox, and only when Vimperator is loaded does the
|
properties to something that matches the specified criteria.
|
||||||
title change. As i3 will get the title as soon as the application maps the
|
|
||||||
window (mapping means actually displaying it on the screen), you’d need to have
|
Thus, it is recommended that you match on window classes (and instances, when
|
||||||
to match on 'Firefox' in this case.
|
appropriate) instead of window titles whenever possible because some
|
||||||
|
applications first create their window, and then worry about setting the correct
|
||||||
|
title. Firefox with Vimperator comes to mind. The window starts up being named
|
||||||
|
Firefox, and only when Vimperator is loaded does the title change. As i3 will
|
||||||
|
get the title as soon as the application maps the window, you’d need to have to
|
||||||
|
match on 'Firefox' in this case.
|
||||||
|
Another known issue is with Spotify, which doesn't set the class hints when
|
||||||
|
mapping the window, meaning you'll have to use a +for_window+ rule to assign
|
||||||
|
Spotify to a specific workspace.
|
||||||
|
Finally, using +assign [tiling]+ and +assign [floating]+ is not supported.
|
||||||
|
|
||||||
You can also assign a window to show up on a specific output. You can use RandR
|
You can also assign a window to show up on a specific output. You can use RandR
|
||||||
names such as +VGA1+ or names relative to the output with the currently focused
|
names such as +VGA1+ or names relative to the output with the currently focused
|
||||||
|
@ -887,7 +909,7 @@ the second screen and so on).
|
||||||
|
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
workspace <workspace> output <output>
|
workspace <workspace> output <output1> [output2]…
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
The 'output' is the name of the RandR output you attach your screen to. On a
|
The 'output' is the name of the RandR output you attach your screen to. On a
|
||||||
|
@ -906,12 +928,15 @@ monitor name is “Dell UP2414Q”.
|
||||||
entire monitor, i3 will still use the entire area of the containing monitor
|
entire monitor, i3 will still use the entire area of the containing monitor
|
||||||
rather than that of just the output's.)
|
rather than that of just the output's.)
|
||||||
|
|
||||||
|
You can specify multiple outputs. The first available will be used.
|
||||||
|
|
||||||
If you use named workspaces, they must be quoted:
|
If you use named workspaces, they must be quoted:
|
||||||
|
|
||||||
*Examples*:
|
*Examples*:
|
||||||
---------------------------
|
---------------------------
|
||||||
workspace 1 output LVDS1
|
workspace 1 output LVDS1
|
||||||
workspace 5 output VGA1
|
workspace 2 output primary
|
||||||
|
workspace 5 output VGA1 LVDS1
|
||||||
workspace "2: vim" output VGA1
|
workspace "2: vim" output VGA1
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
@ -991,7 +1016,7 @@ ipc-socket ~/.i3/i3-ipc.sock
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
You can then use the +i3-msg+ application to perform any command listed in
|
You can then use the +i3-msg+ application to perform any command listed in
|
||||||
the next section.
|
<<list_of_commands>>.
|
||||||
|
|
||||||
=== Focus follows mouse
|
=== Focus follows mouse
|
||||||
|
|
||||||
|
@ -1117,6 +1142,7 @@ force_xinerama yes
|
||||||
Also note that your output names are not descriptive (like +HDMI1+) when using
|
Also note that your output names are not descriptive (like +HDMI1+) when using
|
||||||
Xinerama, instead they are counted up, starting at 0: +xinerama-0+, +xinerama-1+, …
|
Xinerama, instead they are counted up, starting at 0: +xinerama-0+, +xinerama-1+, …
|
||||||
|
|
||||||
|
[[workspace_auto_back_and_forth]]
|
||||||
=== Automatic back-and-forth when switching to the current workspace
|
=== Automatic back-and-forth when switching to the current workspace
|
||||||
|
|
||||||
This configuration directive enables automatic +workspace back_and_forth+ (see
|
This configuration directive enables automatic +workspace back_and_forth+ (see
|
||||||
|
@ -1594,7 +1620,7 @@ bar {
|
||||||
}
|
}
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
=== Strip workspace numbers
|
=== Strip workspace numbers/name
|
||||||
|
|
||||||
Specifies whether workspace numbers should be displayed within the workspace
|
Specifies whether workspace numbers should be displayed within the workspace
|
||||||
buttons. This is useful if you want to have a named workspace that stays in
|
buttons. This is useful if you want to have a named workspace that stays in
|
||||||
|
@ -1605,11 +1631,15 @@ the form "[n]:[NAME]" will display only the name. You could use this, for
|
||||||
instance, to display Roman numerals rather than digits by naming your
|
instance, to display Roman numerals rather than digits by naming your
|
||||||
workspaces to "1:I", "2:II", "3:III", "4:IV", ...
|
workspaces to "1:I", "2:II", "3:III", "4:IV", ...
|
||||||
|
|
||||||
|
When +strip_workspace_name+ is set to +yes+, any workspace that has a name of
|
||||||
|
the form "[n]:[NAME]" will display only the number.
|
||||||
|
|
||||||
The default is to display the full name within the workspace button.
|
The default is to display the full name within the workspace button.
|
||||||
|
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
------------------------------
|
------------------------------
|
||||||
strip_workspace_numbers yes|no
|
strip_workspace_numbers yes|no
|
||||||
|
strip_workspace_name yes|no
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
*Example*:
|
*Example*:
|
||||||
|
@ -1707,6 +1737,7 @@ bar {
|
||||||
}
|
}
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
|
[[list_of_commands]]
|
||||||
== List of commands
|
== List of commands
|
||||||
|
|
||||||
Commands are what you bind to specific keypresses. You can also issue commands
|
Commands are what you bind to specific keypresses. You can also issue commands
|
||||||
|
@ -2025,10 +2056,13 @@ Use the +move+ command to move a container.
|
||||||
# defaults to 10 pixels.
|
# defaults to 10 pixels.
|
||||||
move <left|right|down|up> [<px> px]
|
move <left|right|down|up> [<px> px]
|
||||||
|
|
||||||
# Moves the container either to a specific location
|
# Moves the container to the specified pos_x and pos_y
|
||||||
# or to the center of the screen. If 'absolute' is
|
# coordinates on the screen.
|
||||||
# used, it is moved to the center of all outputs.
|
move position <pos_x> [px] <pos_y> [px]
|
||||||
move [absolute] position <pos_x> [px] <pos_y> [px]
|
|
||||||
|
# Moves the container to the center of the screen.
|
||||||
|
# If 'absolute' is used, it is moved to the center of
|
||||||
|
# all outputs.
|
||||||
move [absolute] position center
|
move [absolute] position center
|
||||||
|
|
||||||
# Moves the container to the current position of the
|
# Moves the container to the current position of the
|
||||||
|
@ -2113,8 +2147,8 @@ for_window [instance=notepad] sticky enable
|
||||||
|
|
||||||
To change to a specific workspace, use the +workspace+ command, followed by the
|
To change to a specific workspace, use the +workspace+ command, followed by the
|
||||||
number or name of the workspace. Pass the optional flag
|
number or name of the workspace. Pass the optional flag
|
||||||
+--no-auto-back-and-forth+ to disable <<back_and_forth>> for this specific call
|
+--no-auto-back-and-forth+ to disable <<workspace_auto_back_and_forth>> for this
|
||||||
only.
|
specific call only.
|
||||||
|
|
||||||
To move containers to specific workspaces, use +move container to workspace+.
|
To move containers to specific workspaces, use +move container to workspace+.
|
||||||
|
|
||||||
|
@ -2253,8 +2287,7 @@ See <<move_to_outputs>> for how to move a container/workspace to a different
|
||||||
RandR output.
|
RandR output.
|
||||||
|
|
||||||
[[move_to_outputs]]
|
[[move_to_outputs]]
|
||||||
[[_moving_containers_workspaces_to_randr_outputs]]
|
=== [[_moving_containers_workspaces_to_randr_outputs]]Moving containers/workspaces to RandR outputs
|
||||||
=== Moving containers/workspaces to RandR outputs
|
|
||||||
|
|
||||||
To move a container to another RandR output (addressed by names like +LVDS1+ or
|
To move a container to another RandR output (addressed by names like +LVDS1+ or
|
||||||
+VGA1+) or to a RandR output identified by a specific direction (like +left+,
|
+VGA1+) or to a RandR output identified by a specific direction (like +left+,
|
||||||
|
@ -2313,20 +2346,21 @@ If you want to resize containers/windows using your keyboard, you can use the
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
resize grow|shrink <direction> [<px> px [or <ppt> ppt]]
|
resize grow|shrink <direction> [<px> px [or <ppt> ppt]]
|
||||||
resize set <width> [px | ppt] <height> [px | ppt]
|
resize set [width] <width> [px | ppt]
|
||||||
|
resize set height <height> [px | ppt]
|
||||||
|
resize set [width] <width> [px | ppt] [height] <height> [px | ppt]
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
Direction can either be one of +up+, +down+, +left+ or +right+. Or you can be
|
Direction can either be one of +up+, +down+, +left+ or +right+. Or you can be
|
||||||
less specific and use +width+ or +height+, in which case i3 will take/give
|
less specific and use +width+ or +height+, in which case i3 will take/give space
|
||||||
space from all the other containers. The optional pixel argument specifies by
|
from all the other containers. The optional pixel argument specifies by how many
|
||||||
how many pixels a *floating container* should be grown or shrunk (the default
|
pixels a container should be grown or shrunk (the default is 10 pixels). The
|
||||||
is 10 pixels). The ppt argument means percentage points and specifies by how
|
optional ppt argument means "percentage points", and if specified it indicates
|
||||||
many percentage points a *tiling container* should be grown or shrunk (the
|
that a *tiling container* should be grown or shrunk by that many points, instead
|
||||||
default is 10 percentage points).
|
of by the +px+ value.
|
||||||
|
|
||||||
Notes about +resize set+: a value of 0 for <width> or <height> means "do
|
Note about +resize set+: a value of 0 for <width> or <height> means "do not
|
||||||
not resize in this direction", and resizing a tiling container by +px+ is not
|
resize in this direction".
|
||||||
implemented.
|
|
||||||
|
|
||||||
It is recommended to define bindings for resizing in a dedicated binding mode.
|
It is recommended to define bindings for resizing in a dedicated binding mode.
|
||||||
See <<binding_modes>> and the example in the i3
|
See <<binding_modes>> and the example in the i3
|
||||||
|
@ -2469,7 +2503,9 @@ To change the border of the current client, you can use +border normal+ to use t
|
||||||
border (including window title), +border pixel 1+ to use a 1-pixel border (no window title)
|
border (including window title), +border pixel 1+ to use a 1-pixel border (no window title)
|
||||||
and +border none+ to make the client borderless.
|
and +border none+ to make the client borderless.
|
||||||
|
|
||||||
There is also +border toggle+ which will toggle the different border styles.
|
There is also +border toggle+ which will toggle the different border styles. The
|
||||||
|
optional pixel argument can be used to specify the border width when switching
|
||||||
|
to the normal and pixel styles.
|
||||||
|
|
||||||
Note that "pixel" refers to logical pixel. On HiDPI displays, a logical pixel
|
Note that "pixel" refers to logical pixel. On HiDPI displays, a logical pixel
|
||||||
may be represented by multiple physical pixels, so +pixel 1+ might not
|
may be represented by multiple physical pixels, so +pixel 1+ might not
|
||||||
|
@ -2477,8 +2513,8 @@ necessarily translate into a single pixel row wide border.
|
||||||
|
|
||||||
*Syntax*:
|
*Syntax*:
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
border normal|pixel [<n>]
|
border normal|pixel|toggle [<n>]
|
||||||
border none|toggle
|
border none
|
||||||
|
|
||||||
# legacy syntax, equivalent to "border pixel 1"
|
# legacy syntax, equivalent to "border pixel 1"
|
||||||
border 1pixel
|
border 1pixel
|
||||||
|
|
|
@ -147,7 +147,7 @@ bindsym Mod1+Shift+c reload
|
||||||
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
|
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
|
||||||
bindsym Mod1+Shift+r restart
|
bindsym Mod1+Shift+r restart
|
||||||
# exit i3 (logs you out of your X session)
|
# exit i3 (logs you out of your X session)
|
||||||
bindsym Mod1+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'"
|
bindsym Mod1+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'"
|
||||||
|
|
||||||
# resize window (you can also use the mouse for that)
|
# resize window (you can also use the mouse for that)
|
||||||
mode "resize" {
|
mode "resize" {
|
||||||
|
|
|
@ -133,7 +133,7 @@ bindcode $mod+Shift+54 reload
|
||||||
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
|
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
|
||||||
bindcode $mod+Shift+27 restart
|
bindcode $mod+Shift+27 restart
|
||||||
# exit i3 (logs you out of your X session)
|
# exit i3 (logs you out of your X session)
|
||||||
bindcode $mod+Shift+26 exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'"
|
bindcode $mod+Shift+26 exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'"
|
||||||
|
|
||||||
# resize window (you can also use the mouse for that)
|
# resize window (you can also use the mouse for that)
|
||||||
mode "resize" {
|
mode "resize" {
|
||||||
|
|
|
@ -77,7 +77,7 @@ for my $line (@lines) {
|
||||||
($line =~ /
|
($line =~ /
|
||||||
^\s* # skip leading whitespace
|
^\s* # skip leading whitespace
|
||||||
([a-z_]+ \s* = \s*|) # optional identifier
|
([a-z_]+ \s* = \s*|) # optional identifier
|
||||||
(.*?) -> \s* # token
|
(.*?) -> \s* # token
|
||||||
(.*) # optional action
|
(.*) # optional action
|
||||||
/x);
|
/x);
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,9 @@
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include <xkbcommon/xkbcommon-x11.h>
|
#include <xkbcommon/xkbcommon-x11.h>
|
||||||
|
|
||||||
|
#define SN_API_NOT_YET_FROZEN 1
|
||||||
|
#include <libsn/sn-launchee.h>
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
|
@ -101,7 +104,7 @@ static struct xkb_keymap *xkb_keymap;
|
||||||
static uint8_t xkb_base_event;
|
static uint8_t xkb_base_event;
|
||||||
static uint8_t xkb_base_error;
|
static uint8_t xkb_base_error;
|
||||||
|
|
||||||
static void finish();
|
static void finish(void);
|
||||||
|
|
||||||
#include "GENERATED_config_enums.h"
|
#include "GENERATED_config_enums.h"
|
||||||
|
|
||||||
|
@ -213,7 +216,7 @@ static const char *get_string(const char *identifier) {
|
||||||
|
|
||||||
static void clear_stack(void) {
|
static void clear_stack(void) {
|
||||||
for (int c = 0; c < 10; c++) {
|
for (int c = 0; c < 10; c++) {
|
||||||
if (stack[c].type == STACK_STR && stack[c].val.str != NULL)
|
if (stack[c].type == STACK_STR)
|
||||||
free(stack[c].val.str);
|
free(stack[c].val.str);
|
||||||
stack[c].identifier = NULL;
|
stack[c].identifier = NULL;
|
||||||
stack[c].val.str = NULL;
|
stack[c].val.str = NULL;
|
||||||
|
@ -293,6 +296,7 @@ static char *next_state(const cmdp_token *token) {
|
||||||
}
|
}
|
||||||
sasprintf(&res, "bindsym %s%s%s %s%s\n", (modifiers == NULL ? "" : modrep), (modifiers == NULL ? "" : "+"), str, (release == NULL ? "" : release), get_string("command"));
|
sasprintf(&res, "bindsym %s%s%s %s%s\n", (modifiers == NULL ? "" : modrep), (modifiers == NULL ? "" : "+"), str, (release == NULL ? "" : release), get_string("command"));
|
||||||
clear_stack();
|
clear_stack();
|
||||||
|
free(modrep);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,7 +482,7 @@ static void txt(int col, int row, char *text, color_t fg, color_t bg) {
|
||||||
* Handles expose events, that is, draws the window contents.
|
* Handles expose events, that is, draws the window contents.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int handle_expose() {
|
static int handle_expose(void) {
|
||||||
const color_t black = draw_util_hex_to_color("#000000");
|
const color_t black = draw_util_hex_to_color("#000000");
|
||||||
const color_t white = draw_util_hex_to_color("#FFFFFF");
|
const color_t white = draw_util_hex_to_color("#FFFFFF");
|
||||||
const color_t green = draw_util_hex_to_color("#00FF00");
|
const color_t green = draw_util_hex_to_color("#00FF00");
|
||||||
|
@ -631,15 +635,13 @@ static void handle_button_press(xcb_button_press_event_t *event) {
|
||||||
modifier = MOD_Mod1;
|
modifier = MOD_Mod1;
|
||||||
handle_expose();
|
handle_expose();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates the config file and tells i3 to reload.
|
* Creates the config file and tells i3 to reload.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void finish() {
|
static void finish(void) {
|
||||||
printf("creating \"%s\"...\n", config_path);
|
printf("creating \"%s\"...\n", config_path);
|
||||||
|
|
||||||
struct xkb_context *xkb_context;
|
struct xkb_context *xkb_context;
|
||||||
|
@ -745,10 +747,12 @@ int main(int argc, char *argv[]) {
|
||||||
char *pattern = "pango:monospace 8";
|
char *pattern = "pango:monospace 8";
|
||||||
char *patternbold = "pango:monospace bold 8";
|
char *patternbold = "pango:monospace bold 8";
|
||||||
int o, option_index = 0;
|
int o, option_index = 0;
|
||||||
|
bool headless_run = false;
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"socket", required_argument, 0, 's'},
|
{"socket", required_argument, 0, 's'},
|
||||||
{"version", no_argument, 0, 'v'},
|
{"version", no_argument, 0, 'v'},
|
||||||
|
{"modifier", required_argument, 0, 'm'},
|
||||||
{"limit", required_argument, 0, 'l'},
|
{"limit", required_argument, 0, 'l'},
|
||||||
{"prompt", required_argument, 0, 'P'},
|
{"prompt", required_argument, 0, 'P'},
|
||||||
{"prefix", required_argument, 0, 'p'},
|
{"prefix", required_argument, 0, 'p'},
|
||||||
|
@ -756,7 +760,7 @@ int main(int argc, char *argv[]) {
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{0, 0, 0, 0}};
|
{0, 0, 0, 0}};
|
||||||
|
|
||||||
char *options_string = "s:vh";
|
char *options_string = "sm:vh";
|
||||||
|
|
||||||
while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
|
while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
|
||||||
switch (o) {
|
switch (o) {
|
||||||
|
@ -767,9 +771,18 @@ int main(int argc, char *argv[]) {
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("i3-config-wizard " I3_VERSION "\n");
|
printf("i3-config-wizard " I3_VERSION "\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
case 'm':
|
||||||
|
headless_run = true;
|
||||||
|
if (strcmp(optarg, "alt") == 0)
|
||||||
|
modifier = MOD_Mod1;
|
||||||
|
else if (strcmp(optarg, "win") == 0)
|
||||||
|
modifier = MOD_Mod4;
|
||||||
|
else
|
||||||
|
err(EXIT_FAILURE, "Invalid modifier key %s", optarg);
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
printf("i3-config-wizard " I3_VERSION "\n");
|
printf("i3-config-wizard " I3_VERSION "\n");
|
||||||
printf("i3-config-wizard [-s <socket>] [-v]\n");
|
printf("i3-config-wizard [-s <socket>] [-m win|alt] [-v] [-h]\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -826,12 +839,22 @@ int main(int argc, char *argv[]) {
|
||||||
modmap_cookie = xcb_get_modifier_mapping(conn);
|
modmap_cookie = xcb_get_modifier_mapping(conn);
|
||||||
symbols = xcb_key_symbols_alloc(conn);
|
symbols = xcb_key_symbols_alloc(conn);
|
||||||
|
|
||||||
|
if (headless_run) {
|
||||||
|
finish();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Place requests for the atoms we need as soon as possible */
|
/* Place requests for the atoms we need as soon as possible */
|
||||||
#define xmacro(atom) \
|
#define xmacro(atom) \
|
||||||
xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
|
xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
|
||||||
#include "atoms.xmacro"
|
#include "atoms.xmacro"
|
||||||
#undef xmacro
|
#undef xmacro
|
||||||
|
|
||||||
|
/* Init startup notification. */
|
||||||
|
SnDisplay *sndisplay = sn_xcb_display_new(conn, NULL, NULL);
|
||||||
|
SnLauncheeContext *sncontext = sn_launchee_context_new_from_environment(sndisplay, screen);
|
||||||
|
sn_display_unref(sndisplay);
|
||||||
|
|
||||||
root_screen = xcb_aux_get_screen(conn, screen);
|
root_screen = xcb_aux_get_screen(conn, screen);
|
||||||
root = root_screen->root;
|
root = root_screen->root;
|
||||||
|
|
||||||
|
@ -864,6 +887,9 @@ int main(int argc, char *argv[]) {
|
||||||
0, /* back pixel: black */
|
0, /* back pixel: black */
|
||||||
XCB_EVENT_MASK_EXPOSURE |
|
XCB_EVENT_MASK_EXPOSURE |
|
||||||
XCB_EVENT_MASK_BUTTON_PRESS});
|
XCB_EVENT_MASK_BUTTON_PRESS});
|
||||||
|
if (sncontext) {
|
||||||
|
sn_launchee_context_setup_window(sncontext, win);
|
||||||
|
}
|
||||||
|
|
||||||
/* Map the window (make it visible) */
|
/* Map the window (make it visible) */
|
||||||
xcb_map_window(conn, win);
|
xcb_map_window(conn, win);
|
||||||
|
@ -925,6 +951,12 @@ int main(int argc, char *argv[]) {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Startup complete. */
|
||||||
|
if (sncontext) {
|
||||||
|
sn_launchee_context_complete(sncontext);
|
||||||
|
sn_launchee_context_unref(sncontext);
|
||||||
|
}
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
xcb_generic_event_t *event;
|
xcb_generic_event_t *event;
|
||||||
|
@ -937,13 +969,12 @@ int main(int argc, char *argv[]) {
|
||||||
/* Strip off the highest bit (set if the event is generated) */
|
/* Strip off the highest bit (set if the event is generated) */
|
||||||
int type = (event->response_type & 0x7F);
|
int type = (event->response_type & 0x7F);
|
||||||
|
|
||||||
|
/* TODO: handle mappingnotify */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case XCB_KEY_PRESS:
|
case XCB_KEY_PRESS:
|
||||||
handle_key_press(NULL, conn, (xcb_key_press_event_t *)event);
|
handle_key_press(NULL, conn, (xcb_key_press_event_t *)event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* TODO: handle mappingnotify */
|
|
||||||
|
|
||||||
case XCB_BUTTON_PRESS:
|
case XCB_BUTTON_PRESS:
|
||||||
handle_button_press((xcb_button_press_event_t *)event);
|
handle_button_press((xcb_button_press_event_t *)event);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -156,7 +156,7 @@ static int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_rel
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finish_input() {
|
static void finish_input(void) {
|
||||||
char *command = (char *)concat_strings(glyphs_utf8, input_position);
|
char *command = (char *)concat_strings(glyphs_utf8, input_position);
|
||||||
|
|
||||||
/* count the occurrences of %s in the string */
|
/* count the occurrences of %s in the string */
|
||||||
|
|
|
@ -95,8 +95,10 @@ static int reply_start_map_cb(void *params) {
|
||||||
|
|
||||||
static int reply_end_map_cb(void *params) {
|
static int reply_end_map_cb(void *params) {
|
||||||
if (!last_reply.success) {
|
if (!last_reply.success) {
|
||||||
fprintf(stderr, "ERROR: Your command: %s\n", last_reply.input);
|
if (last_reply.input) {
|
||||||
fprintf(stderr, "ERROR: %s\n", last_reply.errorposition);
|
fprintf(stderr, "ERROR: Your command: %s\n", last_reply.input);
|
||||||
|
fprintf(stderr, "ERROR: %s\n", last_reply.errorposition);
|
||||||
|
}
|
||||||
fprintf(stderr, "ERROR: %s\n", last_reply.error);
|
fprintf(stderr, "ERROR: %s\n", last_reply.error);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -164,16 +166,18 @@ int main(int argc, char *argv[]) {
|
||||||
uint32_t message_type = I3_IPC_MESSAGE_TYPE_RUN_COMMAND;
|
uint32_t message_type = I3_IPC_MESSAGE_TYPE_RUN_COMMAND;
|
||||||
char *payload = NULL;
|
char *payload = NULL;
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
|
bool monitor = false;
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"socket", required_argument, 0, 's'},
|
{"socket", required_argument, 0, 's'},
|
||||||
{"type", required_argument, 0, 't'},
|
{"type", required_argument, 0, 't'},
|
||||||
{"version", no_argument, 0, 'v'},
|
{"version", no_argument, 0, 'v'},
|
||||||
{"quiet", no_argument, 0, 'q'},
|
{"quiet", no_argument, 0, 'q'},
|
||||||
|
{"monitor", no_argument, 0, 'm'},
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{0, 0, 0, 0}};
|
{0, 0, 0, 0}};
|
||||||
|
|
||||||
char *options_string = "s:t:vhq";
|
char *options_string = "s:t:vhqm";
|
||||||
|
|
||||||
while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
|
while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
|
||||||
if (o == 's') {
|
if (o == 's') {
|
||||||
|
@ -202,25 +206,34 @@ int main(int argc, char *argv[]) {
|
||||||
message_type = I3_IPC_MESSAGE_TYPE_GET_CONFIG;
|
message_type = I3_IPC_MESSAGE_TYPE_GET_CONFIG;
|
||||||
} else if (strcasecmp(optarg, "send_tick") == 0) {
|
} else if (strcasecmp(optarg, "send_tick") == 0) {
|
||||||
message_type = I3_IPC_MESSAGE_TYPE_SEND_TICK;
|
message_type = I3_IPC_MESSAGE_TYPE_SEND_TICK;
|
||||||
|
} else if (strcasecmp(optarg, "subscribe") == 0) {
|
||||||
|
message_type = I3_IPC_MESSAGE_TYPE_SUBSCRIBE;
|
||||||
} else {
|
} else {
|
||||||
printf("Unknown message type\n");
|
printf("Unknown message type\n");
|
||||||
printf("Known types: run_command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config, get_binding_modes, get_version, get_config, send_tick\n");
|
printf("Known types: run_command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config, get_binding_modes, get_version, get_config, send_tick, subscribe\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
} else if (o == 'q') {
|
} else if (o == 'q') {
|
||||||
quiet = true;
|
quiet = true;
|
||||||
|
} else if (o == 'm') {
|
||||||
|
monitor = true;
|
||||||
} else if (o == 'v') {
|
} else if (o == 'v') {
|
||||||
printf("i3-msg " I3_VERSION "\n");
|
printf("i3-msg " I3_VERSION "\n");
|
||||||
return 0;
|
return 0;
|
||||||
} else if (o == 'h') {
|
} else if (o == 'h') {
|
||||||
printf("i3-msg " I3_VERSION "\n");
|
printf("i3-msg " I3_VERSION "\n");
|
||||||
printf("i3-msg [-s <socket>] [-t <type>] <message>\n");
|
printf("i3-msg [-s <socket>] [-t <type>] [-m] <message>\n");
|
||||||
return 0;
|
return 0;
|
||||||
} else if (o == '?') {
|
} else if (o == '?') {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (monitor && message_type != I3_IPC_MESSAGE_TYPE_SUBSCRIBE) {
|
||||||
|
fprintf(stderr, "The monitor option -m is used with -t SUBSCRIBE exclusively.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Use all arguments, separated by whitespace, as payload.
|
/* Use all arguments, separated by whitespace, as payload.
|
||||||
* This way, you don’t have to do i3-msg 'mark foo', you can use
|
* This way, you don’t have to do i3-msg 'mark foo', you can use
|
||||||
* i3-msg mark foo */
|
* i3-msg mark foo */
|
||||||
|
@ -244,9 +257,6 @@ int main(int argc, char *argv[]) {
|
||||||
err(EXIT_FAILURE, "IPC: write()");
|
err(EXIT_FAILURE, "IPC: write()");
|
||||||
free(payload);
|
free(payload);
|
||||||
|
|
||||||
if (quiet)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint32_t reply_length;
|
uint32_t reply_length;
|
||||||
uint32_t reply_type;
|
uint32_t reply_type;
|
||||||
uint8_t *reply;
|
uint8_t *reply;
|
||||||
|
@ -273,8 +283,9 @@ int main(int argc, char *argv[]) {
|
||||||
errx(EXIT_FAILURE, "IPC: Could not parse JSON reply.");
|
errx(EXIT_FAILURE, "IPC: Could not parse JSON reply.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NB: We still fall-through and print the reply, because even if one
|
if (!quiet) {
|
||||||
* command failed, that doesn’t mean that all commands failed. */
|
printf("%.*s\n", reply_length, reply);
|
||||||
|
}
|
||||||
} else if (reply_type == I3_IPC_REPLY_TYPE_CONFIG) {
|
} else if (reply_type == I3_IPC_REPLY_TYPE_CONFIG) {
|
||||||
yajl_handle handle = yajl_alloc(&config_callbacks, NULL, NULL);
|
yajl_handle handle = yajl_alloc(&config_callbacks, NULL, NULL);
|
||||||
yajl_status state = yajl_parse(handle, (const unsigned char *)reply, reply_length);
|
yajl_status state = yajl_parse(handle, (const unsigned char *)reply, reply_length);
|
||||||
|
@ -287,12 +298,30 @@ int main(int argc, char *argv[]) {
|
||||||
case yajl_status_error:
|
case yajl_status_error:
|
||||||
errx(EXIT_FAILURE, "IPC: Could not parse JSON reply.");
|
errx(EXIT_FAILURE, "IPC: Could not parse JSON reply.");
|
||||||
}
|
}
|
||||||
|
} else if (reply_type == I3_IPC_REPLY_TYPE_SUBSCRIBE) {
|
||||||
|
do {
|
||||||
|
free(reply);
|
||||||
|
if ((ret = ipc_recv_message(sockfd, &reply_type, &reply_length, &reply)) != 0) {
|
||||||
|
if (ret == -1)
|
||||||
|
err(EXIT_FAILURE, "IPC: read()");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
goto exit;
|
if (!(reply_type & I3_IPC_EVENT_MASK)) {
|
||||||
|
errx(EXIT_FAILURE, "IPC: Received reply of type %d but expected an event", reply_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!quiet) {
|
||||||
|
fprintf(stdout, "%.*s\n", reply_length, reply);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
} while (monitor);
|
||||||
|
} else {
|
||||||
|
if (!quiet) {
|
||||||
|
printf("%.*s\n", reply_length, reply);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("%.*s\n", reply_length, reply);
|
|
||||||
|
|
||||||
exit:
|
|
||||||
free(reply);
|
free(reply);
|
||||||
|
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
|
|
|
@ -32,6 +32,9 @@
|
||||||
#include <xcb/randr.h>
|
#include <xcb/randr.h>
|
||||||
#include <xcb/xcb_cursor.h>
|
#include <xcb/xcb_cursor.h>
|
||||||
|
|
||||||
|
#define SN_API_NOT_YET_FROZEN 1
|
||||||
|
#include <libsn/sn-launchee.h>
|
||||||
|
|
||||||
#include "i3-nagbar.h"
|
#include "i3-nagbar.h"
|
||||||
|
|
||||||
/** This is the equivalent of XC_left_ptr. I’m not sure why xcb doesn’t have a
|
/** This is the equivalent of XC_left_ptr. I’m not sure why xcb doesn’t have a
|
||||||
|
@ -52,6 +55,7 @@ typedef struct {
|
||||||
char *action;
|
char *action;
|
||||||
int16_t x;
|
int16_t x;
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
|
bool terminal;
|
||||||
} button_t;
|
} button_t;
|
||||||
|
|
||||||
static xcb_window_t win;
|
static xcb_window_t win;
|
||||||
|
@ -99,10 +103,10 @@ void debuglog(char *fmt, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Starts the given application by passing it through a shell. We use double fork
|
* Starts the given application by passing it through a shell. We use double
|
||||||
* to avoid zombie processes. As the started application’s parent exits (immediately),
|
* fork to avoid zombie processes. As the started application’s parent exits
|
||||||
* the application is reparented to init (process-id 1), which correctly handles
|
* (immediately), the application is reparented to init (process-id 1), which
|
||||||
* childs, so we don’t have to do it :-).
|
* correctly handles children, so we don’t have to do it :-).
|
||||||
*
|
*
|
||||||
* The shell is determined by looking for the SHELL environment variable. If it
|
* The shell is determined by looking for the SHELL environment variable. If it
|
||||||
* does not exist, /bin/sh is used.
|
* does not exist, /bin/sh is used.
|
||||||
|
@ -115,7 +119,7 @@ static void start_application(const char *command) {
|
||||||
setsid();
|
setsid();
|
||||||
if (fork() == 0) {
|
if (fork() == 0) {
|
||||||
/* This is the child */
|
/* This is the child */
|
||||||
execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, (void *)NULL);
|
execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, NULL);
|
||||||
/* not reached */
|
/* not reached */
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -184,7 +188,11 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve
|
||||||
}
|
}
|
||||||
|
|
||||||
char *terminal_cmd;
|
char *terminal_cmd;
|
||||||
sasprintf(&terminal_cmd, "i3-sensible-terminal -e %s", link_path);
|
if (button->terminal) {
|
||||||
|
sasprintf(&terminal_cmd, "i3-sensible-terminal -e %s", link_path);
|
||||||
|
} else {
|
||||||
|
terminal_cmd = sstrdup(link_path);
|
||||||
|
}
|
||||||
printf("argv0 = %s\n", argv0);
|
printf("argv0 = %s\n", argv0);
|
||||||
printf("terminal_cmd = %s\n", terminal_cmd);
|
printf("terminal_cmd = %s\n", terminal_cmd);
|
||||||
|
|
||||||
|
@ -358,12 +366,13 @@ int main(int argc, char *argv[]) {
|
||||||
{"version", no_argument, 0, 'v'},
|
{"version", no_argument, 0, 'v'},
|
||||||
{"font", required_argument, 0, 'f'},
|
{"font", required_argument, 0, 'f'},
|
||||||
{"button", required_argument, 0, 'b'},
|
{"button", required_argument, 0, 'b'},
|
||||||
|
{"button-no-terminal", required_argument, 0, 'B'},
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{"message", required_argument, 0, 'm'},
|
{"message", required_argument, 0, 'm'},
|
||||||
{"type", required_argument, 0, 't'},
|
{"type", required_argument, 0, 't'},
|
||||||
{0, 0, 0, 0}};
|
{0, 0, 0, 0}};
|
||||||
|
|
||||||
char *options_string = "b:f:m:t:vh";
|
char *options_string = "b:B:f:m:t:vh";
|
||||||
|
|
||||||
prompt = i3string_from_utf8("Please do not run this program.");
|
prompt = i3string_from_utf8("Please do not run this program.");
|
||||||
|
|
||||||
|
@ -385,12 +394,14 @@ int main(int argc, char *argv[]) {
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
printf("i3-nagbar " I3_VERSION "\n");
|
printf("i3-nagbar " I3_VERSION "\n");
|
||||||
printf("i3-nagbar [-m <message>] [-b <button> <action>] [-t warning|error] [-f <font>] [-v]\n");
|
printf("i3-nagbar [-m <message>] [-b <button> <action>] [-B <button> <action>] [-t warning|error] [-f <font>] [-v]\n");
|
||||||
return 0;
|
return 0;
|
||||||
case 'b':
|
case 'b':
|
||||||
|
case 'B':
|
||||||
buttons = srealloc(buttons, sizeof(button_t) * (buttoncnt + 1));
|
buttons = srealloc(buttons, sizeof(button_t) * (buttoncnt + 1));
|
||||||
buttons[buttoncnt].label = i3string_from_utf8(optarg);
|
buttons[buttoncnt].label = i3string_from_utf8(optarg);
|
||||||
buttons[buttoncnt].action = argv[optind];
|
buttons[buttoncnt].action = argv[optind];
|
||||||
|
buttons[buttoncnt].terminal = (o == 'b');
|
||||||
printf("button with label *%s* and action *%s*\n",
|
printf("button with label *%s* and action *%s*\n",
|
||||||
i3string_as_utf8(buttons[buttoncnt].label),
|
i3string_as_utf8(buttons[buttoncnt].label),
|
||||||
buttons[buttoncnt].action);
|
buttons[buttoncnt].action);
|
||||||
|
@ -415,6 +426,11 @@ int main(int argc, char *argv[]) {
|
||||||
#include "atoms.xmacro"
|
#include "atoms.xmacro"
|
||||||
#undef xmacro
|
#undef xmacro
|
||||||
|
|
||||||
|
/* Init startup notification. */
|
||||||
|
SnDisplay *sndisplay = sn_xcb_display_new(conn, NULL, NULL);
|
||||||
|
SnLauncheeContext *sncontext = sn_launchee_context_new_from_environment(sndisplay, screens);
|
||||||
|
sn_display_unref(sndisplay);
|
||||||
|
|
||||||
root_screen = xcb_aux_get_screen(conn, screens);
|
root_screen = xcb_aux_get_screen(conn, screens);
|
||||||
root = root_screen->root;
|
root = root_screen->root;
|
||||||
|
|
||||||
|
@ -484,6 +500,9 @@ int main(int argc, char *argv[]) {
|
||||||
XCB_EVENT_MASK_BUTTON_PRESS |
|
XCB_EVENT_MASK_BUTTON_PRESS |
|
||||||
XCB_EVENT_MASK_BUTTON_RELEASE,
|
XCB_EVENT_MASK_BUTTON_RELEASE,
|
||||||
cursor});
|
cursor});
|
||||||
|
if (sncontext) {
|
||||||
|
sn_launchee_context_setup_window(sncontext, win);
|
||||||
|
}
|
||||||
|
|
||||||
/* Map the window (make it visible) */
|
/* Map the window (make it visible) */
|
||||||
xcb_map_window(conn, win);
|
xcb_map_window(conn, win);
|
||||||
|
@ -544,6 +563,12 @@ int main(int argc, char *argv[]) {
|
||||||
/* Initialize the drawable bar */
|
/* Initialize the drawable bar */
|
||||||
draw_util_surface_init(conn, &bar, win, get_visualtype(root_screen), win_pos.width, win_pos.height);
|
draw_util_surface_init(conn, &bar, win, get_visualtype(root_screen), win_pos.width, win_pos.height);
|
||||||
|
|
||||||
|
/* Startup complete. */
|
||||||
|
if (sncontext) {
|
||||||
|
sn_launchee_context_complete(sncontext);
|
||||||
|
sn_launchee_context_unref(sncontext);
|
||||||
|
}
|
||||||
|
|
||||||
/* Grab the keyboard to get all input */
|
/* Grab the keyboard to get all input */
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
|
|
|
@ -123,9 +123,7 @@ sub strip_containers {
|
||||||
delete $tree->{current_border_width} if $tree->{current_border_width} == -1;
|
delete $tree->{current_border_width} if $tree->{current_border_width} == -1;
|
||||||
|
|
||||||
for my $key (keys %$tree) {
|
for my $key (keys %$tree) {
|
||||||
next if exists($allowed_keys{$key});
|
delete $tree->{$key} unless exists($allowed_keys{$key});
|
||||||
|
|
||||||
delete $tree->{$key};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for my $key (qw(nodes floating_nodes)) {
|
for my $key (qw(nodes floating_nodes)) {
|
||||||
|
@ -169,7 +167,8 @@ sub dump_containers {
|
||||||
if (leaf_node($tree)) {
|
if (leaf_node($tree)) {
|
||||||
my $swallows = {};
|
my $swallows = {};
|
||||||
for my $property (keys %{$tree->{window_properties}}) {
|
for my $property (keys %{$tree->{window_properties}}) {
|
||||||
$swallows->{$property} = '^' . quotemeta($tree->{window_properties}->{$property}) . '$';
|
$swallows->{$property} = '^' . quotemeta($tree->{window_properties}->{$property}) . '$'
|
||||||
|
if $property ne 'transient_for';
|
||||||
}
|
}
|
||||||
$tree->{swallows} = [ $swallows ];
|
$tree->{swallows} = [ $swallows ];
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# We welcome patches that add distribution-specific mechanisms to find the
|
# We welcome patches that add distribution-specific mechanisms to find the
|
||||||
# preferred terminal emulator. On Debian, there is the x-terminal-emulator
|
# preferred terminal emulator. On Debian, there is the x-terminal-emulator
|
||||||
# symlink for example.
|
# symlink for example.
|
||||||
for terminal in "$TERMINAL" x-terminal-emulator urxvt rxvt termit terminator Eterm aterm uxterm xterm gnome-terminal roxterm xfce4-terminal termite lxterminal mate-terminal terminology st qterminal lilyterm tilix terminix konsole kitty guake tilda; do
|
for terminal in "$TERMINAL" x-terminal-emulator urxvt rxvt termit terminator Eterm aterm uxterm xterm gnome-terminal roxterm xfce4-terminal termite lxterminal mate-terminal terminology st qterminal lilyterm tilix terminix konsole kitty guake tilda alacritty hyper; do
|
||||||
if command -v "$terminal" > /dev/null 2>&1; then
|
if command -v "$terminal" > /dev/null 2>&1; then
|
||||||
exec "$terminal" "$@"
|
exec "$terminal" "$@"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -31,7 +31,7 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
int stop_signal;
|
int stop_signal;
|
||||||
/**
|
/**
|
||||||
* The signal requested by the client to inform it of theun hidden state of i3bar
|
* The signal requested by the client to inform it of the unhidden state of i3bar
|
||||||
*/
|
*/
|
||||||
int cont_signal;
|
int cont_signal;
|
||||||
|
|
||||||
|
@ -85,4 +85,4 @@ bool child_want_click_events(void);
|
||||||
* Generates a click event, if enabled.
|
* Generates a click event, if enabled.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void send_block_clicked(int button, const char *name, const char *instance, int x, int y, int x_rel, int y_rel, int width, int height);
|
void send_block_clicked(int button, const char *name, const char *instance, int x, int y, int x_rel, int y_rel, int width, int height, int mods);
|
||||||
|
|
|
@ -41,17 +41,18 @@ typedef struct tray_output_t {
|
||||||
} tray_output_t;
|
} tray_output_t;
|
||||||
|
|
||||||
typedef struct config_t {
|
typedef struct config_t {
|
||||||
int modifier;
|
uint32_t modifier;
|
||||||
|
|
||||||
TAILQ_HEAD(bindings_head, binding_t)
|
TAILQ_HEAD(bindings_head, binding_t)
|
||||||
bindings;
|
bindings;
|
||||||
|
|
||||||
position_t position;
|
position_t position;
|
||||||
int verbose;
|
bool verbose;
|
||||||
struct xcb_color_strings_t colors;
|
struct xcb_color_strings_t colors;
|
||||||
bool disable_binding_mode_indicator;
|
bool disable_binding_mode_indicator;
|
||||||
bool disable_ws;
|
bool disable_ws;
|
||||||
bool strip_ws_numbers;
|
bool strip_ws_numbers;
|
||||||
|
bool strip_ws_name;
|
||||||
char *bar_id;
|
char *bar_id;
|
||||||
char *command;
|
char *command;
|
||||||
char *fontname;
|
char *fontname;
|
||||||
|
|
|
@ -60,7 +60,7 @@ int separator_symbol_width;
|
||||||
* depend on 'config'.
|
* depend on 'config'.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
char *init_xcb_early();
|
char *init_xcb_early(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialization which depends on 'config' being usable. Called after the
|
* Initialization which depends on 'config' being usable. Called after the
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "yajl_utils.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -27,6 +28,8 @@
|
||||||
#include <yajl/yajl_gen.h>
|
#include <yajl/yajl_gen.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
|
||||||
|
#include <xcb/xcb_keysyms.h>
|
||||||
|
|
||||||
/* Global variables for child_*() */
|
/* Global variables for child_*() */
|
||||||
i3bar_child child;
|
i3bar_child child;
|
||||||
|
|
||||||
|
@ -133,7 +136,7 @@ finish:
|
||||||
* Stop and free() the stdin- and SIGCHLD-watchers
|
* Stop and free() the stdin- and SIGCHLD-watchers
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void cleanup(void) {
|
static void cleanup(void) {
|
||||||
if (stdin_io != NULL) {
|
if (stdin_io != NULL) {
|
||||||
ev_io_stop(main_loop, stdin_io);
|
ev_io_stop(main_loop, stdin_io);
|
||||||
FREE(stdin_io);
|
FREE(stdin_io);
|
||||||
|
@ -400,7 +403,7 @@ static bool read_json_input(unsigned char *input, int length) {
|
||||||
* in statusline
|
* in statusline
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
static void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
||||||
int rec;
|
int rec;
|
||||||
unsigned char *buffer = get_buffer(watcher, &rec);
|
unsigned char *buffer = get_buffer(watcher, &rec);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
|
@ -420,7 +423,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
||||||
* whether this is JSON or plain text
|
* whether this is JSON or plain text
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
static void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
||||||
int rec;
|
int rec;
|
||||||
unsigned char *buffer = get_buffer(watcher, &rec);
|
unsigned char *buffer = get_buffer(watcher, &rec);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
|
@ -457,7 +460,7 @@ void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
||||||
* anymore
|
* anymore
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) {
|
static void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) {
|
||||||
int exit_status = WEXITSTATUS(watcher->rstatus);
|
int exit_status = WEXITSTATUS(watcher->rstatus);
|
||||||
|
|
||||||
ELOG("Child (pid: %d) unexpectedly exited with status %d\n",
|
ELOG("Child (pid: %d) unexpectedly exited with status %d\n",
|
||||||
|
@ -477,7 +480,7 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) {
|
||||||
draw_bars(false);
|
draw_bars(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void child_write_output(void) {
|
static void child_write_output(void) {
|
||||||
if (child.click_events) {
|
if (child.click_events) {
|
||||||
const unsigned char *output;
|
const unsigned char *output;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -580,7 +583,7 @@ void start_child(char *command) {
|
||||||
atexit(kill_child_at_exit);
|
atexit(kill_child_at_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void child_click_events_initialize(void) {
|
static void child_click_events_initialize(void) {
|
||||||
if (!child.click_events_init) {
|
if (!child.click_events_init) {
|
||||||
yajl_gen_array_open(gen);
|
yajl_gen_array_open(gen);
|
||||||
child_write_output();
|
child_write_output();
|
||||||
|
@ -588,15 +591,11 @@ void child_click_events_initialize(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void child_click_events_key(const char *key) {
|
|
||||||
yajl_gen_string(gen, (const unsigned char *)key, strlen(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generates a click event, if enabled.
|
* Generates a click event, if enabled.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void send_block_clicked(int button, const char *name, const char *instance, int x, int y, int x_rel, int y_rel, int width, int height) {
|
void send_block_clicked(int button, const char *name, const char *instance, int x, int y, int x_rel, int y_rel, int width, int height, int mods) {
|
||||||
if (!child.click_events) {
|
if (!child.click_events) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -606,34 +605,52 @@ void send_block_clicked(int button, const char *name, const char *instance, int
|
||||||
yajl_gen_map_open(gen);
|
yajl_gen_map_open(gen);
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
child_click_events_key("name");
|
ystr("name");
|
||||||
yajl_gen_string(gen, (const unsigned char *)name, strlen(name));
|
ystr(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
child_click_events_key("instance");
|
ystr("instance");
|
||||||
yajl_gen_string(gen, (const unsigned char *)instance, strlen(instance));
|
ystr(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
child_click_events_key("button");
|
ystr("button");
|
||||||
yajl_gen_integer(gen, button);
|
yajl_gen_integer(gen, button);
|
||||||
|
|
||||||
child_click_events_key("x");
|
ystr("modifiers");
|
||||||
|
yajl_gen_array_open(gen);
|
||||||
|
if (mods & XCB_MOD_MASK_SHIFT)
|
||||||
|
ystr("Shift");
|
||||||
|
if (mods & XCB_MOD_MASK_CONTROL)
|
||||||
|
ystr("Control");
|
||||||
|
if (mods & XCB_MOD_MASK_1)
|
||||||
|
ystr("Mod1");
|
||||||
|
if (mods & XCB_MOD_MASK_2)
|
||||||
|
ystr("Mod2");
|
||||||
|
if (mods & XCB_MOD_MASK_3)
|
||||||
|
ystr("Mod3");
|
||||||
|
if (mods & XCB_MOD_MASK_4)
|
||||||
|
ystr("Mod4");
|
||||||
|
if (mods & XCB_MOD_MASK_5)
|
||||||
|
ystr("Mod5");
|
||||||
|
yajl_gen_array_close(gen);
|
||||||
|
|
||||||
|
ystr("x");
|
||||||
yajl_gen_integer(gen, x);
|
yajl_gen_integer(gen, x);
|
||||||
|
|
||||||
child_click_events_key("y");
|
ystr("y");
|
||||||
yajl_gen_integer(gen, y);
|
yajl_gen_integer(gen, y);
|
||||||
|
|
||||||
child_click_events_key("relative_x");
|
ystr("relative_x");
|
||||||
yajl_gen_integer(gen, x_rel);
|
yajl_gen_integer(gen, x_rel);
|
||||||
|
|
||||||
child_click_events_key("relative_y");
|
ystr("relative_y");
|
||||||
yajl_gen_integer(gen, y_rel);
|
yajl_gen_integer(gen, y_rel);
|
||||||
|
|
||||||
child_click_events_key("width");
|
ystr("width");
|
||||||
yajl_gen_integer(gen, width);
|
yajl_gen_integer(gen, width);
|
||||||
|
|
||||||
child_click_events_key("height");
|
ystr("height");
|
||||||
yajl_gen_integer(gen, height);
|
yajl_gen_integer(gen, height);
|
||||||
|
|
||||||
yajl_gen_map_close(gen);
|
yajl_gen_map_close(gen);
|
||||||
|
|
|
@ -119,6 +119,7 @@ static int config_string_cb(void *params_, const unsigned char *val, size_t _len
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Kept for backwards compatibility. */
|
||||||
if (!strcmp(cur_key, "modifier")) {
|
if (!strcmp(cur_key, "modifier")) {
|
||||||
DLOG("modifier = %.*s\n", len, val);
|
DLOG("modifier = %.*s\n", len, val);
|
||||||
if (len == strlen("none") && !strncmp((const char *)val, "none", strlen("none"))) {
|
if (len == strlen("none") && !strncmp((const char *)val, "none", strlen("none"))) {
|
||||||
|
@ -297,9 +298,17 @@ static int config_boolean_cb(void *params_, int val) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(cur_key, "strip_workspace_name")) {
|
||||||
|
DLOG("strip_workspace_name = %d\n", val);
|
||||||
|
config.strip_ws_name = val;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(cur_key, "verbose")) {
|
if (!strcmp(cur_key, "verbose")) {
|
||||||
DLOG("verbose = %d\n", val);
|
if (!config.verbose) {
|
||||||
config.verbose = val;
|
DLOG("verbose = %d\n", val);
|
||||||
|
config.verbose = val;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,6 +339,12 @@ static int config_integer_cb(void *params_, long long val) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(cur_key, "modifier")) {
|
||||||
|
DLOG("modifier = %lld\n", val);
|
||||||
|
config.modifier = (uint32_t)val;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ typedef void (*handler_t)(char *);
|
||||||
* Since i3 does not give us much feedback on commands, we do not much
|
* Since i3 does not give us much feedback on commands, we do not much
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_command_reply(char *reply) {
|
static void got_command_reply(char *reply) {
|
||||||
/* TODO: Error handling for command replies */
|
/* TODO: Error handling for command replies */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ void got_command_reply(char *reply) {
|
||||||
* Called, when we get a reply with workspaces data
|
* Called, when we get a reply with workspaces data
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_workspace_reply(char *reply) {
|
static void got_workspace_reply(char *reply) {
|
||||||
DLOG("Got workspace data!\n");
|
DLOG("Got workspace data!\n");
|
||||||
parse_workspaces_json(reply);
|
parse_workspaces_json(reply);
|
||||||
draw_bars(false);
|
draw_bars(false);
|
||||||
|
@ -53,7 +53,7 @@ void got_workspace_reply(char *reply) {
|
||||||
* Since i3 does not give us much feedback on commands, we do not much
|
* Since i3 does not give us much feedback on commands, we do not much
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_subscribe_reply(char *reply) {
|
static void got_subscribe_reply(char *reply) {
|
||||||
DLOG("Got subscribe reply: %s\n", reply);
|
DLOG("Got subscribe reply: %s\n", reply);
|
||||||
/* TODO: Error handling for subscribe commands */
|
/* TODO: Error handling for subscribe commands */
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ void got_subscribe_reply(char *reply) {
|
||||||
* Called, when we get a reply with outputs data
|
* Called, when we get a reply with outputs data
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_output_reply(char *reply) {
|
static void got_output_reply(char *reply) {
|
||||||
DLOG("Clearing old output configuration...\n");
|
DLOG("Clearing old output configuration...\n");
|
||||||
free_outputs();
|
free_outputs();
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ void got_output_reply(char *reply) {
|
||||||
* Called when we get the configuration for our bar instance
|
* Called when we get the configuration for our bar instance
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_bar_config(char *reply) {
|
static void got_bar_config(char *reply) {
|
||||||
DLOG("Received bar config \"%s\"\n", reply);
|
DLOG("Received bar config \"%s\"\n", reply);
|
||||||
/* We initiate the main function by requesting infos about the outputs and
|
/* We initiate the main function by requesting infos about the outputs and
|
||||||
* workspaces. Everything else (creating the bars, showing the right workspace-
|
* workspaces. Everything else (creating the bars, showing the right workspace-
|
||||||
|
@ -114,20 +114,25 @@ void got_bar_config(char *reply) {
|
||||||
|
|
||||||
/* Data structure to easily call the reply handlers later */
|
/* Data structure to easily call the reply handlers later */
|
||||||
handler_t reply_handlers[] = {
|
handler_t reply_handlers[] = {
|
||||||
&got_command_reply,
|
&got_command_reply, /* I3_IPC_REPLY_TYPE_COMMAND */
|
||||||
&got_workspace_reply,
|
&got_workspace_reply, /* I3_IPC_REPLY_TYPE_WORKSPACES */
|
||||||
&got_subscribe_reply,
|
&got_subscribe_reply, /* I3_IPC_REPLY_TYPE_SUBSCRIBE */
|
||||||
&got_output_reply,
|
&got_output_reply, /* I3_IPC_REPLY_TYPE_OUTPUTS */
|
||||||
NULL,
|
NULL, /* I3_IPC_REPLY_TYPE_TREE */
|
||||||
NULL,
|
NULL, /* I3_IPC_REPLY_TYPE_MARKS */
|
||||||
&got_bar_config,
|
&got_bar_config, /* I3_IPC_REPLY_TYPE_BAR_CONFIG */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_VERSION */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_BINDING_MODES */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_CONFIG */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_TICK */
|
||||||
|
NULL, /* I3_IPC_REPLY_TYPE_SYNC */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called, when a workspace event arrives (i.e. the user changed the workspace)
|
* Called, when a workspace event arrives (i.e. the user changed the workspace)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_workspace_event(char *event) {
|
static void got_workspace_event(char *event) {
|
||||||
DLOG("Got workspace event!\n");
|
DLOG("Got workspace event!\n");
|
||||||
i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
|
i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
|
||||||
}
|
}
|
||||||
|
@ -136,7 +141,7 @@ void got_workspace_event(char *event) {
|
||||||
* Called, when an output event arrives (i.e. the screen configuration changed)
|
* Called, when an output event arrives (i.e. the screen configuration changed)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_output_event(char *event) {
|
static void got_output_event(char *event) {
|
||||||
DLOG("Got output event!\n");
|
DLOG("Got output event!\n");
|
||||||
i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL);
|
i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL);
|
||||||
if (!config.disable_ws) {
|
if (!config.disable_ws) {
|
||||||
|
@ -148,7 +153,7 @@ void got_output_event(char *event) {
|
||||||
* Called, when a mode event arrives (i3 changed binding mode).
|
* Called, when a mode event arrives (i3 changed binding mode).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_mode_event(char *event) {
|
static void got_mode_event(char *event) {
|
||||||
DLOG("Got mode event!\n");
|
DLOG("Got mode event!\n");
|
||||||
parse_mode_json(event);
|
parse_mode_json(event);
|
||||||
draw_bars(false);
|
draw_bars(false);
|
||||||
|
@ -158,7 +163,7 @@ void got_mode_event(char *event) {
|
||||||
* Called, when a barconfig_update event arrives (i.e. i3 changed the bar hidden_state or mode)
|
* Called, when a barconfig_update event arrives (i.e. i3 changed the bar hidden_state or mode)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_bar_config_update(char *event) {
|
static void got_bar_config_update(char *event) {
|
||||||
/* check whether this affect this bar instance by checking the bar_id */
|
/* check whether this affect this bar instance by checking the bar_id */
|
||||||
char *expected_id;
|
char *expected_id;
|
||||||
sasprintf(&expected_id, "\"id\":\"%s\"", config.bar_id);
|
sasprintf(&expected_id, "\"id\":\"%s\"", config.bar_id);
|
||||||
|
@ -208,7 +213,7 @@ handler_t event_handlers[] = {
|
||||||
* Called, when we get a message from i3
|
* Called, when we get a message from i3
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
|
static void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
|
||||||
DLOG("Got data!\n");
|
DLOG("Got data!\n");
|
||||||
int fd = watcher->fd;
|
int fd = watcher->fd;
|
||||||
|
|
||||||
|
@ -273,8 +278,8 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
|
||||||
buffer[size] = '\0';
|
buffer[size] = '\0';
|
||||||
|
|
||||||
/* And call the callback (indexed by the type) */
|
/* And call the callback (indexed by the type) */
|
||||||
if (type & (1 << 31)) {
|
if (type & (1UL << 31)) {
|
||||||
type ^= 1 << 31;
|
type ^= 1UL << 31;
|
||||||
event_handlers[type](buffer);
|
event_handlers[type](buffer);
|
||||||
} else {
|
} else {
|
||||||
if (reply_handlers[type])
|
if (reply_handlers[type])
|
||||||
|
@ -304,7 +309,7 @@ int i3_send_msg(uint32_t type, const char *payload) {
|
||||||
char *buffer = smalloc(to_write);
|
char *buffer = smalloc(to_write);
|
||||||
char *walk = buffer;
|
char *walk = buffer;
|
||||||
|
|
||||||
strncpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC));
|
memcpy(buffer, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC));
|
||||||
walk += strlen(I3_IPC_MAGIC);
|
walk += strlen(I3_IPC_MAGIC);
|
||||||
memcpy(walk, &len, sizeof(uint32_t));
|
memcpy(walk, &len, sizeof(uint32_t));
|
||||||
walk += sizeof(uint32_t);
|
walk += sizeof(uint32_t);
|
||||||
|
|
|
@ -44,7 +44,7 @@ void debuglog(char *fmt, ...) {
|
||||||
* Glob path, i.e. expand ~
|
* Glob path, i.e. expand ~
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
char *expand_path(char *path) {
|
static char *expand_path(char *path) {
|
||||||
static glob_t globbuf;
|
static glob_t globbuf;
|
||||||
if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) {
|
if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) {
|
||||||
ELOG("glob() failed\n");
|
ELOG("glob() failed\n");
|
||||||
|
@ -55,13 +55,14 @@ char *expand_path(char *path) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_usage(char *elf_name) {
|
static void print_usage(char *elf_name) {
|
||||||
printf("Usage: %s -b bar_id [-s sock_path] [-h] [-v]\n", elf_name);
|
printf("Usage: %s -b bar_id [-s sock_path] [-h] [-v]\n", elf_name);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("-b, --bar_id <bar_id>\tBar ID for which to get the configuration\n");
|
printf("-b, --bar_id <bar_id>\tBar ID for which to get the configuration\n");
|
||||||
printf("-s, --socket <sock_path>\tConnect to i3 via <sock_path>\n");
|
printf("-s, --socket <sock_path>\tConnect to i3 via <sock_path>\n");
|
||||||
printf("-h, --help Display this help message and exit\n");
|
printf("-h, --help Display this help message and exit\n");
|
||||||
printf("-v, --version Display version number and exit\n");
|
printf("-v, --version Display version number and exit\n");
|
||||||
|
printf("-V, --verbose Enable verbose mode\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" PLEASE NOTE that i3bar will be automatically started by i3\n"
|
printf(" PLEASE NOTE that i3bar will be automatically started by i3\n"
|
||||||
" as soon as there is a 'bar' configuration block in your\n"
|
" as soon as there is a 'bar' configuration block in your\n"
|
||||||
|
@ -75,7 +76,7 @@ void print_usage(char *elf_name) {
|
||||||
* in main() with that
|
* in main() with that
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void sig_cb(struct ev_loop *loop, ev_signal *watcher, int revents) {
|
static void sig_cb(struct ev_loop *loop, ev_signal *watcher, int revents) {
|
||||||
switch (watcher->signum) {
|
switch (watcher->signum) {
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
DLOG("Got a SIGTERM, stopping\n");
|
DLOG("Got a SIGTERM, stopping\n");
|
||||||
|
@ -106,9 +107,10 @@ int main(int argc, char **argv) {
|
||||||
{"bar_id", required_argument, 0, 'b'},
|
{"bar_id", required_argument, 0, 'b'},
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{"version", no_argument, 0, 'v'},
|
{"version", no_argument, 0, 'v'},
|
||||||
|
{"verbose", no_argument, 0, 'V'},
|
||||||
{NULL, 0, 0, 0}};
|
{NULL, 0, 0, 0}};
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "b:s:hv", long_opt, &option_index)) != -1) {
|
while ((opt = getopt_long(argc, argv, "b:s:hvV", long_opt, &option_index)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 's':
|
case 's':
|
||||||
socket_path = expand_path(optarg);
|
socket_path = expand_path(optarg);
|
||||||
|
@ -120,6 +122,9 @@ int main(int argc, char **argv) {
|
||||||
case 'b':
|
case 'b':
|
||||||
config.bar_id = sstrdup(optarg);
|
config.bar_id = sstrdup(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'V':
|
||||||
|
config.verbose = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|
|
@ -106,8 +106,8 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, size_t
|
||||||
const char *ws_name = (const char *)val;
|
const char *ws_name = (const char *)val;
|
||||||
params->workspaces_walk->canonical_name = sstrndup(ws_name, len);
|
params->workspaces_walk->canonical_name = sstrndup(ws_name, len);
|
||||||
|
|
||||||
if (config.strip_ws_numbers && params->workspaces_walk->num >= 0) {
|
if ((config.strip_ws_numbers || config.strip_ws_name) && params->workspaces_walk->num >= 0) {
|
||||||
/* Special case: strip off the workspace number */
|
/* Special case: strip off the workspace number/name */
|
||||||
static char ws_num[10];
|
static char ws_num[10];
|
||||||
|
|
||||||
snprintf(ws_num, sizeof(ws_num), "%d", params->workspaces_walk->num);
|
snprintf(ws_num, sizeof(ws_num), "%d", params->workspaces_walk->num);
|
||||||
|
@ -119,11 +119,14 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, size_t
|
||||||
if (offset && ws_name[offset] == ':')
|
if (offset && ws_name[offset] == ':')
|
||||||
offset += 1;
|
offset += 1;
|
||||||
|
|
||||||
/* Offset may be equal to length, in which case display the number */
|
if (config.strip_ws_numbers) {
|
||||||
params->workspaces_walk->name = (offset < len
|
/* Offset may be equal to length, in which case display the number */
|
||||||
? i3string_from_markup_with_length(ws_name + offset, len - offset)
|
params->workspaces_walk->name = (offset < len
|
||||||
: i3string_from_markup(ws_num));
|
? i3string_from_markup_with_length(ws_name + offset, len - offset)
|
||||||
|
: i3string_from_markup(ws_num));
|
||||||
|
} else {
|
||||||
|
params->workspaces_walk->name = i3string_from_markup(ws_num);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Default case: just save the name */
|
/* Default case: just save the name */
|
||||||
params->workspaces_walk->name = i3string_from_markup_with_length(ws_name, len);
|
params->workspaces_walk->name = i3string_from_markup_with_length(ws_name, len);
|
||||||
|
|
295
i3bar/src/xcb.c
295
i3bar/src/xcb.c
|
@ -79,7 +79,7 @@ int bar_height;
|
||||||
|
|
||||||
/* These are only relevant for XKB, which we only need for grabbing modifiers */
|
/* These are only relevant for XKB, which we only need for grabbing modifiers */
|
||||||
int xkb_base;
|
int xkb_base;
|
||||||
int mod_pressed = 0;
|
bool mod_pressed = 0;
|
||||||
|
|
||||||
/* Event watchers, to interact with the user */
|
/* Event watchers, to interact with the user */
|
||||||
ev_prepare *xcb_prep;
|
ev_prepare *xcb_prep;
|
||||||
|
@ -92,6 +92,9 @@ static mode binding;
|
||||||
/* Indicates whether a new binding mode was recently activated */
|
/* Indicates whether a new binding mode was recently activated */
|
||||||
bool activated_mode = false;
|
bool activated_mode = false;
|
||||||
|
|
||||||
|
/* The output in which the tray should be displayed. */
|
||||||
|
static i3_output *output_for_tray;
|
||||||
|
|
||||||
/* The parsed colors */
|
/* The parsed colors */
|
||||||
struct xcb_colors_t {
|
struct xcb_colors_t {
|
||||||
color_t bar_fg;
|
color_t bar_fg;
|
||||||
|
@ -146,13 +149,13 @@ int _xcb_request_failed(xcb_void_cookie_t cookie, char *err_msg, int line) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_sep_offset(struct status_block *block) {
|
static uint32_t get_sep_offset(struct status_block *block) {
|
||||||
if (!block->no_separator && block->sep_block_width > 0)
|
if (!block->no_separator && block->sep_block_width > 0)
|
||||||
return block->sep_block_width / 2 + block->sep_block_width % 2;
|
return block->sep_block_width / 2 + block->sep_block_width % 2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_tray_width(struct tc_head *trayclients) {
|
static int get_tray_width(struct tc_head *trayclients) {
|
||||||
trayclient *trayclient;
|
trayclient *trayclient;
|
||||||
int tray_width = 0;
|
int tray_width = 0;
|
||||||
TAILQ_FOREACH_REVERSE(trayclient, trayclients, tc_head, tailq) {
|
TAILQ_FOREACH_REVERSE(trayclient, trayclients, tc_head, tailq) {
|
||||||
|
@ -193,7 +196,7 @@ static void draw_separator(i3_output *output, uint32_t x, struct status_block *b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t predict_statusline_length(bool use_short_text) {
|
static uint32_t predict_statusline_length(bool use_short_text) {
|
||||||
uint32_t width = 0;
|
uint32_t width = 0;
|
||||||
struct status_block *block;
|
struct status_block *block;
|
||||||
|
|
||||||
|
@ -245,7 +248,7 @@ uint32_t predict_statusline_length(bool use_short_text) {
|
||||||
/*
|
/*
|
||||||
* Redraws the statusline to the output's statusline_buffer
|
* Redraws the statusline to the output's statusline_buffer
|
||||||
*/
|
*/
|
||||||
void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_colors, bool use_short_text) {
|
static void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_colors, bool use_short_text) {
|
||||||
struct status_block *block;
|
struct status_block *block;
|
||||||
|
|
||||||
color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg);
|
color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg);
|
||||||
|
@ -330,7 +333,7 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_color
|
||||||
* Hides all bars (unmaps them)
|
* Hides all bars (unmaps them)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void hide_bars(void) {
|
static void hide_bars(void) {
|
||||||
if ((config.hide_on_modifier == M_DOCK) || (config.hidden_state == S_SHOW && config.hide_on_modifier == M_HIDE)) {
|
if ((config.hide_on_modifier == M_DOCK) || (config.hidden_state == S_SHOW && config.hide_on_modifier == M_HIDE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -349,7 +352,7 @@ void hide_bars(void) {
|
||||||
* Unhides all bars (maps them)
|
* Unhides all bars (maps them)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void unhide_bars(void) {
|
static void unhide_bars(void) {
|
||||||
if (config.hide_on_modifier != M_HIDE) {
|
if (config.hide_on_modifier != M_HIDE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -457,7 +460,7 @@ static bool execute_custom_command(xcb_keycode_t input_code, bool event_is_relea
|
||||||
* wheel was used and change the workspace appropriately
|
* wheel was used and change the workspace appropriately
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void handle_button(xcb_button_press_event_t *event) {
|
static void handle_button(xcb_button_press_event_t *event) {
|
||||||
/* Determine, which bar was clicked */
|
/* Determine, which bar was clicked */
|
||||||
i3_output *walk;
|
i3_output *walk;
|
||||||
xcb_window_t bar = event->event;
|
xcb_window_t bar = event->event;
|
||||||
|
@ -500,13 +503,12 @@ void handle_button(xcb_button_press_event_t *event) {
|
||||||
/* If the child asked for click events,
|
/* If the child asked for click events,
|
||||||
* check if a status block has been clicked. */
|
* check if a status block has been clicked. */
|
||||||
int tray_width = get_tray_width(walk->trayclients);
|
int tray_width = get_tray_width(walk->trayclients);
|
||||||
int block_x = 0, last_block_x;
|
int last_block_x = 0;
|
||||||
int offset = walk->rect.w - walk->statusline_width - tray_width - logical_px(sb_hoff_px);
|
int offset = walk->rect.w - walk->statusline_width - tray_width - logical_px((tray_width > 0) * sb_hoff_px);
|
||||||
int32_t statusline_x = x - offset;
|
int32_t statusline_x = x - offset;
|
||||||
|
|
||||||
if (statusline_x >= 0 && statusline_x < walk->statusline_width) {
|
if (statusline_x >= 0 && statusline_x < walk->statusline_width) {
|
||||||
struct status_block *block;
|
struct status_block *block;
|
||||||
int sep_offset_remainder = 0;
|
|
||||||
|
|
||||||
TAILQ_FOREACH(block, &statusline_head, blocks) {
|
TAILQ_FOREACH(block, &statusline_head, blocks) {
|
||||||
i3String *text = block->full_text;
|
i3String *text = block->full_text;
|
||||||
|
@ -519,16 +521,15 @@ void handle_button(xcb_button_press_event_t *event) {
|
||||||
if (i3string_get_num_bytes(text) == 0)
|
if (i3string_get_num_bytes(text) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
last_block_x = block_x;
|
const int relative_x = statusline_x - last_block_x;
|
||||||
block_x += render->width + render->x_offset + render->x_append + get_sep_offset(block) + sep_offset_remainder;
|
if (relative_x >= 0 && (uint32_t)relative_x <= render->width) {
|
||||||
|
|
||||||
if (statusline_x <= block_x && statusline_x >= last_block_x) {
|
|
||||||
send_block_clicked(event->detail, block->name, block->instance,
|
send_block_clicked(event->detail, block->name, block->instance,
|
||||||
event->root_x, event->root_y, statusline_x - last_block_x, event->event_y, block_x - last_block_x, bar_height);
|
event->root_x, event->root_y, relative_x, event->event_y, render->width, bar_height,
|
||||||
|
event->state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sep_offset_remainder = block->sep_block_width - get_sep_offset(block);
|
last_block_x += render->width + render->x_append + render->x_offset + block->sep_block_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -604,7 +605,7 @@ void handle_button(xcb_button_press_event_t *event) {
|
||||||
|
|
||||||
const size_t len = namelen + strlen("workspace \"\"") + 1;
|
const size_t len = namelen + strlen("workspace \"\"") + 1;
|
||||||
char *buffer = scalloc(len + num_quotes, 1);
|
char *buffer = scalloc(len + num_quotes, 1);
|
||||||
strncpy(buffer, "workspace \"", strlen("workspace \""));
|
memcpy(buffer, "workspace \"", strlen("workspace \""));
|
||||||
size_t inpos, outpos;
|
size_t inpos, outpos;
|
||||||
for (inpos = 0, outpos = strlen("workspace \"");
|
for (inpos = 0, outpos = strlen("workspace \"");
|
||||||
inpos < namelen;
|
inpos < namelen;
|
||||||
|
@ -694,21 +695,12 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
||||||
if (event->type == atoms[I3_SYNC]) {
|
if (event->type == atoms[I3_SYNC]) {
|
||||||
xcb_window_t window = event->data.data32[0];
|
xcb_window_t window = event->data.data32[0];
|
||||||
uint32_t rnd = event->data.data32[1];
|
uint32_t rnd = event->data.data32[1];
|
||||||
DLOG("[i3 sync protocol] Forwarding random value %d, X11 window 0x%08x to i3\n", rnd, window);
|
/* Forward the request to i3 via the IPC interface so that all pending
|
||||||
|
* IPC messages are guaranteed to be handled. */
|
||||||
void *reply = scalloc(32, 1);
|
char *payload = NULL;
|
||||||
xcb_client_message_event_t *ev = reply;
|
sasprintf(&payload, "{\"rnd\":%d, \"window\":%d}", rnd, window);
|
||||||
|
i3_send_msg(I3_IPC_MESSAGE_TYPE_SYNC, payload);
|
||||||
ev->response_type = XCB_CLIENT_MESSAGE;
|
free(payload);
|
||||||
ev->window = window;
|
|
||||||
ev->type = atoms[I3_SYNC];
|
|
||||||
ev->format = 32;
|
|
||||||
ev->data.data32[0] = window;
|
|
||||||
ev->data.data32[1] = rnd;
|
|
||||||
|
|
||||||
xcb_send_event(conn, false, xcb_root, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (char *)ev);
|
|
||||||
xcb_flush(conn);
|
|
||||||
free(reply);
|
|
||||||
} else if (event->type == atoms[_NET_SYSTEM_TRAY_OPCODE] &&
|
} else if (event->type == atoms[_NET_SYSTEM_TRAY_OPCODE] &&
|
||||||
event->format == 32) {
|
event->format == 32) {
|
||||||
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
|
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
|
||||||
|
@ -770,58 +762,16 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DLOG("X window %08x requested docking\n", client);
|
DLOG("X window %08x requested docking\n", client);
|
||||||
i3_output *output = NULL;
|
|
||||||
i3_output *walk = NULL;
|
|
||||||
tray_output_t *tray_output = NULL;
|
|
||||||
/* We need to iterate through the tray_output assignments first in
|
|
||||||
* order to prioritize them. Otherwise, if this bar manages two
|
|
||||||
* outputs and both are assigned as tray_output as well, the first
|
|
||||||
* output in our list would receive the tray rather than the first
|
|
||||||
* one defined via tray_output. */
|
|
||||||
TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
|
|
||||||
SLIST_FOREACH(walk, outputs, slist) {
|
|
||||||
if (!walk->active)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strcasecmp(walk->name, tray_output->output) == 0) {
|
if (output_for_tray == NULL) {
|
||||||
DLOG("Found tray_output assignment for output %s.\n", walk->name);
|
ELOG("No output found for tray\n");
|
||||||
output = walk;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (walk->primary && strcasecmp("primary", tray_output->output) == 0) {
|
|
||||||
DLOG("Found tray_output assignment on primary output %s.\n", walk->name);
|
|
||||||
output = walk;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we found an output, we're done. */
|
|
||||||
if (output != NULL)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If no tray_output has been specified, we fall back to the first
|
|
||||||
* available output. */
|
|
||||||
if (output == NULL && TAILQ_EMPTY(&(config.tray_outputs))) {
|
|
||||||
SLIST_FOREACH(walk, outputs, slist) {
|
|
||||||
if (!walk->active)
|
|
||||||
continue;
|
|
||||||
DLOG("Falling back to output %s because no primary output is configured\n", walk->name);
|
|
||||||
output = walk;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output == NULL) {
|
|
||||||
ELOG("No output found\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_void_cookie_t rcookie = xcb_reparent_window(xcb_connection,
|
xcb_void_cookie_t rcookie = xcb_reparent_window(xcb_connection,
|
||||||
client,
|
client,
|
||||||
output->bar.id,
|
output_for_tray->bar.id,
|
||||||
output->rect.w - icon_size - logical_px(config.tray_padding),
|
output_for_tray->rect.w - icon_size - logical_px(config.tray_padding),
|
||||||
logical_px(config.tray_padding));
|
logical_px(config.tray_padding));
|
||||||
if (xcb_request_failed(rcookie, "Could not reparent window. Maybe it is using an incorrect depth/visual?"))
|
if (xcb_request_failed(rcookie, "Could not reparent window. Maybe it is using an incorrect depth/visual?"))
|
||||||
return;
|
return;
|
||||||
|
@ -848,7 +798,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
||||||
ev->format = 32;
|
ev->format = 32;
|
||||||
ev->data.data32[0] = XCB_CURRENT_TIME;
|
ev->data.data32[0] = XCB_CURRENT_TIME;
|
||||||
ev->data.data32[1] = XEMBED_EMBEDDED_NOTIFY;
|
ev->data.data32[1] = XEMBED_EMBEDDED_NOTIFY;
|
||||||
ev->data.data32[2] = output->bar.id;
|
ev->data.data32[2] = output_for_tray->bar.id;
|
||||||
ev->data.data32[3] = xe_version;
|
ev->data.data32[3] = xe_version;
|
||||||
xcb_send_event(xcb_connection,
|
xcb_send_event(xcb_connection,
|
||||||
0,
|
0,
|
||||||
|
@ -868,7 +818,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
||||||
tc->win = client;
|
tc->win = client;
|
||||||
tc->xe_version = xe_version;
|
tc->xe_version = xe_version;
|
||||||
tc->mapped = false;
|
tc->mapped = false;
|
||||||
TAILQ_INSERT_TAIL(output->trayclients, tc, tailq);
|
TAILQ_INSERT_TAIL(output_for_tray->trayclients, tc, tailq);
|
||||||
|
|
||||||
if (map_it) {
|
if (map_it) {
|
||||||
DLOG("Mapping dock client\n");
|
DLOG("Mapping dock client\n");
|
||||||
|
@ -1092,7 +1042,7 @@ static void handle_resize_request(xcb_resize_request_event_t *event) {
|
||||||
* events from X11, handle them, then flush our outgoing queue.
|
* events from X11, handle them, then flush our outgoing queue.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) {
|
static void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) {
|
||||||
xcb_generic_event_t *event;
|
xcb_generic_event_t *event;
|
||||||
|
|
||||||
if (xcb_connection_has_error(xcb_connection)) {
|
if (xcb_connection_has_error(xcb_connection)) {
|
||||||
|
@ -1117,49 +1067,18 @@ void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) {
|
||||||
DLOG("received an xkb event\n");
|
DLOG("received an xkb event\n");
|
||||||
|
|
||||||
xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event;
|
xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event;
|
||||||
if (state->xkbType == XCB_XKB_STATE_NOTIFY && config.modifier != XCB_NONE) {
|
const uint32_t mod = (config.modifier & 0xFFFF);
|
||||||
int modstate = state->mods & config.modifier;
|
const bool new_mod_pressed = (mod != 0 && (state->mods & mod) == mod);
|
||||||
|
if (new_mod_pressed != mod_pressed) {
|
||||||
#define DLOGMOD(modmask, status) \
|
mod_pressed = new_mod_pressed;
|
||||||
do { \
|
if (state->xkbType == XCB_XKB_STATE_NOTIFY && config.modifier != XCB_NONE) {
|
||||||
switch (modmask) { \
|
if (mod_pressed) {
|
||||||
case ShiftMask: \
|
|
||||||
DLOG("ShiftMask got " #status "!\n"); \
|
|
||||||
break; \
|
|
||||||
case ControlMask: \
|
|
||||||
DLOG("ControlMask got " #status "!\n"); \
|
|
||||||
break; \
|
|
||||||
case Mod1Mask: \
|
|
||||||
DLOG("Mod1Mask got " #status "!\n"); \
|
|
||||||
break; \
|
|
||||||
case Mod2Mask: \
|
|
||||||
DLOG("Mod2Mask got " #status "!\n"); \
|
|
||||||
break; \
|
|
||||||
case Mod3Mask: \
|
|
||||||
DLOG("Mod3Mask got " #status "!\n"); \
|
|
||||||
break; \
|
|
||||||
case Mod4Mask: \
|
|
||||||
DLOG("Mod4Mask got " #status "!\n"); \
|
|
||||||
break; \
|
|
||||||
case Mod5Mask: \
|
|
||||||
DLOG("Mod5Mask got " #status "!\n"); \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
if (modstate != mod_pressed) {
|
|
||||||
if (modstate == 0) {
|
|
||||||
DLOGMOD(config.modifier, released);
|
|
||||||
if (!activated_mode)
|
|
||||||
hide_bars();
|
|
||||||
} else {
|
|
||||||
DLOGMOD(config.modifier, pressed);
|
|
||||||
activated_mode = false;
|
activated_mode = false;
|
||||||
unhide_bars();
|
unhide_bars();
|
||||||
|
} else if (!activated_mode) {
|
||||||
|
hide_bars();
|
||||||
}
|
}
|
||||||
mod_pressed = modstate;
|
|
||||||
}
|
}
|
||||||
#undef DLOGMOD
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(event);
|
free(event);
|
||||||
|
@ -1223,7 +1142,7 @@ void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) {
|
||||||
* are triggered
|
* are triggered
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
static void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1231,7 +1150,7 @@ void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
||||||
* depend on 'config'.
|
* depend on 'config'.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
char *init_xcb_early() {
|
char *init_xcb_early(void) {
|
||||||
/* FIXME: xcb_connect leaks memory */
|
/* FIXME: xcb_connect leaks memory */
|
||||||
xcb_connection = xcb_connect(NULL, &screen);
|
xcb_connection = xcb_connect(NULL, &screen);
|
||||||
if (xcb_connection_has_error(xcb_connection)) {
|
if (xcb_connection_has_error(xcb_connection)) {
|
||||||
|
@ -1294,7 +1213,7 @@ char *init_xcb_early() {
|
||||||
* in xcb.
|
* in xcb.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void register_xkb_keyevents() {
|
static void register_xkb_keyevents(void) {
|
||||||
const xcb_query_extension_reply_t *extreply;
|
const xcb_query_extension_reply_t *extreply;
|
||||||
extreply = xcb_get_extension_data(conn, &xcb_xkb_id);
|
extreply = xcb_get_extension_data(conn, &xcb_xkb_id);
|
||||||
if (!extreply->present) {
|
if (!extreply->present) {
|
||||||
|
@ -1318,7 +1237,7 @@ void register_xkb_keyevents() {
|
||||||
* Deregister from xkb keyevents.
|
* Deregister from xkb keyevents.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void deregister_xkb_keyevents() {
|
static void deregister_xkb_keyevents(void) {
|
||||||
xcb_xkb_select_events(conn,
|
xcb_xkb_select_events(conn,
|
||||||
XCB_XKB_ID_USE_CORE_KBD,
|
XCB_XKB_ID_USE_CORE_KBD,
|
||||||
0,
|
0,
|
||||||
|
@ -1384,7 +1303,7 @@ static void send_tray_clientmessage(void) {
|
||||||
* atom. Afterwards, tray clients will send ClientMessages to our window.
|
* atom. Afterwards, tray clients will send ClientMessages to our window.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void init_tray(void) {
|
static void init_tray(void) {
|
||||||
DLOG("Initializing system tray functionality\n");
|
DLOG("Initializing system tray functionality\n");
|
||||||
/* request the tray manager atom for the X11 display we are running on */
|
/* request the tray manager atom for the X11 display we are running on */
|
||||||
char atomname[strlen("_NET_SYSTEM_TRAY_S") + 11];
|
char atomname[strlen("_NET_SYSTEM_TRAY_S") + 11];
|
||||||
|
@ -1613,7 +1532,7 @@ void destroy_window(i3_output *output) {
|
||||||
|
|
||||||
/* Strut partial tells i3 where to reserve space for i3bar. This is determined
|
/* Strut partial tells i3 where to reserve space for i3bar. This is determined
|
||||||
* by the `position` bar config directive. */
|
* by the `position` bar config directive. */
|
||||||
xcb_void_cookie_t config_strut_partial(i3_output *output) {
|
static xcb_void_cookie_t config_strut_partial(i3_output *output) {
|
||||||
/* A local struct to save the strut_partial property */
|
/* A local struct to save the strut_partial property */
|
||||||
struct {
|
struct {
|
||||||
uint32_t left;
|
uint32_t left;
|
||||||
|
@ -1655,6 +1574,56 @@ xcb_void_cookie_t config_strut_partial(i3_output *output) {
|
||||||
&strut_partial);
|
&strut_partial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the output which should hold the tray, if one exists.
|
||||||
|
*
|
||||||
|
* An output is returned in these scenarios:
|
||||||
|
* 1. A specific output was listed in tray_outputs which is also in the list
|
||||||
|
* of outputs managed by this bar.
|
||||||
|
* 2. No tray_output directive was specified. In this case, we use the first
|
||||||
|
* available output.
|
||||||
|
* 3. 'tray_output primary' was specified. In this case we use the primary
|
||||||
|
* output.
|
||||||
|
*
|
||||||
|
* Three scenarios in which we specifically don't want to use a tray:
|
||||||
|
* 1. 'tray_output none' was specified.
|
||||||
|
* 2. A specific output was listed as a tray_output, but is not one of the
|
||||||
|
* outputs managed by this bar. For example, consider tray_outputs == [VGA-1],
|
||||||
|
* but outputs == [HDMI-1].
|
||||||
|
* 3. 'tray_output primary' was specified and no output in the list is
|
||||||
|
* primary.
|
||||||
|
*/
|
||||||
|
static i3_output *get_tray_output(void) {
|
||||||
|
i3_output *output = NULL;
|
||||||
|
if (TAILQ_EMPTY(&(config.tray_outputs))) {
|
||||||
|
/* No tray_output specified, use first active output. */
|
||||||
|
SLIST_FOREACH(output, outputs, slist) {
|
||||||
|
if (output->active) {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
} else if (strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0) {
|
||||||
|
/* Check for "tray_output none" */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If one or more tray_output assignments were specified, we ensure that at
|
||||||
|
* least one of them is actually an output managed by this instance. */
|
||||||
|
tray_output_t *tray_output;
|
||||||
|
TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
|
||||||
|
SLIST_FOREACH(output, outputs, slist) {
|
||||||
|
if (output->active &&
|
||||||
|
(strcasecmp(output->name, tray_output->output) == 0 ||
|
||||||
|
(strcasecmp(tray_output->output, "primary") == 0 && output->primary))) {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reconfigure all bars and create new bars for recently activated outputs
|
* Reconfigure all bars and create new bars for recently activated outputs
|
||||||
*
|
*
|
||||||
|
@ -1662,7 +1631,6 @@ xcb_void_cookie_t config_strut_partial(i3_output *output) {
|
||||||
void reconfig_windows(bool redraw_bars) {
|
void reconfig_windows(bool redraw_bars) {
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
uint32_t values[6];
|
uint32_t values[6];
|
||||||
static bool tray_configured = false;
|
|
||||||
|
|
||||||
i3_output *walk;
|
i3_output *walk;
|
||||||
SLIST_FOREACH(walk, outputs, slist) {
|
SLIST_FOREACH(walk, outputs, slist) {
|
||||||
|
@ -1790,58 +1758,6 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unless "tray_output none" was specified, we need to initialize the tray. */
|
|
||||||
bool no_tray = false;
|
|
||||||
if (!(TAILQ_EMPTY(&(config.tray_outputs)))) {
|
|
||||||
no_tray = strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There are three scenarios in which we need to initialize the tray:
|
|
||||||
* 1. A specific output was listed in tray_outputs which is also
|
|
||||||
* in the list of outputs managed by this bar.
|
|
||||||
* 2. No tray_output directive was specified. In this case, we
|
|
||||||
* use the first available output.
|
|
||||||
* 3. 'tray_output primary' was specified. In this case we use the
|
|
||||||
* primary output.
|
|
||||||
*
|
|
||||||
* Three scenarios in which we specifically don't want to
|
|
||||||
* initialize the tray are:
|
|
||||||
* 1. 'tray_output none' was specified.
|
|
||||||
* 2. A specific output was listed as a tray_output, but is not
|
|
||||||
* one of the outputs managed by this bar. For example, consider
|
|
||||||
* tray_outputs == [VGA-1], but outputs == [HDMI-1].
|
|
||||||
* 3. 'tray_output primary' was specified and no output in the list
|
|
||||||
* is primary.
|
|
||||||
*/
|
|
||||||
if (!tray_configured && !no_tray) {
|
|
||||||
/* If no tray_output was specified, we go ahead and initialize the tray as
|
|
||||||
* we will be using the first available output. */
|
|
||||||
if (TAILQ_EMPTY(&(config.tray_outputs))) {
|
|
||||||
init_tray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If one or more tray_output assignments were specified, we ensure that at least one of
|
|
||||||
* them is actually an output managed by this instance. */
|
|
||||||
tray_output_t *tray_output;
|
|
||||||
TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
|
|
||||||
i3_output *output;
|
|
||||||
bool found = false;
|
|
||||||
SLIST_FOREACH(output, outputs, slist) {
|
|
||||||
if (strcasecmp(output->name, tray_output->output) == 0 ||
|
|
||||||
(strcasecmp(tray_output->output, "primary") == 0 && output->primary)) {
|
|
||||||
found = true;
|
|
||||||
init_tray();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tray_configured = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* We already have a bar, so we just reconfigure it */
|
/* We already have a bar, so we just reconfigure it */
|
||||||
mask = XCB_CONFIG_WINDOW_X |
|
mask = XCB_CONFIG_WINDOW_X |
|
||||||
|
@ -1935,6 +1851,19 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Finally, check if we want to initialize the tray or destroy the selection
|
||||||
|
* window. The result of get_tray_output() is cached. */
|
||||||
|
output_for_tray = get_tray_output();
|
||||||
|
if (output_for_tray) {
|
||||||
|
if (selwin == XCB_NONE) {
|
||||||
|
init_tray();
|
||||||
|
}
|
||||||
|
} else if (selwin != XCB_NONE) {
|
||||||
|
DLOG("Destroying tray selection window\n");
|
||||||
|
xcb_destroy_window(xcb_connection, selwin);
|
||||||
|
selwin = XCB_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2048,7 +1977,8 @@ void draw_bars(bool unhide) {
|
||||||
DLOG("Printing statusline!\n");
|
DLOG("Printing statusline!\n");
|
||||||
|
|
||||||
int tray_width = get_tray_width(outputs_walk->trayclients);
|
int tray_width = get_tray_width(outputs_walk->trayclients);
|
||||||
uint32_t max_statusline_width = outputs_walk->rect.w - workspace_width - tray_width - 2 * logical_px(sb_hoff_px);
|
uint32_t hoff = logical_px(((workspace_width > 0) + (tray_width > 0)) * sb_hoff_px);
|
||||||
|
uint32_t max_statusline_width = outputs_walk->rect.w - workspace_width - tray_width - hoff;
|
||||||
uint32_t clip_left = 0;
|
uint32_t clip_left = 0;
|
||||||
uint32_t statusline_width = full_statusline_width;
|
uint32_t statusline_width = full_statusline_width;
|
||||||
bool use_short_text = false;
|
bool use_short_text = false;
|
||||||
|
@ -2062,7 +1992,7 @@ void draw_bars(bool unhide) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t visible_statusline_width = MIN(statusline_width, max_statusline_width);
|
int16_t visible_statusline_width = MIN(statusline_width, max_statusline_width);
|
||||||
int x_dest = outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width;
|
int x_dest = outputs_walk->rect.w - tray_width - logical_px((tray_width > 0) * sb_hoff_px) - visible_statusline_width;
|
||||||
|
|
||||||
draw_statusline(outputs_walk, clip_left, use_focus_colors, use_short_text);
|
draw_statusline(outputs_walk, clip_left, use_focus_colors, use_short_text);
|
||||||
draw_util_copy_surface(&outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0,
|
draw_util_copy_surface(&outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0,
|
||||||
|
@ -2110,5 +2040,4 @@ void set_current_mode(struct mode *current) {
|
||||||
I3STRING_FREE(binding.name);
|
I3STRING_FREE(binding.name);
|
||||||
binding = *current;
|
binding = *current;
|
||||||
activated_mode = binding.name != NULL;
|
activated_mode = binding.name != NULL;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,4 +82,5 @@
|
||||||
#include "fake_outputs.h"
|
#include "fake_outputs.h"
|
||||||
#include "display_version.h"
|
#include "display_version.h"
|
||||||
#include "restore_layout.h"
|
#include "restore_layout.h"
|
||||||
|
#include "sync.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
|
@ -8,6 +8,7 @@ xmacro(_NET_WM_STATE_FULLSCREEN)
|
||||||
xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
|
xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
|
||||||
xmacro(_NET_WM_STATE_MODAL)
|
xmacro(_NET_WM_STATE_MODAL)
|
||||||
xmacro(_NET_WM_STATE_HIDDEN)
|
xmacro(_NET_WM_STATE_HIDDEN)
|
||||||
|
xmacro(_NET_WM_STATE_FOCUSED)
|
||||||
xmacro(_NET_WM_STATE)
|
xmacro(_NET_WM_STATE)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE)
|
xmacro(_NET_WM_WINDOW_TYPE)
|
||||||
xmacro(_NET_WM_WINDOW_TYPE_NORMAL)
|
xmacro(_NET_WM_WINDOW_TYPE_NORMAL)
|
||||||
|
|
|
@ -17,3 +17,4 @@ xmacro(I3_FLOATING_WINDOW)
|
||||||
xmacro(_NET_REQUEST_FRAME_EXTENTS)
|
xmacro(_NET_REQUEST_FRAME_EXTENTS)
|
||||||
xmacro(_NET_FRAME_EXTENTS)
|
xmacro(_NET_FRAME_EXTENTS)
|
||||||
xmacro(_MOTIF_WM_HINTS)
|
xmacro(_MOTIF_WM_HINTS)
|
||||||
|
xmacro(WM_CHANGE_STATE)
|
||||||
|
|
|
@ -216,7 +216,7 @@ void cmd_sticky(I3_CMD, const char *action);
|
||||||
* Implementation of 'move <direction> [<pixels> [px]]'.
|
* Implementation of 'move <direction> [<pixels> [px]]'.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void cmd_move_direction(I3_CMD, const char *direction, long move_px);
|
void cmd_move_direction(I3_CMD, const char *direction_str, long move_px);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of 'layout default|stacked|stacking|tabbed|splitv|splith'.
|
* Implementation of 'layout default|stacked|stacking|tabbed|splitv|splith'.
|
||||||
|
@ -264,7 +264,7 @@ void cmd_focus_output(I3_CMD, const char *name);
|
||||||
* Implementation of 'move [window|container] [to] [absolute] position <px> [px] <px> [px]
|
* Implementation of 'move [window|container] [to] [absolute] position <px> [px] <px> [px]
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void cmd_move_window_to_position(I3_CMD, const char *method, long x, long y);
|
void cmd_move_window_to_position(I3_CMD, long x, long y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of 'move [window|container] [to] [absolute] position center
|
* Implementation of 'move [window|container] [to] [absolute] position center
|
||||||
|
@ -314,13 +314,13 @@ void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name);
|
||||||
*/
|
*/
|
||||||
void cmd_bar(I3_CMD, const char *bar_type, const char *bar_value, const char *bar_id);
|
void cmd_bar(I3_CMD, const char *bar_type, const char *bar_value, const char *bar_id);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Implementation of 'shmlog <size>|toggle|on|off'
|
* Implementation of 'shmlog <size>|toggle|on|off'
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void cmd_shmlog(I3_CMD, const char *argument);
|
void cmd_shmlog(I3_CMD, const char *argument);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Implementation of 'debuglog toggle|on|off'
|
* Implementation of 'debuglog toggle|on|off'
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
#include <yajl/yajl_gen.h>
|
#include <yajl/yajl_gen.h>
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Holds an intermediate represenation of the result of a call to any command.
|
* Holds an intermediate represenation of the result of a call to any command.
|
||||||
* When calling parse_command("floating enable, border none"), the parser will
|
* When calling parse_command("floating enable, border none"), the parser will
|
||||||
* internally use this struct when calling cmd_floating and cmd_border.
|
* internally use this struct when calling cmd_floating and cmd_border.
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
*/
|
*/
|
||||||
Con *con_new_skeleton(Con *parent, i3Window *window);
|
Con *con_new_skeleton(Con *parent, i3Window *window);
|
||||||
|
|
||||||
/* A wrapper for con_new_skeleton, to retain the old con_new behaviour
|
/**
|
||||||
|
* A wrapper for con_new_skeleton, to retain the old con_new behaviour
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Con *con_new(Con *parent, i3Window *window);
|
Con *con_new(Con *parent, i3Window *window);
|
||||||
|
@ -120,6 +121,14 @@ Con *con_parent_with_orientation(Con *con, orientation_t orientation);
|
||||||
*/
|
*/
|
||||||
Con *con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode);
|
Con *con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fullscreen node that covers the given workspace if it exists.
|
||||||
|
* This is either a CF_GLOBAL fullscreen container anywhere or a CF_OUTPUT
|
||||||
|
* fullscreen container in the workspace.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Con *con_get_fullscreen_covering_ws(Con *ws);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the container is internal, such as __i3_scratch
|
* Returns true if the container is internal, such as __i3_scratch
|
||||||
*
|
*
|
||||||
|
@ -212,7 +221,7 @@ void con_mark_toggle(Con *con, const char *mark, mark_mode_t mode);
|
||||||
*/
|
*/
|
||||||
void con_mark(Con *con, const char *mark, mark_mode_t mode);
|
void con_mark(Con *con, const char *mark, mark_mode_t mode);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Removes marks from containers.
|
* Removes marks from containers.
|
||||||
* If con is NULL, all containers are considered.
|
* If con is NULL, all containers are considered.
|
||||||
* If name is NULL, this removes all existing marks.
|
* If name is NULL, this removes all existing marks.
|
||||||
|
@ -394,7 +403,7 @@ Con *con_descend_focused(Con *con);
|
||||||
*/
|
*/
|
||||||
Con *con_descend_tiling_focused(Con *con);
|
Con *con_descend_tiling_focused(Con *con);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Returns the leftmost, rightmost, etc. container in sub-tree. For example, if
|
* Returns the leftmost, rightmost, etc. container in sub-tree. For example, if
|
||||||
* direction is D_LEFT, then we return the rightmost container and if direction
|
* direction is D_LEFT, then we return the rightmost container and if direction
|
||||||
* is D_RIGHT, we return the leftmost container. This is because if we are
|
* is D_RIGHT, we return the leftmost container. This is because if we are
|
||||||
|
|
|
@ -56,12 +56,14 @@ CFGFUN(disable_randr15, const char *value);
|
||||||
CFGFUN(fake_outputs, const char *outputs);
|
CFGFUN(fake_outputs, const char *outputs);
|
||||||
CFGFUN(force_display_urgency_hint, const long duration_ms);
|
CFGFUN(force_display_urgency_hint, const long duration_ms);
|
||||||
CFGFUN(focus_on_window_activation, const char *mode);
|
CFGFUN(focus_on_window_activation, const char *mode);
|
||||||
|
CFGFUN(title_align, const char *alignment);
|
||||||
CFGFUN(show_marks, const char *value);
|
CFGFUN(show_marks, const char *value);
|
||||||
CFGFUN(hide_edge_borders, const char *borders);
|
CFGFUN(hide_edge_borders, const char *borders);
|
||||||
CFGFUN(assign_output, const char *output);
|
CFGFUN(assign_output, const char *output);
|
||||||
CFGFUN(assign, const char *workspace, bool is_number);
|
CFGFUN(assign, const char *workspace, bool is_number);
|
||||||
CFGFUN(no_focus);
|
CFGFUN(no_focus);
|
||||||
CFGFUN(ipc_socket, const char *path);
|
CFGFUN(ipc_socket, const char *path);
|
||||||
|
CFGFUN(ipc_kill_timeout, const long timeout_ms);
|
||||||
CFGFUN(restart_state, const char *path);
|
CFGFUN(restart_state, const char *path);
|
||||||
CFGFUN(popup_during_fullscreen, const char *value);
|
CFGFUN(popup_during_fullscreen, const char *value);
|
||||||
CFGFUN(color, const char *colorclass, const char *border, const char *background, const char *text, const char *indicator, const char *child_border);
|
CFGFUN(color, const char *colorclass, const char *border, const char *background, const char *text, const char *indicator, const char *child_border);
|
||||||
|
@ -81,7 +83,7 @@ CFGFUN(bar_hidden_state, const char *hidden_state);
|
||||||
CFGFUN(bar_id, const char *bar_id);
|
CFGFUN(bar_id, const char *bar_id);
|
||||||
CFGFUN(bar_output, const char *output);
|
CFGFUN(bar_output, const char *output);
|
||||||
CFGFUN(bar_verbose, const char *verbose);
|
CFGFUN(bar_verbose, const char *verbose);
|
||||||
CFGFUN(bar_modifier, const char *modifier);
|
CFGFUN(bar_modifier, const char *modifiers);
|
||||||
CFGFUN(bar_wheel_up_cmd, const char *command);
|
CFGFUN(bar_wheel_up_cmd, const char *command);
|
||||||
CFGFUN(bar_wheel_down_cmd, const char *command);
|
CFGFUN(bar_wheel_down_cmd, const char *command);
|
||||||
CFGFUN(bar_bindsym, const char *button, const char *release, const char *command);
|
CFGFUN(bar_bindsym, const char *button, const char *release, const char *command);
|
||||||
|
@ -96,5 +98,6 @@ CFGFUN(bar_status_command, const char *command);
|
||||||
CFGFUN(bar_binding_mode_indicator, const char *value);
|
CFGFUN(bar_binding_mode_indicator, const char *value);
|
||||||
CFGFUN(bar_workspace_buttons, const char *value);
|
CFGFUN(bar_workspace_buttons, const char *value);
|
||||||
CFGFUN(bar_strip_workspace_numbers, const char *value);
|
CFGFUN(bar_strip_workspace_numbers, const char *value);
|
||||||
|
CFGFUN(bar_strip_workspace_name, const char *value);
|
||||||
CFGFUN(bar_start);
|
CFGFUN(bar_start);
|
||||||
CFGFUN(bar_finish);
|
CFGFUN(bar_finish);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
SLIST_HEAD(variables_head, Variable);
|
SLIST_HEAD(variables_head, Variable);
|
||||||
extern pid_t config_error_nagbar_pid;
|
extern pid_t config_error_nagbar_pid;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* An intermediate reprsentation of the result of a parse_config call.
|
* An intermediate reprsentation of the result of a parse_config call.
|
||||||
* Currently unused, but the JSON output will be useful in the future when we
|
* Currently unused, but the JSON output will be useful in the future when we
|
||||||
* implement a config parsing IPC command.
|
* implement a config parsing IPC command.
|
||||||
|
|
|
@ -201,6 +201,13 @@ struct Config {
|
||||||
* decoration. Marks starting with a "_" will be ignored either way. */
|
* decoration. Marks starting with a "_" will be ignored either way. */
|
||||||
bool show_marks;
|
bool show_marks;
|
||||||
|
|
||||||
|
/** Title alignment options. */
|
||||||
|
enum {
|
||||||
|
ALIGN_LEFT,
|
||||||
|
ALIGN_CENTER,
|
||||||
|
ALIGN_RIGHT
|
||||||
|
} title_align;
|
||||||
|
|
||||||
/** The default border style for new windows. */
|
/** The default border style for new windows. */
|
||||||
border_style_t default_border;
|
border_style_t default_border;
|
||||||
|
|
||||||
|
@ -289,16 +296,7 @@ struct Barconfig {
|
||||||
S_SHOW = 1 } hidden_state;
|
S_SHOW = 1 } hidden_state;
|
||||||
|
|
||||||
/** Bar modifier (to show bar when in hide mode). */
|
/** Bar modifier (to show bar when in hide mode). */
|
||||||
enum {
|
uint32_t modifier;
|
||||||
M_NONE = 0,
|
|
||||||
M_CONTROL = 1,
|
|
||||||
M_SHIFT = 2,
|
|
||||||
M_MOD1 = 3,
|
|
||||||
M_MOD2 = 4,
|
|
||||||
M_MOD3 = 5,
|
|
||||||
M_MOD4 = 6,
|
|
||||||
M_MOD5 = 7
|
|
||||||
} modifier;
|
|
||||||
|
|
||||||
TAILQ_HEAD(bar_bindings_head, Barbinding)
|
TAILQ_HEAD(bar_bindings_head, Barbinding)
|
||||||
bar_bindings;
|
bar_bindings;
|
||||||
|
@ -331,6 +329,10 @@ struct Barconfig {
|
||||||
* 'strip_workspace_numbers yes'. */
|
* 'strip_workspace_numbers yes'. */
|
||||||
bool strip_workspace_numbers;
|
bool strip_workspace_numbers;
|
||||||
|
|
||||||
|
/** Strip workspace name? Configuration option is
|
||||||
|
* 'strip_workspace_name yes'. */
|
||||||
|
bool strip_workspace_name;
|
||||||
|
|
||||||
/** Hide mode button? Configuration option is 'binding_mode_indicator no'
|
/** Hide mode button? Configuration option is 'binding_mode_indicator no'
|
||||||
* but we invert the bool for the same reason as hide_workspace_buttons.*/
|
* but we invert the bool for the same reason as hide_workspace_buttons.*/
|
||||||
bool hide_binding_mode_indicator;
|
bool hide_binding_mode_indicator;
|
||||||
|
@ -432,7 +434,7 @@ void ungrab_all_keys(xcb_connection_t *conn);
|
||||||
* Sends the current bar configuration as an event to all barconfig_update listeners.
|
* Sends the current bar configuration as an event to all barconfig_update listeners.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void update_barconfig();
|
void update_barconfig(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kills the configerror i3-nagbar process, if any.
|
* Kills the configerror i3-nagbar process, if any.
|
||||||
|
|
|
@ -477,6 +477,10 @@ struct Window {
|
||||||
int min_width;
|
int min_width;
|
||||||
int min_height;
|
int min_height;
|
||||||
|
|
||||||
|
/* Maximum size specified for the window. */
|
||||||
|
int max_width;
|
||||||
|
int max_height;
|
||||||
|
|
||||||
/* aspect ratio from WM_NORMAL_HINTS (MPlayer uses this for example) */
|
/* aspect ratio from WM_NORMAL_HINTS (MPlayer uses this for example) */
|
||||||
double aspect_ratio;
|
double aspect_ratio;
|
||||||
};
|
};
|
||||||
|
@ -573,7 +577,7 @@ struct Assignment {
|
||||||
/** the criteria to check if a window matches */
|
/** the criteria to check if a window matches */
|
||||||
Match match;
|
Match match;
|
||||||
|
|
||||||
/** destination workspace/command, depending on the type */
|
/** destination workspace/command/output, depending on the type */
|
||||||
union {
|
union {
|
||||||
char *command;
|
char *command;
|
||||||
char *workspace;
|
char *workspace;
|
||||||
|
|
|
@ -83,6 +83,12 @@ void ewmh_update_client_list_stacking(xcb_window_t *stack, int num_windows);
|
||||||
*/
|
*/
|
||||||
void ewmh_update_sticky(xcb_window_t window, bool sticky);
|
void ewmh_update_sticky(xcb_window_t window, bool sticky);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set or remove _NEW_WM_STATE_FOCUSED on the window.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ewmh_update_focused(xcb_window_t window, bool is_focused);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the EWMH hints on the root window.
|
* Set up the EWMH hints on the root window.
|
||||||
*
|
*
|
||||||
|
|
|
@ -143,7 +143,7 @@ drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event,
|
||||||
* outputs.
|
* outputs.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void floating_reposition(Con *con, Rect newrect);
|
bool floating_reposition(Con *con, Rect newrect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets size of the CT_FLOATING_CON to specified dimensions. Might limit the
|
* Sets size of the CT_FLOATING_CON to specified dimensions. Might limit the
|
||||||
|
|
|
@ -63,6 +63,9 @@ typedef struct i3_ipc_header {
|
||||||
/** Send a tick event to all subscribers. */
|
/** Send a tick event to all subscribers. */
|
||||||
#define I3_IPC_MESSAGE_TYPE_SEND_TICK 10
|
#define I3_IPC_MESSAGE_TYPE_SEND_TICK 10
|
||||||
|
|
||||||
|
/** Trigger an i3 sync protocol message via IPC. */
|
||||||
|
#define I3_IPC_MESSAGE_TYPE_SYNC 11
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Messages from i3 to clients
|
* Messages from i3 to clients
|
||||||
*
|
*
|
||||||
|
@ -78,12 +81,13 @@ typedef struct i3_ipc_header {
|
||||||
#define I3_IPC_REPLY_TYPE_BINDING_MODES 8
|
#define I3_IPC_REPLY_TYPE_BINDING_MODES 8
|
||||||
#define I3_IPC_REPLY_TYPE_CONFIG 9
|
#define I3_IPC_REPLY_TYPE_CONFIG 9
|
||||||
#define I3_IPC_REPLY_TYPE_TICK 10
|
#define I3_IPC_REPLY_TYPE_TICK 10
|
||||||
|
#define I3_IPC_REPLY_TYPE_SYNC 11
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Events from i3 to clients. Events have the first bit set high.
|
* Events from i3 to clients. Events have the first bit set high.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define I3_IPC_EVENT_MASK (1 << 31)
|
#define I3_IPC_EVENT_MASK (1UL << 31)
|
||||||
|
|
||||||
/* The workspace event will be triggered upon changes in the workspace list */
|
/* The workspace event will be triggered upon changes in the workspace list */
|
||||||
#define I3_IPC_EVENT_WORKSPACE (I3_IPC_EVENT_MASK | 0)
|
#define I3_IPC_EVENT_WORKSPACE (I3_IPC_EVENT_MASK | 0)
|
||||||
|
|
|
@ -35,6 +35,11 @@ typedef struct ipc_client {
|
||||||
* event has been sent by i3. */
|
* event has been sent by i3. */
|
||||||
bool first_tick_sent;
|
bool first_tick_sent;
|
||||||
|
|
||||||
|
struct ev_io *callback;
|
||||||
|
struct ev_timer *timeout;
|
||||||
|
uint8_t *buffer;
|
||||||
|
size_t buffer_size;
|
||||||
|
|
||||||
TAILQ_ENTRY(ipc_client)
|
TAILQ_ENTRY(ipc_client)
|
||||||
clients;
|
clients;
|
||||||
} ipc_client;
|
} ipc_client;
|
||||||
|
@ -124,3 +129,9 @@ void ipc_send_barconfig_update_event(Barconfig *barconfig);
|
||||||
* For the binding events, we send the serialized binding struct.
|
* For the binding events, we send the serialized binding struct.
|
||||||
*/
|
*/
|
||||||
void ipc_send_binding_event(const char *event_type, Binding *bind);
|
void ipc_send_binding_event(const char *event_type, Binding *bind);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum duration that we allow for a connection with an unwriteable
|
||||||
|
* socket.
|
||||||
|
*/
|
||||||
|
void ipc_set_kill_timeout(ev_tstamp new);
|
||||||
|
|
|
@ -166,6 +166,14 @@ int sasprintf(char **strp, const char *fmt, ...);
|
||||||
*/
|
*/
|
||||||
ssize_t writeall(int fd, const void *buf, size_t count);
|
ssize_t writeall(int fd, const void *buf, size_t count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like writeall, but instead of retrying upon EAGAIN (returned when a write
|
||||||
|
* would block), the function stops and returns the total number of bytes
|
||||||
|
* written so far.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ssize_t writeall_nonblock(int fd, const void *buf, size_t count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Safe-wrapper around writeall which exits if it returns -1 (meaning that
|
* Safe-wrapper around writeall which exits if it returns -1 (meaning that
|
||||||
* write failed)
|
* write failed)
|
||||||
|
@ -188,11 +196,11 @@ i3String *i3string_from_markup(const char *from_markup);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build an i3String from an UTF-8 encoded string with fixed length.
|
* Build an i3String from an UTF-8 encoded string with fixed length.
|
||||||
* To be used when no proper NUL-terminaison is available.
|
* To be used when no proper NULL-termination is available.
|
||||||
* Returns the newly-allocated i3String.
|
* Returns the newly-allocated i3String.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
i3String *i3string_from_utf8_with_length(const char *from_utf8, size_t num_bytes);
|
i3String *i3string_from_utf8_with_length(const char *from_utf8, ssize_t num_bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build an i3String from an UTF-8 encoded string in Pango markup with fixed
|
* Build an i3String from an UTF-8 encoded string in Pango markup with fixed
|
||||||
|
@ -312,6 +320,11 @@ int ipc_recv_message(int sockfd, uint32_t *message_type,
|
||||||
*/
|
*/
|
||||||
void fake_configure_notify(xcb_connection_t *conn, xcb_rectangle_t r, xcb_window_t window, int border_width);
|
void fake_configure_notify(xcb_connection_t *conn, xcb_rectangle_t r, xcb_window_t window, int border_width);
|
||||||
|
|
||||||
|
#define HAS_G_UTF8_MAKE_VALID GLIB_CHECK_VERSION(2, 52, 0)
|
||||||
|
#if !HAS_G_UTF8_MAKE_VALID
|
||||||
|
gchar *g_utf8_make_valid(const gchar *str, gssize len);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the colorpixel to use for the given hex color (think of HTML). Only
|
* Returns the colorpixel to use for the given hex color (think of HTML). Only
|
||||||
* works for true-color (vast majority of cases) at the moment, avoiding a
|
* works for true-color (vast majority of cases) at the moment, avoiding a
|
||||||
|
@ -330,7 +343,7 @@ uint32_t get_colorpixel(const char *hex) __attribute__((const));
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Taken from FreeBSD
|
* Taken from FreeBSD
|
||||||
* Returns a pointer to a new string which is a duplicate of the
|
* Returns a pointer to a new string which is a duplicate of the
|
||||||
* string, but only copies at most n characters.
|
* string, but only copies at most n characters.
|
||||||
|
@ -459,7 +472,7 @@ xcb_visualtype_t *get_visualtype(xcb_screen_t *screen);
|
||||||
* release version), based on the git version number.
|
* release version), based on the git version number.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool is_debug_build() __attribute__((const));
|
bool is_debug_build(void) __attribute__((const));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of a temporary file with the specified prefix.
|
* Returns the name of a temporary file with the specified prefix.
|
||||||
|
@ -506,11 +519,11 @@ int logical_px(const int logical);
|
||||||
char *resolve_tilde(const char *path);
|
char *resolve_tilde(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the path of the first configuration file found. If override_configpath
|
* Get the path of the first configuration file found. If override_configpath is
|
||||||
* is specified, that path is returned and saved for further calls. Otherwise,
|
* specified, that path is returned and saved for further calls. Otherwise,
|
||||||
* checks the home directory first, then the system directory first, always
|
* checks the home directory first, then the system directory, always taking
|
||||||
* taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
|
* into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
|
||||||
* $XDG_CONFIG_DIRS)
|
* $XDG_CONFIG_DIRS).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
char *get_config_path(const char *override_configpath, bool use_system_paths);
|
char *get_config_path(const char *override_configpath, bool use_system_paths);
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Initializes the Match data structure. This function is necessary because the
|
* Initializes the Match data structure. This function is necessary because the
|
||||||
* members representing boolean values (like dock) need to be initialized with
|
* members representing boolean values (like dock) need to be initialized with
|
||||||
* -1 instead of 0.
|
* -1 instead of 0.
|
||||||
|
|
|
@ -17,3 +17,13 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void tree_move(Con *con, int direction);
|
void tree_move(Con *con, int direction);
|
||||||
|
|
||||||
|
typedef enum { BEFORE,
|
||||||
|
AFTER } position_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function detaches 'con' from its parent and inserts it either before or
|
||||||
|
* after 'target'.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void insert_con_into(Con *con, Con *target, position_t position);
|
||||||
|
|
|
@ -40,5 +40,12 @@ Output *get_output_for_con(Con *con);
|
||||||
* Iterates over all outputs and pushes sticky windows to the currently visible
|
* Iterates over all outputs and pushes sticky windows to the currently visible
|
||||||
* workspace on that output.
|
* workspace on that output.
|
||||||
*
|
*
|
||||||
|
* old_focus is used to determine if a sticky window is going to be focused.
|
||||||
|
* old_focus might be different than the currently focused container because the
|
||||||
|
* caller might need to temporarily change the focus and then call
|
||||||
|
* output_push_sticky_windows. For example, workspace_show needs to set focus to
|
||||||
|
* one of its descendants first, then call output_push_sticky_windows that
|
||||||
|
* should focus a sticky window if it was the focused in the previous workspace.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void output_push_sticky_windows(Con *to_focus);
|
void output_push_sticky_windows(Con *old_focus);
|
||||||
|
|
|
@ -88,6 +88,14 @@ Output *get_output_by_name(const char *name, const bool require_active);
|
||||||
*/
|
*/
|
||||||
Output *get_output_containing(unsigned int x, unsigned int y);
|
Output *get_output_containing(unsigned int x, unsigned int y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the active output which contains the midpoint of the given rect. If
|
||||||
|
* such an output doesn't exist, returns the output which contains most of the
|
||||||
|
* rectangle or NULL if there is no output which intersects with it.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Output *get_output_from_rect(Rect rect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the active output which spans exactly the area specified by
|
* Returns the active output which spans exactly the area specified by
|
||||||
* rect or NULL if there is no output like this.
|
* rect or NULL if there is no output like this.
|
||||||
|
@ -95,15 +103,14 @@ Output *get_output_containing(unsigned int x, unsigned int y);
|
||||||
*/
|
*/
|
||||||
Output *get_output_with_dimensions(Rect rect);
|
Output *get_output_with_dimensions(Rect rect);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* In contained_by_output, we check if any active output contains part of the container.
|
* In output_containing_rect, we check if any active output contains part of the container.
|
||||||
* We do this by checking if the output rect is intersected by the Rect.
|
* We do this by checking if the output rect is intersected by the Rect.
|
||||||
* This is the 2-dimensional counterpart of get_output_containing.
|
* This is the 2-dimensional counterpart of get_output_containing.
|
||||||
* Since we don't actually need the outputs intersected by the given Rect (There could
|
* Returns the output with the maximum intersecting area.
|
||||||
* be many), we just return true or false for convenience.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool contained_by_output(Rect rect);
|
Output *output_containing_rect(Rect rect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the output which is the next one in the given direction.
|
* Gets the output which is the next one in the given direction.
|
||||||
|
@ -130,7 +137,7 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far
|
||||||
*/
|
*/
|
||||||
Output *get_output_next_wrap(direction_t direction, Output *current);
|
Output *get_output_next_wrap(direction_t direction, Output *current);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Creates an output covering the root window.
|
* Creates an output covering the root window.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,7 +12,10 @@
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
/* This is used to keep a state to pass around when rendering a con in render_con(). */
|
/**
|
||||||
|
* This is used to keep a state to pass around when rendering a con in render_con().
|
||||||
|
*
|
||||||
|
*/
|
||||||
typedef struct render_params {
|
typedef struct render_params {
|
||||||
/* A copy of the coordinates of the container which is being rendered. */
|
/* A copy of the coordinates of the container which is being rendered. */
|
||||||
int x;
|
int x;
|
||||||
|
@ -39,7 +42,8 @@ typedef struct render_params {
|
||||||
*/
|
*/
|
||||||
void render_con(Con *con, bool render_fullscreen);
|
void render_con(Con *con, bool render_fullscreen);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Returns the height for the decorations
|
* Returns the height for the decorations
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
int render_deco_height(void);
|
int render_deco_height(void);
|
||||||
|
|
|
@ -13,4 +13,27 @@
|
||||||
|
|
||||||
bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction, bool both_sides);
|
bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction, bool both_sides);
|
||||||
|
|
||||||
int resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event);
|
void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the two given containers using the given amount of pixels or
|
||||||
|
* percentage points. One of the two needs to be 0. A positive amount means
|
||||||
|
* growing the first container while a negative means shrinking it.
|
||||||
|
* Returns false when the resize would result in one of the two containers
|
||||||
|
* having less than 1 pixel of size.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool resize_neighboring_cons(Con *first, Con *second, int px, int ppt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the minimum percent needed for the given container to be at least 1
|
||||||
|
* pixel.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
double percent_for_1px(Con *con);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the given container's new percent given a change in pixels.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
double px_resize_to_percent(Con *con, int px_diff);
|
||||||
|
|
|
@ -29,7 +29,7 @@ void scratchpad_move(Con *con);
|
||||||
* can press the same key to quickly look something up).
|
* can press the same key to quickly look something up).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void scratchpad_show(Con *con);
|
bool scratchpad_show(Con *con);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When starting i3 initially (and after each change to the connected outputs),
|
* When starting i3 initially (and after each change to the connected outputs),
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
/* Default shmlog size if not set by user. */
|
/* Default shmlog size if not set by user. */
|
||||||
extern const int default_shmlog_size;
|
extern const int default_shmlog_size;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Header of the shmlog file. Used by i3/src/log.c and i3/i3-dump-log/main.c.
|
* Header of the shmlog file. Used by i3/src/log.c and i3/i3-dump-log/main.c.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
* Starts the given application by passing it through a shell. We use double
|
* Starts the given application by passing it through a shell. We use double
|
||||||
* fork to avoid zombie processes. As the started application’s parent exits
|
* fork to avoid zombie processes. As the started application’s parent exits
|
||||||
* (immediately), the application is reparented to init (process-id 1), which
|
* (immediately), the application is reparented to init (process-id 1), which
|
||||||
* correctly handles childs, so we don’t have to do it :-).
|
* correctly handles children, so we don’t have to do it :-).
|
||||||
*
|
*
|
||||||
* The shell used to start applications is the system's bourne shell (i.e.,
|
* The shell used to start applications is the system's bourne shell (i.e.,
|
||||||
* /bin/sh).
|
* /bin/sh).
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* vim:ts=4:sw=4:expandtab
|
||||||
|
*
|
||||||
|
* i3 - an improved dynamic tiling window manager
|
||||||
|
* © 2009 Michael Stapelberg and contributors (see also: LICENSE)
|
||||||
|
*
|
||||||
|
* sync.c: i3 sync protocol: https://i3wm.org/docs/testsuite.html#i3_sync
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
void sync_respond(xcb_window_t window, uint32_t rnd);
|
|
@ -78,7 +78,7 @@ void tree_next(char way, orientation_t orientation);
|
||||||
* container) and focus should be set there.
|
* container) and focus should be set there.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool force_set_focus);
|
bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_parent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads tree from ~/.i3/_restart.json (used for in-place restarts).
|
* Loads tree from ~/.i3/_restart.json (used for in-place restarts).
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
#define STARTS_WITH(string, needle) (strncasecmp((string), (needle), strlen((needle))) == 0)
|
#define STARTS_WITH(string, needle) (strncasecmp((string), (needle), strlen((needle))) == 0)
|
||||||
#define CIRCLEQ_NEXT_OR_NULL(head, elm, field) (CIRCLEQ_NEXT(elm, field) != CIRCLEQ_END(head) ? CIRCLEQ_NEXT(elm, field) : NULL)
|
#define CIRCLEQ_NEXT_OR_NULL(head, elm, field) (CIRCLEQ_NEXT(elm, field) != CIRCLEQ_END(head) ? CIRCLEQ_NEXT(elm, field) : NULL)
|
||||||
#define CIRCLEQ_PREV_OR_NULL(head, elm, field) (CIRCLEQ_PREV(elm, field) != CIRCLEQ_END(head) ? CIRCLEQ_PREV(elm, field) : NULL)
|
#define CIRCLEQ_PREV_OR_NULL(head, elm, field) (CIRCLEQ_PREV(elm, field) != CIRCLEQ_END(head) ? CIRCLEQ_PREV(elm, field) : NULL)
|
||||||
#define FOR_TABLE(workspace) \
|
|
||||||
for (int cols = 0; cols < (workspace)->cols; cols++) \
|
|
||||||
for (int rows = 0; rows < (workspace)->rows; rows++)
|
|
||||||
|
|
||||||
#define NODES_FOREACH(head) \
|
#define NODES_FOREACH(head) \
|
||||||
for (Con *child = (Con *)-1; (child == (Con *)-1) && ((child = 0), true);) \
|
for (Con *child = (Con *)-1; (child == (Con *)-1) && ((child = 0), true);) \
|
||||||
|
@ -128,7 +125,7 @@ void i3_restart(bool forget_layout);
|
||||||
|
|
||||||
#if defined(__OpenBSD__) || defined(__APPLE__)
|
#if defined(__OpenBSD__) || defined(__APPLE__)
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Taken from FreeBSD
|
* Taken from FreeBSD
|
||||||
* Find the first occurrence of the byte string s in byte string l.
|
* Find the first occurrence of the byte string s in byte string l.
|
||||||
*
|
*
|
||||||
|
@ -177,3 +174,9 @@ bool parse_long(const char *str, long *out, int base);
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ssize_t slurp(const char *path, char **buf);
|
ssize_t slurp(const char *path, char **buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a direction to its corresponding orientation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
orientation_t orientation_from_direction(direction_t direction);
|
||||||
|
|
|
@ -24,6 +24,27 @@
|
||||||
#define NET_WM_DESKTOP_NONE 0xFFFFFFF0
|
#define NET_WM_DESKTOP_NONE 0xFFFFFFF0
|
||||||
#define NET_WM_DESKTOP_ALL 0xFFFFFFFF
|
#define NET_WM_DESKTOP_ALL 0xFFFFFFFF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the workspace with the given name or NULL if such a workspace does
|
||||||
|
* not exist.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Con *get_existing_workspace_by_name(const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the workspace with the given number or NULL if such a workspace does
|
||||||
|
* not exist.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Con *get_existing_workspace_by_num(int num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the first output assigned to a workspace with the given
|
||||||
|
* workspace assignment is the same as the given output.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool output_triggers_assignment(Output *output, struct Workspace_Assignment *assignment);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a pointer to the workspace with the given number (starting at 0),
|
* Returns a pointer to the workspace with the given number (starting at 0),
|
||||||
* creating the workspace if necessary (by allocating the necessary amount of
|
* creating the workspace if necessary (by allocating the necessary amount of
|
||||||
|
@ -193,4 +214,4 @@ Con *workspace_encapsulate(Con *ws);
|
||||||
* This returns true if and only if moving the workspace was successful.
|
* This returns true if and only if moving the workspace was successful.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool workspace_move_to_output(Con *ws, const char *output);
|
bool workspace_move_to_output(Con *ws, Output *output);
|
||||||
|
|
|
@ -49,6 +49,12 @@ void x_reinit(Con *con);
|
||||||
*/
|
*/
|
||||||
void x_con_kill(Con *con);
|
void x_con_kill(Con *con);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Completely reinitializes the container's frame, without destroying the old window.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void x_con_reframe(Con *con);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the client supports the given protocol atom (like WM_DELETE_WINDOW)
|
* Returns true if the client supports the given protocol atom (like WM_DELETE_WINDOW)
|
||||||
*
|
*
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
ConfigureNotify */ \
|
ConfigureNotify */ \
|
||||||
XCB_EVENT_MASK_POINTER_MOTION | \
|
XCB_EVENT_MASK_POINTER_MOTION | \
|
||||||
XCB_EVENT_MASK_PROPERTY_CHANGE | \
|
XCB_EVENT_MASK_PROPERTY_CHANGE | \
|
||||||
|
XCB_EVENT_MASK_FOCUS_CHANGE | \
|
||||||
XCB_EVENT_MASK_ENTER_WINDOW)
|
XCB_EVENT_MASK_ENTER_WINDOW)
|
||||||
|
|
||||||
#define xmacro(atom) xcb_atom_t A_##atom;
|
#define xmacro(atom) xcb_atom_t A_##atom;
|
||||||
|
|
|
@ -49,14 +49,12 @@ void init_dpi(void) {
|
||||||
dpi = 0;
|
dpi = 0;
|
||||||
goto init_dpi_end;
|
goto init_dpi_end;
|
||||||
}
|
}
|
||||||
dpi = (long)round(in_dpi);
|
dpi = lround(in_dpi);
|
||||||
|
|
||||||
DLOG("Found Xft.dpi = %ld.\n", dpi);
|
DLOG("Found Xft.dpi = %ld.\n", dpi);
|
||||||
|
|
||||||
init_dpi_end:
|
init_dpi_end:
|
||||||
if (resource != NULL) {
|
free(resource);
|
||||||
free(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (database != NULL) {
|
if (database != NULL) {
|
||||||
xcb_xrm_database_free(database);
|
xcb_xrm_database_free(database);
|
||||||
|
|
|
@ -121,7 +121,7 @@ static void draw_util_set_source_color(surface_t *surface, color_t color) {
|
||||||
cairo_set_source_rgba(surface->cr, color.red, color.green, color.blue, color.alpha);
|
cairo_set_source_rgba(surface->cr, color.red, color.green, color.blue, color.alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Draw the given text using libi3.
|
* Draw the given text using libi3.
|
||||||
* This function also marks the surface dirty which is needed if other means of
|
* This function also marks the surface dirty which is needed if other means of
|
||||||
* drawing are used. This will be the case when using XCB to draw text.
|
* drawing are used. This will be the case when using XCB to draw text.
|
||||||
|
@ -140,7 +140,7 @@ void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_
|
||||||
cairo_surface_mark_dirty(surface->surface);
|
cairo_surface_mark_dirty(surface->surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Draws a filled rectangle.
|
* Draws a filled rectangle.
|
||||||
* This function is a convenience wrapper and takes care of flushing the
|
* This function is a convenience wrapper and takes care of flushing the
|
||||||
* surface as well as restoring the cairo state.
|
* surface as well as restoring the cairo state.
|
||||||
|
@ -167,7 +167,7 @@ void draw_util_rectangle(surface_t *surface, color_t color, double x, double y,
|
||||||
cairo_restore(surface->cr);
|
cairo_restore(surface->cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Clears a surface with the given color.
|
* Clears a surface with the given color.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -191,7 +191,7 @@ void draw_util_clear_surface(surface_t *surface, color_t color) {
|
||||||
cairo_restore(surface->cr);
|
cairo_restore(surface->cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Copies a surface onto another surface.
|
* Copies a surface onto another surface.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
26
libi3/font.c
26
libi3/font.c
|
@ -109,9 +109,8 @@ static void draw_text_pango(const char *text, size_t text_len,
|
||||||
cairo_set_source_rgb(cr, pango_font_red, pango_font_green, pango_font_blue);
|
cairo_set_source_rgb(cr, pango_font_red, pango_font_green, pango_font_blue);
|
||||||
pango_cairo_update_layout(cr, layout);
|
pango_cairo_update_layout(cr, layout);
|
||||||
pango_layout_get_pixel_size(layout, NULL, &height);
|
pango_layout_get_pixel_size(layout, NULL, &height);
|
||||||
/* Center the piece of text vertically if its height is smaller than the
|
/* Center the piece of text vertically. */
|
||||||
* cached font height, and just let "high" symbols fall out otherwise. */
|
int yoffset = (height - savedFont->height) / 2;
|
||||||
int yoffset = (height < savedFont->height ? 0.5 : 1) * (height - savedFont->height);
|
|
||||||
cairo_move_to(cr, x, y - yoffset);
|
cairo_move_to(cr, x, y - yoffset);
|
||||||
pango_cairo_show_layout(cr, layout);
|
pango_cairo_show_layout(cr, layout);
|
||||||
|
|
||||||
|
@ -224,9 +223,7 @@ i3Font load_font(const char *pattern, const bool fallback) {
|
||||||
error->error_code);
|
error->error_code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error != NULL) {
|
free(error);
|
||||||
free(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
font.pattern = sstrdup(pattern);
|
font.pattern = sstrdup(pattern);
|
||||||
LOG("Using X font %s\n", pattern);
|
LOG("Using X font %s\n", pattern);
|
||||||
|
@ -275,17 +272,13 @@ void free_font(void) {
|
||||||
case FONT_TYPE_XCB: {
|
case FONT_TYPE_XCB: {
|
||||||
/* Close the font and free the info */
|
/* Close the font and free the info */
|
||||||
xcb_close_font(conn, savedFont->specific.xcb.id);
|
xcb_close_font(conn, savedFont->specific.xcb.id);
|
||||||
if (savedFont->specific.xcb.info)
|
free(savedFont->specific.xcb.info);
|
||||||
free(savedFont->specific.xcb.info);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FONT_TYPE_PANGO:
|
case FONT_TYPE_PANGO:
|
||||||
/* Free the font description */
|
/* Free the font description */
|
||||||
pango_font_description_free(savedFont->specific.pango_desc);
|
pango_font_description_free(savedFont->specific.pango_desc);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
savedFont = NULL;
|
savedFont = NULL;
|
||||||
|
@ -315,9 +308,6 @@ void set_font_colors(xcb_gcontext_t gc, color_t foreground, color_t background)
|
||||||
pango_font_green = foreground.green;
|
pango_font_green = foreground.green;
|
||||||
pango_font_blue = foreground.blue;
|
pango_font_blue = foreground.blue;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,8 +378,6 @@ void draw_text(i3String *text, xcb_drawable_t drawable, xcb_gcontext_t gc,
|
||||||
draw_text_pango(i3string_as_utf8(text), i3string_get_num_bytes(text),
|
draw_text_pango(i3string_as_utf8(text), i3string_get_num_bytes(text),
|
||||||
drawable, visual, x, y, max_width, i3string_is_markup(text));
|
drawable, visual, x, y, max_width, i3string_is_markup(text));
|
||||||
return;
|
return;
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,8 +413,6 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable,
|
||||||
draw_text_pango(text, strlen(text),
|
draw_text_pango(text, strlen(text),
|
||||||
drawable, root_visual_type, x, y, max_width, false);
|
drawable, root_visual_type, x, y, max_width, false);
|
||||||
return;
|
return;
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,8 +505,6 @@ int predict_text_width(i3String *text) {
|
||||||
/* Calculate extents using Pango */
|
/* Calculate extents using Pango */
|
||||||
return predict_text_width_pango(i3string_as_utf8(text), i3string_get_num_bytes(text),
|
return predict_text_width_pango(i3string_as_utf8(text), i3string_get_num_bytes(text),
|
||||||
i3string_is_markup(text));
|
i3string_is_markup(text));
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef STARTS_WITH
|
#ifndef CS_STARTS_WITH
|
||||||
#define STARTS_WITH(string, needle) (strncasecmp((string), (needle), strlen((needle))) == 0)
|
#define CS_STARTS_WITH(string, needle) (strncmp((string), (needle), strlen((needle))) == 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -28,7 +28,7 @@ char *format_placeholders(char *format, placeholder_t *placeholders, int num) {
|
||||||
int buffer_len = strlen(format) + 1;
|
int buffer_len = strlen(format) + 1;
|
||||||
for (char *walk = format; *walk != '\0'; walk++) {
|
for (char *walk = format; *walk != '\0'; walk++) {
|
||||||
for (int i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
if (!STARTS_WITH(walk, placeholders[i].name))
|
if (!CS_STARTS_WITH(walk, placeholders[i].name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
buffer_len = buffer_len - strlen(placeholders[i].name) + strlen(placeholders[i].value);
|
buffer_len = buffer_len - strlen(placeholders[i].name) + strlen(placeholders[i].value);
|
||||||
|
@ -48,7 +48,7 @@ char *format_placeholders(char *format, placeholder_t *placeholders, int num) {
|
||||||
|
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
for (int i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
if (!STARTS_WITH(walk, placeholders[i].name)) {
|
if (!CS_STARTS_WITH(walk, placeholders[i].name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* g_utf8_make_valid.c - Coerce string into UTF-8
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Tom Tromey
|
||||||
|
* Copyright (C) 2000 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libi3.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/* Copied from:
|
||||||
|
* https://gitlab.gnome.org/GNOME/glib/blob/f928dfdf57bf92c883b53b16d7a9d49add504f52/glib/gutf8.c#L1752-1815 */
|
||||||
|
/* clang-format off */
|
||||||
|
#if !HAS_G_UTF8_MAKE_VALID
|
||||||
|
/**
|
||||||
|
* g_utf8_make_valid:
|
||||||
|
* @str: string to coerce into UTF-8
|
||||||
|
* @len: the maximum length of @str to use, in bytes. If @len < 0,
|
||||||
|
* then the string is nul-terminated.
|
||||||
|
*
|
||||||
|
* If the provided string is valid UTF-8, return a copy of it. If not,
|
||||||
|
* return a copy in which bytes that could not be interpreted as valid Unicode
|
||||||
|
* are replaced with the Unicode replacement character (U+FFFD).
|
||||||
|
*
|
||||||
|
* For example, this is an appropriate function to use if you have received
|
||||||
|
* a string that was incorrectly declared to be UTF-8, and you need a valid
|
||||||
|
* UTF-8 version of it that can be logged or displayed to the user, with the
|
||||||
|
* assumption that it is close enough to ASCII or UTF-8 to be mostly
|
||||||
|
* readable as-is.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a valid UTF-8 string whose content resembles @str
|
||||||
|
*
|
||||||
|
* Since: 2.52
|
||||||
|
*/
|
||||||
|
gchar *
|
||||||
|
g_utf8_make_valid (const gchar *str,
|
||||||
|
gssize len)
|
||||||
|
{
|
||||||
|
GString *string;
|
||||||
|
const gchar *remainder, *invalid;
|
||||||
|
gsize remaining_bytes, valid_bytes;
|
||||||
|
|
||||||
|
g_return_val_if_fail (str != NULL, NULL);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
len = strlen (str);
|
||||||
|
|
||||||
|
string = NULL;
|
||||||
|
remainder = str;
|
||||||
|
remaining_bytes = len;
|
||||||
|
|
||||||
|
while (remaining_bytes != 0)
|
||||||
|
{
|
||||||
|
if (g_utf8_validate (remainder, remaining_bytes, &invalid))
|
||||||
|
break;
|
||||||
|
valid_bytes = invalid - remainder;
|
||||||
|
|
||||||
|
if (string == NULL)
|
||||||
|
string = g_string_sized_new (remaining_bytes);
|
||||||
|
|
||||||
|
g_string_append_len (string, remainder, valid_bytes);
|
||||||
|
/* append U+FFFD REPLACEMENT CHARACTER */
|
||||||
|
g_string_append (string, "\357\277\275");
|
||||||
|
|
||||||
|
remaining_bytes -= valid_bytes + 1;
|
||||||
|
remainder = invalid + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string == NULL)
|
||||||
|
return g_strndup (str, len);
|
||||||
|
|
||||||
|
g_string_append_len (string, remainder, remaining_bytes);
|
||||||
|
g_string_append_c (string, '\0');
|
||||||
|
|
||||||
|
g_assert (g_utf8_validate (string->str, -1, NULL));
|
||||||
|
|
||||||
|
return g_string_free (string, FALSE);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -43,7 +43,7 @@ uint32_t get_colorpixel(const char *hex) {
|
||||||
|
|
||||||
/* Shortcut: if our screen is true color, no need to do a roundtrip to X11 */
|
/* Shortcut: if our screen is true color, no need to do a roundtrip to X11 */
|
||||||
if (root_screen == NULL || root_screen->root_depth == 24 || root_screen->root_depth == 32) {
|
if (root_screen == NULL || root_screen->root_depth == 24 || root_screen->root_depth == 32) {
|
||||||
return (0xFF << 24) | (r << 16 | g << 8 | b);
|
return (0xFFUL << 24) | (r << 16 | g << 8 | b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lookup this colorpixel in the cache */
|
/* Lookup this colorpixel in the cache */
|
||||||
|
@ -60,8 +60,7 @@ uint32_t get_colorpixel(const char *hex) {
|
||||||
|
|
||||||
xcb_alloc_color_reply_t *reply;
|
xcb_alloc_color_reply_t *reply;
|
||||||
|
|
||||||
reply = xcb_alloc_color_reply(conn, xcb_alloc_color(conn, root_screen->default_colormap,
|
reply = xcb_alloc_color_reply(conn, xcb_alloc_color(conn, root_screen->default_colormap, r16, g16, b16),
|
||||||
r16, g16, b16),
|
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (!reply) {
|
if (!reply) {
|
||||||
|
|
|
@ -21,11 +21,11 @@ static bool path_exists(const char *path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the path of the first configuration file found. If override_configpath
|
* Get the path of the first configuration file found. If override_configpath is
|
||||||
* is specified, that path is returned and saved for further calls. Otherwise,
|
* specified, that path is returned and saved for further calls. Otherwise,
|
||||||
* checks the home directory first, then the system directory first, always
|
* checks the home directory first, then the system directory, always taking
|
||||||
* taking into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
|
* into account the XDG Base Directory Specification ($XDG_CONFIG_HOME,
|
||||||
* $XDG_CONFIG_DIRS)
|
* $XDG_CONFIG_DIRS).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
char *get_config_path(const char *override_configpath, bool use_system_paths) {
|
char *get_config_path(const char *override_configpath, bool use_system_paths) {
|
||||||
|
@ -38,40 +38,41 @@ char *get_config_path(const char *override_configpath, bool use_system_paths) {
|
||||||
return sstrdup(saved_configpath);
|
return sstrdup(saved_configpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saved_configpath != NULL)
|
if (saved_configpath != NULL) {
|
||||||
return sstrdup(saved_configpath);
|
return sstrdup(saved_configpath);
|
||||||
|
}
|
||||||
|
|
||||||
/* 1: check the traditional path under the home directory */
|
/* 1: check for $XDG_CONFIG_HOME/i3/config */
|
||||||
config_path = resolve_tilde("~/.i3/config");
|
if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) {
|
||||||
if (path_exists(config_path))
|
|
||||||
return config_path;
|
|
||||||
free(config_path);
|
|
||||||
|
|
||||||
/* 2: check for $XDG_CONFIG_HOME/i3/config */
|
|
||||||
if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL)
|
|
||||||
xdg_config_home = "~/.config";
|
xdg_config_home = "~/.config";
|
||||||
|
}
|
||||||
|
|
||||||
xdg_config_home = resolve_tilde(xdg_config_home);
|
xdg_config_home = resolve_tilde(xdg_config_home);
|
||||||
sasprintf(&config_path, "%s/i3/config", xdg_config_home);
|
sasprintf(&config_path, "%s/i3/config", xdg_config_home);
|
||||||
free(xdg_config_home);
|
free(xdg_config_home);
|
||||||
|
|
||||||
if (path_exists(config_path))
|
if (path_exists(config_path)) {
|
||||||
return config_path;
|
return config_path;
|
||||||
|
}
|
||||||
|
free(config_path);
|
||||||
|
|
||||||
|
/* 2: check the traditional path under the home directory */
|
||||||
|
config_path = resolve_tilde("~/.i3/config");
|
||||||
|
if (path_exists(config_path)) {
|
||||||
|
return config_path;
|
||||||
|
}
|
||||||
free(config_path);
|
free(config_path);
|
||||||
|
|
||||||
/* The below paths are considered system-level, and can be skipped if the
|
/* The below paths are considered system-level, and can be skipped if the
|
||||||
* caller only wants user-level configs. */
|
* caller only wants user-level configs. */
|
||||||
if (!use_system_paths)
|
if (!use_system_paths) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* 3: check the traditional path under /etc */
|
/* 3: check for $XDG_CONFIG_DIRS/i3/config */
|
||||||
config_path = SYSCONFDIR "/i3/config";
|
if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL) {
|
||||||
if (path_exists(config_path))
|
|
||||||
return sstrdup(config_path);
|
|
||||||
|
|
||||||
/* 4: check for $XDG_CONFIG_DIRS/i3/config */
|
|
||||||
if ((xdg_config_dirs = getenv("XDG_CONFIG_DIRS")) == NULL)
|
|
||||||
xdg_config_dirs = SYSCONFDIR "/xdg";
|
xdg_config_dirs = SYSCONFDIR "/xdg";
|
||||||
|
}
|
||||||
|
|
||||||
char *buf = sstrdup(xdg_config_dirs);
|
char *buf = sstrdup(xdg_config_dirs);
|
||||||
char *tok = strtok(buf, ":");
|
char *tok = strtok(buf, ":");
|
||||||
|
@ -88,5 +89,11 @@ char *get_config_path(const char *override_configpath, bool use_system_paths) {
|
||||||
}
|
}
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
|
/* 4: check the traditional path under /etc */
|
||||||
|
config_path = SYSCONFDIR "/i3/config";
|
||||||
|
if (path_exists(config_path)) {
|
||||||
|
return sstrdup(config_path);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* release version), based on the git version number.
|
* release version), based on the git version number.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool is_debug_build() {
|
bool is_debug_build(void) {
|
||||||
/* i3_version contains either something like this:
|
/* i3_version contains either something like this:
|
||||||
* "4.0.2 (2011-11-11, branch "release")".
|
* "4.0.2 (2011-11-11, branch "release")".
|
||||||
* or: "4.0.2-123-gCOFFEEBABE (2011-11-11, branch "next")".
|
* or: "4.0.2-123-gCOFFEEBABE (2011-11-11, branch "next")".
|
||||||
|
|
|
@ -44,10 +44,7 @@ int mkdirp(const char *path, mode_t mode) {
|
||||||
|
|
||||||
char *sep = strrchr(copy, '/');
|
char *sep = strrchr(copy, '/');
|
||||||
if (sep == NULL) {
|
if (sep == NULL) {
|
||||||
if (copy != NULL) {
|
free(copy);
|
||||||
free(copy);
|
|
||||||
copy = NULL;
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*sep = '\0';
|
*sep = '\0';
|
||||||
|
|
|
@ -35,9 +35,10 @@ char *resolve_tilde(const char *path) {
|
||||||
} else {
|
} else {
|
||||||
head = globbuf.gl_pathv[0];
|
head = globbuf.gl_pathv[0];
|
||||||
result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1, 1);
|
result = scalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1, 1);
|
||||||
strncpy(result, head, strlen(head));
|
strcpy(result, head);
|
||||||
if (tail)
|
if (tail) {
|
||||||
strncat(result, tail, strlen(tail));
|
strcat(result, tail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
globfree(&globbuf);
|
globfree(&globbuf);
|
||||||
|
|
||||||
|
|
|
@ -68,10 +68,9 @@ int sasprintf(char **strp, const char *fmt, ...) {
|
||||||
|
|
||||||
ssize_t writeall(int fd, const void *buf, size_t count) {
|
ssize_t writeall(int fd, const void *buf, size_t count) {
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
ssize_t n = 0;
|
|
||||||
|
|
||||||
while (written < count) {
|
while (written < count) {
|
||||||
n = write(fd, buf + written, count - written);
|
const ssize_t n = write(fd, ((char *)buf) + written, count - written);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
if (errno == EINTR || errno == EAGAIN)
|
if (errno == EINTR || errno == EAGAIN)
|
||||||
continue;
|
continue;
|
||||||
|
@ -83,6 +82,25 @@ ssize_t writeall(int fd, const void *buf, size_t count) {
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t writeall_nonblock(int fd, const void *buf, size_t count) {
|
||||||
|
size_t written = 0;
|
||||||
|
|
||||||
|
while (written < count) {
|
||||||
|
const ssize_t n = write(fd, ((char *)buf) + written, count - written);
|
||||||
|
if (n == -1) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
return written;
|
||||||
|
} else if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
written += (size_t)n;
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t swrite(int fd, const void *buf, size_t count) {
|
ssize_t swrite(int fd, const void *buf, size_t count) {
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
|
|
||||||
|
|
|
@ -30,15 +30,7 @@ struct _i3String {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
i3String *i3string_from_utf8(const char *from_utf8) {
|
i3String *i3string_from_utf8(const char *from_utf8) {
|
||||||
i3String *str = scalloc(1, sizeof(i3String));
|
return i3string_from_utf8_with_length(from_utf8, -1);
|
||||||
|
|
||||||
/* Get the text */
|
|
||||||
str->utf8 = sstrdup(from_utf8);
|
|
||||||
|
|
||||||
/* Compute and store the length */
|
|
||||||
str->num_bytes = strlen(str->utf8);
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -56,20 +48,18 @@ i3String *i3string_from_markup(const char *from_markup) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build an i3String from an UTF-8 encoded string with fixed length.
|
* Build an i3String from an UTF-8 encoded string with fixed length.
|
||||||
* To be used when no proper NUL-terminaison is available.
|
* To be used when no proper NULL-termination is available.
|
||||||
* Returns the newly-allocated i3String.
|
* Returns the newly-allocated i3String.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
i3String *i3string_from_utf8_with_length(const char *from_utf8, size_t num_bytes) {
|
i3String *i3string_from_utf8_with_length(const char *from_utf8, ssize_t num_bytes) {
|
||||||
i3String *str = scalloc(1, sizeof(i3String));
|
i3String *str = scalloc(1, sizeof(i3String));
|
||||||
|
|
||||||
/* Copy the actual text to our i3String */
|
/* g_utf8_make_valid NULL-terminates the string. */
|
||||||
str->utf8 = scalloc(num_bytes + 1, 1);
|
str->utf8 = g_utf8_make_valid(from_utf8, num_bytes);
|
||||||
strncpy(str->utf8, from_utf8, num_bytes);
|
|
||||||
str->utf8[num_bytes] = '\0';
|
|
||||||
|
|
||||||
/* Store the length */
|
/* num_bytes < 0 means NULL-terminated string, need to calculate length */
|
||||||
str->num_bytes = num_bytes;
|
str->num_bytes = num_bytes < 0 ? strlen(str->utf8) : (size_t)num_bytes;
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +99,7 @@ i3String *i3string_from_ucs2(const xcb_char2b_t *from_ucs2, size_t num_glyphs) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Copies the given i3string.
|
* Copies the given i3string.
|
||||||
* Note that this will not free the source string.
|
* Note that this will not free the source string.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -83,8 +83,7 @@ xcb_char2b_t *convert_utf8_to_ucs2(char *input, size_t *real_strlen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the conversion */
|
/* Do the conversion */
|
||||||
size_t rc = iconv(ucs2_conversion_descriptor, (char **)&input,
|
size_t rc = iconv(ucs2_conversion_descriptor, &input, &input_size, (char **)&output, &output_size);
|
||||||
&input_size, (char **)&output, &output_size);
|
|
||||||
if (rc == (size_t)-1) {
|
if (rc == (size_t)-1) {
|
||||||
perror("Converting to UCS-2 failed");
|
perror("Converting to UCS-2 failed");
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
|
@ -9,7 +9,21 @@ i3-config-wizard - creates a keysym based config based on your layout
|
||||||
|
|
||||||
== SYNOPSIS
|
== SYNOPSIS
|
||||||
|
|
||||||
i3-config-wizard
|
i3-config-wizard [*-s* 'socket'] [*-m* 'modifier'] [*-v*] [*-h*]
|
||||||
|
|
||||||
|
== OPTIONS
|
||||||
|
|
||||||
|
*-s, --socket* 'socket'::
|
||||||
|
Overwrites the path to the i3 IPC socket.
|
||||||
|
|
||||||
|
*-m, --modifier* 'modifier'::
|
||||||
|
Generates the configuration file headlessly. Accepts win or alt.
|
||||||
|
|
||||||
|
*-v, --version*::
|
||||||
|
Display version number and exit.
|
||||||
|
|
||||||
|
*-h, --help*::
|
||||||
|
Display a short help message and exit.
|
||||||
|
|
||||||
== FILES
|
== FILES
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
i3-input(1)
|
i3-input(1)
|
||||||
=========
|
===========
|
||||||
Michael Stapelberg <michael+i3@stapelberg.de>
|
Michael Stapelberg <michael+i3@stapelberg.de>
|
||||||
v4.1.2, April 2012
|
v4.1.2, April 2012
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,11 @@ with an error.
|
||||||
*-t* 'type'::
|
*-t* 'type'::
|
||||||
Send ipc message, see below. This option defaults to "command".
|
Send ipc message, see below. This option defaults to "command".
|
||||||
|
|
||||||
|
*-m*, *--monitor*::
|
||||||
|
Instead of exiting right after receiving the first subscribed event,
|
||||||
|
wait indefinitely for all of them. Can only be used with "-t subscribe".
|
||||||
|
See the "subscribe" IPC message type below for details.
|
||||||
|
|
||||||
*message*::
|
*message*::
|
||||||
Send ipc message, see below.
|
Send ipc message, see below.
|
||||||
|
|
||||||
|
@ -69,6 +74,17 @@ get_version::
|
||||||
Gets the version of i3. The reply will be a JSON-encoded dictionary with the
|
Gets the version of i3. The reply will be a JSON-encoded dictionary with the
|
||||||
major, minor, patch and human-readable version.
|
major, minor, patch and human-readable version.
|
||||||
|
|
||||||
|
get_config::
|
||||||
|
Gets the currently loaded i3 configuration.
|
||||||
|
|
||||||
|
send_tick::
|
||||||
|
Sends a tick to all IPC connections which subscribe to tick events.
|
||||||
|
|
||||||
|
subscribe::
|
||||||
|
The payload of the message describes the events to subscribe to.
|
||||||
|
Upon reception, each event will be dumped as a JSON-encoded object.
|
||||||
|
See the -m option for continuous monitoring.
|
||||||
|
|
||||||
== DESCRIPTION
|
== DESCRIPTION
|
||||||
|
|
||||||
i3-msg is a sample implementation for a client using the unix socket IPC
|
i3-msg is a sample implementation for a client using the unix socket IPC
|
||||||
|
@ -85,6 +101,9 @@ i3-msg border normal
|
||||||
|
|
||||||
# Dump the layout tree
|
# Dump the layout tree
|
||||||
i3-msg -t get_tree
|
i3-msg -t get_tree
|
||||||
|
|
||||||
|
# Monitor window changes
|
||||||
|
i3-msg -t subscribe -m '[ "window" ]'
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
== ENVIRONMENT
|
== ENVIRONMENT
|
||||||
|
|
|
@ -9,7 +9,7 @@ i3-nagbar - displays an error bar on top of your screen
|
||||||
|
|
||||||
== SYNOPSIS
|
== SYNOPSIS
|
||||||
|
|
||||||
i3-nagbar [-m <message>] [-b <button> <action>] [-t warning|error] [-f <font>] [-v]
|
i3-nagbar [-m <message>] [-b <button> <action>] [-B <button> <action>] [-t warning|error] [-f <font>] [-v]
|
||||||
|
|
||||||
== OPTIONS
|
== OPTIONS
|
||||||
|
|
||||||
|
@ -32,6 +32,12 @@ Select font that is being used.
|
||||||
*-b, --button* 'button' 'action'::
|
*-b, --button* 'button' 'action'::
|
||||||
Create a button with text 'button'. The 'action' are the shell commands that
|
Create a button with text 'button'. The 'action' are the shell commands that
|
||||||
will be executed by this button. Multiple buttons can be defined.
|
will be executed by this button. Multiple buttons can be defined.
|
||||||
|
Will launch the shell commands inside a terminal emulator, using
|
||||||
|
i3-sensible-terminal.
|
||||||
|
|
||||||
|
*-B, --button-no-terminal* 'button' 'action'::
|
||||||
|
Same as above, but will execute the shell commands directly, without launching a
|
||||||
|
terminal emulator.
|
||||||
|
|
||||||
== DESCRIPTION
|
== DESCRIPTION
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
i3-sensible-editor(1)
|
i3-sensible-editor(1)
|
||||||
===================
|
=====================
|
||||||
Michael Stapelberg <michael+i3@stapelberg.de>
|
Michael Stapelberg <michael+i3@stapelberg.de>
|
||||||
v4.1, November 2011
|
v4.1, November 2011
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
i3-sensible-pager(1)
|
i3-sensible-pager(1)
|
||||||
===================
|
====================
|
||||||
Michael Stapelberg <michael+i3@stapelberg.de>
|
Michael Stapelberg <michael+i3@stapelberg.de>
|
||||||
v4.1, November 2011
|
v4.1, November 2011
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ It tries to start one of the following (in that order):
|
||||||
* kitty
|
* kitty
|
||||||
* guake
|
* guake
|
||||||
* tilda
|
* tilda
|
||||||
|
* alacritty
|
||||||
|
* hyper
|
||||||
|
|
||||||
Please don’t complain about the order: If the user has any preference, they will
|
Please don’t complain about the order: If the user has any preference, they will
|
||||||
have $TERMINAL set or modified their i3 configuration file.
|
have $TERMINAL set or modified their i3 configuration file.
|
||||||
|
|
|
@ -170,10 +170,10 @@ Exits i3.
|
||||||
|
|
||||||
When starting, i3 looks for configuration files in the following order:
|
When starting, i3 looks for configuration files in the following order:
|
||||||
|
|
||||||
1. ~/.i3/config
|
1. ~/.config/i3/config (or $XDG_CONFIG_HOME/i3/config if set)
|
||||||
2. ~/.config/i3/config (or $XDG_CONFIG_HOME/i3/config if set)
|
2. ~/.i3/config
|
||||||
3. /etc/i3/config
|
3. /etc/xdg/i3/config (or $XDG_CONFIG_DIRS/i3/config if set)
|
||||||
4. /etc/xdg/i3/config (or $XDG_CONFIG_DIRS/i3/config if set)
|
4. /etc/i3/config
|
||||||
|
|
||||||
You can specify a custom path using the -c option.
|
You can specify a custom path using the -c option.
|
||||||
|
|
||||||
|
|
|
@ -86,16 +86,16 @@ state DEBUGLOG:
|
||||||
# border normal|pixel [<n>]
|
# border normal|pixel [<n>]
|
||||||
# border none|1pixel|toggle
|
# border none|1pixel|toggle
|
||||||
state BORDER:
|
state BORDER:
|
||||||
border_style = 'normal', 'pixel'
|
border_style = 'normal', 'pixel', 'toggle'
|
||||||
-> BORDER_WIDTH
|
-> BORDER_WIDTH
|
||||||
border_style = 'none', 'toggle'
|
border_style = 'none'
|
||||||
-> call cmd_border($border_style, 0)
|
-> call cmd_border($border_style, 0)
|
||||||
border_style = '1pixel'
|
'1pixel'
|
||||||
-> call cmd_border($border_style, 1)
|
-> call cmd_border("pixel", 1)
|
||||||
|
|
||||||
state BORDER_WIDTH:
|
state BORDER_WIDTH:
|
||||||
end
|
end
|
||||||
-> call cmd_border($border_style, 2)
|
-> call cmd_border($border_style, -1)
|
||||||
border_width = number
|
border_width = number
|
||||||
-> call cmd_border($border_style, &border_width)
|
-> call cmd_border($border_style, &border_width)
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ state RESIZE_TILING:
|
||||||
'or'
|
'or'
|
||||||
-> RESIZE_TILING_OR
|
-> RESIZE_TILING_OR
|
||||||
end
|
end
|
||||||
-> call cmd_resize($way, $direction, &resize_px, 10)
|
-> call cmd_resize($way, $direction, &resize_px, 0)
|
||||||
|
|
||||||
state RESIZE_TILING_OR:
|
state RESIZE_TILING_OR:
|
||||||
resize_ppt = number
|
resize_ppt = number
|
||||||
|
@ -254,12 +254,24 @@ state RESIZE_TILING_FINAL:
|
||||||
-> call cmd_resize($way, $direction, &resize_px, &resize_ppt)
|
-> call cmd_resize($way, $direction, &resize_px, &resize_ppt)
|
||||||
|
|
||||||
state RESIZE_SET:
|
state RESIZE_SET:
|
||||||
|
'height'
|
||||||
|
-> RESIZE_HEIGHT_GET_NUMBER
|
||||||
|
'width'
|
||||||
|
->
|
||||||
width = number
|
width = number
|
||||||
-> RESIZE_WIDTH
|
-> RESIZE_WIDTH
|
||||||
|
|
||||||
state RESIZE_WIDTH:
|
state RESIZE_WIDTH:
|
||||||
mode_width = 'px', 'ppt'
|
mode_width = 'px', 'ppt'
|
||||||
->
|
->
|
||||||
|
end
|
||||||
|
-> call cmd_resize_set(&width, $mode_width, 0, 0)
|
||||||
|
'height'
|
||||||
|
-> RESIZE_HEIGHT_GET_NUMBER
|
||||||
|
height = number
|
||||||
|
-> RESIZE_HEIGHT
|
||||||
|
|
||||||
|
state RESIZE_HEIGHT_GET_NUMBER:
|
||||||
height = number
|
height = number
|
||||||
-> RESIZE_HEIGHT
|
-> RESIZE_HEIGHT
|
||||||
|
|
||||||
|
@ -396,7 +408,7 @@ state MOVE_TO_POSITION_X:
|
||||||
|
|
||||||
state MOVE_TO_POSITION_Y:
|
state MOVE_TO_POSITION_Y:
|
||||||
'px', end
|
'px', end
|
||||||
-> call cmd_move_window_to_position($method, &coord_x, &coord_y)
|
-> call cmd_move_window_to_position(&coord_x, &coord_y)
|
||||||
|
|
||||||
# mode <string>
|
# mode <string>
|
||||||
state MODE:
|
state MODE:
|
||||||
|
|
|
@ -45,9 +45,11 @@ state INITIAL:
|
||||||
'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS
|
'fake_outputs', 'fake-outputs' -> FAKE_OUTPUTS
|
||||||
'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT
|
'force_display_urgency_hint' -> FORCE_DISPLAY_URGENCY_HINT
|
||||||
'focus_on_window_activation' -> FOCUS_ON_WINDOW_ACTIVATION
|
'focus_on_window_activation' -> FOCUS_ON_WINDOW_ACTIVATION
|
||||||
|
'title_align' -> TITLE_ALIGN
|
||||||
'show_marks' -> SHOW_MARKS
|
'show_marks' -> SHOW_MARKS
|
||||||
'workspace' -> WORKSPACE
|
'workspace' -> WORKSPACE
|
||||||
'ipc_socket', 'ipc-socket' -> IPC_SOCKET
|
'ipc_socket', 'ipc-socket' -> IPC_SOCKET
|
||||||
|
'ipc_kill_timeout' -> IPC_KILL_TIMEOUT
|
||||||
'restart_state' -> RESTART_STATE
|
'restart_state' -> RESTART_STATE
|
||||||
'popup_during_fullscreen' -> POPUP_DURING_FULLSCREEN
|
'popup_during_fullscreen' -> POPUP_DURING_FULLSCREEN
|
||||||
exectype = 'exec_always', 'exec' -> EXEC
|
exectype = 'exec_always', 'exec' -> EXEC
|
||||||
|
@ -247,6 +249,11 @@ state FORCE_DISPLAY_URGENCY_HINT:
|
||||||
duration_ms = number
|
duration_ms = number
|
||||||
-> FORCE_DISPLAY_URGENCY_HINT_MS
|
-> FORCE_DISPLAY_URGENCY_HINT_MS
|
||||||
|
|
||||||
|
# title_align [left|center|right]
|
||||||
|
state TITLE_ALIGN:
|
||||||
|
alignment = 'left', 'center', 'right'
|
||||||
|
-> call cfg_title_align($alignment)
|
||||||
|
|
||||||
# show_marks
|
# show_marks
|
||||||
state SHOW_MARKS:
|
state SHOW_MARKS:
|
||||||
value = word
|
value = word
|
||||||
|
@ -273,7 +280,7 @@ state WORKSPACE_OUTPUT:
|
||||||
-> WORKSPACE_OUTPUT_STR
|
-> WORKSPACE_OUTPUT_STR
|
||||||
|
|
||||||
state WORKSPACE_OUTPUT_STR:
|
state WORKSPACE_OUTPUT_STR:
|
||||||
output = word
|
output = string
|
||||||
-> call cfg_workspace($workspace, $output)
|
-> call cfg_workspace($workspace, $output)
|
||||||
|
|
||||||
# ipc-socket <path>
|
# ipc-socket <path>
|
||||||
|
@ -281,6 +288,11 @@ state IPC_SOCKET:
|
||||||
path = string
|
path = string
|
||||||
-> call cfg_ipc_socket($path)
|
-> call cfg_ipc_socket($path)
|
||||||
|
|
||||||
|
# ipc_kill_timeout
|
||||||
|
state IPC_KILL_TIMEOUT:
|
||||||
|
timeout = number
|
||||||
|
-> call cfg_ipc_kill_timeout(&timeout)
|
||||||
|
|
||||||
# restart_state <path> (for testcases)
|
# restart_state <path> (for testcases)
|
||||||
state RESTART_STATE:
|
state RESTART_STATE:
|
||||||
path = string
|
path = string
|
||||||
|
@ -455,6 +467,7 @@ state BAR:
|
||||||
'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR
|
'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR
|
||||||
'workspace_buttons' -> BAR_WORKSPACE_BUTTONS
|
'workspace_buttons' -> BAR_WORKSPACE_BUTTONS
|
||||||
'strip_workspace_numbers' -> BAR_STRIP_WORKSPACE_NUMBERS
|
'strip_workspace_numbers' -> BAR_STRIP_WORKSPACE_NUMBERS
|
||||||
|
'strip_workspace_name' -> BAR_STRIP_WORKSPACE_NAME
|
||||||
'verbose' -> BAR_VERBOSE
|
'verbose' -> BAR_VERBOSE
|
||||||
'colors' -> BAR_COLORS_BRACE
|
'colors' -> BAR_COLORS_BRACE
|
||||||
'}'
|
'}'
|
||||||
|
@ -490,8 +503,14 @@ state BAR_ID:
|
||||||
-> call cfg_bar_id($bar_id); BAR
|
-> call cfg_bar_id($bar_id); BAR
|
||||||
|
|
||||||
state BAR_MODIFIER:
|
state BAR_MODIFIER:
|
||||||
modifier = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Control', 'Ctrl', 'Shift', 'none', 'off'
|
'off', 'none'
|
||||||
-> call cfg_bar_modifier($modifier); BAR
|
-> call cfg_bar_modifier(NULL); BAR
|
||||||
|
modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl'
|
||||||
|
->
|
||||||
|
'+'
|
||||||
|
->
|
||||||
|
end
|
||||||
|
-> call cfg_bar_modifier($modifiers); BAR
|
||||||
|
|
||||||
state BAR_WHEEL_UP_CMD:
|
state BAR_WHEEL_UP_CMD:
|
||||||
command = string
|
command = string
|
||||||
|
@ -555,6 +574,10 @@ state BAR_STRIP_WORKSPACE_NUMBERS:
|
||||||
value = word
|
value = word
|
||||||
-> call cfg_bar_strip_workspace_numbers($value); BAR
|
-> call cfg_bar_strip_workspace_numbers($value); BAR
|
||||||
|
|
||||||
|
state BAR_STRIP_WORKSPACE_NAME:
|
||||||
|
value = word
|
||||||
|
-> call cfg_bar_strip_workspace_name($value); BAR
|
||||||
|
|
||||||
state BAR_VERBOSE:
|
state BAR_VERBOSE:
|
||||||
value = word
|
value = word
|
||||||
-> call cfg_bar_verbose($value); BAR
|
-> call cfg_bar_verbose($value); BAR
|
||||||
|
|
13
release.sh
13
release.sh
|
@ -1,9 +1,9 @@
|
||||||
#!/bin/zsh
|
#!/bin/zsh
|
||||||
# This script is used to prepare a new release of i3.
|
# This script is used to prepare a new release of i3.
|
||||||
|
|
||||||
export RELEASE_VERSION="4.14.1"
|
export RELEASE_VERSION="4.15"
|
||||||
export PREVIOUS_VERSION="4.14"
|
export PREVIOUS_VERSION="4.14"
|
||||||
export RELEASE_BRANCH="master"
|
export RELEASE_BRANCH="next"
|
||||||
|
|
||||||
if [ ! -e "../i3.github.io" ]
|
if [ ! -e "../i3.github.io" ]
|
||||||
then
|
then
|
||||||
|
@ -85,12 +85,12 @@ if [ "${RELEASE_BRANCH}" = "master" ]; then
|
||||||
git checkout master
|
git checkout master
|
||||||
git merge --no-ff release-${RELEASE_VERSION} -m "Merge branch 'release-${RELEASE_VERSION}'"
|
git merge --no-ff release-${RELEASE_VERSION} -m "Merge branch 'release-${RELEASE_VERSION}'"
|
||||||
git checkout next
|
git checkout next
|
||||||
git merge --no-ff -X ours master -m "Merge branch 'master' into next"
|
git merge --no-ff -s recursive -X ours -X no-renames master -m "Merge branch 'master' into next"
|
||||||
else
|
else
|
||||||
git checkout next
|
git checkout next
|
||||||
git merge --no-ff release-${RELEASE_VERSION} -m "Merge branch 'release-${RELEASE_VERSION}'"
|
git merge --no-ff release-${RELEASE_VERSION} -m "Merge branch 'release-${RELEASE_VERSION}'"
|
||||||
git checkout master
|
git checkout master
|
||||||
git merge --no-ff -X theirs next -m "Merge branch 'next' into master"
|
git merge --no-ff -s recursive -X theirs -X no-renames next -m "Merge branch 'next' into master"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git remote remove origin
|
git remote remove origin
|
||||||
|
@ -126,6 +126,7 @@ WORKDIR /usr/src
|
||||||
RUN mk-build-deps --install --remove --tool 'apt-get --no-install-recommends -y' i3-${RELEASE_VERSION}/debian/control
|
RUN mk-build-deps --install --remove --tool 'apt-get --no-install-recommends -y' i3-${RELEASE_VERSION}/debian/control
|
||||||
WORKDIR /usr/src/i3-${RELEASE_VERSION}
|
WORKDIR /usr/src/i3-${RELEASE_VERSION}
|
||||||
RUN dpkg-buildpackage -sa -j8
|
RUN dpkg-buildpackage -sa -j8
|
||||||
|
RUN dpkg-buildpackage -S -sa -j8
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
CONTAINER_NAME=$(echo "i3-${TMPDIR}" | sed 's,/,,g')
|
CONTAINER_NAME=$(echo "i3-${TMPDIR}" | sed 's,/,,g')
|
||||||
|
@ -139,7 +140,7 @@ echo "Content of resulting package’s .changes file:"
|
||||||
cat ${TMPDIR}/debian/*.changes
|
cat ${TMPDIR}/debian/*.changes
|
||||||
|
|
||||||
# debsign is in devscripts, which is available in fedora and debian
|
# debsign is in devscripts, which is available in fedora and debian
|
||||||
debsign -k4AC8EE1D ${TMPDIR}/debian/*.changes
|
debsign --no-re-sign -k4AC8EE1D ${TMPDIR}/debian/*.changes
|
||||||
|
|
||||||
# TODO: docker cleanup
|
# TODO: docker cleanup
|
||||||
|
|
||||||
|
@ -227,7 +228,7 @@ echo " cd ${TMPDIR}/i3.github.io"
|
||||||
echo " git push"
|
echo " git push"
|
||||||
echo ""
|
echo ""
|
||||||
echo " cd ${TMPDIR}/debian"
|
echo " cd ${TMPDIR}/debian"
|
||||||
echo " dput *.changes"
|
echo " dput"
|
||||||
echo ""
|
echo ""
|
||||||
echo " cd ${TMPDIR}"
|
echo " cd ${TMPDIR}"
|
||||||
echo " sendmail -t < email.txt"
|
echo " sendmail -t < email.txt"
|
||||||
|
|
|
@ -22,7 +22,7 @@ void run_assignments(i3Window *window) {
|
||||||
/* Check if any assignments match */
|
/* Check if any assignments match */
|
||||||
Assignment *current;
|
Assignment *current;
|
||||||
TAILQ_FOREACH(current, &assignments, assignments) {
|
TAILQ_FOREACH(current, &assignments, assignments) {
|
||||||
if (!match_matches_window(&(current->match), window))
|
if (current->type != A_COMMAND || !match_matches_window(&(current->match), window))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
|
@ -45,19 +45,16 @@ void run_assignments(i3Window *window) {
|
||||||
window->ran_assignments = srealloc(window->ran_assignments, sizeof(Assignment *) * window->nr_assignments);
|
window->ran_assignments = srealloc(window->ran_assignments, sizeof(Assignment *) * window->nr_assignments);
|
||||||
window->ran_assignments[window->nr_assignments - 1] = current;
|
window->ran_assignments[window->nr_assignments - 1] = current;
|
||||||
|
|
||||||
DLOG("matching assignment, would do:\n");
|
DLOG("matching assignment, execute command %s\n", current->dest.command);
|
||||||
if (current->type == A_COMMAND) {
|
char *full_command;
|
||||||
DLOG("execute command %s\n", current->dest.command);
|
sasprintf(&full_command, "[id=\"%d\"] %s", window->id, current->dest.command);
|
||||||
char *full_command;
|
CommandResult *result = parse_command(full_command, NULL);
|
||||||
sasprintf(&full_command, "[id=\"%d\"] %s", window->id, current->dest.command);
|
free(full_command);
|
||||||
CommandResult *result = parse_command(full_command, NULL);
|
|
||||||
free(full_command);
|
|
||||||
|
|
||||||
if (result->needs_tree_render)
|
if (result->needs_tree_render)
|
||||||
needs_tree_render = true;
|
needs_tree_render = true;
|
||||||
|
|
||||||
command_result_free(result);
|
command_result_free(result);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If any of the commands required re-rendering, we will do that now. */
|
/* If any of the commands required re-rendering, we will do that now. */
|
||||||
|
|
138
src/bindings.c
138
src/bindings.c
|
@ -198,6 +198,7 @@ void regrab_all_buttons(xcb_connection_t *conn) {
|
||||||
*/
|
*/
|
||||||
static Binding *get_binding(i3_event_state_mask_t state_filtered, bool is_release, uint16_t input_code, input_type_t input_type) {
|
static Binding *get_binding(i3_event_state_mask_t state_filtered, bool is_release, uint16_t input_code, input_type_t input_type) {
|
||||||
Binding *bind;
|
Binding *bind;
|
||||||
|
Binding *result = NULL;
|
||||||
|
|
||||||
if (!is_release) {
|
if (!is_release) {
|
||||||
/* On a press event, we first reset all B_UPON_KEYRELEASE_IGNORE_MODS
|
/* On a press event, we first reset all B_UPON_KEYRELEASE_IGNORE_MODS
|
||||||
|
@ -227,30 +228,27 @@ static Binding *get_binding(i3_event_state_mask_t state_filtered, bool is_releas
|
||||||
/* For keyboard bindings where a symbol was specified by the user, we
|
/* For keyboard bindings where a symbol was specified by the user, we
|
||||||
* need to look in the array of translated keycodes for the event’s
|
* need to look in the array of translated keycodes for the event’s
|
||||||
* keycode */
|
* keycode */
|
||||||
|
bool found_keycode = false;
|
||||||
if (input_type == B_KEYBOARD && bind->symbol != NULL) {
|
if (input_type == B_KEYBOARD && bind->symbol != NULL) {
|
||||||
xcb_keycode_t input_keycode = (xcb_keycode_t)input_code;
|
xcb_keycode_t input_keycode = (xcb_keycode_t)input_code;
|
||||||
bool found_keycode = false;
|
|
||||||
struct Binding_Keycode *binding_keycode;
|
struct Binding_Keycode *binding_keycode;
|
||||||
TAILQ_FOREACH(binding_keycode, &(bind->keycodes_head), keycodes) {
|
TAILQ_FOREACH(binding_keycode, &(bind->keycodes_head), keycodes) {
|
||||||
const uint32_t modifiers_mask = (binding_keycode->modifiers & 0x0000FFFF);
|
const uint32_t modifiers_mask = (binding_keycode->modifiers & 0x0000FFFF);
|
||||||
const bool mods_match = (modifiers_mask == modifiers_state);
|
const bool mods_match = (modifiers_mask == modifiers_state);
|
||||||
DLOG("binding_keycode->modifiers = %d, modifiers_mask = %d, modifiers_state = %d, mods_match = %s\n",
|
DLOG("binding_keycode->modifiers = %d, modifiers_mask = %d, modifiers_state = %d, mods_match = %s\n",
|
||||||
binding_keycode->modifiers, modifiers_mask, modifiers_state, (mods_match ? "yes" : "no"));
|
binding_keycode->modifiers, modifiers_mask, modifiers_state, (mods_match ? "yes" : "no"));
|
||||||
if (binding_keycode->keycode == input_keycode && mods_match) {
|
if (binding_keycode->keycode == input_keycode &&
|
||||||
|
(mods_match || (bind->release == B_UPON_KEYRELEASE_IGNORE_MODS && is_release))) {
|
||||||
found_keycode = true;
|
found_keycode = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found_keycode) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* This case is easier: The user specified a keycode */
|
/* This case is easier: The user specified a keycode */
|
||||||
if (bind->keycode != input_code) {
|
if (bind->keycode != input_code) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool found_keycode = false;
|
|
||||||
struct Binding_Keycode *binding_keycode;
|
struct Binding_Keycode *binding_keycode;
|
||||||
TAILQ_FOREACH(binding_keycode, &(bind->keycodes_head), keycodes) {
|
TAILQ_FOREACH(binding_keycode, &(bind->keycodes_head), keycodes) {
|
||||||
const uint32_t modifiers_mask = (binding_keycode->modifiers & 0x0000FFFF);
|
const uint32_t modifiers_mask = (binding_keycode->modifiers & 0x0000FFFF);
|
||||||
|
@ -262,9 +260,9 @@ static Binding *get_binding(i3_event_state_mask_t state_filtered, bool is_releas
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found_keycode) {
|
}
|
||||||
continue;
|
if (!found_keycode) {
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this binding is a release binding, it matches the key which the
|
/* If this binding is a release binding, it matches the key which the
|
||||||
|
@ -274,23 +272,26 @@ static Binding *get_binding(i3_event_state_mask_t state_filtered, bool is_releas
|
||||||
if (bind->release == B_UPON_KEYRELEASE && !is_release) {
|
if (bind->release == B_UPON_KEYRELEASE && !is_release) {
|
||||||
bind->release = B_UPON_KEYRELEASE_IGNORE_MODS;
|
bind->release = B_UPON_KEYRELEASE_IGNORE_MODS;
|
||||||
DLOG("marked bind %p as B_UPON_KEYRELEASE_IGNORE_MODS\n", bind);
|
DLOG("marked bind %p as B_UPON_KEYRELEASE_IGNORE_MODS\n", bind);
|
||||||
/* The correct binding has been found, so abort the search, but
|
if (result) {
|
||||||
* also don’t return this binding, since it should not be executed
|
break;
|
||||||
* yet (only when the keys are released). */
|
}
|
||||||
bind = TAILQ_END(bindings);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the binding is for a press or a release event */
|
|
||||||
if ((bind->release == B_UPON_KEYPRESS && is_release) ||
|
|
||||||
(bind->release >= B_UPON_KEYRELEASE && !is_release)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
/* Check if the binding is for a press or a release event */
|
||||||
|
if ((bind->release == B_UPON_KEYPRESS && is_release)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_release) {
|
||||||
|
return bind;
|
||||||
|
} else if (!result) {
|
||||||
|
/* Continue looping to mark needed B_UPON_KEYRELEASE_IGNORE_MODS. */
|
||||||
|
result = bind;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (bind == TAILQ_END(bindings) ? NULL : bind);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -361,6 +362,14 @@ struct resolve {
|
||||||
struct xkb_state *xkb_state_numlock_no_shift;
|
struct xkb_state *xkb_state_numlock_no_shift;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ADD_TRANSLATED_KEY(code, mods) \
|
||||||
|
do { \
|
||||||
|
struct Binding_Keycode *binding_keycode = smalloc(sizeof(struct Binding_Keycode)); \
|
||||||
|
binding_keycode->modifiers = (mods); \
|
||||||
|
binding_keycode->keycode = (code); \
|
||||||
|
TAILQ_INSERT_TAIL(&(bind->keycodes_head), binding_keycode, keycodes); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add_keycode_if_matches is called for each keycode in the keymap and will add
|
* add_keycode_if_matches is called for each keycode in the keymap and will add
|
||||||
* the keycode to |data->bind| if the keycode can result in the keysym
|
* the keycode to |data->bind| if the keycode can result in the keysym
|
||||||
|
@ -390,18 +399,10 @@ static void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key,
|
||||||
}
|
}
|
||||||
Binding *bind = resolving->bind;
|
Binding *bind = resolving->bind;
|
||||||
|
|
||||||
#define ADD_TRANSLATED_KEY(mods) \
|
ADD_TRANSLATED_KEY(key, bind->event_state_mask);
|
||||||
do { \
|
|
||||||
struct Binding_Keycode *binding_keycode = smalloc(sizeof(struct Binding_Keycode)); \
|
|
||||||
binding_keycode->modifiers = (mods); \
|
|
||||||
binding_keycode->keycode = key; \
|
|
||||||
TAILQ_INSERT_TAIL(&(bind->keycodes_head), binding_keycode, keycodes); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
ADD_TRANSLATED_KEY(bind->event_state_mask);
|
|
||||||
|
|
||||||
/* Also bind the key with active CapsLock */
|
/* Also bind the key with active CapsLock */
|
||||||
ADD_TRANSLATED_KEY(bind->event_state_mask | XCB_MOD_MASK_LOCK);
|
ADD_TRANSLATED_KEY(key, bind->event_state_mask | XCB_MOD_MASK_LOCK);
|
||||||
|
|
||||||
/* If this binding is not explicitly for NumLock, check whether we need to
|
/* If this binding is not explicitly for NumLock, check whether we need to
|
||||||
* add a fallback. */
|
* add a fallback. */
|
||||||
|
@ -413,17 +414,15 @@ static void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key,
|
||||||
xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(numlock_state, key);
|
xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(numlock_state, key);
|
||||||
if (sym_numlock == resolving->keysym) {
|
if (sym_numlock == resolving->keysym) {
|
||||||
/* Also bind the key with active NumLock */
|
/* Also bind the key with active NumLock */
|
||||||
ADD_TRANSLATED_KEY(bind->event_state_mask | xcb_numlock_mask);
|
ADD_TRANSLATED_KEY(key, bind->event_state_mask | xcb_numlock_mask);
|
||||||
|
|
||||||
/* Also bind the key with active NumLock+CapsLock */
|
/* Also bind the key with active NumLock+CapsLock */
|
||||||
ADD_TRANSLATED_KEY(bind->event_state_mask | xcb_numlock_mask | XCB_MOD_MASK_LOCK);
|
ADD_TRANSLATED_KEY(key, bind->event_state_mask | xcb_numlock_mask | XCB_MOD_MASK_LOCK);
|
||||||
} else {
|
} else {
|
||||||
DLOG("Skipping automatic numlock fallback, key %d resolves to 0x%x with numlock\n",
|
DLOG("Skipping automatic numlock fallback, key %d resolves to 0x%x with numlock\n",
|
||||||
key, sym_numlock);
|
key, sym_numlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ADD_TRANSLATED_KEY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -431,41 +430,22 @@ static void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key,
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void translate_keysyms(void) {
|
void translate_keysyms(void) {
|
||||||
struct xkb_state *dummy_state = xkb_state_new(xkb_keymap);
|
struct xkb_state *dummy_state = NULL;
|
||||||
if (dummy_state == NULL) {
|
struct xkb_state *dummy_state_no_shift = NULL;
|
||||||
ELOG("Could not create XKB state, cannot translate keysyms.\n");
|
struct xkb_state *dummy_state_numlock = NULL;
|
||||||
return;
|
struct xkb_state *dummy_state_numlock_no_shift = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
struct xkb_state *dummy_state_no_shift = xkb_state_new(xkb_keymap);
|
|
||||||
if (dummy_state_no_shift == NULL) {
|
|
||||||
ELOG("Could not create XKB state, cannot translate keysyms.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct xkb_state *dummy_state_numlock = xkb_state_new(xkb_keymap);
|
|
||||||
if (dummy_state_numlock == NULL) {
|
|
||||||
ELOG("Could not create XKB state, cannot translate keysyms.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct xkb_state *dummy_state_numlock_no_shift = xkb_state_new(xkb_keymap);
|
|
||||||
if (dummy_state_numlock_no_shift == NULL) {
|
|
||||||
ELOG("Could not create XKB state, cannot translate keysyms.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_errors = false;
|
bool has_errors = false;
|
||||||
|
|
||||||
|
if ((dummy_state = xkb_state_new(xkb_keymap)) == NULL ||
|
||||||
|
(dummy_state_no_shift = xkb_state_new(xkb_keymap)) == NULL ||
|
||||||
|
(dummy_state_numlock = xkb_state_new(xkb_keymap)) == NULL ||
|
||||||
|
(dummy_state_numlock_no_shift = xkb_state_new(xkb_keymap)) == NULL) {
|
||||||
|
ELOG("Could not create XKB state, cannot translate keysyms.\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
Binding *bind;
|
Binding *bind;
|
||||||
TAILQ_FOREACH(bind, bindings, bindings) {
|
TAILQ_FOREACH(bind, bindings, bindings) {
|
||||||
#define ADD_TRANSLATED_KEY(code, mods) \
|
|
||||||
do { \
|
|
||||||
struct Binding_Keycode *binding_keycode = smalloc(sizeof(struct Binding_Keycode)); \
|
|
||||||
binding_keycode->modifiers = (mods); \
|
|
||||||
binding_keycode->keycode = (code); \
|
|
||||||
TAILQ_INSERT_TAIL(&(bind->keycodes_head), binding_keycode, keycodes); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
if (bind->input_type == B_MOUSE) {
|
if (bind->input_type == B_MOUSE) {
|
||||||
long button;
|
long button;
|
||||||
if (!parse_long(bind->symbol + (sizeof("button") - 1), &button, 10)) {
|
if (!parse_long(bind->symbol + (sizeof("button") - 1), &button, 10)) {
|
||||||
|
@ -616,10 +596,9 @@ void translate_keysyms(void) {
|
||||||
DLOG("state=0x%x, cfg=\"%s\", sym=0x%x → keycodes%s (%d)\n",
|
DLOG("state=0x%x, cfg=\"%s\", sym=0x%x → keycodes%s (%d)\n",
|
||||||
bind->event_state_mask, bind->symbol, keysym, keycodes, num_keycodes);
|
bind->event_state_mask, bind->symbol, keysym, keycodes, num_keycodes);
|
||||||
free(keycodes);
|
free(keycodes);
|
||||||
|
|
||||||
#undef ADD_TRANSLATED_KEY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
xkb_state_unref(dummy_state);
|
xkb_state_unref(dummy_state);
|
||||||
xkb_state_unref(dummy_state_no_shift);
|
xkb_state_unref(dummy_state_no_shift);
|
||||||
xkb_state_unref(dummy_state_numlock);
|
xkb_state_unref(dummy_state_numlock);
|
||||||
|
@ -630,6 +609,8 @@ void translate_keysyms(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef ADD_TRANSLATED_KEY
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Switches the key bindings to the given mode, if the mode exists
|
* Switches the key bindings to the given mode, if the mode exists
|
||||||
*
|
*
|
||||||
|
@ -648,6 +629,14 @@ void switch_mode(const char *new_mode) {
|
||||||
translate_keysyms();
|
translate_keysyms();
|
||||||
grab_all_keys(conn);
|
grab_all_keys(conn);
|
||||||
|
|
||||||
|
/* Reset all B_UPON_KEYRELEASE_IGNORE_MODS bindings to avoid possibly
|
||||||
|
* activating one of them. */
|
||||||
|
Binding *bind;
|
||||||
|
TAILQ_FOREACH(bind, bindings, bindings) {
|
||||||
|
if (bind->release == B_UPON_KEYRELEASE_IGNORE_MODS)
|
||||||
|
bind->release = B_UPON_KEYRELEASE;
|
||||||
|
}
|
||||||
|
|
||||||
char *event_msg;
|
char *event_msg;
|
||||||
sasprintf(&event_msg, "{\"change\":\"%s\", \"pango_markup\":%s}",
|
sasprintf(&event_msg, "{\"change\":\"%s\", \"pango_markup\":%s}",
|
||||||
mode->name, (mode->pango_markup ? "true" : "false"));
|
mode->name, (mode->pango_markup ? "true" : "false"));
|
||||||
|
@ -658,7 +647,7 @@ void switch_mode(const char *new_mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ELOG("ERROR: Mode not found\n");
|
ELOG("Mode not found\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reorder_binding_cmp(const void *a, const void *b) {
|
static int reorder_binding_cmp(const void *a, const void *b) {
|
||||||
|
@ -870,8 +859,6 @@ static int fill_rmlvo_from_root(struct xkb_rule_names *xkb_names) {
|
||||||
xcb_intern_atom_reply_t *atom_reply;
|
xcb_intern_atom_reply_t *atom_reply;
|
||||||
size_t content_max_words = 256;
|
size_t content_max_words = 256;
|
||||||
|
|
||||||
xcb_window_t root = root_screen->root;
|
|
||||||
|
|
||||||
atom_reply = xcb_intern_atom_reply(
|
atom_reply = xcb_intern_atom_reply(
|
||||||
conn, xcb_intern_atom(conn, 0, strlen("_XKB_RULES_NAMES"), "_XKB_RULES_NAMES"), NULL);
|
conn, xcb_intern_atom(conn, 0, strlen("_XKB_RULES_NAMES"), "_XKB_RULES_NAMES"), NULL);
|
||||||
if (atom_reply == NULL)
|
if (atom_reply == NULL)
|
||||||
|
@ -968,10 +955,7 @@ bool load_keymap(void) {
|
||||||
.options = NULL};
|
.options = NULL};
|
||||||
if (fill_rmlvo_from_root(&names) == -1) {
|
if (fill_rmlvo_from_root(&names) == -1) {
|
||||||
ELOG("Could not get _XKB_RULES_NAMES atom from root window, falling back to defaults.\n");
|
ELOG("Could not get _XKB_RULES_NAMES atom from root window, falling back to defaults.\n");
|
||||||
if ((new_keymap = xkb_keymap_new_from_names(xkb_context, &names, 0)) == NULL) {
|
/* Using NULL for the fields of xkb_rule_names. */
|
||||||
ELOG("xkb_keymap_new_from_names(NULL) failed\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
new_keymap = xkb_keymap_new_from_names(xkb_context, &names, 0);
|
new_keymap = xkb_keymap_new_from_names(xkb_context, &names, 0);
|
||||||
free((char *)names.rules);
|
free((char *)names.rules);
|
||||||
|
@ -980,7 +964,7 @@ bool load_keymap(void) {
|
||||||
free((char *)names.variant);
|
free((char *)names.variant);
|
||||||
free((char *)names.options);
|
free((char *)names.options);
|
||||||
if (new_keymap == NULL) {
|
if (new_keymap == NULL) {
|
||||||
ELOG("xkb_keymap_new_from_names(RMLVO) failed\n");
|
ELOG("xkb_keymap_new_from_names failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/click.c
16
src/click.c
|
@ -44,9 +44,6 @@ static bool tiling_resize_for_border(Con *con, border_t border, xcb_button_press
|
||||||
case BORDER_BOTTOM:
|
case BORDER_BOTTOM:
|
||||||
search_direction = D_DOWN;
|
search_direction = D_DOWN;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool res = resize_find_tiling_participants(&first, &second, search_direction, false);
|
bool res = resize_find_tiling_participants(&first, &second, search_direction, false);
|
||||||
|
@ -233,15 +230,12 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod
|
||||||
event->detail == XCB_BUTTON_SCROLL_LEFT ||
|
event->detail == XCB_BUTTON_SCROLL_LEFT ||
|
||||||
event->detail == XCB_BUTTON_SCROLL_RIGHT)) {
|
event->detail == XCB_BUTTON_SCROLL_RIGHT)) {
|
||||||
DLOG("Scrolling on a window decoration\n");
|
DLOG("Scrolling on a window decoration\n");
|
||||||
orientation_t orientation = (con->parent->layout == L_STACKED ? VERT : HORIZ);
|
orientation_t orientation = con_orientation(con->parent);
|
||||||
/* Focus the currently focused container on the same level that the
|
/* Use the focused child of the tabbed / stacked container, not the
|
||||||
* user scrolled on. e.g. the tabbed decoration contains
|
* container the user scrolled on. */
|
||||||
* "urxvt | i3: V[xterm geeqie] | firefox",
|
|
||||||
* focus is on the xterm, but the user scrolled on urxvt.
|
|
||||||
* The splitv container will be focused. */
|
|
||||||
Con *focused = con->parent;
|
Con *focused = con->parent;
|
||||||
focused = TAILQ_FIRST(&(focused->focus_head));
|
focused = TAILQ_FIRST(&(focused->focus_head));
|
||||||
con_activate(focused);
|
con_activate(con_descend_focused(focused));
|
||||||
/* To prevent scrolling from going outside the container (see ticket
|
/* To prevent scrolling from going outside the container (see ticket
|
||||||
* #557), we first check if scrolling is possible at all. */
|
* #557), we first check if scrolling is possible at all. */
|
||||||
bool scroll_prev_possible = (TAILQ_PREV(focused, nodes_head, nodes) != NULL);
|
bool scroll_prev_possible = (TAILQ_PREV(focused, nodes_head, nodes) != NULL);
|
||||||
|
@ -260,7 +254,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod
|
||||||
|
|
||||||
/* 3: For floating containers, we also want to raise them on click.
|
/* 3: For floating containers, we also want to raise them on click.
|
||||||
* We will skip handling events on floating cons in fullscreen mode */
|
* We will skip handling events on floating cons in fullscreen mode */
|
||||||
Con *fs = (ws ? con_get_fullscreen_con(ws, CF_OUTPUT) : NULL);
|
Con *fs = con_get_fullscreen_covering_ws(ws);
|
||||||
if (floatingcon != NULL && fs != con) {
|
if (floatingcon != NULL && fs != con) {
|
||||||
/* 4: floating_modifier plus left mouse button drags */
|
/* 4: floating_modifier plus left mouse button drags */
|
||||||
if (mod_pressed && event->detail == XCB_BUTTON_CLICK_LEFT) {
|
if (mod_pressed && event->detail == XCB_BUTTON_CLICK_LEFT) {
|
||||||
|
|
646
src/commands.c
646
src/commands.c
File diff suppressed because it is too large
Load Diff
|
@ -157,7 +157,7 @@ static long get_long(const char *identifier) {
|
||||||
// TODO move to a common util
|
// TODO move to a common util
|
||||||
static void clear_stack(void) {
|
static void clear_stack(void) {
|
||||||
for (int c = 0; c < 10; c++) {
|
for (int c = 0; c < 10; c++) {
|
||||||
if (stack[c].type == STACK_STR && stack[c].val.str != NULL)
|
if (stack[c].type == STACK_STR)
|
||||||
free(stack[c].val.str);
|
free(stack[c].val.str);
|
||||||
stack[c].identifier = NULL;
|
stack[c].identifier = NULL;
|
||||||
stack[c].val.str = NULL;
|
stack[c].val.str = NULL;
|
||||||
|
|
161
src/con.c
161
src/con.c
|
@ -286,14 +286,14 @@ void con_close(Con *con, kill_window_t kill_window) {
|
||||||
for (child = TAILQ_FIRST(&(con->focus_head)); child;) {
|
for (child = TAILQ_FIRST(&(con->focus_head)); child;) {
|
||||||
nextchild = TAILQ_NEXT(child, focused);
|
nextchild = TAILQ_NEXT(child, focused);
|
||||||
DLOG("killing child = %p.\n", child);
|
DLOG("killing child = %p.\n", child);
|
||||||
tree_close_internal(child, kill_window, false, false);
|
tree_close_internal(child, kill_window, false);
|
||||||
child = nextchild;
|
child = nextchild;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_close_internal(con, kill_window, false, false);
|
tree_close_internal(con, kill_window, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -312,7 +312,7 @@ bool con_has_managed_window(Con *con) {
|
||||||
return (con != NULL && con->window != NULL && con->window->id != XCB_WINDOW_NONE && con_get_workspace(con) != NULL);
|
return (con != NULL && con->window != NULL && con->window->id != XCB_WINDOW_NONE && con_get_workspace(con) != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Returns true if this node has regular or floating children.
|
* Returns true if this node has regular or floating children.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -509,7 +509,24 @@ Con *con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
|
* Returns the fullscreen node that covers the given workspace if it exists.
|
||||||
|
* This is either a CF_GLOBAL fullscreen container anywhere or a CF_OUTPUT
|
||||||
|
* fullscreen container in the workspace.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Con *con_get_fullscreen_covering_ws(Con *ws) {
|
||||||
|
if (!ws) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Con *fs = con_get_fullscreen_con(croot, CF_GLOBAL);
|
||||||
|
if (!fs) {
|
||||||
|
return con_get_fullscreen_con(ws, CF_OUTPUT);
|
||||||
|
}
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
* Returns true if the container is internal, such as __i3_scratch
|
* Returns true if the container is internal, such as __i3_scratch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -879,7 +896,7 @@ int con_num_children(Con *con) {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Returns the number of visible non-floating children of this container.
|
* Returns the number of visible non-floating children of this container.
|
||||||
* For example, if the container contains a hsplit which has two children,
|
* For example, if the container contains a hsplit which has two children,
|
||||||
* this will return 2 instead of 1.
|
* this will return 2 instead of 1.
|
||||||
|
@ -919,6 +936,10 @@ int con_num_windows(Con *con) {
|
||||||
num += con_num_windows(current);
|
num += con_num_windows(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TAILQ_FOREACH(current, &(con->floating_head), floating_windows) {
|
||||||
|
num += con_num_windows(current);
|
||||||
|
}
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1097,7 +1118,7 @@ static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fi
|
||||||
|
|
||||||
/* Prevent moving if this would violate the fullscreen focus restrictions. */
|
/* Prevent moving if this would violate the fullscreen focus restrictions. */
|
||||||
Con *target_ws = con_get_workspace(target);
|
Con *target_ws = con_get_workspace(target);
|
||||||
if (!con_fullscreen_permits_focusing(target_ws)) {
|
if (!ignore_focus && !con_fullscreen_permits_focusing(target_ws)) {
|
||||||
LOG("Cannot move out of a fullscreen container.\n");
|
LOG("Cannot move out of a fullscreen container.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1140,7 +1161,13 @@ static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fi
|
||||||
|
|
||||||
/* 1: save the container which is going to be focused after the current
|
/* 1: save the container which is going to be focused after the current
|
||||||
* container is moved away */
|
* container is moved away */
|
||||||
Con *focus_next = con_next_focused(con);
|
Con *focus_next = NULL;
|
||||||
|
if (!ignore_focus && source_ws == current_ws) {
|
||||||
|
focus_next = con_descend_focused(source_ws);
|
||||||
|
if (focus_next == con || con_has_parent(focus_next, con)) {
|
||||||
|
focus_next = con_next_focused(con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 2: we go up one level, but only when target is a normal container */
|
/* 2: we go up one level, but only when target is a normal container */
|
||||||
if (target->type != CT_WORKSPACE) {
|
if (target->type != CT_WORKSPACE) {
|
||||||
|
@ -1148,13 +1175,13 @@ static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fi
|
||||||
target = target->parent;
|
target = target->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3: if the target container is floating, we get the workspace instead.
|
/* 3: if the original target is the direct child of a floating container, we
|
||||||
* Only tiling windows need to get inserted next to the current container.
|
* can't move con next to it - floating containers have only one child - so
|
||||||
* */
|
* we get the workspace instead. */
|
||||||
Con *floatingcon = con_inside_floating(target);
|
if (target->type == CT_FLOATING_CON) {
|
||||||
if (floatingcon != NULL) {
|
|
||||||
DLOG("floatingcon, going up even further\n");
|
DLOG("floatingcon, going up even further\n");
|
||||||
target = floatingcon->parent;
|
orig_target = target;
|
||||||
|
target = target->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (con->type == CT_FLOATING_CON) {
|
if (con->type == CT_FLOATING_CON) {
|
||||||
|
@ -1170,20 +1197,6 @@ static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fi
|
||||||
floating_fix_coordinates(con, &(source_output->rect), &(dest_output->rect));
|
floating_fix_coordinates(con, &(source_output->rect), &(dest_output->rect));
|
||||||
} else
|
} else
|
||||||
DLOG("Not fixing coordinates, fix_coordinates flag = %d\n", fix_coordinates);
|
DLOG("Not fixing coordinates, fix_coordinates flag = %d\n", fix_coordinates);
|
||||||
|
|
||||||
/* If moving to a visible workspace, call show so it can be considered
|
|
||||||
* focused. Must do before attaching because workspace_show checks to see
|
|
||||||
* if focused container is in its area. */
|
|
||||||
if (!ignore_focus && workspace_is_visible(target_ws)) {
|
|
||||||
workspace_show(target_ws);
|
|
||||||
|
|
||||||
/* Don’t warp if told so (when dragging floating windows with the
|
|
||||||
* mouse for example) */
|
|
||||||
if (dont_warp)
|
|
||||||
x_set_warp_to(NULL);
|
|
||||||
else
|
|
||||||
x_set_warp_to(&(con->rect));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If moving a fullscreen container and the destination already has a
|
/* If moving a fullscreen container and the destination already has a
|
||||||
|
@ -1217,20 +1230,21 @@ static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fi
|
||||||
/* We need to save the focused workspace on the output in case the
|
/* We need to save the focused workspace on the output in case the
|
||||||
* new workspace is hidden and it's necessary to immediately switch
|
* new workspace is hidden and it's necessary to immediately switch
|
||||||
* back to the originally-focused workspace. */
|
* back to the originally-focused workspace. */
|
||||||
Con *old_focus = TAILQ_FIRST(&(output_get_content(dest_output)->focus_head));
|
Con *old_focus_ws = TAILQ_FIRST(&(output_get_content(dest_output)->focus_head));
|
||||||
|
Con *old_focus = focused;
|
||||||
con_activate(con_descend_focused(con));
|
con_activate(con_descend_focused(con));
|
||||||
|
|
||||||
/* Restore focus if the output's focused workspace has changed. */
|
if (old_focus_ws == current_ws && old_focus->type != CT_WORKSPACE) {
|
||||||
if (con_get_workspace(focused) != old_focus)
|
/* Restore focus to the currently focused container. */
|
||||||
con_activate(old_focus);
|
con_activate(old_focus);
|
||||||
|
} else if (con_get_workspace(focused) != old_focus_ws) {
|
||||||
|
/* Restore focus if the output's focused workspace has changed. */
|
||||||
|
con_focus(con_descend_focused(old_focus_ws));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 7: when moving to another workspace, we leave the focus on the current
|
/* 7: when moving to another workspace, we leave the focus on the current
|
||||||
* workspace. (see also #809) */
|
* workspace. (see also #809) */
|
||||||
|
|
||||||
/* Descend focus stack in case focus_next is a workspace which can
|
|
||||||
* occur if we move to the same workspace. Also show current workspace
|
|
||||||
* to ensure it is focused. */
|
|
||||||
if (!ignore_focus) {
|
if (!ignore_focus) {
|
||||||
workspace_show(current_ws);
|
workspace_show(current_ws);
|
||||||
if (dont_warp) {
|
if (dont_warp) {
|
||||||
|
@ -1241,7 +1255,7 @@ static bool _con_move_to_con(Con *con, Con *target, bool behind_focused, bool fi
|
||||||
|
|
||||||
/* Set focus only if con was on current workspace before moving.
|
/* Set focus only if con was on current workspace before moving.
|
||||||
* Otherwise we would give focus to some window on different workspace. */
|
* Otherwise we would give focus to some window on different workspace. */
|
||||||
if (!ignore_focus && source_ws == current_ws)
|
if (focus_next)
|
||||||
con_activate(con_descend_focused(focus_next));
|
con_activate(con_descend_focused(focus_next));
|
||||||
|
|
||||||
/* 8. If anything within the container is associated with a startup sequence,
|
/* 8. If anything within the container is associated with a startup sequence,
|
||||||
|
@ -1310,7 +1324,7 @@ bool con_move_to_mark(Con *con, const char *mark) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (con->type == CT_WORKSPACE) {
|
if (target->type == CT_WORKSPACE) {
|
||||||
DLOG("target container is a workspace, simply moving the container there.\n");
|
DLOG("target container is a workspace, simply moving the container there.\n");
|
||||||
con_move_to_workspace(con, target, true, false, false);
|
con_move_to_workspace(con, target, true, false, false);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1418,20 +1432,16 @@ orientation_t con_orientation(Con *con) {
|
||||||
return HORIZ;
|
return HORIZ;
|
||||||
|
|
||||||
case L_DEFAULT:
|
case L_DEFAULT:
|
||||||
DLOG("Someone called con_orientation() on a con with L_DEFAULT, this is a bug in the code.\n");
|
ELOG("Someone called con_orientation() on a con with L_DEFAULT, this is a bug in the code.\n");
|
||||||
assert(false);
|
assert(false);
|
||||||
return HORIZ;
|
|
||||||
|
|
||||||
case L_DOCKAREA:
|
case L_DOCKAREA:
|
||||||
case L_OUTPUT:
|
case L_OUTPUT:
|
||||||
DLOG("con_orientation() called on dockarea/output (%d) container %p\n", con->layout, con);
|
ELOG("con_orientation() called on dockarea/output (%d) container %p\n", con->layout, con);
|
||||||
assert(false);
|
|
||||||
return HORIZ;
|
|
||||||
|
|
||||||
default:
|
|
||||||
DLOG("con_orientation() ran into default\n");
|
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
/* should not be reached */
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1441,52 +1451,20 @@ orientation_t con_orientation(Con *con) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Con *con_next_focused(Con *con) {
|
Con *con_next_focused(Con *con) {
|
||||||
Con *next;
|
|
||||||
/* floating containers are attached to a workspace, so we focus either the
|
|
||||||
* next floating container (if any) or the workspace itself. */
|
|
||||||
if (con->type == CT_FLOATING_CON) {
|
|
||||||
DLOG("selecting next for CT_FLOATING_CON\n");
|
|
||||||
next = TAILQ_NEXT(con, floating_windows);
|
|
||||||
DLOG("next = %p\n", next);
|
|
||||||
if (!next) {
|
|
||||||
next = TAILQ_PREV(con, floating_head, floating_windows);
|
|
||||||
DLOG("using prev, next = %p\n", next);
|
|
||||||
}
|
|
||||||
if (!next) {
|
|
||||||
Con *ws = con_get_workspace(con);
|
|
||||||
next = ws;
|
|
||||||
DLOG("no more floating containers for next = %p, restoring workspace focus\n", next);
|
|
||||||
while (next != TAILQ_END(&(ws->focus_head)) && !TAILQ_EMPTY(&(next->focus_head))) {
|
|
||||||
next = TAILQ_FIRST(&(next->focus_head));
|
|
||||||
if (next == con) {
|
|
||||||
DLOG("skipping container itself, we want the next client\n");
|
|
||||||
next = TAILQ_NEXT(next, focused);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (next == TAILQ_END(&(ws->focus_head))) {
|
|
||||||
DLOG("Focus list empty, returning ws\n");
|
|
||||||
next = ws;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Instead of returning the next CT_FLOATING_CON, we descend it to
|
|
||||||
* get an actual window to focus. */
|
|
||||||
next = con_descend_focused(next);
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dock clients cannot be focused, so we focus the workspace instead */
|
/* dock clients cannot be focused, so we focus the workspace instead */
|
||||||
if (con->parent->type == CT_DOCKAREA) {
|
if (con->parent->type == CT_DOCKAREA) {
|
||||||
DLOG("selecting workspace for dock client\n");
|
DLOG("selecting workspace for dock client\n");
|
||||||
return con_descend_focused(output_get_content(con->parent->parent));
|
return con_descend_focused(output_get_content(con->parent->parent));
|
||||||
}
|
}
|
||||||
|
if (con_is_floating(con)) {
|
||||||
|
con = con->parent;
|
||||||
|
}
|
||||||
|
|
||||||
/* if 'con' is not the first entry in the focus stack, use the first one as
|
/* if 'con' is not the first entry in the focus stack, use the first one as
|
||||||
* it’s currently focused already */
|
* it’s currently focused already */
|
||||||
Con *first = TAILQ_FIRST(&(con->parent->focus_head));
|
Con *next = TAILQ_FIRST(&(con->parent->focus_head));
|
||||||
if (first != con) {
|
if (next != con) {
|
||||||
DLOG("Using first entry %p\n", first);
|
DLOG("Using first entry %p\n", next);
|
||||||
next = first;
|
|
||||||
} else {
|
} else {
|
||||||
/* try to focus the next container on the same level as this one or fall
|
/* try to focus the next container on the same level as this one or fall
|
||||||
* back to its parent */
|
* back to its parent */
|
||||||
|
@ -1501,6 +1479,10 @@ Con *con_next_focused(Con *con) {
|
||||||
next = TAILQ_FIRST(&(next->focus_head));
|
next = TAILQ_FIRST(&(next->focus_head));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (con->type == CT_FLOATING_CON && next != con->parent) {
|
||||||
|
next = con_descend_focused(next);
|
||||||
|
}
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1734,8 +1716,7 @@ adjacent_t con_adjacent_borders(Con *con) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int con_border_style(Con *con) {
|
int con_border_style(Con *con) {
|
||||||
Con *fs = con_get_fullscreen_con(con->parent, CF_OUTPUT);
|
if (con->fullscreen_mode == CF_OUTPUT || con->fullscreen_mode == CF_GLOBAL) {
|
||||||
if (fs == con) {
|
|
||||||
DLOG("this one is fullscreen! overriding BS_NONE\n");
|
DLOG("this one is fullscreen! overriding BS_NONE\n");
|
||||||
return BS_NONE;
|
return BS_NONE;
|
||||||
}
|
}
|
||||||
|
@ -1935,7 +1916,6 @@ void con_toggle_layout(Con *con, const char *toggle_mode) {
|
||||||
* now let's activate the current layout (next in list) */
|
* now let's activate the current layout (next in list) */
|
||||||
if (current_layout_found) {
|
if (current_layout_found) {
|
||||||
new_layout = layout;
|
new_layout = layout;
|
||||||
free(tm_dup);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1943,6 +1923,7 @@ void con_toggle_layout(Con *con, const char *toggle_mode) {
|
||||||
current_layout_found = true;
|
current_layout_found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(tm_dup);
|
||||||
|
|
||||||
if (new_layout != L_DEFAULT) {
|
if (new_layout != L_DEFAULT) {
|
||||||
con_set_layout(con, new_layout);
|
con_set_layout(con, new_layout);
|
||||||
|
@ -1995,7 +1976,7 @@ static void con_on_remove_child(Con *con) {
|
||||||
if (TAILQ_EMPTY(&(con->focus_head)) && !workspace_is_visible(con)) {
|
if (TAILQ_EMPTY(&(con->focus_head)) && !workspace_is_visible(con)) {
|
||||||
LOG("Closing old workspace (%p / %s), it is empty\n", con, con->name);
|
LOG("Closing old workspace (%p / %s), it is empty\n", con, con->name);
|
||||||
yajl_gen gen = ipc_marshal_workspace_event("empty", con, NULL);
|
yajl_gen gen = ipc_marshal_workspace_event("empty", con, NULL);
|
||||||
tree_close_internal(con, DONT_KILL_WINDOW, false, false);
|
tree_close_internal(con, DONT_KILL_WINDOW, false);
|
||||||
|
|
||||||
const unsigned char *payload;
|
const unsigned char *payload;
|
||||||
ylength length;
|
ylength length;
|
||||||
|
@ -2016,7 +1997,7 @@ static void con_on_remove_child(Con *con) {
|
||||||
int children = con_num_children(con);
|
int children = con_num_children(con);
|
||||||
if (children == 0) {
|
if (children == 0) {
|
||||||
DLOG("Container empty, closing\n");
|
DLOG("Container empty, closing\n");
|
||||||
tree_close_internal(con, DONT_KILL_WINDOW, false, false);
|
tree_close_internal(con, DONT_KILL_WINDOW, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2413,6 +2394,10 @@ bool con_swap(Con *first, Con *second) {
|
||||||
|
|
||||||
/* Move first to second. */
|
/* Move first to second. */
|
||||||
result &= _con_move_to_con(first, second, false, false, false, true, false);
|
result &= _con_move_to_con(first, second, false, false, false, true, false);
|
||||||
|
/* If swapping the containers didn't work we don't need to mess with the focus. */
|
||||||
|
if (!result) {
|
||||||
|
goto swap_end;
|
||||||
|
}
|
||||||
|
|
||||||
/* If we moved the container holding the focused window to another
|
/* If we moved the container holding the focused window to another
|
||||||
* workspace we need to ensure the visible workspace has the focused
|
* workspace we need to ensure the visible workspace has the focused
|
||||||
|
@ -2425,8 +2410,6 @@ bool con_swap(Con *first, Con *second) {
|
||||||
|
|
||||||
/* Move second to where first has been originally. */
|
/* Move second to where first has been originally. */
|
||||||
result &= _con_move_to_con(second, fake, false, false, false, true, false);
|
result &= _con_move_to_con(second, fake, false, false, false, true, false);
|
||||||
|
|
||||||
/* If swapping the containers didn't work we don't need to mess with the focus. */
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
goto swap_end;
|
goto swap_end;
|
||||||
}
|
}
|
||||||
|
|
38
src/config.c
38
src/config.c
|
@ -18,7 +18,7 @@ Config config;
|
||||||
struct modes_head modes;
|
struct modes_head modes;
|
||||||
struct barconfig_head barconfigs = TAILQ_HEAD_INITIALIZER(barconfigs);
|
struct barconfig_head barconfigs = TAILQ_HEAD_INITIALIZER(barconfigs);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Ungrabs all keys, to be called before re-grabbing the keys because of a
|
* Ungrabs all keys, to be called before re-grabbing the keys because of a
|
||||||
* mapping_notify event or a configuration file reload
|
* mapping_notify event or a configuration file reload
|
||||||
*
|
*
|
||||||
|
@ -32,7 +32,7 @@ void ungrab_all_keys(xcb_connection_t *conn) {
|
||||||
* Sends the current bar configuration as an event to all barconfig_update listeners.
|
* Sends the current bar configuration as an event to all barconfig_update listeners.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void update_barconfig() {
|
void update_barconfig(void) {
|
||||||
Barconfig *current;
|
Barconfig *current;
|
||||||
TAILQ_FOREACH(current, &barconfigs, configs) {
|
TAILQ_FOREACH(current, &barconfigs, configs) {
|
||||||
ipc_send_barconfig_update_event(current);
|
ipc_send_barconfig_update_event(current);
|
||||||
|
@ -49,7 +49,8 @@ bool parse_configuration(const char *override_configpath, bool use_nagbar) {
|
||||||
char *path = get_config_path(override_configpath, true);
|
char *path = get_config_path(override_configpath, true);
|
||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
die("Unable to find the configuration file (looked at "
|
die("Unable to find the configuration file (looked at "
|
||||||
"~/.i3/config, $XDG_CONFIG_HOME/i3/config, " SYSCONFDIR "/i3/config and $XDG_CONFIG_DIRS/i3/config)");
|
"$XDG_CONFIG_HOME/i3/config, ~/.i3/config, $XDG_CONFIG_DIRS/i3/config "
|
||||||
|
"and " SYSCONFDIR "/i3/config)");
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Parsing configfile %s\n", path);
|
LOG("Parsing configfile %s\n", path);
|
||||||
|
@ -96,18 +97,27 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
|
||||||
FREE(mode);
|
FREE(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Assignment *assign;
|
|
||||||
while (!TAILQ_EMPTY(&assignments)) {
|
while (!TAILQ_EMPTY(&assignments)) {
|
||||||
assign = TAILQ_FIRST(&assignments);
|
struct Assignment *assign = TAILQ_FIRST(&assignments);
|
||||||
if (assign->type == A_TO_WORKSPACE)
|
if (assign->type == A_TO_WORKSPACE || assign->type == A_TO_WORKSPACE_NUMBER)
|
||||||
FREE(assign->dest.workspace);
|
FREE(assign->dest.workspace);
|
||||||
else if (assign->type == A_COMMAND)
|
else if (assign->type == A_COMMAND)
|
||||||
FREE(assign->dest.command);
|
FREE(assign->dest.command);
|
||||||
|
else if (assign->type == A_TO_OUTPUT)
|
||||||
|
FREE(assign->dest.output);
|
||||||
match_free(&(assign->match));
|
match_free(&(assign->match));
|
||||||
TAILQ_REMOVE(&assignments, assign, assignments);
|
TAILQ_REMOVE(&assignments, assign, assignments);
|
||||||
FREE(assign);
|
FREE(assign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (!TAILQ_EMPTY(&ws_assignments)) {
|
||||||
|
struct Workspace_Assignment *assign = TAILQ_FIRST(&ws_assignments);
|
||||||
|
FREE(assign->name);
|
||||||
|
FREE(assign->output);
|
||||||
|
TAILQ_REMOVE(&ws_assignments, assign, ws_assignments);
|
||||||
|
FREE(assign);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear bar configs */
|
/* Clear bar configs */
|
||||||
Barconfig *barconfig;
|
Barconfig *barconfig;
|
||||||
while (!TAILQ_EMPTY(&barconfigs)) {
|
while (!TAILQ_EMPTY(&barconfigs)) {
|
||||||
|
@ -160,10 +170,16 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
|
||||||
FREE(barconfig);
|
FREE(barconfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invalidate pixmap caches in case font or colors changed */
|
|
||||||
Con *con;
|
Con *con;
|
||||||
TAILQ_FOREACH(con, &all_cons, all_cons)
|
TAILQ_FOREACH(con, &all_cons, all_cons) {
|
||||||
FREE(con->deco_render_params);
|
/* Assignments changed, previously ran assignments are invalid. */
|
||||||
|
if (con->window) {
|
||||||
|
con->window->nr_assignments = 0;
|
||||||
|
FREE(con->window->ran_assignments);
|
||||||
|
}
|
||||||
|
/* Invalidate pixmap caches in case font or colors changed. */
|
||||||
|
FREE(con->deco_render_params);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get rid of the current font */
|
/* Get rid of the current font */
|
||||||
free_font();
|
free_font();
|
||||||
|
@ -183,10 +199,6 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
|
||||||
|
|
||||||
bindings = default_mode->bindings;
|
bindings = default_mode->bindings;
|
||||||
|
|
||||||
#define REQUIRED_OPTION(name) \
|
|
||||||
if (config.name == NULL) \
|
|
||||||
die("You did not specify required configuration option " #name "\n");
|
|
||||||
|
|
||||||
/* Clear the old config or initialize the data structure */
|
/* Clear the old config or initialize the data structure */
|
||||||
memset(&config, 0, sizeof(config));
|
memset(&config, 0, sizeof(config));
|
||||||
|
|
||||||
|
|
|
@ -318,31 +318,46 @@ CFGFUN(focus_on_window_activation, const char *mode) {
|
||||||
DLOG("Set new focus_on_window_activation mode = %i.\n", config.focus_on_window_activation);
|
DLOG("Set new focus_on_window_activation mode = %i.\n", config.focus_on_window_activation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFGFUN(title_align, const char *alignment) {
|
||||||
|
if (strcmp(alignment, "left") == 0) {
|
||||||
|
config.title_align = ALIGN_LEFT;
|
||||||
|
} else if (strcmp(alignment, "center") == 0) {
|
||||||
|
config.title_align = ALIGN_CENTER;
|
||||||
|
} else if (strcmp(alignment, "right") == 0) {
|
||||||
|
config.title_align = ALIGN_RIGHT;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CFGFUN(show_marks, const char *value) {
|
CFGFUN(show_marks, const char *value) {
|
||||||
config.show_marks = eval_boolstr(value);
|
config.show_marks = eval_boolstr(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFGFUN(workspace, const char *workspace, const char *output) {
|
CFGFUN(workspace, const char *workspace, const char *outputs) {
|
||||||
DLOG("Assigning workspace \"%s\" to output \"%s\"\n", workspace, output);
|
DLOG("Assigning workspace \"%s\" to outputs \"%s\"\n", workspace, outputs);
|
||||||
/* Check for earlier assignments of the same workspace so that we
|
/* Check for earlier assignments of the same workspace so that we
|
||||||
* don’t have assignments of a single workspace to different
|
* don’t have assignments of a single workspace to different
|
||||||
* outputs */
|
* outputs */
|
||||||
struct Workspace_Assignment *assignment;
|
struct Workspace_Assignment *assignment;
|
||||||
bool duplicate = false;
|
|
||||||
TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
|
TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) {
|
||||||
if (strcasecmp(assignment->name, workspace) == 0) {
|
if (strcasecmp(assignment->name, workspace) == 0) {
|
||||||
ELOG("You have a duplicate workspace assignment for workspace \"%s\"\n",
|
ELOG("You have a duplicate workspace assignment for workspace \"%s\"\n",
|
||||||
workspace);
|
workspace);
|
||||||
assignment->output = sstrdup(output);
|
return;
|
||||||
duplicate = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!duplicate) {
|
|
||||||
|
char *buf = sstrdup(outputs);
|
||||||
|
char *output = strtok(buf, " ");
|
||||||
|
while (output != NULL) {
|
||||||
assignment = scalloc(1, sizeof(struct Workspace_Assignment));
|
assignment = scalloc(1, sizeof(struct Workspace_Assignment));
|
||||||
assignment->name = sstrdup(workspace);
|
assignment->name = sstrdup(workspace);
|
||||||
assignment->output = sstrdup(output);
|
assignment->output = sstrdup(output);
|
||||||
TAILQ_INSERT_TAIL(&ws_assignments, assignment, ws_assignments);
|
TAILQ_INSERT_TAIL(&ws_assignments, assignment, ws_assignments);
|
||||||
|
output = strtok(NULL, " ");
|
||||||
}
|
}
|
||||||
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFGFUN(ipc_socket, const char *path) {
|
CFGFUN(ipc_socket, const char *path) {
|
||||||
|
@ -403,6 +418,11 @@ CFGFUN(assign_output, const char *output) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (current_match->window_mode != WM_ANY) {
|
||||||
|
ELOG("Assignments using window mode (floating/tiling) is not supported\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DLOG("New assignment, using above criteria, to output \"%s\".\n", output);
|
DLOG("New assignment, using above criteria, to output \"%s\".\n", output);
|
||||||
Assignment *assignment = scalloc(1, sizeof(Assignment));
|
Assignment *assignment = scalloc(1, sizeof(Assignment));
|
||||||
match_copy(&(assignment->match), current_match);
|
match_copy(&(assignment->match), current_match);
|
||||||
|
@ -417,6 +437,11 @@ CFGFUN(assign, const char *workspace, bool is_number) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (current_match->window_mode != WM_ANY) {
|
||||||
|
ELOG("Assignments using window mode (floating/tiling) is not supported\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_number && ws_name_to_number(workspace) == -1) {
|
if (is_number && ws_name_to_number(workspace) == -1) {
|
||||||
ELOG("Could not parse initial part of \"%s\" as a number.\n", workspace);
|
ELOG("Could not parse initial part of \"%s\" as a number.\n", workspace);
|
||||||
return;
|
return;
|
||||||
|
@ -443,6 +468,10 @@ CFGFUN(no_focus) {
|
||||||
TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
|
TAILQ_INSERT_TAIL(&assignments, assignment, assignments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFGFUN(ipc_kill_timeout, const long timeout_ms) {
|
||||||
|
ipc_set_kill_timeout(timeout_ms / 1000.0);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Bar configuration (i3bar)
|
* Bar configuration (i3bar)
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -482,25 +511,8 @@ CFGFUN(bar_verbose, const char *verbose) {
|
||||||
current_bar->verbose = eval_boolstr(verbose);
|
current_bar->verbose = eval_boolstr(verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFGFUN(bar_modifier, const char *modifier) {
|
CFGFUN(bar_modifier, const char *modifiers) {
|
||||||
if (strcmp(modifier, "Mod1") == 0)
|
current_bar->modifier = modifiers ? event_state_from_str(modifiers) : XCB_NONE;
|
||||||
current_bar->modifier = M_MOD1;
|
|
||||||
else if (strcmp(modifier, "Mod2") == 0)
|
|
||||||
current_bar->modifier = M_MOD2;
|
|
||||||
else if (strcmp(modifier, "Mod3") == 0)
|
|
||||||
current_bar->modifier = M_MOD3;
|
|
||||||
else if (strcmp(modifier, "Mod4") == 0)
|
|
||||||
current_bar->modifier = M_MOD4;
|
|
||||||
else if (strcmp(modifier, "Mod5") == 0)
|
|
||||||
current_bar->modifier = M_MOD5;
|
|
||||||
else if (strcmp(modifier, "Control") == 0 ||
|
|
||||||
strcmp(modifier, "Ctrl") == 0)
|
|
||||||
current_bar->modifier = M_CONTROL;
|
|
||||||
else if (strcmp(modifier, "Shift") == 0)
|
|
||||||
current_bar->modifier = M_SHIFT;
|
|
||||||
else if (strcmp(modifier, "none") == 0 ||
|
|
||||||
strcmp(modifier, "off") == 0)
|
|
||||||
current_bar->modifier = M_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bar_configure_binding(const char *button, const char *release, const char *command) {
|
static void bar_configure_binding(const char *button, const char *release, const char *command) {
|
||||||
|
@ -627,12 +639,16 @@ CFGFUN(bar_strip_workspace_numbers, const char *value) {
|
||||||
current_bar->strip_workspace_numbers = eval_boolstr(value);
|
current_bar->strip_workspace_numbers = eval_boolstr(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFGFUN(bar_strip_workspace_name, const char *value) {
|
||||||
|
current_bar->strip_workspace_name = eval_boolstr(value);
|
||||||
|
}
|
||||||
|
|
||||||
CFGFUN(bar_start) {
|
CFGFUN(bar_start) {
|
||||||
current_bar = scalloc(1, sizeof(struct Barconfig));
|
current_bar = scalloc(1, sizeof(struct Barconfig));
|
||||||
TAILQ_INIT(&(current_bar->bar_bindings));
|
TAILQ_INIT(&(current_bar->bar_bindings));
|
||||||
TAILQ_INIT(&(current_bar->tray_outputs));
|
TAILQ_INIT(&(current_bar->tray_outputs));
|
||||||
current_bar->tray_padding = 2;
|
current_bar->tray_padding = 2;
|
||||||
current_bar->modifier = M_MOD4;
|
current_bar->modifier = XCB_KEY_BUT_MASK_MOD_4;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFGFUN(bar_finish) {
|
CFGFUN(bar_finish) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue