]> git.sur5r.net Git - i3/i3/commitdiff
Introduce contrib/
authorMichael Stapelberg <michael@stapelberg.de>
Sun, 10 Jun 2012 16:10:37 +0000 (18:10 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 10 Jun 2012 16:10:37 +0000 (18:10 +0200)
contrib is a place for scripts which live in the i3 git repository
because they are closely related. However, they should not be shipped
with the distribution packages for example.

contrib/dump-asy.pl [new file with mode: 0755]
contrib/gtk-tree-watch.pl [new file with mode: 0755]
contrib/i3-wsbar [new file with mode: 0755]
contrib/show-download-count.sh [new file with mode: 0644]
dump-asy.pl [deleted file]
gtk-tree-watch.pl [deleted file]
i3-wsbar [deleted file]
show-download-count.sh [deleted file]

diff --git a/contrib/dump-asy.pl b/contrib/dump-asy.pl
new file mode 100755 (executable)
index 0000000..a8eab04
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env perl
+# vim:ts=4:sw=4:expandtab
+# renders the layout tree using asymptote
+
+use strict;
+use warnings;
+use Data::Dumper;
+use AnyEvent::I3;
+use File::Temp;
+use v5.10;
+
+my $i3 = i3("/tmp/nestedcons");
+
+my $tree = $i3->get_tree->recv;
+
+my $tmp = File::Temp->new(UNLINK => 0, SUFFIX => '.asy');
+
+say $tmp "import drawtree;";
+
+say $tmp "treeLevelStep = 2cm;";
+
+sub dump_node {
+       my ($n, $parent) = @_;
+
+    my $o = ($n->{orientation} eq 'none' ? "u" : ($n->{orientation} eq 'horizontal' ? "h" : "v"));
+    my $w = (defined($n->{window}) ? $n->{window} : "N");
+    my $na = $n->{name};
+    $na =~ s/#/\\#/g;
+    my $name = "($na, $o, $w)";
+
+    print $tmp "TreeNode n" . $n->{id} . " = makeNode(";
+
+    print $tmp "n" . $parent->{id} . ", " if defined($parent);
+    print $tmp "\"" . $name . "\");\n";
+
+       dump_node($_, $n) for @{$n->{nodes}};
+}
+
+dump_node($tree);
+say $tmp "draw(n" . $tree->{id} . ", (0, 0));";
+
+close($tmp);
+my $rep = "$tmp";
+$rep =~ s/asy$/eps/;
+system("cd /tmp && asy $tmp && gv $rep && rm $rep");
diff --git a/contrib/gtk-tree-watch.pl b/contrib/gtk-tree-watch.pl
new file mode 100755 (executable)
index 0000000..f15d0c1
--- /dev/null
@@ -0,0 +1,219 @@
+#!/usr/bin/env perl
+# vim:ts=4:sw=4:expandtab
+# renders the layout tree using asymptote
+
+use strict;
+use warnings;
+
+use JSON::XS;
+use Data::Dumper;
+use AnyEvent::I3;
+use v5.10;
+
+use Gtk2 '-init';
+use Gtk2::SimpleMenu;
+use Glib qw/TRUE FALSE/;
+
+my $window = Gtk2::Window->new('toplevel');
+$window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
+
+my $tree_store = Gtk2::TreeStore->new(qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/);
+
+my $i3 = i3("/tmp/nestedcons");
+
+my $tree_view = Gtk2::TreeView->new($tree_store);
+
+my $layout_box = undef;
+
+sub copy_node {
+    my ($n, $parent, $piter, $pbox) = @_;
+
+    my $o = ($n->{orientation} == 0 ? "u" : ($n->{orientation} == 1 ? "h" : "v"));
+    my $w = (defined($n->{window}) ? $n->{window} : "N");
+
+    # convert a rectangle struct to X11 notation (WxH+X+Y)
+    my $r = $n->{rect};
+    my $x = $r->{x};
+    my $y = $r->{y};
+    my $dim = $r->{width}."x".$r->{height}.($x<0?$x:"+$x").($y<0?$y:"+$y");
+
+    # add node to the tree with all known properties
+    my $iter = $tree_store->append($piter);
+    $tree_store->set($iter, 0 => $n->{name}, 1 => $w, 2 => $o, 3 => sprintf("0x%08x", $n->{id}), 4 => $n->{urgent}, 5 => $n->{focused}, 6 => $n->{layout}, 7 => $dim);
+
+    # also create a box for the node, each node has a vbox
+    # for combining the title (and properties) with the
+    # container itself, the container will be empty in case
+    # of no children, a vbox or hbox
+    my $box;
+    if($n->{orientation} == 1) {
+        $box = Gtk2::HBox->new(1, 5);
+    } else {
+        $box = Gtk2::VBox->new(1, 5);
+    }
+
+    # combine label and container
+    my $node = Gtk2::Frame->new($n->{name}.",".$o.",".$w);
+    $node->set_shadow_type('etched-out');
+    $node->add($box);
+
+    # the parent is added onto a scrolled window, so add it with a viewport
+    if(defined($pbox)) {
+       $pbox->pack_start($node, 1, 1, 0);
+    } else {
+       $layout_box = $node;
+    }
+
+    # recurse into children
+    copy_node($_, $n, $iter, $box) for @{$n->{nodes}};
+
+    # if it is a window draw a nice color
+    if(defined($n->{window})) {
+       # use a drawing area to fill a colored rectangle
+       my $area = Gtk2::DrawingArea->new();
+
+       # the color is stored as hex in the name
+       $area->{"user-data"} = $n->{name};
+
+       $area->signal_connect(expose_event => sub {
+           my ($widget, $event) = @_;
+
+           # fetch a cairo context and it width/height to start drawing nodes
+           my $cr = Gtk2::Gdk::Cairo::Context->create($widget->window());
+
+           my $w = $widget->allocation->width;
+           my $h = $widget->allocation->height;
+
+           my $hc  = $widget->{"user-data"};
+           my $r = hex(substr($hc, 1, 2)) / 255.0;
+           my $g = hex(substr($hc, 3, 2)) / 255.0;
+           my $b = hex(substr($hc, 5, 2)) / 255.0;
+
+           $cr->set_source_rgb($r, $g, $b);
+           $cr->rectangle(0, 0, $w, $h);
+           $cr->fill();
+
+        return FALSE;
+       });
+
+    $box->pack_end($area, 1, 1, 0);
+    }
+}
+
+# Replaced by Gtk2 Boxes:
+#sub draw_node {
+#    my ($n, $cr, $x, $y, $w, $h) = @_;
+#
+#    $cr->set_source_rgb(1.0, 1.0, 1.0);
+#    $cr->rectangle($x, $y, $w/2, $h/2);
+#    $cr->fill();
+#}
+
+my $json_prev = "";
+
+my $layout_sw = Gtk2::ScrolledWindow->new(undef, undef);
+my $layout_container = Gtk2::HBox->new(0, 0);
+$layout_sw->add_with_viewport($layout_container);
+
+sub copy_tree {
+    my $tree = $i3->get_tree->recv;
+
+    # convert the tree back to json so we only rebuild/redraw when the tree is changed
+    my $json = encode_json($tree);
+    if ($json ne $json_prev) {
+        $json_prev = $json;
+
+        # rebuild the tree and the layout
+        $tree_store->clear();
+        if(defined($layout_box)) {
+            $layout_container->remove($layout_box);
+        }
+        copy_node($tree);
+        $layout_container->add($layout_box);
+        $layout_container->show_all();
+
+        # keep things expanded, otherwise the tree collapses every reload which is more annoying then this :-)
+        $tree_view->expand_all();
+    }
+
+    return(TRUE);
+}
+
+sub new_column {
+    my $tree_column = Gtk2::TreeViewColumn->new();
+    $tree_column->set_title(shift);
+
+    my $renderer = Gtk2::CellRendererText->new();
+    $tree_column->pack_start($renderer, FALSE);
+    $tree_column->add_attribute($renderer, text => shift);
+
+    return($tree_column);
+}
+
+my $col = 0;
+$tree_view->append_column(new_column("Name", $col++));
+$tree_view->append_column(new_column("Window", $col++));
+$tree_view->append_column(new_column("Orientation", $col++));
+$tree_view->append_column(new_column("ID", $col++));
+$tree_view->append_column(new_column("Urgent", $col++));
+$tree_view->append_column(new_column("Focused", $col++));
+$tree_view->append_column(new_column("Layout", $col++));
+$tree_view->append_column(new_column("Rect", $col++));
+
+$tree_view->set_grid_lines("both");
+
+my $tree_sw = Gtk2::ScrolledWindow->new(undef, undef);
+$tree_sw->add($tree_view);
+
+# Replaced by Gtk2 Boxes:
+#my $area = Gtk2::DrawingArea->new();
+#$area->signal_connect(expose_event => sub {
+#    my ($widget, $event) = @_;
+#
+#    # fetch a cairo context and it width/height to start drawing nodes
+#    my $cr = Gtk2::Gdk::Cairo::Context->create($widget->window());
+#
+#    my $w = $widget->allocation->width;
+#    my $h = $widget->allocation->height;
+#
+#    draw_node($gtree, $cr, 0, 0, $w, $h);
+#
+#    return FALSE;
+#});
+
+sub menu_export {
+    print("TODO: EXPORT\n");
+}
+
+my $menu_tree = [
+       _File => {
+               item_type => '<Branch>',
+               children => [
+                       _Export => {
+                               callback => \&menu_export,
+                               accelerator => '<ctrl>E',
+                       },
+                       _Quit => {
+                               callback => sub { Gtk2->main_quit; },
+                               accelerator => '<ctrl>Q',
+                       },
+               ],
+       },
+];
+
+my $menu = Gtk2::SimpleMenu->new(menu_tree => $menu_tree);
+
+my $vbox = Gtk2::VBox->new(0, 0);
+$vbox->pack_start($menu->{widget}, 0, 0, 0);
+$vbox->pack_end($tree_sw, 1, 1, 0);
+$vbox->pack_end($layout_sw, 1, 1, 0);
+
+$window->add($vbox);
+$window->show_all();
+$window->set_size_request(500,500);
+
+Glib::Timeout->add(1000, "copy_tree", undef, Glib::G_PRIORITY_DEFAULT);
+copy_tree();
+
+Gtk2->main();
+
diff --git a/contrib/i3-wsbar b/contrib/i3-wsbar
new file mode 100755 (executable)
index 0000000..a485c15
--- /dev/null
@@ -0,0 +1,290 @@
+#!/usr/bin/env perl
+# vim:ts=4:sw=4:expandtab:ft=perl
+# © 2010 Michael Stapelberg, see LICENSE for license information
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+use IPC::Run qw(start pump);
+use Try::Tiny;
+use AnyEvent::I3;
+use AnyEvent;
+use v5.10;
+
+my $stdin;
+my $socket_path = undef;
+my ($workspaces, $outputs) = ([], {});
+my $last_line = "";
+my $w = AnyEvent->timer(
+    after => 2,
+    cb => sub {
+        say "Connection to i3 timed out. Verify socket path ($socket_path)";
+        exit 1;
+    }
+);
+
+my $command = "";
+my $input_on = "";
+my $output_on = "";
+my $show_all = 0;
+
+my $result = GetOptions(
+    'command=s' => \$command,
+    'socket=s' => \$socket_path,
+    'input-on=s' => \$input_on,
+    'output-on=s' => \$output_on,
+    'show-all' => \$show_all,
+    'help' => sub { pod2usage(1); exit 0 },
+);
+
+if ($command eq '') {
+    say "i3-wsbar is only useful in combination with dzen2.";
+    say "Please specify -c (command)";
+    exit 1;
+}
+
+my $i3 = i3($socket_path);
+
+my @input_on = split(/,/, $input_on);
+my @output_on = split(/,/, $output_on);
+
+# Disable buffering
+$| = 1;
+
+# Wait a short amount of time and try to connect to i3 again
+sub reconnect {
+    my $timer;
+    if (!defined($w)) {
+        $w = AnyEvent->timer(
+            after => 2,
+            cb => sub {
+                say "Connection to i3 timed out. Verify socket path ($socket_path)";
+                exit 1;
+            }
+        );
+    }
+
+    my $c = sub {
+        $timer = AnyEvent->timer(
+            after => 0.01,
+            cb => sub { $i3->connect->cb(\&connected) }
+        );
+    };
+    $c->();
+}
+
+# Connection attempt succeeded or failed
+sub connected {
+    my ($cv) = @_;
+
+    if (!$cv->recv) {
+        reconnect();
+        return;
+    }
+
+    $w = undef;
+
+    $i3->subscribe({
+        workspace => \&ws_change,
+        output => \&output_change,
+        _error => sub { reconnect() }
+    });
+    ws_change();
+    output_change();
+}
+
+# Called when a ws changes
+sub ws_change {
+    # Request the current workspaces and update the output afterwards
+    $i3->get_workspaces->cb(
+        sub {
+            my ($cv) = @_;
+            $workspaces = $cv->recv;
+            update_output();
+        });
+}
+
+# Called when the reply to the GET_OUTPUTS message arrives
+# Compares old outputs with new outputs and starts/kills
+# $command for each output (if specified)
+sub got_outputs {
+    my $reply = shift->recv;
+    my %old = %{$outputs};
+    my %new = map { ($_->{name}, $_) } grep { $_->{active} } @{$reply};
+
+    # If no command was given, we do not need to compare outputs
+    if ($command eq '') {
+        update_output();
+        return;
+    }
+
+    # Handle new outputs
+    for my $name (keys %new) {
+        next if @output_on and !($name ~~ @output_on);
+
+        if (defined($old{$name})) {
+            # Check if the mode changed (by reversing the hashes so
+            # that we can check for equality using the smartmatch op)
+            my %oldrect = reverse %{$old{$name}->{rect}};
+            my %newrect = reverse %{$new{$name}->{rect}};
+            next if (%oldrect ~~ %newrect);
+
+            # On mode changes, we re-start the command
+            $outputs->{$name}->{cmd}->finish;
+            delete $outputs->{$name};
+        }
+
+        my $x = $new{$name}->{rect}->{x};
+        my $w = $new{$name}->{rect}->{width};
+        my $launch = $command;
+        $launch =~ s/([^%])%x/$1$x/g;
+        $launch =~ s/([^%])%w/$1$w/g;
+        $launch =~ s/%%x/%x/g;
+        $launch =~ s/%%w/%w/g;
+
+        $new{$name}->{cmd_input} = '';
+        my @cmd = ('/bin/sh', '-c', $launch);
+        $new{$name}->{cmd} = start \@cmd, \$new{$name}->{cmd_input};
+        $outputs->{$name} = $new{$name};
+    }
+
+    # Handle old outputs
+    for my $name (keys %old) {
+        next if defined($new{$name});
+
+        $outputs->{$name}->{cmd}->finish;
+        delete $outputs->{$name};
+    }
+
+    update_output();
+}
+
+sub output_change {
+    $i3->get_outputs->cb(\&got_outputs)
+}
+
+sub update_output {
+    my $dzen_bg = "#111111";
+    my $out;
+    my $previous_output;
+
+    for my $name (keys %{$outputs}) {
+        my $width = $outputs->{$name}->{rect}->{width};
+
+        $previous_output = undef;
+        $out = qq|^pa(;2)|;
+        for my $ws (@{$workspaces}) {
+            next if $ws->{output} ne $name and !$show_all;
+
+            # Display a separator if we are on a different output now
+            if (defined($previous_output) and
+                ($ws->{output} ne $previous_output)) {
+                $out .= qq|^fg(#900000)^ib(1)\|^ib(0)^p(+4)|;
+            }
+            $previous_output = $ws->{output};
+
+            my ($bg, $fg) = qw(333333 888888);
+            ($bg, $fg) = qw(4c7899 ffffff) if $ws->{visible};
+            ($bg, $fg) = qw(900000 ffffff) if $ws->{urgent};
+
+            my $cmd = q|i3-msg "workspace | . $ws->{name} . q|"|;
+            my $name = $ws->{name};
+
+            # Begin the clickable area
+            $out .= qq|^ca(1,$cmd)|;
+
+            # Draw the rest of the bar in the background color, but
+            # don’t move the "cursor"
+            $out .= qq|^p(_LOCK_X)^fg(#$bg)^r(${width}x17)^p(_UNLOCK_X)|;
+            # Draw the name of the workspace without overwriting the
+            # background color
+            $out .= qq|^p(+3)^fg(#$fg)^ib(1)$name^ib(0)^p(+5)|;
+            # Draw the rest of the bar in the normal background color
+            # without moving the "cursor"
+            $out .= qq|^p(_LOCK_X)^fg($dzen_bg)^r(${width}x17)^p(_UNLOCK_X)|;
+
+            # End the clickable area
+            $out .= qq|^ca()|;
+
+            # Move to the next rect, reset Y coordinate
+            $out .= qq|^p(2)^pa(;2)|;
+        }
+
+        $out .= qq|^p(_LOCK_X)^fg($dzen_bg)^r(${width}x17)^p(_UNLOCK_X)^fg()|;
+        $out .= qq|^p(+5)|;
+        $out .= $last_line if (!@input_on or $name ~~ @input_on);
+        $out .= "\n";
+
+        $outputs->{$name}->{cmd_input} = $out;
+        try {
+            pump $outputs->{$name}->{cmd} while length $outputs->{$name}->{cmd_input};
+        } catch {
+            warn "Could not write to dzen2";
+            exit 1;
+        }
+    }
+}
+
+$i3->connect->cb(\&connected);
+
+$stdin = AnyEvent->io(
+    fh => \*STDIN,
+    poll => 'r',
+    cb => sub {
+        my $line = <STDIN>;
+        if (!defined($line)) {
+            undef $stdin;
+            return;
+        }
+        chomp($line);
+        $last_line = $line;
+        update_output();
+    });
+
+# let AnyEvent do the rest ("endless loop")
+AnyEvent->condvar->recv
+
+__END__
+
+=head1 NAME
+
+i3-wsbar - sample implementation of a standalone workspace bar
+
+=head1 SYNOPSIS
+
+i3-wsbar -c <dzen2-commandline> [options]
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--command> <command>
+
+This command (at the moment only dzen2 is supported) will be started for each
+output. C<%x> will be replaced with the X coordinate of the output, C<%w> will
+be replaced with the width of the output.
+
+Example:
+    --command "dzen2 -dock -x %x -w %w"
+
+=item B<--input-on> <list-of-RandR-outputs>
+
+Specifies on which outputs the contents of stdin should be appended to the
+workspace bar.
+
+Example:
+    --input-on "LVDS1"
+
+=item B<--output-on> <list-of-RandR-outputs>
+
+Specifies for which outputs i3-wsbar should start C<command>.
+
+=item B<--show-all>
+
+If enabled, all workspaces are shown (not only those of the current output).
+Handy to use with C<--output-on>.
+
+=back
+
+=cut
diff --git a/contrib/show-download-count.sh b/contrib/show-download-count.sh
new file mode 100644 (file)
index 0000000..95b955a
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+# © 2012 Han Boetes <han@mijncomputer.nl> (see also: LICENSE)
+YEAR=`date "+%Y"`
+weblog=$(mktemp)
+zcat $(find /var/log/lighttpd/build.i3wm.org -type f -name "access.log.*.gz" | sort | tail -5) > $weblog
+# this will match the latest logfile, which is not yet gzipped
+find /var/log/lighttpd/build.i3wm.org/log$YEAR -type f \! -name "access.log.*.gz" -exec cat '{}' \; >> $weblog
+cat /var/log/lighttpd/build.i3wm.org/access.log >> $weblog
+gitlog=$(mktemp)
+# create a git output logfile. Only keep the first 6 chars of the release hash
+git log -150 --pretty='        %h %s' next > $gitlog
+
+awk '/i3-wm_.*\.deb/ {print $7}' $weblog|awk -F'/' '{print $NF}'|awk -F'_' '{print $2 }'|awk -F'-' '{print $NF}' |cut -c 2-8|sort |uniq -c | while read line; do
+    set -- $line
+    # $1 is the number of downloads, $2 is the release md5sum
+    sed -i "/$2/s|^        |$(printf '%3i' $1) d/l |" $gitlog
+done
+
+cat $gitlog
+rm $gitlog
+rm $weblog
diff --git a/dump-asy.pl b/dump-asy.pl
deleted file mode 100755 (executable)
index a8eab04..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env perl
-# vim:ts=4:sw=4:expandtab
-# renders the layout tree using asymptote
-
-use strict;
-use warnings;
-use Data::Dumper;
-use AnyEvent::I3;
-use File::Temp;
-use v5.10;
-
-my $i3 = i3("/tmp/nestedcons");
-
-my $tree = $i3->get_tree->recv;
-
-my $tmp = File::Temp->new(UNLINK => 0, SUFFIX => '.asy');
-
-say $tmp "import drawtree;";
-
-say $tmp "treeLevelStep = 2cm;";
-
-sub dump_node {
-       my ($n, $parent) = @_;
-
-    my $o = ($n->{orientation} eq 'none' ? "u" : ($n->{orientation} eq 'horizontal' ? "h" : "v"));
-    my $w = (defined($n->{window}) ? $n->{window} : "N");
-    my $na = $n->{name};
-    $na =~ s/#/\\#/g;
-    my $name = "($na, $o, $w)";
-
-    print $tmp "TreeNode n" . $n->{id} . " = makeNode(";
-
-    print $tmp "n" . $parent->{id} . ", " if defined($parent);
-    print $tmp "\"" . $name . "\");\n";
-
-       dump_node($_, $n) for @{$n->{nodes}};
-}
-
-dump_node($tree);
-say $tmp "draw(n" . $tree->{id} . ", (0, 0));";
-
-close($tmp);
-my $rep = "$tmp";
-$rep =~ s/asy$/eps/;
-system("cd /tmp && asy $tmp && gv $rep && rm $rep");
diff --git a/gtk-tree-watch.pl b/gtk-tree-watch.pl
deleted file mode 100755 (executable)
index f15d0c1..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/usr/bin/env perl
-# vim:ts=4:sw=4:expandtab
-# renders the layout tree using asymptote
-
-use strict;
-use warnings;
-
-use JSON::XS;
-use Data::Dumper;
-use AnyEvent::I3;
-use v5.10;
-
-use Gtk2 '-init';
-use Gtk2::SimpleMenu;
-use Glib qw/TRUE FALSE/;
-
-my $window = Gtk2::Window->new('toplevel');
-$window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
-
-my $tree_store = Gtk2::TreeStore->new(qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/, qw/Glib::String/);
-
-my $i3 = i3("/tmp/nestedcons");
-
-my $tree_view = Gtk2::TreeView->new($tree_store);
-
-my $layout_box = undef;
-
-sub copy_node {
-    my ($n, $parent, $piter, $pbox) = @_;
-
-    my $o = ($n->{orientation} == 0 ? "u" : ($n->{orientation} == 1 ? "h" : "v"));
-    my $w = (defined($n->{window}) ? $n->{window} : "N");
-
-    # convert a rectangle struct to X11 notation (WxH+X+Y)
-    my $r = $n->{rect};
-    my $x = $r->{x};
-    my $y = $r->{y};
-    my $dim = $r->{width}."x".$r->{height}.($x<0?$x:"+$x").($y<0?$y:"+$y");
-
-    # add node to the tree with all known properties
-    my $iter = $tree_store->append($piter);
-    $tree_store->set($iter, 0 => $n->{name}, 1 => $w, 2 => $o, 3 => sprintf("0x%08x", $n->{id}), 4 => $n->{urgent}, 5 => $n->{focused}, 6 => $n->{layout}, 7 => $dim);
-
-    # also create a box for the node, each node has a vbox
-    # for combining the title (and properties) with the
-    # container itself, the container will be empty in case
-    # of no children, a vbox or hbox
-    my $box;
-    if($n->{orientation} == 1) {
-        $box = Gtk2::HBox->new(1, 5);
-    } else {
-        $box = Gtk2::VBox->new(1, 5);
-    }
-
-    # combine label and container
-    my $node = Gtk2::Frame->new($n->{name}.",".$o.",".$w);
-    $node->set_shadow_type('etched-out');
-    $node->add($box);
-
-    # the parent is added onto a scrolled window, so add it with a viewport
-    if(defined($pbox)) {
-       $pbox->pack_start($node, 1, 1, 0);
-    } else {
-       $layout_box = $node;
-    }
-
-    # recurse into children
-    copy_node($_, $n, $iter, $box) for @{$n->{nodes}};
-
-    # if it is a window draw a nice color
-    if(defined($n->{window})) {
-       # use a drawing area to fill a colored rectangle
-       my $area = Gtk2::DrawingArea->new();
-
-       # the color is stored as hex in the name
-       $area->{"user-data"} = $n->{name};
-
-       $area->signal_connect(expose_event => sub {
-           my ($widget, $event) = @_;
-
-           # fetch a cairo context and it width/height to start drawing nodes
-           my $cr = Gtk2::Gdk::Cairo::Context->create($widget->window());
-
-           my $w = $widget->allocation->width;
-           my $h = $widget->allocation->height;
-
-           my $hc  = $widget->{"user-data"};
-           my $r = hex(substr($hc, 1, 2)) / 255.0;
-           my $g = hex(substr($hc, 3, 2)) / 255.0;
-           my $b = hex(substr($hc, 5, 2)) / 255.0;
-
-           $cr->set_source_rgb($r, $g, $b);
-           $cr->rectangle(0, 0, $w, $h);
-           $cr->fill();
-
-        return FALSE;
-       });
-
-    $box->pack_end($area, 1, 1, 0);
-    }
-}
-
-# Replaced by Gtk2 Boxes:
-#sub draw_node {
-#    my ($n, $cr, $x, $y, $w, $h) = @_;
-#
-#    $cr->set_source_rgb(1.0, 1.0, 1.0);
-#    $cr->rectangle($x, $y, $w/2, $h/2);
-#    $cr->fill();
-#}
-
-my $json_prev = "";
-
-my $layout_sw = Gtk2::ScrolledWindow->new(undef, undef);
-my $layout_container = Gtk2::HBox->new(0, 0);
-$layout_sw->add_with_viewport($layout_container);
-
-sub copy_tree {
-    my $tree = $i3->get_tree->recv;
-
-    # convert the tree back to json so we only rebuild/redraw when the tree is changed
-    my $json = encode_json($tree);
-    if ($json ne $json_prev) {
-        $json_prev = $json;
-
-        # rebuild the tree and the layout
-        $tree_store->clear();
-        if(defined($layout_box)) {
-            $layout_container->remove($layout_box);
-        }
-        copy_node($tree);
-        $layout_container->add($layout_box);
-        $layout_container->show_all();
-
-        # keep things expanded, otherwise the tree collapses every reload which is more annoying then this :-)
-        $tree_view->expand_all();
-    }
-
-    return(TRUE);
-}
-
-sub new_column {
-    my $tree_column = Gtk2::TreeViewColumn->new();
-    $tree_column->set_title(shift);
-
-    my $renderer = Gtk2::CellRendererText->new();
-    $tree_column->pack_start($renderer, FALSE);
-    $tree_column->add_attribute($renderer, text => shift);
-
-    return($tree_column);
-}
-
-my $col = 0;
-$tree_view->append_column(new_column("Name", $col++));
-$tree_view->append_column(new_column("Window", $col++));
-$tree_view->append_column(new_column("Orientation", $col++));
-$tree_view->append_column(new_column("ID", $col++));
-$tree_view->append_column(new_column("Urgent", $col++));
-$tree_view->append_column(new_column("Focused", $col++));
-$tree_view->append_column(new_column("Layout", $col++));
-$tree_view->append_column(new_column("Rect", $col++));
-
-$tree_view->set_grid_lines("both");
-
-my $tree_sw = Gtk2::ScrolledWindow->new(undef, undef);
-$tree_sw->add($tree_view);
-
-# Replaced by Gtk2 Boxes:
-#my $area = Gtk2::DrawingArea->new();
-#$area->signal_connect(expose_event => sub {
-#    my ($widget, $event) = @_;
-#
-#    # fetch a cairo context and it width/height to start drawing nodes
-#    my $cr = Gtk2::Gdk::Cairo::Context->create($widget->window());
-#
-#    my $w = $widget->allocation->width;
-#    my $h = $widget->allocation->height;
-#
-#    draw_node($gtree, $cr, 0, 0, $w, $h);
-#
-#    return FALSE;
-#});
-
-sub menu_export {
-    print("TODO: EXPORT\n");
-}
-
-my $menu_tree = [
-       _File => {
-               item_type => '<Branch>',
-               children => [
-                       _Export => {
-                               callback => \&menu_export,
-                               accelerator => '<ctrl>E',
-                       },
-                       _Quit => {
-                               callback => sub { Gtk2->main_quit; },
-                               accelerator => '<ctrl>Q',
-                       },
-               ],
-       },
-];
-
-my $menu = Gtk2::SimpleMenu->new(menu_tree => $menu_tree);
-
-my $vbox = Gtk2::VBox->new(0, 0);
-$vbox->pack_start($menu->{widget}, 0, 0, 0);
-$vbox->pack_end($tree_sw, 1, 1, 0);
-$vbox->pack_end($layout_sw, 1, 1, 0);
-
-$window->add($vbox);
-$window->show_all();
-$window->set_size_request(500,500);
-
-Glib::Timeout->add(1000, "copy_tree", undef, Glib::G_PRIORITY_DEFAULT);
-copy_tree();
-
-Gtk2->main();
-
diff --git a/i3-wsbar b/i3-wsbar
deleted file mode 100755 (executable)
index a485c15..0000000
--- a/i3-wsbar
+++ /dev/null
@@ -1,290 +0,0 @@
-#!/usr/bin/env perl
-# vim:ts=4:sw=4:expandtab:ft=perl
-# © 2010 Michael Stapelberg, see LICENSE for license information
-
-use strict;
-use warnings;
-use Getopt::Long;
-use Pod::Usage;
-use IPC::Run qw(start pump);
-use Try::Tiny;
-use AnyEvent::I3;
-use AnyEvent;
-use v5.10;
-
-my $stdin;
-my $socket_path = undef;
-my ($workspaces, $outputs) = ([], {});
-my $last_line = "";
-my $w = AnyEvent->timer(
-    after => 2,
-    cb => sub {
-        say "Connection to i3 timed out. Verify socket path ($socket_path)";
-        exit 1;
-    }
-);
-
-my $command = "";
-my $input_on = "";
-my $output_on = "";
-my $show_all = 0;
-
-my $result = GetOptions(
-    'command=s' => \$command,
-    'socket=s' => \$socket_path,
-    'input-on=s' => \$input_on,
-    'output-on=s' => \$output_on,
-    'show-all' => \$show_all,
-    'help' => sub { pod2usage(1); exit 0 },
-);
-
-if ($command eq '') {
-    say "i3-wsbar is only useful in combination with dzen2.";
-    say "Please specify -c (command)";
-    exit 1;
-}
-
-my $i3 = i3($socket_path);
-
-my @input_on = split(/,/, $input_on);
-my @output_on = split(/,/, $output_on);
-
-# Disable buffering
-$| = 1;
-
-# Wait a short amount of time and try to connect to i3 again
-sub reconnect {
-    my $timer;
-    if (!defined($w)) {
-        $w = AnyEvent->timer(
-            after => 2,
-            cb => sub {
-                say "Connection to i3 timed out. Verify socket path ($socket_path)";
-                exit 1;
-            }
-        );
-    }
-
-    my $c = sub {
-        $timer = AnyEvent->timer(
-            after => 0.01,
-            cb => sub { $i3->connect->cb(\&connected) }
-        );
-    };
-    $c->();
-}
-
-# Connection attempt succeeded or failed
-sub connected {
-    my ($cv) = @_;
-
-    if (!$cv->recv) {
-        reconnect();
-        return;
-    }
-
-    $w = undef;
-
-    $i3->subscribe({
-        workspace => \&ws_change,
-        output => \&output_change,
-        _error => sub { reconnect() }
-    });
-    ws_change();
-    output_change();
-}
-
-# Called when a ws changes
-sub ws_change {
-    # Request the current workspaces and update the output afterwards
-    $i3->get_workspaces->cb(
-        sub {
-            my ($cv) = @_;
-            $workspaces = $cv->recv;
-            update_output();
-        });
-}
-
-# Called when the reply to the GET_OUTPUTS message arrives
-# Compares old outputs with new outputs and starts/kills
-# $command for each output (if specified)
-sub got_outputs {
-    my $reply = shift->recv;
-    my %old = %{$outputs};
-    my %new = map { ($_->{name}, $_) } grep { $_->{active} } @{$reply};
-
-    # If no command was given, we do not need to compare outputs
-    if ($command eq '') {
-        update_output();
-        return;
-    }
-
-    # Handle new outputs
-    for my $name (keys %new) {
-        next if @output_on and !($name ~~ @output_on);
-
-        if (defined($old{$name})) {
-            # Check if the mode changed (by reversing the hashes so
-            # that we can check for equality using the smartmatch op)
-            my %oldrect = reverse %{$old{$name}->{rect}};
-            my %newrect = reverse %{$new{$name}->{rect}};
-            next if (%oldrect ~~ %newrect);
-
-            # On mode changes, we re-start the command
-            $outputs->{$name}->{cmd}->finish;
-            delete $outputs->{$name};
-        }
-
-        my $x = $new{$name}->{rect}->{x};
-        my $w = $new{$name}->{rect}->{width};
-        my $launch = $command;
-        $launch =~ s/([^%])%x/$1$x/g;
-        $launch =~ s/([^%])%w/$1$w/g;
-        $launch =~ s/%%x/%x/g;
-        $launch =~ s/%%w/%w/g;
-
-        $new{$name}->{cmd_input} = '';
-        my @cmd = ('/bin/sh', '-c', $launch);
-        $new{$name}->{cmd} = start \@cmd, \$new{$name}->{cmd_input};
-        $outputs->{$name} = $new{$name};
-    }
-
-    # Handle old outputs
-    for my $name (keys %old) {
-        next if defined($new{$name});
-
-        $outputs->{$name}->{cmd}->finish;
-        delete $outputs->{$name};
-    }
-
-    update_output();
-}
-
-sub output_change {
-    $i3->get_outputs->cb(\&got_outputs)
-}
-
-sub update_output {
-    my $dzen_bg = "#111111";
-    my $out;
-    my $previous_output;
-
-    for my $name (keys %{$outputs}) {
-        my $width = $outputs->{$name}->{rect}->{width};
-
-        $previous_output = undef;
-        $out = qq|^pa(;2)|;
-        for my $ws (@{$workspaces}) {
-            next if $ws->{output} ne $name and !$show_all;
-
-            # Display a separator if we are on a different output now
-            if (defined($previous_output) and
-                ($ws->{output} ne $previous_output)) {
-                $out .= qq|^fg(#900000)^ib(1)\|^ib(0)^p(+4)|;
-            }
-            $previous_output = $ws->{output};
-
-            my ($bg, $fg) = qw(333333 888888);
-            ($bg, $fg) = qw(4c7899 ffffff) if $ws->{visible};
-            ($bg, $fg) = qw(900000 ffffff) if $ws->{urgent};
-
-            my $cmd = q|i3-msg "workspace | . $ws->{name} . q|"|;
-            my $name = $ws->{name};
-
-            # Begin the clickable area
-            $out .= qq|^ca(1,$cmd)|;
-
-            # Draw the rest of the bar in the background color, but
-            # don’t move the "cursor"
-            $out .= qq|^p(_LOCK_X)^fg(#$bg)^r(${width}x17)^p(_UNLOCK_X)|;
-            # Draw the name of the workspace without overwriting the
-            # background color
-            $out .= qq|^p(+3)^fg(#$fg)^ib(1)$name^ib(0)^p(+5)|;
-            # Draw the rest of the bar in the normal background color
-            # without moving the "cursor"
-            $out .= qq|^p(_LOCK_X)^fg($dzen_bg)^r(${width}x17)^p(_UNLOCK_X)|;
-
-            # End the clickable area
-            $out .= qq|^ca()|;
-
-            # Move to the next rect, reset Y coordinate
-            $out .= qq|^p(2)^pa(;2)|;
-        }
-
-        $out .= qq|^p(_LOCK_X)^fg($dzen_bg)^r(${width}x17)^p(_UNLOCK_X)^fg()|;
-        $out .= qq|^p(+5)|;
-        $out .= $last_line if (!@input_on or $name ~~ @input_on);
-        $out .= "\n";
-
-        $outputs->{$name}->{cmd_input} = $out;
-        try {
-            pump $outputs->{$name}->{cmd} while length $outputs->{$name}->{cmd_input};
-        } catch {
-            warn "Could not write to dzen2";
-            exit 1;
-        }
-    }
-}
-
-$i3->connect->cb(\&connected);
-
-$stdin = AnyEvent->io(
-    fh => \*STDIN,
-    poll => 'r',
-    cb => sub {
-        my $line = <STDIN>;
-        if (!defined($line)) {
-            undef $stdin;
-            return;
-        }
-        chomp($line);
-        $last_line = $line;
-        update_output();
-    });
-
-# let AnyEvent do the rest ("endless loop")
-AnyEvent->condvar->recv
-
-__END__
-
-=head1 NAME
-
-i3-wsbar - sample implementation of a standalone workspace bar
-
-=head1 SYNOPSIS
-
-i3-wsbar -c <dzen2-commandline> [options]
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<--command> <command>
-
-This command (at the moment only dzen2 is supported) will be started for each
-output. C<%x> will be replaced with the X coordinate of the output, C<%w> will
-be replaced with the width of the output.
-
-Example:
-    --command "dzen2 -dock -x %x -w %w"
-
-=item B<--input-on> <list-of-RandR-outputs>
-
-Specifies on which outputs the contents of stdin should be appended to the
-workspace bar.
-
-Example:
-    --input-on "LVDS1"
-
-=item B<--output-on> <list-of-RandR-outputs>
-
-Specifies for which outputs i3-wsbar should start C<command>.
-
-=item B<--show-all>
-
-If enabled, all workspaces are shown (not only those of the current output).
-Handy to use with C<--output-on>.
-
-=back
-
-=cut
diff --git a/show-download-count.sh b/show-download-count.sh
deleted file mode 100644 (file)
index 95b955a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-# © 2012 Han Boetes <han@mijncomputer.nl> (see also: LICENSE)
-YEAR=`date "+%Y"`
-weblog=$(mktemp)
-zcat $(find /var/log/lighttpd/build.i3wm.org -type f -name "access.log.*.gz" | sort | tail -5) > $weblog
-# this will match the latest logfile, which is not yet gzipped
-find /var/log/lighttpd/build.i3wm.org/log$YEAR -type f \! -name "access.log.*.gz" -exec cat '{}' \; >> $weblog
-cat /var/log/lighttpd/build.i3wm.org/access.log >> $weblog
-gitlog=$(mktemp)
-# create a git output logfile. Only keep the first 6 chars of the release hash
-git log -150 --pretty='        %h %s' next > $gitlog
-
-awk '/i3-wm_.*\.deb/ {print $7}' $weblog|awk -F'/' '{print $NF}'|awk -F'_' '{print $2 }'|awk -F'-' '{print $NF}' |cut -c 2-8|sort |uniq -c | while read line; do
-    set -- $line
-    # $1 is the number of downloads, $2 is the release md5sum
-    sed -i "/$2/s|^        |$(printf '%3i' $1) d/l |" $gitlog
-done
-
-cat $gitlog
-rm $gitlog
-rm $weblog