1 /* 2 * Copyright 2015, 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 "MessageCodes.h" 17 #include "SignalDispositionMenu.h" 18 #include "SignalDispositionTypes.h" 19 #include "UiUtils.h" 20 #include "UserInterface.h" 21 #include "Team.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