<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="generator" content="AsciiDoc 8.5.2" /> <title>External workspace bars</title> <style type="text/css"> /* Debug borders */ p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { /* border: 1px solid red; */ } body { margin: 1em 5% 1em 5%; } a { color: blue; text-decoration: underline; } a:visited { color: fuchsia; } em { font-style: italic; color: navy; } strong { font-weight: bold; color: #083194; } tt { color: navy; } h1, h2, h3, h4, h5, h6 { color: #527bbd; font-family: sans-serif; margin-top: 1.2em; margin-bottom: 0.5em; line-height: 1.3; } h1, h2, h3 { border-bottom: 2px solid silver; } h2 { padding-top: 0.5em; } h3 { float: left; } h3 + * { clear: left; } div.sectionbody { font-family: serif; margin-left: 0; } hr { border: 1px solid silver; } p { margin-top: 0.5em; margin-bottom: 0.5em; } ul, ol, li > p { margin-top: 0; } pre { padding: 0; margin: 0; } span#author { color: #527bbd; font-family: sans-serif; font-weight: bold; font-size: 1.1em; } span#email { } span#revnumber, span#revdate, span#revremark { font-family: sans-serif; } div#footer { font-family: sans-serif; font-size: small; border-top: 2px solid silver; padding-top: 0.5em; margin-top: 4.0em; } div#footer-text { float: left; padding-bottom: 0.5em; } div#footer-badges { float: right; padding-bottom: 0.5em; } div#preamble { margin-top: 1.5em; margin-bottom: 1.5em; } div.tableblock, div.imageblock, div.exampleblock, div.verseblock, div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, div.admonitionblock { margin-top: 1.0em; margin-bottom: 1.5em; } div.admonitionblock { margin-top: 2.0em; margin-bottom: 2.0em; margin-right: 10%; color: #606060; } div.content { /* Block element content. */ padding: 0; } /* Block element titles. */ div.title, caption.title { color: #527bbd; font-family: sans-serif; font-weight: bold; text-align: left; margin-top: 1.0em; margin-bottom: 0.5em; } div.title + * { margin-top: 0; } td div.title:first-child { margin-top: 0.0em; } div.content div.title:first-child { margin-top: 0.0em; } div.content + div.title { margin-top: 0.0em; } div.sidebarblock > div.content { background: #ffffee; border: 1px solid silver; padding: 0.5em; } div.listingblock > div.content { border: 1px solid silver; background: #f4f4f4; padding: 0.5em; } div.quoteblock, div.verseblock { padding-left: 1.0em; margin-left: 1.0em; margin-right: 10%; border-left: 5px solid #dddddd; color: #777777; } div.quoteblock > div.attribution { padding-top: 0.5em; text-align: right; } div.verseblock > div.content { white-space: pre; } div.verseblock > div.attribution { padding-top: 0.75em; text-align: left; } /* DEPRECATED: Pre version 8.2.7 verse style literal block. */ div.verseblock + div.attribution { text-align: left; } div.admonitionblock .icon { vertical-align: top; font-size: 1.1em; font-weight: bold; text-decoration: underline; color: #527bbd; padding-right: 0.5em; } div.admonitionblock td.content { padding-left: 0.5em; border-left: 3px solid #dddddd; } div.exampleblock > div.content { border-left: 3px solid #dddddd; padding-left: 0.5em; } div.imageblock div.content { padding-left: 0; } span.image img { border-style: none; } a.image:visited { color: white; } dl { margin-top: 0.8em; margin-bottom: 0.8em; } dt { margin-top: 0.5em; margin-bottom: 0; font-style: normal; color: navy; } dd > *:first-child { margin-top: 0.1em; } ul, ol { list-style-position: outside; } ol.arabic { list-style-type: decimal; } ol.loweralpha { list-style-type: lower-alpha; } ol.upperalpha { list-style-type: upper-alpha; } ol.lowerroman { list-style-type: lower-roman; } ol.upperroman { list-style-type: upper-roman; } div.compact ul, div.compact ol, div.compact p, div.compact p, div.compact div, div.compact div { margin-top: 0.1em; margin-bottom: 0.1em; } div.tableblock > table { border: 3px solid #527bbd; } thead, p.table.header { font-family: sans-serif; font-weight: bold; } tfoot { font-weight: bold; } td > div.verse { white-space: pre; } p.table { margin-top: 0; } /* Because the table frame attribute is overriden by CSS in most browsers. */ div.tableblock > table[frame="void"] { border-style: none; } div.tableblock > table[frame="hsides"] { border-left-style: none; border-right-style: none; } div.tableblock > table[frame="vsides"] { border-top-style: none; border-bottom-style: none; } div.hdlist { margin-top: 0.8em; margin-bottom: 0.8em; } div.hdlist tr { padding-bottom: 15px; } dt.hdlist1.strong, td.hdlist1.strong { font-weight: bold; } td.hdlist1 { vertical-align: top; font-style: normal; padding-right: 0.8em; color: navy; } td.hdlist2 { vertical-align: top; } div.hdlist.compact tr { margin: 0; padding-bottom: 0; } .comment { background: yellow; } .footnote, .footnoteref { font-size: 0.8em; } span.footnote, span.footnoteref { vertical-align: super; } #footnotes { margin: 20px 0 20px 0; padding: 7px 0 0 0; } #footnotes div.footnote { margin: 0 0 5px 0; } #footnotes hr { border: none; border-top: 1px solid silver; height: 1px; text-align: left; margin-left: 0; width: 20%; min-width: 100px; } @media print { div#footer-badges { display: none; } } div#toc { margin-bottom: 2.5em; } div#toctitle { color: #527bbd; font-family: sans-serif; font-size: 1.1em; font-weight: bold; margin-top: 1.0em; margin-bottom: 0.1em; } div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { margin-top: 0; margin-bottom: 0; } div.toclevel2 { margin-left: 2em; font-size: 0.9em; } div.toclevel3 { margin-left: 4em; font-size: 0.9em; } div.toclevel4 { margin-left: 6em; font-size: 0.9em; } /* Workarounds for IE6's broken and incomplete CSS2. */ div.sidebar-content { background: #ffffee; border: 1px solid silver; padding: 0.5em; } div.sidebar-title, div.image-title { color: #527bbd; font-family: sans-serif; font-weight: bold; margin-top: 0.0em; margin-bottom: 0.5em; } div.listingblock div.content { border: 1px solid silver; background: #f4f4f4; padding: 0.5em; } div.quoteblock-attribution { padding-top: 0.5em; text-align: right; } div.verseblock-content { white-space: pre; } div.verseblock-attribution { padding-top: 0.75em; text-align: left; } div.exampleblock-content { border-left: 3px solid #dddddd; padding-left: 0.5em; } /* IE6 sets dynamically generated links as visited. */ div#toc a:visited { color: blue; } </style> <script type="text/javascript"> /*<![CDATA[*/ window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);} var asciidoc = { // Namespace. ///////////////////////////////////////////////////////////////////// // Table Of Contents generator ///////////////////////////////////////////////////////////////////// /* Author: Mihai Bazon, September 2002 * http://students.infoiasi.ro/~mishoo * * Table Of Content generator * Version: 0.4 * * Feel free to use this script under the terms of the GNU General Public * License, as long as you do not remove or alter this notice. */ /* modified by Troy D. Hanson, September 2006. License: GPL */ /* modified by Stuart Rackham, 2006, 2009. License: GPL */ // toclevels = 1..4. toc: function (toclevels) { function getText(el) { var text = ""; for (var i = el.firstChild; i != null; i = i.nextSibling) { if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants. text += i.data; else if (i.firstChild != null) text += getText(i); } return text; } function TocEntry(el, text, toclevel) { this.element = el; this.text = text; this.toclevel = toclevel; } function tocEntries(el, toclevels) { var result = new Array; var re = new RegExp('[hH]([2-'+(toclevels+1)+'])'); // Function that scans the DOM tree for header elements (the DOM2 // nodeIterator API would be a better technique but not supported by all // browsers). var iterate = function (el) { for (var i = el.firstChild; i != null; i = i.nextSibling) { if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { var mo = re.exec(i.tagName); if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { result[result.length] = new TocEntry(i, getText(i), mo[1]-1); } iterate(i); } } } iterate(el); return result; } var toc = document.getElementById("toc"); var entries = tocEntries(document.getElementById("content"), toclevels); for (var i = 0; i < entries.length; ++i) { var entry = entries[i]; if (entry.element.id == "") entry.element.id = "_toc_" + i; var a = document.createElement("a"); a.href = "#" + entry.element.id; a.appendChild(document.createTextNode(entry.text)); var div = document.createElement("div"); div.appendChild(a); div.className = "toclevel" + entry.toclevel; toc.appendChild(div); } if (entries.length == 0) toc.parentNode.removeChild(toc); }, ///////////////////////////////////////////////////////////////////// // Footnotes generator ///////////////////////////////////////////////////////////////////// /* Based on footnote generation code from: * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html */ footnotes: function () { var cont = document.getElementById("content"); var noteholder = document.getElementById("footnotes"); var spans = cont.getElementsByTagName("span"); var refs = {}; var n = 0; for (i=0; i<spans.length; i++) { if (spans[i].className == "footnote") { n++; // Use [\s\S] in place of . so multi-line matches work. // Because JavaScript has no s (dotall) regex flag. note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; noteholder.innerHTML += "<div class='footnote' id='_footnote_" + n + "'>" + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + n + "</a>. " + note + "</div>"; spans[i].innerHTML = "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + "' title='View footnote' class='footnote'>" + n + "</a>]"; var id =spans[i].getAttribute("id"); if (id != null) refs["#"+id] = n; } } if (n == 0) noteholder.parentNode.removeChild(noteholder); else { // Process footnoterefs. for (i=0; i<spans.length; i++) { if (spans[i].className == "footnoteref") { var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); href = href.match(/#.*/)[0]; // Because IE return full URL. n = refs[href]; spans[i].innerHTML = "[<a href='#_footnote_" + n + "' title='View footnote' class='footnote'>" + n + "</a>]"; } } } } } /*]]>*/ </script> </head> <body> <div id="header"> <h1>External workspace bars</h1> <span id="author">Michael Stapelberg</span><br /> <span id="email"><tt><<a href="mailto:michael+i3@stapelberg.de">michael+i3@stapelberg.de</a>></tt></span><br /> <span id="revdate">May 2010</span> <div id="toc"> <div id="toctitle">Table of Contents</div> <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript> </div> </div> <div id="content"> <div id="preamble"> <div class="sectionbody"> <div class="paragraph"><p>This document describes why the internal workspace bar is minimal and how an external workspace bar can be used. It explains the concepts using <tt>i3-wsbar</tt> as the reference implementation.</p></div> </div> </div> <h2 id="_internal_and_external_bars">1. Internal and external bars</h2> <div class="sectionbody"> <div class="paragraph"><p>The internal workspace bar of i3 is meant to be a reasonable default so that you can use i3 without having too much hassle when setting it up. It is quite simple and intended to stay this way. So, there is no way to display your own information in this bar (unlike dwm, wmii, awesome, …).</p></div> <div class="paragraph"><p>We chose not to implement such a mechanism because that would be duplicating already existing functionality of tools such as dzen2, xmobar and similar. Instead, you should disable the internal bar and use an external workspace bar (which communicates with i3 through its IPC interface).</p></div> </div> <h2 id="_dock_mode">2. dock mode</h2> <div class="sectionbody"> <div class="paragraph"><p>You typically want to see the same workspace bar on every workspace on a specific screen. Also, you don’t want to place the workspace bar somewhere in your layout by hand. This is where dock mode comes in: When a program sets the appropriate hint (_NET_WM_WINDOW_TYPE_DOCK), it will be managed in dock mode by i3. That means it will be placed at the bottom of the screen (while other edges of the screen are possible in the NetWM standard, this is not yet implemented in i3), it will not overlap any other window and it will be on every workspace for the specific screen it was placed on initially.</p></div> </div> <h2 id="_the_ipc_interface">3. The IPC interface</h2> <div class="sectionbody"> <div class="paragraph"><p>In the context of using an external workspace bar, the IPC interface needs to provide the bar program with the current workspaces and output (as in VGA-1, LVDS-1, …) configuration. In the other direction, the program has to be able to switch to specific workspaces.</p></div> <div class="paragraph"><p>By default, the IPC interface is enabled and places its UNIX socket in <tt>~/.i3/ipc.sock</tt>.</p></div> <div class="paragraph"><p>To learn more about the protocol which is used for IPC, see <tt>docs/ipc</tt>.</p></div> </div> <h2 id="_output_changes_on_the_fly">4. Output changes (on-the-fly)</h2> <div class="sectionbody"> <div class="paragraph"><p>i3 implements the RandR API and can handle changing outputs quite well. So, an external workspace bar implementation needs to make sure that when you change the resolution of any of your screens (or enable/disable an output), the bars will be adjusted properly.</p></div> </div> <h2 id="_i3_wsbar_the_reference_implementation">5. i3-wsbar, the reference implementation</h2> <div class="sectionbody"> <div class="paragraph"><p>Please keep in mind that <tt>i3-wsbar</tt> is just a reference implementation. It is shipped with i3 to have a reasonable default. Thus, <tt>i3-wsbar</tt> is designed to work well with dzen2 and there are no plans to make it more generic.</p></div> <h3 id="_the_big_picture">5.1. The big picture</h3><div style="clear:left"></div> <div class="paragraph"><p>The most common reason to use an external workspace bar is to integrate system information such as what <tt>i3status</tt> provides into the workspace bar (to save screen space). So, we have <tt>i3status</tt> or a similar program, which only provides text output (formatted in some way). To display this text nicely on the screen, there are programs such as dzen2, xmobar and similar. We will stick to dzen2 from here on. So, we have the output of i3status, which needs to go into dzen2 somehow. But we also want to display the list of workspaces. <tt>i3-wsbar</tt> takes input on stdin, combines it with a formatted workspace list and pipes it to dzen2.</p></div> <div class="paragraph"><p>Please note that <tt>i3-wsbar</tt> does not print its output to stdout. Instead, it launches the dzen2 instances on its own. This is necessary to handle changes in the available outputs (to place a new dzen2 on a new screen for example).</p></div> <div class="paragraph"><p><span class="image"> <a class="image" href="wsbar.png"> <img src="wsbar.png" alt="Overview" /> </a> </span></p></div> <h3 id="_running_i3_wsbar">5.2. Running i3-wsbar</h3><div style="clear:left"></div> <div class="paragraph"><p>The most simple usage of i3-wsbar looks like this:</p></div> <div class="listingblock"> <div class="content"> <pre><tt>i3-wsbar -c "dzen2 -x %x -dock"</tt></pre> </div></div> <div class="paragraph"><p>The <tt>%x</tt> in the command name will be replaced by the X position of the output for which this workspace bar is running. i3 will automatically place the workspace bar on the correct output when dzen2 is started in dock mode. The bar which you will see should look exactly like the internal bar of i3.</p></div> <div class="paragraph"><p>To actually get a benefit, you want to give <tt>i3-wsbar</tt> some input:</p></div> <div class="listingblock"> <div class="content"> <pre><tt>i3status | i3-wsbar -c "dzen2 -x %x -dock"</tt></pre> </div></div> <div class="paragraph"><p>It is recommended to place the above command in your i3 configuration file to start it automatically with i3.</p></div> </div> </div> <div id="footnotes"><hr /></div> <div id="footer"> <div id="footer-text"> Last updated 2010-06-09 09:57:43 CEST </div> </div> </body> </html>