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