Merge branch 'next'
This commit is contained in:
commit
34f6f185bf
|
@ -0,0 +1,11 @@
|
|||
BasedOnStyle: google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
IndentWidth: 4
|
||||
PointerBindsToType: false
|
||||
ColumnLimit: 0
|
||||
ForEachMacros: [ TAILQ_FOREACH, TAILQ_FOREACH_REVERSE, SLIST_FOREACH, CIRCLEQ_FOREACH, CIRCLEQ_FOREACH_REVERSE, NODES_FOREACH, NODES_FOREACH_REVERSE ]
|
||||
SpaceBeforeParens: ControlStatements
|
10
DEPENDS
10
DEPENDS
|
@ -12,7 +12,7 @@
|
|||
│ xcb-util │ 0.3.3 │ 0.3.8 │ http://xcb.freedesktop.org/dist/ │
|
||||
│ util-cursor³│ 0.0.99 │ 0.0.99 │ http://xcb.freedesktop.org/dist/ │
|
||||
│ libev │ 4.0 │ 4.11 │ http://libev.schmorp.de/ │
|
||||
│ yajl │ 1.0.8 │ 2.0.1 │ http://lloyd.github.com/yajl/ │
|
||||
│ yajl │ 2.0.1 │ 2.0.4 │ http://lloyd.github.com/yajl/ │
|
||||
│ asciidoc │ 8.3.0 │ 8.6.4 │ 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/
|
||||
|
@ -32,5 +32,9 @@
|
|||
i3bar, i3-msg, i3-input, i3-nagbar and i3-config-wizard do not introduce any
|
||||
new dependencies.
|
||||
|
||||
i3-migrate-config-to-v4 is implemented in Perl, but it has no dependencies
|
||||
besides Perl 5.10.
|
||||
i3-migrate-config-to-v4 and i3-dmenu-desktop are implemented in Perl, but have
|
||||
no dependencies besides Perl 5.10.
|
||||
|
||||
i3-save-tree is also implemented in Perl and needs AnyEvent::I3 and JSON::XS.
|
||||
While i3-save-tree is not required for running i3 itself, it is strongly
|
||||
recommended to provide it in distribution packages.
|
||||
|
|
4
Makefile
4
Makefile
|
@ -30,8 +30,8 @@ dist: distclean
|
|||
[ ! -d i3-${VERSION} ] || rm -rf i3-${VERSION}
|
||||
[ ! -e i3-${VERSION}.tar.bz2 ] || rm i3-${VERSION}.tar.bz2
|
||||
mkdir i3-${VERSION}
|
||||
cp i3-migrate-config-to-v4 generate-command-parser.pl i3-sensible-* i3-dmenu-desktop i3.config.keycodes DEPENDS LICENSE PACKAGE-MAINTAINER RELEASE-NOTES-${VERSION} i3.config i3.xsession.desktop i3-with-shmlog.xsession.desktop i3.applications.desktop pseudo-doc.doxygen common.mk Makefile i3-${VERSION}
|
||||
cp -r src libi3 i3-msg i3-nagbar i3-config-wizard i3bar i3-dump-log yajl-fallback include man parser-specs testcases i3-${VERSION}
|
||||
cp i3-migrate-config-to-v4 i3-save-tree generate-command-parser.pl i3-sensible-* i3-dmenu-desktop i3.config.keycodes DEPENDS LICENSE PACKAGE-MAINTAINER RELEASE-NOTES-${VERSION} i3.config i3.xsession.desktop i3-with-shmlog.xsession.desktop i3.applications.desktop pseudo-doc.doxygen common.mk Makefile i3-${VERSION}
|
||||
cp -r src libi3 i3-msg i3-nagbar i3-config-wizard i3bar i3-dump-log include man parser-specs testcases i3-${VERSION}
|
||||
# Only copy toplevel documentation (important stuff)
|
||||
mkdir i3-${VERSION}/docs
|
||||
# Pre-generate documentation
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.2 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the second release of the new major version of i3, v4.2. It is
|
||||
considered stable. All users of i3 are strongly encouraged to upgrade.
|
||||
|
||||
A big change with this release is (again) a new parser for commands. You might
|
||||
get the impression that we like rewriting parsers, but check the commit message
|
||||
of commit a532f5a for rationale on this decision.
|
||||
|
||||
A more visible change to users is the introduction of a scratchpad command:
|
||||
This is useful to have a permanent editor session ready whenever you need it.
|
||||
Or your music player. Or email client? Or $programming-language REPL? Give it a
|
||||
try!
|
||||
|
||||
Also, you are finally able to move workspaces between the different outputs if
|
||||
you are using multiple monitors. You can rename workspaces on the fly and
|
||||
identify named workspaces by their number. So you can rename "1: www" to "1:
|
||||
code" with one simple rename command and all your keybindings will still work.
|
||||
|
||||
A subtle indicator of the split state of containers has been introduced: In
|
||||
case you are in a split container with precisely one window (a situation which
|
||||
you could not recognize by looking at your screen previously), i3 will
|
||||
highlight the bottom/right border of the split container in a lighter blue.
|
||||
This should reduce confusion about whether you are dealing with a split
|
||||
container or not.
|
||||
|
||||
And finally, i3bar now supports a JSON input protocol, so that with a
|
||||
subsequent release of i3status, you will be able to use colors in your bar!
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.2 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• i3-sensible-*: don’t call which without parameters
|
||||
• i3-config-wizard: Mark the currently selected modifier with an arrow
|
||||
• i3bar: kick tray clients after output configuration changed
|
||||
• i3bar: kill child processes when exit()ing (they might be stopped)
|
||||
• i3bar now supports a JSON input format to provide colors and more (later)
|
||||
• Support different modifier keys for showing i3bar in hide mode
|
||||
• bar config: add i3bar_command for non-standard setups
|
||||
• Implement scratchpad functionality
|
||||
• Implement 'focus output left|right|up|down'
|
||||
• Implement 'workspace next_on_output|prev_on_output'
|
||||
• Implement 'move workspace to output <output>'
|
||||
• Implement a new parser for commands
|
||||
• Implement 'workspace number <number>' to switch to named workspaces
|
||||
• Implement 'move [container|window] to workspace number <number>'
|
||||
• Implement 'rename workspace <old_name> to <new_name>'
|
||||
• Re-implement borders in the workspace bar
|
||||
• Draw a separator line after each tab in tabbed mode
|
||||
• Ignore aspect ratio during fullscreen mode (fixes MPlayer subtitles)
|
||||
• Correctly restore focus after in-place restarts
|
||||
• Highlight the right/bottom border of split windows ("indicator")
|
||||
• Install /usr/share/applications/i3.desktop so that you can select i3 as a
|
||||
window manager in GNOME
|
||||
• Don’t migrate unfocused empty workspaces when disabling an output
|
||||
• randr: Skip workspaces which are assigned to a different output when
|
||||
creating a new workspace
|
||||
• Implement an urgency flag criterion
|
||||
• Render only once for all matching assignments
|
||||
• Implement support for user configuration of constraints on floating window
|
||||
dimensions
|
||||
• Extend move command for floating windows
|
||||
• Added option to select primary display on tray_output
|
||||
• Implement resize <grow|shrink> <width|height>, use it in the default config
|
||||
• Replace the old fullscreen container when requesting fullscreen
|
||||
• Prevent changing focus outside a container when scrolling on the
|
||||
decorations
|
||||
• Only resize when the left/right mouse button is used, not when scrolling
|
||||
• docs: replace the refcard with an HTML version
|
||||
• cfgparse: accept force-xinerama as a synonym of force_xinerama
|
||||
• Implement support for 32 bit visuals (necessary for transparency)
|
||||
• X11: only copy the requested region from buffer pixmaps in ExposeEvents
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• Bugfix: Don’t leak IPC file descriptors
|
||||
• Bugfix: fix empty tray icon areas in i3bar
|
||||
• Bugfix: properly handle workspace names with double quotes
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
Aaron Small, ablepharus, aksr, alexander, badboy, B-con, beauby, ben, biiter,
|
||||
binzter, cg, cradle, darkraven, dbp, dcoppa, Don, dothebart, D Thompson,
|
||||
eeemsi, f8l, Fandekasp, fernandotcl, gamo, garga, gregkh, Han, helgikrs,
|
||||
Jeremy O'Brien, jjfoerch, joepd, Jose Pereira, Jure Ziberna, MasterofJOKers,
|
||||
Merovius, mhcerri, migueldvb, moemoe, mseed, mxf, nh2, noxxun, Paul, Pavel
|
||||
Löbl, Peter Bui, Phlogistique, phnom, piroko, rami, SardemFF7, xeen, xpt,
|
||||
zeus
|
||||
|
||||
-- Michael Stapelberg, 2012-04-25
|
|
@ -1,186 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.3 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the i3 v4.3. This version is considered stable. All users of i3 are
|
||||
strongly encouraged to upgrade.
|
||||
|
||||
One rather visible change is that commands which could not be parsed properly
|
||||
will now spawn i3-nagbar. In case you used "bindsym $mod+x firefox" (and
|
||||
forgot the "exec" keyword) or you made a typo in your config, you will now
|
||||
notice that :).
|
||||
|
||||
|
||||
We also made the orientation (horizontal/vertical) part of the layout
|
||||
mechanism: Before, we got the default layout and you could change
|
||||
orientation. Now, there are two new layouts "splitv" and "splith", which
|
||||
replace the default layout. The "split h" and "split v" commands continue to
|
||||
work as before, they split the current container and you will end up in a
|
||||
split container with layout splith (after "split h") or splitv (after
|
||||
"split v").
|
||||
|
||||
To change a splith container into a splitv container, use either "layout
|
||||
splitv" or "layout toggle split". The latter command is used in the
|
||||
default config as mod+e (formerly "layout default"). In case you have
|
||||
"layout default" in your config file, it is recommended to just replace
|
||||
it by "layout toggle split", which will work as "layout default" did
|
||||
before when pressing it once, but toggle between horizontal/vertical
|
||||
when pressing it repeatedly.
|
||||
|
||||
The rationale behind this change is that it’s cleaner to have all
|
||||
parameters that influence how windows are rendered in the layout itself
|
||||
rather than having one special layout in combination with an additional
|
||||
orientation. This enables us to change existing split containers in all
|
||||
cases without breaking existing features (see ticket #464). Also, users
|
||||
should feel more confident about whether they are actually splitting or
|
||||
just changing an existing split container now.
|
||||
|
||||
As a nice side-effect, this commit brings back the "layout toggle"
|
||||
feature we once had in i3 v3 (see the userguide).
|
||||
|
||||
|
||||
Another very important change is that we now support pango for rendering text.
|
||||
The default is still to use misc-fixed (X core fonts), but you can use a font
|
||||
specification starting with "xft:" now, such as "xft:DejaVu Sans Mono 10" and
|
||||
i3 will use pango. The sole motivation for this is NOT to have fancier window
|
||||
decorations, but to support fonts which have more glyphs (think Japanese for
|
||||
example) and to support right-to-left rendering (open http://www.ftpal.net/
|
||||
for an example). Supporting users from all over the planet is important, and
|
||||
as such I would strongly advise distribution packagers to leave pango support
|
||||
enabled. In case you are working on a very low-spec embedded device, it is
|
||||
easy enough to disable pango support, see common.mk.
|
||||
|
||||
|
||||
Also, the 'layout' command now always works on the parent split container. This
|
||||
allows you to do things like this:
|
||||
|
||||
for_window [class="XTerm"] layout tabbed
|
||||
|
||||
When you now open XTerm on an empty workspace, the whole workspace will be
|
||||
set to tabbed. In case you want to open XTerm in its own tabbed split
|
||||
container, you need to split before:
|
||||
|
||||
for_window [class="XTerm"] split v, layout tabbed
|
||||
|
||||
|
||||
Furthermore, we decided to entirely ignore resize increment size hints for
|
||||
tiling windows. These are set by terminal emulators (such as urxvt,
|
||||
gnome-terminal, …) and specify that the window may only be resized in
|
||||
multiples of the specified size. All terminal emulators cope with the window
|
||||
manager ignoring these hints and by doing so, they can decide what to do with
|
||||
the lost space (that is, pseudo-transparency now works without black bars in
|
||||
urxvt).
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.3 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• docs: there now is documentation about lib::i3test and lib::i3test::Test,
|
||||
the main Perl modules used by our testsuite.
|
||||
• docs/refcard: update for v4
|
||||
• docs/userguide: clarify the default for focus_follows_mouse and new_window
|
||||
• docs/userguide: add section about implicit containers
|
||||
• docs/userguide: give 'move <container|workspace> to output' its own section
|
||||
• docs/ipc: document the 'window' field in the GET_TREE reply
|
||||
• docs/ipc: update links to ipc libraries
|
||||
• docs/ipc: make the reply sections consistent
|
||||
• docs/i3bar-protocol: add example (illustration-only!) shell script
|
||||
• man/i3bar.man: reference i3bar-protocol
|
||||
• IPC: Commands now lead to proper error messages in general. If we forgot
|
||||
about a specific one, please open a ticket.
|
||||
• IPC: implement GET_VERSION to find out the i3 version
|
||||
• i3-dump-log now comes with a massively more helpful error message that
|
||||
should cover all the use cases.
|
||||
• 'workspace number <number>' now opens a new workspace
|
||||
• 'workspace number <number>' now works with the back_and_forth option
|
||||
• Allow focus with target (criteria) when in fullscreen mode in some cases
|
||||
• Allow focus child/parent when in fullscreen mode
|
||||
• Restrict directional focus when in fullscreen mode
|
||||
• Prevent moving out of fullscreen containers
|
||||
• Add 'move to workspace current' (useful when used with criteria)
|
||||
• replace loglevels by a global debug logging
|
||||
• make: new makefile layout
|
||||
• make: canonicalize path when compiling. This leads to sth like
|
||||
../i3-4.2/src/main.c in backtraces, clearly identifying i3 code.
|
||||
• automatically hide i3bar when it’s unneeded (after urgency hints)
|
||||
• i3-config-wizard: use the level 0 keysym whenever it’s unambiguous
|
||||
• i3-nagbar: use custom scripts to work around different terminal emulators
|
||||
using different ways of interpreting the arguments to -e
|
||||
• i3-sensible-terminal: add xfce4-terminal
|
||||
• default config: require confirmation when exiting i3
|
||||
• Display i3-nagbar when a command leads to an error.
|
||||
• testcases: complete-run now supports --xtrace
|
||||
• testcases: handle EAGAIN (fixes hangs)
|
||||
• testcases: handle test bailouts
|
||||
• Introduce splith/splitv layouts, remove orientation
|
||||
• Implement hide_edge_borders option
|
||||
• Support _NET_ACTIVE_WINDOW ClientMessages
|
||||
• Set I3_PID atom on the X11 root window
|
||||
• Implement i3 --moreversion, handy for figuring out whether you run the
|
||||
latest binary which is installed.
|
||||
• i3bar: be less strict about the {"version":1} JSON header
|
||||
• shm-logging: implement i3-dump-log -f (follow)
|
||||
• Implement pango support
|
||||
• 'move workspace number n' will now create the workspace if it doesn’t exist
|
||||
• Accept slashes in RandR output names
|
||||
• Keep startup-notification sequences around for 30s after completion
|
||||
• Introduce bindsym --release, which will trigger the binding not on the
|
||||
KeyPress event, but on the KeyRelease event (useful for import(1) or
|
||||
xdotool(1)).
|
||||
• The signalhandler does not offer you to exit i3 anymore. Instead, there is
|
||||
'b' for writing a backtrace to a file in /tmp (if gdb is installed)
|
||||
• Remove support for resize increment hints for tiling windows
|
||||
• Exit fullscreen mode when 'scratchpad show' is executed while in fullscreen
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• Fix floating precision bug when floating windows are moved between outputs.
|
||||
• i3bar won’t crash when full_text is missing or null in the JSON input
|
||||
• When having "workspace number 1" in your config, there will no longer be a
|
||||
stray workspace "number 1".
|
||||
• i3.config.keycodes used bindsym instead of bindcode for the arrow key
|
||||
resizing bindings by mistake
|
||||
• Fix 'move to workspace' when used with criteria
|
||||
• Handle clicks to the very left edge of i3bar
|
||||
• When using i3 -C, don’t send remaining arguments as an IPC command
|
||||
• Fix reload crashes in rare cases
|
||||
• i3bar: inform all clients of new tray selection owner (fixes tray problems
|
||||
with X-Chat and possibly others)
|
||||
• resizing: traverse containers up properly (fixes non-working resizing when
|
||||
having a h-split within a h-split for example)
|
||||
• Fix floating coordinates when moving assigned workspaces
|
||||
• Properly fix floating coordinates when disabling outputs
|
||||
• floating_fix_coordinates: properly deal with negative positions
|
||||
• floating windows: add deco_height only when in normal border mode (fixes
|
||||
initial floating window position/size when using a different default border
|
||||
setting).
|
||||
• Fix moving scratchpad window
|
||||
• Cleanup zero-byte logfile on immediate exit (they are created by i3
|
||||
--get-socketpath for example).
|
||||
• Fix resizing floating windows by height
|
||||
• Fix back_and_forth in 'workspace number' for named workspaces
|
||||
• Grab server and process pending events before managing existing windows
|
||||
(fixes problems with GIMP windows not being managed after an in-place
|
||||
restart)
|
||||
• Don’t allow ConfigureRequests while in fullscreen (fixes a compatibility
|
||||
issue with gnome-terminal and xfce’s terminal)
|
||||
• Fix flickering with 1pixel border tabbed layouts
|
||||
• Use _exit() instead of exit() when i3 utility programs cannot be executed
|
||||
• Don’t focus the wrong workspace when moving to scratchpad
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
aksr, Axel Wagner, darkraven, David Coppa, eeemsi, Felicitus, Fernando Tarlá
|
||||
Cardoso Lemos, Iakov Davydov, jh, Joel Stemmer, Julius Plenz, loblik, Marcel
|
||||
Hellwig, Marcus, mloskot, Moritz Bandemer, oblique, Ondrej Grover, Pavel
|
||||
Löbl, Philipp Middendorf, prg, Quentin Glidic, Sebastian Ullrich, Simon
|
||||
Elsbrock, somelauw, stfn, tucos, TunnelWicht, Valentin Haenel
|
||||
|
||||
-- Michael Stapelberg, 2012-09-19
|
|
@ -1,107 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.4 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the i3 v4.4. This version is considered stable. All users of i3 are
|
||||
strongly encouraged to upgrade.
|
||||
|
||||
An important under-the-hood change is that we now use the same parser
|
||||
infrastructure for the configuration file as we do for the commands. This
|
||||
makes maintenance and contributions easier and lets us finally escape the
|
||||
insanity that is bison/flex.
|
||||
|
||||
In case there is a bug and your existing config does not work as expected
|
||||
anymore, try using the --force-old-config-parser-v4.4-only flag when starting
|
||||
i3 and please report a bug. This option will only be present in v4.4, so if
|
||||
you don’t report a bug, you are willingly breaking your own config file.
|
||||
|
||||
Apart from that, there have been several little fixes and additions which make
|
||||
i3 pay more attention to detail, particularly in the floating window area of
|
||||
the code. See the changes/bugfixes list for more information.
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.4 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• add i3-dmenu-desktop, a dmenu wrapper which parses application .desktop
|
||||
files and executes them.
|
||||
• also use a custom parser for the config file
|
||||
• i3.xsession.desktop is now standards-compliant
|
||||
• ipc: you can now subscribe to an event called 'mode' (for binding modes)
|
||||
• implement "move container to workspace back_and_forth"
|
||||
• implement delayed urgency hint reset
|
||||
• make "move workspace number" accept a default workspace name after the
|
||||
number
|
||||
• i3bar: allow child to specify start/stop signals to use in hide mode
|
||||
• i3bar: add "urgent" to protocol, it unhides i3bar when in hide mode
|
||||
• make parent of urgent containers also urgent
|
||||
• add descriptive title to split containers (no more "another container")
|
||||
• click to focus: clicking the root window focuses the relevant workspace
|
||||
• display appropriate cursors when resizing or moving floating windows
|
||||
• implement variable border widths for pixel/normal
|
||||
• Implement moving workspaces as if they’re regular containers
|
||||
• Maintain relative positioning when moving floating windows between outputs
|
||||
• Focus the relevant workspace when clicking any container
|
||||
• docs/ipc: remove unnecessary newline
|
||||
• docs/ipc: add a warning to use an existing library
|
||||
• shmlog: remove O_TRUNC flag for shm_open, we truncate on our own
|
||||
• un-fullscreen as needed when moving fullscreen containers
|
||||
• improve startup sequence termination conditions
|
||||
• allow floating cons to be reached using 'focus parent'
|
||||
• grab keys with all permutations of lock and numlock
|
||||
• allow workspace contents to be moved if there are only floating children
|
||||
• allow 'focus <direction>' to move out of non-global fullscreen containers
|
||||
• exit with a proper error message when there are no outputs available
|
||||
• skip floating cons in focus <child|parent> and stop them from being split
|
||||
• focus windows when middle-clicking
|
||||
• skip floating windows in the focus stack when moving through the tree
|
||||
• docs/userguide: use $mod consistently
|
||||
• keycode default config: s/bindcode/bindsym/
|
||||
• implement smart popup_during_fullscreen mode
|
||||
• docs/testsuite: add "installing the dependencies" section
|
||||
• introduce new command to rename focused workspace
|
||||
• libi3: use "pango:" prefix instead of "xft:" to avoid confusion
|
||||
• ipc: add "current" and "old" containers to workspace events
|
||||
• i3bar: add current binding mode indicator
|
||||
• resizing floating windows now obeys the minimum/maximum size
|
||||
• docs/userguide: document new_float option
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• Bugfix: get_output_next() now works with non-aligned RandR setups
|
||||
• Bugfix: close empty workspaces after cross-output move
|
||||
• Bugfix: fix bottom line of tabbed decoration not continuous
|
||||
• Bugfix: use correct coordinates for windows which are opened on a newly
|
||||
created workspace due to assignments
|
||||
• Bugfix: properly react to windows being unmapped before we can reparent
|
||||
• Bugfix: send non-floating window with floating parent to scratchpad
|
||||
• docs/userguide: document how to "un-scratchpad" a window
|
||||
• Bugfix: don’t crash when dragged floating window closes
|
||||
• Bugfix: draw h-split indicator at the correct position
|
||||
• make the resize command honor criteria
|
||||
• Bugfix: with one ws per output, don’t crash on cross-output moves
|
||||
• Bugfix: correctly move floating windows to invisible workspaces
|
||||
cross-output
|
||||
• Bugfix: set workspace_layout in create_workspace_on_output
|
||||
• fix fullscreen focus bug and corresponding test flaw
|
||||
• i3bar: bugfix: don’t send workspace command when at beginning/end of workspace
|
||||
• Bugfix: force rendering when the parent’s orientation changed
|
||||
• Bugfix: fix workspace back_and_forth after displaying a scratchpad window
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
Adrien Schildknecht, aksr, bitonic, chrysn, Conley Moorhous, darkraven, Deiz,
|
||||
Emil Mikulic, Feh, flo, Francesco Mazzoli, hax404, joepd, Kacper Kowalik,
|
||||
Markus, meaneye, Merovius, Michael Walle, moju, Moritz, noxxun, Oliver
|
||||
Kiddle, Pauli Ervi, Pavel Löbl, Piotr, pkordy, Quentin Glidic, Sascha Kruse,
|
||||
Sebastian Ullrich, Simon Elsbrock, slowpoke, strcat, Tblue, Tim, whitequark,
|
||||
xeen, Yaroslav Molochko
|
||||
|
||||
-- Michael Stapelberg, 2012-12-12
|
|
@ -1,103 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.5 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the i3 v4.5. This version is considered stable. All users of i3 are
|
||||
strongly encouraged to upgrade.
|
||||
|
||||
Most of the changes are cleanups and bugfixes. Due to cleanups, i3 no longer
|
||||
depends on flex/bison at all. Furthermore, libev ≥ 4 is now a hard dependency
|
||||
(libev < 4 is not supported anymore).
|
||||
|
||||
One important change to note is that moving windows to a different output will
|
||||
no longer move focus to that output. If you want to have the old behavior,
|
||||
modify the keybindings for moving in your configfile like this:
|
||||
|
||||
bindsym $mod+Shift+1 move workspace 1; workspace 1
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.5 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• docs/hacking-howto: refer people to cr.i3wm.org
|
||||
• docs/ipc: Adds Go IPC lib to the docs.
|
||||
• docs/userguide: remove obsolete sentence about client.background
|
||||
• docs/userguide: be explicit about assignment processing order
|
||||
• docs/userguide: be more clear about the resize command arguments
|
||||
• docs/userguide: fix typo: s/11x/11px/
|
||||
• i3-dmenu-desktop: don’t add “geany” if “Geany” is already present
|
||||
• i3-dmenu-desktop: strip newlines from dmenu ≥ 4.4
|
||||
• i3-dmenu-desktop: skip files with broken utf8 but warn about it
|
||||
• i3-dmenu-desktop: skip broken files (no/empty Exec=) but warn about them
|
||||
• i3-dmenu-desktop: List filenames of .desktop files
|
||||
• i3-dmenu-desktop: remove %i from commandline
|
||||
• i3-nagbar: Work around terminals not supporting -e with quoted arguments
|
||||
• i3-nagbar: use the same font as configured for i3
|
||||
• i3bar: set _NET_SYSTEM_TRAY_COLORS for symbolic icons (gtk3+)
|
||||
• i3bar: don’t use X11 borders to avoid overlapping in hide mode
|
||||
• i3bar: separator color via config; separator width and on/off via ipc
|
||||
• i3bar: Allow min_width of a block in i3bar to be a string
|
||||
• i3-msg: parse command replies and display errors nicely if there were
|
||||
errors
|
||||
• Draw 1px tab separators left/right instead of 2px on the right only
|
||||
• Render tree before destroying X11 containers upon unmap
|
||||
• scratchpad show: move visible scratchpad window from another workspace to
|
||||
focused workspace instead of doing nothing
|
||||
• ignore MotionNotify events generated while warping the pointer
|
||||
• Allow X11 servers which do not support the XKB extension.
|
||||
• remove the urgency indicator when a window is closed
|
||||
• wrap when moving containers to outputs with direction
|
||||
• scratchpad_show: focus unfocused scratchpad window
|
||||
• Split workspace instead of changing orientation
|
||||
• scratchpad: always auto center on 'scratchpad show' if window hasn't been
|
||||
repositioned by the user
|
||||
• Add a new IPC event for changes on windows.
|
||||
• config: accept “smart” as popup_during_fullscreen parameter
|
||||
• Add support for _NET_WM_STATE_DEMANDS_ATTENTION.
|
||||
• Obey WM_SIZE_HINTS's resize increments in floating mode
|
||||
• Do not move focus if a container is moved across outputs
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• Ignore ConfigureRequests for scratchpad windows
|
||||
• Correctly parse `move ... workspace *_on_output`
|
||||
• i3bar: Set separator color properly when drawing
|
||||
• Properly parse commands like “move workspace torrent”
|
||||
• Handle nested transient popups properly
|
||||
• Fix decoration rect size for windows without border
|
||||
• parse outputs as "word", not "string", to ignore trailing whitespace
|
||||
• fix crash when disabling output without any windows
|
||||
• scratchpad: fix crash when moving last window of an invisible workspace
|
||||
• fix coordinates of scratchpad windows on output changes
|
||||
• call scratchpad_show() when focusing scratchpad windows via criteria
|
||||
• fix continuous resize bug in floating mode, e.g. with xbmc
|
||||
• fix “overlapping” --release key bindings
|
||||
• fix IPC messages writes with low buffer sizes
|
||||
• unregister as window manager before restarting (fixes a race condition)
|
||||
• Fix bind[code|sym] --release
|
||||
• remove superfluous #include <xcb/xcb_atom.h>
|
||||
• Makefile: Repect AR environment variable
|
||||
• i3-input: restore input focus on exit()
|
||||
• Also draw right tab border for split containers
|
||||
• Fix scrolling on a tabbed titlebar which contains split cons
|
||||
• Correctly close floating windows
|
||||
• handle MapRequests sent between i3 registering as a wm and handling events
|
||||
• i3bar: fake DestroyNotify and send MANAGER ClientMessages to fix tray restarts
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
Adrien Schildknecht, alex, András Mohari, Artem Shinkarov, badboy, bafain,
|
||||
cradle, dcoppa, Donald, dRbiG, eeemsi, else, emias, f8l, Francesco Mazzoli,
|
||||
jasper, joepd, Kacper Kowalik, Kai, knopwob, Marcos, Marius Muja, Mats,
|
||||
MeanEYE, Merovius, oblique, paolo, phlux, Piotr S. Staszewski, pnutzh4x0r,
|
||||
rasi, saurabhgeek92, Sebastian Rachuj, Sebastian Ullrich, slowpoke, Steven
|
||||
Allen, supplantr, Tai-Lin Chu, Tucos, Vivien Didelot, xeen
|
||||
|
||||
-- Michael Stapelberg, 2013-03-12
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.5.1 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the i3 v4.5.1, a bugfix release. This version is considered stable. All
|
||||
users of i3 are strongly encouraged to upgrade.
|
||||
|
||||
This release fixes an i3 lockup when dragging floating windows from one monitor
|
||||
to another.
|
||||
|
||||
Furthermore, in the release process for v4.5, there was a human error leading
|
||||
to i3 thinking that v4.5 is a debug version, therefore allocating 25 MB of
|
||||
shared memory logging ringbuffer by default.
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.5.1 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• Bugfix: Don’t warp the pointer when dragging floating windows
|
||||
• i3-dmenu-desktop: improve error message when dmenu cannot be found
|
||||
• Add YAJL_CFLAGS to i3-msg.mk
|
||||
|
||||
-- Michael Stapelberg, 2013-03-18
|
|
@ -1,99 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.6 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the i3 v4.6. This version is considered stable. All users of i3 are
|
||||
strongly encouraged to upgrade.
|
||||
|
||||
The main improvement of this release is increased compatibility. We made a few
|
||||
tiny code changes and hope that Mathematica and Java applications will work
|
||||
better with i3 now. i3-nagbar should work with more terminal emulators than
|
||||
before.
|
||||
|
||||
For debugging, the shmlog and debuglog commands can be sent via IPC to enable
|
||||
shared memory logging while i3 is running. For the large number of users using
|
||||
a release version (i.e. a version without shared memory logging by default),
|
||||
this will make debugging their issues much simpler.
|
||||
|
||||
i3bar now supports click events and can be hidden/shown via an i3 IPC command.
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.6 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• docs/userguide: mention forgotten layout splitv/splith
|
||||
• docs/multi-monitor: nVidia ≥ 302.17 works just fine
|
||||
• docs/wsbar: update (we have i3bar now, i3-wsbar is just an example)
|
||||
• docs/testsuite: Document fixes and workarounds for test failures
|
||||
• man/i3-msg.man: updated man page to include all options
|
||||
• lib/i3test: clarify how to identify open_window() windows in i3 commands
|
||||
• Use a saner sanity check for floating_reposition
|
||||
• tabbed: floor(), put extra pixels into the last tab
|
||||
• raise fullscreen windows on top of all other X11 windows
|
||||
• Draw indicator border only for split layouts
|
||||
• re-shuffle struct members to save a bit of memory
|
||||
• Add 'NoDisplay=true' to i3.application.desktop
|
||||
• Store aspect_ratio instead of weird proportional_{width,height}
|
||||
• Implement shmlog command
|
||||
• Implement debuglog command
|
||||
• Implement unmark command
|
||||
• actively delete _NET_WORKAREA on startup
|
||||
• Handle the _NET_REQUEST_FRAME_EXTENTS ClientMessage (java compat)
|
||||
• i3bar: add click events
|
||||
• i3bar: fix -b parameter, fix usage description
|
||||
• i3bar: restore compatibility with libyajl version 1
|
||||
• i3bar: unhide hidden i3bar when mode is active
|
||||
• i3bar: fix font display height in i3bar
|
||||
• i3bar: introduced i3 command for changing the hidden state and mode
|
||||
• i3bar: fix wrong placement of i3bar when connecting/disconnecting outputs
|
||||
• i3bar: draw workspace buttons at x=0 instead of x=1
|
||||
• i3-nagbar: take our terminal execution kludge to the next level
|
||||
• i3-nagbar: Bugfix: -m requires an argument (crashes if none specified)
|
||||
• i3-dmenu-desktop: run commands when they don’t match a .desktop file
|
||||
(e.g. enter “i3 layout stacking”)
|
||||
• i3-dmenu-desktop: honor Path= key
|
||||
• contrib/dump-asy.pl: Fix $ and & in window titles
|
||||
• contrib/dump-asy.pl: Display nicer double-quotes
|
||||
• contrib/gtk-tree-watch.pl: Remove bogus default socket path
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• Bugfix: ipc: use correct workspace in workspace change event
|
||||
• Bugfix: fix floating window size with hide_edge_borders
|
||||
• Bugfix: Fix parsing of comments in the config file
|
||||
• Bugfix: Fix error messages for the debug log
|
||||
• Bugfix: shm_unlink the correct file when handling errors
|
||||
• Bugfix: Fix shm logging on FreeBSD
|
||||
• Bugfix: Fix restarting with 32 bit depth windows
|
||||
• Bugfix: Fix scratchpad_show on non-scratchpad windows
|
||||
• Bugfix: i3bar: mark IPC fd CLOEXEC
|
||||
• Bugfix: fix crash when not having tray_output configured
|
||||
• Bugfix: make sure that resize will take place even if pixel is smaller
|
||||
than size increments.
|
||||
• Bugfix: render_con: fix height rounding in aspect ratio computation
|
||||
• Bugfix: fix problem when moving fullscreen window to scratchpad
|
||||
• Bugfix: Unmap windows before reparenting them to the root window
|
||||
(fixes Mathematica)
|
||||
• Bugfix: update parent urgency hint if a child is removed.
|
||||
• Bugfix: fix bus error on OpenBSD/sparc64
|
||||
• Bugfix: fix focus handling in 'floating disable' on non-visible windows
|
||||
• Bugfix: ignore spaces in front of default workspace name
|
||||
• Bugfix: call i3-nagbar correctly for configfiles without the font directive
|
||||
• Bugfix: resize and center a scratchpad even when a criteria is used.
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
Alexander, Alexander Berntsen, Arun Persaud, badboy, Baptiste Daroussin,
|
||||
Clément Bœsch, Diego Ongaro, Eelis van der Weegen, Eika Enge, enkore, Eric S.
|
||||
Raymond, Franck Michea, haptix, HedgeMage, koebi, Layus, Mayhem, Merovius,
|
||||
necoro, oblique, Philippe Virouleau, phillip, psychon, Simon Elsbrock, Simon
|
||||
Wesp, Thomas Adam, tobiasu, vandannen, xeen, Yuxuan Shui
|
||||
|
||||
-- Michael Stapelberg, 2013-08-07
|
|
@ -1,82 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.7 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the i3 v4.7. This version is considered stable. All users of i3 are
|
||||
strongly encouraged to upgrade.
|
||||
|
||||
This release features a number of documentation improvements, better error
|
||||
messages in various places, better tray compatibility in i3bar, and a number of
|
||||
bugfixes.
|
||||
|
||||
Relevant from a packaging point of view is that we have switched to the new
|
||||
xcb-util-cursor library to get rid of libXcursor. The last remaining big piece
|
||||
of Xlib code now is XKB, which we may be able to tackle in upcoming releases
|
||||
thanks to the just released libxcb 1.10.
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.7 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• docs/userguide: clarify variable parsing
|
||||
• docs/userguide: clarify urgent_workspace
|
||||
• docs/userguide: add proper quoting for rename sample command
|
||||
• docs/userguide: clarify multiple criteria
|
||||
• docs/userguide: userguide: explain the difference between comma and semicolon for command chaining
|
||||
• docs/hacking-howto: update to reflect parser changes
|
||||
• man/i3-dump-log: document -f
|
||||
• switch from libXcursor to xcb-util-cursor
|
||||
• Respect workspace numbers when looking for a free workspace name
|
||||
• Revert "raise fullscreen windows on top of all other X11 windows"
|
||||
• i3bar: Create pixmaps using the real bar height, rather than screen height
|
||||
• Add scratchpad bindings to the default config
|
||||
• Close all children when closing a workspace
|
||||
• i3bar: Add new bar.binding_mode_indicator configuration
|
||||
• Improve error message when $XDG_RUNTIME_DIR is not writable
|
||||
• libi3/font: Draw the text at the expected place
|
||||
• libi3/font: Set DPI for the pango context
|
||||
• Add ability to escape out of a mouse-resize operation
|
||||
• Do not resize/reposition floating containers when moving them to scratchpad
|
||||
• i3-nagbar: Set button inner-width to the width of the label
|
||||
• Assigned windows open urgent when not visible
|
||||
• i3bar: Only configure tray on own outputs
|
||||
• Command 'move <direction>' moves across outputs
|
||||
• i3bar: Handle DestroyNotify events
|
||||
• i3bar: Realign tray clients on map/unmap notify
|
||||
• i3bar: Group child processes for signalling
|
||||
• i3bar: Print error message when status_command fails
|
||||
• Remove references to PATH_MAX macro for GNU/Hurd
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• update root geometry on output changes for “fullscreen global”
|
||||
• don’t flatten tabbed/stacked containers
|
||||
• Fix handling of new windows with WM_STATE_FULLSCREEN
|
||||
• correctly recognize assigned windows as urgent
|
||||
• Fix keyboard and mouse resize in nested containers
|
||||
• Reply to _NET_REQUEST_FRAME_EXTENTS correctly
|
||||
• Fix command parser: resizing tiling windows
|
||||
• Fix output retrieval for floating cons
|
||||
• Use _PATH_BSHELL to ensure using a bourne shell
|
||||
• Instead of crashing, return DRAG_ABORT on UnmapNotify from drag_pointer
|
||||
• Remove-child callback skips output content cons
|
||||
• ignore _NET_ACTIVE_WINDOW for scratchpad windows
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
Alexander Neumann, badboy, Baptiste Daroussin, Bas Pape, Deiz, Franck Michea,
|
||||
Jean-Philippe Ouellet, jj, jookia, kaersten, Lancelot SIX, Leo Gaspard,
|
||||
mistnim, Peter Maatman, Quentin Glidic, Sebastian Ullrich, Slava, syl20bnr,
|
||||
Tony Crisci, Trung Ngo, Vivien Didelot, Xarthisius
|
||||
|
||||
I want to specifically thank Tony Crisci for the very valuable help with
|
||||
responding to bugreports in our bugtracker. Thank you!
|
||||
|
||||
-- Michael Stapelberg, 2013-12-22
|
|
@ -1,36 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.7.1 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the i3 v4.7.1. This version is considered stable. All users of i3 are
|
||||
strongly encouraged to upgrade.
|
||||
|
||||
This is a bugfix release for v4.7.
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.7.1 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• docs/debugging: explain how to enable logging on the fly
|
||||
• docs/debugging: small cleanups (versions, bzip2)
|
||||
• add i3-with-shmlog.xsession.desktop
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• only LOG() the DPI when it changes, DLOG() it otherwise
|
||||
• make “move <direction>” properly send workspace focus event
|
||||
• i3bar: set mapped flag on trayclient creation
|
||||
• i3bar: don’t show EOF status line error in favor of exit code
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
lkraav, TonyC
|
||||
|
||||
-- Michael Stapelberg, 2014-01-21
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.7.2 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is the i3 v4.7.2. This version is considered stable. All users of i3 are
|
||||
strongly encouraged to upgrade.
|
||||
|
||||
This is a bugfix release for v4.7.
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• install i3-with-shmlog.xsession.desktop to the correct location
|
||||
• OpenBSD currently lacks posix_fallocate()
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
David Coppa
|
||||
|
||||
-- Michael Stapelberg, 2014-01-23
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
┌──────────────────────────────┐
|
||||
│ Release notes for i3 v4.8 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
This is i3 v4.8. This version is considered stable. All users of i3 are
|
||||
strongly encouraged to upgrade.
|
||||
|
||||
The biggest new feature certainly is layout saving/restoring. See
|
||||
http://i3wm.org/docs/layout-saving.html for more details. tl;dr: export your
|
||||
current layout as JSON file, load it into new i3 sessions, get placeholder
|
||||
windows that will be replaced by the actual apps once you start them.
|
||||
|
||||
Also very important for owners of HiDPI/“retina” displays is that i3 will now
|
||||
respect your configured DPI and scale up its UI elements accordingly. Use
|
||||
“xrandr --dpi 184” to set your dpi to 184, in case your setup does not figure
|
||||
it out automatically. To get properly scaling fonts, we also changed the
|
||||
default font from a bitmap font to a pango font (“DejaVu Sans Mono 8”).
|
||||
|
||||
Multiple changes improve the compatibility of i3 with other software, e.g.
|
||||
java-based software (focus handling, once again) or external pagers (we now
|
||||
provide _NET_CLIENT_LIST and let pager applications change workspaces).
|
||||
|
||||
For packagers, another change is that yajl ≥ 2.0 is now required for compiling
|
||||
i3. This should not be a problem for anyone, as that version is pretty old by
|
||||
now.
|
||||
|
||||
For contributors, note that we have starting formatting the source code with
|
||||
clang-format-3.5. This means that there will no longer be a need to argue about
|
||||
coding style when discussing patches :).
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Changes in v4.8 │
|
||||
└────────────────────────────┘
|
||||
|
||||
• docs/ipc: reformat/update list of ipc libraries
|
||||
• docs/ipc: fix current_workspace outputs reply member
|
||||
• docs/ipc: update ipc COMMAND reply docs
|
||||
• docs/userguide: fix multiple typos
|
||||
• docs/debugging: use bzip2
|
||||
• docs/debugging: explain how to enable logging on the fly
|
||||
• docs/debugging: merge the debug symbols/backtrace section
|
||||
• docs/debugging: recommend i3 --moreversion
|
||||
• man/i3-nagbar.man: update manpage to document all options
|
||||
• i3bar: Amend status line error 127 message
|
||||
• i3bar: don’t kill watcher on EOF, leads to better error messages
|
||||
• i3bar: send mouse wheel events to child too
|
||||
• i3bar: do click handling and tray padding retina-correctly
|
||||
• i3bar: render separators render-correctly
|
||||
• i3bar: reinit colors on barconfig update
|
||||
• i3bar: Don't start child unless status_command
|
||||
• i3bar: implement custom workspace numbers config
|
||||
• resize floating windows when right-clicking the decoration
|
||||
• enable shmlog when invoked as i3-with-shmlog
|
||||
• Disable pointer warps when focus_follows_mouse is disabled
|
||||
• Movement into a branch considers movement direction
|
||||
• set ewmh desktop properties on startup
|
||||
• handle ButtonPress events with child != XCB_NONE
|
||||
• implement layout restoring
|
||||
• only LOG() the DPI when it changes, DLOG() it otherwise
|
||||
• send IPC window events for focus and title changes
|
||||
• these types of windows are now floating by default:
|
||||
dialog, utility, toolbar and splash windows, modal windows, windows with an
|
||||
equal minimum and maximum size
|
||||
• send last event timestamp with WM_TAKE_FOCUS message
|
||||
• maintain the _NET_CLIENT_LIST property
|
||||
• don’t set input focus _and_ send WM_TAKE_FOCUS
|
||||
• respect CFLAGS in linking command
|
||||
• fix parallel make
|
||||
• reset SIGPIPE handler before executing a command
|
||||
• render default window border width retina-correctly
|
||||
• draw workspace buttons and padded text blocks retina-correctly
|
||||
• render resize windows retina-correctly
|
||||
• delegate click handling to dock clients
|
||||
• send complete config on barconfig_update
|
||||
• implement the window::fullscreen_mode ipc event
|
||||
• make all workspaces starting with "__" internal
|
||||
• improve error messages for i3-internal workspace names
|
||||
• allow _NET_ACTIVE_WINDOW requests to switch workspaces if they indicate
|
||||
that they are a pager (following the spec)
|
||||
• workspace assignments by number
|
||||
• add configuration option for disabling mouse warping
|
||||
• set _NET_ACTIVE_WINDOW to None when none has focus
|
||||
• set X-LightDM-DesktopName in i3.xsession.desktop to fix autostart on Ubuntu
|
||||
• don’t ELOG ipc EOF
|
||||
• replace all printf()s with D?LOG
|
||||
• delete ipc socket when exiting, cleanup tmpdir
|
||||
• default config: switch to DejaVu Sans Mono 8 as default font
|
||||
• cleanup tmpdir when restarting and not using XDG_RUNTIME_DIR
|
||||
• Snap pointer to resize bar on drag resize
|
||||
• Size resizebar according to container size
|
||||
• Fix clang -Wextra except -Wunused-parameter
|
||||
• Respect Motif hint for window decorations
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Bugfixes │
|
||||
└────────────────────────────┘
|
||||
|
||||
• create con pixmaps when not needed
|
||||
• i3bar: fix resource leak: statusline_ctx needs to be freed first
|
||||
• tree_split should not split floating cons
|
||||
• fix memory leak with ipc_receive_message
|
||||
• fix invalid reads by setting con->window to NULL in tree_close
|
||||
• fix memory leak when closing windows
|
||||
• fix memory leak when matching window by criteria
|
||||
• fix memory leak when matching window by con_id
|
||||
• ignore dock clients in the resize command
|
||||
• clear wm_size_hints if they are not set
|
||||
• resize window check should check for NULL
|
||||
• fix window event crash with no window
|
||||
• i3-dmenu-desktop: also quote the %c field code
|
||||
• new_window and new_float can now be used simultaneously with different
|
||||
border widths
|
||||
• fix crash when using multiple for_window statements that move windows
|
||||
• Set input focus with last timestamp
|
||||
• handle windows whose WM_TRANSIENT_FOR points to themselve
|
||||
• don’t overwrite the original size of floating windows when changing border
|
||||
• don’t errnously render floating fullscreen windows during restart
|
||||
• ensure floating windows don’t drop out of fullscreen when restarting
|
||||
• don’t overwrite the window’s geometry after restartingnext
|
||||
• i3bar: Set `mapped` flag on trayclient creation
|
||||
• i3bar: don't show "EOF" status line error
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ Thanks! │
|
||||
└────────────────────────────┘
|
||||
|
||||
Thanks for testing, bugfixes, discussions and everything I forgot go out to:
|
||||
|
||||
Aleksi Blinnikka, Alexander Berntsen, Alexander Kedrik, Antonio, Arun
|
||||
Persaud, Atte Peltomaki, bo, Campbell Barton, chris, David Coppa, eeemsi,
|
||||
Holger Langenau, Jean-Philippe Ouellet, Jens, jeroentbt, Jonas Maaskola,
|
||||
Julian Ospald, Kernc, Koston, lasers, lkraav, Marcin, Marco Hunsicker,
|
||||
Marcus Crestani, Matthias Thubauville, Maxime, Michael Stapelberg, Peter
|
||||
Boström, Petr Písař, Quentin Glidic, Steve Jones, TonyC, Tony Crisci,
|
||||
Vivien Didelot, Wieland Hoffmann, x33a, xeen
|
||||
|
||||
-- Michael Stapelberg, 2014-06-15
|
|
@ -115,9 +115,6 @@ XCURSOR_LIBS := $(call ldflags_for_lib, xcb-cursor,xcb-cursor)
|
|||
|
||||
# yajl
|
||||
YAJL_CFLAGS := $(call cflags_for_lib, yajl)
|
||||
# Fallback for libyajl 1 which did not include yajl_version.h. We need
|
||||
# YAJL_MAJOR from that file to decide which code path should be used.
|
||||
YAJL_CFLAGS += -idirafter $(TOPDIR)/yajl-fallback
|
||||
YAJL_LIBS := $(call ldflags_for_lib, yajl,yajl)
|
||||
|
||||
#libev
|
||||
|
@ -171,8 +168,8 @@ endif
|
|||
|
||||
ifeq ($(UNAME),Darwin)
|
||||
LIBS += -liconv
|
||||
else
|
||||
# Darwin (Mac OS X) doesn’t have librt
|
||||
else ifneq ($(UNAME),OpenBSD)
|
||||
# Darwin (Mac OS X) and OpenBSD do not have librt
|
||||
LIBS += -lrt
|
||||
endif
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env perl
|
||||
# vim:ts=4:sw=4:expandtab
|
||||
# © 2012 Michael Stapelberg
|
||||
# Licensed under BSD license, see http://code.i3wm.org/i3/tree/LICENSE
|
||||
#
|
||||
# Append this line to your i3 config file:
|
||||
# exec_always ~/per-workspace-layout.pl
|
||||
#
|
||||
# Then, change the %layouts hash like you want your workspaces to be set up.
|
||||
# This script requires i3 >= v4.4 for the extended workspace event.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use AnyEvent;
|
||||
use AnyEvent::I3;
|
||||
use v5.10;
|
||||
|
||||
my %layouts = (
|
||||
'4' => 'tabbed',
|
||||
'5' => 'stacked',
|
||||
);
|
||||
|
||||
my $i3 = i3();
|
||||
|
||||
die "Could not connect to i3: $!" unless $i3->connect->recv();
|
||||
|
||||
die "Could not subscribe to the workspace event: $!" unless
|
||||
$i3->subscribe({
|
||||
workspace => sub {
|
||||
my ($msg) = @_;
|
||||
return unless $msg->{change} eq 'focus';
|
||||
die "Your version of i3 is too old. You need >= v4.4"
|
||||
unless exists($msg->{current});
|
||||
my $ws = $msg->{current};
|
||||
|
||||
# If the workspace already has children, don’t change the layout.
|
||||
return unless scalar @{$ws->{nodes}} == 0;
|
||||
|
||||
my $name = $ws->{name};
|
||||
my $con_id = $ws->{id};
|
||||
|
||||
return unless exists $layouts{$name};
|
||||
|
||||
$i3->command(qq|[con_id="$con_id"] layout | . $layouts{$name});
|
||||
},
|
||||
_error => sub {
|
||||
my ($msg) = @_;
|
||||
say "AnyEvent::I3 error: $msg";
|
||||
say "Exiting.";
|
||||
exit 1;
|
||||
},
|
||||
})->recv->{success};
|
||||
|
||||
# Run forever.
|
||||
AnyEvent->condvar->recv
|
Binary file not shown.
|
@ -1,8 +1,26 @@
|
|||
i3-wm (4.6.1-1) unstable; urgency=low
|
||||
i3-wm (4.7.3-1) unstable; urgency=low
|
||||
|
||||
* NOT YET RELEASED.
|
||||
* NOT YET RELEASED
|
||||
|
||||
-- Michael Stapelberg <stapelberg@debian.org> Wed, 07 Aug 2013 20:53:26 +0200
|
||||
-- Michael Stapelberg <stapelberg@debian.org> Thu, 23 Jan 2014 23:11:48 +0100
|
||||
|
||||
i3-wm (4.7.2-1) unstable; urgency=low
|
||||
|
||||
* New upstream release. (Closes: #736396)
|
||||
|
||||
-- Michael Stapelberg <stapelberg@debian.org> Thu, 23 Jan 2014 23:03:03 +0100
|
||||
|
||||
i3-wm (4.7.1-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Michael Stapelberg <stapelberg@debian.org> Tue, 21 Jan 2014 19:29:34 +0100
|
||||
|
||||
i3-wm (4.7-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Michael Stapelberg <stapelberg@debian.org> Sun, 22 Dec 2013 21:19:02 +0100
|
||||
|
||||
i3-wm (4.6-1) unstable; urgency=low
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ Build-Depends: debhelper (>= 7.0.50~),
|
|||
docbook-xml,
|
||||
pkg-config,
|
||||
libev-dev (>= 1:4.04),
|
||||
libyajl-dev,
|
||||
libyajl-dev (>= 2.0.4),
|
||||
libpcre3-dev,
|
||||
libstartup-notification0-dev (>= 0.10),
|
||||
libcairo2-dev,
|
||||
|
@ -38,7 +38,7 @@ Architecture: any
|
|||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, x11-utils
|
||||
Provides: x-window-manager
|
||||
Suggests: rxvt-unicode | x-terminal-emulator
|
||||
Recommends: xfonts-base
|
||||
Recommends: xfonts-base, fonts-dejavu-core, libanyevent-i3-perl, libjson-xs-perl
|
||||
Description: improved dynamic tiling window manager
|
||||
Key features of i3 are good documentation, reasonable defaults (changeable in
|
||||
a simple configuration file) and good multi-monitor support. The user
|
||||
|
|
|
@ -29,3 +29,5 @@ docs/refcard_style.css
|
|||
docs/logo-30.png
|
||||
docs/lib-i3test.html
|
||||
docs/lib-i3test-test.html
|
||||
docs/layout-saving.html
|
||||
docs/layout-saving-1.png
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
usr/share/man/man1/i3.1.gz usr/share/man/man1/i3-with-shmlog.1.gz
|
|
@ -38,7 +38,7 @@ override_dh_auto_build:
|
|||
$(MAKE) -C docs
|
||||
|
||||
override_dh_installchangelogs:
|
||||
dh_installchangelogs RELEASE-NOTES-4.6
|
||||
dh_installchangelogs RELEASE-NOTES-*
|
||||
|
||||
override_dh_install:
|
||||
$(MAKE) DESTDIR=$(CURDIR)/debian/i3-wm/ install
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
|
@ -560,7 +560,7 @@ ifdef::linkcss[]
|
|||
<script type="text/javascript">
|
||||
# Escape as CDATA to pass validators.
|
||||
/*<![CDATA[*/
|
||||
window.onload = function()\{asciidoc.footnotes();{toc? asciidoc.toc({toclevels});}\}
|
||||
document.addEventListener("DOMContentLoaded", function()\{asciidoc.footnotes();{toc? asciidoc.toc({toclevels});}\}, false);
|
||||
/*]]>*/
|
||||
</script>
|
||||
<script type="text/javascript" src="{scriptsdir=.}/asciidoc-xhtml11.js"></script>
|
||||
|
@ -569,7 +569,7 @@ ifndef::linkcss[]
|
|||
<script type="text/javascript">
|
||||
# Escape as CDATA to pass validators.
|
||||
/*<![CDATA[*/
|
||||
window.onload = function()\{asciidoc.footnotes();{toc? asciidoc.toc({toclevels});}\}
|
||||
document.addEventListener("DOMContentLoaded", function()\{asciidoc.footnotes();{toc? asciidoc.toc({toclevels});}\}, false);
|
||||
include1::{scriptsdir=./javascripts}/asciidoc-xhtml11.js[]
|
||||
/*]]>*/
|
||||
</script>
|
||||
|
@ -647,7 +647,7 @@ endif::doctype-manpage[]
|
|||
</div>
|
||||
{disable-javascript%<div id="footnotes"><hr /></div>}
|
||||
<div id="footer" lang="de">
|
||||
© 2009-2012 Michael Stapelberg, <a href="/impress.html">Impressum</a>
|
||||
© 2009-2014 Michael Stapelberg, <a href="http://i3wm.org/impress.html">Impressum</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -14,7 +14,8 @@ ASCIIDOC_TOC_TARGETS = \
|
|||
docs/multi-monitor.html \
|
||||
docs/wsbar.html \
|
||||
docs/testsuite.html \
|
||||
docs/i3bar-protocol.html
|
||||
docs/i3bar-protocol.html \
|
||||
docs/layout-saving.html
|
||||
|
||||
ASCIIDOC_TARGETS = \
|
||||
$(ASCIIDOC_TOC_TARGETS) \
|
||||
|
|
|
@ -172,6 +172,10 @@ values will later be pushed to X11 in +src/x.c+.
|
|||
src/resize.c::
|
||||
Contains the functions to resize containers.
|
||||
|
||||
src/restore_layout.c::
|
||||
Everything for restored containers that is not pure state parsing (which can be
|
||||
found in load_layout.c).
|
||||
|
||||
src/sighandler.c::
|
||||
Handles +SIGSEGV+, +SIGABRT+ and +SIGFPE+ by showing a dialog that i3 crashed.
|
||||
You can chose to let it dump core, to restart it in-place or to restart it
|
||||
|
|
|
@ -225,7 +225,7 @@ instance::
|
|||
Instance of the block, if set
|
||||
x, y::
|
||||
X11 root window coordinates where the click occured
|
||||
button:
|
||||
button::
|
||||
X11 button ID (for example 1 to 3 for left/middle/right mouse button)
|
||||
|
||||
*Example*:
|
||||
|
|
89
docs/ipc
89
docs/ipc
|
@ -1,7 +1,7 @@
|
|||
IPC interface (interprocess communication)
|
||||
==========================================
|
||||
Michael Stapelberg <michael@i3wm.org>
|
||||
October 2012
|
||||
February 2014
|
||||
|
||||
This document describes how to interface with i3 from a separate process. This
|
||||
is useful for example to remote-control i3 (to write test cases for example) or
|
||||
|
@ -140,12 +140,13 @@ VERSION (7)::
|
|||
|
||||
=== COMMAND reply
|
||||
|
||||
The reply consists of a single serialized map. At the moment, the only
|
||||
property is +success (bool)+, but this will be expanded in future versions.
|
||||
The reply consists of a list of serialized maps for each command that was
|
||||
parsed. Each has the property +success (bool)+ and may also include a
|
||||
human-readable error message in the property +error (string)+.
|
||||
|
||||
*Example:*
|
||||
-------------------
|
||||
{ "success": true }
|
||||
[{ "success": true }]
|
||||
-------------------
|
||||
|
||||
=== WORKSPACES reply
|
||||
|
@ -227,9 +228,9 @@ name (string)::
|
|||
The name of this output (as seen in +xrandr(1)+). Encoded in UTF-8.
|
||||
active (boolean)::
|
||||
Whether this output is currently active (has a valid mode).
|
||||
current_workspace (integer)::
|
||||
The current workspace which is visible on this output. +null+ if the
|
||||
output is not active.
|
||||
current_workspace (string)::
|
||||
The name of the current workspace that is visible on this output. +null+ if
|
||||
the output is not active.
|
||||
rect (map)::
|
||||
The rectangle of this output (equals the rect of the output it
|
||||
is on), consists of x, y, width, height.
|
||||
|
@ -240,7 +241,7 @@ rect (map)::
|
|||
{
|
||||
"name": "LVDS1",
|
||||
"active": true,
|
||||
"current_workspace": 4,
|
||||
"current_workspace": "4",
|
||||
"rect": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
|
@ -251,7 +252,7 @@ rect (map)::
|
|||
{
|
||||
"name": "VGA1",
|
||||
"active": true,
|
||||
"current_workspace": 1,
|
||||
"current_workspace": "1",
|
||||
"rect": {
|
||||
"x": 1280,
|
||||
"y": 0,
|
||||
|
@ -277,7 +278,12 @@ name (string)::
|
|||
The internal name of this container. For all containers which are part
|
||||
of the tree structure down to the workspace contents, this is set to a
|
||||
nice human-readable name of the container.
|
||||
For containers that have an X11 window, the content is the title
|
||||
(_NET_WM_NAME property) of that window.
|
||||
For all other containers, the content is not defined (yet).
|
||||
type (string)::
|
||||
Type of this container. Can be one of "root", "output", "con",
|
||||
"floating_con", "workspace" or "dockarea".
|
||||
border (string)::
|
||||
Can be either "normal", "none" or "1pixel", dependending on the
|
||||
container’s border style.
|
||||
|
@ -627,10 +633,11 @@ mode (2)::
|
|||
Sent whenever i3 changes its binding mode.
|
||||
window (3)::
|
||||
Sent when a client's window is successfully reparented (that is when i3
|
||||
has finished fitting it into a container).
|
||||
has finished fitting it into a container), when a window received input
|
||||
focus or when certain properties of the window have changed.
|
||||
barconfig_update (4)::
|
||||
Sent when the hidden_state or mode field in the barconfig of any bar
|
||||
instance was updated.
|
||||
instance was updated and when the config is reloaded.
|
||||
|
||||
*Example:*
|
||||
--------------------------------------------------------------------
|
||||
|
@ -670,12 +677,12 @@ but will still be present in the "old" property.
|
|||
"change": "focus",
|
||||
"current": {
|
||||
"id": 28489712,
|
||||
"type":4,
|
||||
"type": "workspace",
|
||||
...
|
||||
}
|
||||
"old": {
|
||||
"id": 28489715,
|
||||
"type": 4,
|
||||
"type": "workspace",
|
||||
...
|
||||
}
|
||||
}
|
||||
|
@ -707,14 +714,18 @@ mode is simply named default.
|
|||
=== window event
|
||||
|
||||
This event consists of a single serialized map containing a property
|
||||
+change (string)+ which currently can indicate only that a new window
|
||||
has been successfully reparented (the value will be "new").
|
||||
+change (string)+ which indicates the type of the change
|
||||
|
||||
* +new+ - the window has become managed by i3
|
||||
* +focus+ - the window has received input focus
|
||||
* +title+ - the window's title has changed
|
||||
* +fullscreen_mode+ - the window has entered or exited fullscreen mode
|
||||
|
||||
Additionally a +container (object)+ field will be present, which consists
|
||||
of the window's parent container. Be aware that the container will hold
|
||||
the initial name of the newly reparented window (e.g. if you run urxvt
|
||||
with a shell that changes the title, you will still at this point get the
|
||||
window title as "urxvt").
|
||||
of the window's parent container. Be aware that for the "new" event, the
|
||||
container will hold the initial name of the newly reparented window (e.g.
|
||||
if you run urxvt with a shell that changes the title, you will still at
|
||||
this point get the window title as "urxvt").
|
||||
|
||||
*Example:*
|
||||
---------------------------
|
||||
|
@ -722,7 +733,7 @@ window title as "urxvt").
|
|||
"change": "new",
|
||||
"container": {
|
||||
"id": 35569536,
|
||||
"type": 2,
|
||||
"type": "con",
|
||||
...
|
||||
}
|
||||
}
|
||||
|
@ -731,20 +742,8 @@ window title as "urxvt").
|
|||
=== barconfig_update event
|
||||
|
||||
This event consists of a single serialized map reporting on options from the
|
||||
barconfig of the specified bar_id that were updated in i3. The map always
|
||||
consists of a property +id (string)+, which specifies to which bar instance the
|
||||
sent config update belongs, a property +hidden_state (string)+, which indicates
|
||||
the hidden_state of an i3bar instance, and a property +mode (string)+, which
|
||||
corresponds to the current mode.
|
||||
|
||||
*Example:*
|
||||
---------------------------
|
||||
{
|
||||
"id": "bar-0",
|
||||
"hidden_state": "hide"
|
||||
"mode": "hide"
|
||||
}
|
||||
---------------------------
|
||||
barconfig of the specified bar_id that were updated in i3. This event is the
|
||||
same as a +GET_BAR_CONFIG+ reply for the bar with the given id.
|
||||
|
||||
== See also (existing libraries)
|
||||
|
||||
|
@ -756,13 +755,19 @@ know):
|
|||
|
||||
C::
|
||||
i3 includes a headerfile +i3/ipc.h+ which provides you all constants.
|
||||
However, there is no library yet.
|
||||
Ruby::
|
||||
http://github.com/badboy/i3-ipc
|
||||
Perl::
|
||||
https://metacpan.org/module/AnyEvent::I3
|
||||
Python::
|
||||
* https://github.com/whitelynx/i3ipc
|
||||
* https://github.com/ziberna/i3-py (includes higher-level features)
|
||||
|
||||
https://github.com/acrisci/i3ipc-glib
|
||||
Go::
|
||||
* https://github.com/proxypoke/i3ipc
|
||||
JavaScript::
|
||||
* https://github.com/acrisci/i3ipc-gjs
|
||||
Lua::
|
||||
* https:/github.com/acrisci/i3ipc-lua
|
||||
Perl::
|
||||
* https://metacpan.org/module/AnyEvent::I3
|
||||
Python::
|
||||
* https://github.com/acrisci/i3ipc-python
|
||||
* https://github.com/whitelynx/i3ipc (not maintained)
|
||||
* https://github.com/ziberna/i3-py (not maintained)
|
||||
Ruby::
|
||||
http://github.com/badboy/i3-ipc
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
Layout saving in i3
|
||||
===================
|
||||
Michael Stapelberg <michael@i3wm.org>
|
||||
April 2014
|
||||
|
||||
Layout saving/restoring is a feature that was introduced in i3 v4.8.
|
||||
|
||||
Layout saving/restoring allows you to load a JSON layout file so that you can
|
||||
have a base layout to start working with after powering on your computer.
|
||||
Dynamic use-cases also come to mind: if you frequently (but not always!) need a
|
||||
grid layout of terminals with ping/traceroute commands to diagnose network
|
||||
issues, you can easily automate opening these windows in just the right layout.
|
||||
|
||||
== Saving the layout
|
||||
|
||||
You can save the layout of either a single workspace or an entire output (e.g.
|
||||
LVDS1). Of course, you can repeat this step multiple times if you want to
|
||||
save/restore multiple workspaces/outputs.
|
||||
|
||||
+i3-save-tree(1)+ is a tool to save the layout. It will print a JSON
|
||||
representation of i3’s internal layout data structures to stdout. Typically,
|
||||
you may want to take a quick look at the output, then save it to a file and
|
||||
tweak it a little bit:
|
||||
|
||||
---------------------------------------------------
|
||||
i3-save-tree --workspace 1 > ~/.i3/workspace-1.json
|
||||
---------------------------------------------------
|
||||
|
||||
Please note that the output of +i3-save-tree(1)+ is *NOT useful* until you
|
||||
manually modify it — you need to tell i3 how to match/distinguish windows (for
|
||||
example based on their WM_CLASS, title, etc.). By default, all the different
|
||||
window properties are included in the output, but commented out. This is partly
|
||||
to avoid relying on heuristics and partly to make you aware how i3 works so
|
||||
that you can easily solve layout restoring problems.
|
||||
|
||||
How to modify the file manually is described in <<EditingLayoutFiles>>.
|
||||
|
||||
== Restoring the layout
|
||||
|
||||
After restoring the example layout from <<EditingLayoutFiles>>, i3 will open
|
||||
placeholder windows for all the windows that were specified in the layout file.
|
||||
You can recognize the placeholder windows by the watch symbol
|
||||
footnote:[Depending on the font you are using, a placeholder symbol may show up
|
||||
instead of the watch symbol.] in the center of the window, and by the swallow
|
||||
criteria specification at the top of the window:
|
||||
|
||||
image:layout-saving-1.png["Restored layout",width=400,link="layout-saving-1.png"]
|
||||
|
||||
When an application opens a window that matches the specified swallow criteria,
|
||||
it will be placed in the corresponding placeholder window. We say it gets
|
||||
*swallowed* by the placeholder container, hence the term.
|
||||
|
||||
Note: Swallowing windows into unsatisfied placeholder windows takes precedence
|
||||
over
|
||||
link:http://i3wm.org/docs/userguide.html#_automatically_putting_clients_on_specific_workspaces[assignment
|
||||
rules]. For example, if you assign all Emacs windows to workspace 1 in your i3
|
||||
configuration file, but there is a placeholder window on workspace 2 which
|
||||
matches Emacs as well, your newly started Emacs window will end up in the
|
||||
placeholder window on workspace 2.
|
||||
|
||||
The placeholder windows are just regular windows, so feel free to move them
|
||||
around or close them, for example.
|
||||
|
||||
=== append_layout command
|
||||
|
||||
The +append_layout+ command is used to load a layout file into i3. It accepts a
|
||||
path (relative to i3’s current working directory or absolute) to a JSON file.
|
||||
|
||||
*Syntax*:
|
||||
--------------------------------------------------------------------------------
|
||||
append_layout <path>
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
*Examples*:
|
||||
--------------------------------------------------------------------------------
|
||||
# From a terminal or script:
|
||||
i3-msg "workspace 1; append_layout /home/michael/.i3/workspace-1.json"
|
||||
|
||||
# In your i3 configuration file, you can autostart i3-msg like this:
|
||||
# (Note that those lines will quickly become long, so typically you would store
|
||||
# them in a script with proper indentation.)
|
||||
exec --no-startup-id "i3-msg 'workspace 1; append_layout /home/michael/.i3/workspace-1.json'"
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
== Editing layout files
|
||||
|
||||
[[EditingLayoutFiles]]
|
||||
|
||||
=== Anatomy of a layout file
|
||||
|
||||
Here is an example layout file that we’ll discuss:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
{
|
||||
// splitv split container with 2 children
|
||||
"layout": "splitv",
|
||||
"percent": 0.4,
|
||||
"type": "con",
|
||||
"nodes": [
|
||||
{
|
||||
"border": "none",
|
||||
"name": "irssi",
|
||||
"percent": 0.5,
|
||||
"type": "con",
|
||||
"swallows": [
|
||||
{
|
||||
"class": "^URxvt$",
|
||||
"instance": "^irssi$"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
// stacked split container with 2 children
|
||||
"layout": "stacked",
|
||||
"percent": 0.5,
|
||||
"type": "con",
|
||||
"nodes": [
|
||||
{
|
||||
"name": "notmuch",
|
||||
"percent": 0.5,
|
||||
"type": "con",
|
||||
"swallows": [
|
||||
{
|
||||
"class": "^Emacs$",
|
||||
"instance": "^notmuch$"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "midna: ~",
|
||||
"percent": 0.5,
|
||||
"type": "con"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
// stacked split container with 1 children
|
||||
"layout": "stacked",
|
||||
"percent": 0.6,
|
||||
"type": "con",
|
||||
"nodes": [
|
||||
{
|
||||
"name": "chrome",
|
||||
"type": "con",
|
||||
"swallows": [
|
||||
{
|
||||
"class": "^Google-chrome$"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
In this layout, the screen is divided into two columns. In the left column,
|
||||
which covers 40% of the screen, there is a terminal emulator running irssi on
|
||||
the top, and a stacked split container with an Emacs window and a terminal
|
||||
emulator on the bottom. In the right column, there is a stacked container with
|
||||
a Chrome window:
|
||||
|
||||
image:layout-saving-1.png["Restored layout",width=400,link="layout-saving-1.png"]
|
||||
|
||||
The structure of this JSON file looks a lot like the +TREE+ reply, see
|
||||
http://build.i3wm.org/docs/ipc.html#_tree_reply for documentation on that. Some
|
||||
properties are excluded because they are not relevant when restoring a layout.
|
||||
|
||||
Most importantly, look at the "swallows" section of each window. This is where
|
||||
you need to be more or less specific. As an example, remember the section about
|
||||
the Emacs window:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
"swallows": [
|
||||
{
|
||||
"class": "^Emacs$",
|
||||
"instance": "^notmuch$"
|
||||
}
|
||||
]
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Here you can see that i3 will require both the class and the instance to match.
|
||||
Therefore, if you just start Emacs via dmenu, it will not get swallowed by that
|
||||
container. Only if you start Emacs with the proper instance name (+emacs24
|
||||
--name notmuch+), it will get swallowed.
|
||||
|
||||
You can match on "class", "instance", "window_role" and "title". All values are
|
||||
case-sensitive regular expressions (PCRE). Use +xprop(1)+ and click into a
|
||||
window to see its properties:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
$ xprop
|
||||
WM_WINDOW_ROLE(STRING) = "gimp-toolbox-color-dialog"
|
||||
WM_CLASS(STRING) = "gimp-2.8", "Gimp-2.8"
|
||||
_NET_WM_NAME(UTF8_STRING) = "Change Foreground Color"
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The first part of +WM_CLASS+ is the "instance" (gimp-2.8 in this case), the
|
||||
second part is the "class" (Gimp-2.8 in this case). "title" matches against
|
||||
+_NET_WM_NAME+ and "window_role" matches against +WM_WINDOW_ROLE+.
|
||||
|
||||
In general, you should try to be as specific as possible in your swallow
|
||||
criteria. Try to use criteria that match one window and only one window, to
|
||||
have a reliable startup procedure.
|
||||
|
||||
If you specify multiple swallow criteria, the placeholder will be replaced by
|
||||
the window which matches any of the criteria. As an example:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
// Matches either Emacs or Gvim, whichever one is started first.
|
||||
"swallows": [
|
||||
{"class": "^Emacs$"},
|
||||
{"class": "^Gvim$"}
|
||||
]
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
=== JSON standard non-compliance
|
||||
|
||||
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
|
||||
JSON standard only allows precisely one “document” (array or hash).
|
||||
|
||||
2. Layout files contain comments which are not standardized, but understood by
|
||||
many parsers.
|
||||
|
||||
Both deviations from the JSON standard are to make manual editing by humans
|
||||
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
|
||||
example libyajl), transform the layout file to a JSON-conforming file, or
|
||||
link:http://cr.i3wm.org/[submit a patch] to make +i3-save-tree(1)+ optionally
|
||||
output standard-conforming JSON.
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -166,7 +166,8 @@ hint and are opened in floating mode by default.
|
|||
You can toggle floating mode for a window by pressing +$mod+Shift+Space+. By
|
||||
dragging the window’s titlebar with your mouse you can move the window
|
||||
around. By grabbing the borders and moving them you can resize the window. You
|
||||
can also do that by using the <<floating_modifier>>.
|
||||
can also do that by using the <<floating_modifier>>. Another way to resize
|
||||
floating windows using the mouse is to right-click on the titlebar and drag.
|
||||
|
||||
For resizing floating windows with your keyboard, see <<resizingconfig>>.
|
||||
|
||||
|
@ -203,7 +204,7 @@ orientation (horizontal, vertical or unspecified) and the orientation depends
|
|||
on the layout the container is in (vertical for splitv and stacking, horizontal
|
||||
for splith and tabbed). So, in our example with the workspace, the default
|
||||
layout of the workspace +Container+ is splith (most monitors are widescreen
|
||||
nowadays). If you change the layout to splitv (+$mod+l+ in the default config)
|
||||
nowadays). If you change the layout to splitv (+$mod+v+ in the default config)
|
||||
and *then* open two terminals, i3 will configure your windows like this:
|
||||
|
||||
image::tree-shot2.png["shot2",title="Vertical Workspace Orientation"]
|
||||
|
@ -249,13 +250,13 @@ single workspace on which you open three terminal windows. All these terminal
|
|||
windows are directly attached to one node inside i3’s layout tree, the
|
||||
workspace node. By default, the workspace node’s orientation is +horizontal+.
|
||||
|
||||
Now you move one of these terminals down (+$mod+k+ by default). The workspace
|
||||
node’s orientation will be changed to +vertical+. The terminal window you moved
|
||||
down is directly attached to the workspace and appears on the bottom of the
|
||||
screen. A new (horizontal) container was created to accommodate the other two
|
||||
terminal windows. You will notice this when switching to tabbed mode (for
|
||||
example). You would end up having one tab called "another container" and the
|
||||
other one being the terminal window you moved down.
|
||||
Now you move one of these terminals down (+$mod+Shift+k+ by default). The
|
||||
workspace node’s orientation will be changed to +vertical+. The terminal window
|
||||
you moved down is directly attached to the workspace and appears on the bottom
|
||||
of the screen. A new (horizontal) container was created to accommodate the
|
||||
other two terminal windows. You will notice this when switching to tabbed mode
|
||||
(for example). You would end up having one tab called "another container" and
|
||||
the other one being the terminal window you moved down.
|
||||
|
||||
[[configuring]]
|
||||
== Configuring i3
|
||||
|
@ -727,6 +728,9 @@ client.unfocused::
|
|||
A client which is not the focused one of its container.
|
||||
client.urgent::
|
||||
A client which has its urgency hint activated.
|
||||
client.placeholder::
|
||||
Background and text color are used to draw placeholder window contents
|
||||
(when restoring layouts). Border and indicator are ignored.
|
||||
|
||||
You can also specify the color to be used to paint the background of the client
|
||||
windows. This color will be used to paint the window on top of which the client
|
||||
|
@ -749,6 +753,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4
|
|||
client.focused_inactive #333333 #5f676a #ffffff #484e50
|
||||
client.unfocused #333333 #222222 #888888 #292d2e
|
||||
client.urgent #2f343a #900000 #ffffff #900000
|
||||
client.placeholder #000000 #0c0c0c #ffffff #000000
|
||||
---------------------------------------------------------
|
||||
|
||||
Note that for the window decorations, the color around the child window is the
|
||||
|
@ -805,6 +810,26 @@ focus_follows_mouse <yes|no>
|
|||
focus_follows_mouse no
|
||||
----------------------
|
||||
|
||||
=== Mouse warping
|
||||
|
||||
By default, when switching focus to a window on a different output (e.g.
|
||||
focusing a window on workspace 3 on output VGA-1, coming from workspace 2 on
|
||||
LVDS-1), the mouse cursor is warped to the center of that window.
|
||||
|
||||
With the +mouse_warping+ option, you can control when the mouse cursor should
|
||||
be warped. +none+ disables warping entirely, whereas +output+ is the default
|
||||
behavior described above.
|
||||
|
||||
*Syntax*:
|
||||
---------------------------
|
||||
mouse_warping <output|none>
|
||||
---------------------------
|
||||
|
||||
*Example*:
|
||||
------------------
|
||||
mouse_warping none
|
||||
------------------
|
||||
|
||||
=== Popups during fullscreen mode
|
||||
|
||||
When you are in fullscreen mode, some applications still open popup windows
|
||||
|
@ -861,7 +886,7 @@ inferior Xinerama API explicitly and therefore don’t provide support for
|
|||
reconfiguring your screens on the fly (they are read only once on startup and
|
||||
that’s it).
|
||||
|
||||
For people who do cannot modify their +~/.xsession+ to add the
|
||||
For people who cannot modify their +~/.xsession+ to add the
|
||||
+--force-xinerama+ commandline parameter, a configuration option is provided:
|
||||
|
||||
*Syntax*:
|
||||
|
@ -1186,6 +1211,31 @@ bar {
|
|||
}
|
||||
------------------------
|
||||
|
||||
=== Strip workspace numbers
|
||||
|
||||
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
|
||||
order on the bar according to its number without displaying the number prefix.
|
||||
|
||||
When +strip_workspace_numbers+ is set to +yes+, any workspace that has a name of
|
||||
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
|
||||
workspaces to "1:I", "2:II", "3:III", "4:IV", ...
|
||||
|
||||
The default is to display the full name within the workspace button.
|
||||
|
||||
*Syntax*:
|
||||
----------------------------------
|
||||
strip_workspace_numbers <yes|no>
|
||||
----------------------------------
|
||||
|
||||
*Example*:
|
||||
----------------------------
|
||||
bar {
|
||||
strip_workspace_numbers yes
|
||||
}
|
||||
----------------------------
|
||||
|
||||
=== Binding Mode indicator
|
||||
|
||||
Specifies whether the current binding mode indicator should be shown or not.
|
||||
|
|
|
@ -131,7 +131,7 @@ close($enumfh);
|
|||
|
||||
# Third step: Generate the call function.
|
||||
open(my $callfh, '>', "GENERATED_${prefix}_call.h");
|
||||
my $resultname = uc(substr($prefix, 0, 1)) . substr($prefix, 1) . 'Result';
|
||||
my $resultname = uc(substr($prefix, 0, 1)) . substr($prefix, 1) . 'ResultIR';
|
||||
say $callfh "static void GENERATED_call(const int call_identifier, struct $resultname *result) {";
|
||||
say $callfh ' switch (call_identifier) {';
|
||||
my $call_id = 0;
|
||||
|
|
|
@ -53,19 +53,21 @@
|
|||
#error "SYSCONFDIR not defined"
|
||||
#endif
|
||||
|
||||
#define FREE(pointer) do { \
|
||||
if (pointer != NULL) { \
|
||||
free(pointer); \
|
||||
pointer = NULL; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#define FREE(pointer) \
|
||||
do { \
|
||||
if (pointer != NULL) { \
|
||||
free(pointer); \
|
||||
pointer = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#include "xcb.h"
|
||||
#include "libi3.h"
|
||||
|
||||
enum { STEP_WELCOME, STEP_GENERATE } current_step = STEP_WELCOME;
|
||||
enum { MOD_Mod1, MOD_Mod4 } modifier = MOD_Mod4;
|
||||
enum { STEP_WELCOME,
|
||||
STEP_GENERATE } current_step = STEP_WELCOME;
|
||||
enum { MOD_Mod1,
|
||||
MOD_Mod4 } modifier = MOD_Mod4;
|
||||
|
||||
static char *config_path;
|
||||
static uint32_t xcb_numlock_mask;
|
||||
|
@ -102,7 +104,6 @@ typedef struct tokenptr {
|
|||
int n;
|
||||
} cmdp_token_ptr;
|
||||
|
||||
|
||||
#include "GENERATED_config_tokens.h"
|
||||
|
||||
static cmdp_state state;
|
||||
|
@ -111,7 +112,7 @@ static cmdp_state state;
|
|||
* When jumping back to INITIAL, statelist_idx will simply be set to 1
|
||||
* (likewise for other states, e.g. MODE or BAR).
|
||||
* This list is used to process the nearest error token. */
|
||||
static cmdp_state statelist[10] = { INITIAL };
|
||||
static cmdp_state statelist[10] = {INITIAL};
|
||||
/* NB: statelist_idx points to where the next entry will be inserted */
|
||||
static int statelist_idx = 1;
|
||||
|
||||
|
@ -182,7 +183,6 @@ static void push_long(const char *identifier, long num) {
|
|||
"in the code, or a new command which contains more than "
|
||||
"10 identified tokens.\n");
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
static const char *get_string(const char *identifier) {
|
||||
|
@ -195,7 +195,6 @@ static const char *get_string(const char *identifier) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void clear_stack(void) {
|
||||
for (int c = 0; c < 10; c++) {
|
||||
if (stack[c].type == STACK_STR && stack[c].val.str != NULL)
|
||||
|
@ -213,8 +212,8 @@ static void clear_stack(void) {
|
|||
*/
|
||||
static bool keysym_used_on_other_key(KeySym sym, xcb_keycode_t except_keycode) {
|
||||
xcb_keycode_t i,
|
||||
min_keycode = xcb_get_setup(conn)->min_keycode,
|
||||
max_keycode = xcb_get_setup(conn)->max_keycode;
|
||||
min_keycode = xcb_get_setup(conn)->min_keycode,
|
||||
max_keycode = xcb_get_setup(conn)->max_keycode;
|
||||
|
||||
for (i = min_keycode; i && i <= max_keycode; i++) {
|
||||
if (i == except_keycode)
|
||||
|
@ -228,7 +227,6 @@ static bool keysym_used_on_other_key(KeySym sym, xcb_keycode_t except_keycode) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
static char *next_state(const cmdp_token *token) {
|
||||
cmdp_state _next_state = token->next_state;
|
||||
|
||||
|
@ -277,7 +275,7 @@ static char *next_state(const cmdp_token *token) {
|
|||
for (int i = 0; i < statelist_idx; i++) {
|
||||
if (statelist[i] != _next_state)
|
||||
continue;
|
||||
statelist_idx = i+1;
|
||||
statelist_idx = i + 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -286,7 +284,6 @@ static char *next_state(const cmdp_token *token) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static char *rewrite_binding(const char *input) {
|
||||
state = INITIAL;
|
||||
statelist_idx = 1;
|
||||
|
@ -299,13 +296,13 @@ static char *rewrite_binding(const char *input) {
|
|||
|
||||
/* The "<=" operator is intentional: We also handle the terminating 0-byte
|
||||
* explicitly by looking for an 'end' token. */
|
||||
while ((walk - input) <= len) {
|
||||
while ((size_t)(walk - input) <= len) {
|
||||
/* Skip whitespace before every token, newlines are relevant since they
|
||||
* separate configuration directives. */
|
||||
while ((*walk == ' ' || *walk == '\t') && *walk != '\0')
|
||||
walk++;
|
||||
|
||||
//printf("remaining input: %s\n", walk);
|
||||
//printf("remaining input: %s\n", walk);
|
||||
|
||||
cmdp_token_ptr *ptr = &(tokens[state]);
|
||||
for (c = 0; c < ptr->n; c++) {
|
||||
|
@ -354,7 +351,7 @@ static char *rewrite_binding(const char *input) {
|
|||
if (*walk == '"') {
|
||||
beginning++;
|
||||
walk++;
|
||||
while (*walk != '\0' && (*walk != '"' || *(walk-1) == '\\'))
|
||||
while (*walk != '\0' && (*walk != '"' || *(walk - 1) == '\\'))
|
||||
walk++;
|
||||
} else {
|
||||
if (token->name[0] == 's') {
|
||||
|
@ -366,22 +363,22 @@ static char *rewrite_binding(const char *input) {
|
|||
* semicolon (;). */
|
||||
while (*walk != ' ' && *walk != '\t' &&
|
||||
*walk != ']' && *walk != ',' &&
|
||||
*walk != ';' && *walk != '\r' &&
|
||||
*walk != ';' && *walk != '\r' &&
|
||||
*walk != '\n' && *walk != '\0')
|
||||
walk++;
|
||||
}
|
||||
}
|
||||
if (walk != beginning) {
|
||||
char *str = scalloc(walk-beginning + 1);
|
||||
char *str = scalloc(walk - beginning + 1);
|
||||
/* We copy manually to handle escaping of characters. */
|
||||
int inpos, outpos;
|
||||
for (inpos = 0, outpos = 0;
|
||||
inpos < (walk-beginning);
|
||||
inpos < (walk - beginning);
|
||||
inpos++, outpos++) {
|
||||
/* We only handle escaped double quotes to not break
|
||||
* backwards compatibility with people using \w in
|
||||
* regular expressions etc. */
|
||||
if (beginning[inpos] == '\\' && beginning[inpos+1] == '"')
|
||||
if (beginning[inpos] == '\\' && beginning[inpos + 1] == '"')
|
||||
inpos++;
|
||||
str[outpos] = beginning[inpos];
|
||||
}
|
||||
|
@ -410,15 +407,14 @@ static char *rewrite_binding(const char *input) {
|
|||
// TODO: make this testable
|
||||
walk++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Having verboselog(), errorlog() and debuglog() is necessary when using libi3.
|
||||
*
|
||||
|
@ -453,7 +449,7 @@ static char *resolve_tilde(const char *path) {
|
|||
char *head, *tail, *result;
|
||||
|
||||
tail = strchr(path, '/');
|
||||
head = strndup(path, tail ? tail - path : strlen(path));
|
||||
head = strndup(path, tail ? (size_t)(tail - path) : strlen(path));
|
||||
|
||||
int res = glob(head, GLOB_TILDE, NULL, &globbuf);
|
||||
free(head);
|
||||
|
@ -481,14 +477,14 @@ static char *resolve_tilde(const char *path) {
|
|||
static int handle_expose() {
|
||||
/* re-draw the background */
|
||||
xcb_rectangle_t border = {0, 0, 300, (15 * font.height) + 8};
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ get_colorpixel("#000000") });
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {get_colorpixel("#000000")});
|
||||
xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border);
|
||||
|
||||
set_font(&font);
|
||||
|
||||
#define txt(x, row, text) \
|
||||
draw_text_ascii(text, pixmap, pixmap_gc,\
|
||||
x, (row - 1) * font.height + 4, 300 - x * 2)
|
||||
#define txt(x, row, text) \
|
||||
draw_text_ascii(text, pixmap, pixmap_gc, \
|
||||
x, (row - 1) * font.height + 4, 300 - x * 2)
|
||||
|
||||
if (current_step == STEP_WELCOME) {
|
||||
/* restore font color */
|
||||
|
@ -521,14 +517,16 @@ static int handle_expose() {
|
|||
/* the not-selected modifier */
|
||||
if (modifier == MOD_Mod4)
|
||||
txt(31, 5, "<Alt>");
|
||||
else txt(31, 4, "<Win>");
|
||||
else
|
||||
txt(31, 4, "<Win>");
|
||||
|
||||
/* the selected modifier */
|
||||
set_font(&bold_font);
|
||||
set_font_colors(pixmap_gc, get_colorpixel("#FFFFFF"), get_colorpixel("#000000"));
|
||||
if (modifier == MOD_Mod4)
|
||||
txt(10, 4, "-> <Win>");
|
||||
else txt(10, 5, "-> <Alt>");
|
||||
else
|
||||
txt(10, 5, "-> <Alt>");
|
||||
|
||||
/* green */
|
||||
set_font(&font);
|
||||
|
@ -565,16 +563,16 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
|
|||
current_step = STEP_GENERATE;
|
||||
/* Set window title */
|
||||
xcb_change_property(conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_NAME,
|
||||
A_UTF8_STRING,
|
||||
8,
|
||||
strlen("i3: generate config"),
|
||||
"i3: generate config");
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_NAME,
|
||||
A_UTF8_STRING,
|
||||
8,
|
||||
strlen("i3: generate config"),
|
||||
"i3: generate config");
|
||||
xcb_flush(conn);
|
||||
}
|
||||
else finish();
|
||||
} else
|
||||
finish();
|
||||
}
|
||||
|
||||
/* cancel any time */
|
||||
|
@ -618,7 +616,7 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
|
|||
* Handle button presses to make clicking on "<win>" and "<alt>" work
|
||||
*
|
||||
*/
|
||||
static void handle_button_press(xcb_button_press_event_t* event) {
|
||||
static void handle_button_press(xcb_button_press_event_t *event) {
|
||||
if (current_step != STEP_GENERATE)
|
||||
return;
|
||||
|
||||
|
@ -667,7 +665,7 @@ static void finish() {
|
|||
fputs("# This file has been auto-generated by i3-config-wizard(1).\n", ks_config);
|
||||
fputs("# It will not be overwritten, so edit it as you like.\n", ks_config);
|
||||
fputs("#\n", ks_config);
|
||||
fputs("# Should you change your keyboard layout somewhen, delete\n", ks_config);
|
||||
fputs("# Should you change your keyboard layout some time, delete\n", ks_config);
|
||||
fputs("# this file and re-run i3-config-wizard(1).\n", ks_config);
|
||||
fputs("#\n", ks_config);
|
||||
|
||||
|
@ -701,7 +699,8 @@ static void finish() {
|
|||
if (strncmp(walk, "set $mod ", strlen("set $mod ")) == 0) {
|
||||
if (modifier == MOD_Mod1)
|
||||
fputs("set $mod Mod1\n", ks_config);
|
||||
else fputs("set $mod Mod4\n", ks_config);
|
||||
else
|
||||
fputs("set $mod Mod4\n", ks_config);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -729,7 +728,7 @@ static void finish() {
|
|||
|
||||
/* tell i3 to reload the config file */
|
||||
int sockfd = ipc_connect(socket_path);
|
||||
ipc_send_message(sockfd, strlen("reload"), 0, (uint8_t*)"reload");
|
||||
ipc_send_message(sockfd, strlen("reload"), 0, (uint8_t *)"reload");
|
||||
close(sockfd);
|
||||
|
||||
exit(0);
|
||||
|
@ -750,8 +749,7 @@ int main(int argc, char *argv[]) {
|
|||
{"prefix", required_argument, 0, 'p'},
|
||||
{"font", required_argument, 0, 'f'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
char *options_string = "s:vh";
|
||||
|
||||
|
@ -810,11 +808,11 @@ int main(int argc, char *argv[]) {
|
|||
modmap_cookie = xcb_get_modifier_mapping(conn);
|
||||
symbols = xcb_key_symbols_alloc(conn);
|
||||
|
||||
/* Place requests for the atoms we need as soon as possible */
|
||||
#define xmacro(atom) \
|
||||
xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
/* Place requests for the atoms we need as soon as possible */
|
||||
#define xmacro(atom) \
|
||||
xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
|
||||
root_screen = xcb_aux_get_screen(conn, screen);
|
||||
root = root_screen->root;
|
||||
|
@ -832,54 +830,53 @@ int main(int argc, char *argv[]) {
|
|||
xcb_create_window(
|
||||
conn,
|
||||
XCB_COPY_FROM_PARENT,
|
||||
win, /* the window id */
|
||||
root, /* parent == root */
|
||||
win, /* the window id */
|
||||
root, /* parent == root */
|
||||
490, 297, 300, 205, /* dimensions */
|
||||
0, /* X11 border = 0, we draw our own */
|
||||
0, /* X11 border = 0, we draw our own */
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||
XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */
|
||||
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
|
||||
(uint32_t[]){
|
||||
(uint32_t[]) {
|
||||
0, /* back pixel: black */
|
||||
XCB_EVENT_MASK_EXPOSURE |
|
||||
XCB_EVENT_MASK_BUTTON_PRESS
|
||||
});
|
||||
XCB_EVENT_MASK_BUTTON_PRESS});
|
||||
|
||||
/* Map the window (make it visible) */
|
||||
xcb_map_window(conn, win);
|
||||
|
||||
/* Setup NetWM atoms */
|
||||
#define xmacro(name) \
|
||||
do { \
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
|
||||
if (!reply) \
|
||||
errx(EXIT_FAILURE, "Could not get atom " # name "\n"); \
|
||||
\
|
||||
A_ ## name = reply->atom; \
|
||||
free(reply); \
|
||||
} while (0);
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
/* Setup NetWM atoms */
|
||||
#define xmacro(name) \
|
||||
do { \
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
|
||||
if (!reply) \
|
||||
errx(EXIT_FAILURE, "Could not get atom " #name "\n"); \
|
||||
\
|
||||
A_##name = reply->atom; \
|
||||
free(reply); \
|
||||
} while (0);
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
|
||||
/* Set dock mode */
|
||||
xcb_change_property(conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_WINDOW_TYPE,
|
||||
A_ATOM,
|
||||
32,
|
||||
1,
|
||||
(unsigned char*) &A__NET_WM_WINDOW_TYPE_DIALOG);
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_WINDOW_TYPE,
|
||||
A_ATOM,
|
||||
32,
|
||||
1,
|
||||
(unsigned char *)&A__NET_WM_WINDOW_TYPE_DIALOG);
|
||||
|
||||
/* Set window title */
|
||||
xcb_change_property(conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_NAME,
|
||||
A_UTF8_STRING,
|
||||
8,
|
||||
strlen("i3: first configuration"),
|
||||
"i3: first configuration");
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_NAME,
|
||||
A_UTF8_STRING,
|
||||
8,
|
||||
strlen("i3: first configuration"),
|
||||
"i3: first configuration");
|
||||
|
||||
/* Create pixmap */
|
||||
pixmap = xcb_generate_id(conn);
|
||||
|
@ -922,13 +919,13 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
switch (type) {
|
||||
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;
|
||||
|
||||
/* TODO: handle mappingnotify */
|
||||
|
||||
case XCB_BUTTON_PRESS:
|
||||
handle_button_press((xcb_button_press_event_t*)event);
|
||||
handle_button_press((xcb_button_press_event_t *)event);
|
||||
break;
|
||||
|
||||
case XCB_EXPOSE:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef I3_XCB_H
|
||||
#define I3_XCB_H
|
||||
#pragma once
|
||||
|
||||
/* from X11/keysymdef.h */
|
||||
#define XCB_NUM_LOCK 0xff7f
|
||||
|
@ -7,5 +6,3 @@
|
|||
#define xmacro(atom) xcb_atom_t A_ ## atom;
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env perl
|
||||
# vim:ts=4:sw=4:expandtab
|
||||
#
|
||||
# © 2012-2013 Michael Stapelberg
|
||||
# © 2012-2014 Michael Stapelberg
|
||||
#
|
||||
# No dependencies except for perl ≥ v5.10
|
||||
|
||||
|
@ -55,8 +55,12 @@ my $result = GetOptions(
|
|||
die "Could not parse command line options" unless $result;
|
||||
|
||||
# Filter entry types and set default type(s) if none selected
|
||||
my @valid_types = ('name', 'command', 'filename');
|
||||
@entry_types = grep { $_ ~~ @valid_types } @entry_types;
|
||||
my $valid_types = {
|
||||
name => 1,
|
||||
command => 1,
|
||||
filename => 1,
|
||||
};
|
||||
@entry_types = grep { exists($valid_types->{$_}) } @entry_types;
|
||||
@entry_types = ('name', 'command') unless @entry_types;
|
||||
|
||||
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
|
@ -257,7 +261,7 @@ for my $app (keys %apps) {
|
|||
}
|
||||
}
|
||||
|
||||
if ('name' ~~ @entry_types) {
|
||||
if ((scalar grep { $_ eq 'name' } @entry_types) > 0) {
|
||||
if (exists($choices{$name})) {
|
||||
# There are two .desktop files which contain the same “Name” value.
|
||||
# I’m not sure if that is allowed to happen, but we disambiguate the
|
||||
|
@ -273,22 +277,22 @@ for my $app (keys %apps) {
|
|||
$choices{$name} = $app;
|
||||
}
|
||||
|
||||
if ('command' ~~ @entry_types) {
|
||||
if ((scalar grep { $_ eq 'command' } @entry_types) > 0) {
|
||||
my ($command) = split(' ', $apps{$app}->{Exec});
|
||||
|
||||
# Don’t add “geany” if “Geany” is already present.
|
||||
my @keys = map { lc } keys %choices;
|
||||
next if lc(basename($command)) ~~ @keys;
|
||||
next if (scalar grep { $_ eq lc(basename($command)) } @keys) > 0;
|
||||
|
||||
$choices{basename($command)} = $app;
|
||||
}
|
||||
|
||||
if ('filename' ~~ @entry_types) {
|
||||
if ((scalar grep { $_ eq 'filename' } @entry_types) > 0) {
|
||||
my $filename = basename($app, '.desktop');
|
||||
|
||||
# Don’t add “geany” if “Geany” is already present.
|
||||
my @keys = map { lc } keys %choices;
|
||||
next if lc($filename) ~~ @keys;
|
||||
next if (scalar grep { $_ eq lc($filename) } @keys) > 0;
|
||||
|
||||
$choices{$filename} = $app;
|
||||
}
|
||||
|
@ -376,6 +380,7 @@ sub quote {
|
|||
|
||||
$choice = quote($choice);
|
||||
$location = quote($location);
|
||||
$name = quote($name);
|
||||
|
||||
# Remove deprecated field codes, as the spec dictates.
|
||||
$exec =~ s/%[dDnNvm]//g;
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
#include <i3/ipc.h>
|
||||
|
||||
static uint32_t offset_next_write,
|
||||
wrap_count;
|
||||
wrap_count;
|
||||
|
||||
static i3_shmlog_header *header;
|
||||
static char *logbuffer,
|
||||
*walk;
|
||||
*walk;
|
||||
|
||||
static int check_for_wrap(void) {
|
||||
if (wrap_count == header->wrap_count)
|
||||
|
@ -70,8 +70,7 @@ int main(int argc, char *argv[]) {
|
|||
{"verbose", no_argument, 0, 'V'},
|
||||
{"follow", no_argument, 0, 'f'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
char *options_string = "s:vfVh";
|
||||
|
||||
|
@ -139,7 +138,7 @@ int main(int argc, char *argv[]) {
|
|||
if (logbuffer == MAP_FAILED)
|
||||
err(EXIT_FAILURE, "Could not mmap SHM segment for the i3 log");
|
||||
|
||||
header = (i3_shmlog_header*)logbuffer;
|
||||
header = (i3_shmlog_header *)logbuffer;
|
||||
|
||||
if (verbose)
|
||||
printf("next_write = %d, last_wrap = %d, logbuffer_size = %d, shmname = %s\n",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef I3_INPUT
|
||||
#define I3_INPUT
|
||||
#pragma once
|
||||
|
||||
#include <err.h>
|
||||
|
||||
|
@ -13,5 +12,3 @@
|
|||
while (0)
|
||||
|
||||
extern xcb_window_t root;
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -103,7 +103,7 @@ static void restore_input_focus(void) {
|
|||
*
|
||||
*/
|
||||
static uint8_t *concat_strings(char **glyphs, int max) {
|
||||
uint8_t *output = calloc(max+1, 4);
|
||||
uint8_t *output = calloc(max + 1, 4);
|
||||
uint8_t *walk = output;
|
||||
for (int c = 0; c < max; c++) {
|
||||
printf("at %c\n", glyphs[c][0]);
|
||||
|
@ -112,7 +112,7 @@ static uint8_t *concat_strings(char **glyphs, int max) {
|
|||
memcpy(walk, glyphs[c], 2);
|
||||
walk += 2;
|
||||
} else {
|
||||
strcpy((char*)walk, glyphs[c]);
|
||||
strcpy((char *)walk, glyphs[c]);
|
||||
walk += strlen(glyphs[c]);
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +130,9 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t
|
|||
|
||||
/* re-draw the background */
|
||||
xcb_rectangle_t border = {0, 0, 500, font.height + 8}, inner = {2, 2, 496, font.height + 8 - 4};
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ get_colorpixel("#FF0000") });
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {get_colorpixel("#FF0000")});
|
||||
xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &border);
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ get_colorpixel("#000000") });
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {get_colorpixel("#000000")});
|
||||
xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &inner);
|
||||
|
||||
/* restore font color */
|
||||
|
@ -143,8 +143,7 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t
|
|||
draw_text(prompt, pixmap, pixmap_gc, 4, 4, 492);
|
||||
}
|
||||
/* … and the text */
|
||||
if (input_position > 0)
|
||||
{
|
||||
if (input_position > 0) {
|
||||
i3String *input = i3string_from_ucs2(glyphs_ucs, input_position);
|
||||
draw_text(input, pixmap, pixmap_gc, prompt_offset + 4, 4, 492);
|
||||
i3string_free(input);
|
||||
|
@ -174,14 +173,14 @@ static int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_rel
|
|||
}
|
||||
|
||||
static void finish_input() {
|
||||
char *command = (char*)concat_strings(glyphs_utf8, input_position);
|
||||
char *command = (char *)concat_strings(glyphs_utf8, input_position);
|
||||
|
||||
/* count the occurences of %s in the string */
|
||||
int c;
|
||||
int len = strlen(format);
|
||||
int cnt = 0;
|
||||
for (c = 0; c < (len-1); c++)
|
||||
if (format[c] == '%' && format[c+1] == 's')
|
||||
for (c = 0; c < (len - 1); c++)
|
||||
if (format[c] == '%' && format[c + 1] == 's')
|
||||
cnt++;
|
||||
printf("occurences = %d\n", cnt);
|
||||
|
||||
|
@ -189,13 +188,13 @@ static void finish_input() {
|
|||
int inputlen = strlen(command);
|
||||
char *full = calloc(1,
|
||||
strlen(format) - (2 * cnt) /* format without all %s */
|
||||
+ (inputlen * cnt) /* replaced %s */
|
||||
+ 1); /* trailing NUL */
|
||||
+ (inputlen * cnt) /* replaced %s */
|
||||
+ 1); /* trailing NUL */
|
||||
char *dest = full;
|
||||
for (c = 0; c < len; c++) {
|
||||
/* if this is not % or it is % but without a following 's',
|
||||
* just copy the character */
|
||||
if (format[c] != '%' || (c == (len-1)) || format[c+1] != 's')
|
||||
if (format[c] != '%' || (c == (len - 1)) || format[c + 1] != 's')
|
||||
*(dest++) = format[c];
|
||||
else {
|
||||
strncat(dest, command, inputlen);
|
||||
|
@ -212,7 +211,9 @@ static void finish_input() {
|
|||
|
||||
xcb_aux_sync(conn);
|
||||
|
||||
ipc_send_message(sockfd, strlen(full), 0, (uint8_t*)full);
|
||||
ipc_send_message(sockfd, strlen(full), 0, (uint8_t *)full);
|
||||
|
||||
free(full);
|
||||
|
||||
#if 0
|
||||
free(command);
|
||||
|
@ -290,8 +291,8 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press
|
|||
}
|
||||
|
||||
xcb_char2b_t inp;
|
||||
inp.byte1 = ( ucs & 0xff00 ) >> 2;
|
||||
inp.byte2 = ( ucs & 0x00ff ) >> 0;
|
||||
inp.byte1 = (ucs & 0xff00) >> 2;
|
||||
inp.byte2 = (ucs & 0x00ff) >> 0;
|
||||
|
||||
printf("inp.byte1 = %02x, inp.byte2 = %02x\n", inp.byte1, inp.byte2);
|
||||
/* convert it to UTF-8 */
|
||||
|
@ -324,8 +325,7 @@ int main(int argc, char *argv[]) {
|
|||
{"format", required_argument, 0, 'F'},
|
||||
{"font", required_argument, 0, 'f'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
char *options_string = "s:p:P:f:l:F:vh";
|
||||
|
||||
|
@ -403,18 +403,17 @@ int main(int argc, char *argv[]) {
|
|||
xcb_create_window(
|
||||
conn,
|
||||
XCB_COPY_FROM_PARENT,
|
||||
win, /* the window id */
|
||||
root, /* parent == root */
|
||||
win, /* the window id */
|
||||
root, /* parent == root */
|
||||
50, 50, 500, font.height + 8, /* dimensions */
|
||||
0, /* X11 border = 0, we draw our own */
|
||||
0, /* X11 border = 0, we draw our own */
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||
XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */
|
||||
XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK,
|
||||
(uint32_t[]){
|
||||
(uint32_t[]) {
|
||||
0, /* back pixel: black */
|
||||
1, /* override redirect: don’t manage this window */
|
||||
XCB_EVENT_MASK_EXPOSURE
|
||||
});
|
||||
XCB_EVENT_MASK_EXPOSURE});
|
||||
|
||||
/* Map the window (make it visible) */
|
||||
xcb_map_window(conn, win);
|
||||
|
@ -465,15 +464,15 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
switch (type) {
|
||||
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;
|
||||
|
||||
case XCB_KEY_RELEASE:
|
||||
handle_key_release(NULL, conn, (xcb_key_release_event_t*)event);
|
||||
handle_key_release(NULL, conn, (xcb_key_release_event_t *)event);
|
||||
break;
|
||||
|
||||
case XCB_EXPOSE:
|
||||
handle_expose(NULL, conn, (xcb_expose_event_t*)event);
|
||||
handle_expose(NULL, conn, (xcb_expose_event_t *)event);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,20 +76,17 @@ static int reply_boolean_cb(void *params, int val) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int reply_string_cb(void *params, const unsigned char *val, size_t len) {
|
||||
#else
|
||||
static int reply_string_cb(void *params, const unsigned char *val, unsigned int len) {
|
||||
#endif
|
||||
char *str = scalloc(len + 1);
|
||||
strncpy(str, (const char*)val, len);
|
||||
strncpy(str, (const char *)val, len);
|
||||
if (strcmp(last_key, "error") == 0)
|
||||
last_reply.error = str;
|
||||
else if (strcmp(last_key, "input") == 0)
|
||||
last_reply.input = str;
|
||||
else if (strcmp(last_key, "errorposition") == 0)
|
||||
last_reply.errorposition = str;
|
||||
else free(str);
|
||||
else
|
||||
free(str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -106,36 +103,25 @@ static int reply_end_map_cb(void *params) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int reply_map_key_cb(void *params, const unsigned char *keyVal, size_t keyLen) {
|
||||
#else
|
||||
static int reply_map_key_cb(void *params, const unsigned char *keyVal, unsigned keyLen) {
|
||||
#endif
|
||||
free(last_key);
|
||||
last_key = scalloc(keyLen + 1);
|
||||
strncpy(last_key, (const char*)keyVal, keyLen);
|
||||
strncpy(last_key, (const char *)keyVal, keyLen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
yajl_callbacks reply_callbacks = {
|
||||
NULL,
|
||||
&reply_boolean_cb,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&reply_string_cb,
|
||||
&reply_start_map_cb,
|
||||
&reply_map_key_cb,
|
||||
&reply_end_map_cb,
|
||||
NULL,
|
||||
NULL
|
||||
static yajl_callbacks reply_callbacks = {
|
||||
.yajl_boolean = reply_boolean_cb,
|
||||
.yajl_string = reply_string_cb,
|
||||
.yajl_start_map = reply_start_map_cb,
|
||||
.yajl_map_key = reply_map_key_cb,
|
||||
.yajl_end_map = reply_end_map_cb,
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
socket_path = getenv("I3SOCK");
|
||||
int o, option_index = 0;
|
||||
int message_type = I3_IPC_MESSAGE_TYPE_COMMAND;
|
||||
uint32_t message_type = I3_IPC_MESSAGE_TYPE_COMMAND;
|
||||
char *payload = NULL;
|
||||
bool quiet = false;
|
||||
|
||||
|
@ -145,8 +131,7 @@ int main(int argc, char *argv[]) {
|
|||
{"version", no_argument, 0, 'v'},
|
||||
{"quiet", no_argument, 0, 'q'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
char *options_string = "s:t:vhq";
|
||||
|
||||
|
@ -221,10 +206,10 @@ int main(int argc, char *argv[]) {
|
|||
memset(&addr, 0, sizeof(struct sockaddr_un));
|
||||
addr.sun_family = AF_LOCAL;
|
||||
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
||||
if (connect(sockfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0)
|
||||
if (connect(sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
|
||||
err(EXIT_FAILURE, "Could not connect to i3 on socket \"%s\"", socket_path);
|
||||
|
||||
if (ipc_send_message(sockfd, strlen(payload), message_type, (uint8_t*)payload) == -1)
|
||||
if (ipc_send_message(sockfd, strlen(payload), message_type, (uint8_t *)payload) == -1)
|
||||
err(EXIT_FAILURE, "IPC: write()");
|
||||
|
||||
if (quiet)
|
||||
|
@ -245,21 +230,12 @@ int main(int argc, char *argv[]) {
|
|||
* If not, nicely format the error message. */
|
||||
if (reply_type == I3_IPC_MESSAGE_TYPE_COMMAND) {
|
||||
yajl_handle handle;
|
||||
#if YAJL_MAJOR < 2
|
||||
yajl_parser_config parse_conf = { 0, 0 };
|
||||
|
||||
handle = yajl_alloc(&reply_callbacks, &parse_conf, NULL, NULL);
|
||||
#else
|
||||
handle = yajl_alloc(&reply_callbacks, NULL, NULL);
|
||||
#endif
|
||||
yajl_status state = yajl_parse(handle, (const unsigned char*)reply, reply_length);
|
||||
yajl_status state = yajl_parse(handle, (const unsigned char *)reply, reply_length);
|
||||
switch (state) {
|
||||
case yajl_status_ok:
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
#if YAJL_MAJOR < 2
|
||||
case yajl_status_insufficient_data:
|
||||
#endif
|
||||
case yajl_status_error:
|
||||
errx(EXIT_FAILURE, "IPC: Could not parse JSON reply.");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef I3_NAGBAR
|
||||
#define I3_NAGBAR
|
||||
#pragma once
|
||||
|
||||
#include <err.h>
|
||||
|
||||
|
@ -17,5 +16,3 @@ while (0)
|
|||
#undef xmacro
|
||||
|
||||
extern xcb_window_t root;
|
||||
|
||||
#endif
|
||||
|
|
159
i3-nagbar/main.c
159
i3-nagbar/main.c
|
@ -43,7 +43,7 @@ typedef struct {
|
|||
static xcb_window_t win;
|
||||
static xcb_pixmap_t pixmap;
|
||||
static xcb_gcontext_t pixmap_gc;
|
||||
static xcb_rectangle_t rect = { 0, 0, 600, 20 };
|
||||
static xcb_rectangle_t rect = {0, 0, 600, 20};
|
||||
static i3Font font;
|
||||
static i3String *prompt;
|
||||
static button_t *buttons;
|
||||
|
@ -100,7 +100,7 @@ static void start_application(const char *command) {
|
|||
setsid();
|
||||
if (fork() == 0) {
|
||||
/* This is the child */
|
||||
execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, (void*)NULL);
|
||||
execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, (void *)NULL);
|
||||
/* not reached */
|
||||
}
|
||||
exit(0);
|
||||
|
@ -118,7 +118,7 @@ static button_t *get_button_at(int16_t x, int16_t y) {
|
|||
|
||||
static void handle_button_press(xcb_connection_t *conn, xcb_button_press_event_t *event) {
|
||||
printf("button pressed on x = %d, y = %d\n",
|
||||
event->event_x, event->event_y);
|
||||
event->event_x, event->event_y);
|
||||
/* TODO: set a flag for the button, re-render */
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ static void handle_button_press(xcb_connection_t *conn, xcb_button_press_event_t
|
|||
*/
|
||||
static void handle_button_release(xcb_connection_t *conn, xcb_button_release_event_t *event) {
|
||||
printf("button released on x = %d, y = %d\n",
|
||||
event->event_x, event->event_y);
|
||||
event->event_x, event->event_y);
|
||||
/* If the user hits the close button, we exit(0) */
|
||||
if (event->event_x >= (rect.width - 32))
|
||||
exit(0);
|
||||
|
@ -188,13 +188,13 @@ static void handle_button_release(xcb_connection_t *conn, xcb_button_release_eve
|
|||
*/
|
||||
static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
|
||||
/* re-draw the background */
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ color_background });
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {color_background});
|
||||
xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &rect);
|
||||
|
||||
/* restore font color */
|
||||
set_font_colors(pixmap_gc, color_text, color_background);
|
||||
draw_text(prompt, pixmap, pixmap_gc,
|
||||
4 + 4, 4 + 4, rect.width - 4 - 4);
|
||||
4 + 4, 4 + 4, rect.width - 4 - 4);
|
||||
|
||||
/* render close button */
|
||||
const char *close_button_label = "X";
|
||||
|
@ -209,24 +209,23 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
|
|||
values[1] = line_width;
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values);
|
||||
|
||||
xcb_rectangle_t close = { y - w - (2 * line_width), 0, w + (2 * line_width), rect.height };
|
||||
xcb_rectangle_t close = {y - w - (2 * line_width), 0, w + (2 * line_width), rect.height};
|
||||
xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close);
|
||||
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ color_border });
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {color_border});
|
||||
xcb_point_t points[] = {
|
||||
{ y - w - (2 * line_width), line_width / 2 },
|
||||
{ y - (line_width / 2), line_width / 2 },
|
||||
{ y - (line_width / 2), (rect.height - (line_width / 2)) - 2 },
|
||||
{ y - w - (2 * line_width), (rect.height - (line_width / 2)) - 2 },
|
||||
{ y - w - (2 * line_width), line_width / 2 }
|
||||
};
|
||||
{y - w - (2 * line_width), line_width / 2},
|
||||
{y - (line_width / 2), line_width / 2},
|
||||
{y - (line_width / 2), (rect.height - (line_width / 2)) - 2},
|
||||
{y - w - (2 * line_width), (rect.height - (line_width / 2)) - 2},
|
||||
{y - w - (2 * line_width), line_width / 2}};
|
||||
xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points);
|
||||
|
||||
values[0] = 1;
|
||||
set_font_colors(pixmap_gc, color_text, color_button_background);
|
||||
/* the x term here seems to set left/right padding */
|
||||
draw_text_ascii(close_button_label, pixmap, pixmap_gc, y - w - line_width + w / 2 - 4,
|
||||
4 + 4 - 1, rect.width - y + w + line_width - w / 2 + 4);
|
||||
4 + 4 - 1, rect.width - y + w + line_width - w / 2 + 4);
|
||||
y -= w;
|
||||
|
||||
y -= 20;
|
||||
|
@ -239,20 +238,19 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
|
|||
/* account for left/right padding, which seems to be set to 12px (total) below */
|
||||
w += 12;
|
||||
y -= 30;
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ color_button_background });
|
||||
close = (xcb_rectangle_t){ y - w - (2 * line_width), 2, w + (2 * line_width), rect.height - 6 };
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {color_button_background});
|
||||
close = (xcb_rectangle_t) {y - w - (2 * line_width), 2, w + (2 * line_width), rect.height - 6};
|
||||
xcb_poly_fill_rectangle(conn, pixmap, pixmap_gc, 1, &close);
|
||||
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]){ color_border });
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND, (uint32_t[]) {color_border});
|
||||
buttons[c].x = y - w - (2 * line_width);
|
||||
buttons[c].width = w;
|
||||
xcb_point_t points2[] = {
|
||||
{ y - w - (2 * line_width), (line_width / 2) + 2 },
|
||||
{ y - (line_width / 2), (line_width / 2) + 2 },
|
||||
{ y - (line_width / 2), (rect.height - 4 - (line_width / 2)) },
|
||||
{ y - w - (2 * line_width), (rect.height - 4 - (line_width / 2)) },
|
||||
{ y - w - (2 * line_width), (line_width / 2) + 2 }
|
||||
};
|
||||
{y - w - (2 * line_width), (line_width / 2) + 2},
|
||||
{y - (line_width / 2), (line_width / 2) + 2},
|
||||
{y - (line_width / 2), (rect.height - 4 - (line_width / 2))},
|
||||
{y - w - (2 * line_width), (rect.height - 4 - (line_width / 2))},
|
||||
{y - w - (2 * line_width), (line_width / 2) + 2}};
|
||||
xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 5, points2);
|
||||
|
||||
values[0] = color_text;
|
||||
|
@ -260,7 +258,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
|
|||
set_font_colors(pixmap_gc, color_text, color_button_background);
|
||||
/* the x term seems to set left/right padding */
|
||||
draw_text(buttons[c].label, pixmap, pixmap_gc,
|
||||
y - w - line_width + 6, 4 + 3, rect.width - y + w + line_width - 6);
|
||||
y - w - line_width + 6, 4 + 3, rect.width - y + w + line_width - 6);
|
||||
|
||||
y -= w;
|
||||
}
|
||||
|
@ -271,12 +269,10 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
|
|||
values[1] = line_width;
|
||||
xcb_change_gc(conn, pixmap_gc, XCB_GC_FOREGROUND | XCB_GC_LINE_WIDTH, values);
|
||||
xcb_point_t bottom[] = {
|
||||
{ 0, rect.height - 0 },
|
||||
{ rect.width, rect.height - 0 }
|
||||
};
|
||||
{0, rect.height - 0},
|
||||
{rect.width, rect.height - 0}};
|
||||
xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, pixmap, pixmap_gc, 2, bottom);
|
||||
|
||||
|
||||
/* Copy the contents of the pixmap to the real window */
|
||||
xcb_copy_area(conn, pixmap, win, pixmap_gc, 0, 0, 0, 0, rect.width, rect.height);
|
||||
xcb_flush(conn);
|
||||
|
@ -322,7 +318,8 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
char *pattern = sstrdup("-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1");
|
||||
int o, option_index = 0;
|
||||
enum { TYPE_ERROR = 0, TYPE_WARNING = 1 } bar_type = TYPE_ERROR;
|
||||
enum { TYPE_ERROR = 0,
|
||||
TYPE_WARNING = 1 } bar_type = TYPE_ERROR;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"version", no_argument, 0, 'v'},
|
||||
|
@ -331,8 +328,7 @@ int main(int argc, char *argv[]) {
|
|||
{"help", no_argument, 0, 'h'},
|
||||
{"message", required_argument, 0, 'm'},
|
||||
{"type", required_argument, 0, 't'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
char *options_string = "b:f:m:t:vh";
|
||||
|
||||
|
@ -341,7 +337,7 @@ int main(int argc, char *argv[]) {
|
|||
while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
|
||||
switch (o) {
|
||||
case 'v':
|
||||
printf("i3-nagbar " I3_VERSION);
|
||||
printf("i3-nagbar " I3_VERSION "\n");
|
||||
return 0;
|
||||
case 'f':
|
||||
FREE(pattern);
|
||||
|
@ -363,8 +359,8 @@ int main(int argc, char *argv[]) {
|
|||
buttons[buttoncnt].label = i3string_from_utf8(optarg);
|
||||
buttons[buttoncnt].action = argv[optind];
|
||||
printf("button with label *%s* and action *%s*\n",
|
||||
i3string_as_utf8(buttons[buttoncnt].label),
|
||||
buttons[buttoncnt].action);
|
||||
i3string_as_utf8(buttons[buttoncnt].label),
|
||||
buttons[buttoncnt].action);
|
||||
buttoncnt++;
|
||||
printf("now %d buttons\n", buttoncnt);
|
||||
if (optind < argc)
|
||||
|
@ -378,11 +374,11 @@ int main(int argc, char *argv[]) {
|
|||
xcb_connection_has_error(conn))
|
||||
die("Cannot open display\n");
|
||||
|
||||
/* Place requests for the atoms we need as soon as possible */
|
||||
#define xmacro(atom) \
|
||||
xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
/* Place requests for the atoms we need as soon as possible */
|
||||
#define xmacro(atom) \
|
||||
xcb_intern_atom_cookie_t atom##_cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
|
||||
root_screen = xcb_aux_get_screen(conn, screens);
|
||||
root = root_screen->root;
|
||||
|
@ -412,46 +408,45 @@ int main(int argc, char *argv[]) {
|
|||
xcb_create_window(
|
||||
conn,
|
||||
XCB_COPY_FROM_PARENT,
|
||||
win, /* the window id */
|
||||
root, /* parent == root */
|
||||
win, /* the window id */
|
||||
root, /* parent == root */
|
||||
50, 50, 500, font.height + 8 + 8 /* 8 px padding */, /* dimensions */
|
||||
0, /* x11 border = 0, we draw our own */
|
||||
0, /* x11 border = 0, we draw our own */
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||
XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */
|
||||
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
|
||||
(uint32_t[]){
|
||||
(uint32_t[]) {
|
||||
0, /* back pixel: black */
|
||||
XCB_EVENT_MASK_EXPOSURE |
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_BUTTON_PRESS |
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE
|
||||
});
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_BUTTON_PRESS |
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE});
|
||||
|
||||
/* Map the window (make it visible) */
|
||||
xcb_map_window(conn, win);
|
||||
|
||||
/* Setup NetWM atoms */
|
||||
#define xmacro(name) \
|
||||
do { \
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
|
||||
if (!reply) \
|
||||
die("Could not get atom " # name "\n"); \
|
||||
\
|
||||
A_ ## name = reply->atom; \
|
||||
free(reply); \
|
||||
} while (0);
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
/* Setup NetWM atoms */
|
||||
#define xmacro(name) \
|
||||
do { \
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name##_cookie, NULL); \
|
||||
if (!reply) \
|
||||
die("Could not get atom " #name "\n"); \
|
||||
\
|
||||
A_##name = reply->atom; \
|
||||
free(reply); \
|
||||
} while (0);
|
||||
#include "atoms.xmacro"
|
||||
#undef xmacro
|
||||
|
||||
/* Set dock mode */
|
||||
xcb_change_property(conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_WINDOW_TYPE,
|
||||
A_ATOM,
|
||||
32,
|
||||
1,
|
||||
(unsigned char*) &A__NET_WM_WINDOW_TYPE_DOCK);
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_WINDOW_TYPE,
|
||||
A_ATOM,
|
||||
32,
|
||||
1,
|
||||
(unsigned char *)&A__NET_WM_WINDOW_TYPE_DOCK);
|
||||
|
||||
/* Reserve some space at the top of the screen */
|
||||
struct {
|
||||
|
@ -467,20 +462,21 @@ int main(int argc, char *argv[]) {
|
|||
uint32_t top_end_x;
|
||||
uint32_t bottom_start_x;
|
||||
uint32_t bottom_end_x;
|
||||
} __attribute__((__packed__)) strut_partial = {0,};
|
||||
} __attribute__((__packed__)) strut_partial;
|
||||
memset(&strut_partial, 0, sizeof(strut_partial));
|
||||
|
||||
strut_partial.top = font.height + 6;
|
||||
strut_partial.top_start_x = 0;
|
||||
strut_partial.top_end_x = 800;
|
||||
|
||||
xcb_change_property(conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_STRUT_PARTIAL,
|
||||
A_CARDINAL,
|
||||
32,
|
||||
12,
|
||||
&strut_partial);
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
A__NET_WM_STRUT_PARTIAL,
|
||||
A_CARDINAL,
|
||||
32,
|
||||
12,
|
||||
&strut_partial);
|
||||
|
||||
/* Create pixmap */
|
||||
pixmap = xcb_generate_id(conn);
|
||||
|
@ -503,25 +499,24 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
switch (type) {
|
||||
case XCB_EXPOSE:
|
||||
handle_expose(conn, (xcb_expose_event_t*)event);
|
||||
handle_expose(conn, (xcb_expose_event_t *)event);
|
||||
break;
|
||||
|
||||
case XCB_BUTTON_PRESS:
|
||||
handle_button_press(conn, (xcb_button_press_event_t*)event);
|
||||
handle_button_press(conn, (xcb_button_press_event_t *)event);
|
||||
break;
|
||||
|
||||
case XCB_BUTTON_RELEASE:
|
||||
handle_button_release(conn, (xcb_button_release_event_t*)event);
|
||||
handle_button_release(conn, (xcb_button_release_event_t *)event);
|
||||
break;
|
||||
|
||||
case XCB_CONFIGURE_NOTIFY: {
|
||||
xcb_configure_notify_event_t *configure_notify = (xcb_configure_notify_event_t*)event;
|
||||
rect = (xcb_rectangle_t){
|
||||
xcb_configure_notify_event_t *configure_notify = (xcb_configure_notify_event_t *)event;
|
||||
rect = (xcb_rectangle_t) {
|
||||
configure_notify->x,
|
||||
configure_notify->y,
|
||||
configure_notify->width,
|
||||
configure_notify->height
|
||||
};
|
||||
configure_notify->height};
|
||||
|
||||
/* Recreate the pixmap / gc */
|
||||
xcb_free_pixmap(conn, pixmap);
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
#!/usr/bin/env perl
|
||||
# vim:ts=4:sw=4:expandtab
|
||||
#
|
||||
# © 2013-2014 Michael Stapelberg
|
||||
#
|
||||
# Requires perl ≥ v5.10, AnyEvent::I3 and JSON::XS
|
||||
|
||||
use strict;
|
||||
use warnings qw(FATAL utf8);
|
||||
use Data::Dumper;
|
||||
use IPC::Open2;
|
||||
use POSIX qw(locale_h);
|
||||
use File::Find;
|
||||
use File::Basename qw(basename);
|
||||
use File::Temp qw(tempfile);
|
||||
use Getopt::Long;
|
||||
use Pod::Usage;
|
||||
use AnyEvent::I3;
|
||||
use JSON::XS;
|
||||
use List::Util qw(first);
|
||||
use v5.10;
|
||||
use utf8;
|
||||
use open ':encoding(UTF-8)';
|
||||
|
||||
binmode STDOUT, ':utf8';
|
||||
binmode STDERR, ':utf8';
|
||||
|
||||
my $workspace;
|
||||
my $output;
|
||||
my $result = GetOptions(
|
||||
'workspace=s' => \$workspace,
|
||||
'output=s' => \$output,
|
||||
'version' => sub {
|
||||
say "i3-save-tree 0.1 © 2013 Michael Stapelberg";
|
||||
exit 0;
|
||||
},
|
||||
'help' => sub {
|
||||
pod2usage(-exitval => 0);
|
||||
});
|
||||
|
||||
die "Could not parse command line options" unless $result;
|
||||
|
||||
if (!defined($workspace) && !defined($output)) {
|
||||
die "One of --workspace or --output need to be specified";
|
||||
}
|
||||
|
||||
unless (defined($workspace) ^ defined($output)) {
|
||||
die "Only one of --workspace or --output can be specified";
|
||||
}
|
||||
|
||||
my $i3 = i3();
|
||||
if (!$i3->connect->recv) {
|
||||
die "Could not connect to i3";
|
||||
}
|
||||
|
||||
sub filter_containers {
|
||||
my ($tree, $pred) = @_;
|
||||
|
||||
$_ = $tree;
|
||||
return $tree if $pred->();
|
||||
|
||||
for my $child (@{$tree->{nodes}}, @{$tree->{floating_nodes}}) {
|
||||
my $result = filter_containers($child, $pred);
|
||||
return $result if defined($result);
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub leaf_node {
|
||||
my ($tree) = @_;
|
||||
|
||||
return $tree->{type} eq 'con' &&
|
||||
@{$tree->{nodes}} == 0 &&
|
||||
@{$tree->{floating_nodes}} == 0;
|
||||
}
|
||||
|
||||
my %allowed_keys = map { ($_, 1) } qw(
|
||||
type
|
||||
fullscreen_mode
|
||||
layout
|
||||
border
|
||||
current_border_width
|
||||
floating
|
||||
percent
|
||||
nodes
|
||||
floating_nodes
|
||||
name
|
||||
geometry
|
||||
window_properties
|
||||
);
|
||||
|
||||
sub strip_containers {
|
||||
my ($tree) = @_;
|
||||
|
||||
# layout is not relevant for a leaf container
|
||||
delete $tree->{layout} if leaf_node($tree);
|
||||
|
||||
# fullscreen_mode conveys no state at all, it can either be 0 or 1 and the
|
||||
# default is _always_ 0, so skip noop entries.
|
||||
delete $tree->{fullscreen_mode} if $tree->{fullscreen_mode} == 0;
|
||||
|
||||
# names for non-leafs are auto-generated and useful only for i3 debugging
|
||||
delete $tree->{name} unless leaf_node($tree);
|
||||
|
||||
delete $tree->{geometry} if zero_rect($tree->{geometry});
|
||||
|
||||
delete $tree->{current_border_width} if $tree->{current_border_width} == -1;
|
||||
|
||||
for my $key (keys %$tree) {
|
||||
next if exists($allowed_keys{$key});
|
||||
|
||||
delete $tree->{$key};
|
||||
}
|
||||
|
||||
for my $key (qw(nodes floating_nodes)) {
|
||||
$tree->{$key} = [ map { strip_containers($_) } @{$tree->{$key}} ];
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
my $json_xs = JSON::XS->new->pretty(1)->allow_nonref->space_before(0)->canonical(1);
|
||||
|
||||
sub zero_rect {
|
||||
my ($rect) = @_;
|
||||
return $rect->{x} == 0 &&
|
||||
$rect->{y} == 0 &&
|
||||
$rect->{width} == 0 &&
|
||||
$rect->{height} == 0;
|
||||
}
|
||||
|
||||
# Dumps the containers in JSON, but with comments to explain the user what she
|
||||
# needs to fix.
|
||||
sub dump_containers {
|
||||
my ($tree, $ws, $last) = @_;
|
||||
|
||||
$ws //= "";
|
||||
|
||||
say $ws . '{';
|
||||
|
||||
$ws .= (' ' x 4);
|
||||
|
||||
if (!leaf_node($tree)) {
|
||||
my $desc = $tree->{layout} . ' split container';
|
||||
if ($tree->{type} ne 'con') {
|
||||
$desc = $tree->{type};
|
||||
}
|
||||
say "$ws// $desc with " . @{$tree->{nodes}} . " children";
|
||||
}
|
||||
|
||||
# Turn “window_properties” into “swallows” expressions, but only for leaf
|
||||
# nodes. It only makes sense for leaf nodes to swallow anything.
|
||||
if (leaf_node($tree)) {
|
||||
my $swallows = {};
|
||||
for my $property (keys %{$tree->{window_properties}}) {
|
||||
$swallows->{$property} = '^' . quotemeta($tree->{window_properties}->{$property}) . '$';
|
||||
}
|
||||
$tree->{swallows} = [ $swallows ];
|
||||
}
|
||||
delete $tree->{window_properties};
|
||||
|
||||
my @keys = sort keys %$tree;
|
||||
for (0 .. (@keys-1)) {
|
||||
my $key = $keys[$_];
|
||||
# Those are handled recursively, not printed.
|
||||
next if $key eq 'nodes' || $key eq 'floating_nodes';
|
||||
|
||||
# JSON::XS’s encode appends a newline
|
||||
chomp(my $val = $json_xs->encode($tree->{$key}));
|
||||
|
||||
# Fix indentation. Keep in mind we are producing output to be
|
||||
# read/modified by a human.
|
||||
$val =~ s/^/$ws/mg;
|
||||
$val =~ s/^\s+//;
|
||||
|
||||
# Comment out all swallows criteria, they are just suggestions.
|
||||
if ($key eq 'swallows') {
|
||||
$val =~ s,^(\s*)\s{3}",\1// ",gm;
|
||||
}
|
||||
|
||||
# Append a comma unless this is the last value.
|
||||
# Ugly, but necessary so that we can print all values before recursing.
|
||||
my $comma = ($_ == (@keys-1) &&
|
||||
@{$tree->{nodes}} == 0 &&
|
||||
@{$tree->{floating_nodes}} == 0 ? '' : ',');
|
||||
say qq#$ws"$key": $val$comma#;
|
||||
}
|
||||
|
||||
for my $key (qw(nodes floating_nodes)) {
|
||||
my $num = scalar @{$tree->{$key}};
|
||||
next if !$num;
|
||||
|
||||
say qq#$ws"$key": [#;
|
||||
for (0 .. ($num-1)) {
|
||||
dump_containers(
|
||||
$tree->{$key}->[$_],
|
||||
$ws . (' ' x 4),
|
||||
($_ == ($num-1)));
|
||||
}
|
||||
say qq#$ws]#;
|
||||
}
|
||||
|
||||
$ws =~ s/\s{4}$//;
|
||||
|
||||
say $ws . ($last ? '}' : '},');
|
||||
}
|
||||
|
||||
my $tree = $i3->get_tree->recv;
|
||||
|
||||
my $dump;
|
||||
if (defined($workspace)) {
|
||||
$dump = filter_containers($tree, sub {
|
||||
$_->{type} eq 'workspace' && $_->{name} eq $workspace
|
||||
});
|
||||
} else {
|
||||
$dump = filter_containers($tree, sub {
|
||||
$_->{type} eq 'output' && $_->{name} eq $output
|
||||
});
|
||||
# Get the output’s content container (living beneath dockarea containers).
|
||||
$dump = first { $_->{type} eq 'con' } @{$dump->{nodes}};
|
||||
}
|
||||
|
||||
$dump = strip_containers($dump);
|
||||
|
||||
say "// vim:ts=4:sw=4:et";
|
||||
for my $key (qw(nodes floating_nodes)) {
|
||||
for (0 .. (@{$dump->{$key}} - 1)) {
|
||||
dump_containers($dump->{$key}->[$_], undef, 1);
|
||||
# Newlines separate containers so that one can use { and } in vim to
|
||||
# jump out of the current container.
|
||||
say '';
|
||||
}
|
||||
}
|
||||
|
||||
=encoding utf-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
i3-save-tree - save (parts of) the layout tree for restoring
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
i3-save-tree [--workspace=name] [--output=name]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Dumps a workspace (or an entire output) to stdout. The data is supposed to be
|
||||
edited a bit by a human, then later fed to i3 via the append_layout command.
|
||||
|
||||
The append_layout command will create placeholder windows, arranged in the
|
||||
layout the input file specifies. Each container should have a swallows
|
||||
specification. When a window is mapped (made visible on the screen) that
|
||||
matches the specification, i3 will put it into that place and kill the
|
||||
placeholder.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over
|
||||
|
||||
=item B<--workspace=name>
|
||||
|
||||
Specifies the workspace that should be dumped, e.g. 1. Either this or --output
|
||||
need to be specified.
|
||||
|
||||
=item B<--output=name>
|
||||
|
||||
Specifies the output that should be dumped, e.g. LVDS-1. Either this or
|
||||
--workspace need to be specified.
|
||||
|
||||
=back
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
Version 0.1
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Michael Stapelberg, C<< <michael at i3wm.org> >>
|
||||
|
||||
=head1 LICENSE AND COPYRIGHT
|
||||
|
||||
Copyright 2013 Michael Stapelberg.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the BSD license.
|
||||
|
||||
=cut
|
46
i3.config
46
i3.config
|
@ -10,13 +10,23 @@
|
|||
#
|
||||
|
||||
# Font for window titles. Will also be used by the bar unless a different font
|
||||
# is used in the bar {} block below. ISO 10646 = Unicode
|
||||
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||
# is used in the bar {} block below.
|
||||
# This font is widely installed, provides lots of unicode glyphs, right-to-left
|
||||
# text rendering and scalability on retina/hidpi displays (thanks to pango).
|
||||
font pango:DejaVu Sans Mono 8
|
||||
# Before i3 v4.8, we used to recommend this one as the default:
|
||||
# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||
# The font above is very space-efficient, that is, it looks good, sharp and
|
||||
# clear in small sizes. However, if you need a lot of unicode glyphs or
|
||||
# right-to-left text rendering, you should instead use pango for rendering and
|
||||
# chose a FreeType font, such as:
|
||||
# font pango:DejaVu Sans Mono 10
|
||||
# clear in small sizes. However, its unicode glyph coverage is limited, the old
|
||||
# X core fonts rendering does not support right-to-left and this being a bitmap
|
||||
# font, it doesn’t scale on retina/hidpi displays.
|
||||
|
||||
# use these keys for focus, movement, and resize directions when reaching for
|
||||
# the arrows is not convenient
|
||||
set $up l
|
||||
set $down k
|
||||
set $left j
|
||||
set $right semicolon
|
||||
|
||||
# use Mouse+Mod1 to drag floating windows to their wanted position
|
||||
floating_modifier Mod1
|
||||
|
@ -35,10 +45,10 @@ bindsym Mod1+d exec dmenu_run
|
|||
# bindsym Mod1+d exec --no-startup-id i3-dmenu-desktop
|
||||
|
||||
# change focus
|
||||
bindsym Mod1+j focus left
|
||||
bindsym Mod1+k focus down
|
||||
bindsym Mod1+l focus up
|
||||
bindsym Mod1+semicolon focus right
|
||||
bindsym Mod1+$left focus left
|
||||
bindsym Mod1+$down focus down
|
||||
bindsym Mod1+$up focus up
|
||||
bindsym Mod1+$right focus right
|
||||
|
||||
# alternatively, you can use the cursor keys:
|
||||
bindsym Mod1+Left focus left
|
||||
|
@ -47,10 +57,10 @@ bindsym Mod1+Up focus up
|
|||
bindsym Mod1+Right focus right
|
||||
|
||||
# move focused window
|
||||
bindsym Mod1+Shift+j move left
|
||||
bindsym Mod1+Shift+k move down
|
||||
bindsym Mod1+Shift+l move up
|
||||
bindsym Mod1+Shift+semicolon move right
|
||||
bindsym Mod1+Shift+$left move left
|
||||
bindsym Mod1+Shift+$down move down
|
||||
bindsym Mod1+Shift+$up move up
|
||||
bindsym Mod1+Shift+$right move right
|
||||
|
||||
# alternatively, you can use the cursor keys:
|
||||
bindsym Mod1+Shift+Left move left
|
||||
|
@ -130,10 +140,10 @@ mode "resize" {
|
|||
# Pressing right will grow the window’s width.
|
||||
# Pressing up will shrink the window’s height.
|
||||
# Pressing down will grow the window’s height.
|
||||
bindsym j resize shrink width 10 px or 10 ppt
|
||||
bindsym k resize grow height 10 px or 10 ppt
|
||||
bindsym l resize shrink height 10 px or 10 ppt
|
||||
bindsym semicolon resize grow width 10 px or 10 ppt
|
||||
bindsym $left resize shrink width 10 px or 10 ppt
|
||||
bindsym $down resize grow height 10 px or 10 ppt
|
||||
bindsym $up resize shrink height 10 px or 10 ppt
|
||||
bindsym $right resize grow width 10 px or 10 ppt
|
||||
|
||||
# same bindings, but for the arrow keys
|
||||
bindsym Left resize shrink width 10 px or 10 ppt
|
||||
|
|
|
@ -11,13 +11,16 @@
|
|||
set $mod Mod1
|
||||
|
||||
# Font for window titles. Will also be used by the bar unless a different font
|
||||
# is used in the bar {} block below. ISO 10646 = Unicode
|
||||
font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||
# is used in the bar {} block below.
|
||||
# This font is widely installed, provides lots of unicode glyphs, right-to-left
|
||||
# text rendering and scalability on retina/hidpi displays (thanks to pango).
|
||||
font pango:DejaVu Sans Mono 8
|
||||
# Before i3 v4.8, we used to recommend this one as the default:
|
||||
# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
|
||||
# The font above is very space-efficient, that is, it looks good, sharp and
|
||||
# clear in small sizes. However, if you need a lot of unicode glyphs or
|
||||
# right-to-left text rendering, you should instead use pango for rendering and
|
||||
# chose a FreeType font, such as:
|
||||
# font pango:DejaVu Sans Mono 10
|
||||
# clear in small sizes. However, its unicode glyph coverage is limited, the old
|
||||
# X core fonts rendering does not support right-to-left and this being a bitmap
|
||||
# font, it doesn’t scale on retina/hidpi displays.
|
||||
|
||||
# Use Mouse+$mod to drag floating windows to their wanted position
|
||||
floating_modifier $mod
|
||||
|
|
|
@ -2,4 +2,6 @@
|
|||
Name=i3
|
||||
Comment=improved dynamic tiling window manager
|
||||
Exec=i3
|
||||
TryExec=i3
|
||||
Type=Application
|
||||
X-LightDM-DesktopName=i3
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* child.c: Getting Input for the statusline
|
||||
*
|
||||
*/
|
||||
#ifndef CHILD_H_
|
||||
#define CHILD_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
@ -74,10 +73,14 @@ void stop_child(void);
|
|||
*/
|
||||
void cont_child(void);
|
||||
|
||||
/*
|
||||
* Whether or not the child want click events
|
||||
*
|
||||
*/
|
||||
bool child_want_click_events(void);
|
||||
|
||||
/*
|
||||
* Generates a click event, if enabled.
|
||||
*
|
||||
*/
|
||||
void send_block_clicked(int button, const char *name, const char *instance, int x, int y);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* © 2010-2011 Axel Wagner and contributors (see also: LICENSE)
|
||||
*
|
||||
*/
|
||||
#ifndef COMMON_H_
|
||||
#define COMMON_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
@ -74,5 +73,3 @@ TAILQ_HEAD(statusline_head, status_block) statusline_head;
|
|||
#include "config.h"
|
||||
#include "libi3.h"
|
||||
#include "parse_json_header.h"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* config.c: Parses the configuration (received from i3).
|
||||
*
|
||||
*/
|
||||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
@ -18,6 +17,9 @@ typedef enum {
|
|||
POS_BOT
|
||||
} position_t;
|
||||
|
||||
/* Bar display mode (hide unless modifier is pressed or show in dock mode or always hide in invisible mode) */
|
||||
typedef enum { M_DOCK = 0, M_HIDE = 1, M_INVISIBLE = 2 } bar_display_mode_t;
|
||||
|
||||
typedef struct config_t {
|
||||
int modifier;
|
||||
position_t position;
|
||||
|
@ -25,6 +27,7 @@ typedef struct config_t {
|
|||
struct xcb_color_strings_t colors;
|
||||
bool disable_binding_mode_indicator;
|
||||
bool disable_ws;
|
||||
bool strip_ws_numbers;
|
||||
char *bar_id;
|
||||
char *command;
|
||||
char *fontname;
|
||||
|
@ -32,8 +35,7 @@ typedef struct config_t {
|
|||
int num_outputs;
|
||||
char **outputs;
|
||||
|
||||
/* Bar display mode (hide unless modifier is pressed or show in dock mode or always hide in invisible mode) */
|
||||
enum { M_DOCK = 0, M_HIDE = 1, M_INVISIBLE = 2 } hide_on_modifier;
|
||||
bar_display_mode_t hide_on_modifier;
|
||||
|
||||
/* The current hidden_state of the bar, which indicates whether it is hidden or shown */
|
||||
enum { S_HIDE = 0, S_SHOW = 1 } hidden_state;
|
||||
|
@ -52,5 +54,3 @@ void parse_config_json(char *json);
|
|||
*
|
||||
*/
|
||||
void free_colors(struct xcb_color_strings_t *colors);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* ipc.c: Communicating with i3
|
||||
*
|
||||
*/
|
||||
#ifndef IPC_H_
|
||||
#define IPC_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -37,5 +36,3 @@ int i3_send_msg(uint32_t type, const char* payload);
|
|||
*
|
||||
*/
|
||||
void subscribe_events(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* mode.c: Handle mode-event and show current binding mode in the bar
|
||||
*
|
||||
*/
|
||||
#ifndef MODE_H_
|
||||
#define MODE_H_
|
||||
#pragma once
|
||||
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
|
@ -27,5 +26,3 @@ typedef struct mode mode;
|
|||
*
|
||||
*/
|
||||
void parse_mode_json(char *json);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* outputs.c: Maintaining the output-list
|
||||
*
|
||||
*/
|
||||
#ifndef OUTPUTS_H_
|
||||
#define OUTPUTS_H_
|
||||
#pragma once
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
|
@ -53,5 +52,3 @@ struct i3_output {
|
|||
|
||||
SLIST_ENTRY(i3_output) slist; /* Pointer for the SLIST-Macro */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
* protocol version and features.
|
||||
*
|
||||
*/
|
||||
#ifndef PARSE_JSON_HEADER_H_
|
||||
#define PARSE_JSON_HEADER_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -22,5 +21,3 @@
|
|||
*
|
||||
*/
|
||||
void parse_json_header(i3bar_child *child, const unsigned char *buffer, int length, unsigned int *consumed);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* © 2010-2011 Axel Wagner and contributors (see also: LICENSE)
|
||||
*
|
||||
*/
|
||||
#ifndef TRAYCLIENT_H_
|
||||
#define TRAYCLIENT_H_
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
@ -21,5 +20,3 @@ struct trayclient {
|
|||
|
||||
TAILQ_ENTRY(trayclient) tailq; /* Pointer for the TAILQ-Macro */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
|
||||
*
|
||||
*/
|
||||
#ifndef UTIL_H_
|
||||
#define UTIL_H_
|
||||
#pragma once
|
||||
|
||||
#include "queue.h"
|
||||
|
||||
|
@ -36,8 +35,6 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
/* Securely fee tail-queues */
|
||||
#define FREE_TAILQ(l, type) do { \
|
||||
type *walk = TAILQ_FIRST(l); \
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* workspaces.c: Maintaining the workspace-lists
|
||||
*
|
||||
*/
|
||||
#ifndef WORKSPACES_H_
|
||||
#define WORKSPACES_H_
|
||||
#pragma once
|
||||
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
|
@ -32,7 +31,8 @@ void free_workspaces(void);
|
|||
|
||||
struct i3_ws {
|
||||
int num; /* The internal number of the ws */
|
||||
i3String *name; /* The name of the ws */
|
||||
char *canonical_name; /* The true name of the ws according to the ipc */
|
||||
i3String *name; /* The name of the ws that is displayed on the bar */
|
||||
int name_width; /* The rendered width of the name */
|
||||
bool visible; /* If the ws is currently visible on an output */
|
||||
bool focused; /* If the ws is currently focused */
|
||||
|
@ -42,5 +42,3 @@ struct i3_ws {
|
|||
|
||||
TAILQ_ENTRY(i3_ws) tailq; /* Pointer for the TAILQ-Macro */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* xcb.c: Communicating with X
|
||||
*
|
||||
*/
|
||||
#ifndef XCB_H_
|
||||
#define XCB_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
//#include "outputs.h"
|
||||
|
@ -133,5 +132,3 @@ void redraw_bars(void);
|
|||
*
|
||||
*/
|
||||
void set_current_mode(struct mode *mode);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,14 +28,13 @@
|
|||
#include "common.h"
|
||||
|
||||
/* Global variables for child_*() */
|
||||
i3bar_child child = { 0 };
|
||||
i3bar_child child;
|
||||
|
||||
/* stdin- and sigchild-watchers */
|
||||
ev_io *stdin_io;
|
||||
ev_io *stdin_io;
|
||||
ev_child *child_sig;
|
||||
|
||||
/* JSON parser for stdin */
|
||||
yajl_callbacks callbacks;
|
||||
yajl_handle parser;
|
||||
|
||||
/* JSON generator for stdout */
|
||||
|
@ -81,12 +80,7 @@ static void clear_status_blocks() {
|
|||
* `draw_bars' is called, the error message text will be drawn on the bar in
|
||||
* the space allocated for the statusline.
|
||||
*/
|
||||
|
||||
/* forward function declaration is needed to add __attribute__ mechanism which
|
||||
* helps the compiler understand we are defining a printf wrapper */
|
||||
static void set_statusline_error(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
static void set_statusline_error(const char *format, ...) {
|
||||
__attribute__((format(printf, 1, 2))) static void set_statusline_error(const char *format, ...) {
|
||||
clear_status_blocks();
|
||||
|
||||
char *message;
|
||||
|
@ -162,16 +156,12 @@ static int stdin_start_map(void *context) {
|
|||
memset(&(ctx->block), '\0', sizeof(struct status_block));
|
||||
|
||||
/* Default width of the separator block. */
|
||||
ctx->block.sep_block_width = 9;
|
||||
ctx->block.sep_block_width = logical_px(9);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int stdin_map_key(void *context, const unsigned char *key, size_t len) {
|
||||
#else
|
||||
static int stdin_map_key(void *context, const unsigned char *key, unsigned int len) {
|
||||
#endif
|
||||
parser_ctx *ctx = context;
|
||||
FREE(ctx->last_map_key);
|
||||
sasprintf(&(ctx->last_map_key), "%.*s", len, key);
|
||||
|
@ -189,11 +179,7 @@ static int stdin_boolean(void *context, int val) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int stdin_string(void *context, const unsigned char *val, size_t len) {
|
||||
#else
|
||||
static int stdin_string(void *context, const unsigned char *val, unsigned int len) {
|
||||
#endif
|
||||
parser_ctx *ctx = context;
|
||||
if (strcasecmp(ctx->last_map_key, "full_text") == 0) {
|
||||
ctx->block.full_text = i3string_from_utf8_with_length((const char *)val, len);
|
||||
|
@ -202,9 +188,9 @@ static int stdin_string(void *context, const unsigned char *val, unsigned int le
|
|||
sasprintf(&(ctx->block.color), "%.*s", len, val);
|
||||
}
|
||||
if (strcasecmp(ctx->last_map_key, "align") == 0) {
|
||||
if (len == strlen("left") && !strncmp((const char*)val, "left", strlen("left"))) {
|
||||
if (len == strlen("left") && !strncmp((const char *)val, "left", strlen("left"))) {
|
||||
ctx->block.align = ALIGN_LEFT;
|
||||
} else if (len == strlen("right") && !strncmp((const char*)val, "right", strlen("right"))) {
|
||||
} else if (len == strlen("right") && !strncmp((const char *)val, "right", strlen("right"))) {
|
||||
ctx->block.align = ALIGN_RIGHT;
|
||||
} else {
|
||||
ctx->block.align = ALIGN_CENTER;
|
||||
|
@ -215,13 +201,13 @@ static int stdin_string(void *context, const unsigned char *val, unsigned int le
|
|||
i3string_free(text);
|
||||
}
|
||||
if (strcasecmp(ctx->last_map_key, "name") == 0) {
|
||||
char *copy = (char*)malloc(len+1);
|
||||
char *copy = (char *)malloc(len + 1);
|
||||
strncpy(copy, (const char *)val, len);
|
||||
copy[len] = 0;
|
||||
ctx->block.name = copy;
|
||||
}
|
||||
if (strcasecmp(ctx->last_map_key, "instance") == 0) {
|
||||
char *copy = (char*)malloc(len+1);
|
||||
char *copy = (char *)malloc(len + 1);
|
||||
strncpy(copy, (const char *)val, len);
|
||||
copy[len] = 0;
|
||||
ctx->block.instance = copy;
|
||||
|
@ -229,11 +215,7 @@ static int stdin_string(void *context, const unsigned char *val, unsigned int le
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int stdin_integer(void *context, long long val) {
|
||||
#else
|
||||
static int stdin_integer(void *context, long val) {
|
||||
#endif
|
||||
parser_ctx *ctx = context;
|
||||
if (strcasecmp(ctx->last_map_key, "min_width") == 0) {
|
||||
ctx->block.min_width = (uint32_t)val;
|
||||
|
@ -261,7 +243,7 @@ static int stdin_end_map(void *context) {
|
|||
static int stdin_end_array(void *context) {
|
||||
DLOG("dumping statusline:\n");
|
||||
struct status_block *current;
|
||||
TAILQ_FOREACH(current, &statusline_head, blocks) {
|
||||
TAILQ_FOREACH (current, &statusline_head, blocks) {
|
||||
DLOG("full_text = %s\n", i3string_as_utf8(current->full_text));
|
||||
DLOG("color = %s\n", current->color);
|
||||
}
|
||||
|
@ -272,15 +254,17 @@ static int stdin_end_array(void *context) {
|
|||
/*
|
||||
* Helper function to read stdin
|
||||
*
|
||||
* Returns NULL on EOF.
|
||||
*
|
||||
*/
|
||||
static unsigned char *get_buffer(ev_io *watcher, int *ret_buffer_len) {
|
||||
int fd = watcher->fd;
|
||||
int n = 0;
|
||||
int rec = 0;
|
||||
int buffer_len = STDIN_CHUNK_SIZE;
|
||||
unsigned char *buffer = smalloc(buffer_len+1);
|
||||
unsigned char *buffer = smalloc(buffer_len + 1);
|
||||
buffer[0] = '\0';
|
||||
while(1) {
|
||||
while (1) {
|
||||
n = read(fd, buffer + rec, buffer_len - rec);
|
||||
if (n == -1) {
|
||||
if (errno == EAGAIN) {
|
||||
|
@ -291,9 +275,7 @@ static unsigned char *get_buffer(ev_io *watcher, int *ret_buffer_len) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (n == 0) {
|
||||
/* end of file, kill the watcher */
|
||||
ELOG("stdin: received EOF\n");
|
||||
cleanup();
|
||||
*ret_buffer_len = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -318,20 +300,17 @@ static void read_flat_input(char *buffer, int length) {
|
|||
I3STRING_FREE(first->full_text);
|
||||
/* Remove the trailing newline and terminate the string at the same
|
||||
* time. */
|
||||
if (buffer[length-1] == '\n' || buffer[length-1] == '\r')
|
||||
buffer[length-1] = '\0';
|
||||
else buffer[length] = '\0';
|
||||
if (buffer[length - 1] == '\n' || buffer[length - 1] == '\r')
|
||||
buffer[length - 1] = '\0';
|
||||
else
|
||||
buffer[length] = '\0';
|
||||
first->full_text = i3string_from_utf8(buffer);
|
||||
}
|
||||
|
||||
static bool read_json_input(unsigned char *input, int length) {
|
||||
yajl_status status = yajl_parse(parser, input, length);
|
||||
bool has_urgent = false;
|
||||
#if YAJL_MAJOR >= 2
|
||||
if (status != yajl_status_ok) {
|
||||
#else
|
||||
if (status != yajl_status_ok && status != yajl_status_insufficient_data) {
|
||||
#endif
|
||||
char *message = (char *)yajl_get_error(parser, 0, input, length);
|
||||
|
||||
/* strip the newline yajl adds to the error message */
|
||||
|
@ -342,7 +321,7 @@ static bool read_json_input(unsigned char *input, int length) {
|
|||
status, message, length, input);
|
||||
|
||||
set_statusline_error("Could not parse JSON (%s)", message);
|
||||
yajl_free_error(parser, (unsigned char*)message);
|
||||
yajl_free_error(parser, (unsigned char *)message);
|
||||
draw_bars(false);
|
||||
} else if (parser_context.has_urgent) {
|
||||
has_urgent = true;
|
||||
|
@ -364,7 +343,7 @@ void stdin_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
|||
if (child.version > 0) {
|
||||
has_urgent = read_json_input(buffer, rec);
|
||||
} else {
|
||||
read_flat_input((char*)buffer, rec);
|
||||
read_flat_input((char *)buffer, rec);
|
||||
}
|
||||
free(buffer);
|
||||
draw_bars(has_urgent);
|
||||
|
@ -398,7 +377,7 @@ void stdin_io_first_line_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
|||
* full_text pointer later. */
|
||||
struct status_block *new_block = scalloc(sizeof(struct status_block));
|
||||
TAILQ_INSERT_TAIL(&statusline_head, new_block, blocks);
|
||||
read_flat_input((char*)buffer, rec);
|
||||
read_flat_input((char *)buffer, rec);
|
||||
}
|
||||
free(buffer);
|
||||
ev_io_stop(main_loop, stdin_io);
|
||||
|
@ -416,15 +395,15 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) {
|
|||
int exit_status = WEXITSTATUS(watcher->rstatus);
|
||||
|
||||
ELOG("Child (pid: %d) unexpectedly exited with status %d\n",
|
||||
child.pid,
|
||||
exit_status);
|
||||
child.pid,
|
||||
exit_status);
|
||||
|
||||
/* this error is most likely caused by a user giving a nonexecutable or
|
||||
* nonexistent file, so we will handle those cases separately. */
|
||||
if (exit_status == 126)
|
||||
set_statusline_error("status_command is not executable (exit %d)", exit_status);
|
||||
else if (exit_status == 127)
|
||||
set_statusline_error("status_command not found (exit %d)", exit_status);
|
||||
set_statusline_error("status_command not found or is missing a library dependency (exit %d)", exit_status);
|
||||
else
|
||||
set_statusline_error("status_command process exited unexpectedly (exit %d)", exit_status);
|
||||
|
||||
|
@ -435,11 +414,8 @@ void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) {
|
|||
void child_write_output(void) {
|
||||
if (child.click_events) {
|
||||
const unsigned char *output;
|
||||
#if YAJL_MAJOR < 2
|
||||
unsigned int size;
|
||||
#else
|
||||
size_t size;
|
||||
#endif
|
||||
|
||||
yajl_gen_get_buf(gen, &output, &size);
|
||||
write(child_stdin, output, size);
|
||||
write(child_stdin, "\n", 1);
|
||||
|
@ -450,69 +426,66 @@ void child_write_output(void) {
|
|||
/*
|
||||
* Start a child-process with the specified command and reroute stdin.
|
||||
* We actually start a $SHELL to execute the command so we don't have to care
|
||||
* about arguments and such
|
||||
* about arguments and such.
|
||||
*
|
||||
* If `command' is NULL, such as in the case when no `status_command' is given
|
||||
* in the bar config, no child will be started.
|
||||
*
|
||||
*/
|
||||
void start_child(char *command) {
|
||||
if (command == NULL)
|
||||
return;
|
||||
|
||||
/* Allocate a yajl parser which will be used to parse stdin. */
|
||||
memset(&callbacks, '\0', sizeof(yajl_callbacks));
|
||||
callbacks.yajl_map_key = stdin_map_key;
|
||||
callbacks.yajl_boolean = stdin_boolean;
|
||||
callbacks.yajl_string = stdin_string;
|
||||
callbacks.yajl_integer = stdin_integer;
|
||||
callbacks.yajl_start_array = stdin_start_array;
|
||||
callbacks.yajl_end_array = stdin_end_array;
|
||||
callbacks.yajl_start_map = stdin_start_map;
|
||||
callbacks.yajl_end_map = stdin_end_map;
|
||||
#if YAJL_MAJOR < 2
|
||||
yajl_parser_config parse_conf = { 0, 0 };
|
||||
|
||||
parser = yajl_alloc(&callbacks, &parse_conf, NULL, (void*)&parser_context);
|
||||
|
||||
gen = yajl_gen_alloc(NULL, NULL);
|
||||
#else
|
||||
static yajl_callbacks callbacks = {
|
||||
.yajl_boolean = stdin_boolean,
|
||||
.yajl_integer = stdin_integer,
|
||||
.yajl_string = stdin_string,
|
||||
.yajl_start_map = stdin_start_map,
|
||||
.yajl_map_key = stdin_map_key,
|
||||
.yajl_end_map = stdin_end_map,
|
||||
.yajl_start_array = stdin_start_array,
|
||||
.yajl_end_array = stdin_end_array,
|
||||
};
|
||||
parser = yajl_alloc(&callbacks, NULL, &parser_context);
|
||||
|
||||
gen = yajl_gen_alloc(NULL);
|
||||
#endif
|
||||
|
||||
if (command != NULL) {
|
||||
int pipe_in[2]; /* pipe we read from */
|
||||
int pipe_out[2]; /* pipe we write to */
|
||||
int pipe_in[2]; /* pipe we read from */
|
||||
int pipe_out[2]; /* pipe we write to */
|
||||
|
||||
if (pipe(pipe_in) == -1)
|
||||
err(EXIT_FAILURE, "pipe(pipe_in)");
|
||||
if (pipe(pipe_out) == -1)
|
||||
err(EXIT_FAILURE, "pipe(pipe_out)");
|
||||
if (pipe(pipe_in) == -1)
|
||||
err(EXIT_FAILURE, "pipe(pipe_in)");
|
||||
if (pipe(pipe_out) == -1)
|
||||
err(EXIT_FAILURE, "pipe(pipe_out)");
|
||||
|
||||
child.pid = fork();
|
||||
switch (child.pid) {
|
||||
case -1:
|
||||
ELOG("Couldn't fork(): %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
case 0:
|
||||
/* Child-process. Reroute streams and start shell */
|
||||
child.pid = fork();
|
||||
switch (child.pid) {
|
||||
case -1:
|
||||
ELOG("Couldn't fork(): %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
case 0:
|
||||
/* Child-process. Reroute streams and start shell */
|
||||
|
||||
close(pipe_in[0]);
|
||||
close(pipe_out[1]);
|
||||
close(pipe_in[0]);
|
||||
close(pipe_out[1]);
|
||||
|
||||
dup2(pipe_in[1], STDOUT_FILENO);
|
||||
dup2(pipe_out[0], STDIN_FILENO);
|
||||
dup2(pipe_in[1], STDOUT_FILENO);
|
||||
dup2(pipe_out[0], STDIN_FILENO);
|
||||
|
||||
setpgid(child.pid, 0);
|
||||
execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, (char*) NULL);
|
||||
return;
|
||||
default:
|
||||
/* Parent-process. Reroute streams */
|
||||
setpgid(child.pid, 0);
|
||||
execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, (char *)NULL);
|
||||
return;
|
||||
default:
|
||||
/* Parent-process. Reroute streams */
|
||||
|
||||
close(pipe_in[1]);
|
||||
close(pipe_out[0]);
|
||||
close(pipe_in[1]);
|
||||
close(pipe_out[0]);
|
||||
|
||||
dup2(pipe_in[0], STDIN_FILENO);
|
||||
child_stdin = pipe_out[1];
|
||||
dup2(pipe_in[0], STDIN_FILENO);
|
||||
child_stdin = pipe_out[1];
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* We set O_NONBLOCK because blocking is evil in event-driven software */
|
||||
|
@ -625,3 +598,11 @@ void cont_child(void) {
|
|||
killpg(child.pid, child.cont_signal);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether or not the child want click events
|
||||
*
|
||||
*/
|
||||
bool child_want_click_events(void) {
|
||||
return child.click_events;
|
||||
}
|
||||
|
|
|
@ -27,15 +27,11 @@ static char *cur_key;
|
|||
* Essentially we just save it in cur_key.
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int config_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
|
||||
#else
|
||||
static int config_map_key_cb(void *params_, const unsigned char *keyVal, unsigned keyLen) {
|
||||
#endif
|
||||
FREE(cur_key);
|
||||
|
||||
cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1));
|
||||
strncpy(cur_key, (const char*) keyVal, keyLen);
|
||||
strncpy(cur_key, (const char *)keyVal, keyLen);
|
||||
cur_key[keyLen] = '\0';
|
||||
|
||||
return 1;
|
||||
|
@ -61,11 +57,7 @@ static int config_null_cb(void *params_) {
|
|||
* Parse a string
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int config_string_cb(void *params_, const unsigned char *val, size_t _len) {
|
||||
#else
|
||||
static int config_string_cb(void *params_, const unsigned char *val, unsigned int _len) {
|
||||
#endif
|
||||
int len = (int)_len;
|
||||
/* The id and socket_path are ignored, we already know them. */
|
||||
if (!strcmp(cur_key, "id") || !strcmp(cur_key, "socket_path"))
|
||||
|
@ -73,29 +65,29 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in
|
|||
|
||||
if (!strcmp(cur_key, "mode")) {
|
||||
DLOG("mode = %.*s, len = %d\n", len, val, len);
|
||||
config.hide_on_modifier = (len == 4 && !strncmp((const char*)val, "dock", strlen("dock")) ? M_DOCK
|
||||
: (len == 4 && !strncmp((const char*)val, "hide", strlen("hide")) ? M_HIDE
|
||||
: M_INVISIBLE));
|
||||
config.hide_on_modifier = (len == 4 && !strncmp((const char *)val, "dock", strlen("dock")) ? M_DOCK
|
||||
: (len == 4 && !strncmp((const char *)val, "hide", strlen("hide")) ? M_HIDE
|
||||
: M_INVISIBLE));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(cur_key, "hidden_state")) {
|
||||
DLOG("hidden_state = %.*s, len = %d\n", len, val, len);
|
||||
config.hidden_state = (len == 4 && !strncmp((const char*)val, "hide", strlen("hide")) ? S_HIDE : S_SHOW);
|
||||
config.hidden_state = (len == 4 && !strncmp((const char *)val, "hide", strlen("hide")) ? S_HIDE : S_SHOW);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(cur_key, "modifier")) {
|
||||
DLOG("modifier = %.*s\n", len, val);
|
||||
if (len == 5 && !strncmp((const char*)val, "shift", strlen("shift"))) {
|
||||
if (len == 5 && !strncmp((const char *)val, "shift", strlen("shift"))) {
|
||||
config.modifier = ShiftMask;
|
||||
return 1;
|
||||
}
|
||||
if (len == 4 && !strncmp((const char*)val, "ctrl", strlen("ctrl"))) {
|
||||
if (len == 4 && !strncmp((const char *)val, "ctrl", strlen("ctrl"))) {
|
||||
config.modifier = ControlMask;
|
||||
return 1;
|
||||
}
|
||||
if (len == 4 && !strncmp((const char*)val, "Mod", strlen("Mod"))) {
|
||||
if (len == 4 && !strncmp((const char *)val, "Mod", strlen("Mod"))) {
|
||||
switch (val[3]) {
|
||||
case '1':
|
||||
config.modifier = Mod1Mask;
|
||||
|
@ -122,15 +114,11 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in
|
|||
|
||||
if (!strcmp(cur_key, "position")) {
|
||||
DLOG("position = %.*s\n", len, val);
|
||||
config.position = (len == 3 && !strncmp((const char*)val, "top", strlen("top")) ? POS_TOP : POS_BOT);
|
||||
config.position = (len == 3 && !strncmp((const char *)val, "top", strlen("top")) ? POS_TOP : POS_BOT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(cur_key, "status_command")) {
|
||||
/* We cannot directly start the child here, because start_child() also
|
||||
* needs to be run when no command was specified (to setup stdin).
|
||||
* Therefore we save the command in 'config' and access it later in
|
||||
* got_bar_config() */
|
||||
DLOG("command = %.*s\n", len, val);
|
||||
sasprintf(&config.command, "%.*s", len, val);
|
||||
return 1;
|
||||
|
@ -145,7 +133,7 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in
|
|||
if (!strcmp(cur_key, "outputs")) {
|
||||
DLOG("+output %.*s\n", len, val);
|
||||
int new_num_outputs = config.num_outputs + 1;
|
||||
config.outputs = srealloc(config.outputs, sizeof(char*) * new_num_outputs);
|
||||
config.outputs = srealloc(config.outputs, sizeof(char *) * new_num_outputs);
|
||||
sasprintf(&config.outputs[config.num_outputs], "%.*s", len, val);
|
||||
config.num_outputs = new_num_outputs;
|
||||
return 1;
|
||||
|
@ -158,13 +146,13 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in
|
|||
return 1;
|
||||
}
|
||||
|
||||
#define COLOR(json_name, struct_name) \
|
||||
do { \
|
||||
if (!strcmp(cur_key, #json_name)) { \
|
||||
#define COLOR(json_name, struct_name) \
|
||||
do { \
|
||||
if (!strcmp(cur_key, #json_name)) { \
|
||||
DLOG(#json_name " = " #struct_name " = %.*s\n", len, val); \
|
||||
sasprintf(&(config.colors.struct_name), "%.*s", len, val); \
|
||||
return 1; \
|
||||
} \
|
||||
return 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
COLOR(statusline, bar_fg);
|
||||
|
@ -205,6 +193,12 @@ static int config_boolean_cb(void *params_, int val) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(cur_key, "strip_workspace_numbers")) {
|
||||
DLOG("strip_workspace_numbers = %d\n", val);
|
||||
config.strip_ws_numbers = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(cur_key, "verbose")) {
|
||||
DLOG("verbose = %d\n", val);
|
||||
config.verbose = val;
|
||||
|
@ -216,17 +210,10 @@ static int config_boolean_cb(void *params_, int val) {
|
|||
|
||||
/* A datastructure to pass all these callbacks to yajl */
|
||||
static yajl_callbacks outputs_callbacks = {
|
||||
&config_null_cb,
|
||||
&config_boolean_cb,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&config_string_cb,
|
||||
NULL,
|
||||
&config_map_key_cb,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
.yajl_null = config_null_cb,
|
||||
.yajl_boolean = config_boolean_cb,
|
||||
.yajl_string = config_string_cb,
|
||||
.yajl_map_key = config_map_key_cb,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -236,24 +223,15 @@ static yajl_callbacks outputs_callbacks = {
|
|||
void parse_config_json(char *json) {
|
||||
yajl_handle handle;
|
||||
yajl_status state;
|
||||
#if YAJL_MAJOR < 2
|
||||
yajl_parser_config parse_conf = { 0, 0 };
|
||||
|
||||
handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, NULL);
|
||||
#else
|
||||
handle = yajl_alloc(&outputs_callbacks, NULL, NULL);
|
||||
#endif
|
||||
|
||||
state = yajl_parse(handle, (const unsigned char*) json, strlen(json));
|
||||
state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
|
||||
|
||||
/* FIXME: Proper errorhandling for JSON-parsing */
|
||||
switch (state) {
|
||||
case yajl_status_ok:
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
#if YAJL_MAJOR < 2
|
||||
case yajl_status_insufficient_data:
|
||||
#endif
|
||||
case yajl_status_error:
|
||||
ELOG("Could not parse config-reply!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -268,9 +246,9 @@ void parse_config_json(char *json) {
|
|||
*
|
||||
*/
|
||||
void free_colors(struct xcb_color_strings_t *colors) {
|
||||
#define FREE_COLOR(x) \
|
||||
do { \
|
||||
if (colors->x) \
|
||||
#define FREE_COLOR(x) \
|
||||
do { \
|
||||
if (colors->x) \
|
||||
free(colors->x); \
|
||||
} while (0)
|
||||
FREE_COLOR(bar_fg);
|
||||
|
@ -290,4 +268,3 @@ void free_colors(struct xcb_color_strings_t *colors) {
|
|||
FREE_COLOR(focus_ws_border);
|
||||
#undef FREE_COLOR
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
ev_io *i3_connection;
|
||||
ev_io *i3_connection;
|
||||
|
||||
const char *sock_path;
|
||||
|
||||
typedef void(*handler_t)(char*);
|
||||
typedef void (*handler_t)(char *);
|
||||
|
||||
/*
|
||||
* Called, when we get a reply to a command from i3.
|
||||
|
@ -67,7 +67,7 @@ void got_output_reply(char *reply) {
|
|||
reconfig_windows(false);
|
||||
|
||||
i3_output *o_walk;
|
||||
SLIST_FOREACH(o_walk, outputs, slist) {
|
||||
SLIST_FOREACH (o_walk, outputs, slist) {
|
||||
kick_tray_clients(o_walk);
|
||||
}
|
||||
|
||||
|
@ -100,9 +100,6 @@ void got_bar_config(char *reply) {
|
|||
/* Resolve color strings to colorpixels and save them, then free the strings. */
|
||||
init_colors(&(config.colors));
|
||||
|
||||
/* The name of this function is actually misleading. Even if no command is
|
||||
* specified, this function initiates the watchers to listen on stdin and
|
||||
* react accordingly */
|
||||
start_child(config.command);
|
||||
FREE(config.command);
|
||||
}
|
||||
|
@ -160,16 +157,21 @@ void got_bar_config_update(char *event) {
|
|||
char *found_id = strstr(event, expected_id);
|
||||
FREE(expected_id);
|
||||
if (found_id == NULL)
|
||||
return;
|
||||
return;
|
||||
|
||||
free_colors(&(config.colors));
|
||||
|
||||
/* update the configuration with the received settings */
|
||||
DLOG("Received bar config update \"%s\"\n", event);
|
||||
int old_mode = config.hide_on_modifier;
|
||||
bar_display_mode_t old_mode = config.hide_on_modifier;
|
||||
parse_config_json(event);
|
||||
if (old_mode != config.hide_on_modifier) {
|
||||
reconfig_windows(true);
|
||||
}
|
||||
|
||||
init_colors(&(config.colors));
|
||||
realloc_sl_buffer();
|
||||
|
||||
draw_bars(false);
|
||||
}
|
||||
|
||||
|
@ -191,7 +193,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
|
|||
int fd = watcher->fd;
|
||||
|
||||
/* First we only read the header, because we know its length */
|
||||
uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t)*2;
|
||||
uint32_t header_len = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) * 2;
|
||||
char *header = smalloc(header_len);
|
||||
|
||||
/* We first parse the fixed-length IPC-header, to know, how much data
|
||||
|
@ -215,7 +217,7 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
|
|||
|
||||
if (strncmp(header, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC))) {
|
||||
ELOG("Wrong magic code: %.*s\n Expected: %s\n",
|
||||
(int) strlen(I3_IPC_MAGIC),
|
||||
(int)strlen(I3_IPC_MAGIC),
|
||||
header,
|
||||
I3_IPC_MAGIC);
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -223,10 +225,10 @@ void got_data(struct ev_loop *loop, ev_io *watcher, int events) {
|
|||
|
||||
char *walk = header + strlen(I3_IPC_MAGIC);
|
||||
uint32_t size;
|
||||
memcpy(&size, (uint32_t*)walk, sizeof(uint32_t));
|
||||
memcpy(&size, (uint32_t *)walk, sizeof(uint32_t));
|
||||
walk += sizeof(uint32_t);
|
||||
uint32_t type;
|
||||
memcpy(&type, (uint32_t*)walk, sizeof(uint32_t));
|
||||
memcpy(&type, (uint32_t *)walk, sizeof(uint32_t));
|
||||
|
||||
/* Now that we know, what to expect, we can start read()ing the rest
|
||||
* of the message */
|
||||
|
@ -272,7 +274,7 @@ int i3_send_msg(uint32_t type, const char *payload) {
|
|||
}
|
||||
|
||||
/* We are a wellbehaved client and send a proper header first */
|
||||
uint32_t to_write = strlen (I3_IPC_MAGIC) + sizeof(uint32_t)*2 + len;
|
||||
uint32_t to_write = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) * 2 + len;
|
||||
/* TODO: I'm not entirely sure if this buffer really has to contain more
|
||||
* than the pure header (why not just write() the payload from *payload?),
|
||||
* but we leave it for now */
|
||||
|
|
|
@ -99,12 +99,11 @@ int main(int argc, char **argv) {
|
|||
memset(&config, '\0', sizeof(config_t));
|
||||
|
||||
static struct option long_opt[] = {
|
||||
{ "socket", required_argument, 0, 's' },
|
||||
{ "bar_id", required_argument, 0, 'b' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ "version", no_argument, 0, 'v' },
|
||||
{ NULL, 0, 0, 0}
|
||||
};
|
||||
{"socket", required_argument, 0, 's'},
|
||||
{"bar_id", required_argument, 0, 'b'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{NULL, 0, 0, 0}};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "b:s:hv", long_opt, &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
|
@ -112,7 +111,7 @@ int main(int argc, char **argv) {
|
|||
socket_path = expand_path(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
printf("i3bar version " I3_VERSION " © 2010-2011 Axel Wagner and contributors\n");
|
||||
printf("i3bar version " I3_VERSION " © 2010-2014 Axel Wagner and contributors\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'b':
|
||||
|
|
|
@ -18,36 +18,31 @@
|
|||
|
||||
/* A datatype to pass through the callbacks to save the state */
|
||||
struct mode_json_params {
|
||||
char *json;
|
||||
char *cur_key;
|
||||
mode *mode;
|
||||
char *json;
|
||||
char *cur_key;
|
||||
mode *mode;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse a string (change)
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int mode_string_cb(void *params_, const unsigned char *val, size_t len) {
|
||||
#else
|
||||
static int mode_string_cb(void *params_, const unsigned char *val, unsigned int len) {
|
||||
#endif
|
||||
struct mode_json_params *params = (struct mode_json_params*) params_;
|
||||
struct mode_json_params *params = (struct mode_json_params *)params_;
|
||||
|
||||
if (!strcmp(params->cur_key, "change")) {
|
||||
if (!strcmp(params->cur_key, "change")) {
|
||||
/* Save the name */
|
||||
params->mode->name = i3string_from_utf8_with_length((const char *)val, len);
|
||||
/* Save its rendered width */
|
||||
params->mode->width = predict_text_width(params->mode->name);
|
||||
|
||||
/* Save the name */
|
||||
params->mode->name = i3string_from_utf8_with_length((const char *)val, len);
|
||||
/* Save its rendered width */
|
||||
params->mode->width = predict_text_width(params->mode->name);
|
||||
DLOG("Got mode change: %s\n", i3string_as_utf8(params->mode->name));
|
||||
FREE(params->cur_key);
|
||||
|
||||
DLOG("Got mode change: %s\n", i3string_as_utf8(params->mode->name));
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -56,34 +51,21 @@ static int mode_string_cb(void *params_, const unsigned char *val, unsigned int
|
|||
* Essentially we just save it in the parsing-state
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int mode_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
|
||||
#else
|
||||
static int mode_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) {
|
||||
#endif
|
||||
struct mode_json_params *params = (struct mode_json_params*) params_;
|
||||
struct mode_json_params *params = (struct mode_json_params *)params_;
|
||||
FREE(params->cur_key);
|
||||
|
||||
params->cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1));
|
||||
strncpy(params->cur_key, (const char*) keyVal, keyLen);
|
||||
strncpy(params->cur_key, (const char *)keyVal, keyLen);
|
||||
params->cur_key[keyLen] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A datastructure to pass all these callbacks to yajl */
|
||||
yajl_callbacks mode_callbacks = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&mode_string_cb,
|
||||
NULL,
|
||||
&mode_map_key_cb,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
static yajl_callbacks mode_callbacks = {
|
||||
.yajl_string = mode_string_cb,
|
||||
.yajl_map_key = mode_map_key_cb,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -104,24 +86,15 @@ void parse_mode_json(char *json) {
|
|||
yajl_handle handle;
|
||||
yajl_status state;
|
||||
|
||||
#if YAJL_MAJOR < 2
|
||||
yajl_parser_config parse_conf = { 0, 0 };
|
||||
handle = yajl_alloc(&mode_callbacks, NULL, (void *)¶ms);
|
||||
|
||||
handle = yajl_alloc(&mode_callbacks, &parse_conf, NULL, (void*) ¶ms);
|
||||
#else
|
||||
handle = yajl_alloc(&mode_callbacks, NULL, (void*) ¶ms);
|
||||
#endif
|
||||
|
||||
state = yajl_parse(handle, (const unsigned char*) json, strlen(json));
|
||||
state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
|
||||
|
||||
/* FIXME: Propper errorhandling for JSON-parsing */
|
||||
switch (state) {
|
||||
case yajl_status_ok:
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
#if YAJL_MAJOR < 2
|
||||
case yajl_status_insufficient_data:
|
||||
#endif
|
||||
case yajl_status_error:
|
||||
ELOG("Could not parse mode-event!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
/* A datatype to pass through the callbacks to save the state */
|
||||
struct outputs_json_params {
|
||||
struct outputs_head *outputs;
|
||||
i3_output *outputs_walk;
|
||||
char *cur_key;
|
||||
char *json;
|
||||
bool in_rect;
|
||||
i3_output *outputs_walk;
|
||||
char *cur_key;
|
||||
char *json;
|
||||
bool in_rect;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -31,7 +31,7 @@ struct outputs_json_params {
|
|||
*
|
||||
*/
|
||||
static int outputs_null_cb(void *params_) {
|
||||
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
||||
struct outputs_json_params *params = (struct outputs_json_params *)params_;
|
||||
|
||||
FREE(params->cur_key);
|
||||
|
||||
|
@ -43,7 +43,7 @@ static int outputs_null_cb(void *params_) {
|
|||
*
|
||||
*/
|
||||
static int outputs_boolean_cb(void *params_, int val) {
|
||||
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
||||
struct outputs_json_params *params = (struct outputs_json_params *)params_;
|
||||
|
||||
if (!strcmp(params->cur_key, "active")) {
|
||||
params->outputs_walk->active = val;
|
||||
|
@ -64,39 +64,35 @@ static int outputs_boolean_cb(void *params_, int val) {
|
|||
* Parse an integer (current_workspace or the rect)
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int outputs_integer_cb(void *params_, long long val) {
|
||||
#else
|
||||
static int outputs_integer_cb(void *params_, long val) {
|
||||
#endif
|
||||
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
||||
struct outputs_json_params *params = (struct outputs_json_params *)params_;
|
||||
|
||||
if (!strcmp(params->cur_key, "current_workspace")) {
|
||||
params->outputs_walk->ws = (int) val;
|
||||
params->outputs_walk->ws = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "x")) {
|
||||
params->outputs_walk->rect.x = (int) val;
|
||||
params->outputs_walk->rect.x = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "y")) {
|
||||
params->outputs_walk->rect.y = (int) val;
|
||||
params->outputs_walk->rect.y = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "width")) {
|
||||
params->outputs_walk->rect.w = (int) val;
|
||||
params->outputs_walk->rect.w = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "height")) {
|
||||
params->outputs_walk->rect.h = (int) val;
|
||||
params->outputs_walk->rect.h = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
@ -108,16 +104,12 @@ static int outputs_integer_cb(void *params_, long val) {
|
|||
* Parse a string (name)
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int outputs_string_cb(void *params_, const unsigned char *val, size_t len) {
|
||||
#else
|
||||
static int outputs_string_cb(void *params_, const unsigned char *val, unsigned int len) {
|
||||
#endif
|
||||
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
||||
struct outputs_json_params *params = (struct outputs_json_params *)params_;
|
||||
|
||||
if (!strcmp(params->cur_key, "current_workspace")) {
|
||||
char *copy = smalloc(sizeof(const unsigned char) * (len + 1));
|
||||
strncpy(copy, (const char*) val, len);
|
||||
strncpy(copy, (const char *)val, len);
|
||||
copy[len] = '\0';
|
||||
|
||||
char *end;
|
||||
|
@ -136,7 +128,7 @@ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned i
|
|||
}
|
||||
|
||||
char *name = smalloc(sizeof(const unsigned char) * (len + 1));
|
||||
strncpy(name, (const char*) val, len);
|
||||
strncpy(name, (const char *)val, len);
|
||||
name[len] = '\0';
|
||||
|
||||
params->outputs_walk->name = name;
|
||||
|
@ -151,7 +143,7 @@ static int outputs_string_cb(void *params_, const unsigned char *val, unsigned i
|
|||
*
|
||||
*/
|
||||
static int outputs_start_map_cb(void *params_) {
|
||||
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
||||
struct outputs_json_params *params = (struct outputs_json_params *)params_;
|
||||
i3_output *new_output = NULL;
|
||||
|
||||
if (params->cur_key == NULL) {
|
||||
|
@ -184,7 +176,7 @@ static int outputs_start_map_cb(void *params_) {
|
|||
*
|
||||
*/
|
||||
static int outputs_end_map_cb(void *params_) {
|
||||
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
||||
struct outputs_json_params *params = (struct outputs_json_params *)params_;
|
||||
if (params->in_rect) {
|
||||
params->in_rect = false;
|
||||
/* Ignore the end of a rect */
|
||||
|
@ -232,34 +224,26 @@ static int outputs_end_map_cb(void *params_) {
|
|||
* Essentially we just save it in the parsing-state
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
|
||||
#else
|
||||
static int outputs_map_key_cb(void *params_, const unsigned char *keyVal, unsigned keyLen) {
|
||||
#endif
|
||||
struct outputs_json_params *params = (struct outputs_json_params*) params_;
|
||||
struct outputs_json_params *params = (struct outputs_json_params *)params_;
|
||||
FREE(params->cur_key);
|
||||
|
||||
params->cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1));
|
||||
strncpy(params->cur_key, (const char*) keyVal, keyLen);
|
||||
strncpy(params->cur_key, (const char *)keyVal, keyLen);
|
||||
params->cur_key[keyLen] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A datastructure to pass all these callbacks to yajl */
|
||||
yajl_callbacks outputs_callbacks = {
|
||||
&outputs_null_cb,
|
||||
&outputs_boolean_cb,
|
||||
&outputs_integer_cb,
|
||||
NULL,
|
||||
NULL,
|
||||
&outputs_string_cb,
|
||||
&outputs_start_map_cb,
|
||||
&outputs_map_key_cb,
|
||||
&outputs_end_map_cb,
|
||||
NULL,
|
||||
NULL
|
||||
static yajl_callbacks outputs_callbacks = {
|
||||
.yajl_null = outputs_null_cb,
|
||||
.yajl_boolean = outputs_boolean_cb,
|
||||
.yajl_integer = outputs_integer_cb,
|
||||
.yajl_string = outputs_string_cb,
|
||||
.yajl_start_map = outputs_start_map_cb,
|
||||
.yajl_map_key = outputs_map_key_cb,
|
||||
.yajl_end_map = outputs_end_map_cb,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -285,24 +269,15 @@ void parse_outputs_json(char *json) {
|
|||
|
||||
yajl_handle handle;
|
||||
yajl_status state;
|
||||
#if YAJL_MAJOR < 2
|
||||
yajl_parser_config parse_conf = { 0, 0 };
|
||||
handle = yajl_alloc(&outputs_callbacks, NULL, (void *)¶ms);
|
||||
|
||||
handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) ¶ms);
|
||||
#else
|
||||
handle = yajl_alloc(&outputs_callbacks, NULL, (void*) ¶ms);
|
||||
#endif
|
||||
|
||||
state = yajl_parse(handle, (const unsigned char*) json, strlen(json));
|
||||
state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
|
||||
|
||||
/* FIXME: Propper errorhandling for JSON-parsing */
|
||||
switch (state) {
|
||||
case yajl_status_ok:
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
#if YAJL_MAJOR < 2
|
||||
case yajl_status_insufficient_data:
|
||||
#endif
|
||||
case yajl_status_error:
|
||||
ELOG("Could not parse outputs-reply!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -321,7 +296,7 @@ i3_output *get_output_by_name(char *name) {
|
|||
if (name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (!strcmp(walk->name, name)) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -35,11 +35,7 @@ static enum {
|
|||
NO_KEY
|
||||
} current_key;
|
||||
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int header_integer(void *ctx, long long val) {
|
||||
#else
|
||||
static int header_integer(void *ctx, long val) {
|
||||
#endif
|
||||
i3bar_child *child = ctx;
|
||||
|
||||
switch (current_key) {
|
||||
|
@ -74,13 +70,9 @@ static int header_boolean(void *ctx, int val) {
|
|||
}
|
||||
|
||||
#define CHECK_KEY(name) (stringlen == strlen(name) && \
|
||||
STARTS_WITH((const char*)stringval, stringlen, name))
|
||||
STARTS_WITH((const char *)stringval, stringlen, name))
|
||||
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int header_map_key(void *ctx, const unsigned char *stringval, size_t stringlen) {
|
||||
#else
|
||||
static int header_map_key(void *ctx, const unsigned char *stringval, unsigned int stringlen) {
|
||||
#endif
|
||||
if (CHECK_KEY("version")) {
|
||||
current_key = KEY_VERSION;
|
||||
} else if (CHECK_KEY("stop_signal")) {
|
||||
|
@ -93,20 +85,6 @@ static int header_map_key(void *ctx, const unsigned char *stringval, unsigned in
|
|||
return 1;
|
||||
}
|
||||
|
||||
static yajl_callbacks version_callbacks = {
|
||||
NULL, /* null */
|
||||
&header_boolean, /* boolean */
|
||||
&header_integer,
|
||||
NULL, /* double */
|
||||
NULL, /* number */
|
||||
NULL, /* string */
|
||||
NULL, /* start_map */
|
||||
&header_map_key,
|
||||
NULL, /* end_map */
|
||||
NULL, /* start_array */
|
||||
NULL /* end_array */
|
||||
};
|
||||
|
||||
static void child_init(i3bar_child *child) {
|
||||
child->version = 0;
|
||||
child->stop_signal = SIGSTOP;
|
||||
|
@ -122,20 +100,20 @@ static void child_init(i3bar_child *child) {
|
|||
*
|
||||
*/
|
||||
void parse_json_header(i3bar_child *child, const unsigned char *buffer, int length, unsigned int *consumed) {
|
||||
static yajl_callbacks version_callbacks = {
|
||||
.yajl_boolean = header_boolean,
|
||||
.yajl_integer = header_integer,
|
||||
.yajl_map_key = &header_map_key,
|
||||
};
|
||||
|
||||
child_init(child);
|
||||
|
||||
current_key = NO_KEY;
|
||||
|
||||
#if YAJL_MAJOR >= 2
|
||||
yajl_handle handle = yajl_alloc(&version_callbacks, NULL, child);
|
||||
/* Allow trailing garbage. yajl 1 always behaves that way anyways, but for
|
||||
* yajl 2, we need to be explicit. */
|
||||
yajl_config(handle, yajl_allow_trailing_garbage, 1);
|
||||
#else
|
||||
yajl_parser_config parse_conf = { 0, 0 };
|
||||
|
||||
yajl_handle handle = yajl_alloc(&version_callbacks, &parse_conf, NULL, child);
|
||||
#endif
|
||||
|
||||
yajl_status state = yajl_parse(handle, buffer, length);
|
||||
if (state != yajl_status_ok) {
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
/* A datatype to pass through the callbacks to save the state */
|
||||
struct workspaces_json_params {
|
||||
struct ws_head *workspaces;
|
||||
i3_ws *workspaces_walk;
|
||||
char *cur_key;
|
||||
char *json;
|
||||
i3_ws *workspaces_walk;
|
||||
char *cur_key;
|
||||
char *json;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -29,7 +29,7 @@ struct workspaces_json_params {
|
|||
*
|
||||
*/
|
||||
static int workspaces_boolean_cb(void *params_, int val) {
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params *)params_;
|
||||
|
||||
if (!strcmp(params->cur_key, "visible")) {
|
||||
params->workspaces_walk->visible = val;
|
||||
|
@ -58,39 +58,35 @@ static int workspaces_boolean_cb(void *params_, int val) {
|
|||
* Parse an integer (num or the rect)
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int workspaces_integer_cb(void *params_, long long val) {
|
||||
#else
|
||||
static int workspaces_integer_cb(void *params_, long val) {
|
||||
#endif
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params *)params_;
|
||||
|
||||
if (!strcmp(params->cur_key, "num")) {
|
||||
params->workspaces_walk->num = (int) val;
|
||||
params->workspaces_walk->num = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "x")) {
|
||||
params->workspaces_walk->rect.x = (int) val;
|
||||
params->workspaces_walk->rect.x = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "y")) {
|
||||
params->workspaces_walk->rect.y = (int) val;
|
||||
params->workspaces_walk->rect.y = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "width")) {
|
||||
params->workspaces_walk->rect.w = (int) val;
|
||||
params->workspaces_walk->rect.w = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "height")) {
|
||||
params->workspaces_walk->rect.h = (int) val;
|
||||
params->workspaces_walk->rect.h = (int)val;
|
||||
FREE(params->cur_key);
|
||||
return 1;
|
||||
}
|
||||
|
@ -103,51 +99,71 @@ static int workspaces_integer_cb(void *params_, long val) {
|
|||
* Parse a string (name, output)
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int workspaces_string_cb(void *params_, const unsigned char *val, size_t len) {
|
||||
#else
|
||||
static int workspaces_string_cb(void *params_, const unsigned char *val, unsigned int len) {
|
||||
#endif
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params *)params_;
|
||||
|
||||
char *output_name;
|
||||
char *output_name;
|
||||
|
||||
if (!strcmp(params->cur_key, "name")) {
|
||||
/* Save the name */
|
||||
params->workspaces_walk->name = i3string_from_utf8_with_length((const char *)val, len);
|
||||
if (!strcmp(params->cur_key, "name")) {
|
||||
const char *ws_name = (const char *)val;
|
||||
params->workspaces_walk->canonical_name = strndup(ws_name, len);
|
||||
|
||||
/* Save its rendered width */
|
||||
params->workspaces_walk->name_width =
|
||||
predict_text_width(params->workspaces_walk->name);
|
||||
if (config.strip_ws_numbers && params->workspaces_walk->num >= 0) {
|
||||
/* Special case: strip off the workspace number */
|
||||
static char ws_num[10];
|
||||
|
||||
DLOG("Got Workspace %s, name_width: %d, glyphs: %zu\n",
|
||||
i3string_as_utf8(params->workspaces_walk->name),
|
||||
params->workspaces_walk->name_width,
|
||||
i3string_get_num_glyphs(params->workspaces_walk->name));
|
||||
FREE(params->cur_key);
|
||||
snprintf(ws_num, sizeof(ws_num), "%d", params->workspaces_walk->num);
|
||||
|
||||
return 1;
|
||||
/* Calculate the length of the number str in the name */
|
||||
size_t offset = strspn(ws_name, ws_num);
|
||||
|
||||
/* Also strip off the conventional ws name delimiter */
|
||||
if (offset && ws_name[offset] == ':')
|
||||
offset += 1;
|
||||
|
||||
/* Offset may be equal to length, in which case display the number */
|
||||
params->workspaces_walk->name = (offset < len
|
||||
? i3string_from_utf8_with_length(ws_name + offset, len - offset)
|
||||
: i3string_from_utf8(ws_num));
|
||||
|
||||
} else {
|
||||
/* Default case: just save the name */
|
||||
params->workspaces_walk->name = i3string_from_utf8_with_length(ws_name, len);
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "output")) {
|
||||
/* We add the ws to the TAILQ of the output, it belongs to */
|
||||
output_name = smalloc(sizeof(const unsigned char) * (len + 1));
|
||||
strncpy(output_name, (const char*) val, len);
|
||||
output_name[len] = '\0';
|
||||
i3_output *target = get_output_by_name(output_name);
|
||||
if (target) {
|
||||
params->workspaces_walk->output = target;
|
||||
/* Save its rendered width */
|
||||
params->workspaces_walk->name_width =
|
||||
predict_text_width(params->workspaces_walk->name);
|
||||
|
||||
TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces,
|
||||
params->workspaces_walk,
|
||||
tailq);
|
||||
}
|
||||
DLOG("Got Workspace canonical: %s, name: '%s', name_width: %d, glyphs: %zu\n",
|
||||
params->workspaces_walk->canonical_name,
|
||||
i3string_as_utf8(params->workspaces_walk->name),
|
||||
params->workspaces_walk->name_width,
|
||||
i3string_get_num_glyphs(params->workspaces_walk->name));
|
||||
FREE(params->cur_key);
|
||||
|
||||
FREE(output_name);
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(params->cur_key, "output")) {
|
||||
/* We add the ws to the TAILQ of the output, it belongs to */
|
||||
output_name = smalloc(sizeof(const unsigned char) * (len + 1));
|
||||
strncpy(output_name, (const char *)val, len);
|
||||
output_name[len] = '\0';
|
||||
i3_output *target = get_output_by_name(output_name);
|
||||
if (target) {
|
||||
params->workspaces_walk->output = target;
|
||||
|
||||
TAILQ_INSERT_TAIL(params->workspaces_walk->output->workspaces,
|
||||
params->workspaces_walk,
|
||||
tailq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
FREE(output_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -155,7 +171,7 @@ static int workspaces_string_cb(void *params_, const unsigned char *val, unsigne
|
|||
*
|
||||
*/
|
||||
static int workspaces_start_map_cb(void *params_) {
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params *)params_;
|
||||
|
||||
i3_ws *new_workspace = NULL;
|
||||
|
||||
|
@ -182,34 +198,24 @@ static int workspaces_start_map_cb(void *params_) {
|
|||
* Essentially we just save it in the parsing-state
|
||||
*
|
||||
*/
|
||||
#if YAJL_MAJOR >= 2
|
||||
static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, size_t keyLen) {
|
||||
#else
|
||||
static int workspaces_map_key_cb(void *params_, const unsigned char *keyVal, unsigned int keyLen) {
|
||||
#endif
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params*) params_;
|
||||
struct workspaces_json_params *params = (struct workspaces_json_params *)params_;
|
||||
FREE(params->cur_key);
|
||||
|
||||
params->cur_key = smalloc(sizeof(unsigned char) * (keyLen + 1));
|
||||
strncpy(params->cur_key, (const char*) keyVal, keyLen);
|
||||
strncpy(params->cur_key, (const char *)keyVal, keyLen);
|
||||
params->cur_key[keyLen] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A datastructure to pass all these callbacks to yajl */
|
||||
yajl_callbacks workspaces_callbacks = {
|
||||
NULL,
|
||||
&workspaces_boolean_cb,
|
||||
&workspaces_integer_cb,
|
||||
NULL,
|
||||
NULL,
|
||||
&workspaces_string_cb,
|
||||
&workspaces_start_map_cb,
|
||||
&workspaces_map_key_cb,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
static yajl_callbacks workspaces_callbacks = {
|
||||
.yajl_boolean = workspaces_boolean_cb,
|
||||
.yajl_integer = workspaces_integer_cb,
|
||||
.yajl_string = workspaces_string_cb,
|
||||
.yajl_start_map = workspaces_start_map_cb,
|
||||
.yajl_map_key = workspaces_map_key_cb,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -229,24 +235,15 @@ void parse_workspaces_json(char *json) {
|
|||
|
||||
yajl_handle handle;
|
||||
yajl_status state;
|
||||
#if YAJL_MAJOR < 2
|
||||
yajl_parser_config parse_conf = { 0, 0 };
|
||||
handle = yajl_alloc(&workspaces_callbacks, NULL, (void *)¶ms);
|
||||
|
||||
handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) ¶ms);
|
||||
#else
|
||||
handle = yajl_alloc(&workspaces_callbacks, NULL, (void*) ¶ms);
|
||||
#endif
|
||||
|
||||
state = yajl_parse(handle, (const unsigned char*) json, strlen(json));
|
||||
state = yajl_parse(handle, (const unsigned char *)json, strlen(json));
|
||||
|
||||
/* FIXME: Propper errorhandling for JSON-parsing */
|
||||
switch (state) {
|
||||
case yajl_status_ok:
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
#if YAJL_MAJOR < 2
|
||||
case yajl_status_insufficient_data:
|
||||
#endif
|
||||
case yajl_status_error:
|
||||
ELOG("Could not parse workspaces-reply!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -267,12 +264,13 @@ void free_workspaces(void) {
|
|||
if (outputs == NULL) {
|
||||
return;
|
||||
}
|
||||
i3_ws *ws_walk;
|
||||
i3_ws *ws_walk;
|
||||
|
||||
SLIST_FOREACH(outputs_walk, outputs, slist) {
|
||||
SLIST_FOREACH (outputs_walk, outputs, slist) {
|
||||
if (outputs_walk->workspaces != NULL && !TAILQ_EMPTY(outputs_walk->workspaces)) {
|
||||
TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
|
||||
TAILQ_FOREACH (ws_walk, outputs_walk->workspaces, tailq) {
|
||||
I3STRING_FREE(ws_walk->name);
|
||||
FREE(ws_walk->canonical_name);
|
||||
}
|
||||
FREE_TAILQ(outputs_walk->workspaces, i3_ws);
|
||||
}
|
||||
|
|
406
i3bar/src/xcb.c
406
i3bar/src/xcb.c
|
@ -35,19 +35,19 @@
|
|||
|
||||
/* We save the Atoms in an easy to access array, indexed by an enum */
|
||||
enum {
|
||||
#define ATOM_DO(name) name,
|
||||
#include "xcb_atoms.def"
|
||||
#define ATOM_DO(name) name,
|
||||
#include "xcb_atoms.def"
|
||||
NUM_ATOMS
|
||||
};
|
||||
|
||||
xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS];
|
||||
xcb_atom_t atoms[NUM_ATOMS];
|
||||
xcb_atom_t atoms[NUM_ATOMS];
|
||||
|
||||
/* Variables, that are the same for all functions at all times */
|
||||
xcb_connection_t *xcb_connection;
|
||||
int screen;
|
||||
xcb_screen_t *root_screen;
|
||||
xcb_window_t xcb_root;
|
||||
int screen;
|
||||
xcb_screen_t *root_screen;
|
||||
xcb_window_t xcb_root;
|
||||
|
||||
/* selection window for tray support */
|
||||
static xcb_window_t selwin = XCB_NONE;
|
||||
|
@ -63,22 +63,22 @@ static i3Font font;
|
|||
int bar_height;
|
||||
|
||||
/* These are only relevant for XKB, which we only need for grabbing modifiers */
|
||||
Display *xkb_dpy;
|
||||
int xkb_event_base;
|
||||
int mod_pressed = 0;
|
||||
Display *xkb_dpy;
|
||||
int xkb_event_base;
|
||||
int mod_pressed = 0;
|
||||
|
||||
/* Because the statusline is the same on all outputs, we have
|
||||
* global buffer to render it on */
|
||||
xcb_gcontext_t statusline_ctx;
|
||||
xcb_gcontext_t statusline_clear;
|
||||
xcb_pixmap_t statusline_pm;
|
||||
uint32_t statusline_width;
|
||||
xcb_gcontext_t statusline_ctx;
|
||||
xcb_gcontext_t statusline_clear;
|
||||
xcb_pixmap_t statusline_pm;
|
||||
uint32_t statusline_width;
|
||||
|
||||
/* Event-Watchers, to interact with the user */
|
||||
ev_prepare *xcb_prep;
|
||||
ev_check *xcb_chk;
|
||||
ev_io *xcb_io;
|
||||
ev_io *xkb_io;
|
||||
ev_check *xcb_chk;
|
||||
ev_io *xcb_io;
|
||||
ev_io *xkb_io;
|
||||
|
||||
/* The name of current binding mode */
|
||||
static mode binding;
|
||||
|
@ -128,7 +128,7 @@ void refresh_statusline(void) {
|
|||
statusline_width = 0;
|
||||
|
||||
/* Predict the text width of all blocks (in pixels). */
|
||||
TAILQ_FOREACH(block, &statusline_head, blocks) {
|
||||
TAILQ_FOREACH (block, &statusline_head, blocks) {
|
||||
if (i3string_get_num_bytes(block->full_text) == 0)
|
||||
continue;
|
||||
|
||||
|
@ -148,8 +148,8 @@ void refresh_statusline(void) {
|
|||
block->x_offset = padding_width;
|
||||
break;
|
||||
case ALIGN_CENTER:
|
||||
block->x_offset = padding_width / 2;
|
||||
block->x_append = padding_width / 2 + padding_width % 2;
|
||||
block->x_offset = padding_width / logical_px(2);
|
||||
block->x_append = padding_width / logical_px(2) + padding_width % logical_px(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -168,12 +168,12 @@ void refresh_statusline(void) {
|
|||
realloc_sl_buffer();
|
||||
|
||||
/* Clear the statusline pixmap. */
|
||||
xcb_rectangle_t rect = { 0, 0, root_screen->width_in_pixels, font.height + 2 };
|
||||
xcb_rectangle_t rect = {0, 0, root_screen->width_in_pixels, font.height + logical_px(5)};
|
||||
xcb_poly_fill_rectangle(xcb_connection, statusline_pm, statusline_clear, 1, &rect);
|
||||
|
||||
/* Draw the text of each block. */
|
||||
uint32_t x = 0;
|
||||
TAILQ_FOREACH(block, &statusline_head, blocks) {
|
||||
TAILQ_FOREACH (block, &statusline_head, blocks) {
|
||||
if (i3string_get_num_bytes(block->full_text) == 0)
|
||||
continue;
|
||||
|
||||
|
@ -184,14 +184,14 @@ void refresh_statusline(void) {
|
|||
|
||||
if (TAILQ_NEXT(block, blocks) != NULL && !block->no_separator && block->sep_block_width > 0) {
|
||||
/* This is not the last block, draw a separator. */
|
||||
uint32_t sep_offset = block->sep_block_width/2 + block->sep_block_width % 2;
|
||||
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
|
||||
uint32_t values[] = { colors.sep_fg, colors.bar_bg };
|
||||
uint32_t sep_offset = block->sep_block_width / 2 + block->sep_block_width % 2;
|
||||
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_LINE_WIDTH;
|
||||
uint32_t values[] = {colors.sep_fg, colors.bar_bg, logical_px(1)};
|
||||
xcb_change_gc(xcb_connection, statusline_ctx, mask, values);
|
||||
xcb_poly_line(xcb_connection, XCB_COORD_MODE_ORIGIN, statusline_pm,
|
||||
statusline_ctx, 2,
|
||||
(xcb_point_t[]){ { x - sep_offset, 2 },
|
||||
{ x - sep_offset, font.height - 2 } });
|
||||
(xcb_point_t[]) {{x - sep_offset, 2},
|
||||
{x - sep_offset, font.height - 2}});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ void hide_bars(void) {
|
|||
}
|
||||
|
||||
i3_output *walk;
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (!walk->active) {
|
||||
continue;
|
||||
}
|
||||
|
@ -224,14 +224,14 @@ void unhide_bars(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
i3_output *walk;
|
||||
xcb_void_cookie_t cookie;
|
||||
uint32_t mask;
|
||||
uint32_t values[5];
|
||||
i3_output *walk;
|
||||
xcb_void_cookie_t cookie;
|
||||
uint32_t mask;
|
||||
uint32_t values[5];
|
||||
|
||||
cont_child();
|
||||
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (walk->bar == XCB_NONE) {
|
||||
continue;
|
||||
}
|
||||
|
@ -243,7 +243,8 @@ void unhide_bars(void) {
|
|||
values[0] = walk->rect.x;
|
||||
if (config.position == POS_TOP)
|
||||
values[1] = walk->rect.y;
|
||||
else values[1] = walk->rect.y + walk->rect.h - bar_height;
|
||||
else
|
||||
values[1] = walk->rect.y + walk->rect.h - bar_height;
|
||||
values[2] = walk->rect.w;
|
||||
values[3] = bar_height;
|
||||
values[4] = XCB_STACK_MODE_ABOVE;
|
||||
|
@ -265,10 +266,10 @@ void unhide_bars(void) {
|
|||
*
|
||||
*/
|
||||
void init_colors(const struct xcb_color_strings_t *new_colors) {
|
||||
#define PARSE_COLOR(name, def) \
|
||||
do { \
|
||||
#define PARSE_COLOR(name, def) \
|
||||
do { \
|
||||
colors.name = get_colorpixel(new_colors->name ? new_colors->name : def); \
|
||||
} while (0)
|
||||
} while (0)
|
||||
PARSE_COLOR(bar_fg, "#FFFFFF");
|
||||
PARSE_COLOR(bar_bg, "#000000");
|
||||
PARSE_COLOR(sep_fg, "#666666");
|
||||
|
@ -302,7 +303,7 @@ void handle_button(xcb_button_press_event_t *event) {
|
|||
/* Determine, which bar was clicked */
|
||||
i3_output *walk;
|
||||
xcb_window_t bar = event->event;
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (walk->bar == bar) {
|
||||
break;
|
||||
}
|
||||
|
@ -314,7 +315,7 @@ void handle_button(xcb_button_press_event_t *event) {
|
|||
}
|
||||
|
||||
/* TODO: Move this to extern get_ws_for_output() */
|
||||
TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) {
|
||||
TAILQ_FOREACH (cur_ws, walk->workspaces, tailq) {
|
||||
if (cur_ws->visible) {
|
||||
break;
|
||||
}
|
||||
|
@ -330,6 +331,39 @@ void handle_button(xcb_button_press_event_t *event) {
|
|||
|
||||
DLOG("Got Button %d\n", event->detail);
|
||||
|
||||
if (child_want_click_events()) {
|
||||
/* If the child asked for click events,
|
||||
* check if a status block has been clicked. */
|
||||
|
||||
/* First calculate width of tray area */
|
||||
trayclient *trayclient;
|
||||
int tray_width = 0;
|
||||
TAILQ_FOREACH_REVERSE (trayclient, walk->trayclients, tc_head, tailq) {
|
||||
if (!trayclient->mapped)
|
||||
continue;
|
||||
tray_width += (font.height + logical_px(2));
|
||||
}
|
||||
|
||||
int block_x = 0, last_block_x;
|
||||
int offset = (walk->rect.w - (statusline_width + tray_width)) - logical_px(10);
|
||||
|
||||
x = original_x - offset;
|
||||
if (x >= 0) {
|
||||
struct status_block *block;
|
||||
|
||||
TAILQ_FOREACH (block, &statusline_head, blocks) {
|
||||
last_block_x = block_x;
|
||||
block_x += block->width + block->x_offset + block->x_append;
|
||||
|
||||
if (x <= block_x && x >= last_block_x) {
|
||||
send_block_clicked(event->detail, block->name, block->instance, event->root_x, event->root_y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
x = original_x;
|
||||
}
|
||||
|
||||
switch (event->detail) {
|
||||
case 4:
|
||||
/* Mouse wheel up. We select the previous ws, if any.
|
||||
|
@ -351,52 +385,32 @@ void handle_button(xcb_button_press_event_t *event) {
|
|||
|
||||
cur_ws = TAILQ_NEXT(cur_ws, tailq);
|
||||
break;
|
||||
default:
|
||||
case 1:
|
||||
/* Check if this event regards a workspace button */
|
||||
TAILQ_FOREACH(cur_ws, walk->workspaces, tailq) {
|
||||
TAILQ_FOREACH (cur_ws, walk->workspaces, tailq) {
|
||||
DLOG("x = %d\n", x);
|
||||
if (x >= 0 && x < cur_ws->name_width + 10) {
|
||||
if (x >= 0 && x < cur_ws->name_width + logical_px(10)) {
|
||||
break;
|
||||
}
|
||||
x -= cur_ws->name_width + 11;
|
||||
x -= cur_ws->name_width + logical_px(11);
|
||||
}
|
||||
|
||||
/* Otherwise, focus our currently visible workspace if it is not
|
||||
* already focused */
|
||||
if (cur_ws == NULL) {
|
||||
/* No workspace button was pressed.
|
||||
* Check if a status block has been clicked.
|
||||
* This of course only has an effect,
|
||||
* if the child reported bidirectional protocol usage. */
|
||||
|
||||
/* First calculate width of tray area */
|
||||
trayclient *trayclient;
|
||||
int tray_width = 0;
|
||||
TAILQ_FOREACH_REVERSE(trayclient, walk->trayclients, tc_head, tailq) {
|
||||
if (!trayclient->mapped)
|
||||
continue;
|
||||
tray_width += (font.height + 2);
|
||||
TAILQ_FOREACH (cur_ws, walk->workspaces, tailq) {
|
||||
if (cur_ws->visible && !cur_ws->focused)
|
||||
break;
|
||||
}
|
||||
|
||||
int block_x = 0, last_block_x;
|
||||
int offset = (walk->rect.w - (statusline_width + tray_width)) - 10;
|
||||
|
||||
x = original_x - offset;
|
||||
if (x < 0)
|
||||
return;
|
||||
|
||||
struct status_block *block;
|
||||
|
||||
TAILQ_FOREACH(block, &statusline_head, blocks) {
|
||||
last_block_x = block_x;
|
||||
block_x += block->width + block->x_offset + block->x_append;
|
||||
|
||||
if (x <= block_x && x >= last_block_x) {
|
||||
send_block_clicked(event->detail, block->name, block->instance, event->root_x, event->root_y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event->detail != 1)
|
||||
|
||||
/* if there is nothing to focus, we are done */
|
||||
if (cur_ws == NULL)
|
||||
return;
|
||||
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* To properly handle workspace names with double quotes in them, we need
|
||||
|
@ -405,7 +419,7 @@ void handle_button(xcb_button_press_event_t *event) {
|
|||
* buffer, then we copy character by character. */
|
||||
int num_quotes = 0;
|
||||
size_t namelen = 0;
|
||||
const char *utf8_name = i3string_as_utf8(cur_ws->name);
|
||||
const char *utf8_name = cur_ws->canonical_name;
|
||||
for (const char *walk = utf8_name; *walk != '\0'; walk++) {
|
||||
if (*walk == '"')
|
||||
num_quotes++;
|
||||
|
@ -415,9 +429,9 @@ void handle_button(xcb_button_press_event_t *event) {
|
|||
}
|
||||
|
||||
const size_t len = namelen + strlen("workspace \"\"") + 1;
|
||||
char *buffer = scalloc(len+num_quotes);
|
||||
char *buffer = scalloc(len + num_quotes);
|
||||
strncpy(buffer, "workspace \"", strlen("workspace \""));
|
||||
int inpos, outpos;
|
||||
size_t inpos, outpos;
|
||||
for (inpos = 0, outpos = strlen("workspace \"");
|
||||
inpos < namelen;
|
||||
inpos++, outpos++) {
|
||||
|
@ -441,19 +455,19 @@ void handle_button(xcb_button_press_event_t *event) {
|
|||
static void configure_trayclients(void) {
|
||||
trayclient *trayclient;
|
||||
i3_output *output;
|
||||
SLIST_FOREACH(output, outputs, slist) {
|
||||
SLIST_FOREACH (output, outputs, slist) {
|
||||
if (!output->active)
|
||||
continue;
|
||||
|
||||
int clients = 0;
|
||||
TAILQ_FOREACH_REVERSE(trayclient, output->trayclients, tc_head, tailq) {
|
||||
TAILQ_FOREACH_REVERSE (trayclient, output->trayclients, tc_head, tailq) {
|
||||
if (!trayclient->mapped)
|
||||
continue;
|
||||
clients++;
|
||||
|
||||
DLOG("Configuring tray window %08x to x=%d\n",
|
||||
trayclient->win, output->rect.w - (clients * (font.height + 2)));
|
||||
uint32_t x = output->rect.w - (clients * (font.height + 2));
|
||||
trayclient->win, output->rect.w - (clients * (font.height + logical_px(2))));
|
||||
uint32_t x = output->rect.w - (clients * (font.height + logical_px(2)));
|
||||
xcb_configure_window(xcb_connection,
|
||||
trayclient->win,
|
||||
XCB_CONFIG_WINDOW_X,
|
||||
|
@ -469,7 +483,7 @@ static void configure_trayclients(void) {
|
|||
* supported client messages currently are _NET_SYSTEM_TRAY_OPCODE.
|
||||
*
|
||||
*/
|
||||
static void handle_client_message(xcb_client_message_event_t* event) {
|
||||
static void handle_client_message(xcb_client_message_event_t *event) {
|
||||
if (event->type == atoms[_NET_SYSTEM_TRAY_OPCODE] &&
|
||||
event->format == 32) {
|
||||
DLOG("_NET_SYSTEM_TRAY_OPCODE received\n");
|
||||
|
@ -530,7 +544,7 @@ static void handle_client_message(xcb_client_message_event_t* event) {
|
|||
|
||||
DLOG("X window %08x requested docking\n", client);
|
||||
i3_output *walk, *output = NULL;
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (!walk->active)
|
||||
continue;
|
||||
if (config.tray_output) {
|
||||
|
@ -548,7 +562,7 @@ static void handle_client_message(xcb_client_message_event_t* event) {
|
|||
if (output == NULL &&
|
||||
config.tray_output &&
|
||||
strcasecmp("primary", config.tray_output) == 0) {
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (!walk->active)
|
||||
continue;
|
||||
DLOG("Falling back to output %s because no primary output is configured\n", walk->name);
|
||||
|
@ -593,7 +607,7 @@ static void handle_client_message(xcb_client_message_event_t* event) {
|
|||
0,
|
||||
client,
|
||||
XCB_EVENT_MASK_NO_EVENT,
|
||||
(char*)ev);
|
||||
(char *)ev);
|
||||
free(event);
|
||||
|
||||
/* Put the client inside the save set. Upon termination (whether
|
||||
|
@ -632,16 +646,16 @@ static void handle_client_message(xcb_client_message_event_t* event) {
|
|||
* See: http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
|
||||
*
|
||||
*/
|
||||
static void handle_destroy_notify(xcb_destroy_notify_event_t* event) {
|
||||
static void handle_destroy_notify(xcb_destroy_notify_event_t *event) {
|
||||
DLOG("DestroyNotify for window = %08x, event = %08x\n", event->window, event->event);
|
||||
|
||||
i3_output *walk;
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (!walk->active)
|
||||
continue;
|
||||
DLOG("checking output %s\n", walk->name);
|
||||
trayclient *trayclient;
|
||||
TAILQ_FOREACH(trayclient, walk->trayclients, tailq) {
|
||||
TAILQ_FOREACH (trayclient, walk->trayclients, tailq) {
|
||||
if (trayclient->win != event->window)
|
||||
continue;
|
||||
|
||||
|
@ -661,16 +675,16 @@ static void handle_destroy_notify(xcb_destroy_notify_event_t* event) {
|
|||
* window. We respond by realigning the tray clients.
|
||||
*
|
||||
*/
|
||||
static void handle_map_notify(xcb_map_notify_event_t* event) {
|
||||
static void handle_map_notify(xcb_map_notify_event_t *event) {
|
||||
DLOG("MapNotify for window = %08x, event = %08x\n", event->window, event->event);
|
||||
|
||||
i3_output *walk;
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (!walk->active)
|
||||
continue;
|
||||
DLOG("checking output %s\n", walk->name);
|
||||
trayclient *trayclient;
|
||||
TAILQ_FOREACH(trayclient, walk->trayclients, tailq) {
|
||||
TAILQ_FOREACH (trayclient, walk->trayclients, tailq) {
|
||||
if (trayclient->win != event->window)
|
||||
continue;
|
||||
|
||||
|
@ -689,16 +703,16 @@ static void handle_map_notify(xcb_map_notify_event_t* event) {
|
|||
* window. We respond by realigning the tray clients.
|
||||
*
|
||||
*/
|
||||
static void handle_unmap_notify(xcb_unmap_notify_event_t* event) {
|
||||
static void handle_unmap_notify(xcb_unmap_notify_event_t *event) {
|
||||
DLOG("UnmapNotify for window = %08x, event = %08x\n", event->window, event->event);
|
||||
|
||||
i3_output *walk;
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (!walk->active)
|
||||
continue;
|
||||
DLOG("checking output %s\n", walk->name);
|
||||
trayclient *trayclient;
|
||||
TAILQ_FOREACH(trayclient, walk->trayclients, tailq) {
|
||||
TAILQ_FOREACH (trayclient, walk->trayclients, tailq) {
|
||||
if (trayclient->win != event->window)
|
||||
continue;
|
||||
|
||||
|
@ -725,11 +739,11 @@ static void handle_property_notify(xcb_property_notify_event_t *event) {
|
|||
DLOG("xembed_info updated\n");
|
||||
trayclient *trayclient = NULL, *walk;
|
||||
i3_output *o_walk;
|
||||
SLIST_FOREACH(o_walk, outputs, slist) {
|
||||
SLIST_FOREACH (o_walk, outputs, slist) {
|
||||
if (!o_walk->active)
|
||||
continue;
|
||||
|
||||
TAILQ_FOREACH(walk, o_walk->trayclients, tailq) {
|
||||
TAILQ_FOREACH (walk, o_walk->trayclients, tailq) {
|
||||
if (walk->win != event->window)
|
||||
continue;
|
||||
trayclient = walk;
|
||||
|
@ -788,12 +802,12 @@ static void handle_configure_request(xcb_configure_request_event_t *event) {
|
|||
|
||||
trayclient *trayclient;
|
||||
i3_output *output;
|
||||
SLIST_FOREACH(output, outputs, slist) {
|
||||
SLIST_FOREACH (output, outputs, slist) {
|
||||
if (!output->active)
|
||||
continue;
|
||||
|
||||
int clients = 0;
|
||||
TAILQ_FOREACH_REVERSE(trayclient, output->trayclients, tc_head, tailq) {
|
||||
TAILQ_FOREACH_REVERSE (trayclient, output->trayclients, tc_head, tailq) {
|
||||
if (!trayclient->mapped)
|
||||
continue;
|
||||
clients++;
|
||||
|
@ -847,31 +861,31 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) {
|
|||
break;
|
||||
case XCB_BUTTON_PRESS:
|
||||
/* Button-press-events are mouse-buttons clicked on one of our bars */
|
||||
handle_button((xcb_button_press_event_t*) event);
|
||||
handle_button((xcb_button_press_event_t *)event);
|
||||
break;
|
||||
case XCB_CLIENT_MESSAGE:
|
||||
/* Client messages are used for client-to-client communication, for
|
||||
* example system tray widgets talk to us directly via client messages. */
|
||||
handle_client_message((xcb_client_message_event_t*) event);
|
||||
handle_client_message((xcb_client_message_event_t *)event);
|
||||
break;
|
||||
case XCB_DESTROY_NOTIFY:
|
||||
/* DestroyNotify signifies the end of the XEmbed protocol */
|
||||
handle_destroy_notify((xcb_destroy_notify_event_t*) event);
|
||||
handle_destroy_notify((xcb_destroy_notify_event_t *)event);
|
||||
break;
|
||||
case XCB_UNMAP_NOTIFY:
|
||||
/* UnmapNotify is received when a tray client hides its window. */
|
||||
handle_unmap_notify((xcb_unmap_notify_event_t*) event);
|
||||
handle_unmap_notify((xcb_unmap_notify_event_t *)event);
|
||||
break;
|
||||
case XCB_MAP_NOTIFY:
|
||||
handle_map_notify((xcb_map_notify_event_t*) event);
|
||||
handle_map_notify((xcb_map_notify_event_t *)event);
|
||||
break;
|
||||
case XCB_PROPERTY_NOTIFY:
|
||||
/* PropertyNotify */
|
||||
handle_property_notify((xcb_property_notify_event_t*) event);
|
||||
handle_property_notify((xcb_property_notify_event_t *)event);
|
||||
break;
|
||||
case XCB_CONFIGURE_REQUEST:
|
||||
/* ConfigureRequest, sent by a tray child */
|
||||
handle_configure_request((xcb_configure_request_event_t*) event);
|
||||
handle_configure_request((xcb_configure_request_event_t *)event);
|
||||
break;
|
||||
}
|
||||
free(event);
|
||||
|
@ -897,7 +911,7 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
|||
DLOG("Got XKB-Event!\n");
|
||||
|
||||
while (XPending(xkb_dpy)) {
|
||||
XNextEvent(xkb_dpy, (XEvent*)&ev);
|
||||
XNextEvent(xkb_dpy, (XEvent *)&ev);
|
||||
|
||||
if (ev.type != xkb_event_base) {
|
||||
ELOG("No Xkb-Event!\n");
|
||||
|
@ -913,31 +927,31 @@ void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
|
|||
modstate = mods & config.modifier;
|
||||
}
|
||||
|
||||
#define DLOGMOD(modmask, status) \
|
||||
do { \
|
||||
switch (modmask) { \
|
||||
case ShiftMask: \
|
||||
DLOG("ShiftMask got " #status "!\n"); \
|
||||
break; \
|
||||
case ControlMask: \
|
||||
#define DLOGMOD(modmask, status) \
|
||||
do { \
|
||||
switch (modmask) { \
|
||||
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; \
|
||||
} \
|
||||
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) {
|
||||
|
@ -971,9 +985,9 @@ char *init_xcb_early() {
|
|||
conn = xcb_connection;
|
||||
DLOG("Connected to xcb\n");
|
||||
|
||||
/* We have to request the atoms we need */
|
||||
#define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name);
|
||||
#include "xcb_atoms.def"
|
||||
/* We have to request the atoms we need */
|
||||
#define ATOM_DO(name) atom_cookies[name] = xcb_intern_atom(xcb_connection, 0, strlen(#name), #name);
|
||||
#include "xcb_atoms.def"
|
||||
|
||||
root_screen = xcb_aux_get_screen(xcb_connection, screen);
|
||||
xcb_root = root_screen->root;
|
||||
|
@ -981,7 +995,7 @@ char *init_xcb_early() {
|
|||
/* We draw the statusline to a seperate pixmap, because it looks the same on all bars and
|
||||
* this way, we can choose to crop it */
|
||||
uint32_t mask = XCB_GC_FOREGROUND;
|
||||
uint32_t vals[] = { colors.bar_bg, colors.bar_bg };
|
||||
uint32_t vals[] = {colors.bar_bg, colors.bar_bg};
|
||||
|
||||
statusline_clear = xcb_generate_id(xcb_connection);
|
||||
xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
|
||||
|
@ -1005,7 +1019,6 @@ char *init_xcb_early() {
|
|||
root_screen->width_in_pixels,
|
||||
root_screen->height_in_pixels);
|
||||
|
||||
|
||||
/* The various Watchers to communicate with xcb */
|
||||
xcb_io = smalloc(sizeof(ev_io));
|
||||
xcb_prep = smalloc(sizeof(ev_prepare));
|
||||
|
@ -1086,7 +1099,7 @@ void register_xkb_keyevents() {
|
|||
*/
|
||||
void deregister_xkb_keyevents() {
|
||||
if (xkb_dpy != NULL) {
|
||||
ev_io_stop (main_loop, xkb_io);
|
||||
ev_io_stop(main_loop, xkb_io);
|
||||
XCloseDisplay(xkb_dpy);
|
||||
close(xkb_io->fd);
|
||||
FREE(xkb_io);
|
||||
|
@ -1107,7 +1120,7 @@ void init_xcb_late(char *fontname) {
|
|||
font = load_font(fontname, true);
|
||||
set_font(&font);
|
||||
DLOG("Calculated Font-height: %d\n", font.height);
|
||||
bar_height = font.height + 6;
|
||||
bar_height = font.height + logical_px(6);
|
||||
|
||||
xcb_flush(xcb_connection);
|
||||
|
||||
|
@ -1121,8 +1134,8 @@ void init_xcb_late(char *fontname) {
|
|||
*
|
||||
*/
|
||||
static void send_tray_clientmessage(void) {
|
||||
uint8_t buffer[32] = { 0 };
|
||||
xcb_client_message_event_t *ev = (xcb_client_message_event_t*)buffer;
|
||||
uint8_t buffer[32] = {0};
|
||||
xcb_client_message_event_t *ev = (xcb_client_message_event_t *)buffer;
|
||||
|
||||
ev->response_type = XCB_CLIENT_MESSAGE;
|
||||
ev->window = xcb_root;
|
||||
|
@ -1136,10 +1149,9 @@ static void send_tray_clientmessage(void) {
|
|||
0,
|
||||
xcb_root,
|
||||
0xFFFFFF,
|
||||
(char*)buffer);
|
||||
(char *)buffer);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initializes tray support by requesting the appropriate _NET_SYSTEM_TRAY atom
|
||||
* for the X11 display we are running on, then acquiring the selection for this
|
||||
|
@ -1158,7 +1170,7 @@ void init_tray(void) {
|
|||
/* tray support: we need a window to own the selection */
|
||||
selwin = xcb_generate_id(xcb_connection);
|
||||
uint32_t selmask = XCB_CW_OVERRIDE_REDIRECT;
|
||||
uint32_t selval[] = { 1 };
|
||||
uint32_t selval[] = {1};
|
||||
xcb_create_window(xcb_connection,
|
||||
root_screen->root_depth,
|
||||
selwin,
|
||||
|
@ -1207,8 +1219,9 @@ void init_tray(void) {
|
|||
}
|
||||
|
||||
if (selreply->owner != selwin) {
|
||||
ELOG("Could not set the %s selection. " \
|
||||
"Maybe another tray is already running?\n", atomname);
|
||||
ELOG("Could not set the %s selection. "
|
||||
"Maybe another tray is already running?\n",
|
||||
atomname);
|
||||
/* NOTE that this error is not fatal. We just can’t provide tray
|
||||
* functionality */
|
||||
free(selreply);
|
||||
|
@ -1267,7 +1280,7 @@ void init_tray_colors(void) {
|
|||
void clean_xcb(void) {
|
||||
i3_output *o_walk;
|
||||
free_workspaces();
|
||||
SLIST_FOREACH(o_walk, outputs, slist) {
|
||||
SLIST_FOREACH (o_walk, outputs, slist) {
|
||||
destroy_window(o_walk);
|
||||
FREE(o_walk->trayclients);
|
||||
FREE(o_walk->workspaces);
|
||||
|
@ -1294,15 +1307,16 @@ void clean_xcb(void) {
|
|||
*/
|
||||
void get_atoms(void) {
|
||||
xcb_intern_atom_reply_t *reply;
|
||||
#define ATOM_DO(name) reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \
|
||||
if (reply == NULL) { \
|
||||
ELOG("Could not get atom %s\n", #name); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
atoms[name] = reply->atom; \
|
||||
free(reply);
|
||||
#define ATOM_DO(name) \
|
||||
reply = xcb_intern_atom_reply(xcb_connection, atom_cookies[name], NULL); \
|
||||
if (reply == NULL) { \
|
||||
ELOG("Could not get atom %s\n", #name); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
atoms[name] = reply->atom; \
|
||||
free(reply);
|
||||
|
||||
#include "xcb_atoms.def"
|
||||
#include "xcb_atoms.def"
|
||||
DLOG("Got Atoms\n");
|
||||
}
|
||||
|
||||
|
@ -1338,14 +1352,14 @@ void kick_tray_clients(i3_output *output) {
|
|||
/* Fake a DestroyNotify so that Qt re-adds tray icons.
|
||||
* We cannot actually destroy the window because then Qt will not restore
|
||||
* its event mask on the new window. */
|
||||
uint8_t buffer[32] = { 0 };
|
||||
xcb_destroy_notify_event_t *event = (xcb_destroy_notify_event_t*)buffer;
|
||||
uint8_t buffer[32] = {0};
|
||||
xcb_destroy_notify_event_t *event = (xcb_destroy_notify_event_t *)buffer;
|
||||
|
||||
event->response_type = XCB_DESTROY_NOTIFY;
|
||||
event->event = selwin;
|
||||
event->window = selwin;
|
||||
|
||||
xcb_send_event(conn, false, selwin, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char*)event);
|
||||
xcb_send_event(conn, false, selwin, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char *)event);
|
||||
|
||||
send_tray_clientmessage();
|
||||
}
|
||||
|
@ -1384,7 +1398,7 @@ void realloc_sl_buffer(void) {
|
|||
bar_height);
|
||||
|
||||
uint32_t mask = XCB_GC_FOREGROUND;
|
||||
uint32_t vals[2] = { colors.bar_bg, colors.bar_bg };
|
||||
uint32_t vals[2] = {colors.bar_bg, colors.bar_bg};
|
||||
xcb_free_gc(xcb_connection, statusline_clear);
|
||||
statusline_clear = xcb_generate_id(xcb_connection);
|
||||
xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
|
||||
|
@ -1408,7 +1422,6 @@ void realloc_sl_buffer(void) {
|
|||
xcb_request_failed(sl_ctx_cookie, "Could not allocate statusline-buffer-context")) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1421,7 +1434,7 @@ void reconfig_windows(bool redraw_bars) {
|
|||
static bool tray_configured = false;
|
||||
|
||||
i3_output *walk;
|
||||
SLIST_FOREACH(walk, outputs, slist) {
|
||||
SLIST_FOREACH (walk, outputs, slist) {
|
||||
if (!walk->active) {
|
||||
/* If an output is not active, we destroy its bar */
|
||||
/* FIXME: Maybe we rather want to unmap? */
|
||||
|
@ -1504,7 +1517,7 @@ void reconfig_windows(bool redraw_bars) {
|
|||
XCB_ATOM_ATOM,
|
||||
32,
|
||||
1,
|
||||
(unsigned char*) &atoms[_NET_WM_WINDOW_TYPE_DOCK]);
|
||||
(unsigned char *)&atoms[_NET_WM_WINDOW_TYPE_DOCK]);
|
||||
|
||||
/* We need to tell i3, where to reserve space for i3bar */
|
||||
/* left, right, top, bottom, left_start_y, left_end_y,
|
||||
|
@ -1524,7 +1537,9 @@ void reconfig_windows(bool redraw_bars) {
|
|||
uint32_t top_end_x;
|
||||
uint32_t bottom_start_x;
|
||||
uint32_t bottom_end_x;
|
||||
} __attribute__((__packed__)) strut_partial = {0,};
|
||||
} __attribute__((__packed__)) strut_partial;
|
||||
memset(&strut_partial, 0, sizeof(strut_partial));
|
||||
|
||||
switch (config.position) {
|
||||
case POS_NONE:
|
||||
break;
|
||||
|
@ -1563,13 +1578,13 @@ void reconfig_windows(bool redraw_bars) {
|
|||
map_cookie = xcb_map_window_checked(xcb_connection, walk->bar);
|
||||
}
|
||||
|
||||
if (xcb_request_failed(win_cookie, "Could not create window") ||
|
||||
xcb_request_failed(pm_cookie, "Could not create pixmap") ||
|
||||
xcb_request_failed(dock_cookie, "Could not set dock mode") ||
|
||||
xcb_request_failed(class_cookie, "Could not set WM_CLASS") ||
|
||||
xcb_request_failed(name_cookie, "Could not set WM_NAME") ||
|
||||
xcb_request_failed(strut_cookie, "Could not set strut") ||
|
||||
xcb_request_failed(gc_cookie, "Could not create graphical context") ||
|
||||
if (xcb_request_failed(win_cookie, "Could not create window") ||
|
||||
xcb_request_failed(pm_cookie, "Could not create pixmap") ||
|
||||
xcb_request_failed(dock_cookie, "Could not set dock mode") ||
|
||||
xcb_request_failed(class_cookie, "Could not set WM_CLASS") ||
|
||||
xcb_request_failed(name_cookie, "Could not set WM_NAME") ||
|
||||
xcb_request_failed(strut_cookie, "Could not set strut") ||
|
||||
xcb_request_failed(gc_cookie, "Could not create graphical context") ||
|
||||
((config.hide_on_modifier == M_DOCK) && xcb_request_failed(map_cookie, "Could not map window"))) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -1581,9 +1596,9 @@ void reconfig_windows(bool redraw_bars) {
|
|||
* VGA-1 but output == [HDMI-1]).
|
||||
*/
|
||||
i3_output *output;
|
||||
SLIST_FOREACH(output, outputs, slist) {
|
||||
SLIST_FOREACH (output, outputs, slist) {
|
||||
if (strcasecmp(output->name, tray_output) == 0 ||
|
||||
(strcasecmp(tray_output, "primary") == 0 && output->primary)) {
|
||||
(strcasecmp(tray_output, "primary") == 0 && output->primary)) {
|
||||
init_tray();
|
||||
break;
|
||||
}
|
||||
|
@ -1650,9 +1665,9 @@ void reconfig_windows(bool redraw_bars) {
|
|||
|
||||
if (xcb_request_failed(cfg_cookie, "Could not reconfigure window") ||
|
||||
xcb_request_failed(chg_cookie, "Could not change window") ||
|
||||
xcb_request_failed(pm_cookie, "Could not create pixmap") ||
|
||||
(redraw_bars && (xcb_request_failed(umap_cookie, "Could not unmap window") ||
|
||||
(config.hide_on_modifier == M_DOCK && xcb_request_failed(map_cookie, "Could not map window"))))) {
|
||||
xcb_request_failed(pm_cookie, "Could not create pixmap") ||
|
||||
(redraw_bars && (xcb_request_failed(umap_cookie, "Could not unmap window") ||
|
||||
(config.hide_on_modifier == M_DOCK && xcb_request_failed(map_cookie, "Could not map window"))))) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
@ -1670,7 +1685,7 @@ void draw_bars(bool unhide) {
|
|||
refresh_statusline();
|
||||
|
||||
i3_output *outputs_walk;
|
||||
SLIST_FOREACH(outputs_walk, outputs, slist) {
|
||||
SLIST_FOREACH (outputs_walk, outputs, slist) {
|
||||
if (!outputs_walk->active) {
|
||||
DLOG("Output %s inactive, skipping...\n", outputs_walk->name);
|
||||
continue;
|
||||
|
@ -1685,7 +1700,7 @@ void draw_bars(bool unhide) {
|
|||
outputs_walk->bargc,
|
||||
XCB_GC_FOREGROUND,
|
||||
&color);
|
||||
xcb_rectangle_t rect = { 0, 0, outputs_walk->rect.w, bar_height };
|
||||
xcb_rectangle_t rect = {0, 0, outputs_walk->rect.w, bar_height};
|
||||
xcb_poly_fill_rectangle(xcb_connection,
|
||||
outputs_walk->buffer,
|
||||
outputs_walk->bargc,
|
||||
|
@ -1700,7 +1715,7 @@ void draw_bars(bool unhide) {
|
|||
* position */
|
||||
trayclient *trayclient;
|
||||
int traypx = 0;
|
||||
TAILQ_FOREACH(trayclient, outputs_walk->trayclients, tailq) {
|
||||
TAILQ_FOREACH (trayclient, outputs_walk->trayclients, tailq) {
|
||||
if (!trayclient->mapped)
|
||||
continue;
|
||||
/* We assume the tray icons are quadratic (we use the font
|
||||
|
@ -1717,12 +1732,12 @@ void draw_bars(bool unhide) {
|
|||
outputs_walk->bargc,
|
||||
MAX(0, (int16_t)(statusline_width - outputs_walk->rect.w + 4)), 0,
|
||||
MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width - traypx - 4)), 3,
|
||||
MIN(outputs_walk->rect.w - traypx - 4, statusline_width), font.height + 2);
|
||||
MIN(outputs_walk->rect.w - traypx - 4, (int)statusline_width), font.height + 2);
|
||||
}
|
||||
|
||||
if (!config.disable_ws) {
|
||||
i3_ws *ws_walk;
|
||||
TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
|
||||
TAILQ_FOREACH (ws_walk, outputs_walk->workspaces, tailq) {
|
||||
DLOG("Drawing Button for WS %s at x = %d, len = %d\n",
|
||||
i3string_as_utf8(ws_walk->name), i, ws_walk->name_width);
|
||||
uint32_t fg_color = colors.inactive_ws_fg;
|
||||
|
@ -1747,23 +1762,29 @@ void draw_bars(bool unhide) {
|
|||
unhide = true;
|
||||
}
|
||||
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
|
||||
uint32_t vals_border[] = { border_color, border_color };
|
||||
uint32_t vals_border[] = {border_color, border_color};
|
||||
xcb_change_gc(xcb_connection,
|
||||
outputs_walk->bargc,
|
||||
mask,
|
||||
vals_border);
|
||||
xcb_rectangle_t rect_border = { i, 1, ws_walk->name_width + 10, font.height + 4 };
|
||||
xcb_rectangle_t rect_border = {i,
|
||||
logical_px(1),
|
||||
ws_walk->name_width + logical_px(10),
|
||||
font.height + logical_px(4)};
|
||||
xcb_poly_fill_rectangle(xcb_connection,
|
||||
outputs_walk->buffer,
|
||||
outputs_walk->bargc,
|
||||
1,
|
||||
&rect_border);
|
||||
uint32_t vals[] = { bg_color, bg_color };
|
||||
uint32_t vals[] = {bg_color, bg_color};
|
||||
xcb_change_gc(xcb_connection,
|
||||
outputs_walk->bargc,
|
||||
mask,
|
||||
vals);
|
||||
xcb_rectangle_t rect = { i + 1, 2, ws_walk->name_width + 8, font.height + 2 };
|
||||
xcb_rectangle_t rect = {i + logical_px(1),
|
||||
2 * logical_px(1),
|
||||
ws_walk->name_width + logical_px(8),
|
||||
font.height + logical_px(2)};
|
||||
xcb_poly_fill_rectangle(xcb_connection,
|
||||
outputs_walk->buffer,
|
||||
outputs_walk->bargc,
|
||||
|
@ -1771,9 +1792,8 @@ void draw_bars(bool unhide) {
|
|||
&rect);
|
||||
set_font_colors(outputs_walk->bargc, fg_color, bg_color);
|
||||
draw_text(ws_walk->name, outputs_walk->buffer, outputs_walk->bargc,
|
||||
i + 5, 3, ws_walk->name_width);
|
||||
i += 10 + ws_walk->name_width + 1;
|
||||
|
||||
i + logical_px(5), 3 * logical_px(1), ws_walk->name_width);
|
||||
i += logical_px(10) + ws_walk->name_width + logical_px(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1782,24 +1802,24 @@ void draw_bars(bool unhide) {
|
|||
uint32_t bg_color = colors.urgent_ws_bg;
|
||||
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
|
||||
|
||||
uint32_t vals_border[] = { colors.urgent_ws_border, colors.urgent_ws_border };
|
||||
uint32_t vals_border[] = {colors.urgent_ws_border, colors.urgent_ws_border};
|
||||
xcb_change_gc(xcb_connection,
|
||||
outputs_walk->bargc,
|
||||
mask,
|
||||
vals_border);
|
||||
xcb_rectangle_t rect_border = { i, 1, binding.width + 10, font.height + 4 };
|
||||
xcb_rectangle_t rect_border = {i, 1, binding.width + 10, font.height + 4};
|
||||
xcb_poly_fill_rectangle(xcb_connection,
|
||||
outputs_walk->buffer,
|
||||
outputs_walk->bargc,
|
||||
1,
|
||||
&rect_border);
|
||||
|
||||
uint32_t vals[] = { bg_color, bg_color };
|
||||
uint32_t vals[] = {bg_color, bg_color};
|
||||
xcb_change_gc(xcb_connection,
|
||||
outputs_walk->bargc,
|
||||
mask,
|
||||
vals);
|
||||
xcb_rectangle_t rect = { i + 1, 2, binding.width + 8, font.height + 2 };
|
||||
xcb_rectangle_t rect = {i + 1, 2, binding.width + 8, font.height + 2};
|
||||
xcb_poly_fill_rectangle(xcb_connection,
|
||||
outputs_walk->buffer,
|
||||
outputs_walk->bargc,
|
||||
|
@ -1817,8 +1837,8 @@ void draw_bars(bool unhide) {
|
|||
|
||||
/* Assure the bar is hidden/unhidden according to the specified hidden_state and mode */
|
||||
if (mod_pressed ||
|
||||
config.hidden_state == S_SHOW ||
|
||||
unhide) {
|
||||
config.hidden_state == S_SHOW ||
|
||||
unhide) {
|
||||
unhide_bars();
|
||||
} else if (config.hide_on_modifier == M_HIDE) {
|
||||
hide_bars();
|
||||
|
@ -1833,7 +1853,7 @@ void draw_bars(bool unhide) {
|
|||
*/
|
||||
void redraw_bars(void) {
|
||||
i3_output *outputs_walk;
|
||||
SLIST_FOREACH(outputs_walk, outputs, slist) {
|
||||
SLIST_FOREACH (outputs_walk, outputs, slist) {
|
||||
if (!outputs_walk->active) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -79,9 +79,12 @@
|
|||
#include "scratchpad.h"
|
||||
#include "commands.h"
|
||||
#include "commands_parser.h"
|
||||
#include "bindings.h"
|
||||
#include "config_directives.h"
|
||||
#include "config_parser.h"
|
||||
#include "fake_outputs.h"
|
||||
#include "display_version.h"
|
||||
#include "restore_layout.h"
|
||||
#include "main.h"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* assignments.c: Assignments for specific windows (for_window).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_ASSIGNMENTS_H
|
||||
#define I3_ASSIGNMENTS_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Checks the list of assignments for the given window and runs all matching
|
||||
|
@ -22,5 +21,3 @@ void run_assignments(i3Window *window);
|
|||
*
|
||||
*/
|
||||
Assignment *assignment_for(i3Window *window, int type);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@ xmacro(_NET_SUPPORTING_WM_CHECK)
|
|||
xmacro(_NET_WM_NAME)
|
||||
xmacro(_NET_WM_STATE_FULLSCREEN)
|
||||
xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
|
||||
xmacro(_NET_WM_STATE_MODAL)
|
||||
xmacro(_NET_WM_STATE)
|
||||
xmacro(_NET_WM_WINDOW_TYPE)
|
||||
xmacro(_NET_WM_WINDOW_TYPE_DOCK)
|
||||
|
@ -12,6 +13,7 @@ xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR)
|
|||
xmacro(_NET_WM_WINDOW_TYPE_SPLASH)
|
||||
xmacro(_NET_WM_DESKTOP)
|
||||
xmacro(_NET_WM_STRUT_PARTIAL)
|
||||
xmacro(_NET_CLIENT_LIST)
|
||||
xmacro(_NET_CLIENT_LIST_STACKING)
|
||||
xmacro(_NET_CURRENT_DESKTOP)
|
||||
xmacro(_NET_ACTIVE_WINDOW)
|
||||
|
@ -31,3 +33,4 @@ xmacro(I3_SHMLOG_PATH)
|
|||
xmacro(I3_PID)
|
||||
xmacro(_NET_REQUEST_FRAME_EXTENTS)
|
||||
xmacro(_NET_FRAME_EXTENTS)
|
||||
xmacro(_MOTIF_WM_HINTS)
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* vim:ts=4:sw=4:expandtab
|
||||
*
|
||||
* i3 - an improved dynamic tiling window manager
|
||||
* © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE)
|
||||
*
|
||||
* bindings.h: Functions for configuring, finding, and running bindings.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
extern pid_t command_error_nagbar_pid;
|
||||
|
||||
/**
|
||||
* The name of the default mode.
|
||||
*
|
||||
*/
|
||||
const char *DEFAULT_BINDING_MODE;
|
||||
|
||||
/**
|
||||
* Adds a binding from config parameters given as strings and returns a
|
||||
* pointer to the binding structure. Returns NULL if the input code could not
|
||||
* be parsed.
|
||||
*
|
||||
*/
|
||||
Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code,
|
||||
const char *release, const char *command, const char *mode);
|
||||
|
||||
/**
|
||||
* Grab the bound keys (tell X to send us keypress events for those keycodes)
|
||||
*
|
||||
*/
|
||||
void grab_all_keys(xcb_connection_t *conn, bool bind_mode_switch);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the Binding that matches the given xcb event or NULL if
|
||||
* no such binding exists.
|
||||
*
|
||||
*/
|
||||
Binding *get_binding_from_xcb_event(xcb_generic_event_t *event);
|
||||
|
||||
/**
|
||||
* Translates keysymbols to keycodes for all bindings which use keysyms.
|
||||
*
|
||||
*/
|
||||
void translate_keysyms(void);
|
||||
|
||||
/**
|
||||
* Switches the key bindings to the given mode, if the mode exists
|
||||
*
|
||||
*/
|
||||
void switch_mode(const char *new_mode);
|
||||
|
||||
/**
|
||||
* Checks for duplicate key bindings (the same keycode or keysym is configured
|
||||
* more than once). If a duplicate binding is found, a message is printed to
|
||||
* stderr and the has_errors variable is set to true, which will start
|
||||
* i3-nagbar.
|
||||
*
|
||||
*/
|
||||
void check_for_duplicate_bindings(struct context *context);
|
||||
|
||||
/**
|
||||
* Runs the given binding and handles parse errors. Returns a CommandResult for
|
||||
* running the binding's command. Caller should render tree if
|
||||
* needs_tree_render is true. Free with command_result_free().
|
||||
*
|
||||
*/
|
||||
CommandResult *run_binding(Binding *bind);
|
|
@ -7,8 +7,7 @@
|
|||
* click.c: Button press (mouse click) events.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_CLICK_H
|
||||
#define I3_CLICK_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* The button press X callback. This function determines whether the floating
|
||||
|
@ -19,5 +18,3 @@
|
|||
*
|
||||
*/
|
||||
int handle_button_press(xcb_button_press_event_t *event);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
* cmdparse.y: the parser for commands you send to i3 (or bind on keys)
|
||||
*
|
||||
*/
|
||||
#ifndef I3_CMDPARSE_H
|
||||
#define I3_CMDPARSE_H
|
||||
#pragma once
|
||||
|
||||
char *parse_cmd(const char *new);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
* commands.c: all command functions (see commands_parser.c)
|
||||
*
|
||||
*/
|
||||
#ifndef I3_COMMANDS_H
|
||||
#define I3_COMMANDS_H
|
||||
#pragma once
|
||||
|
||||
#include "commands_parser.h"
|
||||
|
||||
/** The beginning of the prototype for every cmd_ function. */
|
||||
#define I3_CMD Match *current_match, struct CommandResult *cmd_output
|
||||
#define I3_CMD Match *current_match, struct CommandResultIR *cmd_output
|
||||
|
||||
/**
|
||||
* Initializes the specified 'Match' data structure and the initial state of
|
||||
|
@ -288,5 +287,3 @@ void cmd_shmlog(I3_CMD, char *argument);
|
|||
*
|
||||
*/
|
||||
void cmd_debuglog(I3_CMD, char *argument);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,22 +7,17 @@
|
|||
* commands.c: all command functions (see commands_parser.c)
|
||||
*
|
||||
*/
|
||||
#ifndef I3_COMMANDS_PARSER_H
|
||||
#define I3_COMMANDS_PARSER_H
|
||||
#pragma once
|
||||
|
||||
#include <yajl/yajl_gen.h>
|
||||
|
||||
/*
|
||||
* Holds the result of a call to any command. When calling
|
||||
* parse_command("floating enable, border none"), the parser will internally
|
||||
* use a struct CommandResult when calling cmd_floating and cmd_border.
|
||||
* parse_command will also return another struct CommandResult, whose
|
||||
* json_output is set to a map of individual json_outputs and whose
|
||||
* needs_tree_trender is true if any individual needs_tree_render was true.
|
||||
*
|
||||
* Holds an intermediate represenation of the result of a call to any command.
|
||||
* When calling parse_command("floating enable, border none"), the parser will
|
||||
* internally use this struct when calling cmd_floating and cmd_border.
|
||||
*/
|
||||
struct CommandResult {
|
||||
/* The JSON generator to append a reply to. */
|
||||
struct CommandResultIR {
|
||||
/* The JSON generator to append a reply to (may be NULL). */
|
||||
yajl_gen json_gen;
|
||||
|
||||
/* The next state to transition to. Passed to the function so that we can
|
||||
|
@ -34,6 +29,31 @@ struct CommandResult {
|
|||
bool needs_tree_render;
|
||||
};
|
||||
|
||||
struct CommandResult *parse_command(const char *input);
|
||||
typedef struct CommandResult CommandResult;
|
||||
|
||||
#endif
|
||||
/**
|
||||
* A struct that contains useful information about the result of a command as a
|
||||
* whole (e.g. a compound command like "floating enable, border none").
|
||||
* needs_tree_render is true if needs_tree_render of any individual command was
|
||||
* true.
|
||||
*/
|
||||
struct CommandResult {
|
||||
bool parse_error;
|
||||
/* the error_message is currently only set for parse errors */
|
||||
char *error_message;
|
||||
bool needs_tree_render;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses and executes the given command. If a caller-allocated yajl_gen is
|
||||
* passed, a json reply will be generated in the format specified by the ipc
|
||||
* protocol. Pass NULL if no json reply is required.
|
||||
*
|
||||
* Free the returned CommandResult with command_result_free().
|
||||
*/
|
||||
CommandResult *parse_command(const char *input, yajl_gen gen);
|
||||
|
||||
/**
|
||||
* Frees a CommandResult
|
||||
*/
|
||||
void command_result_free(CommandResult *result);
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
* …).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_CON_H
|
||||
#define I3_CON_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Create a new container (and attach it to the given parent, if not NULL).
|
||||
|
@ -38,6 +37,12 @@ void con_focus(Con *con);
|
|||
*/
|
||||
bool con_is_leaf(Con *con);
|
||||
|
||||
/**
|
||||
* Returns true when this con is a leaf node with a managed X11 window (e.g.,
|
||||
* excluding dock containers)
|
||||
*/
|
||||
bool con_has_managed_window(Con *con);
|
||||
|
||||
/*
|
||||
* Returns true if a container should be considered split.
|
||||
*
|
||||
|
@ -81,7 +86,7 @@ Con *con_parent_with_orientation(Con *con, orientation_t orientation);
|
|||
* Returns the first fullscreen node below this node.
|
||||
*
|
||||
*/
|
||||
Con *con_get_fullscreen_con(Con *con, int fullscreen_mode);
|
||||
Con *con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode);
|
||||
|
||||
/**
|
||||
* Returns true if the container is internal, such as __i3_scratch
|
||||
|
@ -193,7 +198,7 @@ void con_move_to_workspace(Con *con, Con *workspace, bool fix_coordinates, bool
|
|||
* container).
|
||||
*
|
||||
*/
|
||||
int con_orientation(Con *con);
|
||||
orientation_t con_orientation(Con *con);
|
||||
|
||||
/**
|
||||
* Returns the container which will be focused next when the given container
|
||||
|
@ -340,5 +345,3 @@ void con_set_urgency(Con *con, bool urgent);
|
|||
*
|
||||
*/
|
||||
char *con_get_tree_representation(Con *con);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
* bindings mode).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_CONFIG_H
|
||||
#define I3_CONFIG_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "queue.h"
|
||||
|
@ -99,6 +98,7 @@ struct Config {
|
|||
int container_stack_limit;
|
||||
int container_stack_limit_value;
|
||||
int default_border_width;
|
||||
int default_floating_border_width;
|
||||
|
||||
/** Default orientation for new containers */
|
||||
int default_orientation;
|
||||
|
@ -109,6 +109,16 @@ struct Config {
|
|||
* It is not planned to add any different focus models. */
|
||||
bool disable_focus_follows_mouse;
|
||||
|
||||
/** By default, when switching focus to a window on a different output
|
||||
* (e.g. focusing a window on workspace 3 on output VGA-1, coming from
|
||||
* workspace 2 on LVDS-1), the mouse cursor is warped to the center of
|
||||
* that window.
|
||||
*
|
||||
* With the mouse_warping option, you can control when the mouse cursor
|
||||
* should be warped. "none" disables warping entirely, whereas "output"
|
||||
* is the default behavior described above. */
|
||||
warping_t mouse_warping;
|
||||
|
||||
/** Remove borders if they are adjacent to the screen edge.
|
||||
* This is useful if you are reaching scrollbar on the edge of the
|
||||
* screen or do not want to waste a single pixel of displayspace.
|
||||
|
@ -180,6 +190,7 @@ struct Config {
|
|||
struct Colortriple focused_inactive;
|
||||
struct Colortriple unfocused;
|
||||
struct Colortriple urgent;
|
||||
struct Colortriple placeholder;
|
||||
} client;
|
||||
struct config_bar {
|
||||
struct Colortriple focused;
|
||||
|
@ -267,6 +278,10 @@ struct Barconfig {
|
|||
* zero. */
|
||||
bool hide_workspace_buttons;
|
||||
|
||||
/** Strip workspace numbers? Configuration option is
|
||||
* 'strip_workspace_numbers yes'. */
|
||||
bool strip_workspace_numbers;
|
||||
|
||||
/** Hide mode button? Configuration option is 'binding_mode_indicator no'
|
||||
* but we invert the bool for the same reason as hide_workspace_buttons.*/
|
||||
bool hide_binding_mode_indicator;
|
||||
|
@ -308,12 +323,6 @@ struct Barconfig {
|
|||
*/
|
||||
void load_configuration(xcb_connection_t *conn, const char *override_configfile, bool reload);
|
||||
|
||||
/**
|
||||
* Translates keysymbols to keycodes for all bindings which use keysyms.
|
||||
*
|
||||
*/
|
||||
void translate_keysyms(void);
|
||||
|
||||
/**
|
||||
* Ungrabs all keys, to be called before re-grabbing the keys because of a
|
||||
* mapping_notify event or a configuration file reload
|
||||
|
@ -321,30 +330,11 @@ void translate_keysyms(void);
|
|||
*/
|
||||
void ungrab_all_keys(xcb_connection_t *conn);
|
||||
|
||||
/**
|
||||
* Grab the bound keys (tell X to send us keypress events for those keycodes)
|
||||
*
|
||||
*/
|
||||
void grab_all_keys(xcb_connection_t *conn, bool bind_mode_switch);
|
||||
|
||||
/**
|
||||
* Switches the key bindings to the given mode, if the mode exists
|
||||
*
|
||||
*/
|
||||
void switch_mode(const char *new_mode);
|
||||
|
||||
/**
|
||||
* Sends the current bar configuration as an event to all barconfig_update listeners.
|
||||
* This update mechnism currently only includes the hidden_state and the mode in the config.
|
||||
*
|
||||
*/void update_barconfig();
|
||||
|
||||
/**
|
||||
* Returns a pointer to the Binding with the specified modifiers and keycode
|
||||
* or NULL if no such binding exists.
|
||||
*
|
||||
*/
|
||||
Binding *get_binding(uint16_t modifiers, bool key_release, xcb_keycode_t keycode);
|
||||
void update_barconfig();
|
||||
|
||||
/**
|
||||
* Kills the configerror i3-nagbar process, if any.
|
||||
|
@ -356,5 +346,3 @@ Binding *get_binding(uint16_t modifiers, bool key_release, xcb_keycode_t keycode
|
|||
*
|
||||
*/
|
||||
void kill_configerror_nagbar(bool wait_for_it);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,13 +7,18 @@
|
|||
* config_directives.h: all config storing functions (see config_parser.c)
|
||||
*
|
||||
*/
|
||||
#ifndef I3_CONFIG_DIRECTIVES_H
|
||||
#define I3_CONFIG_DIRECTIVES_H
|
||||
#pragma once
|
||||
|
||||
#include "config_parser.h"
|
||||
|
||||
/**
|
||||
* A utility function to convert a string of modifiers to the corresponding bit
|
||||
* mask.
|
||||
*/
|
||||
uint32_t modifiers_from_str(const char *str);
|
||||
|
||||
/** The beginning of the prototype for every cfg_ function. */
|
||||
#define I3_CFG Match *current_match, struct ConfigResult *result
|
||||
#define I3_CFG Match *current_match, struct ConfigResultIR *result
|
||||
|
||||
/* Defines a configuration function, that is, anything that can be called by
|
||||
* using 'call cfg_foo()' in parser-specs/.*.spec. Useful so that we don’t need
|
||||
|
@ -41,6 +46,7 @@ CFGFUN(default_orientation, const char *orientation);
|
|||
CFGFUN(workspace_layout, const char *layout);
|
||||
CFGFUN(workspace_back_and_forth, const char *value);
|
||||
CFGFUN(focus_follows_mouse, const char *value);
|
||||
CFGFUN(mouse_warping, const char *value);
|
||||
CFGFUN(force_focus_wrapping, const char *value);
|
||||
CFGFUN(force_xinerama, const char *value);
|
||||
CFGFUN(fake_outputs, const char *outputs);
|
||||
|
@ -76,6 +82,5 @@ CFGFUN(bar_color_single, const char *colorclass, const char *color);
|
|||
CFGFUN(bar_status_command, const char *command);
|
||||
CFGFUN(bar_binding_mode_indicator, const char *value);
|
||||
CFGFUN(bar_workspace_buttons, const char *value);
|
||||
CFGFUN(bar_strip_workspace_numbers, const char *value);
|
||||
CFGFUN(bar_finish);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
* config_parser.h: config parser-related definitions
|
||||
*
|
||||
*/
|
||||
#ifndef I3_CONFIG_PARSER_H
|
||||
#define I3_CONFIG_PARSER_H
|
||||
#pragma once
|
||||
|
||||
#include <yajl/yajl_gen.h>
|
||||
|
||||
extern pid_t config_error_nagbar_pid;
|
||||
|
||||
/*
|
||||
* The result of a parse_config call. Currently unused, but the JSON output
|
||||
* will be useful in the future when we implement a config parsing IPC command.
|
||||
* 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
|
||||
* implement a config parsing IPC command.
|
||||
*
|
||||
*/
|
||||
struct ConfigResult {
|
||||
struct ConfigResultIR {
|
||||
/* The JSON generator to append a reply to. */
|
||||
yajl_gen json_gen;
|
||||
|
||||
|
@ -29,7 +29,7 @@ struct ConfigResult {
|
|||
int next_state;
|
||||
};
|
||||
|
||||
struct ConfigResult *parse_config(const char *input, struct context *context);
|
||||
struct ConfigResultIR *parse_config(const char *input, struct context *context);
|
||||
|
||||
/**
|
||||
* Parses the given file by first replacing the variables, then calling
|
||||
|
@ -37,5 +37,3 @@ struct ConfigResult *parse_config(const char *input, struct context *context);
|
|||
*
|
||||
*/
|
||||
void parse_file(const char *f);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* include/data.h: This file defines all data structures used by i3
|
||||
*
|
||||
*/
|
||||
#ifndef I3_DATA_H
|
||||
#define I3_DATA_H
|
||||
#pragma once
|
||||
|
||||
#define SN_API_NOT_YET_FROZEN 1
|
||||
#include <libsn/sn-launcher.h>
|
||||
|
@ -92,6 +91,22 @@ typedef enum {
|
|||
L_SPLITH = 6
|
||||
} layout_t;
|
||||
|
||||
/**
|
||||
* Binding input types. See Binding::input_type.
|
||||
*/
|
||||
typedef enum {
|
||||
B_KEYBOARD = 0,
|
||||
B_MOUSE = 1
|
||||
} input_type_t;
|
||||
|
||||
/**
|
||||
* Mouse pointer warping modes.
|
||||
*/
|
||||
typedef enum {
|
||||
POINTER_WARPING_OUTPUT = 0,
|
||||
POINTER_WARPING_NONE = 1
|
||||
} warping_t;
|
||||
|
||||
/**
|
||||
* Stores a rectangle, for example the size of a window, the child window etc.
|
||||
* It needs to be packed so that the compiler will not add any padding bytes.
|
||||
|
@ -151,7 +166,7 @@ struct deco_render_params {
|
|||
};
|
||||
|
||||
/**
|
||||
* Stores which workspace (by name) goes to which output.
|
||||
* Stores which workspace (by name or number) goes to which output.
|
||||
*
|
||||
*/
|
||||
struct Workspace_Assignment {
|
||||
|
@ -214,6 +229,10 @@ struct regex {
|
|||
*
|
||||
*/
|
||||
struct Binding {
|
||||
/* The type of input this binding is for. (Mouse bindings are not yet
|
||||
* implemented. All bindings are currently assumed to be keyboard bindings.) */
|
||||
input_type_t input_type;
|
||||
|
||||
/** If true, the binding should be executed upon a KeyRelease event, not a
|
||||
* KeyPress (the default). */
|
||||
enum {
|
||||
|
@ -374,7 +393,7 @@ struct Match {
|
|||
struct regex *class;
|
||||
struct regex *instance;
|
||||
struct regex *mark;
|
||||
struct regex *role;
|
||||
struct regex *window_role;
|
||||
enum {
|
||||
U_DONTCHECK = -1,
|
||||
U_LATEST = 0,
|
||||
|
@ -450,6 +469,9 @@ struct Assignment {
|
|||
TAILQ_ENTRY(Assignment) assignments;
|
||||
};
|
||||
|
||||
/** Fullscreen modes. Used by Con.fullscreen_mode. */
|
||||
typedef enum { CF_NONE = 0, CF_OUTPUT = 1, CF_GLOBAL = 2 } fullscreen_mode_t;
|
||||
|
||||
/**
|
||||
* A 'Con' represents everything from the X11 root window down to a single X11 window.
|
||||
*
|
||||
|
@ -538,7 +560,7 @@ struct Con {
|
|||
|
||||
TAILQ_HEAD(swallow_head, Match) swallow_head;
|
||||
|
||||
enum { CF_NONE = 0, CF_OUTPUT = 1, CF_GLOBAL = 2 } fullscreen_mode;
|
||||
fullscreen_mode_t fullscreen_mode;
|
||||
/* layout is the layout of this container: one of split[v|h], stacked or
|
||||
* tabbed. Special containers in the tree (above workspaces) have special
|
||||
* layouts like dockarea or output.
|
||||
|
@ -595,5 +617,3 @@ struct Con {
|
|||
/* Depth of the container window */
|
||||
uint16_t depth;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
* events. This code is from xcb-util.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_DEBUG_H
|
||||
#define I3_DEBUG_H
|
||||
#pragma once
|
||||
|
||||
int handle_event(void *ignored, xcb_connection_t *c, xcb_generic_event_t *e);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* display_version.c: displays the running i3 version, runs as part of
|
||||
* i3 --moreversion.
|
||||
*/
|
||||
#ifndef I3_DISPLAY_VERSION_H
|
||||
#define I3_DISPLAY_VERSION_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Connects to i3 to find out the currently running version. Useful since it
|
||||
|
@ -23,5 +22,3 @@
|
|||
*
|
||||
*/
|
||||
void display_running_version(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* ewmh.c: Get/set certain EWMH properties easily.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_EWMH_C
|
||||
#define I3_EWMH_C
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Updates _NET_CURRENT_DESKTOP with the current desktop number.
|
||||
|
@ -28,6 +27,11 @@ void ewmh_update_current_desktop(void);
|
|||
*/
|
||||
void ewmh_update_active_window(xcb_window_t window);
|
||||
|
||||
/**
|
||||
* Updates the _NET_CLIENT_LIST hint. Used for window listers.
|
||||
*/
|
||||
void ewmh_update_client_list(xcb_window_t *list, int num_windows);
|
||||
|
||||
/**
|
||||
* Updates the _NET_CLIENT_LIST_STACKING hint. Necessary to move tabs in
|
||||
* Chromium correctly.
|
||||
|
@ -62,5 +66,3 @@ void ewmh_setup_hints(void);
|
|||
*
|
||||
*/
|
||||
void ewmh_update_workarea(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
* which don’t support multi-monitor in a useful way) and for our testsuite.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_FAKE_OUTPUTS_H
|
||||
#define I3_FAKE_OUTPUTS_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Creates outputs according to the given specification.
|
||||
|
@ -19,5 +18,3 @@
|
|||
*
|
||||
*/
|
||||
void fake_outputs_init(const char *output_spec);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* floating.c: Floating windows.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_FLOATING_H
|
||||
#define I3_FLOATING_H
|
||||
#pragma once
|
||||
|
||||
#include "tree.h"
|
||||
|
||||
|
@ -183,5 +182,3 @@ void floating_reposition(Con *con, Rect newrect);
|
|||
*
|
||||
*/
|
||||
void floating_fix_coordinates(Con *con, Rect *old_rect, Rect *new_rect);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
* …).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_HANDLERS_H
|
||||
#define I3_HANDLERS_H
|
||||
#pragma once
|
||||
|
||||
#include <xcb/randr.h>
|
||||
|
||||
|
@ -63,5 +62,3 @@ int handle_window_type(void *data, xcb_connection_t *conn, uint8_t state,
|
|||
xcb_window_t window, xcb_atom_t atom,
|
||||
xcb_get_property_reply_t *property);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* i3.h: global variables that are used all over i3.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_I3_H
|
||||
#define I3_I3_H
|
||||
#pragma once
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
@ -62,5 +61,3 @@ extern bool xcursor_supported, xkb_supported;
|
|||
extern xcb_window_t root;
|
||||
extern struct ev_loop *main_loop;
|
||||
extern bool only_check_config;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
* for the IPC interface to i3 (see docs/ipc for more information).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_I3_IPC_H
|
||||
#define I3_I3_IPC_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -101,5 +100,3 @@ typedef struct i3_ipc_header {
|
|||
|
||||
/** Bar config update will be triggered to update the bar config */
|
||||
#define I3_IPC_EVENT_BARCONFIG_UPDATE (I3_IPC_EVENT_MASK | 4)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* ipc.c: UNIX domain socket IPC (initialization, client handling, protocol).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_IPC_H
|
||||
#define I3_IPC_H
|
||||
#pragma once
|
||||
|
||||
#include <ev.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -17,6 +16,7 @@
|
|||
|
||||
#include "data.h"
|
||||
#include "tree.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "i3/ipc.h"
|
||||
|
||||
|
@ -89,4 +89,13 @@ void dump_node(yajl_gen gen, Con *con, bool inplace_restart);
|
|||
*/
|
||||
void ipc_send_workspace_focus_event(Con *current, Con *old);
|
||||
|
||||
#endif
|
||||
/**
|
||||
* For the window events we send, along the usual "change" field,
|
||||
* also the window container, in "container".
|
||||
*/
|
||||
void ipc_send_window_event(const char *property, Con *con);
|
||||
|
||||
/**
|
||||
* For the barconfig update events, we send the serialized barconfig.
|
||||
*/
|
||||
void ipc_send_barconfig_update_event(Barconfig *barconfig);
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
* key_press.c: key press handler
|
||||
*
|
||||
*/
|
||||
#ifndef I3_KEY_PRESS_H
|
||||
#define I3_KEY_PRESS_H
|
||||
|
||||
extern pid_t command_error_nagbar_pid;
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* There was a key press. We compare this key code with our bindings table and pass
|
||||
|
@ -30,5 +27,3 @@ void handle_key_press(xcb_key_press_event_t *event);
|
|||
*
|
||||
*/
|
||||
void kill_commanderror_nagbar(bool wait_for_it);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
* as i3-msg, i3-config-wizard, …
|
||||
*
|
||||
*/
|
||||
#ifndef I3_LIBI3_H
|
||||
#define I3_LIBI3_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -383,4 +382,10 @@ char *get_process_filename(const char *prefix);
|
|||
*/
|
||||
char *get_exe_path(const char *argv0);
|
||||
|
||||
#endif
|
||||
/**
|
||||
* Convert a logical amount of pixels (e.g. 2 pixels on a “standard” 96 DPI
|
||||
* screen) to a corresponding amount of physical pixels on a standard or retina
|
||||
* screen, e.g. 5 pixels on a 227 DPI MacBook Pro 13" Retina screen.
|
||||
*
|
||||
*/
|
||||
int logical_px(const int logical);
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
* restart.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_LOAD_LAYOUT_H
|
||||
#define I3_LOAD_LAYOUT_H
|
||||
#pragma once
|
||||
|
||||
void tree_append_json(const char *filename);
|
||||
|
||||
#endif
|
||||
void tree_append_json(Con *con, const char *filename, char **errormsg);
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* log.c: Logging functions.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_LOG_H
|
||||
#define I3_LOG_H
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -102,5 +101,3 @@ void verboselog(char *fmt, ...)
|
|||
* failures. This function is invoked automatically when exiting.
|
||||
*/
|
||||
void purge_zerobyte_logfile(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* vim:ts=4:sw=4:expandtab
|
||||
*
|
||||
* i3 - an improved dynamic tiling window manager
|
||||
* © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE)
|
||||
*
|
||||
* main.c: Initialization, main loop
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Enable or disable the main X11 event handling function.
|
||||
* This is used by drag_pointer() which has its own, modal event handler, which
|
||||
* takes precedence over the normal event handler.
|
||||
*
|
||||
*/
|
||||
void main_set_x11_cb(bool enable);
|
|
@ -7,8 +7,7 @@
|
|||
* manage.c: Initially managing new windows (or existing ones on restart).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_MANAGE_H
|
||||
#define I3_MANAGE_H
|
||||
#pragma once
|
||||
|
||||
#include "data.h"
|
||||
|
||||
|
@ -52,4 +51,3 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
|||
uint32_t border_width);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
* match_matches_window() to find the windows affected by this command.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_MATCH_H
|
||||
#define I3_MATCH_H
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Initializes the Match data structure. This function is necessary because the
|
||||
|
@ -46,5 +45,3 @@ bool match_matches_window(Match *match, i3Window *window);
|
|||
*
|
||||
*/
|
||||
void match_free(Match *match);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* move.c: Moving containers into some direction.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_MOVE_H
|
||||
#define I3_MOVE_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Moves the current container in the given direction (TOK_LEFT, TOK_RIGHT,
|
||||
|
@ -16,5 +15,3 @@
|
|||
*
|
||||
*/
|
||||
void tree_move(int direction);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,13 +7,10 @@
|
|||
* output.c: Output (monitor) related functions.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_OUTPUT_H
|
||||
#define I3_OUTPUT_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Returns the output container below the given output container.
|
||||
*
|
||||
*/
|
||||
Con *output_get_content(Con *output);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,8 +32,7 @@
|
|||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
|
@ -536,5 +535,3 @@ struct { \
|
|||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
* (take your time to read it completely, it answers all questions).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_RANDR_H
|
||||
#define I3_RANDR_H
|
||||
#pragma once
|
||||
|
||||
#include "data.h"
|
||||
#include <xcb/randr.h>
|
||||
|
@ -85,7 +84,7 @@ Output *get_output_by_name(const char *name);
|
|||
* if there is no output which contains these coordinates.
|
||||
*
|
||||
*/
|
||||
Output *get_output_containing(int x, int y);
|
||||
Output *get_output_containing(unsigned int x, unsigned int y);
|
||||
|
||||
/*
|
||||
* In contained_by_output, we check if any active output contains part of the container.
|
||||
|
@ -121,5 +120,3 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far
|
|||
*
|
||||
*/
|
||||
Output *get_output_next_wrap(direction_t direction, Output *current);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* regex.c: Interface to libPCRE (perl compatible regular expressions).
|
||||
*
|
||||
*/
|
||||
#ifndef I3_REGEX_H
|
||||
#define I3_REGEX_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Creates a new 'regex' struct containing the given pattern and a PCRE
|
||||
|
@ -35,5 +34,3 @@ void regex_free(struct regex *regex);
|
|||
*
|
||||
*/
|
||||
bool regex_matches(struct regex *regex, const char *input);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
* various rects. Needs to be pushed to X11 (see x.c) to be visible.
|
||||
*
|
||||
*/
|
||||
#ifndef I3_RENDER_H
|
||||
#define I3_RENDER_H
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* "Renders" the given container (and its children), meaning that all rects are
|
||||
|
@ -25,5 +24,3 @@ void render_con(Con *con, bool render_fullscreen);
|
|||
* Returns the height for the decorations
|
||||
*/
|
||||
int render_deco_height(void);
|
||||
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue