Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / kits / tracker / Utilities.cpp
blobd161e471a7b92ea0b963870c5dde3de64c6ab79a
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 trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
36 #include "Utilities.h"
38 #include <ctype.h>
39 #include <fs_attr.h>
40 #include <fs_info.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <time.h>
46 #include <BitmapStream.h>
47 #include <Catalog.h>
48 #include <Debug.h>
49 #include <Font.h>
50 #include <IconUtils.h>
51 #include <MenuItem.h>
52 #include <OS.h>
53 #include <PopUpMenu.h>
54 #include <Region.h>
55 #include <StorageDefs.h>
56 #include <TextView.h>
57 #include <Volume.h>
58 #include <VolumeRoster.h>
59 #include <Window.h>
61 #include "Attributes.h"
62 #include "ContainerWindow.h"
63 #include "MimeTypes.h"
64 #include "Model.h"
65 #include "PoseView.h"
68 #ifndef _IMPEXP_BE
69 # define _IMPEXP_BE
70 #endif
71 extern _IMPEXP_BE const uint32 LARGE_ICON_TYPE;
72 extern _IMPEXP_BE const uint32 MINI_ICON_TYPE;
75 FILE* logFile = NULL;
77 static const float kMinSeparatorStubX = 10;
78 static const float kStubToStringSlotX = 5;
81 namespace BPrivate {
83 const float kExactMatchScore = INFINITY;
86 bool gLocalizedNamePreferred;
89 bool
90 SecondaryMouseButtonDown(int32 modifiers, int32 buttons)
92 return (buttons & B_SECONDARY_MOUSE_BUTTON) != 0
93 || ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0
94 && (modifiers & B_CONTROL_KEY) != 0);
98 uint32
99 HashString(const char* string, uint32 seed)
101 char ch;
102 uint32 hash = seed;
104 while((ch = *string++) != 0) {
105 hash = (hash << 7) ^ (hash >> 24);
106 hash ^= ch;
108 hash ^= hash << 12;
110 return hash;
114 uint32
115 AttrHashString(const char* string, uint32 type)
117 char c;
118 uint32 hash = 0;
120 while((c = *string++) != 0) {
121 hash = (hash << 7) ^ (hash >> 24);
122 hash ^= c;
124 hash ^= hash << 12;
126 hash &= ~0xff;
127 hash |= type;
129 return hash;
133 bool
134 ValidateStream(BMallocIO* stream, uint32 key, int32 version)
136 uint32 testKey;
137 int32 testVersion;
139 if (stream->Read(&testKey, sizeof(uint32)) <= 0
140 || stream->Read(&testVersion, sizeof(int32)) <= 0) {
141 return false;
144 return testKey == key && testVersion == version;
148 void
149 DisallowFilenameKeys(BTextView* textView)
151 textView->DisallowChar('/');
155 void
156 DisallowMetaKeys(BTextView* textView)
158 textView->DisallowChar(B_TAB);
159 textView->DisallowChar(B_ESCAPE);
160 textView->DisallowChar(B_INSERT);
161 textView->DisallowChar(B_DELETE);
162 textView->DisallowChar(B_HOME);
163 textView->DisallowChar(B_END);
164 textView->DisallowChar(B_PAGE_UP);
165 textView->DisallowChar(B_PAGE_DOWN);
166 textView->DisallowChar(B_FUNCTION_KEY);
170 PeriodicUpdatePoses::PeriodicUpdatePoses()
172 fPoseList(20, true)
174 fLock = new Benaphore("PeriodicUpdatePoses");
178 PeriodicUpdatePoses::~PeriodicUpdatePoses()
180 fLock->Lock();
181 fPoseList.MakeEmpty();
182 delete fLock;
186 void
187 PeriodicUpdatePoses::AddPose(BPose* pose, BPoseView* poseView,
188 PeriodicUpdateCallback callback, void* cookie)
190 periodic_pose* periodic = new periodic_pose;
191 periodic->pose = pose;
192 periodic->pose_view = poseView;
193 periodic->callback = callback;
194 periodic->cookie = cookie;
195 fPoseList.AddItem(periodic);
199 bool
200 PeriodicUpdatePoses::RemovePose(BPose* pose, void** cookie)
202 int32 count = fPoseList.CountItems();
203 for (int32 index = 0; index < count; index++) {
204 if (fPoseList.ItemAt(index)->pose == pose) {
205 if (!fLock->Lock())
206 return false;
208 periodic_pose* periodic = fPoseList.RemoveItemAt(index);
209 if (cookie)
210 *cookie = periodic->cookie;
211 delete periodic;
212 fLock->Unlock();
213 return true;
217 return false;
221 void
222 PeriodicUpdatePoses::DoPeriodicUpdate(bool forceRedraw)
224 if (!fLock->Lock())
225 return;
227 int32 count = fPoseList.CountItems();
228 for (int32 index = 0; index < count; index++) {
229 periodic_pose* periodic = fPoseList.ItemAt(index);
230 if ((periodic->callback(periodic->pose, periodic->cookie)
231 || forceRedraw) && periodic->pose_view->LockLooper()) {
232 periodic->pose_view->UpdateIcon(periodic->pose);
233 periodic->pose_view->UnlockLooper();
237 fLock->Unlock();
241 PeriodicUpdatePoses gPeriodicUpdatePoses;
243 } // namespace BPrivate
246 void
247 PoseInfo::EndianSwap(void* castToThis)
249 PoseInfo* self = (PoseInfo*)castToThis;
251 PRINT(("swapping PoseInfo\n"));
253 STATIC_ASSERT(sizeof(ino_t) == sizeof(int64));
254 self->fInitedDirectory = SwapInt64(self->fInitedDirectory);
255 swap_data(B_POINT_TYPE, &self->fLocation, sizeof(BPoint), B_SWAP_ALWAYS);
257 // do a sanity check on the icon position
258 if (self->fLocation.x < -20000 || self->fLocation.x > 20000
259 || self->fLocation.y < -20000 || self->fLocation.y > 20000) {
260 // position out of range, force autoplcemement
261 PRINT((" rejecting icon position out of range\n"));
262 self->fInitedDirectory = -1LL;
263 self->fLocation = BPoint(0, 0);
268 void
269 PoseInfo::PrintToStream()
271 PRINT(("%s, inode:%" B_PRIx64 ", location %f %f\n",
272 fInvisible ? "hidden" : "visible",
273 fInitedDirectory, fLocation.x, fLocation.y));
277 // #pragma mark - ExtendedPoseInfo
280 size_t
281 ExtendedPoseInfo::Size() const
283 return sizeof(ExtendedPoseInfo) + fNumFrames * sizeof(FrameLocation);
287 size_t
288 ExtendedPoseInfo::Size(int32 count)
290 return sizeof(ExtendedPoseInfo) + count * sizeof(FrameLocation);
294 size_t
295 ExtendedPoseInfo::SizeWithHeadroom() const
297 return sizeof(ExtendedPoseInfo) + (fNumFrames + 1) * sizeof(FrameLocation);
301 size_t
302 ExtendedPoseInfo::SizeWithHeadroom(size_t oldSize)
304 int32 count = (ssize_t)oldSize - (ssize_t)sizeof(ExtendedPoseInfo);
305 if (count > 0)
306 count /= sizeof(FrameLocation);
307 else
308 count = 0;
310 return Size(count + 1);
314 bool
315 ExtendedPoseInfo::HasLocationForFrame(BRect frame) const
317 for (int32 index = 0; index < fNumFrames; index++) {
318 if (fLocations[index].fFrame == frame)
319 return true;
322 return false;
326 BPoint
327 ExtendedPoseInfo::LocationForFrame(BRect frame) const
329 for (int32 index = 0; index < fNumFrames; index++) {
330 if (fLocations[index].fFrame == frame)
331 return fLocations[index].fLocation;
334 TRESPASS();
335 return BPoint(0, 0);
339 bool
340 ExtendedPoseInfo::SetLocationForFrame(BPoint newLocation, BRect frame)
342 for (int32 index = 0; index < fNumFrames; index++) {
343 if (fLocations[index].fFrame == frame) {
344 if (fLocations[index].fLocation == newLocation)
345 return false;
347 fLocations[index].fLocation = newLocation;
348 return true;
352 fLocations[fNumFrames].fFrame = frame;
353 fLocations[fNumFrames].fLocation = newLocation;
354 fLocations[fNumFrames].fWorkspaces = 0xffffffff;
355 fNumFrames++;
357 return true;
361 void
362 ExtendedPoseInfo::EndianSwap(void* castToThis)
364 ExtendedPoseInfo* self = (ExtendedPoseInfo *)castToThis;
366 PRINT(("swapping ExtendedPoseInfo\n"));
368 self->fWorkspaces = SwapUInt32(self->fWorkspaces);
369 self->fNumFrames = SwapInt32(self->fNumFrames);
371 for (int32 index = 0; index < self->fNumFrames; index++) {
372 swap_data(B_POINT_TYPE, &self->fLocations[index].fLocation,
373 sizeof(BPoint), B_SWAP_ALWAYS);
375 if (self->fLocations[index].fLocation.x < -20000
376 || self->fLocations[index].fLocation.x > 20000
377 || self->fLocations[index].fLocation.y < -20000
378 || self->fLocations[index].fLocation.y > 20000) {
379 // position out of range, force autoplcemement
380 PRINT((" rejecting icon position out of range\n"));
381 self->fLocations[index].fLocation = BPoint(0, 0);
383 swap_data(B_RECT_TYPE, &self->fLocations[index].fFrame,
384 sizeof(BRect), B_SWAP_ALWAYS);
389 void
390 ExtendedPoseInfo::PrintToStream()
395 // #pragma mark - OffscreenBitmap
398 OffscreenBitmap::OffscreenBitmap(BRect frame)
400 fBitmap(NULL)
402 NewBitmap(frame);
406 OffscreenBitmap::OffscreenBitmap()
408 fBitmap(NULL)
413 OffscreenBitmap::~OffscreenBitmap()
415 delete fBitmap;
419 void
420 OffscreenBitmap::NewBitmap(BRect bounds)
422 delete fBitmap;
423 fBitmap = new(std::nothrow) BBitmap(bounds, B_RGB32, true);
424 if (fBitmap && fBitmap->Lock()) {
425 BView* view = new BView(fBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
426 fBitmap->AddChild(view);
428 BRect clipRect = view->Bounds();
429 BRegion newClip;
430 newClip.Set(clipRect);
431 view->ConstrainClippingRegion(&newClip);
433 fBitmap->Unlock();
434 } else {
435 delete fBitmap;
436 fBitmap = NULL;
441 BView*
442 OffscreenBitmap::BeginUsing(BRect frame)
444 if (!fBitmap || fBitmap->Bounds() != frame)
445 NewBitmap(frame);
447 fBitmap->Lock();
448 return View();
452 void
453 OffscreenBitmap::DoneUsing()
455 fBitmap->Unlock();
459 BBitmap*
460 OffscreenBitmap::Bitmap() const
462 ASSERT(fBitmap);
463 ASSERT(fBitmap->IsLocked());
464 return fBitmap;
468 BView*
469 OffscreenBitmap::View() const
471 ASSERT(fBitmap);
472 return fBitmap->ChildAt(0);
476 // #pragma mark - BPrivate functions
479 namespace BPrivate {
481 // Changes the alpha value of the given bitmap to create a nice
482 // horizontal fade out in the specified region.
483 // "from" is always transparent, "to" opaque.
484 void
485 FadeRGBA32Horizontal(uint32* bits, int32 width, int32 height, int32 from,
486 int32 to)
488 // check parameters
489 if (width < 0 || height < 0 || from < 0 || to < 0)
490 return;
492 float change = 1.f / (to - from);
493 if (from > to) {
494 int32 temp = from;
495 from = to;
496 to = temp;
499 for (int32 y = 0; y < height; y++) {
500 float alpha = change > 0 ? 0.0f : 1.0f;
502 for (int32 x = from; x <= to; x++) {
503 if (bits[x] & 0xff000000) {
504 uint32 a = uint32((bits[x] >> 24) * alpha);
505 bits[x] = (bits[x] & 0x00ffffff) | (a << 24);
507 alpha += change;
509 bits += width;
514 /*! Changes the alpha value of the given bitmap to create a nice
515 vertical fade out in the specified region.
516 "from" is always transparent, "to" opaque.
518 void
519 FadeRGBA32Vertical(uint32* bits, int32 width, int32 height, int32 from,
520 int32 to)
522 // check parameters
523 if (width < 0 || height < 0 || from < 0 || to < 0)
524 return;
526 if (from > to)
527 bits += width * (height - (from - to));
529 float change = 1.f / (to - from);
530 if (from > to) {
531 int32 temp = from;
532 from = to;
533 to = temp;
536 float alpha = change > 0 ? 0.0f : 1.0f;
538 for (int32 y = from; y <= to; y++) {
539 for (int32 x = 0; x < width; x++) {
540 if (bits[x] & 0xff000000) {
541 uint32 a = uint32((bits[x] >> 24) * alpha);
542 bits[x] = (bits[x] & 0x00ffffff) | (a << 24);
545 alpha += change;
546 bits += width;
551 } // namespace BPrivate
554 // #pragma mark - DraggableIcon
557 DraggableIcon::DraggableIcon(BRect rect, const char* name,
558 const char* mimeType, icon_size which, const BMessage* message,
559 BMessenger target, uint32 resizingMode, uint32 flags)
561 BView(rect, name, resizingMode, flags),
562 fMessage(*message),
563 fTarget(target)
565 fBitmap = new BBitmap(Bounds(), kDefaultIconDepth);
566 BMimeType mime(mimeType);
567 status_t result = mime.GetIcon(fBitmap, which);
568 ASSERT(mime.IsValid());
569 if (result != B_OK) {
570 PRINT(("failed to get icon for %s, %s\n", mimeType, strerror(result)));
571 BMimeType mime(B_FILE_MIMETYPE);
572 ASSERT(mime.IsInstalled());
573 mime.GetIcon(fBitmap, which);
578 DraggableIcon::~DraggableIcon()
580 delete fBitmap;
584 void
585 DraggableIcon::SetTarget(BMessenger target)
587 fTarget = target;
591 BRect
592 DraggableIcon::PreferredRect(BPoint offset, icon_size which)
594 BRect rect(0, 0, which - 1, which - 1);
595 rect.OffsetTo(offset);
596 return rect;
600 void
601 DraggableIcon::AttachedToWindow()
603 BView* parent = Parent();
604 if (parent != NULL) {
605 SetViewColor(parent->ViewColor());
606 SetLowColor(parent->LowColor());
611 void
612 DraggableIcon::MouseDown(BPoint point)
614 if (!DragStarted(&fMessage))
615 return;
617 BRect rect(Bounds());
618 BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true);
619 dragBitmap->Lock();
620 BView* view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
621 dragBitmap->AddChild(view);
622 view->SetOrigin(0, 0);
623 BRect clipRect(view->Bounds());
624 BRegion newClip;
625 newClip.Set(clipRect);
626 view->ConstrainClippingRegion(&newClip);
628 // Transparent draw magic
629 view->SetHighColor(0, 0, 0, 0);
630 view->FillRect(view->Bounds());
631 view->SetDrawingMode(B_OP_ALPHA);
632 view->SetHighColor(0, 0, 0, 128);
633 // set the level of transparency by value
634 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
635 view->DrawBitmap(fBitmap);
636 view->Sync();
637 dragBitmap->Unlock();
638 DragMessage(&fMessage, dragBitmap, B_OP_ALPHA, point, fTarget.Target(0));
642 bool
643 DraggableIcon::DragStarted(BMessage*)
645 return true;
649 void
650 DraggableIcon::Draw(BRect)
652 SetDrawingMode(B_OP_ALPHA);
653 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
654 DrawBitmap(fBitmap);
658 // #pragma mark - FlickerFreeStringView
661 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name,
662 const char* text, uint32 resizingMode, uint32 flags)
664 BStringView(bounds, name, text, resizingMode, flags),
665 fBitmap(NULL),
666 fViewColor(ViewColor()),
667 fLowColor(LowColor()),
668 fOriginalBitmap(NULL)
673 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name,
674 const char* text, BBitmap* inBitmap, uint32 resizingMode, uint32 flags)
676 BStringView(bounds, name, text, resizingMode, flags),
677 fBitmap(NULL),
678 fViewColor(ViewColor()),
679 fLowColor(LowColor()),
680 fOriginalBitmap(inBitmap)
685 FlickerFreeStringView::~FlickerFreeStringView()
687 delete fBitmap;
691 void
692 FlickerFreeStringView::Draw(BRect)
694 BRect bounds(Bounds());
695 if (fBitmap == NULL)
696 fBitmap = new OffscreenBitmap(Bounds());
698 BView* offscreen = fBitmap->BeginUsing(bounds);
700 if (Parent() != NULL) {
701 fViewColor = Parent()->ViewColor();
702 fLowColor = Parent()->ViewColor();
705 offscreen->SetViewColor(fViewColor);
706 offscreen->SetHighColor(HighColor());
707 offscreen->SetLowColor(fLowColor);
709 BFont font;
710 GetFont(&font);
711 offscreen->SetFont(&font);
713 offscreen->Sync();
714 if (fOriginalBitmap != NULL)
715 offscreen->DrawBitmap(fOriginalBitmap, Frame(), bounds);
716 else
717 offscreen->FillRect(bounds, B_SOLID_LOW);
719 if (Text() != NULL) {
720 BPoint loc;
722 font_height height;
723 GetFontHeight(&height);
725 edge_info eInfo;
726 switch (Alignment()) {
727 case B_ALIGN_LEFT:
728 case B_ALIGN_HORIZONTAL_UNSET:
729 case B_ALIGN_USE_FULL_WIDTH:
731 // If the first char has a negative left edge give it
732 // some more room by shifting that much more to the right.
733 font.GetEdges(Text(), 1, &eInfo);
734 loc.x = bounds.left + (2 - eInfo.left);
735 break;
738 case B_ALIGN_CENTER:
740 float width = StringWidth(Text());
741 float center = (bounds.right - bounds.left) / 2;
742 loc.x = center - (width/2);
743 break;
746 case B_ALIGN_RIGHT:
748 float width = StringWidth(Text());
749 loc.x = bounds.right - width - 2;
750 break;
753 loc.y = bounds.bottom - (1 + height.descent);
754 offscreen->DrawString(Text(), loc);
756 offscreen->Sync();
757 SetDrawingMode(B_OP_COPY);
758 DrawBitmap(fBitmap->Bitmap());
759 fBitmap->DoneUsing();
763 void
764 FlickerFreeStringView::AttachedToWindow()
766 _inherited::AttachedToWindow();
767 if (Parent() != NULL) {
768 fViewColor = Parent()->ViewColor();
769 fLowColor = Parent()->ViewColor();
771 SetViewColor(B_TRANSPARENT_32_BIT);
772 SetLowColor(B_TRANSPARENT_32_BIT);
776 void
777 FlickerFreeStringView::SetViewColor(rgb_color color)
779 if (fViewColor != color) {
780 fViewColor = color;
781 Invalidate();
783 _inherited::SetViewColor(B_TRANSPARENT_32_BIT);
787 void
788 FlickerFreeStringView::SetLowColor(rgb_color color)
790 if (fLowColor != color) {
791 fLowColor = color;
792 Invalidate();
794 _inherited::SetLowColor(B_TRANSPARENT_32_BIT);
798 // #pragma mark - TitledSeparatorItem
801 TitledSeparatorItem::TitledSeparatorItem(const char* label)
803 BMenuItem(label, 0)
805 _inherited::SetEnabled(false);
809 TitledSeparatorItem::~TitledSeparatorItem()
814 void
815 TitledSeparatorItem::SetEnabled(bool)
817 // leave disabled
821 void
822 TitledSeparatorItem::GetContentSize(float* width, float* height)
824 _inherited::GetContentSize(width, height);
828 inline rgb_color
829 ShiftMenuBackgroundColor(float by)
831 return tint_color(ui_color(B_MENU_BACKGROUND_COLOR), by);
835 void
836 TitledSeparatorItem::Draw()
838 BRect frame(Frame());
840 BMenu* parent = Menu();
841 ASSERT(parent != NULL);
843 menu_info minfo;
844 get_menu_info(&minfo);
846 if (minfo.separator > 0) {
847 frame.left += 10;
848 frame.right -= 10;
849 } else {
850 frame.left += 1;
851 frame.right -= 1;
854 float startX = frame.left;
855 float endX = frame.right;
857 float maxStringWidth = endX - startX - (2 * kMinSeparatorStubX
858 + 2 * kStubToStringSlotX);
860 // ToDo:
861 // handle case where maxStringWidth turns out negative here
863 BString truncatedLabel(Label());
864 parent->TruncateString(&truncatedLabel, B_TRUNCATE_END, maxStringWidth);
866 maxStringWidth = parent->StringWidth(truncatedLabel.String());
868 // first calculate the length of the stub part of the
869 // divider line, so we can use it for secondStartX
870 float firstEndX = ((endX - startX) - maxStringWidth) / 2
871 - kStubToStringSlotX;
872 if (firstEndX < 0)
873 firstEndX = 0;
875 float secondStartX = endX - firstEndX;
877 // now finish calculating firstEndX
878 firstEndX += startX;
880 parent->PushState();
882 int32 y = (int32) (frame.top + (frame.bottom - frame.top) / 2);
884 parent->BeginLineArray(minfo.separator == 2 ? 6 : 4);
885 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y),
886 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
887 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y),
888 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
890 if (minfo.separator == 2) {
891 y++;
892 frame.left++;
893 frame.right--;
894 parent->AddLine(BPoint(frame.left,y), BPoint(firstEndX, y),
895 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
896 parent->AddLine(BPoint(secondStartX,y), BPoint(frame.right, y),
897 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
899 y++;
900 if (minfo.separator == 2) {
901 frame.left++;
902 frame.right--;
904 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y),
905 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
906 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y),
907 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
909 parent->EndLineArray();
911 font_height finfo;
912 parent->GetFontHeight(&finfo);
914 parent->SetLowColor(parent->ViewColor());
915 BPoint loc(firstEndX + kStubToStringSlotX,
916 ContentLocation().y + finfo.ascent);
918 parent->MovePenTo(loc + BPoint(1, 1));
919 parent->SetHighColor(ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
920 parent->DrawString(truncatedLabel.String());
922 parent->MovePenTo(loc);
923 parent->SetHighColor(ShiftMenuBackgroundColor(B_DISABLED_LABEL_TINT));
924 parent->DrawString(truncatedLabel.String());
926 parent->PopState();
930 // #pragma mark - ShortcutFilter
933 ShortcutFilter::ShortcutFilter(uint32 shortcutKey, uint32 shortcutModifier,
934 uint32 shortcutWhat, BHandler* target)
936 BMessageFilter(B_KEY_DOWN),
937 fShortcutKey(shortcutKey),
938 fShortcutModifier(shortcutModifier),
939 fShortcutWhat(shortcutWhat),
940 fTarget(target)
945 filter_result
946 ShortcutFilter::Filter(BMessage* message, BHandler**)
948 if (message->what == B_KEY_DOWN) {
949 uint32 modifiers;
950 uint32 rawKeyChar = 0;
951 uint8 byte = 0;
952 int32 key = 0;
954 if (message->FindInt32("modifiers", (int32*)&modifiers) != B_OK
955 || message->FindInt32("raw_char", (int32*)&rawKeyChar) != B_OK
956 || message->FindInt8("byte", (int8*)&byte) != B_OK
957 || message->FindInt32("key", &key) != B_OK) {
958 return B_DISPATCH_MESSAGE;
961 modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY
962 | B_OPTION_KEY | B_MENU_KEY;
963 // strip caps lock, etc.
965 if (modifiers == fShortcutModifier && rawKeyChar == fShortcutKey) {
966 fTarget->Looper()->PostMessage(fShortcutWhat, fTarget);
967 return B_SKIP_MESSAGE;
971 // let others deal with this
972 return B_DISPATCH_MESSAGE;
976 // #pragma mark - BPrivate functions
979 namespace BPrivate {
981 void
982 EmbedUniqueVolumeInfo(BMessage* message, const BVolume* volume)
984 BDirectory rootDirectory;
985 time_t created;
986 fs_info info;
988 if (volume->GetRootDirectory(&rootDirectory) == B_OK
989 && rootDirectory.GetCreationTime(&created) == B_OK
990 && fs_stat_dev(volume->Device(), &info) == 0) {
991 message->AddInt32("creationDate", created);
992 message->AddInt64("capacity", volume->Capacity());
993 message->AddString("deviceName", info.device_name);
994 message->AddString("volumeName", info.volume_name);
995 message->AddString("fshName", info.fsh_name);
1000 status_t
1001 MatchArchivedVolume(BVolume* volume, const BMessage* message, int32 index)
1003 time_t created;
1004 off_t capacity;
1006 if (message->FindInt32("creationDate", index, &created) != B_OK
1007 || message->FindInt64("capacity", index, &capacity) != B_OK) {
1008 return B_ERROR;
1011 BVolumeRoster roster;
1012 BVolume tempVolume;
1013 BString deviceName;
1014 BString volumeName;
1015 BString fshName;
1017 if (message->FindString("deviceName", &deviceName) == B_OK
1018 && message->FindString("volumeName", &volumeName) == B_OK
1019 && message->FindString("fshName", &fshName) == B_OK) {
1020 // New style volume identifiers: We have a couple of characteristics,
1021 // and compute a score from them. The volume with the greatest score
1022 // (if over a certain threshold) is the one we're looking for. We
1023 // pick the first volume, in case there is more than one with the
1024 // same score.
1025 dev_t foundDevice = -1;
1026 int foundScore = -1;
1027 roster.Rewind();
1028 while (roster.GetNextVolume(&tempVolume) == B_OK) {
1029 if (tempVolume.IsPersistent() && tempVolume.KnowsQuery()) {
1030 // get creation time and fs_info
1031 BDirectory root;
1032 tempVolume.GetRootDirectory(&root);
1033 time_t cmpCreated;
1034 fs_info info;
1035 if (root.GetCreationTime(&cmpCreated) == B_OK
1036 && fs_stat_dev(tempVolume.Device(), &info) == 0) {
1037 // compute the score
1038 int score = 0;
1040 // creation time
1041 if (created == cmpCreated)
1042 score += 5;
1044 // capacity
1045 if (capacity == tempVolume.Capacity())
1046 score += 4;
1048 // device name
1049 if (deviceName == info.device_name)
1050 score += 3;
1052 // volume name
1053 if (volumeName == info.volume_name)
1054 score += 2;
1056 // fsh name
1057 if (fshName == info.fsh_name)
1058 score += 1;
1060 // check score
1061 if (score >= 9 && score > foundScore) {
1062 foundDevice = tempVolume.Device();
1063 foundScore = score;
1068 if (foundDevice >= 0)
1069 return volume->SetTo(foundDevice);
1070 } else {
1071 // Old style volume identifiers: We have only creation time and
1072 // capacity. Both must match.
1073 roster.Rewind();
1074 while (roster.GetNextVolume(&tempVolume) == B_OK) {
1075 if (tempVolume.IsPersistent() && tempVolume.KnowsQuery()) {
1076 BDirectory root;
1077 tempVolume.GetRootDirectory(&root);
1078 time_t cmpCreated;
1079 root.GetCreationTime(&cmpCreated);
1080 if (created == cmpCreated && capacity == tempVolume.Capacity()) {
1081 *volume = tempVolume;
1082 return B_OK;
1088 return B_DEV_BAD_DRIVE_NUM;
1092 void
1093 StringFromStream(BString* string, BMallocIO* stream, bool endianSwap)
1095 int32 length;
1096 stream->Read(&length, sizeof(length));
1097 if (endianSwap)
1098 length = SwapInt32(length);
1100 if (length < 0 || length > 10000) {
1101 // TODO: should fail here
1102 PRINT(("problems instatiating a string, length probably wrong %"
1103 B_PRId32 "\n", length));
1104 return;
1107 char* buffer = string->LockBuffer(length + 1);
1108 stream->Read(buffer, (size_t)length + 1);
1109 string->UnlockBuffer(length);
1113 void
1114 StringToStream(const BString* string, BMallocIO* stream)
1116 int32 length = string->Length();
1117 stream->Write(&length, sizeof(int32));
1118 stream->Write(string->String(), (size_t)string->Length() + 1);
1122 int32
1123 ArchiveSize(const BString* string)
1125 return string->Length() + 1 + (ssize_t)sizeof(int32);
1129 int32
1130 CountRefs(const BMessage* message)
1132 uint32 type;
1133 int32 count;
1134 message->GetInfo("refs", &type, &count);
1136 return count;
1140 static entry_ref*
1141 EachEntryRefCommon(BMessage* message, entry_ref *(*func)(entry_ref*, void*),
1142 void* passThru, int32 maxCount)
1144 uint32 type;
1145 int32 count;
1146 message->GetInfo("refs", &type, &count);
1148 if (maxCount >= 0 && count > maxCount)
1149 count = maxCount;
1151 for (int32 index = 0; index < count; index++) {
1152 entry_ref ref;
1153 message->FindRef("refs", index, &ref);
1154 entry_ref* newRef = (func)(&ref, passThru);
1155 if (newRef != NULL)
1156 return newRef;
1159 return NULL;
1163 bool
1164 ContainsEntryRef(const BMessage* message, const entry_ref* ref)
1166 entry_ref match;
1167 for (int32 index = 0; (message->FindRef("refs", index, &match) == B_OK);
1168 index++) {
1169 if (*ref == match)
1170 return true;
1173 return false;
1177 entry_ref*
1178 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*),
1179 void* passThru)
1181 return EachEntryRefCommon(message, func, passThru, -1);
1184 typedef entry_ref *(*EachEntryIteratee)(entry_ref *, void *);
1187 const entry_ref*
1188 EachEntryRef(const BMessage* message,
1189 const entry_ref* (*func)(const entry_ref*, void*), void* passThru)
1191 return EachEntryRefCommon(const_cast<BMessage*>(message),
1192 (EachEntryIteratee)func, passThru, -1);
1196 entry_ref*
1197 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*),
1198 void* passThru, int32 maxCount)
1200 return EachEntryRefCommon(message, func, passThru, maxCount);
1204 const entry_ref *
1205 EachEntryRef(const BMessage* message,
1206 const entry_ref *(*func)(const entry_ref *, void *), void* passThru,
1207 int32 maxCount)
1209 return EachEntryRefCommon(const_cast<BMessage *>(message),
1210 (EachEntryIteratee)func, passThru, maxCount);
1214 void
1215 TruncateLeaf(BString* string)
1217 for (int32 index = string->Length(); index >= 0; index--) {
1218 if ((*string)[index] == '/') {
1219 string->Truncate(index + 1);
1220 return;
1226 int64
1227 StringToScalar(const char* text)
1229 char* end;
1230 int64 val;
1232 char* buffer = new char [strlen(text) + 1];
1233 strcpy(buffer, text);
1235 if (strstr(buffer, "k") || strstr(buffer, "K")) {
1236 val = strtoll(buffer, &end, 10);
1237 val *= kKBSize;
1238 } else if (strstr(buffer, "mb") || strstr(buffer, "MB")) {
1239 val = strtoll(buffer, &end, 10);
1240 val *= kMBSize;
1241 } else if (strstr(buffer, "gb") || strstr(buffer, "GB")) {
1242 val = strtoll(buffer, &end, 10);
1243 val *= kGBSize;
1244 } else if (strstr(buffer, "byte") || strstr(buffer, "BYTE")) {
1245 val = strtoll(buffer, &end, 10);
1246 val *= kGBSize;
1247 } else {
1248 // no suffix, try plain byte conversion
1249 val = strtoll(buffer, &end, 10);
1251 delete[] buffer;
1253 return val;
1257 static BRect
1258 LineBounds(BPoint where, float length, bool vertical)
1260 BRect rect;
1261 rect.SetLeftTop(where);
1262 rect.SetRightBottom(where + BPoint(2, 2));
1263 if (vertical)
1264 rect.bottom = rect.top + length;
1265 else
1266 rect.right = rect.left + length;
1268 return rect;
1272 SeparatorLine::SeparatorLine(BPoint where, float length, bool vertical,
1273 const char* name)
1275 BView(LineBounds(where, length, vertical), name,
1276 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW)
1278 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
1279 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
1283 void
1284 SeparatorLine::Draw(BRect)
1286 BRect bounds(Bounds());
1287 rgb_color hiliteColor = tint_color(ViewColor(), 1.5f);
1289 bool vertical = (bounds.left > bounds.right - 3);
1290 BeginLineArray(2);
1291 if (vertical) {
1292 AddLine(bounds.LeftTop(), bounds.LeftBottom(), hiliteColor);
1293 AddLine(bounds.LeftTop() + BPoint(1, 0),
1294 bounds.LeftBottom() + BPoint(1, 0), kWhite);
1295 } else {
1296 AddLine(bounds.LeftTop(), bounds.RightTop(), hiliteColor);
1297 AddLine(bounds.LeftTop() + BPoint(0, 1),
1298 bounds.RightTop() + BPoint(0, 1), kWhite);
1300 EndLineArray();
1304 void
1305 HexDump(const void* buf, int32 length)
1307 const int32 kBytesPerLine = 16;
1308 int32 offset;
1309 unsigned char* buffer = (unsigned char*)buf;
1311 for (offset = 0; ; offset += kBytesPerLine, buffer += kBytesPerLine) {
1312 int32 remain = length;
1313 int32 index;
1315 printf( "0x%06x: ", (int)offset);
1317 for (index = 0; index < kBytesPerLine; index++) {
1318 if (remain-- > 0)
1319 printf("%02x%c", buffer[index], remain > 0 ? ',' : ' ');
1320 else
1321 printf(" ");
1324 remain = length;
1325 printf(" \'");
1326 for (index = 0; index < kBytesPerLine; index++) {
1327 if (remain-- > 0)
1328 printf("%c", buffer[index] > ' ' ? buffer[index] : '.');
1329 else
1330 printf(" ");
1332 printf("\'\n");
1334 length -= kBytesPerLine;
1335 if (length <= 0)
1336 break;
1338 fflush(stdout);
1342 void
1343 EnableNamedMenuItem(BMenu* menu, const char* itemName, bool on)
1345 BMenuItem* item = menu->FindItem(itemName);
1346 if (item != NULL)
1347 item->SetEnabled(on);
1351 void
1352 MarkNamedMenuItem(BMenu* menu, const char* itemName, bool on)
1354 BMenuItem* item = menu->FindItem(itemName);
1355 if (item != NULL)
1356 item->SetMarked(on);
1360 void
1361 EnableNamedMenuItem(BMenu* menu, uint32 commandName, bool on)
1363 BMenuItem* item = menu->FindItem(commandName);
1364 if (item != NULL)
1365 item->SetEnabled(on);
1369 void
1370 MarkNamedMenuItem(BMenu* menu, uint32 commandName, bool on)
1372 BMenuItem* item = menu->FindItem(commandName);
1373 if (item != NULL)
1374 item->SetMarked(on);
1378 void
1379 DeleteSubmenu(BMenuItem* submenuItem)
1381 if (submenuItem == NULL)
1382 return;
1384 BMenu* menu = submenuItem->Submenu();
1385 if (menu == NULL)
1386 return;
1388 for (;;) {
1389 BMenuItem* item = menu->RemoveItem((int32)0);
1390 if (item == NULL)
1391 return;
1393 delete item;
1398 status_t
1399 GetAppSignatureFromAttr(BFile* file, char* attr)
1401 // This call is a performance improvement that
1402 // avoids using the BAppFileInfo API when retrieving the
1403 // app signature -- the call is expensive because by default
1404 // the resource fork is scanned to read the attribute
1406 #ifdef B_APP_FILE_INFO_IS_FAST
1407 BAppFileInfo appFileInfo(file);
1408 return appFileInfo.GetSignature(attr);
1409 #else
1410 ssize_t readResult = file->ReadAttr(kAttrAppSignature, B_MIME_STRING_TYPE,
1411 0, attr, B_MIME_TYPE_LENGTH);
1413 if (readResult <= 0)
1414 return (status_t)readResult;
1416 return B_OK;
1417 #endif // B_APP_FILE_INFO_IS_FAST
1421 status_t
1422 GetAppIconFromAttr(BFile* file, BBitmap* icon, icon_size which)
1424 // This call is a performance improvement that
1425 // avoids using the BAppFileInfo API when retrieving the
1426 // app icons -- the call is expensive because by default
1427 // the resource fork is scanned to read the icons
1429 //#ifdef B_APP_FILE_INFO_IS_FAST
1430 BAppFileInfo appFileInfo(file);
1431 return appFileInfo.GetIcon(icon, which);
1432 //#else
1434 // const char* attrName = kAttrIcon;
1435 // uint32 type = B_VECTOR_ICON_TYPE;
1437 // // try vector icon
1438 // attr_info ainfo;
1439 // status_t result = file->GetAttrInfo(attrName, &ainfo);
1441 // if (result == B_OK) {
1442 // uint8 buffer[ainfo.size];
1443 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer,
1444 // ainfo.size);
1445 // if (readResult == ainfo.size) {
1446 // if (BIconUtils::GetVectorIcon(buffer, ainfo.size, icon) == B_OK)
1447 // return B_OK;
1448 // }
1449 // }
1451 // // try again with R5 icons
1452 // attrName = which == B_LARGE_ICON ? kAttrLargeIcon : kAttrMiniIcon;
1453 // type = which == B_LARGE_ICON ? LARGE_ICON_TYPE : MINI_ICON_TYPE;
1455 // result = file->GetAttrInfo(attrName, &ainfo);
1456 // if (result < B_OK)
1457 // return result;
1459 // uint8 buffer[ainfo.size];
1461 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, ainfo.size);
1462 // if (readResult <= 0)
1463 // return (status_t)readResult;
1465 // if (icon->ColorSpace() != B_CMAP8)
1466 // result = BIconUtils::ConvertFromCMAP8(buffer, which, which, which, icon);
1467 // else
1468 // icon->SetBits(buffer, icon->BitsLength(), 0, B_CMAP8);
1470 // return result;
1471 //#endif // B_APP_FILE_INFO_IS_FAST
1475 status_t
1476 GetFileIconFromAttr(BNode* node, BBitmap* icon, icon_size which)
1478 BNodeInfo fileInfo(node);
1479 return fileInfo.GetIcon(icon, which);
1483 void
1484 PrintToStream(rgb_color color)
1486 printf("r:%x, g:%x, b:%x, a:%x\n",
1487 color.red, color.green, color.blue, color.alpha);
1491 extern BMenuItem*
1492 EachMenuItem(BMenu* menu, bool recursive, BMenuItem* (*func)(BMenuItem *))
1494 int32 count = menu->CountItems();
1495 for (int32 index = 0; index < count; index++) {
1496 BMenuItem* item = menu->ItemAt(index);
1497 BMenuItem* newItem = (func)(item);
1498 if (newItem != NULL)
1499 return newItem;
1501 if (recursive) {
1502 BMenu* submenu = menu->SubmenuAt(index);
1503 if (submenu != NULL)
1504 return EachMenuItem(submenu, true, func);
1508 return NULL;
1512 extern const BMenuItem*
1513 EachMenuItem(const BMenu* menu, bool recursive,
1514 BMenuItem* (*func)(const BMenuItem *))
1516 int32 count = menu->CountItems();
1517 for (int32 index = 0; index < count; index++) {
1518 BMenuItem* item = menu->ItemAt(index);
1519 BMenuItem* newItem = (func)(item);
1520 if (newItem != NULL)
1521 return newItem;
1523 if (recursive) {
1524 BMenu* submenu = menu->SubmenuAt(index);
1525 if (submenu != NULL)
1526 return EachMenuItem(submenu, true, func);
1530 return NULL;
1534 // #pragma mark - PositionPassingMenuItem
1537 PositionPassingMenuItem::PositionPassingMenuItem(const char* title,
1538 BMessage* message, char shortcut, uint32 modifiers)
1540 BMenuItem(title, message, shortcut, modifiers)
1545 PositionPassingMenuItem::PositionPassingMenuItem(BMenu* menu, BMessage* message)
1547 BMenuItem(menu, message)
1552 status_t
1553 PositionPassingMenuItem::Invoke(BMessage* message)
1555 if (Menu() == NULL)
1556 return B_ERROR;
1558 if (!IsEnabled())
1559 return B_ERROR;
1561 if (message == NULL)
1562 message = Message();
1564 if (message == NULL)
1565 return B_BAD_VALUE;
1567 BMessage clone(*message);
1568 clone.AddInt32("index", Menu()->IndexOf(this));
1569 clone.AddInt64("when", system_time());
1570 clone.AddPointer("source", this);
1572 // embed the invoke location of the menu so that we can create
1573 // a new folder, etc. on the spot
1574 BMenu* menu = Menu();
1576 for (;;) {
1577 if (!menu->Supermenu())
1578 break;
1580 menu = menu->Supermenu();
1583 // use the window position only, if the item was invoked from the menu
1584 // menu->Window() points to the window the item was invoked from
1585 if (dynamic_cast<BContainerWindow*>(menu->Window()) == NULL) {
1586 LooperAutoLocker lock(menu);
1587 if (lock.IsLocked()) {
1588 BPoint invokeOrigin(menu->Window()->Frame().LeftTop());
1589 clone.AddPoint("be:invoke_origin", invokeOrigin);
1593 return BInvoker::Invoke(&clone);
1597 // #pragma mark - BPrivate functions
1600 bool
1601 BootedInSafeMode()
1603 const char* safeMode = getenv("SAFEMODE");
1604 return (safeMode && strcmp(safeMode, "yes") == 0);
1608 float
1609 ComputeTypeAheadScore(const char* text, const char* match, bool wordMode)
1611 // highest score: exact match
1612 const char* found = strcasestr(text, match);
1613 if (found != NULL) {
1614 if (found == text)
1615 return kExactMatchScore;
1617 return 1.f / (found - text);
1620 // there was no exact match
1622 // second best: all characters at word beginnings
1623 if (wordMode) {
1624 float score = 0;
1625 for (int32 j = 0, k = 0; match[j]; j++) {
1626 while (text[k]
1627 && tolower(text[k]) != tolower(match[j])) {
1628 k++;
1630 if (text[k] == '\0') {
1631 score = 0;
1632 break;
1635 bool wordStart = k == 0 || isspace(text[k - 1]);
1636 if (wordStart)
1637 score++;
1638 if (j > 0) {
1639 bool wordEnd = !text[k + 1] || isspace(text[k + 1]);
1640 if (wordEnd)
1641 score += 0.3;
1642 if (match[j - 1] == text[k - 1])
1643 score += 0.7;
1646 score += 1.f / (k + 1);
1647 k++;
1650 return score;
1653 return -1;
1657 // #pragma mark - throw on error functions.
1660 void
1661 _ThrowOnError(status_t result, const char* DEBUG_ONLY(file),
1662 int32 DEBUG_ONLY(line))
1664 if (result != B_OK) {
1665 PRINT(("%s at %s:%d\n", strerror(result), file, (int)line));
1666 throw result;
1671 void
1672 _ThrowIfNotSize(ssize_t size, const char* DEBUG_ONLY(file),
1673 int32 DEBUG_ONLY(line))
1675 if (size < B_OK) {
1676 PRINT(("%s at %s:%d\n", strerror((status_t)size), file, (int)line));
1677 throw (status_t)size;
1682 void
1683 _ThrowOnAssert(bool success, const char* DEBUG_ONLY(file),
1684 int32 DEBUG_ONLY(line))
1686 if (!success) {
1687 PRINT(("Assert failed at %s:%d\n", file, (int)line));
1688 throw B_ERROR;
1692 } // namespace BPrivate