Merge branch 'next'

This commit is contained in:
Michael Stapelberg 2014-06-15 19:14:36 +02:00
commit 34f6f185bf
226 changed files with 8726 additions and 5320 deletions

11
.clang-format Normal file
View File

@ -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
View File

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

View File

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

View File

@ -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-*: dont 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
• Dont 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: Dont 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

View File

@ -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 its 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 its unneeded (after urgency hints)
• i3-config-wizard: use the level 0 keysym whenever its 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 doesnt 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 wont 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, dont 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)
• Dont allow ConfigureRequests while in fullscreen (fixes a compatibility
issue with gnome-terminal and xfces terminal)
• Fix flickering with 1pixel border tabbed layouts
• Use _exit() instead of exit() when i3 utility programs cannot be executed
• Dont 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

View File

@ -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 dont 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 theyre 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: dont 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, dont 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: dont send workspace command when at beginning/end of workspace
• Bugfix: force rendering when the parents 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

View File

@ -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: dont 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: dont 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

View File

@ -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: Dont 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

View File

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

View File

@ -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”
• dont 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

View File

@ -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: dont 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

View File

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

138
RELEASE-NOTES-4.8 Normal file
View File

@ -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: dont 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
• dont 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
• dont 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
• dont overwrite the original size of floating windows when changing border
• dont errnously render floating fullscreen windows during restart
• ensure floating windows dont drop out of fullscreen when restarting
• dont overwrite the windows 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

View File

@ -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) doesnt have librt
else ifneq ($(UNAME),OpenBSD)
# Darwin (Mac OS X) and OpenBSD do not have librt
LIBS += -lrt
endif

View File

@ -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, dont 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.

24
debian/changelog vendored
View File

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

4
debian/control vendored
View File

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

2
debian/i3-wm.docs vendored
View File

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

1
debian/i3-wm.links vendored Normal file
View File

@ -0,0 +1 @@
usr/share/man/man1/i3.1.gz usr/share/man/man1/i3-with-shmlog.1.gz

2
debian/rules vendored
View File

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

View File

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

View File

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

View File

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

View File

@ -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*:

View File

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

233
docs/layout-saving Normal file
View File

@ -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 i3s 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 i3s 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 well 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.

BIN
docs/layout-saving-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -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 windows 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 i3s layout tree, the
workspace node. By default, the workspace nodes orientation is +horizontal+.
Now you move one of these terminals down (+$mod+k+ by default). The workspace
nodes 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 nodes 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 dont provide support for
reconfiguring your screens on the fly (they are read only once on startup and
thats 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.

View File

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

View File

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

View File

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

View File

@ -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.
# Im 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});
# Dont 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');
# Dont 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;

View File

@ -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",

View File

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

View File

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

View File

@ -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.");
}

View File

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

View File

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

288
i3-save-tree Executable file
View File

@ -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::XSs 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 outputs 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

View File

@ -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 doesnt 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 windows width.
# Pressing up will shrink the windows height.
# Pressing down will grow the windows 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

View File

@ -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 doesnt scale on retina/hidpi displays.
# Use Mouse+$mod to drag floating windows to their wanted position
floating_modifier $mod

View File

@ -2,4 +2,6 @@
Name=i3
Comment=improved dynamic tiling window manager
Exec=i3
TryExec=i3
Type=Application
X-LightDM-DesktopName=i3

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */

View File

@ -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':

View File

@ -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 *)&params);
handle = yajl_alloc(&mode_callbacks, &parse_conf, NULL, (void*) &params);
#else
handle = yajl_alloc(&mode_callbacks, NULL, (void*) &params);
#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);

View File

@ -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 *)&params);
handle = yajl_alloc(&outputs_callbacks, &parse_conf, NULL, (void*) &params);
#else
handle = yajl_alloc(&outputs_callbacks, NULL, (void*) &params);
#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;
}

View File

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

View File

@ -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 *)&params);
handle = yajl_alloc(&workspaces_callbacks, &parse_conf, NULL, (void*) &params);
#else
handle = yajl_alloc(&workspaces_callbacks, NULL, (void*) &params);
#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);
}

View File

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

View File

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

View File

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

View File

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

69
include/bindings.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,8 +8,7 @@
* which dont 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

18
include/main.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

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

View File

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