Start and stop a program (original) (raw)
Hello Vala community,
i want to start and stop a program by toggling a button.
for a simple test, this tries to start/stop another instance of this:
// wat.vala
// valac --pkg gtk4 wat.vala
Subprocess proc;
int main (string[] argv) {
var app = new Gtk.Application(
"com.example.GtkApplication",
ApplicationFlags.DEFAULT_FLAGS
);
app.activate.connect(() => {
var window = new Gtk.ApplicationWindow(app);
var button = new Gtk.ToggleButton.with_label("start");
string[] cmd = {"./wat"};
button.toggled.connect(() => {
var down = button.get_active();
print(@"click $down\n");
if (down) {
try {
proc = new Subprocess.newv(cmd, SubprocessFlags.NONE);
var pid = proc.get_identifier();
print(@"PID ON START: $pid\n");
} catch (Error e) {
print(@"ERROR: $(e.message)\n");
}
button.label = "stop";
} else {
var pid = proc.get_identifier();
if (pid == null) {
print("PID LATER: null\n");
} else {
print(@"PID LATER: $pid\n");
}
proc.force_exit();
button.label = "start";
}
});
window.set_child(button);
window.present();
});
return app.run(argv);
}
but it does not stop the second instance
- click on “start”
- another instance of wat is started
- but why does the “PID ON START” not exist when i look in
ps aux
?
- click on “stop”
- the other instance of wat is not stopped
- why is the “PID LATER” null?
what am i doing wrong?
Cheers
Osku
PS. Vala 0.56.18 on Arch Linux
Sid (Sid) April 9, 2025, 4:42pm 2
The wat
program has already exited by the time you call
ps aux
proc.get_identifier()
You can confirm with following command (e.g. giving sleep time 1 and 100 seconds)
string[] cmd = { "/usr/bin/sleep", "100"};
oskude (Osku) April 9, 2025, 5:55pm 3
Aaah, interesting!
It works for sleep 100
, but why doesn’t it work for above program?
How can i make above code work when starting it’s compiled program?
Sid (Sid) April 9, 2025, 6:18pm 4
From what I see no new process is created, only a new thread within the parent process is created, which I guess is due to the Application ID being the same for the 2 instances, making GIO to launch a thread than a process.
Before clicking Start
button.
bash(11567)---test(28582)-+-{test}(28583)
|-{test}(28584)
|-{test}(28585)
|-{test}(28586)
|-{test}(28588)
|-{test}(28589)
|-{test}(28590)
`-{test}(28591)
After clicking Start
button.
bash(11567)---test(28582)-+-{test}(28583)
|-{test}(28584)
|-{test}(28585)
|-{test}(28586)
|-{test}(28589)
|-{test}(28590)
|-{test}(28591)
`-{test}(28641)
What exactly are you trying to achieve here?
oskude (Osku) April 9, 2025, 7:15pm 5
My current use-case would be to run make foo
, that runs ls
piped to entr
and then valac
… etc, for a simple “build&run on source change” thing (And then parse the output to show in UI, just for fun and learning)
But i guess what i really want is, start any program (even bash -c "..."
) and be able to (parse output and) stop or kill it with a button press.
Sorry, i’m new to Vala and all this system? programming, so i don’t even know if GLib.Subprocess
is the right thing for this, and what is even required for “start and stop any program”
Sid (Sid) April 9, 2025, 7:30pm 6
oskude (Osku) April 10, 2025, 4:59pm 7
Thank you for the tip!
Gtk.Application
or Gtk.ApplicationWindow
indeed seems to do some magic when spawned from the same program. When using only a Gtk.Window
i can now easily stop wat
spawned from wat
. (and is now also shown in ps aux
)
So the first problem is solved
But spawning a bash script, bash -c
, make
, or entr
apparently does some other magic that i just cannot stop as simple as ctrl+c in bash terminal.
I don’t understand much, but just found these:
- GSubprocess: add API to reliably kill descendant sub-process tree (#1135) · Issues · GNOME / GLib · GitLab
- How to make a `GLib.Subprocess` having childs exit responsibly?
- How do I kill all subprocesses spawned by my bash script? - Unix & Linux Stack Exchange
And i only got this to work: pstree -A -p $pid | grep -Eow '[0-9]+' | xargs kill
So here’s my stupid? newbie test that seems to work for my bash/make use-case :
# makefile
.PHONY: build hot
build:
valac -X -w --pkg gtk4 grop.vala
hot:
ls *.vala | entr -rcs 'make build && ./grop'
// grop.vala
public class Thing : Gtk.Window
{
Pid pid;
int stdout;
int stderr;
Gtk.TextView text_view;
public Thing (string cmdline)
{
var box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
var print_btn = new Gtk.Button.with_label("print");
var spawn_tgl = new Gtk.ToggleButton.with_label("start");
text_view = new Gtk.TextView();
text_view.hexpand = true;
text_view.vexpand = true;
text_view.monospace = true;
default_width = 640;
default_height = 480;
print_btn.clicked.connect(()=>{
print("hello world\n");
});
spawn_tgl.toggled.connect(()=>{
bool run = spawn_tgl.get_active();
if (run) {
spawn_tgl.label = "stop";
print("START -------------\n");
spawn_cmdline(cmdline);
} else {
spawn_tgl.label = "start";
print("STOP --------------\n");
kill_cmdline();
}
});
box.append(print_btn);
box.append(spawn_tgl);
box.append(text_view);
set_child(box);
}
private bool process_line (IOChannel channel, IOCondition condition, string stream_name)
{
if (condition == IOCondition.HUP) {
return false;
}
try {
string line;
channel.read_line (out line, null, null);
//print ("%s: %s", stream_name, line);
text_view.buffer.text += @"$stream_name: $line";
} catch (IOChannelError e) {
print ("%s: IOChannelError: %s\n", stream_name, e.message);
return false;
} catch (ConvertError e) {
print ("%s: ConvertError: %s\n", stream_name, e.message);
return false;
}
return true;
}
private void kill_cmdline ()
{
string[] cmd = {"bash", "-c",
@"pstree -A -p $pid | grep -Eow '[0-9]+' | xargs kill"};
string[] env = Environ.get();
print(@"Kill pid tree: $pid\n");
try {
Process.spawn_sync(
".", cmd, env, SpawnFlags.SEARCH_PATH, null, null, null, null
);
} catch (SpawnError e) {
print(@"ERROR killing pid <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mi>i</mi><mi>d</mi><mo>:</mo></mrow><annotation encoding="application/x-tex">pid: </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal">i</span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span>(e.message)\n");
}
}
private void spawn_cmdline (string cmdline)
{
string[] cmd = {"bash", "-c", cmdline};
string[] env = Environ.get();
try {
Process.spawn_async_with_pipes(
".", cmd, env, SpawnFlags.SEARCH_PATH,
null,
out pid,
out stdout,
out stderr
);
print(@"Pid on start: $pid\n");
IOChannel output = new IOChannel.unix_new(stdout);
output.add_watch(IOCondition.IN | IOCondition.HUP, (channel, condition) => {
return process_line (channel, condition, "stdout");
});
IOChannel error = new IOChannel.unix_new(stderr);
error.add_watch(IOCondition.IN | IOCondition.HUP, (channel, condition) => {
return process_line (channel, condition, "stderr");
});
} catch (SpawnError e) {
print(@"ERROR: $(e.message)\n");
}
}
}
int main (string[] args) {
Gtk.init();
//var thing = new Thing("./grop");
var thing = new Thing("make hot");
thing.present();
while (Gtk.Window.get_toplevels ().get_n_items () > 0) {
MainContext.@default ().iteration (true);
}
return 0;
}
usage:
- build and run it:
make && ./grop
- click “print”
- should see “hello world” in terminal
- toggle “start”
- should see messages in first window textview
- should see a new grop window
- click “print” in second grop window
- should see messages in first window textview
- click “stop” in first grop window
- should stop second grop window, and make etc.
oskude (Osku) April 10, 2025, 6:10pm 8
Hups, a small “typo” in the code :face_palm:
index e0d3d18..2fb1c74 100644
--- a/grop.vala
+++ b/grop.vala
@@ -6,6 +6,7 @@ public class Thing : Gtk.Window
int stdout;
int stderr;
Gtk.TextView text_view;
+ bool just_for_the_warning;
public Thing (string cmdline)
{
@@ -83,6 +84,7 @@ public class Thing : Gtk.Window
".", cmd, env, SpawnFlags.SEARCH_PATH,
null,
out pid,
+ null,
out stdout,
out stderr
);
system (system) Closed May 10, 2025, 6:11pm 9
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.