vfs: check userland buffers before reading them.
[haiku.git] / src / apps / deskbar / TimeView.cpp
blob4fb05facacb6b6e347a0ddf14e8e096e80cd214a
1 /*
2 Open Tracker License
4 Terms and Conditions
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
32 holders.
33 All rights reserved.
37 #include "TimeView.h"
39 #include <algorithm>
41 #include <string.h>
43 #include <Application.h>
44 #include <Catalog.h>
45 #include <Debug.h>
46 #include <Locale.h>
47 #include <MenuItem.h>
48 #include <MessageRunner.h>
49 #include <PopUpMenu.h>
50 #include <Roster.h>
51 #include <Screen.h>
52 #include <Window.h>
54 #include "CalendarMenuWindow.h"
57 static const char* const kMinString = "99:99 AM";
58 static const float kHMargin = 2.0;
61 #undef B_TRANSLATION_CONTEXT
62 #define B_TRANSLATION_CONTEXT "TimeView"
65 TTimeView::TTimeView(float maxWidth, float height)
67 BView(BRect(-100, -100, -90, -90), "_deskbar_tv_",
68 B_FOLLOW_RIGHT | B_FOLLOW_TOP,
69 B_WILL_DRAW | B_PULSE_NEEDED | B_FRAME_EVENTS),
70 fParent(NULL),
71 fMaxWidth(maxWidth),
72 fHeight(height),
73 fOrientation(true),
74 fShowLevel(0),
75 fShowSeconds(false),
76 fShowDayOfWeek(false),
77 fShowTimeZone(false),
78 fTimeFormat(NULL),
79 fDateFormat(NULL)
81 fCurrentTime = fLastTime = time(NULL);
82 fSeconds = fMinute = fHour = 0;
83 fCurrentTimeStr[0] = 0;
84 fCurrentDateStr[0] = 0;
85 fLastTimeStr[0] = 0;
86 fLastDateStr[0] = 0;
87 fNeedToUpdate = true;
88 UpdateTimeFormat();
92 #ifdef AS_REPLICANT
93 TTimeView::TTimeView(BMessage* data)
94 : BView(data),
95 fTimeFormat(NULL),
96 fDateFormat(NULL)
98 fCurrentTime = fLastTime = time(NULL);
99 data->FindBool("seconds", &fShowSeconds);
101 UpdateTimeFormat();
103 #endif
106 TTimeView::~TTimeView()
108 delete fTimeFormat;
109 delete fDateFormat;
113 #ifdef AS_REPLICANT
114 BArchivable*
115 TTimeView::Instantiate(BMessage* data)
117 if (!validate_instantiation(data, "TTimeView"))
118 return NULL;
120 return new TTimeView(data);
124 status_t
125 TTimeView::Archive(BMessage* data, bool deep) const
127 BView::Archive(data, deep);
128 data->AddBool("orientation", fOrientation);
129 data->AddInt16("showLevel", fShowLevel);
130 data->AddBool("showSeconds", fShowSeconds);
131 data->AddBool("showDayOfWeek", fShowDayOfWeek);
132 data->AddBool("showTimeZone", fShowTimeZone);
133 data->AddInt32("deskbar:private_align", B_ALIGN_RIGHT);
135 return B_OK;
137 #endif
140 void
141 TTimeView::AttachedToWindow()
143 fCurrentTime = time(NULL);
145 SetFont(be_plain_font);
146 if (Parent()) {
147 fParent = Parent();
148 AdoptParentColors();
149 } else
150 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
152 CalculateTextPlacement();
153 ResizeToPreferred();
157 void
158 TTimeView::Draw(BRect /*updateRect*/)
160 PushState();
162 SetHighColor(ViewColor());
163 SetLowColor(ViewColor());
164 FillRect(Bounds());
165 SetHighUIColor(B_MENU_ITEM_TEXT_COLOR);
167 DrawString(fCurrentTimeStr, fTimeLocation);
169 PopState();
173 void
174 TTimeView::FrameMoved(BPoint)
176 Update();
180 void
181 TTimeView::GetPreferredSize(float* width, float* height)
183 *height = fHeight;
185 GetCurrentTime();
187 float timeWidth = StringWidth(fCurrentTimeStr);
189 // TODO: SetOrientation never gets called, fix that when in vertical mode,
190 // we want to limit the width so that it can't overlap the bevels in the
191 // parent view.
192 *width = fOrientation ? std::min(fMaxWidth - kHMargin, timeWidth)
193 : timeWidth;
197 void
198 TTimeView::MessageReceived(BMessage* message)
200 switch (message->what) {
201 case kChangeTime:
203 // launch the time prefs app
204 be_roster->Launch("application/x-vnd.Haiku-Time");
205 // tell Time preflet to switch to the clock tab
206 BMessenger messenger("application/x-vnd.Haiku-Time");
207 BMessage switchToClock('SlCk');
208 messenger.SendMessage(&switchToClock);
209 break;
212 case kShowHideTime:
214 be_app->MessageReceived(message);
215 break;
218 case kShowCalendar:
220 BRect bounds(Bounds());
221 BPoint center(bounds.LeftTop());
222 center += BPoint(bounds.Width() / 2, bounds.Height() / 2);
223 ShowCalendar(center);
224 break;
227 default:
228 BView::MessageReceived(message);
229 break;
234 void
235 TTimeView::MouseDown(BPoint point)
237 uint32 buttons;
239 Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
240 if (buttons == B_SECONDARY_MOUSE_BUTTON) {
241 ShowTimeOptions(ConvertToScreen(point));
242 return;
243 } else if (buttons == B_PRIMARY_MOUSE_BUTTON)
244 ShowCalendar(point);
246 // invalidate last time/date strings and call the pulse
247 // method directly to change the display instantly
248 fLastDateStr[0] = '\0';
249 fLastTimeStr[0] = '\0';
250 Pulse();
254 void
255 TTimeView::Pulse()
257 time_t curTime = time(NULL);
258 tm* ct = localtime(&curTime);
259 if (ct == NULL)
260 return;
262 fCurrentTime = curTime;
264 GetCurrentTime();
265 GetCurrentDate();
266 if (strcmp(fCurrentTimeStr, fLastTimeStr) != 0) {
267 // Update bounds when the size of the strings has changed
268 Update();
270 strlcpy(fLastTimeStr, fCurrentTimeStr, sizeof(fLastTimeStr));
271 fNeedToUpdate = true;
274 // Update the tooltip if the date has changed
275 if (strcmp(fCurrentDateStr, fLastDateStr) != 0) {
276 strlcpy(fLastDateStr, fCurrentDateStr, sizeof(fLastDateStr));
277 SetToolTip(fCurrentDateStr);
280 if (fNeedToUpdate) {
281 fSeconds = ct->tm_sec;
282 fMinute = ct->tm_min;
283 fHour = ct->tm_hour;
285 Draw(Bounds());
286 fNeedToUpdate = false;
291 void
292 TTimeView::ResizeToPreferred()
294 float width;
295 float height;
296 float oldWidth = Bounds().Width();
297 float oldHeight = Bounds().Height();
299 GetPreferredSize(&width, &height);
300 if (height != oldHeight || width != oldWidth) {
301 ResizeTo(width, height);
302 MoveBy(oldWidth - width, 0);
303 fNeedToUpdate = true;
308 // # pragma mark - Public methods
311 void
312 TTimeView::SetOrientation(bool orientation)
314 fOrientation = orientation;
315 CalculateTextPlacement();
316 Invalidate();
320 bool
321 TTimeView::ShowSeconds() const
323 return fShowSeconds;
327 void
328 TTimeView::SetShowSeconds(bool show)
330 fShowSeconds = show;
331 UpdateTimeFormat();
332 Update();
336 bool
337 TTimeView::ShowDayOfWeek() const
339 return fShowDayOfWeek;
343 void
344 TTimeView::SetShowDayOfWeek(bool show)
346 fShowDayOfWeek = show;
347 UpdateTimeFormat();
348 Update();
352 bool
353 TTimeView::ShowTimeZone() const
355 return fShowTimeZone;
359 void
360 TTimeView::SetShowTimeZone(bool show)
362 fShowTimeZone = show;
363 UpdateTimeFormat();
364 Update();
368 void
369 TTimeView::ShowCalendar(BPoint where)
371 if (fCalendarWindow.IsValid()) {
372 // If the calendar is already shown, just activate it
373 BMessage activate(B_SET_PROPERTY);
374 activate.AddSpecifier("Active");
375 activate.AddBool("data", true);
377 if (fCalendarWindow.SendMessage(&activate) == B_OK)
378 return;
381 where.y = Bounds().bottom + 4.0;
382 ConvertToScreen(&where);
384 if (where.y >= BScreen().Frame().bottom)
385 where.y -= (Bounds().Height() + 4.0);
387 CalendarMenuWindow* window = new CalendarMenuWindow(where);
388 fCalendarWindow = BMessenger(window);
390 window->Show();
394 // # pragma mark - Private methods
397 void
398 TTimeView::UpdateTimeFormat()
400 int32 fields = B_DATE_ELEMENT_HOUR | B_DATE_ELEMENT_MINUTE;
401 if (fShowSeconds)
402 fields |= B_DATE_ELEMENT_SECOND;
403 if (fShowDayOfWeek)
404 fields |= B_DATE_ELEMENT_WEEKDAY;
405 if (fShowTimeZone)
406 fields |= B_DATE_ELEMENT_TIMEZONE;
408 delete fTimeFormat;
409 fTimeFormat = new BDateTimeFormat(BLocale::Default());
410 fTimeFormat->SetDateTimeFormat(B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT, fields);
412 delete fDateFormat;
413 fDateFormat = new BDateFormat(BLocale::Default());
416 void
417 TTimeView::GetCurrentTime()
419 fTimeFormat->Format(fCurrentTimeStr, sizeof(fCurrentTimeStr), fCurrentTime,
420 B_SHORT_DATE_FORMAT, B_SHORT_TIME_FORMAT);
424 void
425 TTimeView::GetCurrentDate()
427 char tmp[sizeof(fCurrentDateStr)];
429 fDateFormat->Format(tmp, sizeof(fCurrentDateStr), fCurrentTime,
430 B_FULL_DATE_FORMAT);
432 // remove leading 0 from date when month is less than 10 (MM/DD/YY)
433 // or remove leading 0 from date when day is less than 10 (DD/MM/YY)
434 const char* str = tmp;
435 if (str[0] == '0')
436 str++;
438 strlcpy(fCurrentDateStr, str, sizeof(fCurrentDateStr));
442 void
443 TTimeView::CalculateTextPlacement()
445 BRect bounds(Bounds());
447 fDateLocation.x = 0.0;
448 fTimeLocation.x = 0.0;
450 BFont font;
451 GetFont(&font);
453 const char* stringArray[1];
454 stringArray[0] = fCurrentTimeStr;
455 BRect rectArray[1];
456 escapement_delta delta = { 0.0, 0.0 };
457 font.GetBoundingBoxesForStrings(stringArray, 1, B_SCREEN_METRIC, &delta,
458 rectArray);
460 fTimeLocation.y = fDateLocation.y = ceilf((bounds.Height()
461 - rectArray[0].Height() + 1.0) / 2.0 - rectArray[0].top);
465 void
466 TTimeView::ShowTimeOptions(BPoint point)
468 BPopUpMenu* menu = new BPopUpMenu("", false, false);
469 menu->SetFont(be_plain_font);
470 BMenuItem* item;
472 item = new BMenuItem(B_TRANSLATE("Time preferences" B_UTF8_ELLIPSIS),
473 new BMessage(kChangeTime));
474 menu->AddItem(item);
476 item = new BMenuItem(B_TRANSLATE("Hide clock"),
477 new BMessage(kShowHideTime));
478 menu->AddItem(item);
480 item = new BMenuItem(B_TRANSLATE("Show calendar" B_UTF8_ELLIPSIS),
481 new BMessage(kShowCalendar));
482 menu->AddItem(item);
484 menu->SetTargetForItems(this);
485 // Changed to accept screen coord system point;
486 // not constrained to this view now
487 menu->Go(point, true, true, BRect(point.x - 4, point.y - 4,
488 point.x + 4, point.y +4), true);
492 void
493 TTimeView::Update()
495 GetCurrentTime();
496 GetCurrentDate();
497 SetToolTip(fCurrentDateStr);
499 CalculateTextPlacement();
500 ResizeToPreferred();
502 if (fParent != NULL)
503 fParent->Invalidate();