2 # vim:ts=4:sw=4:expandtab
3 # renders the layout tree using asymptote
15 use Glib qw/TRUE FALSE/;
17 my $window = Gtk2::Window->new('toplevel');
18 $window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
20 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/);
24 my $tree_view = Gtk2::TreeView->new($tree_store);
26 my $layout_box = undef;
29 my ($n, $parent, $piter, $pbox) = @_;
31 my $o = ($n->{orientation} == 0 ? "u" : ($n->{orientation} == 1 ? "h" : "v"));
32 my $w = (defined($n->{window}) ? $n->{window} : "N");
34 # convert a rectangle struct to X11 notation (WxH+X+Y)
38 my $dim = $r->{width}."x".$r->{height}.($x<0?$x:"+$x").($y<0?$y:"+$y");
40 # add node to the tree with all known properties
41 my $iter = $tree_store->append($piter);
42 $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);
44 # also create a box for the node, each node has a vbox
45 # for combining the title (and properties) with the
46 # container itself, the container will be empty in case
47 # of no children, a vbox or hbox
49 if($n->{orientation} == 1) {
50 $box = Gtk2::HBox->new(1, 5);
52 $box = Gtk2::VBox->new(1, 5);
55 # combine label and container
56 my $node = Gtk2::Frame->new($n->{name}.",".$o.",".$w);
57 $node->set_shadow_type('etched-out');
60 # the parent is added onto a scrolled window, so add it with a viewport
62 $pbox->pack_start($node, 1, 1, 0);
67 # recurse into children
68 copy_node($_, $n, $iter, $box) for @{$n->{nodes}};
70 # if it is a window draw a nice color
71 if(defined($n->{window})) {
72 # use a drawing area to fill a colored rectangle
73 my $area = Gtk2::DrawingArea->new();
75 # the color is stored as hex in the name
76 $area->{"user-data"} = $n->{name};
78 $area->signal_connect(expose_event => sub {
79 my ($widget, $event) = @_;
81 # fetch a cairo context and it width/height to start drawing nodes
82 my $cr = Gtk2::Gdk::Cairo::Context->create($widget->window());
84 my $w = $widget->allocation->width;
85 my $h = $widget->allocation->height;
87 my $hc = $widget->{"user-data"};
88 my $r = hex(substr($hc, 1, 2)) / 255.0;
89 my $g = hex(substr($hc, 3, 2)) / 255.0;
90 my $b = hex(substr($hc, 5, 2)) / 255.0;
92 $cr->set_source_rgb($r, $g, $b);
93 $cr->rectangle(0, 0, $w, $h);
99 $box->pack_end($area, 1, 1, 0);
103 # Replaced by Gtk2 Boxes:
105 # my ($n, $cr, $x, $y, $w, $h) = @_;
107 # $cr->set_source_rgb(1.0, 1.0, 1.0);
108 # $cr->rectangle($x, $y, $w/2, $h/2);
114 my $layout_sw = Gtk2::ScrolledWindow->new(undef, undef);
115 my $layout_container = Gtk2::HBox->new(0, 0);
116 $layout_sw->add_with_viewport($layout_container);
119 my $tree = $i3->get_tree->recv;
121 # convert the tree back to json so we only rebuild/redraw when the tree is changed
122 my $json = encode_json($tree);
123 if ($json ne $json_prev) {
126 # rebuild the tree and the layout
127 $tree_store->clear();
128 if(defined($layout_box)) {
129 $layout_container->remove($layout_box);
132 $layout_container->add($layout_box);
133 $layout_container->show_all();
135 # keep things expanded, otherwise the tree collapses every reload which is more annoying then this :-)
136 $tree_view->expand_all();
143 my $tree_column = Gtk2::TreeViewColumn->new();
144 $tree_column->set_title(shift);
146 my $renderer = Gtk2::CellRendererText->new();
147 $tree_column->pack_start($renderer, FALSE);
148 $tree_column->add_attribute($renderer, text => shift);
150 return($tree_column);
154 $tree_view->append_column(new_column("Name", $col++));
155 $tree_view->append_column(new_column("Window", $col++));
156 $tree_view->append_column(new_column("Orientation", $col++));
157 $tree_view->append_column(new_column("ID", $col++));
158 $tree_view->append_column(new_column("Urgent", $col++));
159 $tree_view->append_column(new_column("Focused", $col++));
160 $tree_view->append_column(new_column("Layout", $col++));
161 $tree_view->append_column(new_column("Rect", $col++));
163 $tree_view->set_grid_lines("both");
165 my $tree_sw = Gtk2::ScrolledWindow->new(undef, undef);
166 $tree_sw->add($tree_view);
168 # Replaced by Gtk2 Boxes:
169 #my $area = Gtk2::DrawingArea->new();
170 #$area->signal_connect(expose_event => sub {
171 # my ($widget, $event) = @_;
173 # # fetch a cairo context and it width/height to start drawing nodes
174 # my $cr = Gtk2::Gdk::Cairo::Context->create($widget->window());
176 # my $w = $widget->allocation->width;
177 # my $h = $widget->allocation->height;
179 # draw_node($gtree, $cr, 0, 0, $w, $h);
185 print("TODO: EXPORT\n");
190 item_type => '<Branch>',
193 callback => \&menu_export,
194 accelerator => '<ctrl>E',
197 callback => sub { Gtk2->main_quit; },
198 accelerator => '<ctrl>Q',
204 my $menu = Gtk2::SimpleMenu->new(menu_tree => $menu_tree);
206 my $vbox = Gtk2::VBox->new(0, 0);
207 $vbox->pack_start($menu->{widget}, 0, 0, 0);
208 $vbox->pack_end($tree_sw, 1, 1, 0);
209 $vbox->pack_end($layout_sw, 1, 1, 0);
213 $window->set_size_request(500,500);
215 Glib::Timeout->add(1000, "copy_tree", undef, Glib::G_PRIORITY_DEFAULT);