3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS
15 #include "ButtonController.h"
16 #include "FormForks.h"
17 #include "ControlForks.h"
18 #include "forms/form_forks.h"
20 #include "helper_funcs.h"
21 #include "xforms_helpers.h"
23 #include "support/lstrings.h"
24 #include "lyx_forms.h"
25 #include "support/tostr.h"
27 using namespace lyx::support;
33 typedef FormCB<ControlForks, FormDB<FD_forks> > base_class;
35 FormForks::FormForks()
36 : base_class(_("Child Processes"))
40 void FormForks::build() {
41 dialog_.reset(build_forks(this));
43 // It appears that the browsers aren't initialised properly.
44 // This fudge fixes tings.
45 fl_add_browser_line(dialog_->browser_children, " ");
46 fl_add_browser_line(dialog_->browser_kill, " ");
47 fl_clear_browser(dialog_->browser_children);
48 fl_clear_browser(dialog_->browser_kill);
50 // Manage the ok, apply, restore and cancel/close buttons
51 bcview().setOK(dialog_->button_ok);
52 bcview().setApply(dialog_->button_apply);
53 bcview().setCancel(dialog_->button_close);
56 // Set up the tooltip mechanism
57 string str = _("All currently running child processes forked by LyX.");
58 tooltips().init(dialog_->browser_children, str);
59 #if FL_VERSION == 0 || (FL_REVISION == 0 && FL_FIXLEVEL == 0)
60 // Work-around xforms' bug; enable tooltips for browser widgets.
61 setPrehandler(dialog_->browser_children);
64 str = _("A list of all child processes to kill.");
65 tooltips().init(dialog_->browser_kill, str);
66 #if FL_VERSION == 0 || (FL_REVISION == 0 && FL_FIXLEVEL == 0)
67 // Work-around xforms' bug; enable tooltips for browser widgets.
68 setPrehandler(dialog_->browser_kill);
71 str = _("Add all processes to the list of processes to kill.");
72 tooltips().init(dialog_->button_all, str);
74 str = _("Add the currently selected child process to the list of processes to kill.");
75 tooltips().init(dialog_->button_add, str);
77 str = _("Remove the currently selected item from the list of processes to kill.");
78 tooltips().init(dialog_->button_remove, str);
82 void FormForks::update()
87 string const current_pid_str =
88 getString(dialog_->browser_kill);
89 pid_t const current_pid = strToInt(current_pid_str);
91 vector<pid_t> pids = controller().getPIDs();
93 // No child processes.
95 if (fl_get_browser_maxline(dialog_->browser_kill) > 0)
96 fl_clear_browser(dialog_->browser_kill);
97 if (fl_get_browser_maxline(dialog_->browser_children) > 0)
98 fl_clear_browser(dialog_->browser_children);
100 setEnabled(dialog_->browser_children, false);
101 setEnabled(dialog_->browser_kill, false);
102 setEnabled(dialog_->button_all, false);
103 setEnabled(dialog_->button_add, false);
104 setEnabled(dialog_->button_remove, false);
109 // Remove any processes from the kill browser that aren't in the
110 // vector of existing PIDs.
111 for (int i = 1; i <= fl_get_browser_maxline(dialog_->browser_kill);
113 string const pid_str =
114 getString(dialog_->browser_kill, i);
115 pid_t const pid = strToInt(pid_str);
116 vector<pid_t>::const_iterator it =
117 find(pids.begin(), pids.end(), pid);
118 if (it == pids.end())
119 fl_delete_browser_line(dialog_->browser_kill, i);
122 // Build the children browser from scratch.
123 if (fl_get_browser_maxline(dialog_->browser_children) > 0)
124 fl_clear_browser(dialog_->browser_children);
126 for (vector<pid_t>::const_iterator it = pids.begin();
127 it != pids.end(); ++it) {
128 string const pid_str = tostr(*it);
129 string const command = controller().getCommand(*it);
130 string const line = pid_str + '\t' + command;
132 fl_add_browser_line(dialog_->browser_children, line.c_str());
134 if (*it == current_pid)
135 fl_select_browser_line(dialog_->browser_children, i);
139 setEnabled(dialog_->browser_children, true);
140 setEnabled(dialog_->button_all, true);
141 setEnabled(dialog_->button_add, true);
145 void FormForks::apply()
147 // Get the list of all processes to kill.
148 vector<string> const kill_vec =
149 getVector(dialog_->browser_kill);
151 if (kill_vec.empty())
154 // Remove these items from the vector of child processes.
155 for (int i = 1; i <= fl_get_browser_maxline(dialog_->browser_children);
157 string const selection =
158 getString(dialog_->browser_children, i);
160 split(selection, pid_str, '\t');
162 vector<string>::const_iterator it =
163 find(kill_vec.begin(), kill_vec.end(), pid_str);
165 if (it != kill_vec.end())
166 fl_delete_browser_line(dialog_->browser_children, i);
169 // Clear the kill browser and deactivate appropriately.
170 fl_clear_browser(dialog_->browser_kill);
171 setEnabled(dialog_->browser_kill, false);
172 setEnabled(dialog_->button_remove, false);
174 // Pass these pids to the controller for destruction.
175 for (vector<string>::const_iterator it = kill_vec.begin();
176 it != kill_vec.end(); ++it) {
177 pid_t const pid = strToInt(*it);
178 controller().kill(pid);
184 ButtonPolicy::SMInput FormForks::input(FL_OBJECT * ob, long)
186 ButtonPolicy::SMInput activate = ButtonPolicy::SMI_NOOP;
188 if (ob == dialog_->browser_children) {
189 activate = input_browser_children();
191 } else if (ob == dialog_->browser_kill) {
192 activate = input_browser_kill();
194 } else if (ob == dialog_->button_all) {
195 activate = input_button_all();
197 } else if (ob == dialog_->button_add) {
198 activate = input_button_add();
200 } else if (ob == dialog_->button_remove) {
201 activate = input_button_remove();
207 ButtonPolicy::SMInput FormForks::input_browser_children()
209 // Selected an item in the browser containing a list of all child
212 // 1. Highlight this item in the browser of processes to kill
213 // if it is already there.
215 // 2. If it is there, enable the remove button so that it can
216 // be removed from this list, if so desired.
218 // 3. If it isn't there, activate the add button so that it can
219 // be added to this list if so desired.
221 string const selection =
222 getString(dialog_->browser_children);
224 split(selection, pid_str, '\t');
226 vector<string> const kill_vec =
227 getVector(dialog_->browser_kill);
229 vector<string>::const_iterator it =
230 find(kill_vec.begin(), kill_vec.end(), pid_str);
232 fl_deselect_browser(dialog_->browser_kill);
233 if (it != kill_vec.end()) {
234 int const n = int(it - kill_vec.begin());
235 fl_select_browser_line(dialog_->browser_kill, n+1);
236 fl_set_browser_topline(dialog_->browser_kill, n+1);
239 setEnabled(dialog_->button_remove, it != kill_vec.end());
240 setEnabled(dialog_->button_add, it == kill_vec.end());
242 return ButtonPolicy::SMI_NOOP;
250 FindPID(string const & pid) : pid_(pid) {}
251 bool operator()(string const & line)
257 split(line, pid_str, '\t');
258 return pid_str == pid_;
268 ButtonPolicy::SMInput FormForks::input_browser_kill()
270 // Selected an item in the browser containing a list of processes
273 // 1. Highlight this item in the browser of all child processes.
275 // 2. Enable the remove button so that it can removed from this list,
278 // 3. Disable the add button.
280 string const pid_str =
281 getString(dialog_->browser_kill);
283 // Find this string in the list of all child processes
284 vector<string> const child_vec =
285 getVector(dialog_->browser_children);
287 vector<string>::const_iterator it =
288 find_if(child_vec.begin(), child_vec.end(), FindPID(pid_str));
290 fl_deselect_browser(dialog_->browser_children);
291 if (it != child_vec.end()) {
292 int const n = int(it - child_vec.begin());
293 fl_select_browser_line(dialog_->browser_children, n+1);
294 fl_set_browser_topline(dialog_->browser_children, n+1);
297 setEnabled(dialog_->button_remove, true);
298 setEnabled(dialog_->button_add, false);
300 return ButtonPolicy::SMI_NOOP;
306 vector<string> const getPIDvector(FL_OBJECT * ob)
308 vector<string> vec = getVector(ob);
312 for (vector<string>::iterator it = vec.begin(); it != vec.end(); ++it) {
314 split(*it, pid_str, '\t');
324 ButtonPolicy::SMInput FormForks::input_button_all()
326 // Pressed the "All" button.
328 // 1. Check that the browser of processes to kill doesn't already
329 // contain the entire list.
331 // 2. If it doesn't, copy the PIDs of all child processes into the
332 // browser of processes to kill.
334 // 3. Deactivate the "children" browser and the "add" and "all" buttons
336 // 4. Activate the "kill" browser and the "remove" button"
338 ButtonPolicy::SMInput activate = ButtonPolicy::SMI_NOOP;
340 vector<string> const pid_vec = getPIDvector(dialog_->browser_children);
342 // to resolve a warning about comparison between signed and unsigned.
343 int const pid_vec_size = int(pid_vec.size());
345 if (fl_get_browser_maxline(dialog_->browser_kill) != pid_vec_size) {
346 activate = ButtonPolicy::SMI_VALID;
348 fl_clear_browser(dialog_->browser_kill);
349 for (vector<string>::const_iterator it = pid_vec.begin();
350 it != pid_vec.end(); ++it) {
351 fl_add_browser_line(dialog_->browser_kill, it->c_str());
354 if (fl_get_browser_maxline(dialog_->browser_kill) >= 1)
355 fl_set_browser_topline(dialog_->browser_kill, 1);
358 setEnabled(dialog_->browser_children, false);
359 setEnabled(dialog_->button_add, false);
360 setEnabled(dialog_->button_all, false);
361 setEnabled(dialog_->browser_kill, true);
362 setEnabled(dialog_->button_remove, true);
368 ButtonPolicy::SMInput FormForks::input_button_add()
370 // Pressed the "Add" button.
372 // 1. Copy the PID of the selected item in the browser of all child
373 // processes over into the browser of processes to kill.
375 // 2. Activate the "kill" browser and the "remove" button.
377 // 3. Deactivate the "add" button.
379 string const selection = getString(dialog_->browser_children);
381 split(selection, pid_str, '\t');
383 vector<string> const kill_vec =
384 getVector(dialog_->browser_kill);
386 vector<string>::const_iterator it =
387 find(kill_vec.begin(), kill_vec.end(), pid_str);
389 if (it == kill_vec.end()) {
390 fl_add_browser_line(dialog_->browser_kill, pid_str.c_str());
391 int const n = fl_get_browser_maxline(dialog_->browser_kill);
392 fl_select_browser_line(dialog_->browser_kill, n);
395 setEnabled(dialog_->browser_kill, true);
396 setEnabled(dialog_->button_remove, true);
397 setEnabled(dialog_->button_add, false);
399 return ButtonPolicy::SMI_VALID;
403 ButtonPolicy::SMInput FormForks::input_button_remove()
405 // Pressed the "Remove" button.
407 // 1. Remove the selected item in the browser of processes to kill.
409 // 2. Activate the "add" button and "all" buttons.
411 // 3. Deactivate the "remove" button.
413 int const sel = fl_get_browser(dialog_->browser_kill);
414 fl_delete_browser_line(dialog_->browser_kill, sel);
416 setEnabled(dialog_->button_add, true);
417 setEnabled(dialog_->button_all, true);
418 setEnabled(dialog_->button_remove, false);
420 return ButtonPolicy::SMI_VALID;