1b3f2ebf0SRene Gollent/*
210ba3348SRene Gollent * Copyright 2015-2016, Rene Gollent, rene@gollent.com.
3b3f2ebf0SRene Gollent * Distributed under the terms of the MIT License.
4b3f2ebf0SRene Gollent */
5b3f2ebf0SRene Gollent#include "SignalDispositionEditWindow.h"
6b3f2ebf0SRene Gollent
7b3f2ebf0SRene Gollent#include <signal.h>
8b3f2ebf0SRene Gollent
9b3f2ebf0SRene Gollent#include <Button.h>
10b3f2ebf0SRene Gollent#include <LayoutBuilder.h>
11b3f2ebf0SRene Gollent#include <MenuField.h>
12b3f2ebf0SRene Gollent
13b3f2ebf0SRene Gollent#include <AutoDeleter.h>
14b3f2ebf0SRene Gollent#include <AutoLocker.h>
15b3f2ebf0SRene Gollent
1610ba3348SRene Gollent#include "AppMessageCodes.h"
17b3f2ebf0SRene Gollent#include "SignalDispositionMenu.h"
18b3f2ebf0SRene Gollent#include "SignalDispositionTypes.h"
1910ba3348SRene Gollent#include "Team.h"
20b3f2ebf0SRene Gollent#include "UiUtils.h"
21b3f2ebf0SRene Gollent#include "UserInterface.h"
22b3f2ebf0SRene Gollent
23b3f2ebf0SRene Gollent
24b3f2ebf0SRene Gollentenum {
25b3f2ebf0SRene Gollent	MSG_SELECTED_SIGNAL_CHANGED 		= 'ssic',
26b3f2ebf0SRene Gollent	MSG_SELECTED_DISPOSITION_CHANGED 	= 'sdic',
27b3f2ebf0SRene Gollent	MSG_SAVE_SIGNAL_DISPOSITION 		= 'ssid'
28b3f2ebf0SRene Gollent};
29b3f2ebf0SRene Gollent
30b3f2ebf0SRene Gollent
31b3f2ebf0SRene GollentSignalDispositionEditWindow::SignalDispositionEditWindow(::Team* team,
32b3f2ebf0SRene Gollent	int32 signal, UserInterfaceListener* listener, BHandler* target)
33b3f2ebf0SRene Gollent	:
3432b9dee4SRene Gollent	BWindow(BRect(), "Edit signal disposition", B_FLOATING_WINDOW,
35b3f2ebf0SRene Gollent		B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
36b3f2ebf0SRene Gollent	fTeam(team),
37b3f2ebf0SRene Gollent	fListener(listener),
38b3f2ebf0SRene Gollent	fEditMode(signal > 0),
39b3f2ebf0SRene Gollent	fCurrentSignal(signal),
40b3f2ebf0SRene Gollent	fSaveButton(NULL),
41b3f2ebf0SRene Gollent	fCancelButton(NULL),
42b3f2ebf0SRene Gollent	fSignalSelectionField(NULL),
43b3f2ebf0SRene Gollent	fDispositionSelectionField(NULL),
44b3f2ebf0SRene Gollent	fTarget(target)
45b3f2ebf0SRene Gollent{
46b3f2ebf0SRene Gollent}
47b3f2ebf0SRene Gollent
48b3f2ebf0SRene Gollent
49b3f2ebf0SRene GollentSignalDispositionEditWindow::~SignalDispositionEditWindow()
50b3f2ebf0SRene Gollent{
51b3f2ebf0SRene Gollent	BMessenger(fTarget).SendMessage(MSG_SIGNAL_DISPOSITION_EDIT_WINDOW_CLOSED);
52b3f2ebf0SRene Gollent}
53b3f2ebf0SRene Gollent
54b3f2ebf0SRene Gollent
55b3f2ebf0SRene GollentSignalDispositionEditWindow*
56b3f2ebf0SRene GollentSignalDispositionEditWindow::Create(::Team* team, int32 signal,
57b3f2ebf0SRene Gollent	UserInterfaceListener* listener, BHandler* target)
58b3f2ebf0SRene Gollent{
59b3f2ebf0SRene Gollent	SignalDispositionEditWindow* self = new SignalDispositionEditWindow(
60b3f2ebf0SRene Gollent		team, signal, listener, target);
61b3f2ebf0SRene Gollent
62b3f2ebf0SRene Gollent	try {
63b3f2ebf0SRene Gollent		self->_Init();
64b3f2ebf0SRene Gollent	} catch (...) {
65b3f2ebf0SRene Gollent		delete self;
66b3f2ebf0SRene Gollent		throw;
67b3f2ebf0SRene Gollent	}
68b3f2ebf0SRene Gollent
69b3f2ebf0SRene Gollent	return self;
70b3f2ebf0SRene Gollent
71b3f2ebf0SRene Gollent}
72b3f2ebf0SRene Gollent
73b3f2ebf0SRene Gollentvoid
74b3f2ebf0SRene GollentSignalDispositionEditWindow::MessageReceived(BMessage* message)
75b3f2ebf0SRene Gollent{
76b3f2ebf0SRene Gollent	switch (message->what) {
77b3f2ebf0SRene Gollent		case MSG_SELECTED_SIGNAL_CHANGED:
78b3f2ebf0SRene Gollent		{
79b3f2ebf0SRene Gollent			int32 signal;
80b3f2ebf0SRene Gollent			if (message->FindInt32("signal", &signal) == B_OK)
81b3f2ebf0SRene Gollent				fCurrentSignal = signal;
82b3f2ebf0SRene Gollent			break;
83b3f2ebf0SRene Gollent		}
84b3f2ebf0SRene Gollent		case MSG_SELECTED_DISPOSITION_CHANGED:
85b3f2ebf0SRene Gollent		{
86b3f2ebf0SRene Gollent			int32 disposition;
87b3f2ebf0SRene Gollent			if (message->FindInt32("disposition", &disposition) == B_OK)
88b3f2ebf0SRene Gollent				fCurrentDisposition = disposition;
89b3f2ebf0SRene Gollent			break;
90b3f2ebf0SRene Gollent		}
91b3f2ebf0SRene Gollent		case MSG_SAVE_SIGNAL_DISPOSITION:
92b3f2ebf0SRene Gollent		{
93b3f2ebf0SRene Gollent			fListener->SetCustomSignalDispositionRequested(fCurrentSignal,
94b3f2ebf0SRene Gollent				fCurrentDisposition);
95b3f2ebf0SRene Gollent			// fall through
96b3f2ebf0SRene Gollent		}
97b3f2ebf0SRene Gollent		case B_CANCEL:
98b3f2ebf0SRene Gollent			Quit();
99b3f2ebf0SRene Gollent			break;
100b3f2ebf0SRene Gollent
101b3f2ebf0SRene Gollent		default:
102b3f2ebf0SRene Gollent			BWindow::MessageReceived(message);
103b3f2ebf0SRene Gollent			break;
104b3f2ebf0SRene Gollent	}
105b3f2ebf0SRene Gollent
106b3f2ebf0SRene Gollent}
107b3f2ebf0SRene Gollent
108b3f2ebf0SRene Gollent
109b3f2ebf0SRene Gollentvoid
110b3f2ebf0SRene GollentSignalDispositionEditWindow::Show()
111b3f2ebf0SRene Gollent{
112b3f2ebf0SRene Gollent	CenterOnScreen();
113b3f2ebf0SRene Gollent	BWindow::Show();
114b3f2ebf0SRene Gollent}
115b3f2ebf0SRene Gollent
116b3f2ebf0SRene Gollent
117b3f2ebf0SRene Gollentvoid
118b3f2ebf0SRene GollentSignalDispositionEditWindow::_Init()
119b3f2ebf0SRene Gollent{
120b3f2ebf0SRene Gollent	SignalDispositionMenu* menu = new SignalDispositionMenu("dispositionMenu",
121b3f2ebf0SRene Gollent		new BMessage(MSG_SELECTED_DISPOSITION_CHANGED));
122b3f2ebf0SRene Gollent
123b3f2ebf0SRene Gollent	BLayoutBuilder::Group<>(this, B_VERTICAL)
124b3f2ebf0SRene Gollent		.SetInsets(B_USE_DEFAULT_SPACING)
125b3f2ebf0SRene Gollent		.AddGroup(B_HORIZONTAL)
126b3f2ebf0SRene Gollent			.Add((fSignalSelectionField = new BMenuField("Signal:",
127b3f2ebf0SRene Gollent				_BuildSignalSelectionMenu())))
128b3f2ebf0SRene Gollent			.Add((fDispositionSelectionField = new BMenuField("Disposition:",
129b3f2ebf0SRene Gollent				menu)))
130b3f2ebf0SRene Gollent		.End()
131b3f2ebf0SRene Gollent		.AddGroup(B_HORIZONTAL)
132b3f2ebf0SRene Gollent			.AddGlue()
133b3f2ebf0SRene Gollent			.Add((fSaveButton = new BButton("Save",
134b3f2ebf0SRene Gollent				new BMessage(MSG_SAVE_SIGNAL_DISPOSITION))))
135b3f2ebf0SRene Gollent			.Add((fCancelButton = new BButton("Cancel",
136b3f2ebf0SRene Gollent				new BMessage(B_CANCEL))))
137b3f2ebf0SRene Gollent		.End()
138b3f2ebf0SRene Gollent	.End();
139b3f2ebf0SRene Gollent
140b3f2ebf0SRene Gollent	fSignalSelectionField->Menu()->SetLabelFromMarked(true);
141b3f2ebf0SRene Gollent	fSignalSelectionField->Menu()->SetTargetForItems(this);
142b3f2ebf0SRene Gollent	menu->SetLabelFromMarked(true);
143b3f2ebf0SRene Gollent	menu->SetTargetForItems(this);
144b3f2ebf0SRene Gollent
145b3f2ebf0SRene Gollent	AutoLocker< ::Team> teamLocker(fTeam);
146b3f2ebf0SRene Gollent	_UpdateState();
147b3f2ebf0SRene Gollent
148b3f2ebf0SRene Gollent	// if we're editing an existing row, don't allow changing the signal
149b3f2ebf0SRene Gollent	// selection
150b3f2ebf0SRene Gollent	if (fEditMode)
151b3f2ebf0SRene Gollent		fSignalSelectionField->SetEnabled(false);
152b3f2ebf0SRene Gollent
153b3f2ebf0SRene Gollent
154b3f2ebf0SRene Gollent}
155b3f2ebf0SRene Gollent
156b3f2ebf0SRene Gollent
157b3f2ebf0SRene GollentBMenu*
158b3f2ebf0SRene GollentSignalDispositionEditWindow::_BuildSignalSelectionMenu()
159b3f2ebf0SRene Gollent{
160b3f2ebf0SRene Gollent	BMenu* menu = new BMenu("signals");
161b3f2ebf0SRene Gollent	BMenuItem* item;
162b3f2ebf0SRene Gollent
163b3f2ebf0SRene Gollent	#undef ADD_SIGNAL_MENU_ITEM
164b3f2ebf0SRene Gollent	#define ADD_SIGNAL_MENU_ITEM(x)										\
165b3f2ebf0SRene Gollent		menu->AddItem((item = new BMenuItem(#x, new BMessage(			\
166b3f2ebf0SRene Gollent			MSG_SELECTED_SIGNAL_CHANGED))));							\
167b3f2ebf0SRene Gollent		item->Message()->AddInt32("signal", x);
168b3f2ebf0SRene Gollent
169b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGHUP)
170b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGINT)
171b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGQUIT)
172b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGILL)
173b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGCHLD)
174b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGABRT)
175b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGPIPE)
176b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGFPE)
177b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGKILL)
178b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGSTOP)
179b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGSEGV)
180b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGCONT)
181b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGTSTP)
182b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGALRM)
183b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGTERM)
184b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGTTIN)
185b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGTTOU)
186b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGUSR1)
187b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGUSR2)
188b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGWINCH)
189b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGKILLTHR)
190b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGTRAP)
191b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGPOLL)
192b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGPROF)
193b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGSYS)
194b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGURG)
195b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGVTALRM)
196b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGXCPU)
197b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGXFSZ)
198b3f2ebf0SRene Gollent	ADD_SIGNAL_MENU_ITEM(SIGBUS)
199b3f2ebf0SRene Gollent
200b3f2ebf0SRene Gollent	BString signalName;
201b3f2ebf0SRene Gollent	for (int32 i = SIGRTMIN; i <= SIGRTMAX; i++) {
202b3f2ebf0SRene Gollent		menu->AddItem((item = new BMenuItem(UiUtils::SignalNameToString(i,
203b3f2ebf0SRene Gollent					signalName), new BMessage(MSG_SELECTED_SIGNAL_CHANGED))));
204b3f2ebf0SRene Gollent		item->Message()->AddInt32("signal", i);
205b3f2ebf0SRene Gollent	}
206b3f2ebf0SRene Gollent
207b3f2ebf0SRene Gollent	return menu;
208b3f2ebf0SRene Gollent}
209b3f2ebf0SRene Gollent
210b3f2ebf0SRene Gollent
211b3f2ebf0SRene Gollentvoid
212b3f2ebf0SRene GollentSignalDispositionEditWindow::_UpdateState()
213b3f2ebf0SRene Gollent{
214b3f2ebf0SRene Gollent	if (fCurrentSignal <= 0)
215b3f2ebf0SRene Gollent		fCurrentSignal = SIGHUP;
216b3f2ebf0SRene Gollent
217b3f2ebf0SRene Gollent	fSignalSelectionField->Menu()->ItemAt(fCurrentSignal - 1)->SetMarked(true);
218b3f2ebf0SRene Gollent
219b3f2ebf0SRene Gollent	fCurrentDisposition = fTeam->SignalDispositionFor(fCurrentSignal);
220b3f2ebf0SRene Gollent	fDispositionSelectionField->Menu()->ItemAt(fCurrentDisposition)->SetMarked(
221b3f2ebf0SRene Gollent		true);
222b3f2ebf0SRene Gollent}
223b3f2ebf0SRene Gollent
224