vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / BMCPrivate.cpp
blobd8025656b35c26b5698914a4edaebb1bfb63a4d2
1 /*
2 * Copyright 2001-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stephan Aßmus, superstippi@gmx.de
7 * Marc Flerackers, mflerackers@androme.be
8 * John Scipione, jcipione@gmail.com
9 */
12 #include <BMCPrivate.h>
14 #include <algorithm>
16 #include <ControlLook.h>
17 #include <LayoutUtils.h>
18 #include <MenuField.h>
19 #include <MenuItem.h>
20 #include <Message.h>
21 #include <MessageRunner.h>
22 #include <Window.h>
25 static const float kPopUpIndicatorWidth = 13.0f;
28 #if __GNUC__ == 2
31 // This is kept only for binary compatibility with BeOS R5. This class was
32 // used in their BMenuField implementation and we may come across some archived
33 // BMenuField that needs it.
34 class _BMCItem_: public BMenuItem {
35 public:
36 _BMCItem_(BMessage* data);
37 static BArchivable* Instantiate(BMessage *data);
41 _BMCItem_::_BMCItem_(BMessage* data)
43 BMenuItem(data)
48 /*static*/ BArchivable*
49 _BMCItem_::Instantiate(BMessage *data) {
50 if (validate_instantiation(data, "_BMCItem_"))
51 return new _BMCItem_(data);
53 return NULL;
57 #endif
60 // #pragma mark - _BMCFilter_
63 _BMCFilter_::_BMCFilter_(BMenuField* menuField, uint32 what)
65 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, what),
66 fMenuField(menuField)
71 _BMCFilter_::~_BMCFilter_()
76 filter_result
77 _BMCFilter_::Filter(BMessage* message, BHandler** handler)
79 if (message->what == B_MOUSE_DOWN) {
80 if (BView* view = dynamic_cast<BView*>(*handler)) {
81 BPoint point;
82 message->FindPoint("be:view_where", &point);
83 view->ConvertToParent(&point);
84 message->ReplacePoint("be:view_where", point);
85 *handler = fMenuField;
89 return B_DISPATCH_MESSAGE;
93 // #pragma mark - _BMCMenuBar_
96 _BMCMenuBar_::_BMCMenuBar_(BRect frame, bool fixedSize, BMenuField* menuField)
98 BMenuBar(frame, "_mc_mb_", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_ITEMS_IN_ROW,
99 !fixedSize),
100 fMenuField(menuField),
101 fFixedSize(fixedSize),
102 fShowPopUpMarker(true)
104 _Init();
108 _BMCMenuBar_::_BMCMenuBar_(BMenuField* menuField)
110 BMenuBar("_mc_mb_", B_ITEMS_IN_ROW),
111 fMenuField(menuField),
112 fFixedSize(true),
113 fShowPopUpMarker(true)
115 _Init();
119 _BMCMenuBar_::_BMCMenuBar_(BMessage* data)
121 BMenuBar(data),
122 fMenuField(NULL),
123 fFixedSize(true),
124 fShowPopUpMarker(true)
126 SetFlags(Flags() | B_FRAME_EVENTS);
128 bool resizeToFit;
129 if (data->FindBool("_rsize_to_fit", &resizeToFit) == B_OK)
130 fFixedSize = !resizeToFit;
134 _BMCMenuBar_::~_BMCMenuBar_()
139 // #pragma mark - _BMCMenuBar_ public methods
142 BArchivable*
143 _BMCMenuBar_::Instantiate(BMessage* data)
145 if (validate_instantiation(data, "_BMCMenuBar_"))
146 return new _BMCMenuBar_(data);
148 return NULL;
152 void
153 _BMCMenuBar_::AttachedToWindow()
155 fMenuField = static_cast<BMenuField*>(Parent());
157 // Don't cause the KeyMenuBar to change by being attached
158 BMenuBar* menuBar = Window()->KeyMenuBar();
159 BMenuBar::AttachedToWindow();
160 Window()->SetKeyMenuBar(menuBar);
162 if (fFixedSize && (Flags() & B_SUPPORTS_LAYOUT) == 0)
163 SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
165 if (Parent() != NULL) {
166 color_which which = Parent()->LowUIColor();
167 if (which == B_NO_COLOR)
168 SetLowColor(Parent()->LowColor());
169 else
170 SetLowUIColor(which);
172 } else
173 SetLowUIColor(B_MENU_BACKGROUND_COLOR);
175 fPreviousWidth = Bounds().Width();
179 void
180 _BMCMenuBar_::Draw(BRect updateRect)
182 if (fFixedSize) {
183 // Set the width of the menu bar because the menu bar bounds may have
184 // been expanded by the selected menu item.
185 ResizeTo(fMenuField->_MenuBarWidth(), Bounds().Height());
186 } else {
187 // For compatability with BeOS R5:
188 // - Set to the minimum of the menu bar width set by the menu frame
189 // and the selected menu item width.
190 // - Set the height to the preferred height ignoring the height of the
191 // menu field.
192 float height;
193 BMenuBar::GetPreferredSize(NULL, &height);
194 ResizeTo(std::min(Bounds().Width(), fMenuField->_MenuBarWidth()),
195 height);
198 BRect rect(Bounds());
199 rgb_color base = ui_color(B_MENU_BACKGROUND_COLOR);
200 uint32 flags = 0;
201 if (!IsEnabled())
202 flags |= BControlLook::B_DISABLED;
203 if (IsFocus())
204 flags |= BControlLook::B_FOCUSED;
206 be_control_look->DrawMenuFieldBackground(this, rect,
207 updateRect, base, fShowPopUpMarker, flags);
209 DrawItems(updateRect);
213 void
214 _BMCMenuBar_::FrameResized(float width, float height)
216 // we need to take care of cleaning up the parent menu field
217 float diff = width - fPreviousWidth;
218 fPreviousWidth = width;
220 if (Window() != NULL && diff != 0) {
221 BRect dirty(fMenuField->Bounds());
222 if (diff > 0) {
223 // clean up the dirty right border of
224 // the menu field when enlarging
225 dirty.right = Frame().right + kVMargin;
226 dirty.left = dirty.right - diff - kVMargin * 2;
227 fMenuField->Invalidate(dirty);
228 } else if (diff < 0) {
229 // clean up the dirty right line of
230 // the menu field when shrinking
231 dirty.left = Frame().right - kVMargin;
232 fMenuField->Invalidate(dirty);
236 BMenuBar::FrameResized(width, height);
240 void
241 _BMCMenuBar_::MakeFocus(bool focused)
243 if (IsFocus() == focused)
244 return;
246 BMenuBar::MakeFocus(focused);
250 void
251 _BMCMenuBar_::MessageReceived(BMessage* message)
253 switch (message->what) {
254 case 'TICK':
256 BMenuItem* item = ItemAt(0);
258 if (item != NULL && item->Submenu() != NULL
259 && item->Submenu()->Window() != NULL) {
260 BMessage message(B_KEY_DOWN);
262 message.AddInt8("byte", B_ESCAPE);
263 message.AddInt8("key", B_ESCAPE);
264 message.AddInt32("modifiers", 0);
265 message.AddInt8("raw_char", B_ESCAPE);
267 Window()->PostMessage(&message, this, NULL);
270 // fall through
271 default:
272 BMenuBar::MessageReceived(message);
273 break;
278 void
279 _BMCMenuBar_::SetMaxContentWidth(float width)
281 float left;
282 float right;
283 GetItemMargins(&left, NULL, &right, NULL);
285 BMenuBar::SetMaxContentWidth(width - (left + right));
289 void
290 _BMCMenuBar_::SetEnabled(bool enabled)
292 fMenuField->SetEnabled(enabled);
294 BMenuBar::SetEnabled(enabled);
298 BSize
299 _BMCMenuBar_::MinSize()
301 BSize size;
302 BMenuBar::GetPreferredSize(&size.width, &size.height);
303 if (fShowPopUpMarker) {
304 // account for popup indicator + a few pixels margin
305 size.width += kPopUpIndicatorWidth;
308 return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
312 BSize
313 _BMCMenuBar_::MaxSize()
315 // The maximum width of a normal BMenuBar is unlimited, but we want it
316 // limited.
317 BSize size;
318 BMenuBar::GetPreferredSize(&size.width, &size.height);
320 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size);
324 // #pragma mark - _BMCMenuBar_ private methods
327 void
328 _BMCMenuBar_::_Init()
330 SetFlags(Flags() | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE);
331 SetBorder(B_BORDER_CONTENTS);
333 float left, top, right, bottom;
334 GetItemMargins(&left, &top, &right, &bottom);
336 #if 0
337 // TODO: Better fix would be to make BMenuItem draw text properly
338 // centered
339 font_height fontHeight;
340 GetFontHeight(&fontHeight);
341 top = ceilf((Bounds().Height() - ceilf(fontHeight.ascent)
342 - ceilf(fontHeight.descent)) / 2) + 1;
343 bottom = top - 1;
344 #else
345 // TODO: Fix content location properly. This is just a quick fix to
346 // make the BMenuField label and the super-item of the BMenuBar
347 // align vertically.
348 top++;
349 bottom--;
350 #endif
352 left = right = be_control_look->DefaultLabelSpacing();
354 SetItemMargins(left, top,
355 right + fShowPopUpMarker ? kPopUpIndicatorWidth : 0, bottom);