vfs: check userland buffers before reading them.
[haiku.git] / src / preferences / notifications / GeneralView.cpp
blobbde36889d6781e857f3e50dbce2c6d517566f34c
1 /*
2 * Copyright 2010-2017, Haiku, Inc. All Rights Reserved.
3 * Copyright 2009, Pier Luigi Fiorini.
4 * Distributed under the terms of the MIT License.
6 * Authors:
7 * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
8 * Brian Hill, supernova@tycho.email
9 */
11 #include <stdio.h>
12 #include <stdlib.h>
14 #include <vector>
16 #include <Alert.h>
17 #include <Box.h>
18 #include <Button.h>
19 #include <Catalog.h>
20 #include <Directory.h>
21 #include <File.h>
22 #include <FindDirectory.h>
23 #include <Font.h>
24 #include <LayoutBuilder.h>
25 #include <Node.h>
26 #include <Path.h>
27 #include <Query.h>
28 #include <Roster.h>
29 #include <String.h>
30 #include <SymLink.h>
31 #include <Volume.h>
32 #include <VolumeRoster.h>
34 #include <notification/Notifications.h>
36 #include "GeneralView.h"
37 #include "NotificationsConstants.h"
38 #include "SettingsHost.h"
40 #undef B_TRANSLATION_CONTEXT
41 #define B_TRANSLATION_CONTEXT "GeneralView"
43 const uint32 kToggleNotifications = '_TSR';
44 const uint32 kWidthChanged = '_WIC';
45 const uint32 kTimeoutChanged = '_TIC';
46 const uint32 kPositionChanged = '_NPC';
47 const uint32 kServerChangeTriggered = '_SCT';
48 const BString kSampleMessageID("NotificationsSample");
51 static int32
52 notification_position_to_index(uint32 notification_position) {
53 if (notification_position == B_FOLLOW_NONE)
54 return 0;
55 else if (notification_position == (B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM))
56 return 1;
57 else if (notification_position == (B_FOLLOW_LEFT | B_FOLLOW_BOTTOM))
58 return 2;
59 else if (notification_position == (B_FOLLOW_RIGHT | B_FOLLOW_TOP))
60 return 3;
61 else if (notification_position == (B_FOLLOW_LEFT | B_FOLLOW_TOP))
62 return 4;
63 return 0;
67 GeneralView::GeneralView(SettingsHost* host)
69 SettingsPane("general", host)
71 // Notification server
72 fNotificationBox = new BCheckBox("server",
73 B_TRANSLATE("Enable notifications"),
74 new BMessage(kToggleNotifications));
75 BBox* box = new BBox("box");
76 box->SetLabel(fNotificationBox);
78 // Window width
79 int32 minWidth = int32(kMinimumWidth / kWidthStep);
80 int32 maxWidth = int32(kMaximumWidth / kWidthStep);
81 fWidthSlider = new BSlider("width", B_TRANSLATE("Window width:"),
82 new BMessage(kWidthChanged), minWidth, maxWidth, B_HORIZONTAL);
83 fWidthSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
84 fWidthSlider->SetHashMarkCount(maxWidth - minWidth + 1);
85 BString minWidthLabel;
86 minWidthLabel << int32(kMinimumWidth);
87 BString maxWidthLabel;
88 maxWidthLabel << int32(kMaximumWidth);
89 fWidthSlider->SetLimitLabels(
90 B_TRANSLATE_COMMENT(minWidthLabel.String(), "Slider low text"),
91 B_TRANSLATE_COMMENT(maxWidthLabel.String(), "Slider high text"));
93 // Display time
94 fDurationSlider = new BSlider("duration", B_TRANSLATE("Duration:"),
95 new BMessage(kTimeoutChanged), kMinimumTimeout, kMaximumTimeout,
96 B_HORIZONTAL);
97 fDurationSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
98 fDurationSlider->SetHashMarkCount(kMaximumTimeout - kMinimumTimeout + 1);
99 BString minLabel;
100 minLabel << kMinimumTimeout;
101 BString maxLabel;
102 maxLabel << kMaximumTimeout;
103 fDurationSlider->SetLimitLabels(
104 B_TRANSLATE_COMMENT(minLabel.String(), "Slider low text"),
105 B_TRANSLATE_COMMENT(maxLabel.String(), "Slider high text"));
107 // Notification Position
108 fPositionMenu = new BPopUpMenu(B_TRANSLATE("Follow Deskbar"));
109 const char* positionLabels[] = {
110 B_TRANSLATE_MARK("Follow Deskbar"),
111 B_TRANSLATE_MARK("Lower right"),
112 B_TRANSLATE_MARK("Lower left"),
113 B_TRANSLATE_MARK("Upper right"),
114 B_TRANSLATE_MARK("Upper left")
116 const uint32 positions[] = {
117 B_FOLLOW_DESKBAR, // Follow Deskbar
118 B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT, // Lower right
119 B_FOLLOW_BOTTOM | B_FOLLOW_LEFT, // Lower left
120 B_FOLLOW_TOP | B_FOLLOW_RIGHT, // Upper right
121 B_FOLLOW_TOP | B_FOLLOW_LEFT // Upper left
123 for (int i=0; i < 5; i++) {
124 BMessage* message = new BMessage(kPositionChanged);
125 message->AddInt32(kNotificationPositionName, positions[i]);
127 fPositionMenu->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(
128 positionLabels[i]), message));
130 BMenuField* positionField = new BMenuField(B_TRANSLATE("Position:"),
131 fPositionMenu);
133 box->AddChild(BLayoutBuilder::Group<>(B_VERTICAL)
134 .SetInsets(B_USE_DEFAULT_SPACING)
135 .Add(fWidthSlider)
136 .Add(fDurationSlider)
137 .Add(positionField)
138 .AddGlue()
139 .View());
141 BLayoutBuilder::Group<>(this, B_VERTICAL)
142 .SetInsets(B_USE_WINDOW_SPACING)
143 .Add(box)
144 .End();
148 void
149 GeneralView::AttachedToWindow()
151 BView::AttachedToWindow();
152 fNotificationBox->SetTarget(this);
153 fWidthSlider->SetTarget(this);
154 fDurationSlider->SetTarget(this);
155 fPositionMenu->SetTargetForItems(this);
159 void
160 GeneralView::MessageReceived(BMessage* msg)
162 switch (msg->what) {
163 case kToggleNotifications:
165 SettingsPane::SettingsChanged(false);
166 _EnableControls();
167 break;
169 case kWidthChanged: {
170 int32 value = fWidthSlider->Value() * 50;
171 _SetWidthLabel(value);
172 SettingsPane::SettingsChanged(true);
173 break;
175 case kTimeoutChanged:
177 int32 value = fDurationSlider->Value();
178 _SetTimeoutLabel(value);
179 SettingsPane::SettingsChanged(true);
180 break;
182 case kPositionChanged:
184 int32 position;
185 if (msg->FindInt32(kNotificationPositionName, &position) == B_OK) {
186 fNewPosition = position;
187 SettingsPane::SettingsChanged(true);
189 break;
191 default:
192 BView::MessageReceived(msg);
193 break;
198 status_t
199 GeneralView::Load(BMessage& settings)
201 bool autoStart = settings.GetBool(kAutoStartName, true);
202 fNotificationBox->SetValue(autoStart ? B_CONTROL_ON : B_CONTROL_OFF);
204 if (settings.FindFloat(kWidthName, &fOriginalWidth) != B_OK
205 || fOriginalWidth > kMaximumWidth
206 || fOriginalWidth < kMinimumWidth)
207 fOriginalWidth = kDefaultWidth;
209 if (settings.FindInt32(kTimeoutName, &fOriginalTimeout) != B_OK
210 || fOriginalTimeout > kMaximumTimeout
211 || fOriginalTimeout < kMinimumTimeout)
212 fOriginalTimeout = kDefaultTimeout;
213 // TODO need to save again if values outside of expected range
214 int32 setting;
215 if (settings.FindInt32(kIconSizeName, &setting) != B_OK)
216 fOriginalIconSize = kDefaultIconSize;
217 else
218 fOriginalIconSize = (icon_size)setting;
220 int32 position;
221 if (settings.FindInt32(kNotificationPositionName, &position) != B_OK)
222 fOriginalPosition = kDefaultNotificationPosition;
223 else
224 fOriginalPosition = position;
226 _EnableControls();
228 return Revert();
232 status_t
233 GeneralView::Save(BMessage& settings)
235 bool autoStart = (fNotificationBox->Value() == B_CONTROL_ON);
236 settings.AddBool(kAutoStartName, autoStart);
238 int32 timeout = fDurationSlider->Value();
239 settings.AddInt32(kTimeoutName, timeout);
241 float width = fWidthSlider->Value() * 50;
242 settings.AddFloat(kWidthName, width);
244 icon_size iconSize = B_LARGE_ICON;
245 settings.AddInt32(kIconSizeName, (int32)iconSize);
247 settings.AddInt32(kNotificationPositionName, (int32)fNewPosition);
249 return B_OK;
253 status_t
254 GeneralView::Revert()
256 fDurationSlider->SetValue(fOriginalTimeout);
257 _SetTimeoutLabel(fOriginalTimeout);
259 fWidthSlider->SetValue(fOriginalWidth / 50);
260 _SetWidthLabel(fOriginalWidth);
262 fNewPosition = fOriginalPosition;
263 BMenuItem* item = fPositionMenu->ItemAt(
264 notification_position_to_index(fNewPosition));
265 if (item != NULL)
266 item->SetMarked(true);
268 return B_OK;
272 bool
273 GeneralView::RevertPossible()
275 int32 timeout = fDurationSlider->Value();
276 if (fOriginalTimeout != timeout)
277 return true;
279 int32 width = fWidthSlider->Value() * 50;
280 if (fOriginalWidth != width)
281 return true;
283 if (fOriginalPosition != fNewPosition)
284 return true;
286 return false;
290 status_t
291 GeneralView::Defaults()
293 fDurationSlider->SetValue(kDefaultTimeout);
294 _SetTimeoutLabel(kDefaultTimeout);
296 fWidthSlider->SetValue(kDefaultWidth / 50);
297 _SetWidthLabel(kDefaultWidth);
299 fNewPosition = kDefaultNotificationPosition;
300 BMenuItem* item = fPositionMenu->ItemAt(
301 notification_position_to_index(fNewPosition));
302 if (item != NULL)
303 item->SetMarked(true);
305 return B_OK;
309 bool
310 GeneralView::DefaultsPossible()
312 int32 timeout = fDurationSlider->Value();
313 if (kDefaultTimeout != timeout)
314 return true;
316 int32 width = fWidthSlider->Value() * 50;
317 if (kDefaultWidth != width)
318 return true;
320 if (kDefaultNotificationPosition != fNewPosition)
321 return true;
323 return false;
327 bool
328 GeneralView::UseDefaultRevertButtons()
330 return true;
334 void
335 GeneralView::_EnableControls()
337 bool enabled = fNotificationBox->Value() == B_CONTROL_ON;
338 fWidthSlider->SetEnabled(enabled);
339 fDurationSlider->SetEnabled(enabled);
340 BMenuItem* item = fPositionMenu->ItemAt(
341 notification_position_to_index(fOriginalPosition));
342 if (item != NULL)
343 item->SetMarked(true);
347 void
348 GeneralView::_SetTimeoutLabel(int32 value)
350 BString label(B_TRANSLATE("Timeout:"));
351 label.Append(" ");
352 label << value;
353 label.Append(" ").Append(B_TRANSLATE("seconds"));
354 fDurationSlider->SetLabel(label.String());
358 void
359 GeneralView::_SetWidthLabel(int32 value)
361 BString label(B_TRANSLATE("Width:"));
362 label.Append(" ");
363 label << value;
364 label.Append(" ").Append(B_TRANSLATE("pixels"));
365 fWidthSlider->SetLabel(label.String());
369 bool
370 GeneralView::_IsServerRunning()
372 return be_roster->IsRunning(kNotificationServerSignature);