tag:blogger.com,1999:blog-70394736042876827522024-03-12T20:51:50.514-07:00Mathematical Coffeemathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.comBlogger28125tag:blogger.com,1999:blog-7039473604287682752.post-4771437440662161942014-07-13T19:48:00.001-07:002014-07-13T19:51:52.108-07:00Junethack 2014 is over!<div id="TOC">
<p> This is a rather long post about Junethack (mainly to do with improving unique deaths), so I've provided a table of contents.
<ul>
<li><a href="#some-fun">Some fun</a></li>
<li><a href="#some-fun-death-analysis">Some fun death analysis</a><ul>
<li><a href="#favoured-variants">Favoured variants</a></li>
<li><a href="#favoured-classes">Favoured classes</a></li>
<li><a href="#deadliest-deaths">Deadliest deaths</a></li>
<li><a href="#most-common-deaths-after-cleaning">Most common deaths (after cleaning)</a></li>
</ul></li>
<li><a href="#ideas-for-next-time-unique-deaths">Ideas for next time (unique deaths)</a><ul>
<li><a href="#grunthacks-killed-by-a-falling-foo-death">GruntHack's "killed by a falling {foo}" death</a></li>
<li><a href="#shopkeeper-deaths">Shopkeeper deaths</a></li>
<li><a href="#grunthacks-killed-by-a-foos-bar-deaths">GruntHack's "killed by a {foo}'s {bar}" deaths</a></li>
<li><a href="#deaths-of-the-form-killed-by-foo-while-bar">Deaths of the form "killed by {foo}, while {bar}"</a></li>
<li><a href="#killed-by-a-ghost-of-playername">Killed by a ghost of {playername}</a></li>
<li><a href="#food-poisoning">Food poisoning</a></li>
<li><a href="#deities">Deities</a></li>
<li><a href="#minions-of-deities">Minions of deities</a></li>
<li><a href="#priests-and-priestesses">Priests and priestesses</a></li>
<li><a href="#grunthacks-change-of-the-kill-prefix">GruntHack's change of the kill prefix</a></li>
<li><a href="#grunthacks-racial-monsters">GruntHack's Racial monsters</a></li>
</ul></li>
<li><a href="#appendix-implementation">Appendix: Implementation</a></li>
<li><a href="#appendix-filter-unique-deaths">Appendix: filter unique deaths</a></li>
<li><a href="#appendix-data">Appendix: data</a><ul>
<li><a href="#deaths-table"><code>deaths</code> table</a></li>
<li><a href="#users-table"><code>users</code> table</a></li>
<li><a href="#junethack.users-table"><code>junethack.users</code> table</a></li>
<li><a href="#clans-table"><code>clans</code> table</a></li>
</ul></li>
</ul>
</div>
<p>June is finally over, and with it <a href="http://junethack.de">Junethack</a>. Check out the individual scoreboard <a href="https://junethack.de/scoreboard">here</a> and the clan scoreboard <a href="https://junethack.de/clan_competition">here</a>.</p>
<p>I managed to take out the most unique deaths trophy (<a href="https://junethack.de/clan/overcaffeinated">my clan</a> consisted of just me), and also to ascend once. I had planned to ascend more often, but <a href="https://junethack.de/clan/demilichens">clan demilichens</a> put up some pretty fierce competition for unique deaths, so I had to focus solely on it.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-Hb7_3NedONE/U8M-t8N2m3I/AAAAAAAAEHc/x24f9idYVsc/s1600/victory_avatar.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-Hb7_3NedONE/U8M-t8N2m3I/AAAAAAAAEHc/x24f9idYVsc/s1600/victory_avatar.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Woohoo!</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-AZ5HZAMVKBE/U8M-7R9X0aI/AAAAAAAAEHg/mdXzDJpdFrc/s1600/most_unique_deaths.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-AZ5HZAMVKBE/U8M-7R9X0aI/AAAAAAAAEHg/mdXzDJpdFrc/s640/most_unique_deaths.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">clan demilichens put up very strong competition</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-nJDhgtOPrPw/U8M_KetC_oI/AAAAAAAAEHo/qbY2fBxUgs0/s1600/fastest_ascension_nethack4.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-nJDhgtOPrPw/U8M_KetC_oI/AAAAAAAAEHo/qbY2fBxUgs0/s640/fastest_ascension_nethack4.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Somehow I managed to get the second fastest ascension (by turns) for nethack4</td></tr>
</tbody></table>
<p>A big thanks to all the organisers of Junethack, and also to member jonadab (from demilichens) who was the main unique deaths player from that clanned, and with whom it was very fun competing.</p>
<p>I definitely had a lot of fun going for unique deaths (after 500 or so they start to become quite hard to get, short of startscumming for wands of polymorph which I didn't do (it is perfectly acceptable, but I have a personal preference not to)).</p>
<p>I have a few comments to make, most (all) of which relate to unique deaths. You can see a list of all unique deaths attained throughout the month <a href="https://junethack.de/deaths#unique_deaths">here</a>.</p>
<p>I was personally proud of these deaths:</p>
<ul>
<li>"killed by touching {artifact}", where I managed to get every aligned artifact (not just Quest artifacts). Looots of fountain quaffing. I was the only clan/person to obtain all of these.</li>
<li>"pissed off deity", obtained by #pray-ing in nethack1.3d until the deity smites you. One other clan did obtain this but I told them how to do it.</li>
<li>"disintegrated by amateur-hour horseshit": as an incantifier in dnethack, die of oversatiating while hallucinating. Incantifiers are a new race in dnethack who eat magic rather than food.</li>
</ul>
<h2 id="some-fun">Some fun</h2>
<p>Overall:</p>
<ul>
<li>12919 games were played, of which</li>
<li>6416 were actually played, and</li>
<li>6503 were scummed (quit or escaped on turn <= 10).</li>
</ul>
<p>The top 3 most games played:</p>
<table>
<caption>Most games played</caption>
<colgroup>
<col width="29%" />
<col width="6%" />
<col width="8%" />
<col width="27%" />
<col width="5%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">Junethack.Username</th>
<th align="center">N</th>
<th align="left"></th>
<th align="center">Clan</th>
<th align="center">N</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">jonadab</td>
<td align="center">1228</td>
<td align="left"><strong>1</strong></td>
<td align="center">demilichens</td>
<td align="center">2126</td>
</tr>
<tr class="even">
<td align="center">coffeebug</td>
<td align="center">746</td>
<td align="left"><strong>2</strong></td>
<td align="center">overcaffeinated</td>
<td align="center">1312</td>
</tr>
<tr class="odd">
<td align="center">coffeebeetle</td>
<td align="center">566</td>
<td align="left"><strong>3</strong></td>
<td align="center">BlackjackAndHookers</td>
<td align="center">620</td>
</tr>
<tr class="even">
<td align="center">Wooble</td>
<td align="center">462</td>
<td align="left"><strong>4</strong></td>
<td align="center">TeamSplat</td>
<td align="center">366</td>
</tr>
<tr class="odd">
<td align="center">Ecthel</td>
<td align="center">327</td>
<td align="left"><strong>5</strong></td>
<td align="center">Justice</td>
<td align="center">327</td>
</tr>
</tbody>
</table>
<p>Who was responsible for the ~50% of scummed games? Note: these could be attempts at conducts or particular unique deaths, like rolling a wizard until you get a wand of polymorph to zap your pet with to get an out-of-depth monster. Not all players agree with start-scumming (for example in the case of unique deaths I didn't do any), but to be honest it is a perfectly valid/accepted tactic.</p>
<table>
<caption>Most games scummed</caption>
<colgroup>
<col width="29%" />
<col width="6%" />
<col width="8%" />
<col width="16%" />
<col width="5%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">Junethack.Username</th>
<th align="center">N</th>
<th align="left"></th>
<th align="center">Clan</th>
<th align="center">N</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">Ecthel</td>
<td align="center">3101</td>
<td align="left"><strong>1</strong></td>
<td align="center">demilichens</td>
<td align="center">3146</td>
</tr>
<tr class="even">
<td align="center">DeuceofJune</td>
<td align="center">2244</td>
<td align="left"><strong>2</strong></td>
<td align="center">Goonsinjune</td>
<td align="center">2247</td>
</tr>
<tr class="odd">
<td align="center">the88kod</td>
<td align="center">858</td>
<td align="left"><strong>3</strong></td>
<td align="center">hi</td>
<td align="center">52</td>
</tr>
<tr class="even">
<td align="center">nooodl</td>
<td align="center">47</td>
<td align="left"><strong>4</strong></td>
<td align="center">Justice</td>
<td align="center">21</td>
</tr>
<tr class="odd">
<td align="center">timco</td>
<td align="center">37</td>
<td align="left"><strong>5</strong></td>
<td align="center">Smile_Mold</td>
<td align="center">16</td>
</tr>
</tbody>
</table>
<p>What does the average nethack game look like?</p>
<table>
<colgroup>
<col width="8%" />
<col width="19%" />
<col width="26%" />
<col width="20%" />
<col width="15%" />
<col width="8%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">variant</th>
<th align="center">Average length game (ascension)</th>
<th align="center">Average length game (death)</th>
<th align="center">Number of ascensions</th>
<th align="center">Number of games</th>
<th align="center">Rate (%)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">vanilla</td>
<td align="center">39704</td>
<td align="center">669</td>
<td align="center">108</td>
<td align="center">8217</td>
<td align="center">1.31</td>
</tr>
<tr class="even">
<td align="center">nethack4</td>
<td align="center">39411</td>
<td align="center">6168</td>
<td align="center">20</td>
<td align="center">116</td>
<td align="center">17.24</td>
</tr>
<tr class="odd">
<td align="center">acehack</td>
<td align="center">36304</td>
<td align="center">739</td>
<td align="center">16</td>
<td align="center">1345</td>
<td align="center">1.19</td>
</tr>
<tr class="even">
<td align="center">unnethack</td>
<td align="center">31184</td>
<td align="center">1991</td>
<td align="center">8</td>
<td align="center">1125</td>
<td align="center">0.71</td>
</tr>
<tr class="odd">
<td align="center">dnethack</td>
<td align="center">76620</td>
<td align="center">2607</td>
<td align="center">1</td>
<td align="center">239</td>
<td align="center">0.42</td>
</tr>
<tr class="even">
<td align="center">grunthack</td>
<td align="center">50257</td>
<td align="center">483</td>
<td align="center">1</td>
<td align="center">1418</td>
<td align="center">0.07</td>
</tr>
<tr class="odd">
<td align="center">sporkhack</td>
<td align="center">40914</td>
<td align="center">3006</td>
<td align="center">1</td>
<td align="center">169</td>
<td align="center">0.59</td>
</tr>
<tr class="even">
<td align="center">oldhack</td>
<td align="center">NaN</td>
<td align="center">368</td>
<td align="center">0</td>
<td align="center">290</td>
<td align="center">0</td>
</tr>
</tbody>
</table>
<ul>
<li>dnetgames are very long</li>
<li>no-one ascended oldhack</li>
<li>nethack4 had the highest rate (it's not popular; people tend not to play it unless they specifically wanted the ascension for a trophy, for example)</li>
<li>vanilla is the most played variant (no surprises there)</li>
<li>only 1 ascension for dnethack, GruntHack and sporkhack (stth...)!</li>
<li>GruntHack and oldhack games are very short, probably because oldhack was mainly used for its unique deaths, and GruntHack was also a major unique-death variant.</li>
</ul>
<h2 id="some-fun-death-analysis">Some fun death analysis</h2>
<p>Note: see also <a href="http://74.135.83.0:8018/nethack-stuff/junethack-unique-deaths-comments-2014-jonadab.html">Jonadab's unique death comments</a>.</p>
<p>Here I'll just focus on the overcaffeinated (777) and demilichens (767) clans as there was a decent break between these two and the rest (but very well done to BlackjackAndHookers (341) too).</p>
<p>In total, 12919 unique deaths were obtained over the month.</p>
<p>It's hard to achieve a different death every time you play. Here's how we went. The "unique deaths (proposed)" column lists unique deaths under the <a href="#ideas-for-next-time-unique-deaths">scheme I propose later</a>.</p>
<table>
<caption>statistics</caption>
<colgroup>
<col width="14%" />
<col width="13%" />
<col width="20%" />
<col width="25%" />
<col width="25%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">clan</th>
<th align="center">games played</th>
<th align="center">unique deaths (raw)</th>
<th align="center">unique deaths (junethack)</th>
<th align="center">unique deaths (proposed)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">demilichens</td>
<td align="center">5272</td>
<td align="center">888 (17%)</td>
<td align="center">767 (15%)</td>
<td align="center">458 (9%)</td>
</tr>
<tr class="even">
<td align="center">overcaffeinated</td>
<td align="center">1313</td>
<td align="center">812 (62%)</td>
<td align="center">777 (59%)</td>
<td align="center">520 (40%)</td>
</tr>
</tbody>
</table>
<p>Note: demilichens did not exclusively focus on unique deaths, so disregard their percentages.</p>
<h3 id="favoured-variants">Favoured variants</h3>
<p>For jonadab (the main deaths-player from demilichens) and I, here are some further stats:</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;">
<a href="http://4.bp.blogspot.com/-apDkE-j8D6U/U8NAgsDtXgI/AAAAAAAAEH0/beOwW8VqUgo/s1600/games_for_deaths.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-apDkE-j8D6U/U8NAgsDtXgI/AAAAAAAAEH0/beOwW8VqUgo/s1600/games_for_deaths.png" /></a>
</td></tr>
<tr><td class="tr-caption" style="text-align: center;">Breakdown of games played per variant</td></tr>
</tbody></table>
<p>As you can see, we both used GruntHack heavily (it has the most verbose death messages), jonadab used acehack heavily whereas I used NAO heavily. I didn't play any vanilla games on the acehack server, and jonadab didn't play vanilla games on the NAO server.</p>
<h3 id="favoured-classes">Favoured classes</h3>
<p>What classes do we like to deathscum in? (restricting to vanilla classes only):</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;">
<a href="http://4.bp.blogspot.com/-KotnL0lp8yc/U8NA197PGbI/AAAAAAAAEH8/lGfsRuPIntc/s1600/roles_for_deaths.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-KotnL0lp8yc/U8NA197PGbI/AAAAAAAAEH8/lGfsRuPIntc/s1600/roles_for_deaths.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Favourite roles for death scumming</td></tr>
</tbody></table>
<p>I heavily favour arcs because of the ability to grab them and dig down in order to find harder monsters (E takes care of most monsters you /don't/ want to die to).</p>
<p>Wizards are popular for two reasons:</p>
<ul>
<li>to use acehack's ability to reroll the starting inventory for a wand of polymorph. The wand can then be zapped at the pet to obtain out-of-depth monsters to die to.</li>
<li>they start with a cloak of magic resistance, so if you want to die to "M[rs]. Foo, the shopkeeper" as opposed to their wands (recorded in most variants as "killed by a (wand|magic missile)"), the cloak of magic resistance lets you survive the wands until the shopkeeper starts melee-ing you. (Shopkeepers all start with at least a wand of striking, and 25% chance for a wand of magic missile).</li>
</ul>
<p>Priests can also be popular in order to die to the "wrath of {deity}" for deities that are unavailable as starting deities. For example, one can never start with a neutral knight: to become neutral, you must convert. Priests, however, get a random deity from the pantheon. Hence if you really wanted to be killed by Brigit you could play a knight and hope to find somewhere to convert relatively early on, or just keep rolling neutral priests until you got Brigit.</p>
<h3 id="deadliest-deaths">Deadliest deaths</h3>
<p>As mentioned earlier, it's hard to be killed by something different each time. What were we killed by the most? Note: from now on, I will concentrate on just jonadab as the demilichens representative, because he was the main deaths-player and seemed to focus just on deaths. Including other demilichens members whose sole purpose was /not/ to obtain unique deaths would misrepresent the statistics.</p>
<table>
<caption>deadliest killers (combined)</caption>
<colgroup>
<col width="40%" />
<col width="16%" />
<col width="12%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">unique.death.junethack</th>
<th align="center">coffeebug</th>
<th align="center">jonadab</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">killed by a dwarf</td>
<td align="center">8</td>
<td align="center">38</td>
</tr>
<tr class="even">
<td align="center">killed by a water moccasin</td>
<td align="center">34</td>
<td align="center">3</td>
</tr>
<tr class="odd">
<td align="center">killed by a jackal</td>
<td align="center">13</td>
<td align="center">12</td>
</tr>
<tr class="even">
<td align="center">killed by a sewer rat</td>
<td align="center">14</td>
<td align="center">10</td>
</tr>
<tr class="odd">
<td align="center">killed by the wrath of Thoth</td>
<td align="center">3</td>
<td align="center">20</td>
</tr>
</tbody>
</table>
<table>
<caption>deadliest killers (individual)</caption>
<colgroup>
<col width="35%" />
<col width="15%" />
<col width="37%" />
<col width="11%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">unique.death.junethack</th>
<th align="center">coffeebug</th>
<th align="center">unique.death.junethack</th>
<th align="center">jonadab</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">killed by a water moccasin</td>
<td align="center">34</td>
<td align="center">killed by a dwarf</td>
<td align="center">38</td>
</tr>
<tr class="even">
<td align="center">killed by a water demon</td>
<td align="center">19</td>
<td align="center">killed by the wrath of Thoth</td>
<td align="center">20</td>
</tr>
<tr class="odd">
<td align="center">killed by a sewer rat</td>
<td align="center">14</td>
<td align="center">killed by the wrath of Odin</td>
<td align="center">15</td>
</tr>
<tr class="even">
<td align="center">killed by a small mimic</td>
<td align="center">13</td>
<td align="center">escaped</td>
<td align="center">14</td>
</tr>
<tr class="odd">
<td align="center">killed by a fox</td>
<td align="center">13</td>
<td align="center">killed by the wrath of Anhur</td>
<td align="center">14</td>
</tr>
</tbody>
</table>
<p>No surprise that I was disproportionately killed by water moccasins and demons. I obtained 26 deaths to touching artifacts (and one "due to inadvisable haste" which required wishing for an artifact in dnethack). All of these required wishing bar Sting and Orcrist, so there was a lot of fountain scumming.</p>
<p>Jonadab was killed by dwarves a lot --- I'm not sure what to make of that. Perhaps expeditions to Minetown for all the shopkeepers one could die to there? I imagine the wrath of Thoth (neutral wiz) could be a way of ending a game that was not going well (Jonadab's favoured class was wizard as mentioned earlier)?</p>
<p>I'm not sure why I had so many deaths to E-able monsters (besides the water foo); perhaps overconfidence? In the case of mimics, they can kill a level 1 player in one hit (3d4 damage), particularly if you encounter a second one while running away from the first. I'm inclined to believe overconfidence, though. I did manage 6 minotaur deaths (one in nh1.3d, the others in the other variants) which I'm quite proud of; they were all at the Castle with level 1 or 2 characters.</p>
<h3 id="most-common-deaths-after-cleaning">Most common deaths (after cleaning)</h3>
<p>Here are the most common deaths, after the <a href="#ideas-for-next-time-unique-deaths">suggestions I made</a> have been implemented.</p>
<table>
<caption>deadliest killers (individual)</caption>
<colgroup>
<col width="37%" />
<col width="14%" />
<col width="37%" />
<col width="11%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">unique.death.me</th>
<th align="center">coffeebug</th>
<th align="center">unique.death.me</th>
<th align="center">jonadab</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">killed by a shopkeeper's wand</td>
<td align="center">74</td>
<td align="center">killed by the wrath of a deity</td>
<td align="center">268</td>
</tr>
<tr class="even">
<td align="center">killed by the wrath of a deity</td>
<td align="center">52</td>
<td align="center">killed by a minion of a deity</td>
<td align="center">58</td>
</tr>
<tr class="odd">
<td align="center">poisoned by a rotted corpse</td>
<td align="center">51</td>
<td align="center">killed by a shopkeeper</td>
<td align="center">57</td>
</tr>
<tr class="even">
<td align="center">killed by a shopkeeper</td>
<td align="center">42</td>
<td align="center">poisoned by a rotted corpse</td>
<td align="center">49</td>
</tr>
<tr class="odd">
<td align="center">killed by a shopkeeper's magic missile</td>
<td align="center">40</td>
<td align="center">killed by a shopkeeper's wand</td>
<td align="center">48</td>
</tr>
</tbody>
</table>
<p>You can see we would have saved a lot of time dying to shopkeepers (me) or #praying for minions/smites (jonadab), or eating lots of rotted corpses.</p>
<h2 id="ideas-for-next-time-unique-deaths">Ideas for next time (unique deaths)</h2>
<p>In light of the month gone by, I have some suggestions re unique deaths to cut down on those deaths that are not "truly different".</p>
<p>In general I think the competition went quite well, but there are definitely some improvements to be made next year (mostly to do with GruntHack's very verbose way of reporting deaths).</p>
<p>I'm not sure how far to take condensing the deaths though. If you can argue that "poisoned by a rotten {monster} corpse" should be condensed to "poisoned by a rotten corpse" for all monsters, why can't "killed by a {monster}" be condensed to "killed by a monster"? But then there would be no fun to it.</p>
<p>Note: many of these suggestions are already implemented in NAO's "reduced deaths" page for each player. See <a href="http://alt.org/nethack/player-endings-reduced.php?player=DeathRobin">DeathRobin's</a> for an example.</p>
<h3 id="grunthacks-killed-by-a-falling-foo-death">GruntHack's "killed by a falling {foo}" death</h3>
<p><strong>Must</strong> be converted to "killed by a falling object", to be in line with all the other variants (besides "killed by a falling rock", which comes from dying to a rock trap).</p>
<p>Otherwise one could simply keep renaming their playerfruit and die over and over to it (by throwing it up in the air and having it fall onto them, which causes some small amount of damage). This would generate an infinite number of deaths that are currently counted as unique. (This is the very reason "killed by kicking {foo}" is converted currently).</p>
<p>For interest, in June 2014 the only deaths of this nature were "killed by a falling slime mold", "killed by a falling statue of a newt", and "killed by a falling dart". I know I was certainly aware of this death as was demilichens, and after testing it a couple of times we mutually agreed not to do it (it would explode the number of possible deaths given then large number of items easily available in nethack. Particularly with GruntHack's addition of materials to the item name, e.g. 'plastic pick-axe', 'gold pick-axe').</p>
<h3 id="shopkeeper-deaths">Shopkeeper deaths</h3>
<p>There are many, many shopkeepers that one can die to. In all the variants but GruntHack, you need a way to survive the shopkeeper's wands in order to be killed by the shopkeeper themselves (e.g. be a wizard since you start with the CoMR).</p>
<p>With GruntHack's verbose death reporting (next section), the number of deaths that can be obtained just from shopkeepers explodes, and isn't really worth it.</p>
<p>I suggest to change "M[rs]. Foo, the shopkeeper" to "a shopkeeper" (this is what the NAO "reduced deaths" does).</p>
<h3 id="grunthacks-killed-by-a-foos-bar-deaths">GruntHack's "killed by a {foo}'s {bar}" deaths</h3>
<p>GruntHack is very verbose in its death reasons. If you are killed by a wand of striking zapped by a gnome, the other variants record this as "killed by a wand". GruntHack records this as "killed by a gnome's wand".</p>
<p>In general, this is great (you know specifically what killed you). For unique deaths, this means that in practice one can run around attacking every shopkeeper one finds and die to their magic missile or wand of striking (or if a wizard, the shopkeeper themselves once the wands run out). Every shopkeeper is guaranteed to have a wand of striking, and has a 25% chance to have a wand of magic missile.</p>
<p>Given the huge number of shopkeepers (some of the variants have more), this makes shopkeeper-related deaths (and wand deaths) quite tedious. In practice, the deaths are the same.</p>
<p>The case of shopkeepers can be largely dealt with with the above fix (all shopkeepers become "a shopkeeper"), but in general, one could convert "killed by {foo}'s {bar}" to "killed by a monster's {bar}".</p>
<p>This is to stop tedious deaths where one throws/gives their attack wand to the first intelligent monster they see so that it will zap the wand at the player (and kill them). Granted, in practice this may not be particularly easy to do (I haven't tried), and you'd want to be a wizard to improve the chance of starting with an attack wand.</p>
<p>The regex would also be hard to implement, due to valid deaths with apostrophes in them, such as</p>
<ul>
<li>"killed by a gas spore's explosion" would become "killed by a monster's explosion"</li>
<li>"quit while already on Charon's boat" --> "quit while already on monster's boat"</li>
<li>"killed by Durin's Bane" (a monster in unnethack) --> "killed by monster's Bane"</li>
</ul>
<p>These are clearly nonsensical, but also there could be too many counterexamples to simply exclude them in a regex.</p>
<h3 id="deaths-of-the-form-killed-by-foo-while-bar">Deaths of the form "killed by {foo}, while {bar}"</h3>
<p>Vanilla nethack only has ", while helpless" deaths but the patched version of vanilla on NAO is more detailed in the types of helplessness, and some of the variants add even more.</p>
<p>Some of these are non-trivial to obtain (e.g. "while being scared by rattling") and I think that one of each death should count.</p>
<p>For example, "{kill message}, while {bar}" could be "killed, while {bar}".</p>
<p>A single death such as "killed by a gnome, while frozen by a monster's gaze" would count as the single death "killed, while frozen by a monster's gaze" (it is up to you to be killed by a gnome while not frozen in order to get "killed by a gnome").</p>
<p>There is actually a huge range of conditions that one can die while experiencing.</p>
<ul>
<li>getting stoned: delayed stoning by a footrice</li>
<li>fumbling: while fumbling (fumble boots/gloves or ice, I think)</li>
<li>sleeping: sleeping (e.g. by a trap or spell or wand or potion)</li>
<li>hiding from thunderstorm: during a lightning strike on the Plane of Air</li>
<li>stuck in a spider web: stuck in a spider web trap</li>
<li>reading a book: reading a spellbook</li>
<li>being frightened to death: ghost from a milky bottle, or haunted temple</li>
<li>frozen by a potion: paralysis potion</li>
<li>sleeping off a magical draught: sleeping from the <em>vapour</em> of a sleep potion (quaffing is "while sleeping").</li>
<li>gazing into a mirror: you are a floating eye and looked into a mirror, freezing yourself</li>
<li>ringing a bell: you rang a cursed bell and summoned a nymph, then there's a chance you simply take some time to ring the bell.</li>
<li>jumping around: while jumping (either magical or non-magical)</li>
<li>moving through the air: from Newton's third law</li>
<li>taking off clothes: while a nymph is stealing armour from you</li>
<li>paralyzed by a monster: as a result of it hitting you (e.g. guardian nagas have a paralysing bite attack)</li>
<li>digesting something: while digesting a monster, e.g. polymorphed into a purple worm. You have a better chance of this if you have slow digestion as digestion is slower then.</li>
<li>frozen by a monster's gaze: frozen because (e.g.) you hit the ubiquitous floating eye</li>
<li>frozen by a monster: frozen because you hit a gelatinous cube (cv "paralyzed by a monster", it hit you)</li>
<li>frozen by a trap: some chest traps will freeze you.</li>
<li>being scared by rattling: skeletons rattle their bones when you #chat to them. Scary.</li>
<li>being terrified of a demon: when you summon a demon after chaotic same-race sacrifice, you are momentarily terrified.</li>
<li>trying to turn the monsters: while using #turn</li>
<li>praying: while #praying.</li>
<li>disrobing: while taking off armour</li>
<li>dressing up: while putting on armour</li>
<li>dragging an iron ball: while punished</li>
<li>pretending to be a pile of gold: while polymorphed into a mimic, and pretending to be a pile of gold.</li>
<li>unconscious from rotten food: self-explanatory</li>
<li>fainted from lack of food: self-explanatory</li>
<li>vomiting: if you eat a rotten egg, for example.</li>
<li>being scared stiff: being scared by Magicbane</li>
<li>opening a container: It takes one turn to open a container. I <em>think</em> if you are paralyzed by a trap you get that instead. Or perhaps tins, which take some time to open.</li>
<li>gazing into a crystal ball: Using a crystal ball takes time.</li>
<li>helpless: anything not covered by the above (while engraving, for example).</li>
</ul>
<p>In vanilla I'm not sure that you can actually obtain deaths that involve you being polymorphed (because when you die you either revert to human form meaning you don't die, or if you're wearing an amulet of unchanging you always get "killed while stuck in creature form"). However I think some of the other variants have fixed this. For example in GruntHack if you are polymorphed into a paper golem and are caught in a fire trap, you will get "burned away" (or something like that) if you wearing the amulet of unchanging instead of "killed while stuck in creature form".</p>
<h3 id="killed-by-a-ghost-of-playername">Killed by a ghost of {playername}</h3>
<p>Strip the player names. Sure, it'd be hard to actually exploit this (you'd have to organise with a few other players to all play at the same time and die on particular levels in an attempt to load each other's ghosts), but these deaths are all really the same.</p>
<p>I suppose you could keep those ghosts whose names are hard-coded into the source (they are the names of the nethack devs), but again, they're the same deaths.</p>
<h3 id="food-poisoning">Food poisoning</h3>
<p>When you eat a tainted corpse and get "poisoned by a rotted {monster} corpse", perhaps this could be converted to "poisoned by a rotted corpse". I suppose you need to draw the line at condensing deaths somehow (for example, one could argue that condensing these deaths was the same as condensing "killed by a {monster}" to "killed by a monster" for all monsters). But I think there are still enough unique deaths available that condensing these will encourage players to go for different types of deaths.</p>
<h3 id="deities">Deities</h3>
<p>Many, many deaths of the form "killed by the wrath of {deity}". These are obtained by starting a character with the appropriate alignment and simply #pray-ing until smitten by your god.</p>
<p>One <em>could</em> condense these to "killed by the wrath of a deity" (a la nethack 1.3d's "pissed off deity"), though one could also argue that there are only a relatively small number of deities (39) so this is not much of an issue.</p>
<p>To obtain deaths to deities that can not normally be accessed (for example, a knight can never start neutral), you can either convert (in my opinion this requires some skill and hence these deaths should somehow be noted), <em>or</em> you can simply roll a neutral priest, who will get a random neutral deity, and hope that you get Brigit. The latter doesn't require skill, just luck and the willingness to keep rerolling until you get the right deity.</p>
<h3 id="minions-of-deities">Minions of deities</h3>
<p>Sometimes when you #pray to a deity they will send a minion to smite you. Minions can be any A bar ki-rin and Archon (lawful deities), any E (neutral), or any & (demon) that is not a lord or prince, and is either nonaligned or chaotically-aligned (for example, erinyes are lawful).</p>
<p>There are many "killed by a {monster} of {deity}" deaths that are somewhat tedious to obtain, because really the only way to do it is to #pray repeatedly and hope you get a minion before you get smitten. You could also farm the high altar for minions but it seems like a bit too much work to get all the way to the high altar only to summon a single minion to die to.</p>
<p>I think these could either be converted to "killed by a minion of {deity}" or "killed by a minion of a deity" or "killed by a water elemental of {deity}" for each minion. NAO's "reduced deaths" version uses the latter, though I prefer the middle.</p>
<h3 id="priests-and-priestesses">Priests and priestesses</h3>
<p>At the very least, priests and priestesses should be the same, i.e. "killed by a priest(ess) of {deity}". One could conceivably condense this to "killed by a priest(ess) of a deity", which I favour, but again there is the question of condensing too much.</p>
<h3 id="grunthacks-change-of-the-kill-prefix">GruntHack's change of the kill prefix</h3>
<p>In GruntHack, rather than being "killed by a freezing sphere", you are "frozen by a freezing sphere". The kill prefix is changed to match the damage type ("frozen by", "burned by", "shocked by", ...).</p>
<p>This means that you can obtain both "frozen by a freezing sphere" and "killed by a freezing sphere" depending on which variant to play, though those of these are really the same death.</p>
<p>One could strip off the kill prefix "(killed|frozen|burned|shocked|disintegrated) by" completely, though I haven't thought about this hard enough to decide yet whether this could merge deaths that are different. One example that comes to mind is being killed by a black dragon hitting you, as opposed to being disintegrated by one. In this case vanilla nethack has 'killed by a black dragon' and 'killed by a blast of disintegration', but perhaps there are other similar cases.</p>
<p>Ahh, grunt again. For example, water elementals have engulfing attacks. You can be "killed by a water elemental" (it melees you to death) or "suffocated by a water elemental" (it engulfs you), and these are fundamentally different. Silly grunt!</p>
<h3 id="grunthacks-racial-monsters">GruntHack's Racial monsters</h3>
<p>GruntHack introduces racial monsters, for example there are ogre werejackals, elven werejackals, ettin werejackals, ... Soldiers, sergeants, captains, lieutenants, mummies, zombies, vampire foo, werefoo, nurses, guards, prisoners, watchmen, watch captains, shopkeepers, and priests/priestesses can be racial, leading to a huge number of deaths by the same monster of different races.</p>
<p>I probably <strong>wouldn't</strong> bother condensing these, since it does appear that races add to the difficulty of the monsters and hence affect their generation. For example, ettin werefoo have a much higher difficulty level than kobold werefoo and are hence only encountered much deeper in the dungeon.</p>
<p>The one exception is in the case of shopkeepers and priest(esse)s. Shopkeepers have been addressed previously (and their races are not recorded in the death message). I think races should be stripped from priests because rather than having difficulties and so on, they are only generated in temples so to hope to encounter a good spread of the clergy in various races is unlikely.</p>
<h1 id="appendix-implementation">Appendix: Implementation</h1>
<p>Here's some code similar to <a href="https://github.com/junethack/Junethack/blob/master/lib/junethack/normalize_death.rb">Junethack's <code>normalize_death</code></a> code, but it implements my suggestions. It's written in <a href="http://www.r-project.org/">R</a>:</p>
<table>
<caption>conversions made</caption>
<colgroup>
<col width="41%" />
<col width="41%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">from</th>
<th align="center">to</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">killed by a {foo}, while {bar}</td>
<td align="center">killed, while {bar}</td>
</tr>
<tr class="even">
<td align="center">killed by a hallucinogen-distorted {foo}</td>
<td align="center">killed by a hallucinogen-distorted monster</td>
</tr>
<tr class="odd">
<td align="center">killed by a invisible {foo}</td>
<td align="center">killed by a invisible monster</td>
</tr>
<tr class="even">
<td align="center">killed by a falling {not 'rock'}</td>
<td align="center">killed by a falling object</td>
</tr>
<tr class="odd">
<td align="center">ghost of {name}</td>
<td align="center">ghost</td>
</tr>
<tr class="even">
<td align="center">poisoned by a rotted {monster} corpse</td>
<td align="center">poisoned by a rotted corpse</td>
</tr>
<tr class="odd">
<td align="center">wrath of {deity}</td>
<td align="center">wrath of a deity</td>
</tr>
<tr class="even">
<td align="center">priest/priestess</td>
<td align="center">priest(ess)</td>
</tr>
<tr class="odd">
<td align="center">M[rs]. {name}, the shopkeeper</td>
<td align="center">a shopkeeper</td>
</tr>
<tr class="even">
<td align="center">killed by touching {artifact}</td>
<td align="center">killed by touching an artifact</td>
</tr>
<tr class="odd">
<td align="center">killed by a {minion} of {deity}</td>
<td align="center">killed by a minion of a deity</td>
</tr>
</tbody>
</table>
<p>Notes:</p>
<ul>
<li>naming a monster strips <em>everything</em> after the name, <em>including</em> ", while bar" (if present). Otherwise I could name (say) my dog "foo, while helpless" and be killed by it to get "killed by a little dog named foo, while helpless" in an attempt to get "killed, while helpless".</li>
<li>"invisible hallucinogen-distorted" as a combination counts as unique.</li>
<li>deaths with ", while" attempt to preserve the first word. For example "burned by asdf, while helpless" and "killed by asdf, while helpless" counts as two different deaths. I'm not sure if this could lead to some nonsensical deaths.</li>
</ul>
<pre><code class="language-r">normalize.deaths.extra <- function (deaths) {
# sic. the 'killey' is a typo on that site.
deaths <- gsub('^killey by an ', 'killed by a ', deaths)
# convert 'killed by a foo, while bar' to 'killed, while bar'
# (up to you to be killed by them while *not* bar)
# NOTE: preserve first verb, is this nonsensical?
# NOTE: ', while' occurs AFTER 'named', so do not die to a named animal
# or you will lose this.
deaths <- gsub('^([^ ]+).*, while (.*)$', '\\1, while \\2', deaths)
# 'hallucinogen-distorted'
deaths <- gsub('hallucinogen-distorted .*', 'hallucinogen-distorted monster', deaths)
# 'invisible'
deaths <- gsub('by (the )?invisible ', 'by ', deaths)
deaths <- gsub('by (an|a) invisible ', 'by a ', deaths)
deaths <- gsub('by invisible ', 'by a ', deaths)
deaths <- gsub('by a invisible (hallucinogen-distorted )?.*', 'by an invisible \\1monster', deaths)
deaths <- gsub(' (her|his) ', ' eir ', deaths)
deaths <- gsub(' (her|him)self ', ' eirself ', deaths)
deaths <- gsub(' (her|him)self$', ' eirself', deaths)
# note: named strips everything after it, so don't try to get ', while bar'
# conditions with a named monster.
deaths <- gsub(' (called|named) .*', '', deaths)
deaths <- gsub(' \\(with the Amulet\\)$', '', deaths)
deaths <- gsub('choked on .*', 'choked on something', deaths)
deaths <- gsub('killed by kicking .*', 'killed by kicking something', deaths)
# killed by a falling {foo}
deaths <- gsub("^killed by a falling (?!rock).*$", "killed by a falling object", deaths, perl=T)
# strip ghost names
deaths <- gsub(" ghost of .*", " ghost", deaths)
# food poisoning
deaths <- gsub("^poisoned by a rotted .* corpse", "poisoned by a rotted corpse", deaths)
# deities
deaths <- gsub(" wrath of .*", " wrath of a deity", deaths)
# priests and priestesses
deaths <- gsub("priest(ess)?", "priest(ess)", deaths)
# shopkeepers
deaths <- gsub("M[rs]\\. [A-Z].*, the shopkeeper", "a shopkeeper", deaths)
# a {monster}'s {item}: tricky because of general regex looking for `'`
# e.g. Durin's Bane, gas spore's explosion, quit while already on Charon's boat
# while frozen by a monster's gaze
# deaths <- gsub("^(\\w+) by (an?|the) .*'s (?!explosion.*)$", "\\1 by a monster's \\2", deaths, perl=T)
# narrow it down to wands only?
# ?? touching (an artifact)?
deaths <- gsub("killed by touching .*", "killed by touching an artifact", deaths)
# ?? minions of deities? "minion of a deity"? "minion of {deity}"? "{minion} of a deity"?
# the first: 1 death. the second: 39 deaths (#gods). third: #minions deaths.
deaths <- gsub("(\\w+ elemental|Aleax|couatl|Angel|\\w+ demon|\\w+ devil|(suc|in)cubus|balrog|pit fiend|nalfeshnee|hezrou|vrock|marilitherinyes) of [A-Z].*", "minion of a deity", deaths)
# ?? racial priest*s?
# return
deaths
}</code></pre>
<h1 id="appendix-filter-unique-deaths">Appendix: filter unique deaths</h1>
<p>The implementation for Junethack 2014, ported to <a href="http://www.r-project.org/">R</a>. Taken from <a href="https://github.com/junethack/Junethack/blob/master/lib/junethack/normalize_death.rb"><code>normalize_death.rb</code> on the junethack GitHub repository</a></p>
<pre><code class="language-r">normalize.deaths <- function(deaths) {
# sic. the 'killey' is a typo on that site.
deaths <- gsub('^killey by an ', 'killed by a ', deaths)
deaths <- gsub(', while .*', '', deaths)
deaths <- gsub('hallucinogen-distorted ', '', deaths)
deaths <- gsub('by (the )?invisible ', 'by ', deaths)
deaths <- gsub('by (an|a) invisible ', 'by a ', deaths)
deaths <- gsub('by invisible ', 'by a ', deaths)
deaths <- gsub(' (her|his) ', ' eir ', deaths)
deaths <- gsub(' (her|him)self ', ' eirself ', deaths)
deaths <- gsub(' (her|him)self$', ' eirself', deaths)
deaths <- gsub(' (called|named) .*', '', deaths)
deaths <- gsub(' \\(with the Amulet\\)$', '', deaths)
deaths <- gsub('choked on .*', 'choked on something', deaths)
deaths <- gsub('killed by kicking .*', 'killed by kicking something', deaths)
# deaths <- gsub('^killed by (the|an?) ', 'killed by ', deaths)
return(deaths)
}</code></pre>
<h1 id="appendix-data">Appendix: data</h1>
<p>If you're after data for all games from participating players in Junethack, I am making it available in two formats:</p>
<ul>
<li><p>all bundled as an <a href="http://www.r-project.org/">R</a> <code>RData</code> file as data.frames (or data.tables, if you care to load that package):</p>
<pre><code class="language-r">load('junethack.2014.rda') # tables deaths, users, junethack.users, clans</code></pre></li>
<li><p>an archive of CSVs. Comma-separated, string fields quoted (there should not be embedded quotes, but if there are they are escaped), non-values are 'NA' (no quotes).</p></li>
</ul>
<p>The RData file is at <a href="https://bitbucket.org/mathematicalcoffee/junethack-analysis/downloads/junethack.2014.rda">https://bitbucket.org/mathematicalcoffee/junethack-analysis/downloads</a>.<br />The CSV zipfile is at <a href="https://bitbucket.org/mathematicalcoffee/junethack-analysis/downloads/junethack.2014.zip">https://bitbucket.org/mathematicalcoffee/junethack-analysis/downloads</a>.</p>
<p>There are 4 tables provided. Yes, there is redundancy between the tables because I know nothing about databases and found it useful in writing these posts.</p>
<p>The tables do not include games that Junethack counted as "junk games" (explore, polyinit, debug, or multiplayer games).</p>
<p>(The script used to generate these files is <a href="https://bitbucket.org/mathematicalcoffee/junethack-analysis/src/master/package.junethack.data.r">here</a>; it worked for me but <strong>is not guaranteed to work for you</strong>, and is not really in a release-ready state. Use at your own risk).</p>
<h3 id="deaths-table"><code>deaths</code> table</h3>
<table>
<caption>Sample from the deaths table (continued below)</caption>
<colgroup>
<col width="4%"></col>
<col width="3%"></col>
<col width="6%"></col>
<col width="5%"></col>
<col width="6%"></col>
<col width="12%"></col>
<col width="12%"></col>
<col width="6%"></col>
<col width="5%"></col>
<col width="5%"></col>
<col width="6%"></col>
<col width="11%"></col>
<col width="7%"></col>
<col width="4%"></col>
</colgroup>
<thead>
<tr class="header">
<th align="center">mode</th>
<th align="center">exp</th>
<th align="center">xplevel</th>
<th align="center">align0</th>
<th align="center">gender0</th>
<th align="center">endtime</th>
<th align="center">starttime</th>
<th align="center">carried</th>
<th align="center">event</th>
<th align="center">turns</th>
<th align="center">conduct</th>
<th align="center">death</th>
<th align="center">name</th>
<th align="center">align</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center">Cha</td>
<td align="center">Mal</td>
<td align="center">2014-06-20 09:29:19</td>
<td align="center">2014-06-20 09:24:38</td>
<td align="center"></td>
<td align="center"></td>
<td align="center">1170</td>
<td align="center">3976</td>
<td align="center">killed by a rothe</td>
<td align="center">coffeebug</td>
<td align="center">Cha</td>
</tr>
<tr class="even">
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center">Neu</td>
<td align="center">Mal</td>
<td align="center">2014-06-04 01:22:42</td>
<td align="center">2014-06-04 01:22:39</td>
<td align="center"></td>
<td align="center"></td>
<td align="center">1</td>
<td align="center">4095</td>
<td align="center">quit</td>
<td align="center">DeuceofJune</td>
<td align="center">Neu</td>
</tr>
</tbody>
</table>
<table>
<caption>Table continues below</caption>
<colgroup>
<col width="5%"></col>
<col width="4%"></col>
<col width="4%"></col>
<col width="3%"></col>
<col width="7%"></col>
<col width="7%"></col>
<col width="5%"></col>
<col width="5%"></col>
<col width="3%"></col>
<col width="5%"></col>
<col width="7%"></col>
<col width="7%"></col>
<col width="5%"></col>
<col width="6%"></col>
<col width="10%"></col>
<col width="5%"></col>
</colgroup>
<thead>
<tr class="header">
<th align="center">gender</th>
<th align="center">race</th>
<th align="center">role</th>
<th align="center">uid</th>
<th align="center">birthdate</th>
<th align="center">deathdate</th>
<th align="center">deaths</th>
<th align="center">maxhp</th>
<th align="center">hp</th>
<th align="center">maxlvl</th>
<th align="center">deathlev</th>
<th align="center">deathdnum</th>
<th align="center">points</th>
<th align="center">version</th>
<th align="center">server</th>
<th align="center">variant</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">Mal</td>
<td align="center">Gno</td>
<td align="center">Bar</td>
<td align="center">5</td>
<td align="center">2014-06-20</td>
<td align="center">2014-06-20</td>
<td align="center">1</td>
<td align="center">38</td>
<td align="center">-2</td>
<td align="center">4</td>
<td align="center">4</td>
<td align="center">2</td>
<td align="center">794</td>
<td align="center">0.6.3</td>
<td align="center">sporkhack.com</td>
<td align="center">sporkhack</td>
</tr>
<tr class="even">
<td align="center">Mal</td>
<td align="center">Gno</td>
<td align="center">Wiz</td>
<td align="center">5</td>
<td align="center">2014-06-04</td>
<td align="center">2014-06-04</td>
<td align="center">0</td>
<td align="center">11</td>
<td align="center">11</td>
<td align="center">1</td>
<td align="center">1</td>
<td align="center">0</td>
<td align="center">0</td>
<td align="center">3.4.3</td>
<td align="center">nethack.alt.org</td>
<td align="center">vanilla</td>
</tr>
</tbody>
</table>
<table>
<caption>Table continues below</caption>
<colgroup>
<col width="6%"></col>
<col width="6%"></col>
<col width="5%"></col>
<col width="8%"></col>
<col width="7%"></col>
<col width="8%"></col>
<col width="7%"></col>
<col width="7%"></col>
<col width="7%"></col>
<col width="6%"></col>
<col width="15%"></col>
<col width="10%"></col>
</colgroup>
<thead>
<tr class="header">
<th align="center">realtime</th>
<th align="center">achieve</th>
<th align="center">flags</th>
<th align="center">dnetachieve</th>
<th align="center">endtimeus</th>
<th align="center">starttimeus</th>
<th align="center">temporary</th>
<th align="center">intrinsic</th>
<th align="center">extrinsic</th>
<th align="center">charname</th>
<th align="center">unique.death.junethack</th>
<th align="center">unique.death.me</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">280</td>
<td align="center">0</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center">killed by a rothe</td>
<td align="center">killed by a rothe</td>
</tr>
<tr class="even">
<td align="center">2</td>
<td align="center">0</td>
<td align="center">0</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center">quit</td>
<td align="center">quit</td>
</tr>
</tbody>
</table>
<table>
<colgroup>
<col width="20%"></col>
<col width="20%"></col>
</colgroup>
<thead>
<tr class="header">
<th align="center">startscummed</th>
<th align="center">clan</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">FALSE</td>
<td align="center">overcaffeinated</td>
</tr>
<tr class="even">
<td align="center">TRUE</td>
<td align="center">Goonsinjune</td>
</tr>
</tbody>
</table>
<p>This is essentially the xlogfile for each server, filtered to contain just games by Junethack participants. See the nethackwiki pages for the <a href="http://nethackwiki.com/wiki/Xlogfile">Xlogfile</a> and <a href="http://nethackwiki.com/wiki/Logfile">logfile</a> for information on these fields. If the xlogfile for a particular server does not support that value, it is listed as NA.</p>
<pre><code>Columns of note:
* `death`: the original death.
* `starttime`, `endtime`: start and end time of the game. In the CSV formats they are left as-is (seconds since UNIX epoch); in the Rdata file they are POSIXct objects with GMT timezone.
* `name`: the character's name, but on the nethack4 server it is the name of the nethack4 account and `charname` is the character's name (on nethack4 you can pick your character name freely of your account name).
Columns I've added:
* `server`: the server on which the game was played
* `variant`: name of the variant
* `clan`: the clan this user was from (if any)
* `startscummed`: whether the game is considered startscummed or not (reason for death was escaped/quit and turns less than or equal to 10).
* `unique.death.junethack`: the death as Junethack counted it.
* `unique.death.me`: the death with my proposed changes.</code></pre>
<h3 id="users-table"><code>users</code> table</h3>
<table>
<caption>Sample from the users table</caption>
<colgroup>
<col width="29%" />
<col width="20%" />
<col width="22%" />
<col width="13%" />
<col width="9%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">Junethack.Username</th>
<th align="center">Account</th>
<th align="center">Server</th>
<th align="center">Variant</th>
<th align="center">Clan</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">MrSnide</td>
<td align="center">MrSnide</td>
<td align="center">acehack.de</td>
<td align="center">acehack</td>
<td align="center">Justice</td>
</tr>
<tr class="even">
<td align="center">schistosomatic</td>
<td align="center">schistosomatic</td>
<td align="center">nethack.alt.org</td>
<td align="center">vanilla</td>
<td align="center">Justice</td>
</tr>
</tbody>
</table>
<p>Information about users on Junethack. Note: when you register for Junethack, you pick an account name for Junethack (say 'coffeebug'). Then, on each server, you may register an account (from the server) to your Junethack username.</p>
<p>For example, I registered 'coffeebug' on NAO and 'coffeebeet' on the dnethack server.</p>
<p>The columns of the users table:</p>
<ul>
<li><code>Junethack.Username</code>: your Junethack account name (e.g. 'coffeebug')</li>
<li><code>Account</code>: the name of the account on a specific server (e.g. 'coffeebeet')</li>
<li><code>Server</code>: the name of the server that account is on (e.g. 'dnethack.ilbelkyr.de')</li>
<li><code>Variant</code>: the variant (e.g. 'dnethack'. Note: the acehack.de server has oldhack, vanilla, and acehack variants and you can register an account for each).</li>
<li><code>Clan</code>: the clan this Junethack user is in (if any).</li>
</ul>
<p>If you look up all the rows for a particular Junethack.Username, that's just like the table on that user's Junethack page that lists their accounts on each server.</p>
<p>To look up all deaths for a given <em>account</em> on a <em>server</em> (e.g. all of my acehack.de acehack deaths), I'd look for rows in <code>deaths</code> where <code>name</code> was 'coffeebug' (my <code>Account</code> for acehack.de), <code>server</code> was 'acehack.de', and <code>variant</code> was 'acehack'.</p>
<p>To look up all deaths for my coffeebug <em>Junethack</em> account, I'd take all rows corresponding to <code>Junethack.Username='coffeebug'</code> from the users table, and join to <code>deaths</code> where the users <code>(Account, Server, Variant)</code> matches the <code>deaths</code> <code>(name, server, variant)</code>.</p>
<h3 id="junethack.users-table"><code>junethack.users</code> table</h3>
<table>
<caption>Sample from the junethack.users table</caption>
<colgroup>
<col width="24%" />
<col width="12%" />
<col width="9%" />
<col width="12%" />
<col width="10%" />
<col width="11%" />
<col width="17%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">Junethack.Username</th>
<th align="center">Accounts</th>
<th align="center">Games</th>
<th align="center">Trophies</th>
<th align="center">Played</th>
<th align="center">Scummed</th>
<th align="center">Clan</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">coffeebeetle</td>
<td align="center">2</td>
<td align="center">567</td>
<td align="center">1</td>
<td align="center">566</td>
<td align="center">1</td>
<td align="center">overcaffeinated</td>
</tr>
<tr class="even">
<td align="center">coffeebug</td>
<td align="center">8</td>
<td align="center">746</td>
<td align="center">19</td>
<td align="center">746</td>
<td align="center">0</td>
<td align="center">overcaffeinated</td>
</tr>
</tbody>
</table>
<p>This is essentially the Junethack users table (https://junethack.de/users), with the number of start-scummed games added and the user's clan.</p>
<p>The 'Junethack.Username' column here matches up with the same column from the 'users' table.</p>
<h3 id="clans-table"><code>clans</code> table</h3>
<table>
<caption>Sample from the clans table</caption>
<colgroup>
<col width="17%" />
<col width="9%" />
<col width="21%" />
<col width="32%" />
<col width="19%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">Username</th>
<th align="center">Role</th>
<th align="center">User trophies</th>
<th align="center">Last game played (UTC)</th>
<th align="center">Clan</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">coffeebeetle</td>
<td align="center">member</td>
<td align="center">1</td>
<td align="center">2014-06-19 06:38</td>
<td align="center">overcaffeinated</td>
</tr>
<tr class="even">
<td align="center">coffeebug</td>
<td align="center">admin</td>
<td align="center">19</td>
<td align="center">2014-06-30 15:01</td>
<td align="center">overcaffeinated</td>
</tr>
</tbody>
</table>
<p>This is just the 'Clan members' table from each clan page, joined together.</p>
<p>The 'Username' column here corresponds to the 'Junethack.Username' column in <code>users</code> and <code>clans</code>.</p>
<hr />
<p>P.S. turns out that although I pronounce "deity" in the way that suggests the correct spelling, I have been spelling it "diety" for years. Hahaha!.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com1tag:blogger.com,1999:blog-7039473604287682752.post-49021098046642599332014-06-26T00:27:00.000-07:002014-06-26T00:27:09.209-07:00ggpie: pie graphs in ggplot2<p>How does one make a pie chart in R using <code>ggplot2</code>? (If you're impatient: see the final code <a href="#tldr">here</a>).</p>
<p>I know, I know, pie charts are often not very good ways of displaying data. It is hard to visually compare the relative sizes of slices (particularly the smaller ones and if they are scattered with larger ones in between), and you get no sense of scale.</p>
<p>However, sometimes a good ol' pie chart can convey your point in a way that many of the general public will find easy to understand. For example, this is how I've spent my "work" hours this week so far:</p>
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-HY1rTjjg59E/U6vDOF_8K_I/AAAAAAAAD90/RdHIb0Xie_w/s1600/unnamed-chunk-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-HY1rTjjg59E/U6vDOF_8K_I/AAAAAAAAD90/RdHIb0Xie_w/s1600/unnamed-chunk-2.png" /></a></div>
<p>(I manually inserted the line break into "marking exams" so it wouldn't get cut off - not sure how to automatically do this).</p>
<p>Terrible, I know. But the plot conveys quite clearly the point I want to make: I wasted away almost half (!) of my week so far playing nethack when I should have been doing my PhD, which is much more time than I have spent on my PhD itself!</p>
<p>(Aside: <a href="http://en.wikipedia.org/wiki/NetHack">nethack</a> is a most excellent ASCII game that can be obtained <a href="http://www.nethack.org/">here</a>, or from your repositories on most Linux systems. In my defence, during the month of June the <a href="https://junethack.de/">Junethack tournament</a> is run and <a href="https://junethack.de/clan/overcaffeinated">clan overcaffeinated (me)</a> is in a deadly battle with <a href="https://junethack.de/clan/demilichens">clan demilichens</a> to win the "most unique deaths" trophy. And this is the last week of June).</p>
<h2 id="how-to-do-it">How to do it</h2>
<p>My data looks like this (I've been using <a href="http://projecthamster.wordpress.com/about/">hamster time tracker</a>, though I keep forgetting to track things.):</p>
<table>
<caption>How I've spent my PhD hours this week</caption>
<colgroup>
<col width="25%" />
<col width="8%" />
</colgroup>
<thead>
<tr class="header">
<th align="center">activity</th>
<th align="center">time</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="center">Nethack</td>
<td align="center">15.2</td>
</tr>
<tr class="even">
<td align="center">PhD</td>
<td align="center">7.4</td>
</tr>
<tr class="odd">
<td align="center">Marking exams</td>
<td align="center">4</td>
</tr>
<tr class="even">
<td align="center">Meetings</td>
<td align="center">2.3</td>
</tr>
<tr class="odd">
<td align="center">Lunch</td>
<td align="center">2</td>
</tr>
<tr class="even">
<td align="center">Writing this post</td>
<td align="center">1.5</td>
</tr>
</tbody>
</table>
<p>My first attempt at building a pie chart of this data follows the <a href="http://docs.ggplot2.org/current/coord_polar.html">ggplot2 documentation for coord_polar</a> and <a href="http://www.r-chart.com/2010/07/pie-charts-in-ggplot2.html">this excellent post on r-chart</a>. There are also a number of relevant questions on StackOverflow.</p>
<p>First we construct a stacked bar chart, coloured by the activity type (<code>fill=activity</code>). Note that <code>x=1</code> is a dummy variable purely so that ggplot has an x variable to plot by (we will remove the label later).</p>
<p>(Aside: if <code>x</code> is a factor (e.g. <code>factor("dummy")</code>) for some reason the bar does not get full width, and the resulting pie chart has a funny little hole in the middle).</p>
<pre><code class="language-r">p <- ggplot(df, aes(x=1, y=time, fill=activity)) +
geom_bar(stat="identity") +
ggtitle("How I've spent my PhD hours this week")
print(p)</code></pre>
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-aL-Zmjo7hhA/U6vDOCRdZwI/AAAAAAAAD94/JNVezCam5qY/s1600/unnamed-chunk-4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-aL-Zmjo7hhA/U6vDOCRdZwI/AAAAAAAAD94/JNVezCam5qY/s1600/unnamed-chunk-4.png" /></a></div>
<p>Then we use <code>coord_polar()</code> to turn it into a pie chart:</p>
<pre><code class="language-r">p <- p + coord_polar(theta='y')
print(p)</code></pre>
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-7q3Qt0_llGo/U6vDPJl2hwI/AAAAAAAAD-M/M7Rv4tkWt60/s1600/unnamed-chunk-5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-7q3Qt0_llGo/U6vDPJl2hwI/AAAAAAAAD-M/M7Rv4tkWt60/s1600/unnamed-chunk-5.png" /></a></div>
<p>(Aside: does anyone find it weird that although my x axis was 1 and my y axis was <code>time</code>, on the resultant graph the x axis is now 'time' and the y axis is now 1?)</p>
<p>Let's tweak this so it doesn't look so bad.</p>
<p>First, some pure aesthetics: let's outline each slice of the pie in black using <code>color='black'</code> in <code>geom_bar()</code>. This causes there to be an ugly black line and outline on each square of the legend, so we remove that.</p>
<pre><code class="language-r"># We have to start the plot again because `color='black'` goes into geom_bar
p <- ggplot(df, aes(x=1, y=time, fill=activity)) +
ggtitle("How I've spent my PhD hours this week") +
coord_polar(theta='y')
p <- p +
# black border around pie slices
geom_bar(stat="identity", color='black') +
# remove black diagonal line from legend
guides(fill=guide_legend(override.aes=list(colour=NA)))
print(p)</code></pre>
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-JRBbwI1oBTg/U6vDPdDdaSI/AAAAAAAAD-U/TsXJ4nZOaTU/s1600/unnamed-chunk-6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-JRBbwI1oBTg/U6vDPdDdaSI/AAAAAAAAD-U/TsXJ4nZOaTU/s1600/unnamed-chunk-6.png" /></a></div>
<p>Now, remove the axes:</p>
<ul>
<li>both the axis labels ("time", "1"),</li>
<li>the tick marks on the vertical axis,</li>
<li>the tick labels on the vertical axis (0.75, 1.00, 1.25).</li>
</ul>
<p>Note - for some reason, although <code>1</code> was our <code>x</code> variable, you remove its tick label by setting <code>axis.text.y</code>...</p>
<pre><code class="language-r">p <- p +
theme(axis.ticks=element_blank(), # the axis ticks
axis.title=element_blank(), # the axis labels
axis.text.y=element_blank()) # the 0.75, 1.00, 1.25 labels.
print(p)</code></pre>
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-_WbRAD1cWlE/U6vDPmgVazI/AAAAAAAAD-c/goQBKmTtofQ/s1600/unnamed-chunk-7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-_WbRAD1cWlE/U6vDPmgVazI/AAAAAAAAD-c/goQBKmTtofQ/s1600/unnamed-chunk-7.png" /></a></div>
<p>Now, I should also remove the '0', '5', '10', '15' tick marks/labels, being the cumulative number of hours spent so far, since they're not meaningful.</p>
<p>However, I want to label each slice of the pie, and it is convenient to put my labels in place of the '0', '5', etc.</p>
<p>In terms of their <em>position</em>, they should be located at the midpoint of each pie slice. Think back to the stacked bar chart I produced at the start, and recall that the y axis (<code>time</code>) shows cumulative hours spent.</p>
<p>This means the y coordinate of the <em>end</em> of each slice is given by <code>cumsum(df$time)</code> (cumulative sum of time spent so far), and so the coordinate of the <em>midpoint</em> of each slice is given by:</p>
<pre><code class="language-r">y.breaks <- cumsum(df$time) - df$time/2
y.breaks</code></pre>
<pre><code>## [1] 7.60 18.90 24.60 27.75 29.90 31.65</code></pre>
<p>In order to implement this in the pie chart, we use <code>scale_y_continuous</code> with the <code>breaks</code> argument being the coordinates we've just calculated, and the <code>labels</code> argument being the activity name.</p>
<pre><code class="language-r">p <- p +
# prettiness: make the labels black
theme(axis.text.x=element_text(color='black')) +
scale_y_continuous(
breaks=y.breaks, # where to place the labels
labels=df$activity # the labels
)
print(p)</code></pre>
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-p3H3wu0YcfM/U6vDQX1gqYI/AAAAAAAAD-Y/ZdvxCddplyQ/s1600/unnamed-chunk-9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-p3H3wu0YcfM/U6vDQX1gqYI/AAAAAAAAD-Y/ZdvxCddplyQ/s1600/unnamed-chunk-9.png" /></a></div>
<p>Altogether now:</p>
<pre><code class="language-r">p <- ggplot(df, aes(x=1, y=time, fill=activity)) +
ggtitle("How I've spent my PhD hours this week") +
# black border around pie slices
geom_bar(stat="identity", color='black') +
# remove black diagonal line from legend
guides(fill=guide_legend(override.aes=list(colour=NA))) +
# polar coordinates
coord_polar(theta='y') +
# label aesthetics
theme(axis.ticks=element_blank(), # the axis ticks
axis.title=element_blank(), # the axis labels
axis.text.y=element_blank(), # the 0.75, 1.00, 1.25 labels
axis.text.x=element_text(color='black')) +
# pie slice labels
scale_y_continuous(
breaks=cumsum(df$time) - df$time/2,
labels=df$activity
)</code></pre>
<h2 id="tldr">TL;DR</h2>
<p>I've tied it together into a function <code>ggpie</code>:</p>
<pre><code class="language-r">library(ggplot2)
# ggpie: draws a pie chart.
# give it:
# * `dat`: your dataframe
# * `by` {character}: the name of the fill column (factor)
# * `totals` {character}: the name of the column that tracks
# the time spent per level of `by` (percentages work too).
# returns: a plot object.
ggpie <- function (dat, by, totals) {
ggplot(dat, aes_string(x=factor(1), y=totals, fill=by)) +
geom_bar(stat='identity', color='black') +
guides(fill=guide_legend(override.aes=list(colour=NA))) + # removes black borders from legend
coord_polar(theta='y') +
theme(axis.ticks=element_blank(),
axis.text.y=element_blank(),
axis.text.x=element_text(colour='black'),
axis.title=element_blank()) +
scale_y_continuous(breaks=cumsum(dat[[totals]]) - dat[[totals]] / 2, labels=dat[[by]])
}</code></pre>
<p>For example:</p>
<pre><code class="language-r">library(grid) # for `unit`
ggpie(df, by='activity', totals='time') +
ggtitle("A fun but wasteful week.") +
theme(axis.ticks.margin=unit(0,"lines"),
plot.margin=rep(unit(0, "lines"),4))</code></pre>
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-VZndb208OS4/U6vDOFthMbI/AAAAAAAAD98/kwkKCA5oSjQ/s1600/unnamed-chunk-11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-VZndb208OS4/U6vDOFthMbI/AAAAAAAAD98/kwkKCA5oSjQ/s1600/unnamed-chunk-11.png" /></a></div>
<p>(Note: for some reason the pie plots have an unreasonably large amount of white space, and the <code>theme(*.margin)</code> settings are an attempt to control that. However, I still get a lot of vertical space that I'm not sure how to compress).</p>
<p>Clearly the labels could do with more work (if they are too long they go out of the plot boundary, or they bump into the pie chart), but not bad for an hour and a half's work :)</p>
mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com17tag:blogger.com,1999:blog-7039473604287682752.post-5664517076272450802013-12-12T18:16:00.000-08:002014-06-25T23:10:59.906-07:00A Prism Syntax Highlighter for R<p>(<strong>Update</strong>: description of a known issue, below the numbered list.) As I mentioned in <a href="http://mathematicalcoffee.blogspot.com.au/2013/05/searching-for-syntax-highlighter-for-r.html">a previous post</a>, I've recently begun to use Lea Verou's fantastic <a href="http://prismjs.com/">PrismJS</a> to do syntax highlighting on this blog.</p>
<p>As I could not find an R plugin for PrismJS, I wrote one myself. PrismJS highlighting is regex based, which means that while it sometimes makes mistakes with highlighting, it's easy to add in a new language.</p>
<p>You can see a demo <a href="http://bl.ocks.org/mathematicalcoffee/raw/5655496/"><strong>here</strong></a> and get the script/style <a href="https://gist.github.com/mathematicalcoffee/5655496#file-prism-r-js">from my gist</a> (I've also embedded the gist at the end of this post). It's similar to <a href="http://yihui.name/en/2010/09/syntaxhighlighter-brush-for-the-r-language/">Yihui Xie's SyntaxHighlighter brush for R</a>.</p>
<p>Without further ado, here's a demonstration:</p>
<pre class="language-r"><code>n <- 10
for (i in seq_len(n)) {
# say hello, many times
message("hello world")
}</code></pre>
<p>You can grab the files <a href="http://gist.github.com/mathematicalcoffee/5655496">from my gist</a>; you can also <a href="http://bl.ocks.org/mathematicalcoffee/raw/5655496/"><strong>view an example page demonstrating 3 different themes</strong></a> I modified earlier.</p>
<p>To use it:</p>
<ol style="list-style-type: decimal">
<li><p>Host the the <a href="http://prismjs.com/download.html">PrismJS</a> and <a href="https://gist.github.com/mathematicalcoffee/5655496#file-prism-r-js">R PrismJS</a> script somewhere and include them (note: you may wish to minify the R script and add it to the end of your PrismJS script so you only need to include one file):</p>
<pre class="language-markup"><code><script src='prism.js'></script>
<script src='prism.r.js'></script></code></pre></li>
<li><p>Include the stylesheet of your choice. You may wish to also define style classes for <code>.token.function</code>, <code>.token.variable</code> and <code>.token.namespace</code>, to determine how functions, variables, and namespaces are styled (the stylesheets <a href="http://gist.github.com/mathematicalcoffee/5655496">on my gist</a> have this already):</p>
<pre class="language-markup"><code><link rel='stylesheet' href='prism.css' /></code></pre></li>
<li><p>Any R code you want to be syntax highlighted should have <code>class="language-r"</code> on it (note: on the <code>code</code> tag, not the <code>pre</code> tag). Works for inline code too.</p></li>
</ol>
<p>Et Voila!</p>
<p><strong>Update:</strong> There is a <a href="http://bl.ocks.org/mathematicalcoffee/raw/5655496/index.html#known-issue"><strong>known issue</strong></a> whereby hash tags within strings will be highlighted as comments. There are a number of workarounds mentioned in the link, though each has a use that will break it (regex-based highlighters always have these problems).</p>
<p>You can <a href="http://bl.ocks.org/mathematicalcoffee/raw/5655496/">view my gist via bl.ocks.org</a> to see a larger code snippet, and play around with a few themes I modified to make the R look pretty: Okaidia (the one from PrismJS), Zenburn (based off the vim theme by <a href="http://slinky.imukuppi.org/zenburnpage/">Jami Nurminen</a>), and Tomorrow Night 80s (like the one from RStudio, by <a href="https://github.com/chriskempson/tomorrow-theme">Chris Kempson</a>). I'm using Tomorrow Night 80s on my blog.</p>
<script src="https://gist.github.com/mathematicalcoffee/5655496.js?file=prism.r.js"></script>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-13357967998677367522013-08-18T04:07:00.000-07:002013-08-18T04:08:37.545-07:00Tiny Crochet Despicable Me Minion<table style="clear: both; margin: auto; text-align: center;"><tr><td><a href="http://1.bp.blogspot.com/--MwS8N9DOlA/UhCk_VA3kKI/AAAAAAAAB0k/n-Cn5_2w660/s1600/P1020878.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/--MwS8N9DOlA/UhCk_VA3kKI/AAAAAAAAB0k/n-Cn5_2w660/s200/P1020878.JPG" /></a>
</td><td><a href="http://2.bp.blogspot.com/-5pVNh7TUq8Q/UhCqimW0tCI/AAAAAAAAB00/DrsQCBM_ZS0/s1600/minion.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-5pVNh7TUq8Q/UhCqimW0tCI/AAAAAAAAB00/DrsQCBM_ZS0/s1600/minion.png" /></a></td></tr></table>
<p>After I watched the first Despicable Me, I decided to try make one of the minions for my sister. Now that the second Despicable Me has come out I've been reminded to post my pattern.</p>
<p>At the time I was very much into making tiny little toys, so this pattern is specifically for a small minion - I used 4ply-equivalent cotton to make this minion and he stands 3 - 4cm tall when done. Since he's small (you not only make him in thinner yarn, he has less stitches in him), he relies on a fair bit of embroidery to get all of his features (face, arms, feet,...) as opposed to crochet. I.e., he is made smaller at the expense of detail (he might not look any good in wool or anything big).</p>
<p>If you wish to make a bigger minion or one with more detail/crochet in it, I recommend one of the <a href="http://www.ravelry.com/patterns/search#craft=crochet&query=minion&view=captioned_thumbs&sort=best&pc=toysandhobbies">many patterns</a> out on the net (ravelry is a nice way to collect them all, though they are not all hosted on ravelry). In particular, I like <a href="https://sites.google.com/site/crochetgoods/home/minion">this one from crochet-goods</a>. My pattern is based on this one, just with a greatly reduced number of stitches.</p>
<h2>Small minion</h2>
<table style="clear: both; margin: auto; text-align: center;"><tr><td><a href="http://1.bp.blogspot.com/--MwS8N9DOlA/UhCk_VA3kKI/AAAAAAAAB0k/n-Cn5_2w660/s1600/P1020878.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/--MwS8N9DOlA/UhCk_VA3kKI/AAAAAAAAB0k/n-Cn5_2w660/s200/P1020878.JPG" /></a>
</td><td><a href="http://4.bp.blogspot.com/-V0PWaDv17Vo/UhCk-ibQ6WI/AAAAAAAAB0c/ozyuY3BbcAQ/s1600/IMG_20130818_195424.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-V0PWaDv17Vo/UhCk-ibQ6WI/AAAAAAAAB0c/ozyuY3BbcAQ/s200/IMG_20130818_195424.jpg" /></a></td></tr>
<tr><td>slightly too happy minion</td><td>back of minion</td></tr></table>
<p>(I was going for "very happy" with the expression but I overshot a little and now he looks like a "special" minion :P)<br />
3-4cm tall (4ply cotton).<br />
Work it in the round without joining.</p>
<p><strong>Body (yellow)</strong><br />
R1: 6sc in magic ring. (6)<br />
R2: inc (2sc in ea sc) around (12)<br />
R3: *inc, sc* around (18)<br />
R4-R12: sc around (18)<br />
[add extra rows if you want a taller minion]<br />
R13: *sc, dec* around (12). Stuff.<br />
R14: dec around (6)<br />
Finish off.</p>
<p><strong>Overalls (blue)</strong><br />
R1: 6sc in magic ring (6)<br />
R2: inc around (12)<br />
R3: *inc, inc, sc* around (20)<br />
R4-R5: sc around (20)<br />
[add extra rows if you have a taller minion]<br />
R6 - 8: 5sc, ch1, turn [this is worked back and forth, not in the round, to make the front of the overalls].</p>
<p><strong>Assembly</strong><br />
Put the overalls on the minion.<br />
Using the blue/overall yarn, sl st into one corner of the overall front panel.<br />
Do a set of chain stitches to be the overall strap and attach to the back.<br />
Repeat on the other side.</p>
<p><strong>Finishing</strong><br />
Embroider a goofy expression onto the minion (but not as goofy as the one I did!).<br />
Stick some small googly eyes on and embroider on the goggles strap and goggles frames (I used silver wire for my goggles frames).<br />
Make the arms using a strand of yarn with a bead on the end.<br />
Use big beads to make the feet.<br />
Embroider the black and blue "G" logo on the front of the overalls and you're done!</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com2tag:blogger.com,1999:blog-7039473604287682752.post-50262646391405654662013-05-29T06:06:00.000-07:002013-05-29T06:06:18.644-07:00Searching for a Syntax Highlighter for R<p>I've recently been looking at various syntax highlighters I could add to my blog to prettify it a bit more.
The only criteria was that it had to be easy for me to incorporate into this blog (me being an interwebs ignoramus), and it should support syntax highlighting for R and Javascript, being two languages I post a lot of snippets of.</p>
<p>At a (very) cursory glance, I found a few options:</p>
<ul>
<li>the <a href="http://highlight.r-enthusiasts.com/">Highlight package for R</a>;</li>
<li><a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a>;</li>
<li><a href="http://prismjs.com">PrismJS</a>.</li>
</ul>
<h2>R-Highlight</h2>
<p>To use the <a href="http://highlight.r-enthusiasts.com/">highlight package for R</a>:</p>
<ul>
<li>include jQuery, the highlight script and CSS stylesheet;</li>
<li>initiate highlighting by using jQuery to select the nodes we wish to highlight and calling <code>r_syntax_highlight()</code>;</li>
<li>has a list of recognised functions that will be highlighted (no regex there);</li>
<li>can even cause each function to link to its documentation (!)</li>
</ul>
<p>However, the script seems to support the R language only (the highlight package when used from R appears to support many languages, but the script for webpages seems to only expose R syntax highlighting. I could be wrong here).</p>
<h2>Syntax Highlighter</h2>
<p>To use <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a>:</p>
<ul>
<li>include the script <code>shCore.js</code> and stylesheets <code>shCore.css</code>, <code>shThemeDefault.css</code>, <em>plus</em> the script for each language you wish to syntax highlight;</li>
<li>initiate highlighting by labelling <code><pre></code> tags to be highlighted with <code>class: "brush: <language>"</code>, and add a call to <code>SyntaxHighlighter.all()</code>;</li>
<li>does not support R out of the box, but <a href="http://yihui.name/en/2010/09/syntaxhighlighter-brush-for-the-r-language/">Yihui Xie has written a language definition for it</a> (regex-based).</li>
</ul>
<h2>PrismJS</h2>
<p>To use <a href="http://prismjs.com">PrismJS</a>:</p>
<ul>
<li>include the script <code>prism.js</code> and stylesheet <code>prism.css</code>;</li>
<li>mark code to be highlighted using <code><code class="language-<language>"></code>;</li>
<li>no need to call any functions to initiate highlighting;</li>
<li>does <strong>not</strong> support R out of the box, but languages can be defined using regexes.</li>
</ul>
<h2>Conclusion</h2>
<p>They all seem pretty awesome, and I absolutely love R-highlight's ability to link to a function's documentation as well as marking it up. All three are fairly easily themeable. I strongly recommend you check them all out.</p>
<p>However, in the end I went with PrismJS, because</p>
<ul>
<li>I couldn't work out how to use R-highlight for languages other than R (I often blog with Javascript snippets).</li>
<li>SyntaxHighlighter, while very popular, required me to host and link to many Javascript files (one per language). I didn't feel like doing this.</li>
<li>I love how PrismJS requires the <code>class="language-X"</code> part to be in the <em>code</em> tag, not the <em>pre</em> tag. A language is an attribute of code, not of a preformatted block, and as such you should mark a code block's language in the <code>code</code> tag, not the <code>pre</code> tag. Plus, this way of hinting the code language is <a href="http://www.w3.org/html/wg/drafts/html/master/Overview.html#the-code-element">recommended in the HTML5 specification</a>.</li>
<li>PrismJS requires me to include just two files; the script and stylesheet. In addition, it's tiny! With Javascript, R, HTML/XML, CSS and Bash highlighting support the file is all of 7.8kB. <3</li>
</ul>
<p>I wrote a syntax highlighter for R and PrismJS; I'll post it tomorrow (or whenever I get round to it). Here's a sneak-preview:</p>
<pre><code class="language-r"># iterate a dis/like of green eggs and ham
helloSam <- function (times=10, like=F) {
str <- paste('I', ifelse(like, 'like', 'do not like'), 'green eggs and ham!')
for (i in seq_len(times)) {
message(str)
}
}
</code></pre>
mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-21945339239223361352013-05-26T18:00:00.000-07:002013-05-29T05:01:32.705-07:00R gotcha - regular expressions<p>Just a quick post --- I came across this today and thought it was worth mentioning.</p>
<p>By default, the regular expression functions <code>grep</code>, <code>gsub</code>, <code>regexpr</code>, etc use extended regular expressions. By passing in <code>perl=TRUE</code> as an argument, one can use Perl regular expressions.</p>
<p>Note that in extended regular expressions, the <code>.</code> character matches the newline character <code>'\n'</code>. <strong>In Perl regular expressions, it doesn't.</strong></p>
<pre><code class="language-r">grep('.', '\n')
## [1] 1
grep('.', '\n', perl=T)
## integer(0)
</code></pre>
<p>Something to keep in mind if you use regular expressions in R with strings with embedded newlines and were having puzzling results.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-36741723173301845612013-04-17T18:38:00.001-07:002013-04-17T19:01:13.323-07:00Installing RStudio Server on Fedora 18<p>I'm trying to install <a href="http://www.rstudio.com/ide/download/server">RStudio Server</a> on Fedora 18 (64bit) but keep getting an error about <code>libcrypto.so.6</code> and <code>libssl.so.6</code>. (I didn't enable EPEL as I am not on RedHat/CentOS).</p>
<p>Following the installation instructions, I:</p>
<pre><code>wget http://download2.rstudio.org/rstudio-server-0.97.336-x86_64.rpm
sudo yum install --nogpgcheck rstudio-server-0.97.336-x86_64.rpm
</code></pre>
<p>But I get the error:</p>
<pre><code>Error: Package: rstudio-server-0.97.336-1.x86_64 (/rstudio-server-0.97.336-x86_64)
Requires: libcrypto.so.6()(64bit)
Error: Package: rstudio-server-0.97.336-1.x86_64 (/rstudio-server-0.97.336-x86_64)
Requires: libssl.so.6()(64bit)
</code></pre>
<p>If I look in <code>/usr/lib64</code> I have (both from the <code>openssl-libs</code> package: <code>yum provides /usr/lib64/libssl.so.10</code>):</p>
<pre><code>/usr/lib64/libcrypto.so.10
/usr/lib64/libssl.so.10
</code></pre>
<p>So it appears my package versions are too new for RStudio Server (!).</p>
<p>I decided to try the hacky solution of making some links from the old version to the new (hoping that they are backwards-compatible):</p>
<pre><code>sudo ln -s /usr/lib64/libcrypto.so.10 /usr/lib64/libcrypto.so.6
sudo ln -s /usr/lib64/libssl.so.10 /usr/lib64/libssl.so.6
</code></pre>
<p>Now I attempt to install again, and use <code>rpm --nodeps</code> instead of <code>yum</code> to force installation:</p>
<pre><code>sudo rpm -ivh --nodeps rstudio-server-0.97.336-x86_64.rpm
</code></pre>
<p>It works!</p>
<pre><code>Preparing... ################################# [100%]
Updating / installing...
1:rstudio-server-0.97.336-1 ################################# [100%]
rsession: no process found
Stopping rstudio-server (via systemctl): [ OK ]
Starting rstudio-server (via systemctl): [ OK ]
</code></pre>
<p>(Note - if it's still complaining to you about not finding libraries, try</p>
<pre><code>sudo ldd /usr/lib/rstudio-server/bin/rserver | grep 'not found'
</code></pre>
<p>You might get something like:</p>
<pre><code>libssl.so.6 => not found
libcrypto.so.6 => not found
</code></pre>
<p>This will tell you which libraries you need to make links for.)</p>
<p>I can test whether it worked OK by opening a browser and pointing it to <code>http://127.0.0.1:8787</code>:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-XyLXuhSSjEw/UW9NtEHT4eI/AAAAAAAAByU/zOzQDj33Zqs/s1600/rstudio.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://1.bp.blogspot.com/-XyLXuhSSjEw/UW9NtEHT4eI/AAAAAAAAByU/zOzQDj33Zqs/s320/rstudio.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Huzzah! RStudio Server!</td></tr>
</tbody></table>
</p>
<p>To enable external access I had to open port 8787 for my firewall (you could use the firewall applet for this instead of command-line)</p>
<pre><code>iptables -A INPUT -p tcp --dport 8787 -j ACCEPT
</code></pre>
<p>Now I can continue with the <a href="http://www.rstudio.com/ide/docs/server/getting_started">rest of the instructions</a>! Yay!</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com2tag:blogger.com,1999:blog-7039473604287682752.post-29996028356240081252013-04-16T19:29:00.000-07:002013-05-29T05:10:30.612-07:00Getting RStudio to include your `R_LIBS_USER` in its library paths.<p>I recently installed <a href="http://www.rstudio.com/">RStudio</a> Desktop version on my Linux computer, as I wanted to test it out.
Previously I'd been happily using R from the command-line.
</p>
<p>However, it kept complaining that I didn't have the <a href="http://yihui.name/knitr/"><code>knitr</code></a> package installed.</p>
<p>Starting <code>R</code> from the command-line, I found that I <em>did</em> have knitr installed - <code>library(knitr)</code> worked fine!
But <code>library(knitr)</code> from RStudio gave the errror:</p>
<pre><code>Error in library(knitr) : there is no package called ‘knitr’
</code></pre>
<p>Upon further inspection, I realised that my package library paths were between R-command-line and RStudio, despite the R executable being identical between the two.</p>
<p>My usual R library for command-line R is <code>~/R/library</code>, and this was in the <code>.libPaths()</code> as expected (executed from R from the command line).</p>
<p>However, when I executed <code>.libPaths()</code> from RStudio, I got:</p>
<pre><code class="language-r">[1] "/usr/local/lib/R/site-library" "/usr/lib/R/site-library"
[3] "/usr/lib/R/library" "/usr/lib/rstudio/R/library"
</code></pre>
<p>So why did the same R binary produce different library paths?</p>
<p>It turns out that I set my default path <code>~/R/library</code> by setting my <code>R_LIBS_USER</code> environment variable in my <code>.bashrc</code> file:</p>
<pre><code class="language-bash">export R_LIBS_USER=$HOME/R/library
</code></pre>
<p>but RStudio was not reading my <code>.bashrc</code> file when it started up (makes sense I guess, as it's not running from the terminal).</p>
<p>The solution was to create a file <code>~/.Renviron</code> and set the <code>R_LIBS_USER</code> variable there.
R looks for this file upon starting up to set environment variables (see also <a href="http://stat.ethz.ch/R-manual/R-patched/library/base/html/Startup.html"><code>?Startup</code></a>):</p>
<pre><code class="language-bash">R_LIBS_USER=~/R/library
</code></pre>
<p>(Note - I could also just do <code>.libPaths(c('~/R/library', .libPaths())</code> in an <code>.Rprofile</code> file, but I don't use those in general).</p>
<p>Now I start up RStudio and hey presto! It all works.</p>
<p>Thanks to the folk at <a href="http://stackoverflow.com/">StackOverflow</a>, in particular <a href="http://stackoverflow.com/users/1201032/flodel">flodel</a> and <a href="http://stackoverflow.com/users/143305/dirk-eddelbuettel">Dirk EddelBuettel</a>, who helped me work this out (the question has probably been deleted since then as it was too localized and probably should have been asked at the <a href="http://support.rstudio.org/help/discussions">RStudio support page</a>).</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com2tag:blogger.com,1999:blog-7039473604287682752.post-45106938016099641092012-11-29T18:26:00.001-08:002013-05-29T05:13:17.134-07:00Sending notifications in GNOME shell<p>This is a quick tutorial on how to send notifications in gnome shell from an extension/javascript (you can also send them over DBus but that's for another day).</p>
<ul>
<li><a href="#recipe">Recipe</a></li>
<li><a href="#longer-recipe">Longer recipe</a></li>
<li><a href="#explanation">Explanation</a></li>
<li><a href="#code">Code snippets</a></li>
</ul>
<h2><a name="recipe">Recipe</a></h2>
<p>For those of you who can't wait, here is the quick way to pop up a notification:</p>
<pre><code class="language-javascript">Main.notify('notification title', 'notification summary');
</code></pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-oMJRlmrw2Wg/ULgMMVu7tmI/AAAAAAAABuw/ixwIHPO6PYQ/s1600/main_notify.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="24" src="http://4.bp.blogspot.com/-oMJRlmrw2Wg/ULgMMVu7tmI/AAAAAAAABuw/ixwIHPO6PYQ/s320/main_notify.png" width="320" /></a></div>
<p>The above function <code>Main.notify</code> does a number of things. I'll explain them in the next section:</p>
<h2><a name="longer-recipe">Longer recipe</a></h2>
<p>To make notifications in gnome shell, you essentially create a Source (a source of notifications) and add it to the message tray, and then make a Notification and notify it from the source.</p>
<p>The basic steps shown below demonstrate this, although in practice one may wish to use various subclasses of the Source or Notification classes.</p>
<ol>
<li><p>Create a <em>subclass of</em> <code>MessageTray.Source</code> (in GNOME 3.2 or 3.4), or a <code>MessageTray.Source</code> in GNOME 3.6:</p>
<pre><code class="language-javascript">// example in GNOME 3.2 and 3.4.
// SystemNotificationSource subclasses MessageTray.Source
let source = new MessageTray.SystemNotificationSource();
// example in GNOME 3.6 - we can use MessageTray.Source() directly
let source = new MessageTray.Source('source title', 'source-icon-name');
</code></pre></li>
<li><p>Create a Notification, passing in the source, title, and summary:</p>
<pre><code class="language-javascript">let notification = new MessageTray.Notification(source,
'notification title',
'notification summary');
</code></pre></li>
<li><p>Add the source to the message tray. This is so that the icon appears in the message tray (and no notification will pop up unless its source is added):</p>
<pre><code class="language-javascript">Main.messageTray.add(source);
</code></pre></li>
<li><p>Either notify the notification from the source, or simply add it (without notifying):</p>
<pre><code class="language-javascript">// adds the notification to the source and pops it up
source.notify(notification);
// OR:
// just adds the notification to the source (doesn't pop it up)
source.pushNotification(notification);
</code></pre></li>
</ol>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-bs8Xv4yBA2o/ULgQGcJXncI/AAAAAAAABvg/_KU82yHMcB0/s1600/notification_source.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="63" src="http://2.bp.blogspot.com/-bs8Xv4yBA2o/ULgQGcJXncI/AAAAAAAABvg/_KU82yHMcB0/s320/notification_source.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The example we will work through in this post</td></tr>
</tbody></table>
<h2><a name="explanation">Explanation</a></h2>
<p>Here I'll explain the two main classes: a <code>Source</code> and a <code>Notification</code>.</p>
<h3>Source</h3>
<p>Think of a <code>Source</code> as a source of notifications - many notifications can come from the same source (for example many email notifications coming from your one email client).
In fact, all notifications <em>require</em> a source.</p>
<p>You can also think of a <code>Source</code> as the icon in the message tray (that you click on to show its notifications).</p>
<p>The basic <code>Source</code> class is <code>MessageTray.Source</code>. To be used, it needs to know what icon to show in the Message Tray.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-0wVeJen0zBI/ULgNiDmCJzI/AAAAAAAABvI/51t9Ws0L02I/s1600/source.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-0wVeJen0zBI/ULgNiDmCJzI/AAAAAAAABvI/51t9Ws0L02I/s1600/source.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The Source provides the icon in the message tray. </td></tr>
</tbody></table>
<h4>GNOME 3.6</h4>
<p>In GNOME 3.6, the way to do this is to feed the icon's name into <code>MessageTray.Source</code>'s constructor (along with the title of the source):</p>
<pre><code class="language-javascript">let source = new MessageTray.Source("Source title", 'avatar-default');
</code></pre>
<p>Alternatively if you wanted something more fancy, you could override <code>Source.createIcon(size)</code> in a subclass to return an icon of the appropriate size for the source.</p>
<h4>GNOME 3.2, 3.4</h4>
<p>In GNOME 3.2 and 3.4, you tell the Source what icon it should show in the message tray with one of two methods:</p>
<p>a. when you create a notification for the source, set the icon explicitly in the notification, <strong>OR</strong>
b. subclass it, implement the <code>createNotificationIcon()</code> function and call <code>_setSummaryIcon</code> with it in the constructor.</p>
<p>Method b. is the one most commonly used, but to do method a) you feed in an object as the fourth parameter to MessageTray.Notification with an 'icon' property (explained a bit more in the Notification section):</p>
<pre><code class="language-javascript">let source = new MessageTray.Source("source title");
let notification = new MessageTray.Notification(source,
"notification title",
"notification message",
{icon: new St.Icon({
icon_name: 'avatar-default',
icon_size: source.ICON_SIZE})
});
// add the source to the message tray and pop up the notification
Main.messageTray.add(source);
source.notify(notification);
</code></pre>
<p>The bare minimum implementation of a subclass of MessageTray.Source (to demonstrate method b.) is:</p>
<pre><code class="language-javascript">const MySource = new Lang.Class({
Name: 'MySource',
Extends: MessageTray.Source,
_init: function (title) {
// call the parent constructor
this.parent(title);
// set our icon
this._setSummaryIcon(this.createNotificationIcon());
},
// this should return an icon to show in the message tray. You can use
// this.ICON_SIZE for a default icon size if you want.
createNotificationIcon: function () {
return new St.Icon({
icon_name: 'avatar-default',
icon_size: this.ICON_SIZE
});
}
});
</code></pre>
<p>One would use it like so:</p>
<pre><code class="language-javascript">let source = new MySource("source title");
let notification = new MessageTray.Notification(source, "title", "message");
// add the source to the message tray and pop up the notification
Main.messageTray.add(source);
source.notify(notification);
</code></pre>
<h3>Notification</h3>
<p>Recall that every notification must belong to a source. Once a notification is added to its source, it can also be "notified".</p>
<p>When a notification is "notified", it pops up from the bottom of the screen showing the user the notification's title and the first line of its details (if they fit).</p>
<table align="center" cellpadding="5" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-cEjWF-t6Qtc/ULgMPHxPG-I/AAAAAAAABu4/RtiaVtSO10c/s1600/notification_banner.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="23" src="http://3.bp.blogspot.com/-cEjWF-t6Qtc/ULgMPHxPG-I/AAAAAAAABu4/RtiaVtSO10c/s320/notification_banner.png" width="320" /></a></div>
<a href="http://2.bp.blogspot.com/-bs8Xv4yBA2o/ULgQGcJXncI/AAAAAAAABvg/_KU82yHMcB0/s1600/notification_source.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="63" src="http://2.bp.blogspot.com/-bs8Xv4yBA2o/ULgQGcJXncI/AAAAAAAABvg/_KU82yHMcB0/s320/notification_source.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A notification upon being notified (above); the same notification being opened from its source (below). </td></tr>
</tbody></table>
<p>Hovering the mouse over the notification will expand it, showing the full summary of the notification.</p>
<p>Actually <em>clicking</em> on the notification will usually dismiss it (unless you override this behaviour).</p>
<p>After a while the notification will time out, dropping back down off the screen.</p>
<p>After this happens there are a couple of options:</p>
<ul>
<li>if the notification is set as "transient", it will disappear forever. Make a notification transient with <code>notification.setTransient(true)</code>.</li>
<li>otherwise (the default), it will now reside in the message tray. Clicking on the notification's icon in the message tray will show the notification, from which it may be dismissed (by clicking on it).</li>
<li>if you want a notification to <em>never</em> be able to be dismissed (by clicking on it after clicking on its source in the message tray), you can set the notification to be "resident". Do this with <code>notification.setResident(true)</code>.</li>
</ul>
<p>The base notification class is <code>MessageTray.Notification</code>, and it allows the construction of very versatile notifications.
At its most basic, the notification has a text title and a text summary:</p>
<pre><code class="language-javascript">let notification = new MessageTray.Notification(source,
'notification title',
'notification message');
</code></pre>
<p>One can also feed in an (optional) parameters object giving the notification's icon. One typically uses an icon size of <code>source.ICON_SIZE</code> (24 pixels) to create the icon:</p>
<pre><code class="language-javascript">// source is whatever Source this notification belongs to
let notification = new MessageTray.Notification(
source,
'notification title',
'notification message', {
icon: new St.Icon({
icon_name: 'avatar-default',
icon_size: source.ICON_SIZE
})
});
</code></pre>
<p>However, it is also possible to construct much more complex notifications. One can add buttons to the notification with <code>notification.addButton</code>, add extra text labels to it with <code>notification.addBody</code>, or extra actors (entry boxes, pictures, ...) to it with <code>notification.addActor</code>.</p>
<p>For an example of a notification with buttons on it, see the Telepathy Client <code>AudieoVideoNotification</code> (in <code>telepathyClient.js</code>), which has two buttons for the user to accept or reject a call.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-vAP7p56Lajo/UFLK-ZQG_tI/AAAAAAAABjY/HZFWcbGqBs0/s1600/telepathyClient.AudioVideoNotification.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="93" src="http://1.bp.blogspot.com/-vAP7p56Lajo/UFLK-ZQG_tI/AAAAAAAABjY/HZFWcbGqBs0/s320/telepathyClient.AudioVideoNotification.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">AudioVideoNotification has had buttons added</td></tr>
</tbody></table>
<p>For an example of a very complex notification, see the <code>TelepathyClient.ChatNotification</code> in <code>telepathyClient.js</code>. This adds chat texts to a scrollable area, and adds an entry box for typing chat messages.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-fYqil14Dmz4/UFLK_SF73wI/AAAAAAAABjg/Bmvp_vOZLao/s1600/telepathyClient.Chat.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="179" src="http://3.bp.blogspot.com/-fYqil14Dmz4/UFLK_SF73wI/AAAAAAAABjg/Bmvp_vOZLao/s320/telepathyClient.Chat.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">ChatNotifiation is a very complex custom notification</td></tr>
</tbody></table>
<h2><a name="code">Bringing it all together</a></h2>
<p>Code snippet - notifying a notification with the 'avatar-default' icon. This will create the notification shown below.</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-bs8Xv4yBA2o/ULgQGcJXncI/AAAAAAAABvg/_KU82yHMcB0/s1600/notification_source.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="63" src="http://2.bp.blogspot.com/-bs8Xv4yBA2o/ULgQGcJXncI/AAAAAAAABvg/_KU82yHMcB0/s320/notification_source.png" width="320" /></a></div>
<h3>GNOME 3.2 and 3.4</h3>
<p>Where we give the source icon via the notification:</p>
<pre><code class="language-javascript">// 1. Make a source
let source = new MessageTray.Source("source title");
// 2. Make a notification
let notification = new MessageTray.Notification(source,
"notification title",
"notification message",
{icon: new St.Icon({
icon_name: 'avatar-default',
icon_size: source.ICON_SIZE
})});
// 3. Add the source to the message tray
Main.messageTray.add(source);
// 4. notify!
source.notify(notification);
</code></pre>
<p>Where we create our own source subclass:</p>
<pre><code class="language-javascript">const MySource = new Lang.Class({
Name: 'MySource',
Extends: MessageTray.Source,
_init: function (title) {
// call the parent constructor
this.parent(title);
// set our icon
this._setSummaryIcon(this.createNotificationIcon());
},
// this should return an icon to show in the message tray. You can use
// this.ICON_SIZE for a default icon size if you want.
createNotificationIcon: function () {
return new St.Icon({
icon_name: 'avatar-default',
icon_size: this.ICON_SIZE
});
}
});
// 1. Make a source
let source = new MySource("source title");
// 2. Make a notification
let notification = new MessageTray.Notification(source,
"notification title",
"notification message");
// 3. Add the source to the message tray
Main.messageTray.add(source);
// 4. notify!
source.notify(notification);
</code></pre>
<h3>GNOME 3.6</h3>
<pre><code class="language-javascript">// 1. Make a source
let source = new MessageTray.Source("source title", 'avatar-default');
// 2. Make a notification
let notification = new MessageTray.Notification(source,
"notification title",
"notification message");
// 3. Add the source to the message tray
Main.messageTray.add(source);
// 4. notify!
source.notify(notification);
</code></pre>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-38630782121727146512012-11-14T04:51:00.004-08:002012-11-14T04:52:39.891-08:00Solar Eclipse, Cairns 2012On 14 Nov 2012 right in the morning, there was a total solar eclipse viewable from Cairns, QLD Australia.
As I live in QLD I decided to see the eclipse - a real treat, as I've never seen one before, and a *total* (as opposed to partial or annular) solar eclipse is a fairly rare occurence in one's lifetime. I rationed off one day of leave, flying up the night before the eclipse and back the following evening.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-Bo3GBxlx3wo/UKOQIE3JGwI/AAAAAAAABtU/FiJMtiZAfQU/s1600/P1050013.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="240" src="http://3.bp.blogspot.com/-Bo3GBxlx3wo/UKOQIE3JGwI/AAAAAAAABtU/FiJMtiZAfQU/s320/P1050013.JPG" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">CLOUD, Y U NO MOVE?</td></tr>
</tbody></table>
Wednesday morning, 5AM. I wake up and head out to Cairns esplanade, and am greeted by this dismal weather (come on QLD, we're the "Sunshine State"??!!):
<br />
<br />
It will clear up, right? There's an hour until totality....No. See that big fat cloud over the peninsula? Well, it conspired to cover the sun for the ENTIRE FIRST THREE QUARTERS of the eclipse.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-6QmXdu6XKtQ/UKOQbObDtuI/AAAAAAAABtg/Z6JweFa4gnU/s1600/P1050017.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="http://1.bp.blogspot.com/-6QmXdu6XKtQ/UKOQbObDtuI/AAAAAAAABtg/Z6JweFa4gnU/s320/P1050017.JPG" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">ooooo, creepy. It's dark but it's 6.40am!</td></tr>
</tbody></table>
Still, totality was cool when it happened - the sky got dark and the birds all stopped flying/chattering.<br />
<br />
It's a shame we didn't get to actually *see* the sun though (and still hadn't all morning), because that's one of the main points of a
total solar eclipse (being able to look at the sun with your naked eye). I always thought an eclipse would be pitch-black, but turns out it's more like twilight.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-GXF-PPjlBpY/UKOQiZz5_FI/AAAAAAAABts/-_5lvOWL3jg/s1600/eclipse.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="241" src="http://4.bp.blogspot.com/-GXF-PPjlBpY/UKOQiZz5_FI/AAAAAAAABts/-_5lvOWL3jg/s320/eclipse.JPG" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Yay I got to use my eclipse glasses!</td></tr>
</tbody></table>
It lasted a couple of minutes before the sky got bright again.
And then, 20 minutes <i>after</i> totality had finished, the sun *finally* decided to peek its head out from the cloud obscuring it, so we all got to see it for the first time that morning. By then the moon was only about 50% covering the sun and on the way out, but at least I got to use my eclipse glasses!<br />
<br />
I was trying to keep a positive attitude about it all, but then I got to the airport and caught the plane back home with everyone else from my city who'd also gone to see the eclipse.
<br />
Apparently had I been just 20mins drive south, west, or north of Cairns (or really anywhere *except* Cairns), the clouds would have cleared <b>just in time for me to see the totality</b>!<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-DLykfLZQneY/UKORpigQK5I/AAAAAAAABuE/XkLb3IHKLlo/s1600/P1050019.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="http://4.bp.blogspot.com/-DLykfLZQneY/UKORpigQK5I/AAAAAAAABuE/XkLb3IHKLlo/s320/P1050019.JPG" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">In the absence of a sun to look at, I could look at other things.<br />
Like this cloud floating way too low?!?!<br />
(It definitely isn't steam coming from the boat...)</td></tr>
</tbody></table>
AAARRRRGHHHHHH!! Did everyone see the eclipse except me??!! To make matters worse, had I stayed in my home city I would have at least seen an 80% eclipse whereas because of the clouds in Cairns I only saw about a 50%!<br />
<br />
Ahh well. I'm trying really hard to remain positive about it, although it's hard when you've gone so far only to miss by a 20minute drive.
Next time...(we don't get another total eclipse in Australia til 2028).<br />
<br />
Or...Anyone up for a holiday to <a href="http://en.wikipedia.org/wiki/Solar_eclipse_of_March_9,_2016">Indonesia in March 2016</a>? Anyone? :D
mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com2tag:blogger.com,1999:blog-7039473604287682752.post-43206370734707361852012-11-08T17:07:00.001-08:002013-05-29T05:15:40.515-07:00Upgrading your GNOME shell extensions from 3.4 to 3.6<p>I recently started upgrading all my extensions from 3.4 to 3.6. Here are a few things I ran into:</p>
<h3>New useful things:</h3>
<ul>
<li><p>you can reload just a single extension rather than restarting GNOME-shell. To do it by UUID:</p>
<pre><code class="language-javascript">Main.shellDBusService._extensionSerivce.ReloadExtension(UUID)
// ** NOTE ** the typo 'Serivce' --> this is a typo in 3.6.0 and 3.6.1
</code></pre></li>
</ul>
<p>OR, if you prefer not to have the typo:</p>
<pre><code class="language-javascript"> const ExtensionUtils = imports.misc.extensionUtils;
const ExtensionSystem = imports.ui.extensionSystem;
ExtensionSystem.reloadExtension(ExtensionUtils.extensions[UUID]);
</code></pre>
<h3>Gotchas for extension developers!</h3>
<p>Whenever you enter the lock screen all the extensions get disabled until the user logs back in, and then they get re-enabled.</p>
<p>This means: <strong>your extension must be able to disable and re-enable itself smoothly!</strong></p>
<p>Before this wasn't so important because typically a user does not toggle their extensions on and off many times within one session; so extensions typically get enabled once (when the user logs in) and not disabled until the user logs out, after which it doesn't matter whether it disables cleanly or not.</p>
<p>I've noticed quite a few extensions (including most of mine, oops...) that don't disable cleanly at the lock screen and hence don't re-enable cleanly once unlocked, causing all sorts of havoc...</p>
<h3>Changes (some)</h3>
<p>Some changes I noticed (certainly not all of them; just ones relevant to <a href="https://extensions.gnome.org/accounts/profile/mathematical.coffee">my extensions</a> and a few others I use):</p>
<ul>
<li><code>~/.xsession-errors</code> got renamed to <code>~/.cache/gdm/session.log</code> (calls to <code>log</code> output here, as well as in the terminal if you're running gnome-shell from the terminal).</li>
<li><code>panel._menus</code> -> <code>panel.menuManager</code> (main panel popup menu manager is now public)</li>
<li><code>panel._statusArea</code> -> <code>panel.statusArea</code> (status area is now public)</li>
<li><code>panel._dateMenu</code> -> <code>panel.statusArea.dateMenu</code> (date menu etc have all been stored in the status area and now is public)</li>
<li><code>panel._appMenu</code> -> <code>panel.statusArea.appMenu</code> (app menu moved to the status area, and now is public)</li>
<li><code>overview._workspacesDisplay</code> -> <code>overview._viewSelector._workspacesDisplay</code> (the "windows" tab of the overview)</li>
<li>search providers: in GNOME 3.4 we had <code>getInitialResultSet</code> (which returns an array of results) and <code>getInitialResultSetAsync</code> (which calls <code>this.searchSystem.pushResults</code>). In GNOME 3.6 there is <em>just</em> <code>getInitialResultSet</code>, which takes an extra argument <code>callback</code> and should call <code>this.searchSystem.pushResults</code> on the results (rather than returning them) and <em>also</em> apply <code>callback</code> to the results.</li>
<li>Use <code>Main.panel.addToStatusArea(unique_name_of_indicator, inidicator, position, box)</code> to add a SystemStatusButton or PanelButton to the panel. This handles adding its menu to the menu manager for you (box is Main.panel._{left, right, center}Box, omitting the box argument gives right box by default, and ommitting position gives position 0). If your button is a ButtonBox only (i.e. no menu) then stick with. <code>_{left, right, center}Box.insert_child_at_index</code>.</li>
<li>Symbolic/Full-colour Icons: previously system status buttons would always do a symbolic icon. Now they will do either full colour or symbolic. Use 'iconname' to get the full colour and 'iconname-symbolic' to get symbolic icons (so if your extension made a SystemStatusButton in 3.4, to get it looking the same in 3.6 you have to add '-symbolic' to the icon name).</li>
<li>Overview - the "tab" system where you could click on the "Windows" or "Applications" tab has been removed (!!!). Instead the windows tab is shown by default (as before) and to get to the application tab you click on the applications button on the dash. This means you can no longer simply add your own tabs to the overview, like <a href="https://extensions.gnome.org/extension/320/extension-list/">the Extension List extension</a> did (which added an "Extensions" tab to manage your extensions from). This is a <strong>major</strong> regression, in my opinion!</li>
<li>Looking glass - there's no longer an "Errors" tab. <code>global.log</code> used to output to the Errors tab whereas <code>log</code> would output to the terminal. Now they all output to the terminal if you're running from the terminal (makes more sense than having two separate logging systems).</li>
<li>System status icons and panel menu buttons. The top-level actor 'indicator.actor' is <em>NOT</em> the top-level actor that is placed into the panel. There is a new member 'indicator.container' which is a St.Bin that <em>contains</em> 'indicator.actor', and 'indicator.conainer' is what gets put into the panel boxes. So if you were previously looping through *Box.get_children() and accessing <code>child._delegate</code> to get the associated <code>PanelMenu.Button</code>, now you have to access <code>child.child._delegate</code>.</li>
<li>StatusIconDispatcher - in GNOME 3.2 and 3.4, this listens to icons being added by application to the tray (for example Dropbox) and depending on the type, either emits 'status-icon-added' or 'message-icon-added'. The Panel listens to the former to make a button in the top panel for the icon, and the NotificationDaemon listens to the latter to make an icon in the message tray for the icon. This let some icons be "dispatched" to the top panel and others to the bottom without overlap. In 3.6, this class has been removed and the functionality implemented directly into the classes; if the notification daemon gets 'tray-icon-added' it will make an icon in the message tray for it <em>unless</em> it's a standard status icon, but the top panel <em>won't</em> make top panels for these.</li>
<li>Contact Search Provider (contactDisplay.js) was removed. Apparenty <code>gnome-contacts</code> is implementing one so it's no longer necessary.</li>
<li>lock screens: there is a new lock screen in GNOME3.6 that wasn't there in 3.4. It's the one where you have to swipe up (to drag the screen up).</li>
</ul>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com1tag:blogger.com,1999:blog-7039473604287682752.post-80414836594230248222012-09-14T05:39:00.002-07:002013-05-29T05:17:33.520-07:00GNOME shell: Javascript Source Documentation (extensions development)<p>When you try to write gnome shell extensions, you quickly realise that while there's plenty of documentation for imported libraries like <a href="http://developer.gnome.org/clutter/stable/">Clutter</a>, there is none for the Javascript files that make up gnome-shell's Javascript side (<code>/usr/share/gnome-shell/js/ui</code>). This is a quick summary of files in <code>/usr/share/gnome-shell/js/ui</code> and <code>/usr/share/gnome-shell/misc</code> and what's in them. I compiled the list because it helps me to learn more about the source. Feel free to correct bits (I certainly have some things wrong).</p>
<h3>Important notes/caveats</h3>
<ul>
<li>This is based off GNOME 3.2/3.4 JS source. When I say 'GNOME 3.4 only' it might mean 'GNOME 3.4+', but I don't have the source for anything later to check.</li>
<li>This is just a reference list, not full documentation or anything. Use this to get a quick idea of what is in what file, and then <em>go and read that file</em> for further information.</li>
<li><strong>I might not be correct!</strong> I mainly did this so that <em>I</em> could learn things, and I don't always get them right ;) In particular, I'm quite confused about DBus and the words "interface", "proxy", "server", "listener" - so I might misuse them.</li>
<li>I give a list of just the classes in the files, but sometimes there are other functions there instead of classes that may be useful.</li>
<li>Contributions welcome (perhaps I should put this page on some sort of wiki/versioning system so that other people can easily edit it).</li>
</ul>
<p>Let me know of mistakes/broken links.</p>
<h3>Quick links:</h3>
<ul>
<li><a href="#imports.ui">UI files</a> <code>/usr/share/gnome-shell/js/ui</code>, <code>imports.ui</code>.</li>
<li><a href="#imports.misc">miscellaneous files</a> <code>/usr/share/gnome-shell/js/misc</code>, <code>imports.misc</code>.</li>
</ul>
<p>(If you're interested: I use <a href="http://daringfireball.net/projects/markdown/">Markdown</a> to write blog posts and used the following command to generate the list of classes in each file for me to write explanations into. It missed some things like classes generated from DBus interface specifications but got all the other classes:</p>
<pre><code class="language-bash">cd /usr/share/gnome-shell/js/ui
for f in *.js
do
echo "### <a name='${f/.js/}'>"'`'$f'`'"</a>"
# GNOME 3.2:
# grep -oP '^([A-Za-z_0-9]+)(?=\.prototype)' $f | sed -r -e "s@(.+)@* <a name='${f/.js/}.\1'>"'`\1`'"</a>:@"
# GNOME 3.4:
grep -oP '([A-Za-z_0-9]+)(?= *= *new *Lang.Class)' $f | sed -r -e "s@(.+)@* <a name='${f/.js/}.\1'>"'`\1`'"</a>:@"
done
</code></pre>
<p>)</p>
<h1><a name='imports.ui'>UI files in <code>/usr/share/gnome-shell/js/ui</code> (<code>imports.ui</code>)</a></h1>
<ul>
<li><a href="#altTab"><code>altTab.js</code></a>: the popup that appears when you press <code>Alt+Tab</code>.</li>
<li><a href="#appDisplay"><code>appDisplay.js</code></a>: to do with the applications tab in the overview - searching for apps and displaying their icons.</li>
<li><a href="#appFavorites"><code>appFavorites.js</code></a>: manages app favourites in the dash (left hand sidebar in the overview).</li>
<li><a href="#automountManager"><code>automountManager.js</code></a>: handles the automagic detection of external media (USB sticks, ...).</li>
<li><a href="#autorunManager"><code>autorunManager.js</code></a>: handles the popup menu when you mount an external media offering you options to view photos, browse, play music, etc on the media.</li>
<li><a href="#boxpointer"><code>boxpointer.js</code></a>: whenever you open a popup menu there's a little arrow connecting the button to the menu. That's what this is.</li>
<li><a href="#calendar"><code>calendar.js</code></a>: stuff to do with the calendar in the clock dropdown menu.</li>
<li><a href="#checkBox"><code>checkBox.js</code></a> (<strong>GNOME 3.4 only</strong>): A checkbox (in < GNOME3.4 you just have the <a href="#popupMenu.Switch">PopupMenu.Switch</a>). As far as I can tell there's one in the Keyring Prompt and that's it.</li>
<li><a href="#contactDisplay"><code>contactDisplay.js</code></a>: Handles the display and searching of contacts in the Overview.</li>
<li><a href="#ctrlAltTab"><code>ctrlAltTab.js</code></a>: Handles the Accessibility switcher which lets you select UI elements (top panel, dash, ...) so that you can navigate around them with the keyboard (I never knew this existed!). According to <a href="https://live.gnome.org/GnomeShell/CheatSheet">here</a> it's not yet fully functional.</li>
<li><a href="#dash"><code>dash.js</code></a>: Handles the dash (left-hand sidebar in the overview showing the application favourites).</li>
<li><a href="#dateMenu"><code>dateMenu.js</code></a>: The graphical calendar widget in the calendar menu (the grid of squares where you click on the date to see events for that date).</li>
<li><a href="#dnd"><code>dnd.js</code></a>: Handles drag and drop.</li>
<li><a href="#docDisplay"><code>docDisplay.js</code></a> (<strong>GNOME 3.2 only</strong>): gives search results for 'recent items'. GNOME 3.4 doesn't have this.</li>
<li><a href="#endSessionDialog"><code>endSessionDialog.js</code></a>: the dialog that appears when you log out/shut down/etc.</li>
<li><a href="#environment"><code>environment.js</code></a>: sets up the GJS environment for the rest of the code.</li>
<li><a href="#extensionSystem"><code>extensionSystem.js</code></a>: handles installing, enabling, and disabling extensions.</li>
<li><a href="#flashspot"><code>flashspot.js</code></a> (<strong>GNOME 3.4 only</strong>): When you press the printscreen key and get a screenshot, the screen has this white flash (like a camera flash). This is that... (this also happens in GNOME 3.2, but it looks like the screenshot code has changed between 3.2 and 3.4).</li>
<li><a href="#iconGrid"><code>iconGrid.js</code></a>: classes for layout out icons in a grid (e.g. the Overview search results)</li>
<li><a href="#keyboard"><code>keyboard.js</code></a>: on-screen keyboard class.</li>
<li><a href="#keyringPrompt"><code>keyringPrompt.js</code></a> (<strong>GNOME 3.4 only</strong>): prompt for gnome-keyring.</li>
<li><a href="#layout"><code>layout.js</code></a>: stuff to do with laying out actors on the stage? (panel, message tray, hot corners, ...)</li>
<li><a href="#lightbox"><code>lightbox.js</code></a>: Creates a dark translucent shade covering a UI element (e.g. when the end session modal dialog causes the rest of the screen to be shaded; this is the shade).</li>
<li><a href="#link"><code>link.js</code></a>: defines links in the looking glass.</li>
<li><a href="#lookingGlass"><code>lookingGlass.js</code></a>: the looking glass (<code>Alt+F2</code>, 'r').</li>
<li><a href="#magnifierDBus"><code>magnifierDBus.js</code></a>: Shell magnifier (for accessibility): the Dbus interface.</li>
<li><a href="#magnifier"><code>magnifier.js</code></a>: Shell magnifier (for accessibility): the magnifier object itself (see <a href="https://live.gnome.org/GnomeShell/Magnification">Magnifier specification</a>).</li>
<li><a href="#main"><code>main.js</code></a>: This is what defines most of the global object instances in GNOME shell and sets everything up - the top panel, overview, .... Also defines a bunch of convenience functions.</li>
<li><a href="#messageTray"><code>messageTray.js</code></a>: the message tray (bottom of the screen showing notifications).</li>
<li><a href="#modalDialog"><code>modalDialog.js</code></a>: defines the gnome-shell popup dialogs (logout/shutdown, authentication, ...).</li>
<li><a href="#networkAgent"><code>networkAgent.js</code></a>: wrapper around network authentication (listens on dbus for password requests and pops up the authentication dialog).</li>
<li><a href="#notificationDaemon"><code>notificationDaemon.js</code></a>: listens for notifications via DBus and adds them to the message tray.</li>
<li><a href="#overview"><code>overview.js</code></a>: The overview (press the windows key).</li>
<li><a href="#panel"><code>panel.js</code></a>: Defines the top panel.</li>
<li><a href="#panelMenu"><code>panelMenu.js</code></a>: Defines various helper functions for items in the panel (notably, the system status icon class, being a button in the top panel with a dropdown menu).</li>
<li><a href="#placeDisplay"><code>placeDisplay.js</code></a>: Handles searching for Places (Home, Network, mounted volumes, ...) in the overview.</li>
<li><a href="#polkitAuthenticationAgent"><code>polkitAuthenticationAgent.js</code></a>: Handles popping up a password dialog on receiving authentication requests (e.g. on updating software).</li>
<li><a href="#popupMenu"><code>popupMenu.js</code></a>: Defines the popup menus and items that can go in them (for example the popup menu from the user menu).</li>
<li><a href="#remoteSearch"><code>remoteSearch.js</code></a> <strong>(GNOME 3.4 only)</strong>: Handles remote search providers (search providers that operate through DBus, like Google and Wikipedia where searches go through the internet).</li>
<li><a href="#runDialog"><code>runDialog.js</code></a>: The run dialog/command prompt when you pres <code>Alt+F2</code>.</li>
<li><a href="#scripting"><code>scripting.js</code></a>: A scripting module for gnome-shell devs to do performance/unit tests...(?)</li>
<li><a href="#searchDisplay"><code>searchDisplay.js</code></a>: Classes for displaying the results of a search in the overview.</li>
<li><a href="#search"><code>search.js</code></a>: Abstract classes that handle searching and providing results (that are then displayed in the overview by <code>searchDisplay.js</code> classes). They are all implemented through other classes (e.g. <a href="#appDisplay"><code>appDisplay.js</code></a>, <a href="#contactDisplay"><code>contactDisplay.js</code></a>, ...</li>
<li><a href="#shellDBus"><code>shellDBus.js</code></a>: GNOME shell DBus implementation (interface name <code>org.gnome.shell</code>, path <code>/org/gnome/Shell</code>) - for installing/enabling/disabling/uninstalling extensions and requesting information from them, taking screenshots, and so on.</li>
<li><a href="#shellEntry"><code>shellEntry.js</code></a>: Adds context menus to entry widgets with 'copy' and 'paste' and (if it's a password widget) 'show/hide text'. Examples: in the run dialog and authentication dialog.</li>
<li><a href="#shellMountOperation"><code>shellMountOperation.js</code></a>: Wrappers around <code>Shell.MountOperation</code> that handle the ejecting of a device from the <a href="#autorunManager.AutorunResidentNotification"><code>autorunManager.AutorunResidentNotification</code></a>. Provides a dialog letting you know if the device is busy/what processes are inhibiting unmounting and notifications if passwords are needed for the volume.</li>
<li><a href="#statusIconDispatcher"><code>statusIconDispatcher.js</code></a>: Diverts some message-tray icons into standard status area icons (for example 'gnome-sound-control-applet' and 'gnome-volume-control-applet' will be removed from the message tray as they are handled by the 'volume' status icon).</li>
<li><a href="#telepathyClient"><code>telepathyClient.js</code></a>: handles chat through telepathy and setting up notifications etc for these.</li>
<li><a href="#tweener"><code>tweener.js</code></a>: a module that wraps around <code>imports.tweener.tweener</code> adding extra goodness for gnome-shell (initialised in <a href="#main"><code>main.js</code></a>).</li>
<li><a href="#userMenu"><code>userMenu.js</code></a>: defines the user menu (with your username, chat status, avatar, ...).</li>
<li><a href="#viewSelector"><code>viewSelector.js</code></a>: The main part of the Overview - defining a notebook/tabs model. For example the 'Applications' and 'Windows' sections of the Overview are 'tabs' within the notebook.</li>
<li><a href="#wanda"><code>wanda.js</code></a> <strong>(GNOME 3.4 only)</strong>: Dispenses wisdom from Wanda the GNOME-panel fish from the overview if you type the magic phrase into the search box.</li>
<li><a href="#windowAttentionHandler"><code>windowAttentionHandler.js</code></a>: Handles requests for attention from windows (e.g. when you start up and app and it takes a while to start, when the app is done loading you get a '<application> is ready' notification).</li>
<li><a href="#windowManager"><code>windowManager.js</code></a>: Extra bells and whistles for the window manager implemented on the JS side (mainly window animations).</li>
<li><a href="#workspace"><code>workspace.js</code></a>: Classes handling the window previews you see in the 'Windows' tab of the Overview.</li>
<li><a href="#workspacesView"><code>workspacesView.js</code></a>: Essentially the 'Windows' tab in the Overview - handles assembling the window previews (from <code>workspace.js</code>) and the workspaces sidebar (<code>workspaceThumbnail.js</code>) into one 'tab' for the Overview.</li>
<li><a href="#workspaceSwitcherPopup"><code>workspaceSwitcherPopup.js</code></a>: The popup you get upon switching workspaces through the keybindings that shows you which workspace you're switching to.</li>
<li><a href="#workspaceThumbnail"><code>workspaceThumbnail.js</code></a>: Defines the classes in the workspaces sidebar in the 'Windows' tab of the Overview - the little snapshots of each workspace allowing you to drag windows between them.</li>
<li><a href="#xdndHandler"><code>xdndHandler.js</code></a>: GNOME-shell handling of <a href="http://en.wikipedia.org/wiki/X_Window_selection">Xdnd</a>: dragging and dropping things between an X window and a gnome-shell object. E.g. if you try to drag a file from Nautilus over the Overview button, <code>panel.js</code> uses <code>xdndHandler</code> to detect this and trigger the overview.</li>
<li><a href="#status"><code>status</code></a> directory: this contains the files for all the standard status indicators in the status area.
<ul>
<li><a href="#accessibility"><code>accessibility.js</code></a>: the accessibility (a11y) indicator.</li>
<li><a href="#bluetooth"><code>bluetooth.js</code></a>: the bluetooth indicator.</li>
<li><a href="#status.keyboard"><code>keyboard.js</code></a>: keyboard layout indicator (letting you switch between layouts).</li>
<li><a href="#network"><code>network.js</code></a>: the network (wifi/wired) indicator.</li>
<li><a href="#power"><code>power.js</code></a>: the power (battery life/power settings) indicator.</li>
<li><a href="#volume"><code>volume.js</code></a>: the volume/sound settings indicator.</li>
</ul></li>
</ul>
<hr />
<h2>Overview of classes in each file.</h2>
<h3><a name='altTab'><code>altTab.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-6soMhxap6PE/UFK8KnmDhVI/AAAAAAAABcA/0R9tCRzgaxw/s1600/altTabPopup.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="229" src="http://2.bp.blogspot.com/-6soMhxap6PE/UFK8KnmDhVI/AAAAAAAABcA/0R9tCRzgaxw/s400/altTabPopup.png" alt="altTabPopup" title="altTabPopup" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The <code>AltTabPopup</code>. <code>SwitcherList</code>s are outlined yellow and <code>AppIcon</code>s are outlined green. The <code>AppSwitcher</code> is the top one and the <code>ThumbnailList</code> is the bottom one (both <code>SwitcherList</code>s).</td></tr>
</tbody></table>
<ul>
<li><a name='altTab.AltTabPopup'><code>AltTabPopup</code></a>: the popup that shows all the window previous when you press <code>Alt+Tab</code></li>
<li><a name='altTab.AppIcon'><code>AppIcon</code></a>: class defining the icon for an app (used in the alt tab popup)</li>
<li><a name='altTab.SwitcherList'><code>SwitcherList</code></a>: Helper function defining a list of items to switch between when alt-tab is pressed (used for switching between apps and between windows of a particular app in the AltTab popup).</li>
<li><a name='altTab.AppSwitcher'><code>AppSwitcher</code></a>: This handles the display of icons for each app in the AltTab popup. Generates an <code>AppIcon</code> per app.</li>
<li><a name='altTab.ThumbnailList'><code>ThumbnailList</code></a>: This is what appears when you hover over an app with multiple windows in the AltTab popup (and it shows you a bunch of window thumbnails). It handles the list of thumbnails for a given app.</li>
</ul>
<h3><a name='appDisplay'><code>appDisplay.js</code></a></h3>
<table align="center" cellpadding="5" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-8s3m34ObOAE/UFLABYZZLkI/AAAAAAAABcc/kjZdbCkxEyg/s1600/appDisplay.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="http://3.bp.blogspot.com/-8s3m34ObOAE/UFLABYZZLkI/AAAAAAAABcc/kjZdbCkxEyg/s320/appDisplay.png" alt="appDisplay" title="appDisplay" width="320" /></a></td><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-zoHulCt54i4/UFLACBeiPzI/AAAAAAAABco/T5mRjJc3PVg/s1600/AppWellIcon.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="160" src="http://3.bp.blogspot.com/-zoHulCt54i4/UFLACBeiPzI/AAAAAAAABco/T5mRjJc3PVg/s320/AppWellIcon.png" alt="AppWellIcon" title="AppWellIcon" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>AlphabeticalView</code> is the grid displaying the apps. <code>ViewByCategory</code> handles the categories filter on the side. </td><td class="tr-caption" style="text-align: center;"><code>AppWellIcon</code> consisting of an <code>AppIcon</code> with an <code>AppIconMenu</code></td></tr>
</tbody></table>
<ul>
<li><a name='appDisplay.AlphabeticalView'><code>AlphabeticalView</code></a>: Based off <a href="#iconGrid.IconGrid">IconGrid.IconGrid</a> - a grid of application icons (<a href="#appDisplay.AppWellIcon">AppWellIcon</a>) that displays its results alphabetically (the grid of app entries the Applications tab).</li>
<li><a name='appDisplay.ViewByCategories'><code>ViewByCategories</code></a>: Handles the showing of applications by category (see the Applications tab).</li>
<li><a name='appDisplay.AllAppDisplay'><code>AllAppDisplay</code></a>: Handles showing every app in all categories.</li>
<li><a name='appDisplay.AppSearchProvider'><code>AppSearchProvider</code></a>: Handles finding apps matching search term(s).</li>
<li><a name='appDisplay.SettingsSearchProvider'><code>SettingsSearchProvider</code></a>: Handles finding entries in the gnome control centre matching search term(s). (The 'SETTINGS' set of results when you do a search - searches through subcategories of 'System Settings').</li>
<li><a name='appDisplay.AppIcon'><code>AppIcon</code></a>: An icon for an app (there's a similar class <a href="#altTab.appIcon">AltTab.AppIcon</a>).</li>
<li><a name='appDisplay.AppWellIcon'><code>AppWellIcon</code></a>: Extends AppIcon. One per app - the icon + label (giving the app name) + drag and drop support + right-click menu ("New Window", etc) that appears in the applications tab/application search results.</li>
<li><a name='appDisplay.AppIconMenu'><code>AppIconMenu</code></a>: The right-click menu of an AppWellIcon containing the relevant actions (New Window, Remove from Favorites, Add to Favorites, ...)</li>
</ul>
<h3><a name='appFavorites'><code>appFavorites.js</code></a></h3>
<ul>
<li><a name='appFavorites.AppFavorites'><code>AppFavorites</code></a>: handles your list of app favourites - updates the list when you choose 'add to favourite', provides API for you to add/remove from your favourites.</li>
</ul>
<h3><a name='automountManager'><code>automountManager.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-EfqSwjMMnbw/UFLBpYzOn3I/AAAAAAAABc0/FVt1QIp3X94/s1600/autorunResidentNotification.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="88" src="http://4.bp.blogspot.com/-EfqSwjMMnbw/UFLBpYzOn3I/AAAAAAAABc0/FVt1QIp3X94/s320/autorunResidentNotification.png" alt="autorunResidentNotification" title="autorunResidentNotification" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>AutorunResidentNotification</code></td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-rhvcfAd8BnI/UFLBpgzQi9I/AAAAAAAABdA/dR0M-__4ZaQ/s1600/autorunTransientNotification.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="80" src="http://3.bp.blogspot.com/-rhvcfAd8BnI/UFLBpgzQi9I/AAAAAAAABdA/dR0M-__4ZaQ/s320/autorunTransientNotification.png" alt="autorunTransientNotification" title="autorunTransientNotification" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>AutorunTransientNotification</code></td></tr>
</tbody></table>
<ul>
<li><a name='automountManager.ConsoleKitManager'><code>ConsoleKitManager</code></a>: Connection to ConsoleKit DBus</li>
<li><a name='automountManager.AutomountManager'><code>AutomountManager</code></a>: Uses ConsoleKitManager to listen for drives being added, removed, connected, disconnected, ejected, etc and automounts the drive.</li>
</ul>
<h3><a name='autorunManager'><code>autorunManager.js</code></a></h3>
<ul>
<li><a name='autorunManager.HotplugSniffer'><code>HotplugSniffer</code></a>: Listens on the dbus for something...</li>
<li><a name='autorunManager.ContentTypeDiscoverer'><code>ContentTypeDiscoverer</code></a>: Guesses what content is on a media (filesystem? photos? ...), uses HotplugSniffer to discover this.</li>
<li><a name='autorunManager.AutorunManager'><code>AutorunManager</code></a>: Master class that handles monitoring when volumes are mounted/dismounted, uses the other classes in the file to determine what content is on the media and send a notification with the right options for that media on it (if it's a camera card offer to view photos, if it's music offer to play it, ...)</li>
<li><a name='autorunManager.AutorunResidentSource'><code>AutorunResidentSource</code></a>: Inherits from <a href="#messageTray.Source">MessageTray.Source</a>: handles the notification side of things. A resident source is one that stays in the messageTray permanently (i.e. the 'Removable Devices' item in the message tray when you have a removable device plugged in).</li>
<li><a name='autorunManager.AutorunResidentNotification'><code>AutorunResidentNotification</code></a>: Inherits from <a href="#messageTray.Notification">MessageTray.Notification</a>: handles the creation of the 'removable devices' notification showing a menu of removable devices with an eject button for each..</li>
<li><a name='autorunManager.AutorunTransientDispatcher'><code>AutorunTransientDispatcher</code></a>: Determines a mounted volume's autorun settings for its transient notification.</li>
<li><a name='autorunManager.AutorunTransientSource'><code>AutorunTransientSource</code></a>: Inherits from <a href="#messageTray.Source">MessageTray.Source</a>: the notification source for the autorun notification that you get upon plugging in a device. It can be dismissed (unlike the <code>AutorunResidentSource</code>, which only dismisses when all the devices have been ejected).</li>
<li><a name='autorunManager.AutorunTransientNotification'><code>AutorunTransientNotification</code></a>: Inherits from <a href="#messageTray.Notification">MessageTray.Notification</a>: handles the creation of the transient notification you get upon plugging in a device. This is the notification that says 'View photos with Shotwell', 'Play music', 'Browse Files', etc.</li>
</ul>
<h3><a name='boxpointer'><code>boxpointer.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-Cijy8Xwlx14/UFLBqKyPfGI/AAAAAAAABdM/DCkcoMg1JpU/s1600/BoxPointer.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="168" src="http://4.bp.blogspot.com/-Cijy8Xwlx14/UFLBqKyPfGI/AAAAAAAABdM/DCkcoMg1JpU/s320/BoxPointer.png" alt="BoxPointer" title="BoxPointer" width="151" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>BoxPointer</code> is the triangular bit.</td></tr>
</tbody></table>
<ul>
<li><a name='boxpointer.BoxPointer'><code>BoxPointer</code></a>: The triangle arrow connecting a popupmenu to its source (you can configure what side of the menu the pointer appears).</li>
</ul>
<h3><a name='calendar'><code>calendar.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-qbsGqXv_zVc/UFLDPOEW7YI/AAAAAAAABds/3bDae29z1dY/s1600/calendar.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="194" src="http://3.bp.blogspot.com/-qbsGqXv_zVc/UFLDPOEW7YI/AAAAAAAABds/3bDae29z1dY/s320/calendar.png" alt="calendar" title="calendar" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The date menu. In red: <code>Calendar.Calendar</code>. Blue: <code>Calendar.EventsList</code>. The entire button and popup are <code>DateMenu.DateMenuButton</code>.</td></tr>
</tbody></table>
<ul>
<li>There are a whole bunch of functions in here to do with changing between date formats, getting day-of-the-week abbreviations, etc.</li>
<li><a name='calendar.CalendarEvent'><code>CalendarEvent</code></a>: an event in the calendar.</li>
<li><a name='calendar.EmptyEventSource'><code>EmptyEventSource</code></a>: "Interface for appointments/events".</li>
<li><a name='calendar.CalendarServer'><code>CalendarServer</code></a>: sets up a Dbus server for the calendar.</li>
<li><a name='calendar.DBusEventSource'><code>DBusEventSource</code></a>: A calendar event on the dbus. Interacts with CalendarServer.</li>
<li><a name='calendar.Calendar'><code>Calendar</code></a>: main Calendar class, handles the UI part for the calendar (month navigation, date, graphical calendar) as well as monitoring events.</li>
<li><a name='calendar.EventsList'><code>EventsList</code></a>: List of events. The UI part to the right of the calendar with the list of upcoming events.</li>
</ul>
<p>See also <a href="#dateMenu"><code>dateMenu.js</code></a> which ties all these elements together.</p>
<h3><a name='checkBox'><code>checkBox.js</code></a> (GNOME 3.4 only)</h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-wJun4gQlcsg/UFLF9JM5dgI/AAAAAAAABeA/leQ_tCmuroE/s1600/checkBox.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-wJun4gQlcsg/UFLF9JM5dgI/AAAAAAAABeA/leQ_tCmuroE/s1600/checkBox.png" alt="checkBox" title="checkBox" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A <code>CheckBox</code>. They only appear on a <code>KeyringDialog</code> (I created this one from the looking glass).</td></tr>
</tbody></table>
<ul>
<li><a name='checkBox.CheckBoxContainer'><code>CheckBoxContainer</code></a>: checkbox container class (helper class), with a checkbox and label.</li>
<li><a name='checkBox.CheckBox'><code>CheckBox</code></a>: checkbox itself. If you want a checkbox, use this, not the container class.</li>
</ul>
<h3><a name='contactDisplay'><code>contactDisplay.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-exZCDcDPQr8/UFLBqTse-2I/AAAAAAAABdY/M8-XEKgFqxE/s1600/Contact.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="117" src="http://4.bp.blogspot.com/-exZCDcDPQr8/UFLBqTse-2I/AAAAAAAABdY/M8-XEKgFqxE/s200/Contact.png" alt="Contact" title="Contact" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A <code>Contact</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='contactDisplay.Contact'><code>Contact</code></a>: A class representing a contact (wrapper around the <a href="https://live.gnome.org/Folks">Folks</a> library) and also a UI element being what is displayed in the Overview when you search for contacts.</li>
<li><a name='contactDisplay.ContactSearchProvider'><code>ContactSearchProvider</code></a>: Handles searching for contacts matching specified search term(s).</li>
</ul>
<h3><a name='ctrlAltTab'><code>ctrlAltTab.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-i4bElF37BOk/UFLBquyborI/AAAAAAAABdk/rX8qHvCG7vM/s1600/ctrlAltTabPopup.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="176" src="http://2.bp.blogspot.com/-i4bElF37BOk/UFLBquyborI/AAAAAAAABdk/rX8qHvCG7vM/s320/ctrlAltTabPopup.png" alt="ctrlAltTabPopup" title="ctrlAltTabPopup" width="175" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>CtrlAltTabPopup</code> (with a one-child <code>CtrlAltTabSwitcher</code>).</td></tr>
</tbody></table>
<ul>
<li><a name='ctrlAltTab.CtrlAltTabManager'><code>CtrlAltTabManager</code></a>: handles control alt tab behaviour - showing the popup, setting up the stage to be ready for keyboard navigation, ..</li>
<li><a name='ctrlAltTab.CtrlAltTabPopup'><code>CtrlAltTabPopup</code></a>: control alt tab popup itself (UI)</li>
<li><a name='ctrlAltTab.CtrlAltTabSwitcher'><code>CtrlAltTabSwitcher</code></a>: inherits from <a href="#altTab.SwitcherList">AltTab.SwitcherList</a>: UI element holding all the options you can alt-tab between.</li>
</ul>
<h3><a name='dash'><code>dash.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-lgTLP0edjT0/UFLHE5-z8nI/AAAAAAAABeI/0dlVclrd8NE/s1600/dash.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://2.bp.blogspot.com/-lgTLP0edjT0/UFLHE5-z8nI/AAAAAAAABeI/0dlVclrd8NE/s320/dash.png" alt="dash" title="dash" width="50" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>Dash</code>. The <code>RemoveFavouriteIcon</code> is the rubbish bin at the bottom, the <code>DragPlaceholderItem</code> is the line with the white circle at the centre (in the screenshot I am dragging the 'Terminal' icon to put it there).</td></tr>
</tbody></table>
<ul>
<li><a name='dash.DashItemContainer'><code>DashItemContainer</code></a>: Helper class - each item in the dash is one of these.</li>
<li><a name='dash.RemoveFavoriteIcon'><code>RemoveFavoriteIcon</code></a>: Inherits DashItemContainer. It's the little rubbish bin that appears on the dash when you drag an icon (that lets you remove from your favourite).</li>
<li><a name='dash.DragPlaceholderItem'><code>DragPlaceholderItem</code></a>: When you drag your favourites around to re-order them, you see a little bar showing you where the item will be dropped. That's what this is.</li>
<li><a name='dash.Dash'><code>Dash</code></a>: the master Dash class, making use of all the other classes.</li>
</ul>
<h3><a name='dateMenu'><code>dateMenu.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-qbsGqXv_zVc/UFLDPOEW7YI/AAAAAAAABds/3bDae29z1dY/s1600/calendar.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="194" src="http://3.bp.blogspot.com/-qbsGqXv_zVc/UFLDPOEW7YI/AAAAAAAABds/3bDae29z1dY/s320/calendar.png" alt="calendar" title="calendar" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The date menu. In red: <code>Calendar.Calendar</code>. Blue: <code>Calendar.EventsList</code>. The entire button and popup are <code>DateMenu.DateMenuButton</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='dateMenu.DateMenuButton'><code>DateMenuButton</code></a>: Subclasses [<code>PanelMenu.Button</code>] to provide the date menu in the middle of the top panel. It's made up of the date/time label in the panel, as well as its PopupMenu containing the <a href="#calendar.Calendar"><code>Calendar</code></a> and the <a href="#calendar.EventsList"><code>EventsList</code></a>.</li>
</ul>
<p>See also: <a href="#calendar"><code>calendar.js</code></a>.</p>
<h3><a name='dnd'><code>dnd.js</code></a></h3>
<p>This allows you to add drag-and-drop functionality to your own classes.
You use the following functions defined in the file:</p>
<ul>
<li><code>addDragMonitor</code>: you define an object defining the drag behaviour you want, and use <code>addDragMonitor</code> to add it.
A drag monitor is an object with the key <code>dragMotion</code> which is a callback for what happens when a drag motion event occurs.
Unsure of further details, but see (e.g) <a href="#dash"><code>dash.js</code></a> and <a href="#workspacesView"><code>workspacesView.js</code></a> for examples.</li>
<li><code>removeDragMonitor</code>: remove your drag behaviour that you added with <code>addDragMonitor</code>.</li>
<li><code>makeDraggable</code>: this is what makes an item draggable. You call it on an actor and get a draggable actor back out. You have to define some functions in <code>actor._delegate</code>'s class in order for this to work: <code>handleDragOver</code>, <code>acceptDrop</code>, <code>getDragActor</code>, <code>getDragActorSource</code>, <code>handleDragOver</code>. I don't know the details or if all of these are mandatory, but will write a blog post on this if I ever work it out.</li>
</ul>
<p>Classes:</p>
<ul>
<li><a name='dnd._Draggable'><code>_Draggable</code></a>: Class defining a basic draggable item, defining how the dragging happens (starting it, animating it, what to do if the user cancels, ...). You do not use this directly. Instead, use <code>makeDraggable</code> to make an actor draggable.</li>
</ul>
<h3><a name='docDisplay'><code>docDisplay.js</code></a> (GNOME 3.2 only)</h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-QnyOYKjIq4Y/UFLHF2QsekI/AAAAAAAABeM/WbmyMA1ztSA/s1600/docDisplay.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-QnyOYKjIq4Y/UFLHF2QsekI/AAAAAAAABeM/WbmyMA1ztSA/s1600/docDisplay.png" alt="docDisplay" title="docDisplay" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Example of <code>docDisplay</code> results.</td></tr>
</tbody></table>
<ul>
<li><a name='docDisplay.DocSearchProvider'><code>DocSearchProvider</code></a>: Handles finding recent documents matching search term(s).</li>
</ul>
<h3><a name='endSessionDialog'><code>endSessionDialog.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-BVxuegmoubA/UFLHGXOKViI/AAAAAAAABeU/IJZOzzaDVXQ/s1600/endSessionDialogLogoutInhibitor.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="203" src="http://2.bp.blogspot.com/-BVxuegmoubA/UFLHGXOKViI/AAAAAAAABeU/IJZOzzaDVXQ/s320/endSessionDialogLogoutInhibitor.png" alt="endSessionDialogLogoutInhibitor" title="endSessionDialogLogoutInhibitor" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A <code>EndSessionDialog</code> for logging out, with its <code>ListItem</code> (gedit is impeding logout) outlined in green.</td></tr>
</tbody></table>
<ul>
<li><a name='endSessionDialog.ListItem'><code>ListItem</code></a>: A list item in the end session dialog - when it gives a list of applications impeding shutdown, each gets its own ListItem.</li>
<li><a name='endSessionDialog.EndSessionDialog'><code>EndSessionDialog</code></a>: The end session dialog. Handles the UI part (presentation of the dialog). In terms of actually logging out/shutting down etc, the dialog simply sends messages to the GNOME SessionManager Dbus to request a shutdown rather than doing the shutdown itself.</li>
</ul>
<h3><a name='environment'><code>environment.js</code></a></h3>
<p>This module sets up the GJS environment for the rest of the JS files:</p>
<ul>
<li>adds up the <code>global</code> object (with <code>global.display</code>, <code>global.screen</code>, ...) to the environment</li>
<li>adds the <code>add</code> function to <code>St.BoxLayout</code> and <code>St.Table</code> (???)</li>
<li>adds/improves the <code>toString()</code> function (e.g. Clutter.Actors will state their delegate if this is set, e.g.:
function MyLabelClass() {
this.actor = new Clutter.Text({text: 'asdf'});
this.actor._delegate = this;
}</li>
<li>adds the method <code>String.format</code> (a bit like <code>sprintf</code>; allows us to do (e.g.) <code>'Hello, %s'.format('world')</code>).</li>
<li>initialises various things the shell needs to work.</li>
</ul>
<h3><a name='extensionSystem'><code>extensionSystem.js</code></a></h3>
<p>This is a collection of functions to do with installing, enabling and disabling extensions, and accessing their metadata. (Note - the extension UUID is something like <code>extensionname@some.website.com</code>).</p>
<p>In GNOME 3.2 you access particular extensions through the <code>extensions</code> and <code>extensionMeta</code> objects in <code>imports.ui.extensionSystem</code> (these are indexed by extension UUID). In GNOME 3.4, access extensions and their metadata using <code>imports.misc.extensionUtils.extensions</code> instead (use <code>imports.misc.extensionUtils.getCurrentExtension()</code> from within an extension to get the object for that extension).</p>
<p>There is also an array <code>enabledExtensions</code> containing the UUID of enabled extensions. In GNOME 3.4 there's additionally an array 'extensionOrder' giving the order in which extensions were loaded.</p>
<p>Some of the functions:</p>
<ul>
<li><code>installExtensionFromUUID</code>: installs an extension by UUID by downloading it from <a href="https://extensions.gnome.org">extensions.gnome.org</a>.</li>
<li><code>uninstallExtensionFromUUID</code>: installs an extension by UUID.</li>
<li><code>disableExtension</code>: disables an extension by UUID.</li>
<li><code>enableExtension</code>: enables an extension by UUID.</li>
</ul>
<p>The other functions are to do with the Shell looking for all the extensions you have installed and enabling them.</p>
<p>Just one class provided here:</p>
<ul>
<li><a name='extensionSystem.InstallExtensionDialog'><code>InstallExtensionDialog</code></a>: The dialog that pops up when you choose to install an extension (e.g. from <a href="https://extensions.gnome.org">e.g.o</a>) confirming that you want to install the extension.</li>
</ul>
<h3><a name='flashspot'><code>flashspot.js</code></a> (GNOME 3.4 only)</h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/--pJvxm2M5PM/UFLHHLtRVuI/AAAAAAAABeg/H-08y-Mwmos/s1600/flashspot_1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/--pJvxm2M5PM/UFLHHLtRVuI/AAAAAAAABeg/H-08y-Mwmos/s1600/flashspot_1.png" alt="flashspot_1" title="flashspot_1" style="border: 1px solid black;" /></a></td><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-qUo138L_FCY/UFLHHxxXuDI/AAAAAAAABek/-30w6ebwwy8/s1600/flashspot_2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-qUo138L_FCY/UFLHHxxXuDI/AAAAAAAABek/-30w6ebwwy8/s1600/flashspot_2.png" alt="flashspot_2" title="flashspot_2" style="border: 1px solid black;" /></a></td></tr>
<tr><td class="tr-caption" colspan="2" style="text-align: center;">When I screenshot the 'Activities' button , <code>Flashspot</code> starts to simulate a camera flash. It gets brighter and then fades again.</td></tr>
</tbody></table>
<ul>
<li><a name='flashspot.Flashspot'><code>Flashspot</code></a>: extends <a href="#lightBox.LightBox">LightBox</a>. That white flash that you get (like a camera flash) when you press the printscreen button (..odd..)...</li>
</ul>
<h3><a name='iconGrid'><code>iconGrid.js</code></a></h3>
<ul>
<li><a name='iconGrid.BaseIcon'><code>BaseIcon</code></a>: A basic icon class consisting of an icon and a label.</li>
<li><a name='iconGrid.IconGrid'><code>IconGrid</code></a>: A widget displaying its children in a grid (allowing you to set a row limit or column limit, and actors that don't fit in will not be painted).</li>
</ul>
<h3><a name='keyboard'><code>keyboard.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-lOuyurMJFno/UFLKoGPRtwI/AAAAAAAABgU/zRQa9uFrfpk/s1600/keyboard.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="http://4.bp.blogspot.com/-lOuyurMJFno/UFLKoGPRtwI/AAAAAAAABgU/zRQa9uFrfpk/s320/keyboard.png" alt="keyboard" title="keyboard" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>Keyboard</code> with many <code>Key</code>s.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-ePJ7rh8PN7c/UFLKpRuIeSI/AAAAAAAABgc/A-UbJQnKm34/s1600/keyboardSource.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-ePJ7rh8PN7c/UFLKpRuIeSI/AAAAAAAABgc/A-UbJQnKm34/s1600/keyboardSource.png" alt="keyboardSource" title="keyboardSource" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>KeyboardSource</code> (click on it to bring up the keyboard)</td></tr>
</tbody></table>
<ul>
<li><a name='keyboard.Key'><code>Key</code></a>: A key on the keyboard.</li>
<li><a name='keyboard.Keyboard'><code>Keyboard</code></a>: The Keyboard class (implements DBus class <code>/org/gnome/Caribou/Keyboard</code>?)</li>
<li><a name='keyboard.KeyboardSource'><code>KeyboardSource</code></a>: Inherits from <a href="#messageTray.Source">MessageTray.Source</a>, shows the keyboard in the message tray.</li>
</ul>
<h3><a name='keyringPrompt'><code>keyringPrompt.js</code></a>:</h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-3WXME6gR6do/UFLKqA4HixI/AAAAAAAABgk/OmWryEaSnbY/s1600/keyringDialog.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="190" src="http://3.bp.blogspot.com/-3WXME6gR6do/UFLKqA4HixI/AAAAAAAABgk/OmWryEaSnbY/s320/keyringDialog.png" alt="keyringDialog" title="keyringDialog" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">KeyringDialog</td></tr>
</tbody></table>
<ul>
<li><a name='keyringPrompt.KeyringDialog'><code>KeyringDialog</code></a>: a <a href="#modalDialog.ModalDialog"><code>ModalDialog</code></a> that is a dialog for gnome-keyring.</li>
</ul>
<h3><a name='layout'><code>layout.js</code></a></h3>
<ul>
<li><a name='layout.LayoutManager'><code>LayoutManager</code></a>: Manages layout of items on the stage (message tray, top panel, hot corners) and updates these when monitors change. I <em>think</em> you might have to call <code>LayoutManager.addChrome(actor)</code> if you want to add an actor to the stage and want it to be able to receive events.</li>
<li><a name='layout.HotCorner'><code>HotCorner</code></a>: Hot corners (e.g. the top-left hot corner lets you switch to the overview).</li>
<li><a name='layout.Chrome'><code>Chrome</code></a>: The UI that's visible in the non-overview mode that surrounds all the windows (panel, message tray, ..)</li>
</ul>
<h3><a name='lightbox'><code>lightbox.js</code></a></h3>
<ul>
<li><a name='lightbox.Lightbox'><code>Lightbox</code></a>: A shade obscuring the specified container actor (for example the screen in the case of a modal dialog). The <a href="#flashspot.Flashspot"><code>Flashspot</code></a> subclasses this to do a white flash instead of a dark shade.</li>
</ul>
<h3><a name='link'><code>link.js</code></a></h3>
<ul>
<li><a name='link.Link'><code>Link</code></a>: Defines a Link (only used in the looking glass) - creates a St.Button with a link markup style (underline, ...). The <a href="#lookingGlass.ObjLink"><code>LookingGlass.ObjLink</code></a> is an example of this.</li>
</ul>
<h3><a name='lookingGlass'><code>lookingGlass.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="5" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-_v_Qlog4_ys/UFLKZeV-mpI/AAAAAAAABe8/Df4vfXmqDjY/s1600/LookinGlassAutocomplete.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="253" src="http://4.bp.blogspot.com/-_v_Qlog4_ys/UFLKZeV-mpI/AAAAAAAABe8/Df4vfXmqDjY/s320/LookinGlassAutocomplete.png" alt="LookinGlassAutocomplete" title="LookinGlassAutocomplete" width="320" /></a></td><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-EN6dAn2XiPE/UFLKcAJNqnI/AAAAAAAABfM/wHpCGCeksIs/s1600/LookingGlassObjInspector.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="237" src="http://3.bp.blogspot.com/-EN6dAn2XiPE/UFLKcAJNqnI/AAAAAAAABfM/wHpCGCeksIs/s320/LookingGlassObjInspector.png" alt="LookingGlassObjInspector" title="LookingGlassObjInspector" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Autocomplete function in the looking glass (GNOME 3.4+).</td><td class="tr-caption" style="text-align: center;">LookingGlass <code>ObjInspector</code> - inspecting <code>Meta.KeyBindingAction</code></td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="5" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-eQQ5TruNTt0/UFLKa32PeXI/AAAAAAAABfE/gU8kzN7WZcg/s1600/LookingGlassInspector.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="142" src="http://2.bp.blogspot.com/-eQQ5TruNTt0/UFLKa32PeXI/AAAAAAAABfE/gU8kzN7WZcg/s320/LookingGlassInspector.png" alt="LookingGlassInspector" title="LookingGlassInspector" width="320" /></a></td><td class="tr-caption" style="text-align: center;">Looking Glass <code>Inspector</code> - outlines the actor your mouse is over and lets you pick it.</td></tr>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-V9J2go0aVfA/UFLKdRwiU5I/AAAAAAAABfU/D8YyzKORCjU/s1600/LookingGlassResultObjLink.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-V9J2go0aVfA/UFLKdRwiU5I/AAAAAAAABfU/D8YyzKORCjU/s1600/LookingGlassResultObjLink.png" alt="LookingGlassResultObjLink" title="LookingGlassResultObjLink" /></a></td><td class="tr-caption" style="text-align: center;">Looking Glass <code>ObjLink</code> - clicking on it launches the <code>ObjInspector</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='lookingGlass.AutoComplete'><code>AutoComplete</code></a> (<strong>GNOME 3.4 only</strong>): Adds completion behaviour on Tab/double-Tab to the looking glass!! (Like the Terminal).</li>
<li><a name='lookingGlass.Notebook'><code>Notebook</code></a>: The Looking Glass consists of multiple 'tabs' (Evaluator; Windows; Errors; Memory; Extensions); the notebook is what holds them all. Defines the tab controls, ability to add/switch tab pages, and an area where the page content will appear.</li>
<li><a name='lookingGlass.ObjLink'><code>ObjLink</code></a>: inherits from <a href="#link.Link">Link.Link</a> - when you type things into the Looking Glass console the results are clickable. This class handles those links.</li>
<li><p><a name='lookingGlass.Result'><code>Result</code></a>: When you type things into the Looking Glass the results get printed like so:</p>
<pre><code class="language-javascript">r(result_number) = result
</code></pre>
<p>That is what this class is (where <code>result</code> is an ObjLink`).</p></li>
<li><a name='lookingGlass.WindowList'><code>WindowList</code></a>: The Windows tab of the Looking Glass.</li>
<li><a name='lookingGlass.ObjInspector'><code>ObjInspector</code></a>: When you click on a result in the Looking Glass you get a window that shows you more information about that result. For example, clicking on an object will show (some of) its properties. This is that class.</li>
<li><a name='lookingGlass.Inspector'><code>Inspector</code></a>: There's a 'picker' icon in the Evaluator tab of the Looking Glass. When you select it, you can 'pick' an object from the stage to examine further. As you move your pointer over particular objects, they get a red border drawn around them. The <code>Inspector</code> class handles adding and removing these borders, and tracking which object your pointer is over (the actual function to add the borders is called <code>addBorderPaintHook</code>).</li>
<li><a name='lookingGlass.ErrorLog'><code>ErrorLog</code></a>: The 'Errors' tab in the Looking Glass.</li>
<li><a name='lookingGlass.Memory'><code>Memory</code></a>: The 'Memory' tab in the Looking Glass.</li>
<li><a name='lookingGlass.Extensions'><code>Extensions</code></a>: The 'Extensions' tab in the looking glass.</li>
<li><a name='lookingGlass.LookingGlass'><code>LookingGlass</code></a>: Assembles the whole looking glass together. Also provides the 'Evaluator' tab and handles the actual evaluation of commands typed into the console.</li>
</ul>
<h3><a name='magnifierDBus'><code>magnifierDBus.js</code></a></h3>
<ul>
<li><a name='magnifierDBus.ShellMagnifier'><code>ShellMagnifier</code></a>: DBus proxy (proxy? server?) representing the Shell Magnifier (<code>org.gnome.Magnifier</code>).</li>
<li><a name='magnifierDBus.ShellMagnifierZoomRegion'><code>ShellMagnifierZoomRegion</code></a>: DBus proxy (??server?? I don't know about DBus) representing a zoom region (region being magnified).</li>
</ul>
<h3><a name='magnifier'><code>magnifier.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-n-zVpO8tSkc/UFLKq6WFQXI/AAAAAAAABgs/XOyNoLSCuvg/s1600/magnifier.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="217" src="http://1.bp.blogspot.com/-n-zVpO8tSkc/UFLKq6WFQXI/AAAAAAAABgs/XOyNoLSCuvg/s320/magnifier.png" alt="magnifier" title="magnifier" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>Magnifier</code>. The <code>ZoomRegion</code> is the little region of the screen being displayed/zoomed, and the <code>Crosshairs</code> are in red.</td></tr>
</tbody></table>
<ul>
<li><a name='magnifier.Magnifier'><code>Magnifier</code></a>: Defines the shell magnifier.</li>
<li><a name='magnifier.ZoomRegion'><code>ZoomRegion</code></a>: Defines a particular zoom region.</li>
<li><a name='magnifier.Crosshairs'><code>Crosshairs</code></a>: Defines the crosshairs of the magnifier.</li>
</ul>
<h3><a name='main'><code>main.js</code></a></h3>
<p>No classes in here. This file is like the <code>int main();</code> of programs, setting up the whole gnome-shell interface and making parts available to everyone else (the top panel, overview, ...). Many global objects in gnome-shell create just one instance. These are stored here.</p>
<p>This file also handles dynamic workspaces (when you have no windows left on a workspace it is removed).</p>
<p>Some of the objects stored to be accessed by others (there are more, see <code>main.js</code>):</p>
<ul>
<li><code>panel</code>: this is the top panel. If you want to add buttons to the status area etc, you use this panel to add them to.</li>
<li><code>hotCorners</code>: the hot corner(s), e.g. the top-left one (move your cursor over it and the Overview opens).</li>
<li><code>overview</code>: the Overview.</li>
<li><code>runDialog</code>: the dialog when you press <code>Alt+F2</code>.</li>
<li><code>lookingGlass</code>: the looking glass.</li>
<li><code>messageTray</code>: the message tray.</li>
<li><code>recorder</code>: gnome-shell recorder (when you record a screencast).</li>
<li><code>shellDBusService</code>: Gnome-shell's Dbus service.</li>
<li><code>magnifier</code>: the accessibility magnifier.</li>
<li><code>keyboard</code>: the accessibility on-screen keyboard.</li>
</ul>
<p>Some handy functions (there are other functions in <code>main.js</code> too; these are just some handy one):</p>
<ul>
<li><code>getThemeStylesheet()</code>: gets the file path for the (custom) theme you are using for gnome-shell, if any (e.g. <code>$HOME/.themes/<themename>/gnome-shell/gnome-shell.css</code>). If you are not using a custom gnome-shell theme, this will be null.</li>
<li><code>setThemeStylesheet(path)</code>: sets the file path for the custom theme for gnome-shell (but doesn't actually cause a theme change; use <code>loadTheme</code> to reload the theme after doing this).</li>
<li><code>loadTheme()</code>: reloads the style for gnome-shell. It sets the <code>getThemeStylesheet</code> (any custom gnome-shell theme if you have one, or just the default <code>/usr/share/gnome-shell/themes/gnome-shell.css</code>) as the top priority style sheet, and then loads all the extra stylesheets (e.g. extension stylesheets) at a lower priority. This is why if you set a style in your extension's <code>stylesheet.css</code> that conflicts with the a gnome-shell style class, gnome-shell will win.</li>
<li><code>notify(msg, details)</code>: creates a gnome-shell notification (i.e. popup from the message tray) with title <code>msg</code> and text <code>details</code>.</li>
<li><a name='main.notifyError'><code>notifyError(msg, details)</code></a>: calls <code>notify(msg, details)</code> to send a popup notification from the message tray, and additionally logs the message/details using <code>log</code> (if you are running <code>gnome-shell</code> from a terminal, the message will appear there).</li>
<li><code>_log(category, msg)</code>: logs a message to the Looking Glass errors tab, where <code>category</code> is 'info', 'error', or 'debug'. You will probably want to use <code>global.log(message)</code> instead of this (which logs with category 'debug').</li>
<li><code>_logError(msg)</code>: calls <code>_log</code> with category 'error'. Aliased as <code>global.logError</code>.</li>
<li><code>_logDebug(msg)</code>: calls <code>_log</code> with category 'debug'. Aliased as <code>global.log</code>.</li>
<li><code>pushModal(actor, timestamp, options)</code>: Grabs all keyboard/mouse input to the stage and focuses <code>actor</code>. When the modal stack is empty we return focus to whatever had focus before <code>pushModal</code> was called. The overview, run dialog, looking glass, alt-tab switchers, and modal dialogs all use this (there are probably more too).</li>
<li><code>popModal(actor, timestamp)</code>: Opposite of <code>pushModal</code> (removes <code>actor</code> from the modal stack).</li>
<li><code>initializeDeferredWork(actor, callback, props)</code>: Sets up a callback to be invoked either when <code>actor</code> is mapped, or when the machine is idle - useful if your actor isn't always visible on the screen and you don't want to consume resources updating if the actor isn't actually visible. (The Overview actors are all examples of these). Returns a work ID that you can use with <code>queueDeferredWork</code> every time you update the actor.</li>
<li><code>queueDeferredWork(workId)</code>: Ensures that the work identified by <code>workId</code> will be run on map or timeout. It is called by default on <code>initializeDeferredWork</code>, call it again when (say) the data being displayed by the actor changes.</li>
</ul>
<p>A few of convenience functions (again, this is not all of them)`:</p>
<ul>
<li><code>getWindowActorsForWorkspace(workspaceIndex)</code>: gets a list of window actors for windows displayed on workspace <code>workspaceIndex</code> (this includes windows that are set as 'on all workspaces'). (Just a convenience wrapper around <code>global.get_window_actors()</code> with filtering for windows on the specified workspace and checking for windows on all workspaces).</li>
<li><code>activateWindow(window, time, workspaceNum)</code>: activates the Meta.Window <code>window</code>, switching to its workspace first if necessary, and switching out of the overview if active (just a convenience wrapper around <code>Meta.Window.activate(time)</code> with workspace/overview checking).</li>
</ul>
<h3><a name='messageTray'><code>messageTray.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-dxN0qi6AmqQ/UFLKe9r65WI/AAAAAAAABfY/AU6fn4z-C6g/s1600/MessageTray.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="77" src="http://4.bp.blogspot.com/-dxN0qi6AmqQ/UFLKe9r65WI/AAAAAAAABfY/AU6fn4z-C6g/s320/MessageTray.png" alt="MessageTray" title="MessageTray" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The <code>messageTray</code>, showing three <code>SummaryItem</code>s (which each have their own underlying <code>Source</code>) and one <code>Notification</code>.</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="5" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-MjAhMc74xNg/UFLKsEtX-QI/AAAAAAAABgw/fDSA8cOykTk/s1600/messageTraySummaryItemYellowSourceRed.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-MjAhMc74xNg/UFLKsEtX-QI/AAAAAAAABgw/fDSA8cOykTk/s1600/messageTraySummaryItemYellowSourceRed.png" alt="messageTraySummaryItemYellowSourceRed" title="messageTraySummaryItemYellowSourceRed" /></a></td><td class="tr-caption" style="text-align: center;">The <code>SummaryItem</code> is outlined in yellow and its associated <code>Source</code> provides the icon and counter (outlined in red).</td></tr>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-irUuo8uuf6s/UFLKfQZPRmI/AAAAAAAABfg/X8XLw__xJQ0/s1600/MessageTrayNotificationTransient.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="44" src="http://4.bp.blogspot.com/-irUuo8uuf6s/UFLKfQZPRmI/AAAAAAAABfg/X8XLw__xJQ0/s320/MessageTrayNotificationTransient.png" alt="MessageTrayNotificationTransient" title="MessageTrayNotificationTransient" width="320" /></a></td><td class="tr-caption" style="text-align: center;">A <code>Notification</code> in "banner mode" (pops up from bottom of the screen), also demonstrating the <code>UrlHighlighter</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='messageTray.URLHighlighter'><code>URLHighlighter</code></a>: class to markup URLs in notifications.</li>
<li><a name='messageTray.FocusGrabber'><code>FocusGrabber</code></a>: grabs focus to a notification.</li>
<li><strong><a name='messageTray.Source'><code>Source</code></a></strong>: abstract class defining a notifications source. It provides the UI element of the icon + notification counter in the message tray. Implementations must provide the method <code>createNotificationIcon</code> to create the icon. When you wish to create a notification, you notify <em>from</em> a source (e.g. a source (Thunderbird) can provide many notifications (about new emails)).</li>
<li><strong><a name='messageTray.Notification'><code>Notification</code></a></strong>: base class defining a notification - the UI element. A notification belongs to a <code>Source</code> and has a title and text. In banner mode, the notification shows an icon, title, and banner on a single line. If the notification has additional elements in it or the banner doesn't fit on a single line, the notification is expandable. See <code>messageTray.js</code> for much more in-depth documentation. Also, if the notification is transient, it will pop up from the button of your screen. If the notification is resident, its <code>Source</code>/<code>SummaryItem</code> will stay in the message tray and clicking on that will bring up the <code>Notification</code>.</li>
<li><a name='messageTray.SummaryItem'><code>SummaryItem</code></a>: This is the UI element that sits in the message tray, one per source. It display's the source's summary icon (being the <code>source.createNotificationIcon()</code> plus a counter of the number of notifications) and also displays the title of the source upon mouseover and defines the right-click menu (with Open/Remove) when you right-click a summary item in the message tray. Think of a notification source as being composed of a <code>Source</code> (being tied to the application and handling its notifications) and a <code>SummaryItem</code> handling all the UI/message tray part. Then only UI task that the <code>Source</code> has to do is provide an icon for the notification.</li>
<li><a name='messageTray.MessageTray'><code>MessageTray</code></a>: the MessageTray class.</li>
<li><a name='messageTray.SystemNotificationSource'><code>SystemNotificationSource</code></a>: Example of a Source - for system notifications.</li>
</ul>
<p>Recap - if you wish to create notifications, the <code>MessageTray.Source</code> is the class you subclass. You need to implement the <code>createNotificationIcon</code> function at a minimum. When you want to send a <em>notification</em> from that source, use <code>source.notify(notification)</code>, where <code>notification</code> is a <code>MessageTray.Notification</code> (or subclass thereof).</p>
<h3><a name='modalDialog'><code>modalDialog.js</code></a></h3>
<ul>
<li><a name='modalDialog.ModalDialog'><code>ModalDialog</code></a>: a handy class defining a modal (popup) dialog. Use <code>.setButtons</code> to add buttons to it, and <code>open</code> and <code>close</code> to show or hide it. Examples: <a href="#endSessionDialog.EndSessionDialog">end session dialog</a>, <a href="#extensionSystem.InstallExtensionDialog">install extensions confirmation dialog</a>, <a href="#networkAgent.NetworkSecretDialog">wifi network password entry dialog</a>...</li>
</ul>
<h3><a name='networkAgent'><code>networkAgent.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/--Jyk8gBtGPc/UFLKgCO1bXI/AAAAAAAABfs/WJrVuON8fO0/s1600/NetworkSecretDialog.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="154" src="http://4.bp.blogspot.com/--Jyk8gBtGPc/UFLKgCO1bXI/AAAAAAAABfs/WJrVuON8fO0/s320/NetworkSecretDialog.png" alt="NetworkSecretDialog" title="NetworkSecretDialog" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>NetworkSecretDialog</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='networkAgent.NetworkSecretDialog'><code>NetworkSecretDialog</code></a>: dialog that pops up getting you to entire in your password for wifi.</li>
<li><a name='networkAgent.NetworkAgent'><code>NetworkAgent</code></a>: listens to NetworkAgent on Dbus - handles authentication requests.</li>
<li><a name='networkAgent.VPNRequestHandler'><code>VPNRequestHandler</code></a> (<strong>GNOME 3.4 only</strong>): handles authentication requests for VPN.</li>
</ul>
<h3><a name='notificationDaemon'><code>notificationDaemon.js</code></a></h3>
<ul>
<li><a name='notificationDaemon.Bus'><code>Bus</code></a>: Listens to <code>org.freedesktop.DBus</code>, interface 'org.freedesktop.Notifications'.</li>
<li><a name='notificationDaemon.NotificationDaemon'><code>NotificationDaemon</code></a>: gnome-shell uses dbus to listen/send notifications; this handles that.</li>
<li><a name='notificationDaemon.Source'><code>Source</code></a>: extends <a href="#messageTray.Source">MessageTray.Source</a> - a message tray source for notifications that arrive over DBus path 'org.freedesktop.Bus'. The icon is usually the icon of the application causing the notification.</li>
</ul>
<h3><a name='overview'><code>overview.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-Gl3tsp2xr3Q/UFLKhyIpoVI/AAAAAAAABf0/jZfr-chn1b0/s1600/Overview.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="http://4.bp.blogspot.com/-Gl3tsp2xr3Q/UFLKhyIpoVI/AAAAAAAABf0/jZfr-chn1b0/s320/Overview.png" alt="Overview" title="Overview" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>Overview</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='overview.ShellInfo'><code>ShellInfo</code></a>: Handles spawning notifications for actions performed from the overview and undoing them (only examples I could find were adding/removing favourites from the dash in <a href="#appDisplay"><code>appDisplay.js</code></a> and adding/removing places in <a href="#placeDisplay"><code>placeDisplay.js</code></a>.</li>
<li><a name='overview.Overview'><code>Overview</code></a>: The Overview (triggered when you press the windows key). Made up of various tabs defined in other classes. Code in here is to do with animation when the overview shows and hides, loading search providers, interaction with the overview (typing, dragging, clicking) and so on.</li>
</ul>
<p>See also <a href="#viewSelector"><code>viewSelector.js</code></a> for the classes defining the 'notebook/tab' classes, and <code>*Display.js</code> files for files defining various tabs (e.g. the core 'Applications' tab code is in <a href="#appDisplay"><code>appDisplay.js</code></a>, the code for the 'Windows' tab is in <a href="#workspacesView"><code>workspacesView.WorkspacesDisplay</code></a>.</p>
<h3><a name='panel'><code>panel.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-7_cwAEwuYSU/UFLKxSCMMWI/AAAAAAAABhs/9lNGzOnR0Lw/s1600/panelMenu.boxes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="14" src="http://4.bp.blogspot.com/-7_cwAEwuYSU/UFLKxSCMMWI/AAAAAAAABhs/9lNGzOnR0Lw/s320/panelMenu.boxes.png" alt="panelMenu boxes" title="panelMenu boxes" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Panel <code>_leftBox</code> (red), <code>_centerBox</code> (green), <code>_rightBox</code> (blue).</td></tr>
</tbody></table>
<table cellpadding="0" cellspacing="5" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-Zyde-vmkRJc/UFLKsz6asoI/AAAAAAAABg4/LWxkvfRlymU/s1600/panelCorner.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-Zyde-vmkRJc/UFLKsz6asoI/AAAAAAAABg4/LWxkvfRlymU/s1600/panelCorner.png" alt="panelCorner" title="panelCorner" /></a></td><td class="tr-caption" style="text-align: center;"><div style="text-align: left;">
<code>PanelCorner</code>.</div>
</td></tr>
<tr>
<td style="text-align: center;"><a href="http://3.bp.blogspot.com/-o8pG-IKLydA/UFLKtpQU4SI/AAAAAAAABhE/l2RURjlOCpo/s1600/panelMenu.ActivitiesButton.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-o8pG-IKLydA/UFLKtpQU4SI/AAAAAAAABhE/l2RURjlOCpo/s1600/panelMenu.ActivitiesButton.png" alt="panelMenu ActivitiesButton" title="panelMenu ActivitiesButton" /></a></td>
<td class="tr-caption" style="text-align: center;"><div style="text-align: left;">
<code>ActivitiesButton</code>.</div>
</td>
</tr>
<tr>
<td style="text-align: center;"><a href="http://3.bp.blogspot.com/-Ab41_quK2rg/UFLKumuxfNI/AAAAAAAABhI/YVm736qk41E/s1600/panelMenu.AnimatedIcon.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-Ab41_quK2rg/UFLKumuxfNI/AAAAAAAABhI/YVm736qk41E/s1600/panelMenu.AnimatedIcon.png" alt="panelMenu AnimatedIcon" title="panelMenu AnimatedIcon" /></a></td><td class="tr-caption" style="text-align: center;"><div style="text-align: left;">
<code>AnimatedIcon</code> (red) in the <code>AppMenu</code>. The text shadowed effect is achieved using a <code>TextShadower</code>.</div>
</td></tr>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-SwWLuEnMp-I/UFLKwTBXubI/AAAAAAAABho/O5wZkpvTD1w/s1600/panelMenu.appMenu.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-SwWLuEnMp-I/UFLKwTBXubI/AAAAAAAABho/O5wZkpvTD1w/s1600/panelMenu.appMenu.png" alt="panelMenu appMenu" title="panelMenu appMenu" /></a></td><td class="tr-caption" style="text-align: center;"><div style="text-align: left;">
<code>AppMenu</code> with its dropdown menu.</div>
</td></tr>
</tbody></table>
<ul>
<li><a name='panel.AnimatedIcon'><code>AnimatedIcon</code></a>: handles loading an animated icon whereby the icon's underlying image is a tiled image showing stages of the animation (for example the 'process working' animation - the spinning circle in the titlebar when you start up a program).</li>
<li><a name='panel.TextShadower'><code>TextShadower</code></a>: A label with simulated text shadowing - it actually consists of one white label and 4 'shadow' labels (black and 40% transparent). All the labels show the same text. The white label is the one you see and the 'shadow' labels sit behind and slightly offset from the white text, creating the effect of a shadow. The text in the titlebar (app title) is an example of this.</li>
<li><a name='panel.AppMenuButton'><code>AppMenuButton</code></a>: This is the top titlebar (stored in <code>Main.panel._appMenu</code>). It contains a <code>TextShadower</code> showing the current app title and <code>AnimatedIcon</code> for when apps are starting up. Inherits from <a href="#panelMenu.Button"><code>PanelMenu.Button</code></a>, so it has a dropdown menu (by default showing 'Quit' (application)).</li>
<li><a name='panel.ActivitiesButton'><code>ActivitiesButton</code></a>: The 'Activities' button on the top-left that triggers the overview. It's a <a href="#panelMenu.Button"><code>PanelMenu.Button</code></a> but without a menu. Contains the <a href="#layout.HotCorner"><code>Layout.HotCorner</code></a> that triggers the overview.</li>
<li><a name='panel.PanelCorner'><code>PanelCorner</code></a>: You know the black rounded corners that extend down from the top panel on either side of the screen (they match the rounded corners of a maximised window)? That's what these are. They are painted onto the screen using the panel colour.</li>
<li><a name='panel.Panel'><code>Panel</code></a>: The top panel, stored in <code>Main.panel</code>. It is split into three 'boxes' into which various panel elements are all placed:
<ul>
<li><code>_leftBox</code>: contains the activities button and app menu button</li>
<li><code>_centerBox</code>: contains the clock (by default; there are various extensions that move this to the right if you wish).</li>
<li><code>_rightBox</code>: contains the <a href="#status">status area</a>. However when you want to insert icons into the status area you should use <code>Main.panel.addToStatusArea(role, myButton, position)</code>, where <code>role</code> is the role that button performs ('network', 'a11y', ...). There can only be one button performing each role in the status area.</li>
</ul></li>
</ul>
<p>Constants that could be interesting:</p>
<ul>
<li><code>STANDARD_STATUS_AREA_ORDER</code>: the default order for the default status icons (left to right: accessibility, keyboard, volume, bluetooth, network, battery, user menu). Stored in <code>Main.overview._status_area_order</code> and used in <code>startStatusArea</code> which lays out all the icons.</li>
</ul>
<h3><a name='panelMenu'><code>panelMenu.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-AijxQ1sTQaM/UFLKvkO8ksI/AAAAAAAABhc/SEpRhlG9ugk/s1600/panelMenu.SystemStatusButton.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-AijxQ1sTQaM/UFLKvkO8ksI/AAAAAAAABhc/SEpRhlG9ugk/s1600/panelMenu.SystemStatusButton.png" alt="panelMenu SystemStatusButton" title="panelMenu SystemStatusButton" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Example of a <code>SystemStatusButton</code>, being the indicator and menu where the indicator is an icon. (Custom indicator + menu is a <code>Button</code>, custom indicator (no menu) is a <code>ButtonBox</code>).</td></tr>
</tbody></table>
<ul>
<li><a name='panelMenu.ButtonBox'><code>ButtonBox</code></a>: The base button class for buttons in the panel (incorporates the <code>-minimum-hpadding</code> and <code>-natural-hpadding</code> attributes in the <code>panel-button</code> style class - so whatever you insert into the ButtonBox should get padded uniformly with all the other buttons in the panel.</li>
<li><a name='panelMenu.Button'><code>Button</code></a>: Inherits from <code>ButtonBox</code> - adds a menu. So this is an object for use in the panel that will have a menu and some sort of display item (e.g. an icon), which you are responsible for defining and adding. The date menu is an example of this (its display item is a <code>St.Label</code> with the current date/time).</li>
<li><a name='panelMenu.SystemStatusButton'><code>SystemStatusButton</code></a>: This is just a <code>Button</code> with an icon. Feed it in an icon name (one of the stock icon names) and it'll display it. Just about every icon you have in your status area is one of these (accessibility indicator, network indicator, ...).</li>
</ul>
<h3><a name='placeDisplay'><code>placeDisplay.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-9YNZAgetZ68/UFLKyziuaSI/AAAAAAAABh8/vkJSCNMYu8I/s1600/placesDisplay.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-9YNZAgetZ68/UFLKyziuaSI/AAAAAAAABh8/vkJSCNMYu8I/s1600/placesDisplay.png" alt="placesDisplay" title="placesDisplay" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Example result from the <code>PlacesSearchProvider</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='placeDisplay.PlaceInfo'><code>PlaceInfo</code></a>: According to in-file documentation, this represents a place object, which is most likely a bookmark entry, volume/mount, or special place like Home, Computer or Network.</li>
<li><a name='placeDisplay.PlaceDeviceInfo'><code>PlaceDeviceInfo</code></a>: This is a <code>PlaceInfo</code> for a mounted volume.</li>
<li><a name='placeDisplay.PlacesManager'><code>PlacesManager</code></a>: handles many places (mounted volumes, Home folder, ....). Essentially manages many <code>placeInfo</code>s.</li>
<li><a name='placeDisplay.PlaceSearchProvider'><code>PlaceSearchProvider</code></a>: Finds places matching search term(s) (e.g. the 'PLACES & DEVICES' results section in the Overview).</li>
</ul>
<h3><a name='polkitAuthenticationAgent'><code>polkitAuthenticationAgent.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-XdytPPySauc/UFLKzyyCQ6I/AAAAAAAABiE/FkSRg1YwvZw/s1600/polkitAuthenticationDialog.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="204" src="http://3.bp.blogspot.com/-XdytPPySauc/UFLKzyyCQ6I/AAAAAAAABiE/FkSRg1YwvZw/s320/polkitAuthenticationDialog.png" alt="polkitAuthenticationDialog" title="polkitAuthenticationDialog" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>AuthenticationDialog</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='polkitAuthenticationAgent.AuthenticationDialog'><code>AuthenticationDialog</code></a>: The <a href="#modalDialog.ModalDialog">ModalDialog</a> that appears when you have to enter your password to authenticate (e.g. installing software updates).</li>
<li><a name='polkitAuthenticationAgent.AuthenticationAgent'><code>AuthenticationAgent</code></a>: Wrapper around Shell.PolkitAuthenticationAgent, listens for authentication requests and shows the AuthenticationDialog.</li>
</ul>
<h3><a name='popupMenu'><code>popupMenu.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="5" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-Kuwdhucp3rI/UFLKiiMC6aI/AAAAAAAABf8/FVfPVnxF0Kk/s1600/PopupMenu.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="284" src="http://1.bp.blogspot.com/-Kuwdhucp3rI/UFLKiiMC6aI/AAAAAAAABf8/FVfPVnxF0Kk/s320/PopupMenu.png" alt="PopupMenu" title="PopupMenu" width="320" /></a></td>
<td style="text-align: center;"><a href="http://2.bp.blogspot.com/-zJeHn6uTk8M/UFLKkbGr1JI/AAAAAAAABgE/rFi_7jyNs1M/s1600/PopupMenuExpanded.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="309" src="http://2.bp.blogspot.com/-zJeHn6uTk8M/UFLKkbGr1JI/AAAAAAAABgE/rFi_7jyNs1M/s320/PopupMenuExpanded.png" alt="PopupMenuExpanded" title="PopupMenuExpanded" width="320" /></a></td></tr>
<tr><td class="tr-caption" colspan="2" style="text-align: center;"><code>PopupMenu</code> displaying various items. From top to bottom: <code>PopupMenuItem</code>, <code>PopupSeparator</code>, <code>PopupSliderMenuItem</code>, <code>PopupSwitchMenuItem</code>, <code>PopupSubMenuMenuItem</code>. The remaining items are within the submenu item: <code>PopupSwitchMenuItem</code> (again, with the <code>Switch</code> component outlined), <code>PopupImageMenuItem</code>, and <code>PopupComboBoxMenuItem</code>. You can put any sort of <code>Popup*MenuItem</code> into the combo box; on the right is the combo box open with a <code>PopupMenuItem</code> and <code>PopupImageMenuItem</code> in it.</td></tr>
</tbody></table>
<ul>
<li><a name='popupMenu.PopupBaseMenuItem'><code>PopupBaseMenuItem</code></a>: Base class for popup menu items - an empty popup menu item. Has an 'activate' signal that gets fired when the item is activated. Use <code>.addActor</code> to add visual elements to it (like a <code>St.Label</code>). <strong>All</strong> the other <code>Popup*MenuItem</code> classes inherit from this (and respond to the 'activate' signal).</li>
<li><a name='popupMenu.PopupMenuItem'><code>PopupMenuItem</code></a>: A <code>PopupBaseMenuItem</code> that displays text (in a <code>St.Label</code>).</li>
<li><a name='popupMenu.PopupSeparatorMenuItem'><code>PopupSeparatorMenuItem</code></a>: A <code>PopupBaseMenuItem</code> that is a separator.</li>
<li><a name='popupMenu.PopupAlternatingMenuItem'><code>PopupAlternatingMenuItem</code></a>: A <code>PopupBaseMenuItem</code> that has two texts - one that shows by default, and one that appears upon pressing <code>Clutter.ModifierType.MOD1_MASK</code> (Alt for me). The alternating 'Suspend...'/'Power off' menu item in the user menu is one of these.</li>
<li><a name='popupMenu.PopupSliderMenuItem'><code>PopupSliderMenuItem</code></a>: A <code>PopupBaseMenuItem</code> that is a slider widget. Its value is between 0 and 1 and the item doesn't include a label showing the slider's current value, so that's your job. Example: the volume slider. Use the 'value-changed' signal to detect when the user moves the slider (gets fired with the current value as an argument), and/or the 'drag-end' signal to detect when the user has finished dragging the slider. For example, you could have a label displaying the current value of the slider that gets updated on 'value-changed', and then an action that gets taken when 'drag-end' occurs.</li>
<li><a name='popupMenu.Switch'><code>Switch</code></a>: An on-off toggle switch (<em>not</em> a <code>PopupBaseMenuItem</code>; see <code>PopupSwitchMenuItem</code> for that).</li>
<li><a name='popupMenu.PopupSwitchMenuItem'><code>PopupSwitchMenuItem</code></a>: A <code>PopupBaseMenuItem</code> containing a label/text and a <code>Switch</code> to the right. Example: Wifi/wired connection on/off switch in the network menu. Use the 'toggled' signal to determine when the user toggles it.</li>
<li><a name='popupMenu.PopupImageMenuItem'><code>PopupImageMenuItem</code></a>: A <code>PopupBaseMenuItem</code> containing a label/text and an icon to the right. Example: in the network menu, available wifi networks have the network name and an icon indicating connection strength.</li>
<li><a name='popupMenu.PopupSubMenuMenuItem'><code>PopupSubMenuMenuItem</code></a>: A <code>PopupBaseMenuItem</code> defining a collapsible submenu - click on it to expand/open the submenu and reveal the items inside. Is really just a <code>PopupBaseMenuItem</code> with a label and a <code>PopupSubMenu</code>. Use <code>myItem.menu.addMenuItem</code> to add to its menu.</li>
<li><a name='popupMenu.PopupComboBoxMenuItem'><code>PopupComboBoxMenuItem</code></a>: A <code>PopupBaseMenuItem</code> that is a combo box. Example: the chat status combo box (available/offline) in the user menu. Use <code>myItem.addMenuItem(item)</code> to add a choice to the combo box, and <code>myItem.setActiveItem</code> to set the active item. When a selection is changed, it emits signal <code>active-item-changed</code> with the (0-based) index of the activated item.</li>
</ul>
<p>Menus:</p>
<ul>
<li><a name='popupMenu.PopupMenuBase'><code>PopupMenuBase</code></a>: The base class for a popup menu (e.g. the menu that appears when you click most of the items in the status area). You don't use this directly (unless you are extending it); use any of its child classes and use <code>menu.addMenuItem</code> to add a popup menu item/submenu to it.</li>
<li><a name='popupMenu.PopupMenu'><code>PopupMenu</code></a>: Extends <code>PopupMenuBase</code> to provide a popup menu. This is the main popup menu class (the one that gets used for all the <a href="#panelMenu.Button"><code>PanelMenu.Button</code></a>s).</li>
<li><a name='popupMenu.PopupSubMenu'><code>PopupSubMenu</code></a>: A popup submenu - designed to be nested within a <code>PopupMenu</code>, has a scrollbar in case the content is too long. If you want to add it to a <code>PopupMenu</code> as a collapsible menu section, use <code>PopupSubMenuMenuItem</code>.</li>
<li><a name='popupMenu.PopupMenuSection'><code>PopupMenuSection</code></a>: This acts like a <code>PopupSubMenu</code>, but to the user just looks like a normal <code>PopupMenu</code>. It can be useful to add multiple <code>PopupMenuSection</code>s to a single <code>PopupMenu</code> to 'group' items together code-wise (and to the user it looks like a flat popup menu).</li>
<li><a name='popupMenu.PopupComboMenu'><code>PopupComboMenu</code></a>: Extends <code>PopupMenuBase</code>: this is the menu that drops down from a combo box. If you want a combo box, use <code>PopupComboBoxMenuItem</code>.</li>
<li><a name='popupMenu.RemoteMenu'><code>RemoteMenu</code></a> (<strong>GNOME 3.4 only</strong>): "A <code>PopupMenu</code> that tracks a <code>GMenuModel</code> and shows its actions (exposed by GApplication/GActionGroup). This adds application-specific menu items to a menu (for example in Epiphany the titlebar menu shows 'New Window', 'Bookmarks', etc).</li>
</ul>
<p>Misc:</p>
<ul>
<li><a name='popupMenu.PopupMenuManager'><code>PopupMenuManager</code></a>: "Basic implementation of a menu manager. Call <code>addMenu</code> to add menus". I <em>think</em> you use this if you want to manage multiple menus (???). For example, all the status area menus and the date menu appear to have the same manager (<code>Main.panel._menus</code>). It also looks like it handles the menus grabbing focus, responding to key events, etc.</li>
</ul>
<h3><a name='remoteSearch'><code>remoteSearch.js</code></a> (GNOME 3.4 only)</h3>
<ul>
<li><a name='remoteSearch.SearchProviderProxy'><code>SearchProviderProxy</code></a>: DBus proxy for remote search providers (on 'org.gnome.shell.SearchProvider').</li>
<li><a name='remoteSearch.RemoteSearchProvider'><code>RemoteSearchProvider</code></a>: Extends <a href="#search.SearchProvider">Search.SearchProvider</a> - a search provider that acts through dbus (e.g. Google and Wikipedia). Displays its results in the Overview.</li>
</ul>
<p>Also defines some functions for loading search providers (like Google/Wikipedia): <code>loadRemoteSearchProviders</code> and <code>loadRemoteSearchProvidersFromDir</code> (for me there are some XML files in <code>/usr/share/gnome-shell/open-search-providers</code> for Google/Wikipedia).</p>
<h3><a name='runDialog'><code>runDialog.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-FcwldNb7O5I/UFLK1mEIb2I/AAAAAAAABiI/kufHnFOgMUY/s1600/runDialog.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="62" src="http://4.bp.blogspot.com/-FcwldNb7O5I/UFLK1mEIb2I/AAAAAAAABiI/kufHnFOgMUY/s320/runDialog.png" alt="runDialog" title="runDialog" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>RunDialog</code></td></tr>
</tbody></table>
<ul>
<li><a name='runDialog.CommandCompleter'><code>CommandCompleter</code></a>: command completer for the run dialog (that appears when you press <code>Alt+F2</code>).</li>
<li><a name='runDialog.RunDialog'><code>RunDialog</code></a>: the run dialog that you get on <code>Alt+F2</code>. Type commands in here to have them executed. Also defines a couple of 'special' commands:
<ul>
<li><code>lg</code>: opens the <a href="#lookingGlass">Looking Glass</a>, the developer console for gnome-shell.</li>
<li><code>r</code>, <code>restart</code>: restarts gnome-shell. Needed if you make changes to JS files.</li>
<li><code>rt</code>: 'reload theme', reloads the shell theme (if you only make changes to CSS files this will reload them).</li>
<li><code>debugexit</code>: quits the shell with debug info (well for me it just quits the shell, but maybe I need debug symbol packages).</li>
</ul></li>
</ul>
<h3><a name='scripting'><code>scripting.js</code></a></h3>
<p>Note - all this documentation comes straight from the source, and there is much more in the source.</p>
<p>This module provides functionality for driving the shell user interface in an automated fashion.
The primary current use case for this is automated performance testing (see <code>runPerfScript()</code>), but it could be applied to other forms of automation, such as testing for correctness as well.</p>
<p>When scripting an automated test we want to make a series of calls in a linear fashion, but we also want to be able to let the main loop run so actions can finish. For this reason we write the script as a generator function that yields when it want to let the main loop run.</p>
<pre><code class="language-javascript">yield Scripting.sleep(1000);
main.overview.show();
yield Scripting.waitLeisure();
</code></pre>
<p>While it isn't important to the person writing the script, the actual yielded result is a function that the caller uses to provide the callback for resuming the script.</p>
<p>Provides:</p>
<ul>
<li><p><code>sleep(milliseconds)</code>: Used within an automation script to pause the the execution of the current script for the specified amount of time. Use as:</p>
<pre><code class="language-javascript">yield Scripting.sleep(500);
</code></pre></li>
<li><p><code>waitLeisure()</code>: Used within an automation script to pause the the execution of the current script until the shell is completely idle. Use as:</p>
<pre><code class="language-javascript">yield Scripting.waitLeisure();
</code></pre></li>
<li><a name='scripting.PerfHelper'><code>PerfHelper</code></a>: DBus proxy for 'org.gnome.shell.PerfHelper'.</li>
<li><code>createTestWindow(width, height, alpha, maximized)</code>:
Creates a window using gnome-shell-perf-helper for testing purposes.
While this function can be used with yield in an automation script to pause until the D-Bus call to the helper process returns, because of the normal X asynchronous mapping process, to actually wait until the window has been mapped and exposed, use <code>waitTestWindows()</code>.</li>
<li><code>waitTestWindows()</code>:
Used within an automation script to pause until all windows previously created with <code>createTestWindow</code> have been mapped and exposed.</li>
<li><code>destroyTestWindows()</code>:
Destroys all windows previously created with <code>createTestWindow()</code>.
While this function can be used with yield in an automation script to pause until the D-Bus call to the helper process returns, this doesn't guarantee that Mutter has actually finished the destroy process because of normal X asynchronicity.</li>
<li><code>defineScriptEvent(name, description)</code>:
Convenience function to define a zero-argument performance event within the 'script' namespace that is reserved for events defined locally within a performance automation script.</li>
<li><code>scriptEvent(name)</code>:
Convenience function to record a script-local performance event previously defined with <code>defineScriptEvent</code></li>
<li><code>collectStatistics()</code>: Convenience function to trigger statistics collection.</li>
<li><code>runPerfScript(scriptModule)</code>: module object with run and finish functions and event handlers.
Runs a script for automated collection of performance data. The script is defined as a Javascript module with specified contents. See the <code>scripting.js</code> file for much more detail (it's documented in there).</li>
</ul>
<h3><a name='searchDisplay'><code>searchDisplay.js</code></a></h3>
<ul>
<li><a name='searchDisplay.SearchResult'><code>SearchResult</code></a>: Class representing a single result of a search in the Overview. The UI side is a <code>St.Button</code> containing an <a href="#iconGrid.BaseIcon"><code>IconGrid.BaseIcon</code></a>.</li>
<li><a name='searchDisplay.GridSearchResults'><code>GridSearchResults</code></a>: extends <a href="#search.SearchResultDisplay"><code>Search.SearchResultDisplay</code></a>, a wrapper around an <a href="#iconGrid.IconGrid">Icon Grid</a>. This handles the display of search results from multiple providers in the overview.</li>
<li><a name='searchDisplay.SearchResults'><code>SearchResults</code></a>: displays search results that don't get displayed in a grid? The Wikipedia/Google results (but these don't appear in the overview, at least for me - they get opened in a browser)?</li>
</ul>
<h3><a name='search'><code>search.js</code></a></h3>
<p>Note - this is a set of abstract classes to be subclassed and particular methods implemented in order to work. The file is very well-documented with the details; not all of them are provided here.</p>
<ul>
<li><a name='search.SearchResultDisplay'><code>SearchResultDisplay</code></a>: Abstract class that handles the display of results from a searchProvider. It <em>must</em> be subclassed. In particular, it must implement methods <code>getVisibleResultCount</code>, <code>clear</code> (clears all results from the display), and <code>renderResults</code>. Examples: <a href="#searchDisplay.GridSearchResults"><code>GridSearchResults</code></a>.</li>
<li><a name='search.SearchProvider'><code>SearchProvider</code></a>: Abstract class representing a search provider (search engine). <em>Must</em> be subclassed to implement methods <code>getInitialResultSet</code> (called when user first begins a search), <code>getSubsearchResultSet</code>, <code>getResultMetas</code>, <code>activateResult</code>, ... (and asynchronous versions). Should also implement <code>createResultContainerActor</code> if you wish to override how results get rendered (default is a vertical list) - should return a <code>SearchResultDisplay</code>. Examples of implementations: <a href="#contactDisplay.ContactSearchProvider"><code>ContactSearchProvider</code> (searches contacts)</a>, <a href="#appDisplay.AppSearchProvider"><code>AppSearchProvider</code> (searches apps)</a>, <a href="#placesDisplay.PlaceSearchProvider"><code>PlaceSearchProvider</code> (searches volumes/places)</a>, <a href="#remoteSearch.RemoteSearchProvider"><code>RemoteSearchProvider</code> (searches Wikipedia/Google)</a>, <a href="#wanda.WandaSearchProvider"><code>WandaSearchProvider</code> (finds wanda if you type in the magic incantation!)</a>. Most of these just use <a href="#searchDisplay.GridSearchResults"><code>GridSearchResults</code></a> to render their results.</li>
<li><a name='search.OpenSearchSystem'><code>OpenSearchSystem</code></a>: An open search system (has multiple providers), loading its providers from <code>/usr/share/gnome-shell/open-search-providers</code> (e.g. Google/Wikipedia).</li>
<li><a name='search.SearchSystem'><code>SearchSystem</code></a>: A search system (searches terms in multiple providers). Add search providers to it through <code>registerProvider</code>.</li>
</ul>
<h3><a name='shellDBus'><code>shellDBus.js</code></a></h3>
<ul>
<li><a name='shellDBus.GnomeShell'><code>GnomeShell</code></a>: GNOME shell DBus implementation (interface name <code>org.gnome.shell</code>, path <code>/org/gnome/Shell</code>)</li>
</ul>
<p>The GNOME-shell DBus interface allows requests for the shell to:</p>
<ul>
<li><code>Eval</code>: takes in a string argument of code, executes in the mainloop, and returns a boolean success and JSON representation of the result as a string.</li>
<li><code>ListExtensions</code>: Return a list of installed extensions, being an object of UUID -> extension info (see next method).</li>
<li><code>GetExtensionInfo</code>: Returns the information for a particular extension. Input is the extension UUID, output is an 'Extension Info', being an object indexed by property ('type', 'state', 'path', 'error', 'hasPrefs').</li>
<li><code>GetExtensionErrors</code>: Gets errors thrown by an extension. Input is UUID, output is an array of errors (as strings).</li>
<li><code>EnableExtension</code>: enables an extension. Input argument is the UUID of the extension.</li>
<li><code>DisableExtension</code>: disable an extension. Input argument is the UUID.</li>
<li><code>InstallRemoteExtension</code>: Install an extension remotely (from e.g.o). Input arguments: UUID and version.</li>
<li><code>UninstallExtension</code>: Uninstall an extension. Input arguments: UUID.</li>
<li><code>LaunchExtensionPrefs</code> (<strong>GNOME 3.4 only</strong>): Launch the extension prefs dialog. Input argument: UUID of which extension to show the preferences widget of.</li>
<li><code>ScreenshotArea</code>: Takes a screenshot of an area on the screen. Input arguments: position and dimensions of the area to screenshot, whether to flash the screen, and the filename to save as.</li>
<li><code>ScreenshotWindow</code>: Takes a screenshot of the focused window. Arguments are whether to include the window frame, whether to include the window cursor, whether to flash the screen upon completion, what filename to save.</li>
<li><code>Screenshot</code>: Takes a screenshot. Input arguments are whether to include the cursor, whether to flash the screen on completion, and the filename to save as.</li>
<li><code>FlashArea</code> (<strong>GNOME 3.4 only</strong>): Flash a particular area. Input arguments are the positon and dimensions of the area.</li>
</ul>
<p>See the file for further information (it's very well-documented).</p>
<p>Properties on the DBus:</p>
<ul>
<li><code>OverviewActive</code>: get/set whether the overview is active.</li>
<li><code>ApiVersion</code>: returns the extension system's <code>API_VERSION</code>.</li>
<li><code>ShellVersion</code>: returns GNOME-shell's version.</li>
</ul>
<p>Signals:</p>
<ul>
<li>'ExtensionStatusChanged': whenever an extension's status changes. Gives the extension's UUID, state, and any error.</li>
</ul>
<h3><a name='shellEntry'><code>shellEntry.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-3K4DBDUBwco/UFLK2r9MqRI/AAAAAAAABiU/3ydg4QoC3oY/s1600/shellEntry.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="140" src="http://2.bp.blogspot.com/-3K4DBDUBwco/UFLK2r9MqRI/AAAAAAAABiU/3ydg4QoC3oY/s320/shellEntry.png" alt="shellEntry" title="shellEntry" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The context menu of the run dialog's entry via <code>ShellEntry.addContextMenu</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='shellEntry._EntryMenu'><code>_EntryMenu</code></a>: A subclass of <a href="#popupMenu.PopupMenu"><code>PopupMenu</code></a> used to provide a context menu to a <code>Clutter.Entry</code> or <code>St.Entry</code> (text box). Do not use this class directly; instead use <code>ShellEntry.addContextMenu(entry)</code>. The context menu acts like so: when the user long-presses or right-clicks the entry, they get a popup menu with 'paste' and 'copy' (unless it's a context menu for a password dialog!). If it's for a password dialog it'll have a 'show/hide characters' item too.</li>
</ul>
<h3><a name='shellMountOperation'><code>shellMountOperation.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-C9axNhJ7v1w/UFLK33EkVbI/AAAAAAAABig/RhVmm6afj9U/s1600/shellProcessesDialog.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="169" src="http://1.bp.blogspot.com/-C9axNhJ7v1w/UFLK33EkVbI/AAAAAAAABig/RhVmm6afj9U/s320/shellProcessesDialog.png" alt="shellProcessesDialog" title="shellProcessesDialog" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>ShellProcessesDialog</code> containing a <code>ListItem</code> per application that is holding up the volume.</td></tr>
</tbody></table>
<ul>
<li><a name='shellMountOperation.ShellMountOperation'><code>ShellMountOperation</code></a>: Wrapper around a <code>Shell.MountOperation</code>. This is created when the user clicks a device's 'eject' button from the <a href="#autorunManager.AutorunResidentNotification"><code>autorunManager.AutorunResidentNotification</code></a>, or mounts a device. It checks if there is anything stopping the device from being ejected (e.g. it's still in use) and shows a <code>ShellMountQuestionDialog</code> if appropriate. If passwords are required for the device, it will create a new notification (<code>ShellMountPasswordSource</code> and <code>ShellMountPasswordNotification</code>).</li>
<li><a name='shellMountOperation.ShellMountQuestionDialog'><code>ShellMountQuestionDialog</code></a>: Extends <a href="#modalDialog.ModalDialog"><code>ModalDialog</code></a> to provide a dialog that asks a question about a mount and offers choices. UPTO want a pic</li>
<li><a name='shellMountOperation.ShellMountPasswordSource'><code>ShellMountPasswordSource</code></a>: Extends <a href="#messageTray.Source"><code>MessageTray.Source</code></a>: a source of notifications in the message tray that asks for a password if unmounting requires it. UPTO want a pic</li>
<li><a name='shellMountOperation.ShellMountPasswordNotification'><code>ShellMountPasswordNotification</code></a>: Extends <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> to provide the notification in the message tray that tells you you've entered the wrong password/queries you for a password (i.e. defines the UI elements, being the text, password entry box, ...).</li>
<li><a name='shellMountOperation.ShellProcessesDialog'><code>ShellProcessesDialog</code></a>: Extends <a href="#modalDialog.ModalDialog"><code>ModalDialog</code></a> to provide a dialog that shows you which applications are impeding the removal of a device. I have never actually seen this dialog and am unsure how to make it display (when I try to eject a device that is open in another process I just get 'the device is busy' with a 'Unmount anyway' or 'Cancel' choice, but not the list of processes using it).</li>
<li><a name='shellMountOperation.ListItem'><code>ListItem</code></a>: A button displaying a particular application's icon and name, that will launch the application when clicked. These are used in the <code>ShellProcessesDialog</code>, one per application that impedes the removal of a device.</li>
</ul>
<h3><a name='statusIconDispatcher'><code>statusIconDispatcher.js</code></a></h3>
<ul>
<li><a name='statusIconDispatcher.StatusIconDispatcher'><code>StatusIconDispatcher</code></a>: Handles re-directoring tray icons for applications to the standard gnome-shell status icons. For example, when <code>gnome-volume-control-applet</code> or <code>gnome-sound-control-applet</code> launch and add their icons to the message tray, the dispatcher suppresses their icons as they are handled by the 'volume' status icon.</li>
</ul>
<h3><a name='telepathyClient'><code>telepathyClient.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-vAP7p56Lajo/UFLK-ZQG_tI/AAAAAAAABjY/HZFWcbGqBs0/s1600/telepathyClient.AudioVideoNotification.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="92" src="http://1.bp.blogspot.com/-vAP7p56Lajo/UFLK-ZQG_tI/AAAAAAAABjY/HZFWcbGqBs0/s320/telepathyClient.AudioVideoNotification.png" alt="telepathyClient AudioVideoNotification" title="telepathyClient AudioVideoNotification" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A <code>AudioVideoNotification</code>.</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-fYqil14Dmz4/UFLK_SF73wI/AAAAAAAABjg/Bmvp_vOZLao/s1600/telepathyClient.Chat.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="178" src="http://3.bp.blogspot.com/-fYqil14Dmz4/UFLK_SF73wI/AAAAAAAABjg/Bmvp_vOZLao/s320/telepathyClient.Chat.png" alt="telepathyClient Chat" title="telepathyClient Chat" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A <code>ChatNotification</code> (the corresponding <code>ChatSource</code> provides the avatar of the contact from whom the chat originates).</td></tr>
</tbody></table>
<p>Reminder - a notification 'source' can provide many 'notification's, and a 'source' handles logic whereas the notifications are on the UI side.</p>
<ul>
<li><a name='telepathyClient.Client'><code>Client</code></a>: A big wrapper around telepathy client. It communicates over DBus to receive and send your messages and display notifications/etc from the message tray.</li>
<li><a name='telepathyClient.ChatSource'><code>ChatSource</code></a>: A <a href="#messageTray.Source"><code>MessageTray.Source</code></a> that is tailored for chats. You have one source per contact you're chatting with and you can continue chatting with them from the message tray.</li>
<li><a name='telepathyClient.ChatNotification'><code>ChatNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> that pops up a notification whenever you get a new chat and defines the UI elements in the notification allowing you to chat from it.</li>
<li><a name='telepathyClient.ApproverSource'><code>ApproverSource</code></a>: A <a href="#messageTray.Source"><code>MessageTray.Source</code></a> for approval requests (e.g. being invited into a chat room, accepting a call, file transfers, ..). The icon is relevant to the request - a microphone icon for an audio call, video icon for a video call, ...</li>
<li><a name='telepathyClient.RoomInviteNotification'><code>RoomInviteNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> that pops up when you get a room invite (notifies from an <code>ApproverSource</code>).</li>
<li><a name='telepathyClient.AudioVideoNotification'><code>AudioVideoNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> that pops up when you get a call (notifies from an <code>ApproverSource</code>).</li>
<li><a name='telepathyClient.FileTransferNotification'><code>FileTransferNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> that pops up when you get a file transfer request (notifies from an <code>ApproverSource</code>).</li>
<li><a name='telepathyClient.MultiNotificationSource'><code>MultiNotificationSource</code></a>: A <a href="#messageTray.Source"><code>MessageTray.Source</code></a> is "A notification source that can embed multiple notifications". It is used (for example) to display account notifications about failing to connect...</li>
<li><a name='telepathyClient.SubscriptionRequestNotification'><code>SubscriptionRequestNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> for subscription requests (e.g. '<alias> would like permission to see when you are online') -- has 'Accept' and 'Decline' options.</li>
<li><a name='telepathyClient.AccountNotification'><code>AccountNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> for account-related notifications - e.g. connection failure. Also has 'Reconnect' or 'Edit account' buttons.</li>
</ul>
<h3><a name='tweener'><code>tweener.js</code></a></h3>
<p>From the source - "This is a wrapper around <code>imports.tweener.tweener</code> that adds a bit of Clutter integration and some additional callbacks:</p>
<ol>
<li>If the tweening target is a <code>Clutter.Actor</code>, then the tweenings will be automatically removed if the actor is destroyed.</li>
<li>If <code>target._delegate.onAnimationStart()</code> exists, it will be called when the target starts being animated.</li>
<li>If <code>target._delegate.onAnimationComplete()</code> exists, it will be called once the target is no longer being animated.</li>
</ol>
<p>More documentation/explanation in the file, which contains functions and a class <code>ClutterFrameTicker</code> to make the magic happen (<code>main.js</code> calls <code>init()</code> in the file to get it all working).</p>
<h3><a name='userMenu'><code>userMenu.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="5" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-zyCuEsHQJtY/UFLLAWXbP6I/AAAAAAAABjo/0uj0ji9ncVA/s1600/userMenu.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://2.bp.blogspot.com/-zyCuEsHQJtY/UFLLAWXbP6I/AAAAAAAABjo/0uj0ji9ncVA/s320/userMenu.png" alt="userMenu" title="userMenu" width="214" /></a></td><td class="tr-caption" style="text-align: center;"><div style="text-align: left;">
The <code>UserMenu</code>.</div>
</td>
</tr>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-2faHpL3By5s/UFLLBcEyqeI/AAAAAAAABjw/xU_YeAy3ASA/s1600/userMenu_IMUserNameItem-blue_IMStatusChooserItem-red.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-2faHpL3By5s/UFLLBcEyqeI/AAAAAAAABjw/xU_YeAy3ASA/s1600/userMenu_IMUserNameItem-blue_IMStatusChooserItem-red.png" alt="userMenu_IMUserNameItem-blue_IMStatusChooserItem-red" title="userMenu_IMUserNameItem-blue_IMStatusChooserItem-red" /></a></td><td class="tr-caption" style="text-align: center;"><div style="text-align: left;">
<code>IMStatusChooserItem</code> (red); <code>IMUserNameItem</code> (blue); the combo box contains <code>IMStatusItem</code>s.</div>
</td></tr>
</tbody></table>
<ul>
<li><a name='userMenu.IMStatusItem'><code>IMStatusItem</code></a>: A <a href="#popupMenu.PopupBaseMenuItem"><code>PopupMenu.PopupBaseMenuItem</code></a> consisting of a label (like 'Away', 'Busy') and its corresponding icon. Used in the combobox in the user menu where you select your status.</li>
<li><a name='userMenu.IMUserNameItem'><code>IMUserNameItem</code></a>: A <a href="#popupMenu.PopupBaseMenuItem"><code>PopupMenu.PopupBaseMenuItem</code></a> showing the user's username.</li>
<li><a name='userMenu.IMStatusChooserItem'><code>IMStatusChooserItem</code></a>: A <a href="#popupMenu.PopupBaseMenuItem"><code>PopupMenu.PopupBaseMenuItem</code></a> that is the <em>entire</em> avatar-username-status chooser item in the user menu. It displays user's avatar on the left (which you can click to let you change your picture), a <code>IMUserNameItem</code> to the top-right (showing the user's username), and a <a href="#popupMenu.PopupComboBoxMenuItem"><code>PopupMenu.PopupComboBoxMenuItem</code></a> on the bottom-right that allows you to change your online status. The items in the ecombo box are <code>IMStatusItem</code>s. It also makes sure to keep your status icon up to date with your actual status. Note that only 'available' and 'offline' are <em>always</em> shown as options in the combo box; 'busy', 'hidden', 'away' and 'idle' are only shown if that is your current status. That is, you can only set your status to 'available' or 'offline'; the other statuses are read-only (will show if that is your status but not allow you to set them as your status).</li>
<li><a name='userMenu.UserMenuButton'><code>UserMenuButton</code></a>: This is a <a href="#panelMenu.Button"><code>PanelMenu.Button</code></a> that represents the user menu in your top panel - both the icon/username and its PopupMenu.</li>
</ul>
<h3><a name='viewSelector'><code>viewSelector.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-5S17gVzZkRo/UFLKlgfukBI/AAAAAAAABgM/uvJO6KB6RQg/s1600/ViewSelector.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="http://1.bp.blogspot.com/-5S17gVzZkRo/UFLKlgfukBI/AAAAAAAABgM/uvJO6KB6RQg/s320/ViewSelector.png" alt="ViewSelector" title="ViewSelector" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">ViewSelector outlined in red (currently displaying the 'Applications' tab; it also has a Windows and Search tab).</td></tr>
</tbody></table>
<ul>
<li><a name='viewSelector.BaseTab'><code>BaseTab</code></a>: Base class for a tab (a page in the overview, e.g. 'Windows' and 'Applications'). Requires an actor defining its title (being the thing you click on to switch to that tab) and an actor defining the tab contents.</li>
<li><a name='viewSelector.ViewTab'><code>ViewTab</code></a>: Extends <code>BaseTab</code> where the title actor is just a <code>St.Button</code> with some text in it. The 'windows' and 'applications' tabs are examples of this.</li>
<li><a name='viewSelector.SearchTab'><code>SearchTab</code></a>: Extends <code>BaseTab</code> where the title actor is a search box. The search 'tab' has a title being the <code>St.Entry</code> you enter your search into, and its page is the search results (it uses a <a href="#search.SearchSystem"><code>Search.SearchSystem</code></a> to perform the search through all of its <a href="#search.SearchProvider"><code>Search.SearchProvider</code></a>s, displaying results in a <a href="#searchDisplay.SearchResults"><code>SearchDisplay.SearchResults</code></a>. Use <code>addSearchProvider</code> and <code>removeSearchProvider</code> to add/remove providers to the search system (however if you want to add/remove search providers to the search tab in the overview, you should use <code>Main.overview.addSearchProvider</code> and <code>Main.overview.removeSearchProvider</code>, which pass the commands down to the search system in the search tab).</li>
<li><a name='viewSelector.ViewSelector'><code>ViewSelector</code></a>: This is the notebook-like class being the 'content area' bit of the overview (the overview minus the workspace display and dash). You add pages ('tabs') to it with <code>addViewTab</code>, and switch between tabs with <code>switchTab</code>. The view selector is stored in <code>Main.overview._viewSelector</code>.</li>
</ul>
<h3><a name='wanda'><code>wanda.js</code></a> (GNOME 3.4 only)</h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-sOTroZqLaJY/UFLLDRhL6bI/AAAAAAAABkE/EdQcz3J5yfQ/s1600/wanda.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-sOTroZqLaJY/UFLLDRhL6bI/AAAAAAAABkE/EdQcz3J5yfQ/s1600/wanda.png" alt="wanda" title="wanda" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>WandaIcon</code> from the <code>WandaSearchProvider</code>.</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-QFqYdojX1jM/UFLLCHqL7eI/AAAAAAAABj8/Baz135S-r64/s1600/wanda.FortuneDialog.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="220" src="http://4.bp.blogspot.com/-QFqYdojX1jM/UFLLCHqL7eI/AAAAAAAABj8/Baz135S-r64/s320/wanda.FortuneDialog.png" alt="wanda FortuneDialog" title="wanda FortuneDialog" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Example of Wanda's wisdom (popup in the middle of your screen)</td></tr>
</tbody></table>
<ul>
<li><a name='wanda.WandaIcon'><code>WandaIcon</code></a>: Extends <a href="#iconGrid.BaseIcon"><code>IconGrid.BaseIcon</code></a>: it's an icon displaying an animated Wanda :).</li>
<li><a name='wanda.WandaIconBin'><code>WandaIconBin</code></a>: A <code>St.Bin</code> consisting of the Wanda.</li>
<li><a name='wanda.FortuneDialog'><code>FortuneDialog</code></a>: When you ask for wisdom from Wanda she will give it to you via a popup dialog on your screen. This is that.</li>
<li><a name='wanda.WandaSearchProvider'><code>WandaSearchProvider</code></a>: Wanda's search provider -- Wanda will only appear if you type in the magic words <em>exactly</em> into the search box! What are the magic words to summon the Oracle? .... find out for yourself ;) (Hint: <code>MAGIC_FISH_KEY</code>).</li>
</ul>
<h3><a name='windowAttentionHandler'><code>windowAttentionHandler.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-udBFUzKJTmA/UFLLECAnnKI/AAAAAAAABkI/7Vpvtas0HUg/s1600/windowAttentionHandler.Source.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="62" src="http://3.bp.blogspot.com/-udBFUzKJTmA/UFLLECAnnKI/AAAAAAAABkI/7Vpvtas0HUg/s320/windowAttentionHandler.Source.png" alt="windowAttentionHandler Source" title="windowAttentionHandler Source" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Example of notification from the <code>WindowAttentionHandler</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='windowAttentionHandler.WindowAttentionHandler'><code>WindowAttentionHandler</code></a>: Handles 'window-demands-attention' signals from <code>global.display</code> and pops up the "<app> is ready" notification upon receiving it. When you start up an app it can take a while to load an in the meantime you move on to another window; when the window does actually load you get a notification letting you know the application is ready to be used.</li>
<li><a name='windowAttentionHandler.Source'><code>Source</code></a>: A [<code>MessageTray.Source</code>] tailored to window attention requests (e.g. if you focus the window then the notification is no longer relevant so it will remove itself).</li>
</ul>
<h3><a name='windowManager'><code>windowManager.js</code></a></h3>
<ul>
<li><a name='windowManager.WindowDimmer'><code>WindowDimmer</code></a>: When created with an actor (for example a <code>Meta.WindowActor</code>), dims that actor. For example when you open a modal dialog from a window, that window is dimmed until you're finished with the modal dialog.</li>
<li><a name='windowManager.WindowManager'><code>WindowManager</code></a>: Extra bells and whistles on the underlying window manager (being <code>global.windowManager</code>, a <code>Shell.WM</code>). This handles things like:
<ul>
<li>showing the workspace swicther popup upon receiving a 'switch-to-worskpace-*' keybinding,</li>
<li>animating all your windows sliding off the screen when you switch workspaces,</li>
<li>adding animations to windows when they are minimized/maximized/mapped/destroyed,</li>
<li>dimming a parent window if you open a modal dialog for it (undimming when the dialog is dismissed),</li>
<li>showing the window switcher (Alt+Tab) popup, and</li>
<li>showing the accessibility switcher (Ctrl+Alt+Tab) popup.</li>
</ul></li>
</ul>
<h3><a name='workspace'><code>workspace.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-BKp1BjXzVxw/UFLLGTjF85I/AAAAAAAABkk/Q3Bt8KOeOsU/s1600/workspace_Display-red_Clone-yellow_Overlay-green.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="http://2.bp.blogspot.com/-BKp1BjXzVxw/UFLLGTjF85I/AAAAAAAABkk/Q3Bt8KOeOsU/s320/workspace_Display-red_Clone-yellow_Overlay-green.png" alt="workspace_Display-red_Clone-yellow_Overlay-green" title="workspace_Display-red_Clone-yellow_Overlay-green" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>WorkspacesView.WorkspacesDisplay</code> is in red. The <code>Workspace</code> is holds all the <code>WindowClone</code>s (yellow) with the <code>WindowOverlay</code> (green, also includes the close button).</td></tr>
</tbody></table>
<ul>
<li><a name='workspace.ScaledPoint'><code>ScaledPoint</code></a>: A point (<code>x</code>, <code>y</code>) that has a scale applied to it in the X and Y dimensions. Contains convenience methods to interpolate between positions, or between scales. Only used for zooming in <code>WindowClone</code>s.</li>
<li><a name='workspace.WindowClone'><code>WindowClone</code></a>: The thumbnail of a window that you see in the windows tab of the Overview. You can vertical-scroll on the window to zoom in/out, click on it to activate it, drag it to move it between workspaces. One per window actor.</li>
<li><a name='workspace.WindowOverlay'><code>WindowOverlay</code></a>: This defines items that are overlaid on to the <code>WindowClone</code>. In particular, the window's caption and the close button (that you see on each window in the Overview).</li>
<li><a name='workspace.Workspace'><code>Workspace</code></a>: Represents a collection of <code>WindowOverlay</code>s in the overview. Each one just looks after the overlays in its own workspace and monitor (specified at creation). It handles how to lay out its overlays (for example in GNOME 3.4 when you have 5 overlays it positions three in the top row and two in the bottom row). This is <em>not</em> the workspace previews you see in the workspaces sidebar; that's a <code>WorkspaceThumbnail.WorkspaceThumbnail</code>.</li>
</ul>
<h3><a name='workspacesView'><code>workspacesView.js</code></a></h3>
<ul>
<li><a name='workspacesView.WorkspacesView'><code>WorkspacesView</code></a>: A container for many <a href="#workspace.Workspace"><code>Workspace.Workspace</code></a>s. Recall that a <code>Workspace.Workspace</code> manages window thumbnails for all the windows on its <em>own</em> workspace <em>and</em> monitor. The <code>WorkspacesView</code> maintains a list of <code>Workspace</code>s and handles not only inter-monitor (intra-workspace) interactions (like dragging a window from one monitor to the other on the <em>same</em> workspace, which involves moving it from the <code>Workspace.Workspace</code> for workspace <code>i</code> and monitor <code>j</code> to the <code>Workspace.Workspace</code> for workspace <code>i</code> and monitor <code>k</code>), but inter-workspace interactions (when you switch workspaces, the <code>WorkspacesView</code> should show the appropriate <code>Workspace.Workspace</code>s for that workspace, taking into account the 'workspaces-only-on-primary' setting, and also animate this action). There may be more to it than that.</li>
<li><a name='workspacesView.WorkspacesDisplay'><code>WorkspacesDisplay</code></a>: This is essentially the 'Windows' tab in the Overview. On the right hand side it has a sidebar showing workspace thumbnails that you can choose; this is a <a href="#workspaceThumbnail.ThumbnailsBox"><code>WorkspaceThumbnail.ThumbnailsBox</code></a>. The part that shows all the window thumbnails is a <code>WorkspacesView</code>. This class handles things like when the workspaces preview sidebar (<code>ThumbnailBox</code>) should be slidden out and in, showing/animating the rectangle about the current workspace in the sidebar animating when dynamic workspaces are added/removed, changing workspaces on scrolling over the sidebar, etc.</li>
</ul>
<h3><a name='workspaceSwitcherPopup'><code>workspaceSwitcherPopup.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-f0L9g-WQUiY/UFLLElWzuYI/AAAAAAAABkQ/Sydvkcq7wKA/s1600/workspaceSwitcherPopup.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="200" src="http://3.bp.blogspot.com/-f0L9g-WQUiY/UFLLElWzuYI/AAAAAAAABkQ/Sydvkcq7wKA/s200/workspaceSwitcherPopup.png" alt="workspaceSwitcherPopup" title="workspaceSwitcherPopup" width="139" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><code>WorkspaceSwitcherPopup</code>.</td></tr>
</tbody></table>
<ul>
<li><a name='workspaceSwitcherPopup.WorkspaceSwitcherPopup'><code>WorkspaceSwitcherPopup</code></a>: This is the popup that appears when you switch workspaces (via e.g. via the keybindings) showing which workspace you've switched to.</li>
</ul>
<h3><a name='workspaceThumbnail'><code>workspaceThumbnail.js</code></a></h3>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-XcIWG6Dm-XQ/UFLLFYJHhHI/AAAAAAAABkY/f-j6WF1ulkA/s1600/workspaceThumbnails.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://1.bp.blogspot.com/-XcIWG6Dm-XQ/UFLLFYJHhHI/AAAAAAAABkY/f-j6WF1ulkA/s320/workspaceThumbnails.png" alt="workspaceThumbnails" title="workspaceThumbnails" width="78" /></a></td>
<td class="tr-caption" style="text-align: center;">The <code>ThumbnailsBox.</code> (yellow), with <code>WorkspaceThumbnail</code> (red) containing <code>WindowClone</code>s (green). The <code>dragPlaceholder</code> is the white bar in between the thumbnails where I'm attempting to drag a window.</td>
</tr>
</tbody></table>
<ul>
<li><a name='workspaceThumbnail.ThumbnailsBox'><code>ThumbnailsBox</code></a>: This is a collection of workspace thumbnails (the workspaces sidebar you see in the Overview). Handles the sliding in or out of workspaces as they are added/destroyed, and also dragging windows to create <em>new</em> workspaces between existing ones (try dragging a window to the boundary between a two workspaces - this feature is not there in GNOME 3.2 however).</li>
<li><a name='workspaceThumbnail.WorkspaceThumbnail'><code>WorkspaceThumbnail</code></a>: This is a thumbnail of a workspace, one per workspace (seen in the workspaces sidebar in the Overview). Shows thumbnails of all the windows on that workspace (I <em>think</em> it will only preview the primary monitor; if you have more than one monitors the other monitors & their windows will not be in the thumbnail). It is an up-to-date snapshot of its windows (updates when windows are added/removed/minimized state changed - not if they are moved or resized).</li>
<li><a name='workspaceThumbnail.WindowClone'><code>WindowClone</code></a>: This is a thumbnail of a window (used in a <code>WorkspaceThumbnail</code>) - one per window. It can be dragged to another workspace to switch its workspace.</li>
</ul>
<h3><a name='xdndHandler'><code>xdndHandler.js</code></a></h3>
<ul>
<li><a name='xdndHandler.XdndHandler'><code>XdndHandler</code></a>: Sets up Xdnd and passes through signals. When a non-gnome-shell object is first dragged over a gnome-shell object, the handler fires a 'drag-begin' signal. When the object being dragged leaves the gnome-shell object, the 'drag-end' signal is fired. I think it somehow incorporates with the <a href="#dnd"><code>dnd.js</code></a> code too whereby a draggable target/object registered with <code>dnd.js</code> has the appropriate events called on it (?). Use <code>Main.xdndHandler</code> to access the instance of the handler and connect to its signals.</li>
</ul>
<hr />
<h2><a name='status'>Status indicators</a></h2>
<p>These files all live in <code>js/ui/status/</code> and define the standardstatus indicators in the status area.</p>
<h3><a name='accessibility'><code>accessibility.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-ZQCylQz6C5I/UFLK54jYiCI/AAAAAAAABio/IXvmg_JVA98/s1600/status.accessibility.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://4.bp.blogspot.com/-ZQCylQz6C5I/UFLK54jYiCI/AAAAAAAABio/IXvmg_JVA98/s320/status.accessibility.png" alt="status accessibility" title="status accessibility" width="226" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Accessibility status icon</td></tr>
</tbody></table>
<ul>
<li><a name='accessibility.ATIndicator'><code>ATIndicator</code></a>: The <a href="#panelMenu.SystemStatusButton"><code>PanelMenu.SystemStatusButton</code></a> defining the accessibility indicator.
This provides a number of <a href="#popupMenu.PopupSwitchMenuItem"><code>PopupSwitchMenuItem</code></a>s allowing you to toggle on and off various accessibility features (high contrast, zoom, on-screen keyboard, ...)</li>
</ul>
<h3><a name='bluetooth'><code>bluetooth.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="5" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td rowspan="2" style="text-align: center;"><a href="http://2.bp.blogspot.com/-y4s2aAi-mmM/UFMfEmoP7BI/AAAAAAAABng/pJexossiQ3U/s1600/status.bluetooth.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://2.bp.blogspot.com/-y4s2aAi-mmM/UFMfEmoP7BI/AAAAAAAABng/pJexossiQ3U/s320/status.bluetooth.png" width="261" alt="status bluetooth" title="status bluetooth" /></a></td><td style="height: 160px; text-align: center;"><a href="http://2.bp.blogspot.com/-fyGSOfzSJZ0/UFMe8ZFB7LI/AAAAAAAABnI/qie-mwRnMfk/s1600/bluetooth.AuthNotification.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="78" src="http://2.bp.blogspot.com/-fyGSOfzSJZ0/UFMe8ZFB7LI/AAAAAAAABnI/qie-mwRnMfk/s320/bluetooth.AuthNotification.png" width="320" alt="bluetooth AuthNotification" title="bluetooth AuthNotification" /></a></td></tr>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-jstA7wrSYp0/UFMe9o_q1mI/AAAAAAAABnQ/Dp3XXbYVALo/s1600/bluetooth.ConfirmNotification.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="103" src="http://2.bp.blogspot.com/-jstA7wrSYp0/UFMe9o_q1mI/AAAAAAAABnQ/Dp3XXbYVALo/s320/bluetooth.ConfirmNotification.png" width="320" alt="bluetooth ConfirmNotification" title="bluetooth ConfirmNotification" /></a></td></tr>
<tr><td class="tr-caption" colspan="2" style="text-align: center;">Bluetooth indicator icon (left); <code>AuthNotification</code> (top right); <code>ConfirmNotification</code> (bottom right).</td></tr>
</tbody></table>
<ul>
<li><a name='bluetooth.Indicator'><code>Indicator</code></a>: The <a href="#panelMenu.SystemStatusButton"><code>PanelMenu.SystemStatusButton</code></a> defining the bluetooth indicator. Wraps around gi repository/bindings <code>GnomeBluetoothApplet</code>. Contains toggles for turning on and off bluetooth and your visibility, along with menu items to access bluetooth settings and show current bluetooth devices.</li>
<li><a name='bluetooth.Source'><code>Source</code></a>: A <a href="#messageTray.Source"><code>MessageTray.Source</code></a> for bluetooth notifications (pin requests, transfer requests, ...).</li>
<li><a name='bluetooth.AuthNotification'><code>AuthNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> providing the notification for authorization requests, providing options 'Grant this time only', 'Reject' and 'Always grant access'.</li>
<li><a name='bluetooth.ConfirmNotification'><code>ConfirmNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> providing the notification for pairing confirmations: "Device XYZ wants to pair with this computer. Please confirm whether PIN 'xxxx' matches the one on the device" with "Matches" and "Does not match" options.</li>
<li><a name='bluetooth.PinNotification'><code>PinNotification</code></a>: A <a href="#messageTray.Notification"><code>MessageTray.Notification</code></a> providing the notification for PIN requests: "Device XYZ wants to pair with this computer. Please enter the PIN mentioned on the device", with a <code>St.Entry</code> to let you enter the PIN.</li>
</ul>
<h3><a name='status.keyboard'><code>keyboard.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-0OGq-2Bla4k/UFLK7T8u7-I/AAAAAAAABi4/8VaJpjnoNA8/s1600/status.keyboard.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-0OGq-2Bla4k/UFLK7T8u7-I/AAAAAAAABi4/8VaJpjnoNA8/s1600/status.keyboard.png" alt="status keyboard" title="status keyboard" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Keyboard layout status icon</td></tr>
</tbody></table>
<ul>
<li><a name='keyboard.LayoutMenuItem'><code>LayoutMenuItem</code></a>: Extends <a href="#popupMenu.PopupBaseMenuItem"><code>PopupMenu.PopupBaseMenuItem</code></a> consists of text and an either a label with the keyboard layout's abbreviation (eg 'en' for English (US)), or an icon with that country's flag <em>if</em> you have gnome keyboard's 'showFlags' setting set to TRUE. In GNOME 3.2 and 3.4, this can be adjusted with dconf setting 'org.gnome.libgnomekbd.indicator.show-flags'. If you're lucky supposedly Ubuntu has the flag images in <code>/usr/share/pixmaps/flags</code> and then the flags will show. Otherwise you have to find pictures of them and put them in <code>$HOME/.icons/flags</code> named with the country's <a href="http://www.iso.org/iso/support/country_codes/iso_3166_code_lists/iso-3166-1_decoding_table.htm">two-letter ISO 3166-1 combination</a>. I think some packages may provide flags, but you can also get them from <a href="http://gnome-look.org/content/search.php?search&text=language%20flags">gnome-look.org</a>.</li>
<li><a name='keyboard.XKBIndicator'><code>XKBIndicator</code></a>: The <a href="#panelMenu.Button"><code>PanelMenu.Button</code></a> defining the keyboard indicator. Note it is not a <code>SystemStatusButton</code> since its 'icon' is not a stock one, but either text (current keyboard layout code like 'en') or icon (flag for the country's keyboard layout). Lets you switch between keyboard layouts (only shows if you set more than one layout in the GNOME control centre -> 'Keyboard' -> 'Layout Settings').</li>
</ul>
<h3><a name='network'><code>network.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-vneOXZHWoow/UFMe-Zc_20I/AAAAAAAABnY/YEPReQvScOs/s1600/status.network.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="318" src="http://4.bp.blogspot.com/-vneOXZHWoow/UFMe-Zc_20I/AAAAAAAABnY/YEPReQvScOs/s320/status.network.png" width="320" alt="status network" title="status network"/></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Network status indicator. <code>NMWirelessSectionTitleMenuItem</code> in red; the <code>NMDevice</code> is in blue (its title <code>PopupSwitchMenuItem</code> "Realtek RTL8188CE 802.11b/g/n Wigi Adapter" is hidden as I only have one wireless adapter; if I had more then it would display).</td></tr>
</tbody></table>
<ul>
<li><a name='network.NMNetworkMenuItem'><code>NMNetworkMenuItem</code></a>: Extends <a href="#popupMenu.PopupBaseMenuItem"><code>PopupMenu.PopupBaseMenuItem</code></a>. A menu item representing a single network (which may have many access points). Shows the network name with an icon for signal strength and whether the network is secure. Shows the strength of the strongest access point.</li>
<li><a name='network.NMWiredSectionTitleMenuItem'><code>NMWiredSectionTitleMenuItem</code></a>: Extends <a href="#popupMenu.PopupSwitchMenuItem"><code>PopupMenu.PopupSwitchMenuItem</code></a>. A menu item with an on/off toggle for the wired connection.</li>
<li><a name='network.NMWirelessSectionTitleMenuItem'><code>NMWirelessSectionTitleMenuItem</code></a>: Extends <a href="#popupMenu.PopupSwitchMenuItem"><code>PopupMenu.PopupSwitchMenuItem</code></a>. A menu item with an on/off toggle for the wifi connection (if enabled, will list the available networks as <code>NMNetworkMenuItem</code>s).</li>
<li><a name='network.NMDevice'><code>NMDevice</code></a>: A base class representing a particular network manager device (ethernet controller, wireless card, ...). Consists of one 'title' <a href="#popupMenu.PopupSwitchMenuItem"><code>PopupMenu.PopupSwitchMenuItem</code></a> that is the device name (e.g. "Realktek RTL8188CE 802.11b/g/n Wifi Adapter", "XYZ PCI Express Gigabit Ethernet Conroller") with an on/off toggle, as well as its own menu subsection under which various connections are listed (visible bluetooth devices, visible wireless networks, ...). When the toggle is switched on, it will show a status ('disconnecting...', 'authentication required', 'cable unplugged', ...) until the connection is complete, after which it just shows the 'on' toggle. The connections are sorted by strength and up to <code>NUM_VISIBLE_NETWORKS</code> (default 5) are shown with a 'More...' item. Has functions to handle checking, adding, removing, and activating particular connections. NOTE: The difference between the <code>NMDevice</code> and (say) <code>NMWiredSectionTitleMenuItem</code>: the title menu item ("Wired") is always visible. If you have <em>multiple</em> <em>wired</em> ethernet controllers (ports) for some reason, then there is on <code>NMDevice</code> for <em>each</em>, and <em>both</em> appear under the "Wired" section. Then each will have an individual toggle (being the <code>PopupSwitchMenuItem</code>) allowing you to control the two wired connections separately. If you only have <em>one</em> device for a given section, then the switch item for the Device is hidden (but the subsection with available connections is still shown).</li>
<li><a name='network.NMDeviceWired'><code>NMDeviceWired</code></a>: Extends <code>NMDevice</code> for wired connections (will only display the on/off switch if you only have one wired connection port - if you have more it will have a menu section with them all).</li>
<li><a name='network.NMDeviceModem'><code>NMDeviceModem</code></a>: Extends <code>NMDevice</code> for a modem (dial up/broadband). Items for individual connections have text desribing the connection with an icon for signal strength.</li>
<li><a name='network.NMDeviceBluetooth'><code>NMDeviceBluetooth</code></a>: Extends <code>NMDevice</code> for bluetooth. (NOTE: wouldn't this double up with the <a href="#bluetooth.Indicator">Bluetooth indicator</a>?)</li>
<li><a name='network.NMDeviceVPN'><code>NMDeviceVPN</code></a>: Extends <code>NMDevice</code> for VPN connections.</li>
<li><a name='network.NMDeviceWireless'><code>NMDeviceWireless</code></a>: Extends <code>NMDevice</code> for wireless connections. The items in the submenu (one per visible network) are <code>NMNetworkMenuItem</code>s.</li>
<li><a name='network.NMApplet'><code>NMApplet</code></a>: The <a href="#panelMenu.SystemStatusButton"><code>PanelMenu.SystemStatusButton</code></a> defining the network connections indicator. Contains the various <code>NMDevice</code> subclasses (menu subsections) for each connection device you have.</li>
<li><a name='network.NMMessageTraySource'><code>NMMessageTraySource</code></a>: A <a href="#messageTray.Source"><code>MessageTray.Source</code></a> for network manager notifications.</li>
</ul>
<p>Also contains convenience functions for comparing MAC addresses and SSIDs, sorting access points by strength and converting signal strengths to a category ('strong', 'good', 'ok', 'weak'), and a constant <code>NUM_VISIBLE_NETWORKS</code> that determines the number of networks to show on the list (wifi) before adding a 'More...' item (default 5).</p>
<h3><a name='power'><code>power.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-7EmFg__wJJ4/UFLK81ZyIII/AAAAAAAABjA/fJ-ojKFiG1k/s1600/status.power.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-7EmFg__wJJ4/UFLK81ZyIII/AAAAAAAABjA/fJ-ojKFiG1k/s1600/status.power.png" alt="status power" title="status power" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Power status icon</td></tr>
</tbody></table>
<ul>
<li><a name='power.Indicator'><code>Indicator</code></a>: The <a href="#panelMenu.SystemStatusButton"><code>PanelMenu.SystemStatusButton</code></a> defining the power indicator. Listens over DBus with object '/org/gnome/SettingsDaemon/Power' on bus 'org.gnome.SettingsDaemon' with interface 'org.gnome.SettingsDaemon.Power' for changes in your power devices (like when you switch from battery to plugged in). Displays an appropriate icon for your current power state as well as calculating estimated battery life, etc.</li>
<li><a name='power.DeviceItem'><code>DeviceItem</code></a>: A <a href="#popupMenu.PopupBaseMenuItem"><code>PopupMenu.PopupBaseMenuItem</code></a> with a label for the device type (e.g. 'AC adapter', 'Laptop battery') with a matching icon and (if appropriate) a status text (like '94%' for a battery).</li>
</ul>
<h3><a name='volume'><code>volume.js</code></a></h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-lZRuRxQxhJ8/UFLK9raiIFI/AAAAAAAABjI/oTVkecGnpQI/s1600/status.volume.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-lZRuRxQxhJ8/UFLK9raiIFI/AAAAAAAABjI/oTVkecGnpQI/s1600/status.volume.png" alt="status volume" title="status volume" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Volume status icon</td></tr>
</tbody></table>
<ul>
<li><a name='volume.Indicator'><code>Indicator</code></a>: The <a href="#panelMenu.SystemStatusButton"><code>PanelMenu.SystemStatusButton</code></a> defining the volume indicator. Contains a <a href="#popupMenu.PopupSliderMenuItem"><code>PopupSliderMenuItem</code></a> for the volume of each of your sound devices (microphone, speakers, ...), and adjusts its icon according to the volume.</li>
</ul>
<hr />
<h1><a name='imports.misc'>Miscellaneous files in <code>/usr/share/gnome-shell/js/misc</code>: 'imports.misc'</a></h1>
<ul>
<li><a href="#config"><code>config.js</code></a>: a collection of constants that could come in handy (version numbers).</li>
<li><a href="#docInfo"><code>docInfo.js</code></a> (<strong>GNOME 3.2 only</strong>): wrappers around <code>Shell.DocSystem</code> that are used in <a href="#docDisplay"><code>docDisplay.js</code></a> to allow documents to be searched for in the Overview. GNOME 3.4 doesn't have the doc search capability.</li>
<li><a href="#extensionUtils"><code>extensionUtils.js</code></a> (<strong>GNOME 3.4 only</strong>): set of utilities to do with extensions - some of the stuff in <a href="#extensionSystem"><code>extensionSystem.js</code></a> in GNOME 3.2 has been moved here, plus some extras.</li>
<li><a href="#fileUtils"><code>fileUtils.js</code></a>: set of helpful functions for Gio files.</li>
<li><a href="#format"><code>format.js</code></a>: an implementation of <code>sprintf</code>.</li>
<li><a href="#gnomeSession"><code>gnomeSession.js</code></a>: DBus stuff to do with 'org.gnome.SessionManager'.</li>
<li><a href="#history"><code>history.js</code></a>: A class that saves history to a gsettings key (like looking glass command history).</li>
<li><a href="#jsParse"><code>jsParse.js</code></a> (<strong>GNOME 3.4 only</strong>): A set of functions for parsing strings of javascript code, used in the autocomplete function for the looking glass.</li>
<li><a href="#modemManager"><code>modemManager.js</code></a>: DBus stuff to do with mobile broadband.</li>
<li><a href="#params"><code>params.js</code></a>: a helpful function for parsing input parameters against default parameters.</li>
<li><a href="#screenSaver"><code>screenSaver.js</code></a>: DBus stuff to do with 'org.gnome.ScreenSaver'.</li>
<li><a href="#util"><code>util.js</code></a>: a set of useful functions, mainly to do with spawning external processes in the background.</li>
</ul>
<hr />
<h2>Overview of classes in each file (<code>imports.ui</code>).</h2>
<h3><a name='config'><code>config.js</code></a></h3>
<p>Contains the constants:</p>
<ul>
<li><code>PACKAGE_NAME</code>: 'gnome-shell' (non-localized name of the package).</li>
<li><code>PACKAGE_VERSION</code>: your gnome-shell version, a string (e.g. '3.2.2.1').</li>
<li><code>GJS_VERSION</code>: your gjs version, a string (e.g. '1.30.0').</li>
<li><code>HAVE_BLUETOOTH</code>: whether <code>gnome-bluetooth</code> is available (1 or 0).</li>
<li><code>SHELL_SYSTEM_CA_FILE</code>: the system TLS CA list (e.g. '/etc/pki/tls/certs/ca-bundle.crt').</li>
</ul>
<p>The following constants are in GNOME 3.4 only (or 3.4+):</p>
<ul>
<li><code>GETTEXT_PACKAGE</code>: 'gnome-shell'. GNOME-shell's gettext package name.</li>
<li><code>LOCALEDIR</code>: the locale directory (<code>/usr/share/locale</code>).</li>
<li><code>LIBEXECDIR</code>: <code>/usr/lib/gnome-shell</code> (maybe <code>lib64</code> for 64 bit systems).</li>
<li><code>SYSCONFDIR</code>: <code>/etc</code>.</li>
</ul>
<h3><a name='docInfo'><code>docInfo.js</code></a> (GNOME 3.2 only)</h3>
<ul>
<li><a name='docInfo.DocInfo'><code>DocInfo</code></a>: represents the info for a single document (name, timestamp, uri, mime type) along with an icon, a <code>launch</code> function to open it, and a <code>matchTerms</code> function telling you whether the given search terms match that document.</li>
<li><a name='docInfo.DocManager'><code>DocManager</code></a>: Wraps <code>Shell.DocSystem</code>, creating <code>DocInfo</code>s for documents and returning search results against search terms.</li>
</ul>
<h3><a name='extensionUtils'><code>extensionUtils.js</code></a> (GNOME 3.4 only)</h3>
<p>Contains the <code>extensions</code> object (maps UUID to extension object, described in <code>createExtensionObject</code>) that previously was in <a href="#extensionSystem"><code>extensionSystem.js</code></a> on GNOME 3.2.</p>
<p>Helpful functions:</p>
<ul>
<li><code>getCurrentExtension</code>: call it from your extension file to get the current extension object (<code>imports.misc.extensionUtils.getCurrentExtension()</code>).</li>
<li><code>versionCheck</code>: checks if the version in <code>metadata.json</code> is compatible with the current shell version.</li>
<li><code>isOutOfDate</code>: checks if an extension is out of date (by UUID).</li>
<li><code>createExtensionObject</code>: creates an object representing an extension (used in <a href="#extensionSystem"><code>extensionSystem.js</code></a>). The object has members:
<ul>
<li><code>metadata</code>: the metadata for the extension (<code>JSON.parse</code> of the <code>metadata.json</code> file).</li>
<li><code>uuid</code>: the extension's UUID ('my-extension@some.domain.name').</li>
<li><code>type</code>: the type of extension.</li>
<li><code>dir</code>: the extension's directory (a <code>Gio</code> object).</li>
<li><code>path</code>: the extension's directory as a string.</li>
</ul></li>
<li>other functions to do with searching for extensions and loading them.</li>
</ul>
<h3><a name='fileUtils'><code>fileUtils.js</code></a></h3>
<p>Functions:</p>
<ul>
<li><code>listDirAsync</code>: give it a directory (create with e.g. <code>Gio.file_new_for_path</code>) and a callback, and it will apply the callback to the files it finds. Convenience wrapper around <a href="http://developer.gnome.org/gio/stable/GFile.html#g-file-enumerate-children-async"><code>Gio.File.enumerate_children_async</code></a>.</li>
<li><code>deleteGFile</code>: deletes a (Gio) file object ("work around 'delete' being a keyword in JS" -- just calls <code>file.delete(null)</code>).</li>
<li><code>recursivelyDeleteDir</code>: recursively deletes a directory.</li>
</ul>
<h3><a name='format'><code>format.js</code></a></h3>
<p>This file defines the <code>format</code> function (that gets assigned to <code>String.prototype.format</code> in <a href="#environment"><code>environment.js</code></a>) - it's basically an implementation of <code>sprintf</code>.</p>
<h3><a name='gnomeSession'><code>gnomeSession.js</code></a></h3>
<p><strong>Remember!</strong> I'm really confused about the words "proxy", "server", "interface" etc when it comes to DBus, so I've probably used the wrong terminology below.</p>
<ul>
<li><a name='gnomeSession.Presence'><code>Presence</code></a>: DBus proxy (?) for DBus object '/org/gnome/SessionManager/Presence', path 'org.gnome.SessionManager', interface 'org.gnome.SessionManager.Presence') - for getting and setting a status.</li>
<li><a name='gnomeSession.Inhibitor'><code>Inhibitor</code></a>: DBus proxy (?) for DBus path 'org.gnome.SessionManager', interface 'org.gnome.SessionManager.Inhibitor'.</li>
<li><a name='gnomeSession.SessionManager'><code>SessionManager</code></a>: DBus proxy (?) for path 'org.gnome.SessionManager', object '/org/gnome/Sessionmanager', interface 'org.gnome.SessionManager'.</li>
</ul>
<h3><a name='history'><code>history.js</code></a></h3>
<ul>
<li><a name='history.HistoryManager'><code>HistoryManager</code></a>: An object that remembers text up to 512 items (<code>DEFAULT_LIMIT</code>) and optionally saves them into a gsettings key. For example, the looking glass command history is saved in gsettings key 'org.gnome.shell.looking-glass-history', and the run prompt (Alt+F2) history is saved in 'org.gnome.shell.command-history'.</li>
</ul>
<h3><a name='jsParse'><code>jsParse.js</code></a> (GNOME 3.4 only)</h3>
<p>This is a set of functions doing some basic parsing of javascript code in order to provide sensible autocompletions.</p>
<p>The main function you will probably want to call from external modules (according to the source) is <code>getCompletions(text, commandHeader, globalCompletionList)</code>. There are a whole bunch of other helper functions in there too. See the source for full documentation.</p>
<h3><a name='modemManager'><code>modemManager.js</code></a></h3>
<p><strong>Remember!</strong> I'm really confused about the words "proxy", "server", "interface" etc when it comes to DBus, so I've probably used the wrong terminology below.</p>
<ul>
<li><a name='modemManager.ModemGsm'><code>ModemGsm</code></a>: Class for interacting with DBus interface 'org.freedesktop.ModemManager.Modem.Gsm.Network' (mobile internet).</li>
<li><a name='modemManager.ModemCdma'><code>ModemCdma</code></a>: Class for interacting with DBus interface 'org.freedesktop.ModemManager.Modem.Cdma' (mobile internet).</li>
</ul>
<h3><a name='params'><code>params.js</code></a></h3>
<p>Contains a handy function <code>parse</code> that parses user-provided parameters against default parameters (filling in with defaults if not supplied), and throwing an error if unrecognised parameters are given (if unrecognised parameters are not allowed). Used throughout the <code>js/ui/*.js</code> code.</p>
<h3><a name='screenSaver'><code>screenSaver.js</code></a></h3>
<ul>
<li><a name='screenSaver.ScreenSaverProxy'><code>ScreenSaverProxy</code></a>: A proxy for DBus object '/org/gnome/ScreenSaver' on bus 'org.gnome.ScreenSaver'.</li>
</ul>
<h3><a name='util'><code>util.js</code></a></h3>
<p>Handful of utility functions (more documentation in the source):</p>
<ul>
<li><code>findUrls</code>: searches input string for URLs.</li>
<li><code>spawn</code>: spawns a process specified by the argument in array form (e.g. <code>['ls', '-al', '$HOME']</code>), handling errors by popping up a notification in the message tray.</li>
<li><code>spawnCommandLine</code>: spawns a process specified by a string (e.g. <code>ls -al $HOME</code>), handling errors by popping up a notification in the message tray (using <code>Main.notifyError</code>(#main.notifyError)).</li>
<li><code>killall</code>: kills the process specified by the given name.</li>
<li><code>fixupPCIDescription</code>: converts the description of a device to something a little shorter. Used in <a href="#network"><code>status/network.js</code></a> for the network indicator applet.</li>
</ul>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com17tag:blogger.com,1999:blog-7039473604287682752.post-85698799990511775662012-09-06T19:28:00.001-07:002013-05-29T05:19:36.726-07:00Developing GNOME shell extensions: finding documentation part 2
<p>Part 2 of finding documentation for developing gnome shell extensions; <a href="http://mathematicalcoffee.blogspot.com.au/2012/09/developing-gnome-shell-extensions.html">Part 1 is here</a>.</p>
<p>You can't always find documentation online. For example, Meta (<code>imports.gi.Meta</code>) doesn't have documentation online.
Or perhaps you just want more details on the specific GNOME Javascript implementation of the C functions. Or there's a function listed on the page that you can't seem to find on the GNOME Javascript side.</p>
<p>Then, I recommend you look at the corresponding <code>.gir</code> file for your library, for example <code>Meta-3.0.gir</code>.</p>
<p>A <code>gir</code> file defines the binding between the C functions and the Javascript functions. They're used to define <em>bindings</em> between languages.
If you look inside a <code>gir</code> file, you'll see it just looks like an XML file.</p>
<p>In this post I'll cover a few things:</p>
<ul>
<li><a href="#getting-information">Getting information from the raw <code>gir</code> file</a></li>
<li><a href="#locating">Where to find <code>gir</code> files, and converting <code>typelib</code> to <code>gir</code></a></li>
<li><a href="#html-gen">Compiling the <code>gir</code> file into HTML documentation.</a></li>
<li><a href="#summary">Summary</a></li>
</ul>
<h2><a name="getting-information">Getting information from the <code>gir</code> file</a></h2>
<h3>Looking for signals in a <code>gir</code> file</h3>
<p>To quickly look for signals in a <code>gir</code> file, you can just <code>grep</code> for <code>glib:signal</code> like so:</p>
<pre><code class="language-bash">grep 'glib:signal' Meta-3.0.gir
# will give me a list of signals in the Meta library.
# ... (lots of signals)
<glib:signal name="workspace-changed" when="last">
</glib:signal>
# ... (lots more signals)
</code></pre>
<p>In the example above I wanted to see what signals the <code>Meta</code> library provided and in particular was after the <code>workspace-changed</code> signal.
You can then go into the gir file and see that the <code>workspace-changed</code> signal belongs to the <code>Meta.Screen</code> class, so if I want to monitor workspace changes I have to do:</p>
<pre><code class="language-javascript">global.screen.connect('workspace-changed', myFunction);
</code></pre>
<p>(This is an example of a useful signal that is not used anywhere in the gnome-shell javascript files, so I wouldn't have known about it otherwise). Note - many of the <code>global.*</code> objects (<code>global.screen</code>, <code>global.display</code>, ...) are Meta objects.</p>
<h3>Methods not available on the javascript side</h3>
<p>Often you'll find that a function that is documented and available on the C side, but you can't seem to find it on the javascript side.</p>
<p>For example, suppose I want to get the current Metacity theme. I see that there's a function <code>meta_theme_get_current</code> that will do what I want, but when I try <code>Meta.Theme.get_current()</code>, I found out that <code>.get_current()</code> is not a function!</p>
<p>Looking in the <code>gir</code> file:</p>
<pre><code class="language-markup"><record name="Theme" c:type="MetaTheme" disguised="1">
.... (more functions in between) ...
<function name="get_current"
c:identifier="meta_theme_get_current"
introspectable="0">
<return-value>
<type name="Theme" c:type="MetaTheme*"/>
</return-value>
</function>
</code></pre>
<p>See the <code>introspectable="0"</code>? that means you can't get it from the javascript side. Too bad (time to pester the mailing list/find another way around it).</p>
<h2><a name="locating">Where to find <code>gir</code> files/Converting <code>typelib</code> files to <code>gir</code></a></h2>
<p>Great, so we now know about looking into <code>gir</code> files for more information. But where do we find these <code>gir</code> files?</p>
<p>Most of them live in <code>/usr/share/gir-1.0</code>. Often they will not appear there until you install the relevant dev or gir package (for example if you want <code>Wnck-[version].gir</code> on Ubuntu you need to install the <code>gir[girversion]-wnck-[version]</code> package (e.g. <code>gir1.0-wnck-1.0</code>), of the <code>libwnck-devel</code> package on Fedora).</p>
<p>Chances are you don't have many gir files in <code>/usr/share/gir-1.0</code>. Don't despair!</p>
<p>A <code>gir</code> file is really a human-readable version of a <code>typelib</code> file (a bit like what <code>gschema.xml</code> is to <code>gschema.compiled</code>).
Have a look in <code>/usr/lib/girepository-1.0</code>. You will see a <em>huge</em> number of <code>.typelib</code> files. (Maybe <code>/usr/lib</code><strong>64</strong><code>/girepository-1.0</code> for 64bit machines).</p>
<p>Everything in here can be imported in GJS through <code>imports.gi.[name]</code>.</p>
<p>Some of them are not there (e.g. Meta, Shell, St) because they are considered "private". This means if you run <code>gjs</code> on the command line, you will not be able to find them. However, you can find their typelib files here:</p>
<ul>
<li><code>/usr/lib/gnome-shell</code> (Shell, St)</li>
<li><code>/usr/lib/mutter</code> (Meta)</li>
</ul>
<p>So, how do we convert <code>typelib</code> files to human-readable <code>gir</code> files?</p>
<p>Use the <code>g-ir-*</code> tools. These are a collection of tools for generating <code>gir</code> or <code>typelib</code> files from source and converting between the two.
We will be using <code>g-ir-generate</code>.</p>
<p>If you do not have these tools installed already (I think from GNOME 3.4+ on they come packaged with gnome-shell), you can install them in the <code>gobject-introspection</code> package (Ubuntu), or on Fedora 16 they were in <code>gobject-introspection-devel</code>. Or you could just <a href="https://github.com/magcius/gobject-introspection">get the source from github</a>.</p>
<p>To create a <code>gir</code> from a typelib (for example Meta):</p>
<pre><code class="language-bash">g-ir-generate /usr/lib/mutter/Meta-3.0.typelib > Meta-3.0.gir
</code></pre>
<p>And voila! A <code>gir</code> file for Meta!</p>
<p>Sometimes <code>g-ir-generate</code> will complain about not being able to find various other typelibs, for example if you try to generate <code>Shell-0.1.gir</code> from the typelib:</p>
<pre><code class="language-bash">[mathematicalcoffee ~]$ g-ir-generate /usr/lib/gnome-shell/Shell-0.1.typelib
** (g-ir-generate:9599): ERROR **: failed to load typelib: Typelib file for namespace 'St', version '1.0' not found
Trace/breakpoint trap (core dumped)
</code></pre>
<p>In this case it's trying to find <code>St-1.0.typelib</code>, which is one of those "private" ones in <code>/usr/lib/gnome-shell</code>, so you can include it using the <code>--includedir</code> argument (it also needs to find <code>Meta-3.0.typelib</code> in <code>/usr/lib/mutter</code>; I think by default just <code>/usr/lib/girepository-1.0</code> is included):</p>
<pre><code class="language-bash">[mathematicalcoffee ~]$ g-ir-generate --includedir=/usr/lib/gnome-shell \
--includedir=/usr/lib/mutter /usr/lib/gnome-shell/Shell-0.1.typelib > Shell-0.1.gir
</code></pre>
<p>And that works.</p>
<h2><a name="html-gen">Generating HTML documentation from <code>gir</code> files</a></h2>
<p>It's easier to use some form of documentation than wading through the <code>gir</code> files all the time.</p>
<p>Here is how to generate HTML documentation from the <code>gir</code> files (you use <code>g-ir-doc-tool</code>):</p>
<pre><code class="language-bash">mkdir mutter-docs
g-ir-doc-tool Meta-3.0.gir -o mutter-docs
</code></pre>
<p>Then turn the output (yelp files) into HTML (or you could just use the yelp files if you prefer):</p>
<pre><code class="language-bash">yelp-build html mutter-docs
</code></pre>
<p>Then load index.html in a browser and you have some basic browsable documentation, complete with a list of signals (so if you
click on the Meta.Screen page it has a list of signals you can connect to, although it is a bit sparse on explanation).</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-fHYW36Qopkg/UElb2PTp50I/AAAAAAAABaU/8LhMbaJ6Ceg/s1600/meta-documentation.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="320" width="319" src="http://1.bp.blogspot.com/-fHYW36Qopkg/UElb2PTp50I/AAAAAAAABaU/8LhMbaJ6Ceg/s320/meta-documentation.png" /></a></div>
<p>Notes:</p>
<ul>
<li>If you can find the documentation online, use that instead. The generated documentation is often quite sparse/no explanations.</li>
<li>Sometimes <code>g-ir-doc-tool</code> complains about repository versions being unsupported. You can go into the <code>gir</code> file and modify the line <code><repository version="1.0"</code> to <code><repository version="1.2"</code> and it will then generate the documentation (not sure if anything is affected by that)</li>
<li>Sometimes <code>g-ir-doc-tool</code> complains about not being able to find the <code>gir</code> files of other libraries it depends on. You have to generate them and make sure they're in <code>/usr/share/gir-1.0</code> (it doesn't seem to support an <code>--includedir</code> argument like <code>g-ir-generate</code> does).</li>
</ul>
<h1><a name="summary">Summary</a></h1>
<p>When looking for documentation:</p>
<ul>
<li>First look on <a href="http://developer.gnome.org/">developer.gnome.org</a></li>
<li><p>Otherwise generate some documentation from the <code>gir</code> file (<code>/usr/share/gir-1.0</code>, <code>/usr/lib/mutter</code>, <code>/usr/lib/gnome-shell</code>):</p>
<pre><code class="language-bash">g-ir-doc-tool /path/to/gir -o /path/to/output/directory
yelp-build html /path/to/output/directory
</code></pre></li>
<li><p>If you can't find the <code>gir</code> file, find the <code>typelib</code> file and convert it to <code>gir</code> first (<code>/usr/lib/girepository-1.0</code>):</p>
<pre><code class="language-bash">g-ir-generate /path/to/typelib > /path/to/output/filename # use --includedir=/path/to/typelib/folder if need be
</code></pre></li>
</ul>
<p>Hope that helps! Feedback welcome.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com6tag:blogger.com,1999:blog-7039473604287682752.post-10506844289169350752012-09-06T19:16:00.002-07:002012-09-06T19:29:31.283-07:00Developing GNOME shell extensions: finding documentation part 1<p>So, you've recently started developing gnome shell extensions.</p>
<p>You ask a question on the mailing list about wanting to achieve goal X and are told "simple - connect to signal Y and that's exactly what you want". And it <em>is</em> exactly what you want. Only when you look through the gnome-shell javascript files to see examples of how to use the signal, there is <em>nothing</em> in the source that connects to it.</p>
<p>So you think to yourself, "how could I even have <em>known</em> there was a signal/class/method that did X if there are no examples of it being used? Is there a magical list of signals/classes/methods that I don't know about? Will I be stuck forever asking questions on the mailing list hoping that some person is aware of the magical hidden/undocumented signal/method/class that I'm interested in??!!".</p>
<p>I went through the same pain when I first started developing gnome shell extensions.
I felt I was stuck asking simple questions that I could easily work out on my own, if only I could find some documentation, and that was hindering me from making progress on the extension and asking the more complex questions.</p>
<p>Well, documentation <em>does</em> exist, although it is sometimes hard to find.
I thought I'd share what I've learned so far about finding and generating documentation for classes I'm interested in.</p>
<p>This is part 1; part 2 is <a href="http://mathematicalcoffee.blogspot.com.au/2012/09/developing-gnome-shell-extensions_6.html">here</a>.</p>
<h2>Documentation on developer.gnome.org</h2>
<p>The absolute best documentation I've find is online on the <a href="http://developer.gnome.org/">gnome developer's website</a>.
Documentation for most of the <code>imports.gi.XXXX</code> libraries lives here.
You can search for the library you're interested in from that site, or try <code>developer.gnome.org/XXXX/</code> for documentation for library XXXX.
For example:</p>
<ul>
<li><a href="http://developer.gnome.org/st/stable/">imports.gi.St</a></li>
<li><a href="http://developer.gnome.org/shell/unstable/">imports.gi.Shell</a> (I found that one hard to find - while most of the documentation lives on developer.gnome.org/xxx/stable, this one lives on developer.gnome.org/xxx/<strong>unstable</strong>)</li>
<li><a href="http://developer.gnome.org/clutter/stable/">imports.gi.Clutter</a></li>
</ul>
<p>These pages have lists of available classes you can use, and the page for each class will have a list of methods, signals, and properties of each object.</p>
<p>A quick note - a property with a hyphen (<code>-</code>) in it will be converted to an underscore on the javascript side.
For example a property <code>schema-id</code> will turn into <code>schema_id</code>.</p>
<p>Signals retain their hyphens, so a signal <code>workspace-changed</code> remains <code>workspace-changed</code>.</p>
<p>The function names are all in C syntax. To convert from that to the javascript syntax you just remove the name prefix and omit the <code>self</code> argument.</p>
<p>For example, <code>clutter_actor_allocate(self, box, flags)</code> turns into <code>actor.allocate(box, flags)</code> on the javascript side, where <code>actor</code> is a <code>Clutter.Actor</code> instance.</p>
<p>There is a <em>huge</em> amount of documentation on the <a href="http://developer.gnome.org/">developer.gnome.org</a> site.
You should be able to find most of what you want there.</p>
<p>However sometimes you can't (for example <code>imports.gi.Meta</code>, and that's what my <a href="http://mathematicalcoffee.blogspot.com.au/2012/09/developing-gnome-shell-extensions_6.html">next blog post</a> will be about.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com1tag:blogger.com,1999:blog-7039473604287682752.post-19280130520940882472012-09-06T19:13:00.000-07:002013-05-29T05:21:32.041-07:00Gnome shell extensions: Getting started writing your own
<p>Getting started on GNOME shell extensions.</p>
<p>You've seen the great extensions on <a href="https://extensions.gnome.org/">extensions.gnome.org</a> (I call this e.g.o) and now want to have a fiddle and start writing your own.</p>
<p>Where to start?
I can't answer that completely, but here's a few things that might help (I am currently using GNOME 3.4 and GNOME 3.2 for writing extensions; some of this might get outdated with newer versions). It's not so much a tutorial as a list of useful things to get you started.</p>
<h2>Get acquainted</h2>
<p>First things first. Extensions are written in GNOME javascript, which they say is based off Spidermonkey (Mozilla's flavour of Javascript).
I never learned normal javascript, so I am not in a position to comment on similarities/differences.</p>
<p><a href="https://live.gnome.org/GnomeShell/Extensions">A nice introductory page</a> is on the GNOME website.
Have a look, but don't get too scared yet and don't start writing yet.
I think the main points to get out of this are the anatomy of an extension.</p>
<p>An extension <strong>must</strong> have the files <code>extension.js</code> and <code>metadata.json</code>.</p>
<p>The <code>metadata.json</code> file contains information about your extension - its name, unique identifier, homepage, description, what gnome-shell versions it is compatible with, etc. Have a look at the example one on the website.</p>
<p>The <code>extension.js</code> file is the GNOME-javascript file that GNOME-shell uses to run your extension. It <strong>MUST</strong> have at least three functions in it:</p>
<ul>
<li><code>init(metadata)</code>: called to initialise your extension. The <code>metadata</code> argument is an object containing the metadata from your <code>metadata.json</code> file plus a few extras (for example, <code>metadata.path</code> contains the path to your extension).</li>
<li><code>enable</code>: called when the user actually <em>enables</em> your extension (for example when they toggle the switch on e.g.o). This is where you do whatever you want your extension to do.</li>
<li><code>disable</code>: called when the user <em>disables</em> your extension. It should stop whatever your extension does and restore the system to a state such that it looks like your extension was never there.</li>
</ul>
<p>There is also an optional file <code>stylesheet.css</code> which you can use to style things in your extension, and you can of course have other files (like images, extra javascript files, ...).</p>
<p>I recommend you <strong>not start writing your extension yet</strong>! Instead...</p>
<h2>Stand on the shoulders of giants</h2>
<p>OK, well we who have submitted extensions to e.g.o are not giants ;), but before you even start writing any code, I recommend you look at the source of existing extensions first to get a feel for them.</p>
<p>Whenever you install an extension, its files get put into <code>$HOME/.local/share/gnome-shell/extensions</code>.</p>
<p>If you look in the directories here you will see the <code>extension.js</code> and <code>metadata.json</code> files I was talking about (plus any others that extension uses).</p>
<p>To start off with, try a simple extension. Or if you have an idea you want to implement in an extension, try looking at similar extensions. For example, if you want to do something with the Alt Tab popup, look at the various Alt Tab extensions out there.</p>
<p>Don't worry if you don't understand the details of the code in the file; a lot of the extensions on e.g.o will be a bit more complex than your first extension.
If you do</p>
<pre><code class="language-bash">gnome-shell-extension-tool --create-extension
</code></pre>
<p>this tool will walk you through creating your own extension. The resulting files define a simple extension that creates a button in your status area (right hand side of the top panel), that will say "Hello, World!" when you click it.</p>
<p>This is a <em>great</em> example to look through for the first time. I go through explaining it; there is a good explanation <a href="http://blogs.openshine.com/cgtapia/2011/05/16/writing-extensions-to-the-new-gnome-shell/">here</a>.</p>
<h2>GNOME-shell's own javascript code</h2>
<p>I recommend looking at the javascript files for gnome-shell.
You can get them in <code>/usr/share/gnome-shell/js</code>.
These are the files gnome-shell uses to define parts of its interface - for example, the alt-tab code is in <code>/usr/share/gnome-shell/js/ui/altTab.js</code>.
I recommend looking in <code>/usr/share/gnome-shell/js/ui</code> - most classes you will want to use are in here.</p>
<p>I'll write another blog post on that at a later date.</p>
<h2>Further down the rabbit hole...</h2>
<p>Now you have to actually write your extension.</p>
<p>Well, there's not too much I can say here. Just jump in and give it a go! I do recommend tweaking an existing, simple/similar extension to what you want to do as opposed to writing your own for your first extension.</p>
<p>The main point I wanted to make is that you can learn a lot by looking at existing extensions, and it is often easier to <em>tweak</em> an <em>existing</em> extension to do what you want rather than write your own from scratch.</p>
<p>Quick list of useful things while developing extensions:</p>
<ul>
<li>to install an extension, add its UUID to dconf key <code>org.gnome.shell.enabled-extensions</code> and make sure it is in <code>~/.local/share/gnome-shell/extensions</code></li>
<li>every time you make a change to the javascript of an extension (e.g. <code>extension.js</code>), you have to restart gnome-shell for the change to take effect. Press <code>Alt+F2</code> and type in 'r'.</li>
<li>you can access an interacitve gnome-javascript console by either using the Looking Glass (<code>Alt+F2</code>, type <code>lg</code>) or by typing <code>gjs</code> or <code>gjs-console</code> on the command-line. The Looking Glass will let you access more libraries (like the Metacity or GNOME-shell ones) than the console and also has a 'picker' widget that lets you select any widget on the screen to query its properties etc.</li>
<li><p>If your extension doesn't load, you can look in the looking glass 'Errors' tab. It might say something like</p>
<pre><code>Extension myextension@abcd.efgh.com had error: [error message]
</code></pre></li>
<li><p>It is invaluable to run gnome-shell from a terminal to see extra error messages:</p>
<pre class="language-bash"><code>gnome-shell --replace
</code></pre>
<p>from a terminal will start gnome-shell and output error messages to this terminal</p></li>
<li>If an extension doesn't load, this is due to errors in the <code>init()</code> or <code>enable()</code> functions. The error will probably appear in the looking glass 'Errors' tab and not in the terminal.</li>
<li>If an extension load but something breaks while you're using it, the error will probably appear in the terminal rather than the 'Errors' tab.</li>
<li><p>To use classes you found in <code>/usr/share/gnome-shell/js/ui</code>, import the javascript file with <code>const FileName = imports.ui.fileName;</code>. For example, if I want to use classes in <code>popupMenu.js</code>:</p>
<pre class="language-javascript"><code>const PopupMenu = imports.ui.popupMenu;
// now I can use PopupMenu.PopupMenuItem, etc
</code></pre></li>
<li><p>To use external libraries (like <code>Meta</code>, <code>Shell</code>, ...), use <code>const Meta = imports.gi.Meta;</code>. To see what external libraries you can use, have a look in <code>/usr/lib/girepository-1.0</code>; these files all define javascript bindings to the C libraries. Documentation exists for these online, mainly from <a href="http://developer.gnome.org">developer.gnome.org</a>; see my <a href="http://mathematicalcoffee.blogspot.com.au/2012/09/developing-gnome-shell-extensions.html">other blog post</a> for further details.</p></li>
</ul>
<p>And finally but most important...</p>
<h2>Ask for help!</h2>
<p>Feel free to ask for help in what you're doing! It's really hard when you first start writing extensions, because there isn't much in the way of documentation/tutorials to help out. That's why I think it's easiest to look at heaps of other people's extension code before starting your own and even just tweak their code to achieve your purposes when you first start.</p>
<p>Places you can ask for help (more info <a href="https://live.gnome.org/GnomeShell">here</a>):</p>
<ul>
<li>IRC: <a href="irc://irc.gnome.org/#gnome-shell">irc.gnome.org:#gnome-shell</a> - plenty of people willing to answer questions</li>
<li><a href="https://mail.gnome.org/mailman/listinfo/gnome-shell-list">GNOME shell mailing list</a> - perfectly appropriate to ask extension questions here.</li>
</ul>
<p>Great links:</p>
<ul>
<li><a href="http://blogs.openshine.com/cgtapia/2011/05/16/writing-extensions-to-the-new-gnome-shell/">Writing extensions for the new Gnome Shell</a> - a great introduction to writing extensions (includes explanation of the Hello World extension and more helpful links)</li>
<li><a href="https://live.gnome.org/GnomeShell/Extensions/StepByStepTutorial">Step by step tutorial to create extensions</a> on the gnome website. Only partially complete, but there's a lot of stuff there (GNOME 3.4+)</li>
<li><a href="http://blog.mecheye.net/2012/02/requirements-and-tips-for-getting-your-gnome-shell-extension-approved/">Tips for getting extensions approved</a>: for when you eventually get to the point of submitting your extension on e.g.o</li>
<li><a href="https://live.gnome.org/GnomeShell/StyleGuide">GNOME shell style guide</a>: if you're interested (GJS style guide).</li>
<li><a href="http://blog.fpmurphy.com/2011/06/patching-a-gnome-shell-theme.html">Finnibar Murphy's walkthough on creating an extension</a> NOTE: this is a great walkthrough but it is for GNOME 3.0 and those extensions are incompatible with 3.2+ (3.0 just required a single <code>main</code> function instead of <code>init</code>, <code>enable</code> and <code>disable</code>). Walkthrough is still good though.</li>
<li><a href="http://blog.mecheye.net/2012/02/more-extension-api-breaks/">Set of tips for GNOME 3.4</a> from the gnome-shell people - in particular, how to do multifile extensions (although the syntax they provide is GNOME 3.3+)</li>
<li>... others?</li>
</ul>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com8tag:blogger.com,1999:blog-7039473604287682752.post-78005028384481997122012-08-06T18:49:00.002-07:002012-08-06T18:49:33.408-07:00XPenguins in GNOME shell!<p>Do you all remember <a href="http://xpenguins.seul.org/">XPenguins</a>?</p>
<p>It's a program that spawns a whole bunch of penguins on your desktop - they walk on top of your windows and fall off them, and moving a window over them will squash them.</p>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://cdn.bitbucket.org/mathematicalcoffee/xpenguins-gnome-shell-extension/downloads/xpenguins-screenshot.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="135" src="http://cdn.bitbucket.org/mathematicalcoffee/xpenguins-gnome-shell-extension/downloads/xpenguins-screenshot.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">XPenguins in action</td></tr>
</tbody></table>
<p>If you're on Linux, most distributions have an <code>xpenguins</code> package in their repositories for you to install.</p>
<p>However on GNOME shell, the xpenguins from the package manager doesn't work. This is not a fault of XPenguins, but rather that XPenguins picks the wrong window to draw the penguins onto. (XPenguins will draw on the Nautilus 'desktop' window which GNOME shell covers up by default).</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;">
<embed allowfullscreen="true" height="400" src="http://cdn.bitbucket.org/mathematicalcoffee/xpenguins-gnome-shell-extension/downloads/XPenguins_demo.webm" width="540" style="margin-left: auto; margin-right: auto;"></embed></td></tr>
<tr><td class="tr-caption" style="text-align: center;">XPenguins GNOME shell extension in action.</td></tr>
</tbody></table>
<p>So, I wrote an <a href="https://extensions.gnome.org/extension/405/xpenguins/">XPenguins GNOME shell extension</a> to get it working on GNOME shell. You can install it from <a href="https://extensions.gnome.org/extension/405/xpenguins/">extensions.gnome.org</a>. You can configure things like the toon speed, which toons to load (Bill, Penguins, Turtles, ...) and how many, and much more! See the video above for a preview (I'm so uber proud!).</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://cdn.bitbucket.org/mathematicalcoffee/xpenguins-gnome-shell-extension/downloads/xpenguins-menu.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="170" src="http://cdn.bitbucket.org/mathematicalcoffee/xpenguins-gnome-shell-extension/downloads/xpenguins-menu.png" width="298" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Configure XPenguins GNOME shell extension via menu.</td></tr>
</tbody></table>
<p>It uses the standard XPenguins themes (if you have any in <code>.xpenguins/themes</code> it will load them). More themes can be found from the <a href="http://xpenguins.seul.org/">(original) XPenguins home page</a> on the right under "XPenguins Themes 1.0", and also on the "User contributed software" link on that page.</p>
<p>If you want to check out the code, it lives <a href="https://bitbucket.org/mathematicalcoffee/xpenguins-gnome-shell-extension">at bitbucket</a>.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-59632991918532468572012-05-13T19:32:00.003-07:002013-05-29T05:22:36.280-07:00Automatically undecorate maximised windows in GNOME Shell<p>One feature I really liked about the Ubuntu Netbook Remix (while it lasted) was how whenever you maximised a window, it removed the title bar. The program that did this was called <a href="https://launchpad.net/maximus">Maximus</a>.</p>
<p>This was really handy for saving a bit of vertical screen real estate, especially when you had a small 10" screen.
Yes, it became harder to unmaximise a window/drag it around/resize it, but on a 10" screen you don't do that often anyway as it's really not big enough to bother with having multiple windows visible at once.</p>
<p>Anyhow, I wanted this ability in GNOME shell (undecorate maximised windows), so I wrote an extension to do this.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://cdn.bitbucket.org/mathematicalcoffee/maximus-gnome-shell-extension/downloads/maximus.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="120" src="http://cdn.bitbucket.org/mathematicalcoffee/maximus-gnome-shell-extension/downloads/maximus.png" width="250" /></a></td>
<td style="text-align: center;"><a href="http://cdn.bitbucket.org/mathematicalcoffee/maximus-gnome-shell-extension/downloads/no-maximus.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="120" src="http://cdn.bitbucket.org/mathematicalcoffee/maximus-gnome-shell-extension/downloads/no-maximus.png" width="250" /></a></td>
</tr>
<tr><td class="tr-caption" style="text-align: center;">Maximus GNOME shell extension undecorates maximised windows</td>
<td class="tr-caption" style="text-align: center;">Without Maximus: title bar consumes vertical space.</td>
</tr>
</tbody></table>
<p>Before I give the link, I'll mention that you don't actually need an extension to get this behaviour; <a href="http://www.webupd8.org/2011/05/how-to-remove-maximized-windows.html">this blog post</a> gives two ways to do it:</p>
<ol>
<li>Install Maximus: if you're lucky or have Ubuntu, you can just <code>sudo apt-get install maximus</code>. This will install the original Maximus program for you and then you're done. However if you have Fedora, Maximus is not in the package repositories. In that case you could try to <a href="https://launchpad.net/maximus">download the source</a> and build/install it yourself. This isn't as easy as simply installing a program or extension though.</li>
<li>Edit your window theme: you can edit the theme GNOME-shell uses to decorate your windows to artificially remove the title bar from maximised windows. See <a href="http://www.webupd8.org/2011/05/how-to-remove-maximized-windows.html">Method 2 in this blog post</a> for how. This is nice and easy, but you have to do it every time you change your window theme.</li>
</ol>
<p>I'd recommend installing Maximus from your package manager if you have it (i.e. Ubuntu). Otherwise, edit your window theme (knowing that it could get written over every time you change your theme), or try my <a href="https://extensions.gnome.org/extension/354/maximus/">Maximus GNOME shell extension (from extensions.gnome.org)</a>.</p>
<p>The <a href="https://extensions.gnome.org/extension/354/maximus/">Maximus GNOME shell extension</a> is just an extension that emulates the behaviour of the original Maximus program. All it does is undecorate windows that are maximised.</p>
<p>The homepage/repository/instructions are <a href="https://bitbucket.org/mathematicalcoffee/maximus-gnome-shell-extension/overview">here</a>. For a one-click install just visit <a href="https://extensions.gnome.org/extension/354/maximus/">extensions.gnome.org</a> (or you can also <a href="https://bitbucket.org/mathematicalcoffee/maximus-gnome-shell-extension/downloads/maximus@mathematical.coffee.gmail.com.zip">download the zip file</a> and use <code>gnome-tweak-tool</code> to install it ('Shell Extensions' > 'Install Extension' > select .zip file). Make sure you additionally enable it.)</p>
<p>Enjoy & let me know of any bugs :)</p>
<hr />
<h2>For developers: How it's done</h2>
<p>For those who are interested, this is how I managed to get the windows undecorated.</p>
<p>Recall that in GNOME-shell, window objects are <code>Meta.Window</code>s (using the Mutter = Metacity + Clutter bindings).
There are four ways I tried to undecorate/redecorate a window:</p>
<ul>
<li>use the Mutter interface: try modifying the <code>window.decorated</code> property of a <code>Meta.Window</code>.</li>
<li>use the Gtk interface: try using <code>window.set_hide_titlebar_when_maximised()</code> or <code>window.set_decorated()</code>. on a <code>Gtk.Window</code>.</li>
<li>use the Gdk interface: try using <code>window.set_decorations()</code> on a <code>Gdk.Window</code>.</li>
<li>make an external call to <code>xprop</code> to set the window manager hints saying to undecorate the window.</li>
</ul>
<h3>Mutter: <code>window.decorated = false</code></h3>
<p>It would be ideal to undecorate using the Mutter bindings as GNOME-shell treats all windows as <code>Meta.Window</code>s anyway.</p>
<p>There is a <code>window.decorated</code> property for <code>Meta.Window</code>s but it's treated as read-only (as of GNOME 3.4.1); setting it to <code>true</code> or <code>false</code> has no effect.
There is no way to set the window's decorations from the current (GNOME 3.4.1) Mutter gobject introspection. Not surprising; the Mutter API can't do much at the moment.</p>
<h3>Gtk: <code>window.set_hide_titlebar_when_maximised</code></h3>
<p>Now assume that we could convert a <code>Meta.Window</code> into a <code>Gtk.Window</code>. Then we'd be able to use the function <a href="http://developer.gnome.org/gtk3/stable/GtkWindow.html#gtk-window-set-hide-titlebar-when-maximized"><code>gtk_window_set_hide_titlebar_when_maximised()</code></a> to get the behaviour we wanted, or if that didn't work, <a href="http://developer.gnome.org/gtk3/stable/GtkWindow.html#gtk-window-set-decorated"><code>gtk_window_set_decorated()</code></a>.</p>
<p>However I couldn't find a way to make a GTK window from a Meta.Window, and in fact I'm not sure if it's possible/GTK works like that.</p>
<h3>Gdk: <code>window.set_decorations</code></h3>
<p>Well, why not assume we could convert a <code>Meta.Window</code> into a <code>Gdk.Window</code>. Then we could use the function <a href="http://developer.gnome.org/gdk/stable/gdk-Windows.html#gdk-window-set-decorations"><code>gdk_window_set_decorations(0)</code></a> to remove decorations from a window.</p>
<p>How to create a <code>Gdk.Window</code> from a <code>Meta.Window</code> from the gobject introspection bindings? The best I could find was a function <a href="http://developer.gnome.org/gdk/stable/gdk-X-Window-System-Interaction.html#gdk-x11-window-foreign-new-for-display"><code>gdk_x11_window_foreign_new_for_display</code></a>, which will create a Gdk.Window given the window's X ID. In the GNOME javascript bindings:</p>
<pre><code class="language-javascript">const Gdk = imports.gi.Gdk;
const GdkX11 = imports.gi.GdkX11;
let window = GdkX11.X11Window.foreign_new_for_display( Gdk.Display.get_default(), WINDOW_XID );
// remove decorations
window.set_decorations(0);
// add back decorations
window.set_decorations(Gdk.WMDecoration.ALL);
</code></pre>
<p>Assuming you can find the window's X ID (for example with <code>xwininfo</code>), this works!</p>
<p>However, this is another unfortunate caveat; when you call this code from <strong>within</strong> the GNOME-shell process (i.e. from a GNOME shell extension), the window gets killed! If you run the <em>exact same code</em> using the <code>gjs</code> binary, or you write the exact same code in Python with the Python bindings, <strong>it works</strong>!.</p>
<p>After <a href="https://mail.gnome.org/archives/gnome-shell-list/2012-May/msg00024.html">a bit of asking around</a>, it turns out that using the above code simply won't work as long as it's run directly from a gnome shell extension; I have to make sure that the code that undecorates the window happens from an external process. This means making an external call (for example, <code>gjs undecorate_window.js</code>) from my code.</p>
<p>Then I'll need to somehow pass the window's X ID into the script from the extension to make sure it undecorates the right window.</p>
<p>So yes, this option is viable, but given that I have to make an external call anyway I'd rather not have to load up the various libraries in the external script <em>each time</em> a window is maximised.</p>
<h3><code>xprop</code></h3>
<p><code>xprop</code> is a command-line utility for examining/setting the X properties of a window.</p>
<p>Looking through the <code>set_decorations</code> code in GDK and the C source for <code>Maximus</code>, to undecorate a window one sets the <code>_MOTIF_WM_HINTS</code> property on the window. In the hints one specifies that the window should be undecorated. When the window manager looks at these hints it then attempts to undecorate the window according to the hints.</p>
<p>Translating this into using <code>xprop</code> to set the hints, one uses the following command (credit to <a href="http://xrunhprof.wordpress.com/2009/04/13/removing-decorations-in-metacity/">this post</a> that got me started):</p>
<pre><code class="language-bash">xprop -id [window_XID] -f _MOTIF_WM_HINTS 32c -set _MOTIF_WM_HINTS "0x2, 0x0, 0x0, 0x0, 0x0"
</code></pre>
<p>To explain:</p>
<ul>
<li><code>-id [window_XID]</code>: this tells <code>xprop</code> which window we wish to modify the hints of.</li>
<li><code>-f _MOTIF_WM_HINTS 32c</code>: this specifies the format of the <code>_MOTIF_WM_HINTS</code> property, each field being a 32bit unsigned integer.</li>
<li><code>-set _MOTIF_WM_HINTS 0x2, 0x0, 0x0, 0x0, 0x0</code>: says we wish to set the value of <code>_MOTIF_WM_HINTS</code> to <code>0x2, 0x0, 0x0, 0x0, 0x0</code>.</li>
</ul>
<p>A quick explanation of what all the numbers in <code>_MOTIF_WM_HINTS</code> mean (see <code>MwmUtil.h</code> from the <a href="http://cvs.openmotif.org/">OpenMotif source</a> for the documentation, or there is some rudimentary online documentation <a href="http://odl.sysworks.biz/disk$cddoc04sep11/decw$book/d3b0aa63.p264.decw$book">here</a>).</p>
<p>The hints structure has 5 fields, and (<strong>in order</strong>) they are:</p>
<ul>
<li>what fields we're specifying with the hints: the window functions, decorations, input mode and/or status. </li>
<li>the hints for the window functions. That is, which buttons to display on the window's title bar: maximise, minimise, close, ...</li>
<li>the decorations to be drawn on the window: title bar, border, all decorations, no decorations, ...</li>
<li>the input mode of the window: modeless (can't click on it), application modal, sytem modal, ...</li>
<li>the status of the window: whether it's a tearoff window or not.</li>
</ul>
<p>So in the above, <code>0x2, 0x0, 0x0, 0x0, 0x0</code> says that:</p>
<ul>
<li>we want to specify the decorations of the window (<code>0x2</code>); ignore all the other fields</li>
<li>we want there to be no decorations on the window (the third number is <code>0x0</code>).</li>
</ul>
<p>If we wanted to <em>decorate</em> the window we'd set the window hints to <code>0x2, 0x0, 0x1, 0x0, 0x0</code>.</p>
<h3>Summary</h3>
<p>Out of all of the above, only <code>xprop</code> and the GDK version were viable. Since I have to make an external call to undecorate the window anyway, I'd rather have my external call be <code>xprop -id ...</code> than <code>gjs undecorate_window.js</code> because in the latter <code>gjs</code> has to load all the relevant modules to execute the code, whereas the former is a simple command-line call that does the undecorating directly.</p>
<p>So the only question left is how to get the X ID of a window in order to pass it in to <code>xprop</code> (we'd have the same problem with Gdk too).</p>
<h2>Getting the X ID of a window</h2>
<p>There is currently (GNOME 3.4.1) <strong>no official way</strong> to get the X ID from a <code>Meta.Window</code>. If I listen to <code>maximise</code> events, I get a <code>Meta.Window</code> specifying the window that was maximised. There is no method in the API to extract this window's X ID. (aaargh!)</p>
<p>So how can I find the <code>Meta.Window</code>'s X ID? I could try convert it into a Wnck window which has a <code>get_xid</code> method, but there's no way to do this directly other than looping through a list of Wnck windows and (say) comparing titles to determine whether the Wnck window is the same as the Meta.Window. This is prone to error - what happens when you have multiple windows with the same title? How will you work out which Wnck window is <em>your</em> window?</p>
<p>After a bit of digging around in the source of Mutter, I found two (somewhat hacky) ways to grab a Meta.Window's X ID.</p>
<h3>Method 1: Using the window's description</h3>
<p>It turns out that the <code>window.get_description()</code> of a Meta.Window consists of its X ID followed by its name (truncated to 10 characters) in brackets.
For example, <code>0x26005b (Google Chr)</code>.</p>
<p>So, method 1 is to extract the X ID from the description of the window. However, it isn't guaranteed that the window's description will have the X ID in it in future releases of GNOME/Mutter; it's just lucky that in 3.2 to 3.4 this is what the description is set to.</p>
<h3>Method 2: Using the window <em>frame</em>'s X ID</h3>
<p>If one has the actor for a Meta.Window, then the property <code>actor['x-window']</code> is the X ID of the window's <em>frame</em>.</p>
<p>By the frame of the window, I mean that every window has a frame created for it by the window manager, <code>actor['x-window']</code> is the X ID for that frame.</p>
<p>However, to perform undecoration/decoration of windows, one must use the X ID for the <em>client window</em>, being the window that the frame contains.</p>
<p>The client window is actually the child of the frame window. By using <code>xwininfo -children -id [frame_XID]</code> we can get a list of all the X IDs for the frame window's children, namely the one client window.</p>
<p>So method 2 is to make an external call to <code>xwininfo</code> and parse the output the extract the child's X ID. Again, it is not guaranteed that <code>actor['x-window']</code> will still be there in future releases of GNOME.</p>
<h3>Failing that</h3>
<p>If the above two methods fail to locate a window's X ID we can use its title as a last resort. This is because <code>xprop -id [window's XID]</code> can be replaced with <code>xprop -name [window's title]</code> to identify the window in question. However if you have multiple windows of the same title, you aren't guaranteed that <code>xprop</code> will identify the <em>particular</em> window you're after.</p>
<h2>Putting it all together.</h2>
<p>Putting it all together, this is what happens:</p>
<ol>
<li>Create a function <code>onMaximise</code> that fires whenever a window is maximised. One of its arguments is the window (that was maximised)'s actor.</li>
<li>Get the window's X ID, first by trying to parse the window's description and failing that by calling <code>xwininfo</code> on <code>actor['x-window']</code> to get the child's X ID.</li>
<li>If we found the X ID, then call <code>xprop -id [XI D] -f _MOTIF_WM_HINTS 32c -set _MOTIF_WM_HINTS "0x2, 0x0, 0x0, 0x0, 0x0"</code>. If we didn't, then call <code>xprop -name [window.get_title()] ...</code>.</li>
</ol>
<p>If you find a less cludgy way to do this (i.e. doing the external system call) please let me know!</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-54767231287016178852012-05-02T17:31:00.000-07:002012-08-06T16:25:27.078-07:00Adding window options to title bar in GNOME 3.2, 3.4<p>In GNOME you can usually right-click on the title bar of an application's window to select Minimize, Maximize, Always on Top, Always on Visible Workspace, etc.</p>
<p>If you use Google Chrome and are not using the system title bar and borders (the default), you'll notice it's not possible to access this menu. </p>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-PgroqTu1zug/T6HJb1GKXrI/AAAAAAAABWU/Xuvu8_bVbCY/s1600/window-options.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://1.bp.blogspot.com/-PgroqTu1zug/T6HJb1GKXrI/AAAAAAAABWU/Xuvu8_bVbCY/s320/window-options.png" width="262" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Window Options GNOME Shell Extension in action</td></tr>
</tbody></table>
<p>I've written a small GNOME Shell Extension that adds this drop-down list to the GNOME Shell title bar that gets drawn for the current window. See it in action in the picture.</p>
<p>It's called <a href="https://bitbucket.org/mathematicalcoffee/window-options-gnome-shell-extension">Window Options</a> and is available for installation <a href="https://extensions.gnome.org/extension/354/maximus/">from extensions.gnome.org</a>.</p>
<p>To install it, visit <a href="https://extensions.gnome.org/extension/354/maximus/">extensions.gnome.org</a> - one-click install.</p>
<p>
Otherwise, download the .zip file on the <a href="https://bitbucket.org/mathematicalcoffee/window-options-gnome-shell-extension/downloads">Downloads page</a>. Open <code>gnome-tweak-tool</code>, go to "Shell Extensions", "Install Extension" and select the .zip file.
</p>
<p>This extension also works with the <a href="https://extensions.gnome.org/extension/59/status-title-bar/">Status Title Bar</a> extension (which shows the full window title in the top instead of just the current application's name). <del>However, you have to make sure that Window Options is loaded <em>after</em> Status Title Bar, or else Status Title Bar will write over the menu.</del>(<strong>UPDATE:</strong> It now works with Status Title Bar regardless of install order.)</p>
<p><del>To do this, just make sure that if you're using Status Title Bar, you install it before Window Options. If it's too late and you installed Window Options first, you can either uninstall and reinstall Window Options, OR just toggle Window Options on and off a couple of times (from <code>gnome-tweak-tool</code>) when you log in. This will cause Window Options to put its menu items in Status Title Bar's menu instead of the default panel one (that Status Title Bar removes).</del></p>
<p>You can configure which items are shown in the menu; to see how, see the Readme on <a href="https://bitbucket.org/mathematicalcoffee/window-options-gnome-shell-extension">Window Options' homepage</a> (just scroll down a bit).</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-53427635755710284342012-04-12T23:34:00.001-07:002013-05-29T05:23:49.846-07:00Reduce horizontal spacing between icons in GNOME 3.2<p>One thing that annoys me about the default GNOME shell is the amount of horizontal space it wastes in between icons/indicators in the status area (top right on the panel).</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-Kdw2lhWlwxg/T4fGBVeSycI/AAAAAAAABUk/YuPbxK_HGAw/s1600/notification_tray_original.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="24" width="257" src="http://1.bp.blogspot.com/-Kdw2lhWlwxg/T4fGBVeSycI/AAAAAAAABUk/YuPbxK_HGAw/s320/notification_tray_original.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Urgh look how much space is between all the icons!</td></tr>
</tbody></table>
<p>I wrote a very simple GNOME shell extension to fix this. (My first ever! More an exercise in how to do it than anything else).</p>
<p>It's available for one-click install from <a href="https://extensions.gnome.org/extension/355/status-area-horizontal-spacing/">extensions.gnome.org</a>. The repository (for anyone interested in the code) is <a href="https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension">here</a>.</p>
<p>If for some reason you don't want to/can't install from extensions.gnome.org, you can go to the <a href="https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension/downloads#download-84302">'Downloads' page</a> and download the .zip file. Then start <code>gnome-tweak-tool</code>, select "Shell Extensions", "Install Shell Extensions", and choose the .zip file. Restart the gnome-shell, enable the extension, and you're all done!</p>
<p>The result?</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;">
<a href="http://1.bp.blogspot.com/-k61-1F47Ylk/T4fHW1SgdtI/AAAAAAAABUw/ovl51ORLZ0g/s1600/notification_tray_after.png" imageanchor="1" style="margin-left:auto; margin-right:auto; text-align: center"><img border="0" height="24" width="217" src="http://1.bp.blogspot.com/-k61-1F47Ylk/T4fHW1SgdtI/AAAAAAAABUw/ovl51ORLZ0g/s320/notification_tray_after.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Nice and slim</td></tr>
</tbody></table>
<p><b>Voila! Enjoy :)</b></p>
<h2>What it Does</h2>
<p>It basically just modifies these lines from the file <code>/usr/share/gnome-shell/theme/gnome-shell.css</code>:</p>
<pre><code class="language-css">.panel-button {
-natural-hpadding: 12px;
-minimum-hpadding: 6px;
/* ... and so on */
}
</code></pre>
<p>The attribute <code>-natural-hpadding</code> is set by default to 12 pixels wide. My extension sets this to 6 pixels wide (you can modify this if you want; just change the relevant lines in <code>stylesheet.css</code> that comes with the extensions).</p>
<p>If you set <code>-naturial-hpadding</code> below 6 pixels you will have to adjust <code>-minimum-hpadding</code> to match it too.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com2tag:blogger.com,1999:blog-7039473604287682752.post-63428463854855262002012-04-12T20:29:00.002-07:002012-04-12T20:41:20.745-07:00Shell Extensions in Gnome 3.2/Fedora 16<p>I just upgraded my work computer from Fedora 15 to Fedora 16, which uses Gnome 3.2. This is my first real experience with the GNOME shell in Fedora, because I got rid of it straight away (fallback mode) in F15 since I couldn't stand it so haven't used it since.</p>
<p>Anyhow, I thought I'd give it a shot this time as the GNOME team have apparently been doing good things with the newer versions of GNOME shell.</p>
<p>My first impression - danger Will Robinson! Switch back to fallback mode!</p>
<ul>
<li>poor support for dual monitor which I use at work: top panel is only on one screen</li>
<li>to get to the Overview to switch/view windows I have to hover over the top left corner of the left-most screen, rather than just clicking a window from the top panel</li>
<li>the clock is in the middle of my top panel, meaning I wouldn't be able to see my current window title, <em>except</em> that</li>
<li>the window title of the current window I'm in doesn't show in the top panel. Just the application name. </li>
</ul>
<p>I was just about to switch to fallback mode again, when I discovered <a href="https://extensions.gnome.org/about/">GNOME shell extensions</a>.
These are little plugins (think of them like browser plugins) that add functionality to the GNOME shell interface.</p>
<p>Below I'll summarise some of the shell extensions that I found at the <a href="https://extensions.gnome.org/">GNOME shell extensions website</a> that rectified my problems. You generally install them from that website, and then use <code>gnome-tweak-tool</code> (or "Advanced Settings" in Fedora) to toggle them on and off.</p>
<p>You'll need to log out and in again or restart the shell (Alt+F2, type 'r' for restart, press Enter) to have them take effect.</p>
<h3>Top Panel</h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-LRFm3fT1l-I/T4ePonVPNUI/AAAAAAAABSg/AmDlRetODUg/s1600/extensions_moveclock.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="24" src="http://3.bp.blogspot.com/-LRFm3fT1l-I/T4ePonVPNUI/AAAAAAAABSg/AmDlRetODUg/s320/extensions_moveclock.png" width="256" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Frippery Move Clock moves the clock to the left</td></tr>
</tbody></table>
<p><a href="https://extensions.gnome.org/extension/2/move-clock/">Frippery Move Clock</a> This moves the clock from the centre of the panel to the left of the status menu button (over the right of the screen). This frees up space for extensions that show icons for open windows, etc. Essential.</p>
<p><a href="https://extensions.gnome.org/extension/51/extend-left-box/">Extend Left Box</a> This allows extensions using the top panel (e.g. window list extensions) to use the whole of the top panel instead of just the left half. Essential.</p>
<p><a href="https://extensions.gnome.org/extension/59/status-title-bar/">Status Title Bar</a> This shows the entire title (e.g. "Blogger: Mathematical Coffee - Edit post - Google chrome") of your current window in the top panel, rather than just the application name ("Chrome"). Whether to use this or not depends on your top panel real-estate.< /p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-4LlHjx-V7J8/T4eP5ELNhlI/AAAAAAAABSs/TIAH9UYin-A/s1600/extensions_windowTitle.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="14" src="http://3.bp.blogspot.com/-4LlHjx-V7J8/T4eP5ELNhlI/AAAAAAAABSs/TIAH9UYin-A/s320/extensions_windowTitle.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Status Title Bar with Extend Left Box show the full window title</td></tr>
</tbody></table>
<h3>
Notification Icons</h3>
The following extensions affect the notification icons up the top-right of the screen (accessibility, volume, ...) and the messaging tray at the bottom of the screen. <br />
<p><a href="https://extensions.gnome.org/extension/99/evial-status-icon-forerver/">Evil Status Icon Forever</a> There are many extensions that hide icons (e.g. accessibility) or move icons from the messaging tray to the notification bar (dropbox, ...), but this one seems to cover the functionality of all of them. This allows you to set which notification icons to move from the messaging tray to the top panel (I added dropbox and guake up there) and which to hide (the accessibility icon). For instructions see <a href="https://github.com/brianhsu/EvilStatusIconForever">here</a>.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-eWjnetxTTnc/T4eP_4WAiVI/AAAAAAAABS4/7ev_XGQ_FOo/s1600/extensions_evil-status-icon.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="19" src="http://1.bp.blogspot.com/-eWjnetxTTnc/T4eP_4WAiVI/AAAAAAAABS4/7ev_XGQ_FOo/s320/extensions_evil-status-icon.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Evil Status Icon Forever lets me put dropbox & other icons up the top; <br />notice also the workspace indicator.</td></tr>
</tbody></table>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-xBV0Y5Pommw/T4eZhqMM8nI/AAAAAAAABT0/16OLK8gvjiM/s1600/screenshot_8.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="208" src="http://4.bp.blogspot.com/-xBV0Y5Pommw/T4eZhqMM8nI/AAAAAAAABT0/16OLK8gvjiM/s320/screenshot_8.png" width="113" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Places menu</td></tr>
</tbody></table>
<p><a href="https://extensions.gnome.org/extension/8/places-status-indicator/">Places Status Indicator</a> adds a folder to the notification tray that, when clicked, shows a list of folders to open in nautilus.</p>
<p>If you want to remove an individual icon (accessibility, bluetooth, volume, ..) from the notification bar, use Evil Status Icon Forever. If for some reason you don't want to do that, you can install the <a href="https://extensions.gnome.org/extension/124/volume-icon-remover/">volume icon remover</a>, <a href="https://extensions.gnome.org/extension/125/bluetooth-icon-remover/">bluetooth icon remover</a>, or <code>gnome-shell-extension-remove-accessibility-icon</code> from the fedora repositories.</p>
<p><a href="https://extensions.gnome.org/extension/21/workspace-indicator/">Workspace indicator</a> adds a little drop-down menu from the notification area letting you switch between workspaces (The '1' in the box in the above picture). Since I added this functionality on my docklet (later in this post), I didn't need this any more).</p>
<h3>
Status Icon</h3>
The "Status Icon" is the menu at the top-right of your panel with a speech bubble next to your user name.
The speech bubble is your chat availability - you can control it from there. The menu also contains the "System Settings", "Log out", etc options.<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-jVUn7sfnS34/T4eQTQAKIQI/AAAAAAAABTE/stbAvzoWn3A/s1600/status_menu.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="320" src="http://1.bp.blogspot.com/-jVUn7sfnS34/T4eQTQAKIQI/AAAAAAAABTE/stbAvzoWn3A/s320/status_menu.png" width="182" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Chat, Hibernate, Power Off options;<br />No name on the button</td></tr>
</tbody></table>
<p><a href="https://extensions.gnome.org/extension/5/alternative-status-menu/">Alternative Status Menu</a> By default the status menu only gives a "Suspend" option for closing your computer, and you have to hold down Alt to see "Hibernate" or "Power Off". This extension adds the "Hibernate" and "Power Off" buttons <em>permanently</em> to the menu. Very useful (for me anyway), because I want to power off my computer much more often than suspend it.</p>
<p><a href="https://extensions.gnome.org/extension/40/status-only-icon/">Status Only icon</a> removes your username from next to the speech bubble, leaving just the speech bubble. I know my name already so there's no use having it there taking up space!</p>
<p><a href="https://extensions.gnome.org/extension/259/empathy-menu/">Empathy Menu</a> You can set your availability for chat with the status menu, but you can't actually start a chat from it. What a pain! This extension adds an option "Chat" to the menu that launches empathy (there are similar ones for <a href="https://extensions.gnome.org/extension/260/pidgin-menu/">Pidgin</a> and <a href="https://extensions.gnome.org/extension/198/empathy-gwibber-in-usermenu/">Gwibber</a>). I still think I'd like to be able to click on a contact's name from that menu though, like Unity.</p>
<p><a href="https://extensions.gnome.org/extension/258/notifications-alert-on-user-menu/">Notifications Alert</a> this paints the speech bubble on the status menu red when you have a new notification (e.g. IM messages).</p>
<h3>
Window list</h3>
My biggest gripe is not having a one-click window list. I just want something like the good old gnome-panel. There are a number of extensions providing this functionality. These all work best with Frippery Move Clock extension and the Extend Left extension.<br />
<p><a href="https://extensions.gnome.org/extension/17/dock/">Dock</a> this puts a permanent dock on the left or right side of the screen, the same dock that appears in the overview. You can configure it to autohide or not, and which side of the screen to put it on (not top and bottom though, and doesn't support one per monitor). Quite slick, although not very customisable.</p>
<p><a href="https://extensions.gnome.org/extension/25/window-list/">Window List</a> does what it says on the can. Adds window buttons (icon and text) to the top panel. Like the Windows XP task bar.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-L-gjvxHC5lw/T4efy2_o-FI/AAAAAAAABUY/kB6TjR38sfc/s1600/window_list.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="12" width="320" src="http://1.bp.blogspot.com/-L-gjvxHC5lw/T4efy2_o-FI/AAAAAAAABUY/kB6TjR38sfc/s320/window_list.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Window list</td></tr>
</tbody></table>
<p><a href="https://extensions.gnome.org/extension/70/window-icon-list/">Window Icon List</a> Adds icons for open windows to the top panel, like Windows 7.</p>
<p><a href="https://extensions.gnome.org/extension/105/panel-docklet/">Panel Docklet S</a> I've saved the best til last! This is the extension I ended up going with - sleek, infinitely customisable. It lets me create either a panel or docklet (my chose) on any side of the screen I like. I can show one icon per group of icons (text too if I want), or one icon per application, and <strong>best of all</strong>, I can put <strong>one docklet per monitor</strong>, and I'll only get icons for applications on that monitor! I can also add a workspace switcher (depreciating the need for a separate workspace switcher app), add a button to go to the desktop, add my 'favourites' (on the side dock) as icon shortcuts, and much, much more. I <strong>strongly recommend</strong> this. The only downfall is that I find that the panel on the second monitor sometimes shows icons of applications even though they've already been closed, and if I right click on them gnome-shell crashes :(.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-EaSonIKNG9k/T4eY0bOx8fI/AAAAAAAABTc/iQdLAX_jZMc/s1600/extension_panel_docklet.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="48" src="http://4.bp.blogspot.com/-EaSonIKNG9k/T4eY0bOx8fI/AAAAAAAABTc/iQdLAX_jZMc/s320/extension_panel_docklet.png" width="264" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Panel Docklet S in 'docklet' mode</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-Invamlb_aGc/T4ecou4_ikI/AAAAAAAABUI/Paodoh0Wsow/s1600/extension_panedocklet.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="17" src="http://3.bp.blogspot.com/-Invamlb_aGc/T4ecou4_ikI/AAAAAAAABUI/Paodoh0Wsow/s320/extension_panedocklet.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Panel Docklet S in 'panel-docklet' mode over my top panel</td></tr>
</tbody></table>
<h3>Other</h3>
<p><a href="https://extensions.gnome.org/extension/19/user-themes/">User Themes</a>: this allows you to install custom skins for the GNOME shell and switch between them from <code>gnome-tweak-tool</code>.</p>
<p><a href="https://extensions.gnome.org/extension/141/lame-extensions-manager/">Lame Extensions Manager</a> while you're playing around with all the shiny extensions on <a href="https://extensions.gnome.org">extensions.gnome.org</a>, this provides a button in the status bar allowing you to toggle them on and off quickly.\</p>
<h2>Summary</h2>
<p>In the end, I managed to fix most my gripes - removed notification icons I don't use, moved the clock to the left, removed the name from the status bar, and these freed up a lot of space in the top panel.</p>
<p>With that free space I dumped a Panel Docklet S there (in the 'docklet panel' mode) which allows me to quickly see what windows I have open on a particular monitor and go to them (as well as letting me switch between workspaces), and changed the title bar to show the full name of the current window rather than the application name.</p>
<p>All in all, that covers most the gripes I started with! The fact that I can make one docklet per monitor soothes the gnome-shell dual-monitor pain, and the docklet really lets me do most things I wanted (workspace and window switching, shortcuts).</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-2820865887190983632012-03-29T05:32:00.001-07:002013-05-29T05:25:59.906-07:00Getting straight single quotes for code/verbatim in Sweave/knitr<p><b>Update 16 April 2012: Yihiu has <a href="https://github.com/yihui/knitr/commit/b4934de5eb769437cf8c080cd11c2c4366d3e7a7">fixed this</a> from knitr 0.5! Thanks!</b></p>
<p>I've recently started using <a href="http://yihui.name/knitr/">knitr</a> to write reports, mainly about code I've written in R.</p>
<p>One thing that I insist upon in documentation on code is that code snippets <em>within</em> the document be able to be copy-and-pasted easily so the user can follow along.</p>
<p>This is why I don't like having the following in my documents:</p>
<pre><code class="language-r">> words <- c('Hello','world!')
> paste(words)
[1] "Hello" "world!"
</code></pre>
<p>If the user wants to perform the code I've just written, they can't simply select everything and copy-paste; the <code>></code> symbols are going to get in the way.</p>
<p>I much prefer something like this:</p>
<pre><code class="language-r">words <- c('Hello','world!')
paste(words)
## "Hello" "world!"
</code></pre>
<p>This is why I like knitr as opposed to <a href="http://www.statistik.lmu.de/~leisch/Sweave/">Sweave</a> on which it is based; knitr seems to be more flexible in suppressing the leading <code>></code> in input commands, and putting comments (<code>##</code>) in front of the outputs.</p>
<p>However, knitr has an annoying drawback that Sweave doesn't when it comes to typesetting code: a single quote mark/apostrophe <code>'</code> in Sweave will stay as such in the output; in knitr, it will be converted to a left or right single quote.</p>
<p>By default, LaTeX will change "straight" single quotes ' into left <span style="font-size: x-large; vertical-align: sub;">‘</span> and right <span style="font-size: x-large; vertical-align: sub;">’</span> single quotes that are curled depending on whether the quote is open or closed.</p>
<p>If you try and copy-paste these into a terminal you will run into trouble, and R will complain about "unexpected input in "??"", where the "??" may be a funny looking symbol (depending on your terminal) that basically means "I don't understand this fancy symbol you gave me!"</p>
<p>Now, Sweave has some way of dealing with this. It converts all of these funky quotes into normal straight quotes that can be safely copy-pasted into R. Knitr doesn't.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-9Du4GWxLxX8/T3RUdvOhOzI/AAAAAAAABRw/vy0XzEihdyk/s1600/sweaveCurlyQuotes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="42" src="http://2.bp.blogspot.com/-9Du4GWxLxX8/T3RUdvOhOzI/AAAAAAAABRw/vy0XzEihdyk/s320/sweaveCurlyQuotes.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">weird curly quotes in knitr</td></tr>
</tbody></table>
<p>How to fix this? Well, there is a LaTeX package <a href="http://www.ctan.org/tex-archive/macros/latex/contrib/upquote">upquote</a> that converts all single quotes that occur in a verbatim environment (or <code>\verb</code> commands) from left/right single quotes into straight single quotes.</p>
<p>It uses the textcomp package to access the command <code>\textquotesingle</code> which is the straight single quote (it also does backticks via <code>\textasciigrave</code>). The upquote package basically says "if you encounter a quote in a verb-like environment, make sure it's <code>\textquotesingle</code>!".</p>
<p>So how does this tie into getting straight quotes in Sweave/knitr? Easy: add <code>\usepackage{upquote}</code> and a fairly arcane command to your preamble:</p>
<pre><code class="language-tex">\documentclass{article}
\usepackage{upquote} % to convert funny quotes to straight quotes
\setbox\hlnormalsizeboxsinglequote=\hbox{\normalsize\verb.'.}%
\begin{document}
<<eval=TRUE,echo=TRUE,tidy=FALSE>>=
words <- c('Hello','world!')
@
\end{document}
</code></pre>
<p>Now you can just run knitr on this and then pdflatex, and voila! Straight quotes.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-C-MmdMEvAvw/T3RTqwjfr1I/AAAAAAAABRk/ru7iim6W7QY/s1600/sweavestraightquotes.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="30" src="http://1.bp.blogspot.com/-C-MmdMEvAvw/T3RTqwjfr1I/AAAAAAAABRk/ru7iim6W7QY/s320/sweavestraightquotes.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">straight quotes in knitr!</td></tr>
</tbody></table>
<h3> How does this work? </h3>
<p>For the more TeX-inclined among you, this is why it works.</p>
<p>First of all, when knitr process a Rnw file (and makes a tex file as an output), it defines a whole bunch of individual characters and uses them in the output. Have a look at the preamble of a knitted document and you will see a whole bunch of:</p>
<pre><code class="language-tex">
\newsavebox{\hlnormalsizeboxclosebrace}%
\newsavebox{\hlnormalsizeboxopenbrace}%
....
\setbox\hlnormalsizeboxopenbrace=\hbox{\begin{normalsize}\verb.{.\end{normalsize}}%
\setbox\hlnormalsizeboxclosebrace=\hbox{\begin{normalsize}\verb.}.\end{normalsize}}%
</code></pre>
<p>There are lots and <em>lots</em> of these definitions. There appears to be one for each punctuation character and text size.</p>
<p>In particular there is one for the single quote mark, called <code>\hlnormalsizeboxsinglequote</code>. <em>Every single time</em> you have a single quote in a code chunk, knitr replaces this single quote with <code>\usebox{\hlnormalsizeboxsinglequote}</code>. <em>Every single time</em> you use <em>any</em> punctuation character <em>at all</em> within a code chunk, knitr will replace it with the relevant <code>\hlnormalsize[charactername]</code>. It's bizarre, and leads to very ugly code!</p>
<p>For example, the simple chunk in the example above gets rendered (in the tex document) like so:</p>
<pre><code class="language-tex">
\begin{knitrout}
\definecolor{shadecolor}{rgb}{0.969, 0.969, 0.969}\color{fgcolor}\begin{kframe}
\begin{flushleft}
\ttfamily\noindent
{\ }{\ }{\ }{\ }\hlsymbol{words}{\ }\hlassignement{\usebox{\hlnormalsizeboxlessthan}-}{\ }\hlfunctioncall{c}\hlkeyword{(}\hlstring{\usebox{\hlnormalsizeboxsinglequote}Hello\usebox{\hlnormalsizeboxsinglequote}}\hlkeyword{,}\hlstring{\usebox{\hlnormalsizeboxsinglequote}world!\usebox{\hlnormalsizeboxsinglequote}}\hlkeyword{)}\mbox{}
\normalfont
\end{flushleft}
\end{kframe}
\end{knitrout}
</code></pre>
How gross!<br />
<p>Anyhow, remember that knitr inserts all the savebox commands <em>before</em> the preamble you put in your Rnw document. Well, <code>\setbox</code> operates such that it calculates the contents of the box <em>straight away</em> and saves it to the box register, and then forgets the definition of the box (i.e. the <code>\normalsize\verb.'.</code>).</p>
<p>What this means is that <code>\hlnormalsizeboxsinglequote</code> gets defined <em><b>before</b></em> the upquote package is even <em>loaded</em>, and hence the effect of upquote (redefining <code>'</code> to <code>\textquotesingle</code> within verbatim commands) happens too late to affect the <code>\verb.'.</code> that occurs in <code>\hlnormalsizeboxsinglequote</code>.</p>
<p>To fix this, we would like to retrieve the definition of the <code>\hlnormalsizeboxsinglequote</code> command <em>after</em> we load the upquote package so that its definition gets re-parsed. Then we'd just have to type something like \edef\hlnormalsizeboxsinglequote\hlnormalsizeboxsinglequote to say "set <code>\hlnormalsizeboxsinglequote</code> to what it used to be, but re-read the definition first".</p>
Unfortunately there appears to be no way to do this.
Hence the only fix is to look up how knitr defines <code>\hlnormalsizeboxsinglequote</code> by grabbing it out of the preamble of a knitted document, and copy its definition into the preamble of the source document.</p>
<p>This works for now, but it just means that if the knitr package changes how it defines <code>\hlnormalsizeboxsinglequote</code> (maybe in one revision they decide to make all quotes blue in colour), it is up to you to make sure that your redefinition of <code>\hlnormalsizeboxsinglequote</code> in your Rnw file matches that used by Sweave.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com6tag:blogger.com,1999:blog-7039473604287682752.post-81484352914390874452012-03-07T22:28:00.000-08:002013-05-29T05:30:48.874-07:00Be a NethackR!<p><a href="http://www.nethack.org/">Net Hack</a> is one of the most amazing games of all times.</p>
<p>It's a rogue-like game, where the quest is to retrieve the Amulet of Yendor from the bottom of the dungeon and bring back it up to the top in order to sacrifice it to your deity and achieve immortal fame & glory, etc. Along the way, one must avoid the many (and I mean <em>many</em>) ways to die, including from the evil Wizard of Yendor, also known as Rodney.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-BEb05MrU-Lg/T1hRMyUEs2I/AAAAAAAABQo/UY48fdTa1UQ/s1600/died.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="207" src="http://2.bp.blogspot.com/-BEb05MrU-Lg/T1hRMyUEs2I/AAAAAAAABQo/UY48fdTa1UQ/s320/died.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Adventuring through the dungeon (aww, I died)</td></tr>
</tbody></table>
<p>There are many, <em>many</em>, <strong>many</strong> ways to die in Net Hack. Also, there's no saving except to resume your game later - once you die, you die. You have to restart the game from scratch. Finally, the game comes with a small hints book to get you started, but no real instructions (like "don't look at Medusa or you'll die! Don't touch a cockatrice or you'll turn to stone! Don't eat to much or you'll die of overeating (not kidding!)").</p>
<p>These factors all make Net Hack a very, very, hard game. And yet addictive! I have yet to win the game after a couple of years of on and off playing, but I still love it.</p>
<p>Anyhow, I decided to write an <a href="http://www.r-project.org">R</a> package that would let me play Net Hack in R (terminal version, of course! I wouldn't play the graphics version unless I didn't have a keyboard!).</p>
<p>Why would I want to play Net Hack from R? Well ... why not? :D</p>
<p>You can download it from <a href="https://bitbucket.org/mathematicalcoffee/nethackr">here</a> - either go to the 'Downloads' page and grab the .zip file and install within R (Packages -> Install package(s) from local zip files... OR <code>install.packages('nethackR_1.0.1.zip',repos=NULL)</code>), or if you feel hackerish and are running Cygwin or Linux (or Mac? haven't tested it there), you can grab the source, unzip, and type:</p>
<pre><code class="language-bash">make
make install
</code></pre>
<p>After that, go into R, read the help file, and start a game!</p>
<pre><code class="language-r">library(nethackR)
?nethackR # read some help files
?nethack # read some help files
nethack() # start a game!
</code></pre>
<p>You can even feed in nethack options:</p>
<pre><code class="language-r">nethack(dogname='Indy',catname='lolcatz',hilite_pet=TRUE,time=TRUE)
</code></pre>
<p>Enjoy! (and let me know of bugs, I'm sure there are some).</p>
<p>As a note - the package comes bundled with the Net Hack executable already. You may not feel secure running an exe that the package author (me) guarantees you is the actual NetHack.exe and not one filled with viruses. If so, download NetHack yourself and place it within the <code>bin/your_OS-type</code> folder in the <code>nethackR</code> folder of your R library. <code>your_OS-type</code> is either 'unix' (for Linux and Mac) or 'windows' (for Windows). That way you can be sure the executable is safe.</p>
<p>Onward NethackRs!</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-YG53YtPd9cY/T1hRNC8TPMI/AAAAAAAABQ0/vTH-ARSSe7A/s1600/rip.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="238" src="http://2.bp.blogspot.com/-YG53YtPd9cY/T1hRNC8TPMI/AAAAAAAABQ0/vTH-ARSSe7A/s320/rip.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">RIP yet another character!</td></tr>
</tbody></table>
<h3>Extra rambling (mainly for R people):</h3>
<p>This was mostly an exercise in writing R packages - it was the first one I ever wrote and wanted something fun to motivate me.</p>
<p>It turned out to be much easier than I thought - you can just call <code>system('nethack')</code>, and R takes care of the rest, even the interactive part - it's as if I'd just run nethack from the terminal instead.</p>
<p>However, I then took this to Windows to test, and if I used the GUI console for R (Rgui.exe as opposed to Rterm.exe), NetHack would start but hang my system until I forcibly closed the NetHack.exe process using the System Manager.</p>
<p>I figured out the solution today by looking at the help file for <code>system</code> in R in Windows (turns out the help file is different in Linux and didn't include this all-important information) - turns out I can't run interactive (text) programs in Rgui, it just doesn't work.</p>
<p>So instead, if the user uses Rgui, the package will launch a command prompt from which the user can play.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-2924453947474983212012-02-15T04:02:00.000-08:002013-05-29T05:30:10.604-07:0011.10 Oneiric: "Bad password" and rtlwifi<p>Today my wireless decided to stop working (under Linux; it of course worked in Windows).</p>
<p>Whenever I tried to connect to a network, it (wicd, that is) would spend ages on the "authenticate" stage before eventually saying "Bad password".
Of course, the password was correct. "Bad password" seems to be a generic error wicd gives you that covers all manner of actual errors.</p>
<p>Looking at <code>dmesg | tail</code>, I'd get a whole bunch of:</p>
<pre><code>[ 134.347782] rtl8192c: Loading firmware file rtlwifi/rtl8192cfw.bin
[ 134.686790] ADDRCONF(NETDEV_UP): wlan0: link is not ready
[ 135.037001] rtl8192c: Loading firmware file rtlwifi/rtl8192cfw.bin
[ 135.376045] ADDRCONF(NETDEV_UP): wlan0: link is not ready
[ 135.548216] rtl8192c: Loading firmware file rtlwifi/rtl8192cfw.bin
[ 135.887744] ADDRCONF(NETDEV_UP): wlan0: link is not ready
</code></pre>
<p>...and so on.</p>
<p><code>lsmod | grep rtl</code> yields:</p>
<pre><code>rtl8192ce 84775 0
rtl8192c_common 75767 1 rtl8192ce
rtlwifi 110972 1 rtl8192ce
mac80211 462046 3 rtl8192ce,rtl8192c_common,rtlwifi
cfg80211 199630 2 rtlwifi,mac80211
</code></pre>
<p>And <code>lspci | grep -i network</code> gave</p>
<pre><code>04:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8188CE 802.11b/g/n WiFi Adapter (rev 01)
</code></pre>
<p>After ages of googling, I found <a href="https://bugzilla.redhat.com/show_bug.cgi?id=729618">this bug</a>, actually a Fedora bug, that sounds a lot like mine.</p>
<p>Looking through the various attempts at fixes, etc, the only one that worked for me was:</p>
<pre><code class="language-bash">ifconfig wlan0 down
iwconfig wlan0 mode monitor
ifconfig wlan0 up
</code></pre>
<p>I know the first line switches off my wireless for a bit, the second sets the mode to 'monitor' (whatever that means??!!), and the third switches it on again, but I have no idea what this all actually means.</p>
<p>It'd love to have an understanding of what was wrong and why that fixed it, but I'll <em>definitely</em> settle for having it fixed :).</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-53603932041197973162012-02-07T20:22:00.000-08:002013-05-29T05:29:49.758-07:00Indicators in OneiricNew annoyed-with-unity-o-meter (indicators made me feel happier):
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-e6EbHe4MT5k/TzH4WTq9oBI/AAAAAAAABQY/Rk_6ivuQ5pg/s1600/meter_0.55.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="133" width="320" src="http://2.bp.blogspot.com/-e6EbHe4MT5k/TzH4WTq9oBI/AAAAAAAABQY/Rk_6ivuQ5pg/s320/meter_0.55.png" /></a></div>
<h1>Indicators</h1>
Today I discovered about Indicator Apps. They are just like the applets of GNOME 2 that I could add to my panel, except they're upgraded for GNOME 3 instead. They all sit up the top-left of your screen.<br />
<br />
Also, instead of having a nice, single list of these applets where I can choose which ones to add to my panel (like in old Ubuntu), they are now....<em>all over the place</em>.<br />
You basically have to look them up on the internet, add a new repository <em>for each one</em>, install it, and then <em>manually</em> run the program each time you start up to get it showing (well, I lie; you can add them into your auto-startup list to have them runn on their own).<br />
I found <a href="http://askubuntu.com/questions/30334/what-application-indicators-are-available">this page</a> very helpful in giving a list of the most popular indicator applets and how to install them.
Then, <a href="http://www.omgubuntu.co.uk/tag/indicatorapplets/">this page</a> gives a much bigger list of applets (although less helpful in how to install them).<br />
<h2>Installing Indicator Applets</h2>
Since they're not in the standard ubuntu repository, you usually have to update your list of repositories that Ubuntu looks in to get packages.<br />
Let's do an example with the <a href="https://launchpad.net/indicator-workspaces">Workspace indicator</a>, which sits in your top panel and lets you switch between workspaces.<br />
Going to its launchpad page, we see "Use this ppa for install: ppa:geod/ppa-geod".
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-DwfZK9bh6Hk/TzHe7R-1Y8I/AAAAAAAABPQ/X8lqGLU3sh0/s1600/indicator-workspaces.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="123" src="http://2.bp.blogspot.com/-DwfZK9bh6Hk/TzHe7R-1Y8I/AAAAAAAABPQ/X8lqGLU3sh0/s320/indicator-workspaces.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">launchpad page for inicitator-workspaces</td></tr>
</tbody></table>
<pre><code class="language-bash">sudo add-apt-repository ppa:geod/ppa-geod
</code></pre>
Then, we update the list of available packages and install <code>indicator-workspaces</code>:<br />
<pre><code class="language-bash">apt-get update
apt-get install indicator-workspaces
</code></pre>
But wait! You're not done yet! Go to the dashboard and actually <em>start</em> the indicator. Then it will appear in your notification tray.
If you right-click this one and look at the preferences you'll also see a "Start indicator at login", which you should check, if that's what you want.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-oCxGHGAmYxg/TzHuZWw6DgI/AAAAAAAABPc/B30SEdQ6itU/s1600/workspaceswitcher.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="86" src="http://3.bp.blogspot.com/-oCxGHGAmYxg/TzHuZWw6DgI/AAAAAAAABPc/B30SEdQ6itU/s200/workspaceswitcher.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Workspace switcher indicator.</td></tr>
</tbody></table>
<h2>
List of applets I added.</h2>
<ul>
<li><a href="https://launchpad.net/indicator-workspaces">Workspace switcher</a>: <code>add-apt-repository ppa:ppa/geod</code> and <code>apt-get install indicator-workspaces</code>.</li>
<li>System Load Indicator - you can just <code>apt-get install indicator-multiload</code> this one.
</li>
<li><a href="https://launchpad.net/google-reader-indicator">Google Reader Indicator</a>: lets me read my rss feeds from the panel. <code>add-apt-repository ppa:atareao/atareao</code> and <code>apt-get install google-reader-indicator</code>.
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-dRKCmMmmL8k/TzHviG0iszI/AAAAAAAABPo/psx0lbJ8v9M/s1600/reader.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="134" src="http://2.bp.blogspot.com/-dRKCmMmmL8k/TzHviG0iszI/AAAAAAAABPo/psx0lbJ8v9M/s200/reader.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">google reader indicator (top left icon)</td></tr>
</tbody></table>
</li>
</ul>
<h2>
User menu/indicator</h2>
I don't like the "User Menu" (the little person and your username up the top left) - it only has "switch user" etc and I'm the only user on my laptop, so it just takes up space. <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-oApCe_7XrhA/TzHwfxOGCiI/AAAAAAAABQA/9YGKYxhz8sc/s1600/usermenu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="24" src="http://1.bp.blogspot.com/-oApCe_7XrhA/TzHwfxOGCiI/AAAAAAAABQA/9YGKYxhz8sc/s320/usermenu.png" width="215" /></a></div>
To remove it, go to dconf-editor and apps>indicator-session, and untick 'show-user-menu'.<br />
Log out and back in to have it take effect (or just do <code>unity --replace</code>).
<br />
<h2>
Current snapshot</h2>
My current snapshot is:
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-2LTIP3S7ji8/TzHvzsaJW3I/AAAAAAAABP0/XouiRwwOwJU/s1600/indicators-good.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="22" src="http://3.bp.blogspot.com/-2LTIP3S7ji8/TzHvzsaJW3I/AAAAAAAABP0/XouiRwwOwJU/s320/indicators-good.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Left to Right: Dropbox, Google Reader, System Monitor, Workspace switcher, Messages, Battery, Volume, Date/time.</td></tr>
</tbody></table>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0tag:blogger.com,1999:blog-7039473604287682752.post-11943920753697671252012-02-07T16:31:00.000-08:002013-05-29T05:29:33.041-07:00First tweaks to Oneiric UnityThese are the first things I did to Oneiric to try make it more palatable to me.
<h1>Fed-Up-With-Unity-O-Metre:</h1>
After all the tweaks so far (left is "happy", right is "argh downgrade to 10.x or use Classic Ubuntu!":
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-H_u2cVY7Vj4/TzH4OZ0dNhI/AAAAAAAABQM/Nb2PjXv3VUk/s1600/meter_0.7.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="133" width="320" src="http://2.bp.blogspot.com/-H_u2cVY7Vj4/TzH4OZ0dNhI/AAAAAAAABQM/Nb2PjXv3VUk/s320/meter_0.7.png" /></a></div>
<h2>Terminal text</h2>
<p>The terminal text is this fancy different font. I just want the normal monospace.
No big deal this time --- Terminal -> Edit Profile -> General -> don't use system default font, change to Monospace size 10 (my preferred size).</p>
<h2>Wireless icon not there/network manager not showing networks</h2>
<p>I can't seem to get any wireless. The wireless icon I expect is not in my notification area like it used to be.
When I go into System Settings > Networking > Wireless, I get no network names detected, and the 'Configure...' button is greyed out. <code>ifconfig</code> and <code>iwconfig</code> do yield the expected <code>wlan0</code> interface though.</p>
<p>I used to have <code>wicd</code> installed (and apparently it still is) but I can't see the tray icon, so I go to my "Dash", type in "wicd" and open up the Wicd Network Manager (as an aside: <code>wicd-client</code> and <code>wicd-gtk</code> from the command line didn't open up any visible interface, what's its command?).</p>
<p>Woohoo! I can see networks and connect to them! The reason the in-built network manager wasn't doing anything is (I guess) that wicd is managing all the networks instead.</p>
<p>My problem was not that wireless wasn't working, but just that I can't see the wicd wireless indicator in my notification area.</p>
<p>So, how do I get it showing?</p>
<p>Following <a href="http://askubuntu.com/questions/69005/wicd-tray-icon-doesnt-show">this answer</a>, I install <code>dconf-tools</code>, and then run <code>dconf-editor</code>.
I navigate to desktop>unity>panel and add <code>Wicd</code> to <code>systray-whitelist</code>. As an aside, if you want to allow any tray icon to appear, use 'all'.
<!-- TODO: show image --></p>
<p>Then I log out and back in. Hey presto!
<!-- TODO: show image --></p>
<h2>Wireless slowing down startup</h2>
<p>Another thing I noticed is that when I start up the laptop, it spends forever on the startup screen (purple-black with "Ubuntu" and the dots underneath) saying "waiting for network configuration...", followed by "waiting another 60 secondsmore for network...", ended by "starting up without network configuration". However, my wireless <em>does</em> work (with wicd, I don't use the standard network-manager).</p>
<p>Looking at <a href="http://uksysadmin.wordpress.com/2011/10/14/upgrade-to-ubuntu-11-10-problem-waiting-for-network-configuration-then-black-screen-solution/">this post</a> which references <a href="https://bugs.launchpad.net/ubuntu/+source/dbus/+bug/811441/comments/24">this answer on this bugreport</a>, it does appear that this is a bug, and you may get it if you upgrade (you won't get it from a fresh install) (?). The solution (the usual <strong>DANGER THERE BE DRAGONS</strong> disclaimer):</p>
<pre><code class="language-bash">mkdir -p /run /run/lock
rm -rf /var/run /var/lock
ln -s /run /var
ln -s /run/lock /var
</code></pre>
<p>What these do:</p>
<ol>
<li>make directories <code>/run</code> and <code>/run/lock</code></li>
<li>remove directories <code>/var/run</code> and <code>/var/lock</code></li>
<li>create symbolic links: <code>/var/run</code> points to <code>/run</code>, and</li>
<li><code>/var/lock</code> points to <code>/run/lock</code>.</li>
</ol>
<p><strong>Argh!</strong> This didn't solve my problem. To be continued.</p>
<!--
`lspci | grep Network` yields:
04:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8188CE 802.11b/g/n WiFi Adapter (rev 01)
Now to work out`lsmod | grep -i rtl` yields:
rtl8192ce 84775 0
rtl8192c_common 75767 1 rtl8192ce
rtlwifi 110972 1 rtl8192ce
mac80211 462092 3 rtl8192ce,rtl8192c_common,rtlwifi
cfg80211 199630 2 rtlwifi,mac80211
-->
<h2>Argh I hate hovering over the bar to open up my application!</h2>
<p>I do like that the side launcher hides itself when you're not using it, giving you more screen real estate.
I also like the Mac-style merging of the top bit of any given window (with the min/max/restore/close buttons and the window title) is merged with the File/Edit/etc menus.</p>
<p>Unfortunately the side-launcher hiding means that when I want to switch between programs I can't just click on its icon and get there instantly --- I have to hover my mouse at the side of the screen to get the launcher to show, and then select my icon.</p>
<p>I have a few alternatives:</p>
<ul>
<li>I can press the meta key (windows key for my laptop) and it will show the side bar. I'll stick with this for a while --- it's a pretty good alternative. This is enabled by default.</li>
<li>I can remove the autohide on the side bar to have it permanently show. I might do this on my big laptop, since it only takes up a small amount of horizontal space and the screen is big enough that I only worry about vertical space.</li>
</ul>
<p>For completeness:</p>
<h2>Disabling autohide on the side bar.</h2>
<h3>Option 1: use <code>ccsm</code>.</h3>
<p><code>ccsm</code> is the compiz config settings manager. You can <code>sudo apt-get install</code> it. (I already had it from my previous incarnation of Ubuntu).</p>
<p>Go to the 'Ubuntu Unity' plugin and you can set "Hide launcher" to "Never", or you could change the "Edge Reveal Timeout" to something small to get the launcher to autohide but appear <em>instantly</em> when your mouse goes to the edge of the screen.</p>
<h3>Option 2:use <code>dconf</code></h3>
<p>(This is what I was initially going to do --- I discovered the compiz method by accident whilst getting my Wobbly Windows back).</p>
<p>You have to use <code>dconf</code> again! It's annoying, because you <em>should</em> be able to just right-click the side launcher and select "enable/disable autohide". ahh well:</p>
<pre><code class="language-bash">dconf write /com/canonical/unity-2d/launcher/use-strut true
dconf write /com/canonical/unity-2d/launcher/hide-mode 0
</code></pre>
<p>Alternatively open <code>dconf-editor</code>, navigate to <code>/com/canonical/unity-2d/launcher/</code>. Change <code>hide-mode</code> to 0 and tick <code>use-strut</code> to make it True.</p>
<p>While you're there, have a look at the explanation for <code>hide-mode</code>:</p>
<blockquote>
<p>Possible values:
<b>0:</b> never hide; the launcher is always visible. Always set /com/canonical/unity-2d/launcher/use-strut to true when using that mode.
<b>1:</b> auto hide; the launcher will disappear after a short time if the user is not interacting with it.
<b>2:</b> intellihide; the launcher will disappear if a window is placed on top of it and if the user is not interacting with it</p>
</blockquote>
<p>So to go back to autohide, change <code>hide-mode</code> back to 2 and <code>use-strut</code> to false.</p>
<p>You have to log out and in again for this to work.</p>
<h2>Auto-login</h2>
<p>User Accounts > Unlock > toggle "Automatic login"</p>
<h2>Disable lockscreen</h2>
<p>System Settings > Screen > toggle "Lock" off</p>
<h2>I want my wobbly windows back :(</h2>
<p>Install/run <code>ccsm</code> (I already had it from my previous version of Ubuntu) and re-enable.</p>
<h2>Customising the messenger menu</h2>
<p>It's that little icon in the notification area that looks like an envelope:</p>
<blockquote>
<p>Easily launch and receive incoming notifications from messaging applications including email, social networking, and Internet chat.</p>
</blockquote>
<p>I do like having the email notifications and functionality (the "compose email" opening up thunderbird is very cool (I set thunderbird as my default mail app)), but don't want the chat/evolution bit.</p>
<p>Argh --- I can't work out how to get rid of the "chat" bit and leave the "email" bit --- my only option is to remove the entire menu (<code>sudo apt-get remove indicator-messages</code>), which I don't want to do.
Oh well.</p>
<h2>Further tweaks.</h2>
<p><a href="http://www.webupd8.org/2011/10/things-to-tweak-after-installing-ubuntu.html">This blog post</a> is one I <em>just</em> found and it has a whole list of further tweaks.</p>mathematical.coffeehttp://www.blogger.com/profile/15453196627437456098noreply@blogger.com0