Skip to content

Commit 66dbb66

Browse files
committed
Beginnings of a GUI in vala
1 parent 91546d1 commit 66dbb66

File tree

5 files changed

+485
-0
lines changed

5 files changed

+485
-0
lines changed

appimageupdategui/build.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
if [ "$(which apt-get)" != "" ] ; then
4+
add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) universe"
5+
add-apt-repository -y ppa:vala-team
6+
apt-get update
7+
apt-get -y install libgtk-3-dev valac-0.30 clang cmake libvala-0.30 git
8+
fi
9+
10+
if [ "(which yum)" != "" ] ; then
11+
yum -y install gtk3-devel vala clang cmake vala-devel
12+
fi
13+
14+
valac --pkg 'gtk+-3.0' --pkg 'gmodule-2.0' --pkg posix main.vala progress.vala -o appimageupdategui -v
15+
strip appimageupdategui

appimageupdategui/main.vala

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using GLib;
2+
using Gtk;
3+
4+
static Window window_main;
5+
static Gtk.Menu main_menu;
6+
static Gtk.Menu popup_menu; // Too new to assume it is there?
7+
static HeaderBar header_bar; // Too new to assume it is there?
8+
9+
static string selected_file;
10+
11+
/* Open file */
12+
static void open_file(string filename) {
13+
selected_file = filename;
14+
new ProgressWindow(selected_file, {});
15+
}
16+
17+
/* Handle open click event */
18+
static void on_open_clicked() {
19+
20+
var file_chooser = new FileChooserDialog ("Open File", window_main,
21+
FileChooserAction.OPEN,
22+
"gtk-cancel", ResponseType.CANCEL,
23+
"gtk-ok", ResponseType.ACCEPT);
24+
FileFilter filter = new FileFilter ();
25+
file_chooser.set_filter (filter);
26+
filter.add_pattern("*.AppImage");
27+
filter.add_pattern("*.iso");
28+
if (file_chooser.run () == ResponseType.ACCEPT) {
29+
open_file(file_chooser.get_filename ());
30+
}
31+
file_chooser.destroy ();
32+
}
33+
34+
/* Handle about click event */
35+
static void on_about_clicked() {
36+
show_about_dialog (window_main,
37+
"program-name", ("AppImageUpdate"),
38+
"copyright", ("Copyright © 2015 Simon Peter"),
39+
"version", "@@@VERSION@@@" // To be replaced e.g., with the git tag during the build process
40+
);
41+
}
42+
43+
static void main (string[] args) {
44+
init (ref args);
45+
46+
/* Set up the main window */
47+
window_main = new Window();
48+
window_main.title = "AppImageUpdate";
49+
window_main.set_default_size (800, 600);
50+
window_main.destroy.connect (main_quit);
51+
52+
/* Set app icon */
53+
try {
54+
window_main.icon = new Gdk.Pixbuf.from_file("appimageupdate.svg");
55+
} catch (Error e) {
56+
stderr.printf ("Could not load application icon: %s\n", e.message);
57+
}
58+
59+
/* Vertical box containing widgets */
60+
var vbox_main = new Box (Orientation.VERTICAL, 0);
61+
62+
/* Init headerbar for app title and buttons */
63+
header_bar = new HeaderBar();
64+
header_bar.set_title(window_main.title);
65+
header_bar.show_close_button = true;
66+
window_main.set_titlebar(header_bar);
67+
68+
var btn_menu = new MenuButton();
69+
var btn_open = new Button();
70+
71+
var menu_icon = new Image.from_icon_name("gtk-menu" , IconSize.LARGE_TOOLBAR);
72+
var open_icon = new Image.from_icon_name("gtk-open" , IconSize.LARGE_TOOLBAR);
73+
74+
var builder = new Builder();
75+
try {
76+
builder.add_from_file ("ui/menu.ui");
77+
}
78+
catch (Error e) {
79+
error ("Unable to load file: %s", e.message);
80+
}
81+
builder.connect_signals (null);
82+
main_menu = builder.get_object("main_menu") as Gtk.Menu;
83+
var open_item = builder.get_object("open") as Gtk.MenuItem;
84+
var about_item = builder.get_object("about") as Gtk.MenuItem;
85+
open_item.activate.connect (on_open_clicked);
86+
about_item.activate.connect (on_about_clicked);
87+
88+
popup_menu = builder.get_object("popup_menu") as Gtk.Menu;
89+
90+
btn_menu.set_popup(main_menu);
91+
btn_menu.set_image(menu_icon);
92+
btn_open.set_image(open_icon);
93+
94+
btn_open.set_tooltip_text("Open");
95+
96+
header_bar.pack_start(btn_open);
97+
header_bar.pack_end(btn_menu);
98+
99+
vbox_main.pack_start(header_bar, false, true);
100+
101+
window_main.add (vbox_main);
102+
103+
window_main.show_all();
104+
105+
on_open_clicked();
106+
107+
Gtk.main();
108+
}

appimageupdategui/progress.vala

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
using Gtk;
2+
3+
public class ProgressWindow : Window {
4+
5+
private string file_name;
6+
private string[] files_to_be_updated;
7+
private int counter;
8+
private int file_counts;
9+
10+
private ProgressBar progress;
11+
12+
private Label action_label;
13+
private Label message_label;
14+
15+
private Button btn_cancel;
16+
private Button btn_show_files;
17+
private Button btn_quit;
18+
19+
private Pid child_pid;
20+
21+
22+
public ProgressWindow(string file_name, string[] files_to_be_updated) {
23+
var builder = new Builder();
24+
try {
25+
builder.add_from_file ("ui/progress.ui");
26+
}
27+
catch (Error e) {
28+
error ("Unable to load file: %s", e.message);
29+
}
30+
31+
action_label = builder.get_object("action_label") as Label;
32+
action_label.set_vexpand(false);
33+
34+
message_label = builder.get_object("message_label") as Label;
35+
progress = builder.get_object("progress_progressbar") as ProgressBar;
36+
37+
this.title = "Updating " + file_name;
38+
this.window_position = WindowPosition.CENTER;
39+
40+
/* Set app icon */
41+
try {
42+
this.icon = new Gdk.Pixbuf.from_file("appimageupdate");
43+
} catch (Error e) {
44+
stderr.printf ("Could not load application icon: %s\n", e.message);
45+
}
46+
47+
var vbox = builder.get_object("main_box") as Box;
48+
add(vbox);
49+
50+
btn_cancel = builder.get_object("btn_cancel") as Button;
51+
btn_cancel.clicked.connect(cancel);
52+
53+
btn_quit = builder.get_object("btn_quit") as Button;
54+
btn_quit.clicked.connect(Gtk.main_quit);
55+
btn_quit.set_visible(false);
56+
57+
btn_show_files = builder.get_object("btn_show_files") as Button;
58+
btn_show_files.clicked.connect(this.show_files);
59+
btn_show_files.set_visible(false);
60+
61+
this.files_to_be_updated = files_to_be_updated;
62+
this.file_name = file_name;
63+
64+
counter = 0;
65+
this.show_all();
66+
67+
update();
68+
}
69+
70+
private void update() {
71+
try {
72+
int extra_args = 0;
73+
74+
string[] spawn_args = new string[8 + files_to_be_updated.length + extra_args];
75+
spawn_args[0] = "appimageupdate";
76+
spawn_args[1] = this.file_name;
77+
78+
string[] spawn_env = Environ.get ();
79+
int standard_error;
80+
int standard_out;
81+
82+
string a_string = string.joinv(" ", spawn_args);
83+
stdout.printf(a_string);
84+
85+
Process.spawn_async_with_pipes ("/",
86+
spawn_args,
87+
spawn_env,
88+
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
89+
null,
90+
out child_pid,
91+
null,
92+
out standard_out,
93+
out standard_error);
94+
95+
// stdout:
96+
IOChannel output = new IOChannel.unix_new (standard_out);
97+
output.add_watch (IOCondition.IN | IOCondition.HUP, (channel, condition) => {
98+
return this.process_line (channel, condition, "stdout");
99+
});
100+
101+
// stderr:
102+
IOChannel error = new IOChannel.unix_new (standard_error);
103+
error.add_watch (IOCondition.IN | IOCondition.HUP, (channel, condition) => {
104+
return this.process_error (channel, condition, "stderr");
105+
});
106+
107+
ChildWatch.add (child_pid, (pid, status) => {
108+
// Triggered when the child indicated by child_pid exits
109+
Process.close_pid (pid);
110+
btn_cancel.set_label("Close");
111+
btn_quit.set_visible(true);
112+
btn_show_files.set_visible(true);
113+
});
114+
115+
} catch (SpawnError e) {
116+
action_label.label = "Error: " + e.message;
117+
}
118+
119+
}
120+
121+
/* Handle output pipe */
122+
private bool process_line (IOChannel channel, IOCondition condition, string stream_name) {
123+
if (condition == IOCondition.HUP) {
124+
// action_label.label = "Done";
125+
return false;
126+
}
127+
128+
try {
129+
string line;
130+
channel.read_line (out line, null, null);
131+
stdout.printf(line); // Be verbose
132+
file_counts = 12; // TODO: Get from command line output
133+
action_label.label = "Updating: " + line.substring(0, line.length - 1);
134+
counter++;
135+
progress.set_fraction( 1.0f * counter / file_counts);
136+
137+
} catch (IOChannelError e) {
138+
stdout.printf ("%s: IOChannelError: %s\n", stream_name, e.message);
139+
return false;
140+
} catch (ConvertError e) {
141+
stdout.printf ("%s: ConvertError: %s\n", stream_name, e.message);
142+
return false;
143+
}
144+
145+
return true;
146+
}
147+
148+
private bool process_error(IOChannel channel, IOCondition condition, string stream_name) {
149+
if (condition == IOCondition.HUP) {
150+
return false;
151+
}
152+
153+
try {
154+
string line;
155+
channel.read_line (out line, null, null);
156+
stdout.printf(line); // Be verbose
157+
message_label.label = line.substring(0, line.length - 1);
158+
159+
} catch (IOChannelError e) {
160+
stdout.printf ("%s: IOChannelError: %s\n", stream_name, e.message);
161+
return false;
162+
} catch (ConvertError e) {
163+
stdout.printf ("%s: ConvertError: %s\n", stream_name, e.message);
164+
return false;
165+
}
166+
167+
return true;
168+
}
169+
170+
private void show_files() {
171+
// To be implemented
172+
this.close();
173+
}
174+
175+
private void cancel() {
176+
Posix.kill(child_pid, Posix.SIGTERM);
177+
this.close();
178+
}
179+
180+
}

appimageupdategui/ui/menu.ui

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<interface>
3+
<requires lib="gtk+" version="3.10"/>
4+
<object class="GtkMenu" id="main_menu">
5+
<property name="visible">True</property>
6+
<property name="can_focus">False</property>
7+
<child>
8+
<object class="GtkMenuItem" id="open">
9+
<property name="visible">True</property>
10+
<property name="can_focus">False</property>
11+
<property name="label" translatable="yes">Open</property>
12+
<property name="use_underline">True</property>
13+
</object>
14+
</child>
15+
<child>
16+
<object class="GtkMenuItem" id="about">
17+
<property name="visible">True</property>
18+
<property name="can_focus">False</property>
19+
<property name="label" translatable="yes">About</property>
20+
<property name="use_underline">True</property>
21+
</object>
22+
</child>
23+
<child>
24+
<object class="GtkMenuItem" id="exit">
25+
<property name="visible">True</property>
26+
<property name="can_focus">False</property>
27+
<property name="label" translatable="yes">Exit</property>
28+
<property name="use_underline">True</property>
29+
</object>
30+
</child>
31+
</object>
32+
<object class="GtkMenu" id="popup_menu">
33+
<property name="visible">True</property>
34+
<property name="can_focus">False</property>
35+
<child>
36+
<object class="GtkMenuItem" id="view">
37+
<property name="visible">True</property>
38+
<property name="can_focus">False</property>
39+
<property name="label" translatable="yes">View</property>
40+
<property name="use_underline">True</property>
41+
</object>
42+
</child>
43+
<child>
44+
<object class="GtkMenuItem" id="extract">
45+
<property name="visible">True</property>
46+
<property name="can_focus">False</property>
47+
<property name="label" translatable="yes">Update...</property>
48+
<property name="use_underline">True</property>
49+
</object>
50+
</child>
51+
</object>
52+
</interface>

0 commit comments

Comments
 (0)