Hi Guys, i create a process in a child-windows with io.popen. If users closes this window, for example via click on "X" i need to react in the parent window. How can i catch the evt_close of this child-process?
on 2012-09-13 08:59
on 2012-09-13 13:25
Am Thu, 13 Sep 2012 08:59:47 +0200 schrieb "Daniel S." <lists@ruby-forum.com>: > Hi Guys, > > i create a process in a child-windows with io.popen. > > If users closes this window, for example via click on "X" i need to > react in the parent window. > > How can i catch the evt_close of this child-process? If I get you right, you run a Ruby application via IO.popen and want your parent process to do something? Something like this: ================================= IO.popen("ruby myapp.rb"){...stuff...} ================================= ? So you have three possibilities now: 1. EVT_CLOSE usually means your child application is going to exit. So just use IO.popen with the block form, which will wait until your child process has finished. 2. If you can’t use the block form for some reason, use Process.wait which will wait for all child processes to exit. 3. Assuming you #veto the close event, but want your parent process to take action nevertheless, you can use process signals to achieve what you want. In the parent process, register a signal handler for your "reaction": ================================= Signal.trap("SIGUSR1") do puts "Hi, I've been notified!" # or do whatever you want end ================================= In the child process, register an event handler for the EVT_CLOSE event that notifies your parent process (Process.ppid returns the PID of your process’ parent process): ================================= evt_close do |event| Process.kill("SIGUSR1", Process.ppid) event.veto # Do not close the window end ================================= Or if you meant it the other way round, having your child process to react when the parent process gets EVT_CLOSE, you could catch the EVT_CLOSE in the parent process and send a signal to the child process. Example (using the open4 gem): ================================= require "open4" require "wx" class MainFrame < Wx::Frame include Wx def initialize(parent = nil) super(parent, title: "Test", size: [400, 400]) StaticText.new(self, label: "Test app", pos: [20, 20]) @button = Button.new(self, label: "Click me", pos: [20, 50]) evt_button(@button, :on_button_click) evt_close(:on_close) end private def on_button_click(event) # Note you cannot use the block form @childpid, @childstdin, @childstdout, @childstderr = \ Open4.popen4("sleep") end def on_close(event) Process.kill("SIGTERM", @childpid) event.skip # Otherwise closing is prohibited end end class MyApp < Wx::App def on_init @mainwindow = MainFrame.new @mainwindow.show end end ================================= This application will send SIGTERM to the "sleep" child process when EVT_CLOSE is received. Vale, Marvin -- Blog: http://pegasus-alpha.eu/blog ASCII-Ribbon-Kampagne () | ASCII Ribbon Campaign () - Stoppt HTML-E-Mail /\ | - Against HTML E-Mail /\ - Stoppt proprietäre Anhänge | - Against proprietary attachments www.asciiribbon.org/index-de.html | www.asciiribbon.org
on 2012-09-13 16:46
Hi Marvin,
thx for ur long answer, but this is not exactly what i wanted, because
my childprocess is not really a second ruby process. In my case i am
using Gnuplot in the childwindow and coontrol it via buttons in the
parent window.
So here is my example:
At first i create my parent window with some buttons and the following
code to invoke the child process:
...
def on_buttonclick
@gnuplot = Plot.new(filelist)
end
def on_anotherbuttonclick
@gnuplot.do_something
end
...
Here is what my Plot-Class does:
class Plot
def initialize(filelist)
@gp=IO.popen("gnuplot","w+")
@gp.puts("plot #{filelist}")
end
def do_something
@gp.puts("do something")
end
...
end
Situation after Click on first button:
- Parent window is open with two button
- Gnuplot-Window has been openend as a child of parentwindow with some
plot
- both are idle
- After Click on second button the childprocess is forced to do
something, this is what the parent process should do.
Now my problem:
If the user closes the Childwindow (For example Alt-F4, or click on "X"
the Window closes, but the object @gnuplot still exists in memory.
If this happens i want to react in ParentProcess for example with
@gnuplot.close or disable some buttons which have no function any longer
when Childwindows doesnt exist anymore.
evt_close in my Plot-Class does not seem to work, because this event is
not thrown in case of clicking on "X" or Alr-F4.
So the question is: How to catch those (User-)Events?
If i could catch these events i could use your solution with SIGTERM
on 2012-09-13 22:58
Am Thu, 13 Sep 2012 16:46:35 +0200 schrieb "Daniel S." <lists@ruby-forum.com>: > Hi Marvin, > thx for ur long answer, but this is not exactly what i wanted, > because my childprocess is not really a second ruby process. In my > case i am using Gnuplot in the childwindow and coontrol it via > buttons in the parent window. You cannot listen to events to other processes. So if GnuPlot doesn’t have a possibility to tell you when its main window is closed, you can’t check this without relying on dirty hacks such as making xdotool check the visibility of the window regularily by means of a Wx::Timer. > Situation after Click on first button: > - Parent window is open with two button > - Gnuplot-Window has been openend as a child of parentwindow with > some plot > - both are idle > - After Click on second button the childprocess is forced to do > something, this is what the parent process should do. First for clarity: This way the GnuPlot window is *not* a child window of your application. It’s the main window of a completely autonome and separate process. The GnuPlot *process* is a child process of your Ruby process, but the window belongs to the child process, not to your process. I don’t know GnuPlot, but when its main window exits (as a result to [Alt]+[F4] or clicking on the close button) I suspect the process running the window dies, doesn’t it? If you’re developing for a *nix platform there’s a special process signal, SIGCHLD, which is fired on your process when a child process dies. Any *nix application (including Ruby applications) can register a handler for this signal, so you can for example do (IO.popen creates child processes, and #spawn does so as well): ===================================== spawn("sleep 5") Signal.trap("SIGCHLD") do puts "This was it." puts "But for $500.000 I will send you the body." exit end puts "If you don't pay $1.000.000 I will kill this child." loop do puts "I'm waiting..." sleep 0.5 end ===================================== You should be able to combine this with your usecase[1]. I however am not sure how wxRuby reacts if you try to modify wx stuff from this asynchronously run code; I often saw segfaults or arcane error messages when I even tried this with threads, so I cannot predict what happens from within signal handlers. What you probably can do safely is registering a callback to run as soon as possible (probably utilising Timer.after with a very short time interval) which will then be run from within the wx eventloop and therefore be safe. > So the question is: How to catch those (User-)Events? As said: There’s no way to listen to events for another process (apart from using GDB, I suppose). > If i could catch these events i could use your solution with SIGTERM Vale, Marvin [1] I mean the concept employed by the code, not the way this hypothetic kidnapper acts, of course. Btw. from the code you can see he never had the intention to leave the child alive after receiving the money. -- Blog: http://pegasus-alpha.eu/blog ASCII-Ribbon-Kampagne () | ASCII Ribbon Campaign () - Stoppt HTML-E-Mail /\ | - Against HTML E-Mail /\ - Stoppt proprietäre Anhänge | - Against proprietary attachments www.asciiribbon.org/index-de.html | www.asciiribbon.org
on 2012-09-13 23:38
> First for clarity: This way the GnuPlot window is *not* a child window > of your application. It’s the main window of a completely autonome and > separate process. The GnuPlot *process* is a child process of your Ruby > process, but the window belongs to the child process, not to your > process. okay, this was my problem... > > I don’t know GnuPlot, but when its main window exits (as a result to > [Alt]+[F4] or clicking on the close button) I suspect the process > running the window dies, doesn’t it? No, it doesn't. I'll check some gnuplot forums to realize this behavior. After this is can use SIGCHLD, i think As an alternative i'll prevent the gnuplot window to be closed by user (don't know yet how to do so) and implement a "close window"-button in my parent which kills the whole gnuplot-process... Thx for your help!
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.