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.
36 #include "Utilities.h"
46 #include <BitmapStream.h>
50 #include <IconUtils.h>
53 #include <PopUpMenu.h>
55 #include <StorageDefs.h>
58 #include <VolumeRoster.h>
61 #include "Attributes.h"
62 #include "ContainerWindow.h"
63 #include "MimeTypes.h"
71 extern _IMPEXP_BE
const uint32 LARGE_ICON_TYPE
;
72 extern _IMPEXP_BE
const uint32 MINI_ICON_TYPE
;
77 static const float kMinSeparatorStubX
= 10;
78 static const float kStubToStringSlotX
= 5;
83 const float kExactMatchScore
= INFINITY
;
86 bool gLocalizedNamePreferred
;
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);
99 HashString(const char* string
, uint32 seed
)
104 while((ch
= *string
++) != 0) {
105 hash
= (hash
<< 7) ^ (hash
>> 24);
115 AttrHashString(const char* string
, uint32 type
)
120 while((c
= *string
++) != 0) {
121 hash
= (hash
<< 7) ^ (hash
>> 24);
134 ValidateStream(BMallocIO
* stream
, uint32 key
, int32 version
)
139 if (stream
->Read(&testKey
, sizeof(uint32
)) <= 0
140 || stream
->Read(&testVersion
, sizeof(int32
)) <= 0) {
144 return testKey
== key
&& testVersion
== version
;
149 DisallowFilenameKeys(BTextView
* textView
)
151 textView
->DisallowChar('/');
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()
174 fLock
= new Benaphore("PeriodicUpdatePoses");
178 PeriodicUpdatePoses::~PeriodicUpdatePoses()
181 fPoseList
.MakeEmpty();
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
);
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
) {
208 periodic_pose
* periodic
= fPoseList
.RemoveItemAt(index
);
210 *cookie
= periodic
->cookie
;
222 PeriodicUpdatePoses::DoPeriodicUpdate(bool forceRedraw
)
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();
241 PeriodicUpdatePoses gPeriodicUpdatePoses
;
243 } // namespace BPrivate
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);
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
281 ExtendedPoseInfo::Size() const
283 return sizeof(ExtendedPoseInfo
) + fNumFrames
* sizeof(FrameLocation
);
288 ExtendedPoseInfo::Size(int32 count
)
290 return sizeof(ExtendedPoseInfo
) + count
* sizeof(FrameLocation
);
295 ExtendedPoseInfo::SizeWithHeadroom() const
297 return sizeof(ExtendedPoseInfo
) + (fNumFrames
+ 1) * sizeof(FrameLocation
);
302 ExtendedPoseInfo::SizeWithHeadroom(size_t oldSize
)
304 int32 count
= (ssize_t
)oldSize
- (ssize_t
)sizeof(ExtendedPoseInfo
);
306 count
/= sizeof(FrameLocation
);
310 return Size(count
+ 1);
315 ExtendedPoseInfo::HasLocationForFrame(BRect frame
) const
317 for (int32 index
= 0; index
< fNumFrames
; index
++) {
318 if (fLocations
[index
].fFrame
== frame
)
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
;
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
)
347 fLocations
[index
].fLocation
= newLocation
;
352 fLocations
[fNumFrames
].fFrame
= frame
;
353 fLocations
[fNumFrames
].fLocation
= newLocation
;
354 fLocations
[fNumFrames
].fWorkspaces
= 0xffffffff;
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
);
390 ExtendedPoseInfo::PrintToStream()
395 // #pragma mark - OffscreenBitmap
398 OffscreenBitmap::OffscreenBitmap(BRect frame
)
406 OffscreenBitmap::OffscreenBitmap()
413 OffscreenBitmap::~OffscreenBitmap()
420 OffscreenBitmap::NewBitmap(BRect bounds
)
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();
430 newClip
.Set(clipRect
);
431 view
->ConstrainClippingRegion(&newClip
);
442 OffscreenBitmap::BeginUsing(BRect frame
)
444 if (!fBitmap
|| fBitmap
->Bounds() != frame
)
453 OffscreenBitmap::DoneUsing()
460 OffscreenBitmap::Bitmap() const
463 ASSERT(fBitmap
->IsLocked());
469 OffscreenBitmap::View() const
472 return fBitmap
->ChildAt(0);
476 // #pragma mark - BPrivate functions
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.
485 FadeRGBA32Horizontal(uint32
* bits
, int32 width
, int32 height
, int32 from
,
489 if (width
< 0 || height
< 0 || from
< 0 || to
< 0)
492 float change
= 1.f
/ (to
- from
);
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);
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.
519 FadeRGBA32Vertical(uint32
* bits
, int32 width
, int32 height
, int32 from
,
523 if (width
< 0 || height
< 0 || from
< 0 || to
< 0)
527 bits
+= width
* (height
- (from
- to
));
529 float change
= 1.f
/ (to
- from
);
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);
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
),
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()
585 DraggableIcon::SetTarget(BMessenger target
)
592 DraggableIcon::PreferredRect(BPoint offset
, icon_size which
)
594 BRect
rect(0, 0, which
- 1, which
- 1);
595 rect
.OffsetTo(offset
);
601 DraggableIcon::AttachedToWindow()
603 BView
* parent
= Parent();
604 if (parent
!= NULL
) {
605 SetViewColor(parent
->ViewColor());
606 SetLowColor(parent
->LowColor());
612 DraggableIcon::MouseDown(BPoint point
)
614 if (!DragStarted(&fMessage
))
617 BRect
rect(Bounds());
618 BBitmap
* dragBitmap
= new BBitmap(rect
, B_RGBA32
, true);
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());
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
);
637 dragBitmap
->Unlock();
638 DragMessage(&fMessage
, dragBitmap
, B_OP_ALPHA
, point
, fTarget
.Target(0));
643 DraggableIcon::DragStarted(BMessage
*)
650 DraggableIcon::Draw(BRect
)
652 SetDrawingMode(B_OP_ALPHA
);
653 SetBlendingMode(B_PIXEL_ALPHA
, B_ALPHA_OVERLAY
);
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
),
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
),
678 fViewColor(ViewColor()),
679 fLowColor(LowColor()),
680 fOriginalBitmap(inBitmap
)
685 FlickerFreeStringView::~FlickerFreeStringView()
692 FlickerFreeStringView::Draw(BRect
)
694 BRect
bounds(Bounds());
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
);
711 offscreen
->SetFont(&font
);
714 if (fOriginalBitmap
!= NULL
)
715 offscreen
->DrawBitmap(fOriginalBitmap
, Frame(), bounds
);
717 offscreen
->FillRect(bounds
, B_SOLID_LOW
);
719 if (Text() != NULL
) {
723 GetFontHeight(&height
);
726 switch (Alignment()) {
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
);
740 float width
= StringWidth(Text());
741 float center
= (bounds
.right
- bounds
.left
) / 2;
742 loc
.x
= center
- (width
/2);
748 float width
= StringWidth(Text());
749 loc
.x
= bounds
.right
- width
- 2;
753 loc
.y
= bounds
.bottom
- (1 + height
.descent
);
754 offscreen
->DrawString(Text(), loc
);
757 SetDrawingMode(B_OP_COPY
);
758 DrawBitmap(fBitmap
->Bitmap());
759 fBitmap
->DoneUsing();
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
);
777 FlickerFreeStringView::SetViewColor(rgb_color color
)
779 if (fViewColor
!= color
) {
783 _inherited::SetViewColor(B_TRANSPARENT_32_BIT
);
788 FlickerFreeStringView::SetLowColor(rgb_color color
)
790 if (fLowColor
!= color
) {
794 _inherited::SetLowColor(B_TRANSPARENT_32_BIT
);
798 // #pragma mark - TitledSeparatorItem
801 TitledSeparatorItem::TitledSeparatorItem(const char* label
)
805 _inherited::SetEnabled(false);
809 TitledSeparatorItem::~TitledSeparatorItem()
815 TitledSeparatorItem::SetEnabled(bool)
822 TitledSeparatorItem::GetContentSize(float* width
, float* height
)
824 _inherited::GetContentSize(width
, height
);
829 ShiftMenuBackgroundColor(float by
)
831 return tint_color(ui_color(B_MENU_BACKGROUND_COLOR
), by
);
836 TitledSeparatorItem::Draw()
838 BRect
frame(Frame());
840 BMenu
* parent
= Menu();
841 ASSERT(parent
!= NULL
);
844 get_menu_info(&minfo
);
846 if (minfo
.separator
> 0) {
854 float startX
= frame
.left
;
855 float endX
= frame
.right
;
857 float maxStringWidth
= endX
- startX
- (2 * kMinSeparatorStubX
858 + 2 * kStubToStringSlotX
);
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
;
875 float secondStartX
= endX
- firstEndX
;
877 // now finish calculating firstEndX
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) {
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
));
900 if (minfo
.separator
== 2) {
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();
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());
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
),
946 ShortcutFilter::Filter(BMessage
* message
, BHandler
**)
948 if (message
->what
== B_KEY_DOWN
) {
950 uint32 rawKeyChar
= 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
982 EmbedUniqueVolumeInfo(BMessage
* message
, const BVolume
* volume
)
984 BDirectory rootDirectory
;
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
);
1001 MatchArchivedVolume(BVolume
* volume
, const BMessage
* message
, int32 index
)
1006 if (message
->FindInt32("creationDate", index
, &created
) != B_OK
1007 || message
->FindInt64("capacity", index
, &capacity
) != B_OK
) {
1011 BVolumeRoster roster
;
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
1025 dev_t foundDevice
= -1;
1026 int foundScore
= -1;
1028 while (roster
.GetNextVolume(&tempVolume
) == B_OK
) {
1029 if (tempVolume
.IsPersistent() && tempVolume
.KnowsQuery()) {
1030 // get creation time and fs_info
1032 tempVolume
.GetRootDirectory(&root
);
1035 if (root
.GetCreationTime(&cmpCreated
) == B_OK
1036 && fs_stat_dev(tempVolume
.Device(), &info
) == 0) {
1037 // compute the score
1041 if (created
== cmpCreated
)
1045 if (capacity
== tempVolume
.Capacity())
1049 if (deviceName
== info
.device_name
)
1053 if (volumeName
== info
.volume_name
)
1057 if (fshName
== info
.fsh_name
)
1061 if (score
>= 9 && score
> foundScore
) {
1062 foundDevice
= tempVolume
.Device();
1068 if (foundDevice
>= 0)
1069 return volume
->SetTo(foundDevice
);
1071 // Old style volume identifiers: We have only creation time and
1072 // capacity. Both must match.
1074 while (roster
.GetNextVolume(&tempVolume
) == B_OK
) {
1075 if (tempVolume
.IsPersistent() && tempVolume
.KnowsQuery()) {
1077 tempVolume
.GetRootDirectory(&root
);
1079 root
.GetCreationTime(&cmpCreated
);
1080 if (created
== cmpCreated
&& capacity
== tempVolume
.Capacity()) {
1081 *volume
= tempVolume
;
1088 return B_DEV_BAD_DRIVE_NUM
;
1093 StringFromStream(BString
* string
, BMallocIO
* stream
, bool endianSwap
)
1096 stream
->Read(&length
, sizeof(length
));
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
));
1107 char* buffer
= string
->LockBuffer(length
+ 1);
1108 stream
->Read(buffer
, (size_t)length
+ 1);
1109 string
->UnlockBuffer(length
);
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);
1123 ArchiveSize(const BString
* string
)
1125 return string
->Length() + 1 + (ssize_t
)sizeof(int32
);
1130 CountRefs(const BMessage
* message
)
1134 message
->GetInfo("refs", &type
, &count
);
1141 EachEntryRefCommon(BMessage
* message
, entry_ref
*(*func
)(entry_ref
*, void*),
1142 void* passThru
, int32 maxCount
)
1146 message
->GetInfo("refs", &type
, &count
);
1148 if (maxCount
>= 0 && count
> maxCount
)
1151 for (int32 index
= 0; index
< count
; index
++) {
1153 message
->FindRef("refs", index
, &ref
);
1154 entry_ref
* newRef
= (func
)(&ref
, passThru
);
1164 ContainsEntryRef(const BMessage
* message
, const entry_ref
* ref
)
1167 for (int32 index
= 0; (message
->FindRef("refs", index
, &match
) == B_OK
);
1178 EachEntryRef(BMessage
* message
, entry_ref
* (*func
)(entry_ref
*, void*),
1181 return EachEntryRefCommon(message
, func
, passThru
, -1);
1184 typedef entry_ref
*(*EachEntryIteratee
)(entry_ref
*, void *);
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);
1197 EachEntryRef(BMessage
* message
, entry_ref
* (*func
)(entry_ref
*, void*),
1198 void* passThru
, int32 maxCount
)
1200 return EachEntryRefCommon(message
, func
, passThru
, maxCount
);
1205 EachEntryRef(const BMessage
* message
,
1206 const entry_ref
*(*func
)(const entry_ref
*, void *), void* passThru
,
1209 return EachEntryRefCommon(const_cast<BMessage
*>(message
),
1210 (EachEntryIteratee
)func
, passThru
, maxCount
);
1215 TruncateLeaf(BString
* string
)
1217 for (int32 index
= string
->Length(); index
>= 0; index
--) {
1218 if ((*string
)[index
] == '/') {
1219 string
->Truncate(index
+ 1);
1227 StringToScalar(const char* text
)
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);
1238 } else if (strstr(buffer
, "mb") || strstr(buffer
, "MB")) {
1239 val
= strtoll(buffer
, &end
, 10);
1241 } else if (strstr(buffer
, "gb") || strstr(buffer
, "GB")) {
1242 val
= strtoll(buffer
, &end
, 10);
1244 } else if (strstr(buffer
, "byte") || strstr(buffer
, "BYTE")) {
1245 val
= strtoll(buffer
, &end
, 10);
1248 // no suffix, try plain byte conversion
1249 val
= strtoll(buffer
, &end
, 10);
1258 LineBounds(BPoint where
, float length
, bool vertical
)
1261 rect
.SetLeftTop(where
);
1262 rect
.SetRightBottom(where
+ BPoint(2, 2));
1264 rect
.bottom
= rect
.top
+ length
;
1266 rect
.right
= rect
.left
+ length
;
1272 SeparatorLine::SeparatorLine(BPoint where
, float length
, bool vertical
,
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
));
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);
1292 AddLine(bounds
.LeftTop(), bounds
.LeftBottom(), hiliteColor
);
1293 AddLine(bounds
.LeftTop() + BPoint(1, 0),
1294 bounds
.LeftBottom() + BPoint(1, 0), kWhite
);
1296 AddLine(bounds
.LeftTop(), bounds
.RightTop(), hiliteColor
);
1297 AddLine(bounds
.LeftTop() + BPoint(0, 1),
1298 bounds
.RightTop() + BPoint(0, 1), kWhite
);
1305 HexDump(const void* buf
, int32 length
)
1307 const int32 kBytesPerLine
= 16;
1309 unsigned char* buffer
= (unsigned char*)buf
;
1311 for (offset
= 0; ; offset
+= kBytesPerLine
, buffer
+= kBytesPerLine
) {
1312 int32 remain
= length
;
1315 printf( "0x%06x: ", (int)offset
);
1317 for (index
= 0; index
< kBytesPerLine
; index
++) {
1319 printf("%02x%c", buffer
[index
], remain
> 0 ? ',' : ' ');
1326 for (index
= 0; index
< kBytesPerLine
; index
++) {
1328 printf("%c", buffer
[index
] > ' ' ? buffer
[index
] : '.');
1334 length
-= kBytesPerLine
;
1343 EnableNamedMenuItem(BMenu
* menu
, const char* itemName
, bool on
)
1345 BMenuItem
* item
= menu
->FindItem(itemName
);
1347 item
->SetEnabled(on
);
1352 MarkNamedMenuItem(BMenu
* menu
, const char* itemName
, bool on
)
1354 BMenuItem
* item
= menu
->FindItem(itemName
);
1356 item
->SetMarked(on
);
1361 EnableNamedMenuItem(BMenu
* menu
, uint32 commandName
, bool on
)
1363 BMenuItem
* item
= menu
->FindItem(commandName
);
1365 item
->SetEnabled(on
);
1370 MarkNamedMenuItem(BMenu
* menu
, uint32 commandName
, bool on
)
1372 BMenuItem
* item
= menu
->FindItem(commandName
);
1374 item
->SetMarked(on
);
1379 DeleteSubmenu(BMenuItem
* submenuItem
)
1381 if (submenuItem
== NULL
)
1384 BMenu
* menu
= submenuItem
->Submenu();
1389 BMenuItem
* item
= menu
->RemoveItem((int32
)0);
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
);
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
;
1417 #endif // B_APP_FILE_INFO_IS_FAST
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
);
1434 // const char* attrName = kAttrIcon;
1435 // uint32 type = B_VECTOR_ICON_TYPE;
1437 // // try vector icon
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,
1445 // if (readResult == ainfo.size) {
1446 // if (BIconUtils::GetVectorIcon(buffer, ainfo.size, icon) == B_OK)
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)
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);
1468 // icon->SetBits(buffer, icon->BitsLength(), 0, B_CMAP8);
1471 //#endif // B_APP_FILE_INFO_IS_FAST
1476 GetFileIconFromAttr(BNode
* node
, BBitmap
* icon
, icon_size which
)
1478 BNodeInfo
fileInfo(node
);
1479 return fileInfo
.GetIcon(icon
, which
);
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
);
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
)
1502 BMenu
* submenu
= menu
->SubmenuAt(index
);
1503 if (submenu
!= NULL
)
1504 return EachMenuItem(submenu
, true, func
);
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
)
1524 BMenu
* submenu
= menu
->SubmenuAt(index
);
1525 if (submenu
!= NULL
)
1526 return EachMenuItem(submenu
, true, func
);
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
)
1553 PositionPassingMenuItem::Invoke(BMessage
* message
)
1561 if (message
== NULL
)
1562 message
= Message();
1564 if (message
== NULL
)
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();
1577 if (!menu
->Supermenu())
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
1603 const char* safeMode
= getenv("SAFEMODE");
1604 return (safeMode
&& strcmp(safeMode
, "yes") == 0);
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
) {
1615 return kExactMatchScore
;
1617 return 1.f
/ (found
- text
);
1620 // there was no exact match
1622 // second best: all characters at word beginnings
1625 for (int32 j
= 0, k
= 0; match
[j
]; j
++) {
1627 && tolower(text
[k
]) != tolower(match
[j
])) {
1630 if (text
[k
] == '\0') {
1635 bool wordStart
= k
== 0 || isspace(text
[k
- 1]);
1639 bool wordEnd
= !text
[k
+ 1] || isspace(text
[k
+ 1]);
1642 if (match
[j
- 1] == text
[k
- 1])
1646 score
+= 1.f
/ (k
+ 1);
1657 // #pragma mark - throw on error functions.
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
));
1672 _ThrowIfNotSize(ssize_t size
, const char* DEBUG_ONLY(file
),
1673 int32
DEBUG_ONLY(line
))
1676 PRINT(("%s at %s:%d\n", strerror((status_t
)size
), file
, (int)line
));
1677 throw (status_t
)size
;
1683 _ThrowOnAssert(bool success
, const char* DEBUG_ONLY(file
),
1684 int32
DEBUG_ONLY(line
))
1687 PRINT(("Assert failed at %s:%d\n", file
, (int)line
));
1692 } // namespace BPrivate