1 /*
2 Open Tracker License
3
4 Terms and Conditions
5
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
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:
14
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.
17
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.
24
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.
28
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.
33 */
34
35
36 #include "Utilities.h"
37
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>
45
46 #include <BitmapStream.h>
47 #include <Catalog.h>
48 #include <ControlLook.h>
49 #include <Debug.h>
50 #include <Font.h>
51 #include <IconUtils.h>
52 #include <MenuItem.h>
53 #include <OS.h>
54 #include <PopUpMenu.h>
55 #include <Region.h>
56 #include <StorageDefs.h>
57 #include <TextView.h>
58 #include <Volume.h>
59 #include <VolumeRoster.h>
60 #include <Window.h>
61
62 #include "Attributes.h"
63 #include "ContainerWindow.h"
64 #include "MimeTypes.h"
65 #include "Model.h"
66 #include "PoseView.h"
67
68
69 #ifndef _IMPEXP_BE
70 # define _IMPEXP_BE
71 #endif
72 extern _IMPEXP_BE const uint32 LARGE_ICON_TYPE;
73 extern _IMPEXP_BE const uint32 MINI_ICON_TYPE;
74
75
76 FILE* logFile = NULL;
77
78 static const float kMinSeparatorStubX = 10;
79 static const float kStubToStringSlotX = 5;
80
81
82 namespace BPrivate {
83
84 const float kExactMatchScore = INFINITY;
85
86
87 bool gLocalizedNamePreferred;
88
89
90 float
ReadOnlyTint(rgb_color base)91 ReadOnlyTint(rgb_color base)
92 {
93 // darken tint if read-only (or lighten if dark)
94 return base.IsLight() ? B_DARKEN_1_TINT : 0.85;
95 }
96
97
98 rgb_color
InvertColor(rgb_color color)99 InvertColor(rgb_color color)
100 {
101 return make_color(255 - color.red, 255 - color.green, 255 - color.blue);
102 }
103
104
105 rgb_color
InvertedBackColor(rgb_color background)106 InvertedBackColor(rgb_color background)
107 {
108 rgb_color inverted = InvertColor(background);
109
110 // The colors are different enough, we can use inverted
111 if (rgb_color::Contrast(background, inverted) > 127)
112 return inverted;
113
114 // use black or white
115 return background.IsLight() ? kBlack : kWhite;
116 }
117
118
119 bool
SecondaryMouseButtonDown(int32 modifiers,int32 buttons)120 SecondaryMouseButtonDown(int32 modifiers, int32 buttons)
121 {
122 return (buttons & B_SECONDARY_MOUSE_BUTTON) != 0
123 || ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0
124 && (modifiers & B_CONTROL_KEY) != 0);
125 }
126
127
128 uint32
SeededHashString(const char * string,uint32 seed)129 SeededHashString(const char* string, uint32 seed)
130 {
131 char ch;
132 uint32 hash = seed;
133
134 while((ch = *string++) != 0) {
135 hash = (hash << 7) ^ (hash >> 24);
136 hash ^= ch;
137 }
138 hash ^= hash << 12;
139
140 return hash;
141 }
142
143
144 uint32
AttrHashString(const char * string,uint32 type)145 AttrHashString(const char* string, uint32 type)
146 {
147 char c;
148 uint32 hash = 0;
149
150 while((c = *string++) != 0) {
151 hash = (hash << 7) ^ (hash >> 24);
152 hash ^= c;
153 }
154 hash ^= hash << 12;
155
156 hash &= ~0xff;
157 hash |= type;
158
159 return hash;
160 }
161
162
163 bool
ValidateStream(BMallocIO * stream,uint32 key,int32 version)164 ValidateStream(BMallocIO* stream, uint32 key, int32 version)
165 {
166 uint32 testKey;
167 int32 testVersion;
168
169 if (stream->Read(&testKey, sizeof(uint32)) <= 0
170 || stream->Read(&testVersion, sizeof(int32)) <= 0) {
171 return false;
172 }
173
174 return testKey == key && testVersion == version;
175 }
176
177
178 void
DisallowFilenameKeys(BTextView * textView)179 DisallowFilenameKeys(BTextView* textView)
180 {
181 textView->DisallowChar('/');
182 }
183
184
185 void
DisallowMetaKeys(BTextView * textView)186 DisallowMetaKeys(BTextView* textView)
187 {
188 textView->DisallowChar(B_TAB);
189 textView->DisallowChar(B_ESCAPE);
190 textView->DisallowChar(B_INSERT);
191 textView->DisallowChar(B_DELETE);
192 textView->DisallowChar(B_HOME);
193 textView->DisallowChar(B_END);
194 textView->DisallowChar(B_PAGE_UP);
195 textView->DisallowChar(B_PAGE_DOWN);
196 textView->DisallowChar(B_FUNCTION_KEY);
197 }
198
199
PeriodicUpdatePoses()200 PeriodicUpdatePoses::PeriodicUpdatePoses()
201 :
202 fPoseList(20, true)
203 {
204 fLock = new Benaphore("PeriodicUpdatePoses");
205 }
206
207
~PeriodicUpdatePoses()208 PeriodicUpdatePoses::~PeriodicUpdatePoses()
209 {
210 fLock->Lock();
211 fPoseList.MakeEmpty();
212 delete fLock;
213 }
214
215
216 void
AddPose(BPose * pose,BPoseView * poseView,PeriodicUpdateCallback callback,void * cookie)217 PeriodicUpdatePoses::AddPose(BPose* pose, BPoseView* poseView,
218 PeriodicUpdateCallback callback, void* cookie)
219 {
220 periodic_pose* periodic = new periodic_pose;
221 periodic->pose = pose;
222 periodic->pose_view = poseView;
223 periodic->callback = callback;
224 periodic->cookie = cookie;
225 fPoseList.AddItem(periodic);
226 }
227
228
229 bool
RemovePose(BPose * pose,void ** cookie)230 PeriodicUpdatePoses::RemovePose(BPose* pose, void** cookie)
231 {
232 int32 count = fPoseList.CountItems();
233 for (int32 index = 0; index < count; index++) {
234 if (fPoseList.ItemAt(index)->pose == pose) {
235 if (!fLock->Lock())
236 return false;
237
238 periodic_pose* periodic = fPoseList.RemoveItemAt(index);
239 if (cookie)
240 *cookie = periodic->cookie;
241 delete periodic;
242 fLock->Unlock();
243 return true;
244 }
245 }
246
247 return false;
248 }
249
250
251 void
DoPeriodicUpdate(bool forceRedraw)252 PeriodicUpdatePoses::DoPeriodicUpdate(bool forceRedraw)
253 {
254 if (!fLock->Lock())
255 return;
256
257 int32 count = fPoseList.CountItems();
258 for (int32 index = 0; index < count; index++) {
259 periodic_pose* periodic = fPoseList.ItemAt(index);
260 if ((periodic->callback(periodic->pose, periodic->cookie)
261 || forceRedraw) && periodic->pose_view->LockLooper()) {
262 periodic->pose_view->UpdateIcon(periodic->pose);
263 periodic->pose_view->UnlockLooper();
264 }
265 }
266
267 fLock->Unlock();
268 }
269
270
271 PeriodicUpdatePoses gPeriodicUpdatePoses;
272
273 } // namespace BPrivate
274
275
276 void
EndianSwap(void * castToThis)277 PoseInfo::EndianSwap(void* castToThis)
278 {
279 PoseInfo* self = (PoseInfo*)castToThis;
280
281 PRINT(("swapping PoseInfo\n"));
282
283 STATIC_ASSERT(sizeof(ino_t) == sizeof(int64));
284 self->fInitedDirectory = SwapInt64(self->fInitedDirectory);
285 swap_data(B_POINT_TYPE, &self->fLocation, sizeof(BPoint), B_SWAP_ALWAYS);
286
287 // do a sanity check on the icon position
288 if (self->fLocation.x < -20000 || self->fLocation.x > 20000
289 || self->fLocation.y < -20000 || self->fLocation.y > 20000) {
290 // position out of range, force autoplcemement
291 PRINT((" rejecting icon position out of range\n"));
292 self->fInitedDirectory = -1LL;
293 self->fLocation = BPoint(0, 0);
294 }
295 }
296
297
298 void
PrintToStream()299 PoseInfo::PrintToStream()
300 {
301 PRINT(("%s, inode:%" B_PRIx64 ", location %f %f\n",
302 fInvisible ? "hidden" : "visible",
303 fInitedDirectory, fLocation.x, fLocation.y));
304 }
305
306
307 // #pragma mark - ExtendedPoseInfo
308
309
310 size_t
Size() const311 ExtendedPoseInfo::Size() const
312 {
313 return sizeof(ExtendedPoseInfo) + fNumFrames * sizeof(FrameLocation);
314 }
315
316
317 size_t
Size(int32 count)318 ExtendedPoseInfo::Size(int32 count)
319 {
320 return sizeof(ExtendedPoseInfo) + count * sizeof(FrameLocation);
321 }
322
323
324 size_t
SizeWithHeadroom() const325 ExtendedPoseInfo::SizeWithHeadroom() const
326 {
327 return sizeof(ExtendedPoseInfo) + (fNumFrames + 1) * sizeof(FrameLocation);
328 }
329
330
331 size_t
SizeWithHeadroom(size_t oldSize)332 ExtendedPoseInfo::SizeWithHeadroom(size_t oldSize)
333 {
334 int32 count = (ssize_t)oldSize - (ssize_t)sizeof(ExtendedPoseInfo);
335 if (count > 0)
336 count /= sizeof(FrameLocation);
337 else
338 count = 0;
339
340 return Size(count + 1);
341 }
342
343
344 bool
HasLocationForFrame(BRect frame) const345 ExtendedPoseInfo::HasLocationForFrame(BRect frame) const
346 {
347 for (int32 index = 0; index < fNumFrames; index++) {
348 if (fLocations[index].fFrame == frame)
349 return true;
350 }
351
352 return false;
353 }
354
355
356 BPoint
LocationForFrame(BRect frame) const357 ExtendedPoseInfo::LocationForFrame(BRect frame) const
358 {
359 for (int32 index = 0; index < fNumFrames; index++) {
360 if (fLocations[index].fFrame == frame)
361 return fLocations[index].fLocation;
362 }
363
364 TRESPASS();
365 return BPoint(0, 0);
366 }
367
368
369 bool
SetLocationForFrame(BPoint newLocation,BRect frame)370 ExtendedPoseInfo::SetLocationForFrame(BPoint newLocation, BRect frame)
371 {
372 for (int32 index = 0; index < fNumFrames; index++) {
373 if (fLocations[index].fFrame == frame) {
374 if (fLocations[index].fLocation == newLocation)
375 return false;
376
377 fLocations[index].fLocation = newLocation;
378 return true;
379 }
380 }
381
382 fLocations[fNumFrames].fFrame = frame;
383 fLocations[fNumFrames].fLocation = newLocation;
384 fLocations[fNumFrames].fWorkspaces = 0xffffffff;
385 fNumFrames++;
386
387 return true;
388 }
389
390
391 void
EndianSwap(void * castToThis)392 ExtendedPoseInfo::EndianSwap(void* castToThis)
393 {
394 ExtendedPoseInfo* self = (ExtendedPoseInfo *)castToThis;
395
396 PRINT(("swapping ExtendedPoseInfo\n"));
397
398 self->fWorkspaces = SwapUInt32(self->fWorkspaces);
399 self->fNumFrames = SwapInt32(self->fNumFrames);
400
401 for (int32 index = 0; index < self->fNumFrames; index++) {
402 swap_data(B_POINT_TYPE, &self->fLocations[index].fLocation,
403 sizeof(BPoint), B_SWAP_ALWAYS);
404
405 if (self->fLocations[index].fLocation.x < -20000
406 || self->fLocations[index].fLocation.x > 20000
407 || self->fLocations[index].fLocation.y < -20000
408 || self->fLocations[index].fLocation.y > 20000) {
409 // position out of range, force autoplcemement
410 PRINT((" rejecting icon position out of range\n"));
411 self->fLocations[index].fLocation = BPoint(0, 0);
412 }
413 swap_data(B_RECT_TYPE, &self->fLocations[index].fFrame,
414 sizeof(BRect), B_SWAP_ALWAYS);
415 }
416 }
417
418
419 void
PrintToStream()420 ExtendedPoseInfo::PrintToStream()
421 {
422 }
423
424
425 // #pragma mark - OffscreenBitmap
426
427
OffscreenBitmap(BRect frame)428 OffscreenBitmap::OffscreenBitmap(BRect frame)
429 :
430 fBitmap(NULL)
431 {
432 NewBitmap(frame);
433 }
434
435
OffscreenBitmap()436 OffscreenBitmap::OffscreenBitmap()
437 :
438 fBitmap(NULL)
439 {
440 }
441
442
~OffscreenBitmap()443 OffscreenBitmap::~OffscreenBitmap()
444 {
445 delete fBitmap;
446 }
447
448
449 void
NewBitmap(BRect bounds)450 OffscreenBitmap::NewBitmap(BRect bounds)
451 {
452 delete fBitmap;
453 fBitmap = new(std::nothrow) BBitmap(bounds, B_RGB32, true);
454 if (fBitmap != NULL && fBitmap->Lock()) {
455 BView* view = new BView(fBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
456 fBitmap->AddChild(view);
457
458 BRect clipRect = view->Bounds();
459 BRegion newClip;
460 newClip.Set(clipRect);
461 view->ConstrainClippingRegion(&newClip);
462
463 fBitmap->Unlock();
464 } else {
465 delete fBitmap;
466 fBitmap = NULL;
467 }
468 }
469
470
471 BView*
BeginUsing(BRect frame)472 OffscreenBitmap::BeginUsing(BRect frame)
473 {
474 if (!fBitmap || fBitmap->Bounds() != frame)
475 NewBitmap(frame);
476
477 fBitmap->Lock();
478 return View();
479 }
480
481
482 void
DoneUsing()483 OffscreenBitmap::DoneUsing()
484 {
485 fBitmap->Unlock();
486 }
487
488
489 BBitmap*
Bitmap() const490 OffscreenBitmap::Bitmap() const
491 {
492 ASSERT(fBitmap);
493 ASSERT(fBitmap->IsLocked());
494 return fBitmap;
495 }
496
497
498 BView*
View() const499 OffscreenBitmap::View() const
500 {
501 ASSERT(fBitmap);
502 return fBitmap->ChildAt(0);
503 }
504
505
506 // #pragma mark - BPrivate functions
507
508
509 namespace BPrivate {
510
511 // Changes the alpha value of the given bitmap to create a nice
512 // horizontal fade out in the specified region.
513 // "from" is always transparent, "to" opaque.
514 void
FadeRGBA32Horizontal(uint32 * bits,int32 width,int32 height,int32 from,int32 to)515 FadeRGBA32Horizontal(uint32* bits, int32 width, int32 height, int32 from,
516 int32 to)
517 {
518 // check parameters
519 if (width < 0 || height < 0 || from < 0 || to < 0)
520 return;
521
522 float change = 1.f / (to - from);
523 if (from > to) {
524 int32 temp = from;
525 from = to;
526 to = temp;
527 }
528
529 for (int32 y = 0; y < height; y++) {
530 float alpha = change > 0 ? 0.0f : 1.0f;
531
532 for (int32 x = from; x <= to; x++) {
533 if (bits[x] & 0xff000000) {
534 uint32 a = uint32((bits[x] >> 24) * alpha);
535 bits[x] = (bits[x] & 0x00ffffff) | (a << 24);
536 }
537 alpha += change;
538 }
539 bits += width;
540 }
541 }
542
543
544 /*! Changes the alpha value of the given bitmap to create a nice
545 vertical fade out in the specified region.
546 "from" is always transparent, "to" opaque.
547 */
548 void
FadeRGBA32Vertical(uint32 * bits,int32 width,int32 height,int32 from,int32 to)549 FadeRGBA32Vertical(uint32* bits, int32 width, int32 height, int32 from,
550 int32 to)
551 {
552 // check parameters
553 if (width < 0 || height < 0 || from < 0 || to < 0)
554 return;
555
556 if (from > to)
557 bits += width * (height - (from - to));
558
559 float change = 1.f / (to - from);
560 if (from > to) {
561 int32 temp = from;
562 from = to;
563 to = temp;
564 }
565
566 float alpha = change > 0 ? 0.0f : 1.0f;
567
568 for (int32 y = from; y <= to; y++) {
569 for (int32 x = 0; x < width; x++) {
570 if (bits[x] & 0xff000000) {
571 uint32 a = uint32((bits[x] >> 24) * alpha);
572 bits[x] = (bits[x] & 0x00ffffff) | (a << 24);
573 }
574 }
575 alpha += change;
576 bits += width;
577 }
578 }
579
580 } // namespace BPrivate
581
582
583 // #pragma mark - DraggableIcon
584
585
DraggableIcon(BRect rect,const char * name,const char * type,icon_size which,const BMessage * message,BMessenger target,uint32 resizingMode,uint32 flags)586 DraggableIcon::DraggableIcon(BRect rect, const char* name,
587 const char* type, icon_size which, const BMessage* message,
588 BMessenger target, uint32 resizingMode, uint32 flags)
589 :
590 BView(rect, name, resizingMode, flags),
591 fMessage(*message),
592 fTarget(target)
593 {
594 fBitmap = new BBitmap(Bounds(), kDefaultIconDepth);
595 BMimeType mime(type);
596 status_t result = mime.GetIcon(fBitmap, which);
597 ASSERT(mime.IsValid());
598 if (result != B_OK) {
599 PRINT(("failed to get icon for %s, %s\n", type, strerror(result)));
600 BMimeType mime(B_FILE_MIMETYPE);
601 ASSERT(mime.IsInstalled());
602 mime.GetIcon(fBitmap, which);
603 }
604 }
605
606
~DraggableIcon()607 DraggableIcon::~DraggableIcon()
608 {
609 delete fBitmap;
610 }
611
612
613 void
SetTarget(BMessenger target)614 DraggableIcon::SetTarget(BMessenger target)
615 {
616 fTarget = target;
617 }
618
619
620 BRect
PreferredRect(BPoint offset,icon_size which)621 DraggableIcon::PreferredRect(BPoint offset, icon_size which)
622 {
623 BRect rect(0, 0, which - 1, which - 1);
624 rect.OffsetTo(offset);
625 return rect;
626 }
627
628
629 void
AttachedToWindow()630 DraggableIcon::AttachedToWindow()
631 {
632 AdoptParentColors();
633 }
634
635
636 void
MouseDown(BPoint point)637 DraggableIcon::MouseDown(BPoint point)
638 {
639 if (!DragStarted(&fMessage))
640 return;
641
642 BRect rect(Bounds());
643 BBitmap* dragBitmap = new BBitmap(rect, B_RGBA32, true);
644 dragBitmap->Lock();
645 BView* view = new BView(dragBitmap->Bounds(), "", B_FOLLOW_NONE, 0);
646 dragBitmap->AddChild(view);
647 view->SetOrigin(0, 0);
648 BRect clipRect(view->Bounds());
649 BRegion newClip;
650 newClip.Set(clipRect);
651 view->ConstrainClippingRegion(&newClip);
652
653 // Transparent draw magic
654 view->SetHighColor(0, 0, 0, 0);
655 view->FillRect(view->Bounds());
656 view->SetDrawingMode(B_OP_ALPHA);
657 view->SetHighColor(0, 0, 0, 128);
658 // set the level of transparency by value
659 view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
660 view->DrawBitmap(fBitmap);
661 view->Sync();
662 dragBitmap->Unlock();
663 DragMessage(&fMessage, dragBitmap, B_OP_ALPHA, point, fTarget.Target(0));
664 }
665
666
667 bool
DragStarted(BMessage *)668 DraggableIcon::DragStarted(BMessage*)
669 {
670 return true;
671 }
672
673
674 void
Draw(BRect)675 DraggableIcon::Draw(BRect)
676 {
677 SetDrawingMode(B_OP_ALPHA);
678 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
679 DrawBitmap(fBitmap);
680 }
681
682
683 // #pragma mark - FlickerFreeStringView
684
685
FlickerFreeStringView(BRect bounds,const char * name,const char * text,uint32 resizingMode,uint32 flags)686 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name,
687 const char* text, uint32 resizingMode, uint32 flags)
688 :
689 BStringView(bounds, name, text, resizingMode, flags),
690 fBitmap(NULL),
691 fViewColor(ViewColor()),
692 fLowColor(LowColor()),
693 fOriginalBitmap(NULL)
694 {
695 }
696
697
FlickerFreeStringView(BRect bounds,const char * name,const char * text,BBitmap * inBitmap,uint32 resizingMode,uint32 flags)698 FlickerFreeStringView::FlickerFreeStringView(BRect bounds, const char* name,
699 const char* text, BBitmap* inBitmap, uint32 resizingMode, uint32 flags)
700 :
701 BStringView(bounds, name, text, resizingMode, flags),
702 fBitmap(NULL),
703 fViewColor(ViewColor()),
704 fLowColor(LowColor()),
705 fOriginalBitmap(inBitmap)
706 {
707 }
708
709
~FlickerFreeStringView()710 FlickerFreeStringView::~FlickerFreeStringView()
711 {
712 delete fBitmap;
713 }
714
715
716 void
Draw(BRect)717 FlickerFreeStringView::Draw(BRect)
718 {
719 BRect bounds(Bounds());
720 if (fBitmap == NULL)
721 fBitmap = new OffscreenBitmap(Bounds());
722
723 BView* offscreen = fBitmap->BeginUsing(bounds);
724
725 if (Parent() != NULL) {
726 fViewColor = Parent()->ViewColor();
727 fLowColor = Parent()->ViewColor();
728 }
729
730 offscreen->SetViewColor(fViewColor);
731 offscreen->SetHighColor(HighColor());
732 offscreen->SetLowColor(fLowColor);
733
734 BFont font;
735 GetFont(&font);
736 offscreen->SetFont(&font);
737
738 offscreen->Sync();
739 if (fOriginalBitmap != NULL)
740 offscreen->DrawBitmap(fOriginalBitmap, Frame(), bounds);
741 else
742 offscreen->FillRect(bounds, B_SOLID_LOW);
743
744 if (Text() != NULL) {
745 BPoint loc;
746
747 font_height height;
748 GetFontHeight(&height);
749
750 edge_info eInfo;
751 switch (Alignment()) {
752 case B_ALIGN_LEFT:
753 case B_ALIGN_HORIZONTAL_UNSET:
754 case B_ALIGN_USE_FULL_WIDTH:
755 {
756 // If the first char has a negative left edge give it
757 // some more room by shifting that much more to the right.
758 font.GetEdges(Text(), 1, &eInfo);
759 loc.x = bounds.left + (2 - eInfo.left);
760 break;
761 }
762
763 case B_ALIGN_CENTER:
764 {
765 float width = StringWidth(Text());
766 float center = (bounds.right - bounds.left) / 2;
767 loc.x = center - (width/2);
768 break;
769 }
770
771 case B_ALIGN_RIGHT:
772 {
773 float width = StringWidth(Text());
774 loc.x = bounds.right - width - 2;
775 break;
776 }
777 }
778 loc.y = bounds.bottom - (1 + height.descent);
779 offscreen->DrawString(Text(), loc);
780 }
781 offscreen->Sync();
782 SetDrawingMode(B_OP_COPY);
783 DrawBitmap(fBitmap->Bitmap());
784 fBitmap->DoneUsing();
785 }
786
787
788 void
AttachedToWindow()789 FlickerFreeStringView::AttachedToWindow()
790 {
791 _inherited::AttachedToWindow();
792 if (Parent() != NULL) {
793 fViewColor = Parent()->ViewColor();
794 fLowColor = Parent()->ViewColor();
795 }
796 SetViewColor(B_TRANSPARENT_32_BIT);
797 SetLowColor(B_TRANSPARENT_32_BIT);
798 }
799
800
801 void
SetViewColor(rgb_color color)802 FlickerFreeStringView::SetViewColor(rgb_color color)
803 {
804 if (fViewColor != color) {
805 fViewColor = color;
806 Invalidate();
807 }
808 _inherited::SetViewColor(B_TRANSPARENT_32_BIT);
809 }
810
811
812 void
SetLowColor(rgb_color color)813 FlickerFreeStringView::SetLowColor(rgb_color color)
814 {
815 if (fLowColor != color) {
816 fLowColor = color;
817 Invalidate();
818 }
819 _inherited::SetLowColor(B_TRANSPARENT_32_BIT);
820 }
821
822
823 // #pragma mark - TitledSeparatorItem
824
825
TitledSeparatorItem(const char * label)826 TitledSeparatorItem::TitledSeparatorItem(const char* label)
827 :
828 BMenuItem(label, 0)
829 {
830 _inherited::SetEnabled(false);
831 }
832
833
~TitledSeparatorItem()834 TitledSeparatorItem::~TitledSeparatorItem()
835 {
836 }
837
838
839 void
SetEnabled(bool)840 TitledSeparatorItem::SetEnabled(bool)
841 {
842 // leave disabled
843 }
844
845
846 void
GetContentSize(float * width,float * height)847 TitledSeparatorItem::GetContentSize(float* width, float* height)
848 {
849 _inherited::GetContentSize(width, height);
850
851 // Adjust for the extra space needed by the separator bars at the left and right
852 if (width)
853 *width += (kMinSeparatorStubX + kStubToStringSlotX) * 2;
854 }
855
856
857 inline rgb_color
ShiftMenuBackgroundColor(float by)858 ShiftMenuBackgroundColor(float by)
859 {
860 return tint_color(ui_color(B_MENU_BACKGROUND_COLOR), by);
861 }
862
863
864 void
Draw()865 TitledSeparatorItem::Draw()
866 {
867 BRect frame(Frame());
868
869 BMenu* parent = Menu();
870 ASSERT(parent != NULL);
871
872 menu_info minfo;
873 get_menu_info(&minfo);
874
875 if (minfo.separator > 0) {
876 frame.left += 10;
877 frame.right -= 10;
878 } else {
879 frame.left += 1;
880 frame.right -= 1;
881 }
882
883 float startX = frame.left;
884 float endX = frame.right;
885
886 float maxStringWidth = endX - startX - (2 * kMinSeparatorStubX
887 + 2 * kStubToStringSlotX);
888
889 // ToDo:
890 // handle case where maxStringWidth turns out negative here
891
892 BString truncatedLabel(Label());
893 parent->TruncateString(&truncatedLabel, B_TRUNCATE_END, maxStringWidth);
894
895 maxStringWidth = parent->StringWidth(truncatedLabel.String());
896
897 // first calculate the length of the stub part of the
898 // divider line, so we can use it for secondStartX
899 float firstEndX = ((endX - startX) - maxStringWidth) / 2
900 - kStubToStringSlotX;
901 if (firstEndX < 0)
902 firstEndX = 0;
903
904 float secondStartX = endX - firstEndX;
905
906 // now finish calculating firstEndX
907 firstEndX += startX;
908
909 parent->PushState();
910
911 int32 y = (int32) (frame.top + (frame.bottom - frame.top) / 2);
912
913 parent->BeginLineArray(minfo.separator == 2 ? 6 : 4);
914 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y),
915 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
916 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y),
917 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
918
919 if (minfo.separator == 2) {
920 y++;
921 frame.left++;
922 frame.right--;
923 parent->AddLine(BPoint(frame.left,y), BPoint(firstEndX, y),
924 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
925 parent->AddLine(BPoint(secondStartX,y), BPoint(frame.right, y),
926 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
927 }
928 y++;
929 if (minfo.separator == 2) {
930 frame.left++;
931 frame.right--;
932 }
933 parent->AddLine(BPoint(frame.left, y), BPoint(firstEndX, y),
934 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
935 parent->AddLine(BPoint(secondStartX, y), BPoint(frame.right, y),
936 ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
937
938 parent->EndLineArray();
939
940 font_height finfo;
941 parent->GetFontHeight(&finfo);
942
943 parent->SetLowColor(parent->ViewColor());
944 BPoint loc(firstEndX + kStubToStringSlotX,
945 ContentLocation().y + finfo.ascent);
946
947 parent->MovePenTo(loc + BPoint(1, 1));
948 parent->SetHighColor(ShiftMenuBackgroundColor(B_DARKEN_1_TINT));
949 parent->DrawString(truncatedLabel.String());
950
951 parent->MovePenTo(loc);
952 parent->SetHighColor(ShiftMenuBackgroundColor(B_DISABLED_LABEL_TINT));
953 parent->DrawString(truncatedLabel.String());
954
955 parent->PopState();
956 }
957
958
959 // #pragma mark - ShortcutFilter
960
961
ShortcutFilter(uint32 shortcutKey,uint32 shortcutModifier,uint32 shortcutWhat,BHandler * target)962 ShortcutFilter::ShortcutFilter(uint32 shortcutKey, uint32 shortcutModifier,
963 uint32 shortcutWhat, BHandler* target)
964 :
965 BMessageFilter(B_KEY_DOWN),
966 fShortcutKey(shortcutKey),
967 fShortcutModifier(shortcutModifier),
968 fShortcutWhat(shortcutWhat),
969 fTarget(target)
970 {
971 }
972
973
974 filter_result
Filter(BMessage * message,BHandler **)975 ShortcutFilter::Filter(BMessage* message, BHandler**)
976 {
977 if (message->what == B_KEY_DOWN) {
978 uint32 modifiers;
979 uint32 rawKeyChar = 0;
980 uint8 byte = 0;
981 int32 key = 0;
982
983 if (message->FindInt32("modifiers", (int32*)&modifiers) != B_OK
984 || message->FindInt32("raw_char", (int32*)&rawKeyChar) != B_OK
985 || message->FindInt8("byte", (int8*)&byte) != B_OK
986 || message->FindInt32("key", &key) != B_OK) {
987 return B_DISPATCH_MESSAGE;
988 }
989
990 modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY
991 | B_OPTION_KEY | B_MENU_KEY;
992 // strip caps lock, etc.
993
994 if (modifiers == fShortcutModifier && rawKeyChar == fShortcutKey) {
995 fTarget->Looper()->PostMessage(fShortcutWhat, fTarget);
996 return B_SKIP_MESSAGE;
997 }
998 }
999
1000 // let others deal with this
1001 return B_DISPATCH_MESSAGE;
1002 }
1003
1004
1005 // #pragma mark - BPrivate functions
1006
1007
1008 namespace BPrivate {
1009
1010 void
EmbedUniqueVolumeInfo(BMessage * message,const BVolume * volume)1011 EmbedUniqueVolumeInfo(BMessage* message, const BVolume* volume)
1012 {
1013 BDirectory rootDirectory;
1014 time_t created;
1015 fs_info info;
1016
1017 if (volume->GetRootDirectory(&rootDirectory) == B_OK
1018 && rootDirectory.GetCreationTime(&created) == B_OK
1019 && fs_stat_dev(volume->Device(), &info) == 0) {
1020 message->AddInt64("creationDate", created);
1021 message->AddInt64("capacity", volume->Capacity());
1022 message->AddString("deviceName", info.device_name);
1023 message->AddString("volumeName", info.volume_name);
1024 message->AddString("fshName", info.fsh_name);
1025 }
1026 }
1027
1028
1029 status_t
MatchArchivedVolume(BVolume * volume,const BMessage * message,int32 index)1030 MatchArchivedVolume(BVolume* volume, const BMessage* message, int32 index)
1031 {
1032 int64 created64;
1033 off_t capacity;
1034
1035 if (message->FindInt64("creationDate", index, &created64) != B_OK) {
1036 int32 created32;
1037 if (message->FindInt32("creationDate", index, &created32) != B_OK)
1038 return B_ERROR;
1039 created64 = created32;
1040 }
1041
1042 time_t created = created64;
1043
1044 if (message->FindInt64("capacity", index, &capacity) != B_OK)
1045 return B_ERROR;
1046
1047 BVolumeRoster roster;
1048 BVolume tempVolume;
1049 BString deviceName;
1050 BString volumeName;
1051 BString fshName;
1052
1053 if (message->FindString("deviceName", &deviceName) == B_OK
1054 && message->FindString("volumeName", &volumeName) == B_OK
1055 && message->FindString("fshName", &fshName) == B_OK) {
1056 // New style volume identifiers: We have a couple of characteristics,
1057 // and compute a score from them. The volume with the greatest score
1058 // (if over a certain threshold) is the one we're looking for. We
1059 // pick the first volume, in case there is more than one with the
1060 // same score.
1061 dev_t foundDevice = -1;
1062 int foundScore = -1;
1063 roster.Rewind();
1064 while (roster.GetNextVolume(&tempVolume) == B_OK) {
1065 if (tempVolume.IsPersistent() && tempVolume.KnowsQuery()) {
1066 // get creation time and fs_info
1067 BDirectory root;
1068 tempVolume.GetRootDirectory(&root);
1069 time_t cmpCreated;
1070 fs_info info;
1071 if (root.GetCreationTime(&cmpCreated) == B_OK
1072 && fs_stat_dev(tempVolume.Device(), &info) == 0) {
1073 // compute the score
1074 int score = 0;
1075
1076 // creation time
1077 if (created == cmpCreated)
1078 score += 5;
1079
1080 // capacity
1081 if (capacity == tempVolume.Capacity())
1082 score += 4;
1083
1084 // device name
1085 if (deviceName == info.device_name)
1086 score += 3;
1087
1088 // volume name
1089 if (volumeName == info.volume_name)
1090 score += 2;
1091
1092 // fsh name
1093 if (fshName == info.fsh_name)
1094 score += 1;
1095
1096 // check score
1097 if (score >= 9 && score > foundScore) {
1098 foundDevice = tempVolume.Device();
1099 foundScore = score;
1100 }
1101 }
1102 }
1103 }
1104 if (foundDevice >= 0)
1105 return volume->SetTo(foundDevice);
1106 } else {
1107 // Old style volume identifiers: We have only creation time and
1108 // capacity. Both must match.
1109 roster.Rewind();
1110 while (roster.GetNextVolume(&tempVolume) == B_OK) {
1111 if (tempVolume.IsPersistent() && tempVolume.KnowsQuery()) {
1112 BDirectory root;
1113 tempVolume.GetRootDirectory(&root);
1114 time_t cmpCreated;
1115 root.GetCreationTime(&cmpCreated);
1116 if (created == cmpCreated && capacity == tempVolume.Capacity()) {
1117 *volume = tempVolume;
1118 return B_OK;
1119 }
1120 }
1121 }
1122 }
1123
1124 return B_DEV_BAD_DRIVE_NUM;
1125 }
1126
1127
1128 void
StringFromStream(BString * string,BMallocIO * stream,bool endianSwap)1129 StringFromStream(BString* string, BMallocIO* stream, bool endianSwap)
1130 {
1131 int32 length;
1132 stream->Read(&length, sizeof(length));
1133 if (endianSwap)
1134 length = SwapInt32(length);
1135
1136 if (length < 0 || length > 10000) {
1137 // TODO: should fail here
1138 PRINT(("problems instatiating a string, length probably wrong %"
1139 B_PRId32 "\n", length));
1140 return;
1141 }
1142
1143 char* buffer = string->LockBuffer(length + 1);
1144 stream->Read(buffer, (size_t)length + 1);
1145 string->UnlockBuffer(length);
1146 }
1147
1148
1149 void
StringToStream(const BString * string,BMallocIO * stream)1150 StringToStream(const BString* string, BMallocIO* stream)
1151 {
1152 int32 length = string->Length();
1153 stream->Write(&length, sizeof(int32));
1154 stream->Write(string->String(), (size_t)string->Length() + 1);
1155 }
1156
1157
1158 int32
ArchiveSize(const BString * string)1159 ArchiveSize(const BString* string)
1160 {
1161 return string->Length() + 1 + (ssize_t)sizeof(int32);
1162 }
1163
1164
1165 int32
CountRefs(const BMessage * message)1166 CountRefs(const BMessage* message)
1167 {
1168 uint32 type;
1169 int32 count;
1170 message->GetInfo("refs", &type, &count);
1171
1172 return count;
1173 }
1174
1175
1176 static entry_ref*
EachEntryRefCommon(BMessage * message,entry_ref * (* func)(entry_ref *,void *),void * passThru,int32 maxCount)1177 EachEntryRefCommon(BMessage* message, entry_ref *(*func)(entry_ref*, void*),
1178 void* passThru, int32 maxCount)
1179 {
1180 uint32 type;
1181 int32 count;
1182 message->GetInfo("refs", &type, &count);
1183
1184 if (maxCount >= 0 && count > maxCount)
1185 count = maxCount;
1186
1187 for (int32 index = 0; index < count; index++) {
1188 entry_ref ref;
1189 message->FindRef("refs", index, &ref);
1190 entry_ref* newRef = (func)(&ref, passThru);
1191 if (newRef != NULL)
1192 return newRef;
1193 }
1194
1195 return NULL;
1196 }
1197
1198
1199 bool
ContainsEntryRef(const BMessage * message,const entry_ref * ref)1200 ContainsEntryRef(const BMessage* message, const entry_ref* ref)
1201 {
1202 entry_ref match;
1203 for (int32 index = 0; (message->FindRef("refs", index, &match) == B_OK);
1204 index++) {
1205 if (*ref == match)
1206 return true;
1207 }
1208
1209 return false;
1210 }
1211
1212
1213 entry_ref*
EachEntryRef(BMessage * message,entry_ref * (* func)(entry_ref *,void *),void * passThru)1214 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*),
1215 void* passThru)
1216 {
1217 return EachEntryRefCommon(message, func, passThru, -1);
1218 }
1219
1220 typedef entry_ref *(*EachEntryIteratee)(entry_ref *, void *);
1221
1222
1223 const entry_ref*
EachEntryRef(const BMessage * message,const entry_ref * (* func)(const entry_ref *,void *),void * passThru)1224 EachEntryRef(const BMessage* message,
1225 const entry_ref* (*func)(const entry_ref*, void*), void* passThru)
1226 {
1227 return EachEntryRefCommon(const_cast<BMessage*>(message),
1228 (EachEntryIteratee)func, passThru, -1);
1229 }
1230
1231
1232 entry_ref*
EachEntryRef(BMessage * message,entry_ref * (* func)(entry_ref *,void *),void * passThru,int32 maxCount)1233 EachEntryRef(BMessage* message, entry_ref* (*func)(entry_ref*, void*),
1234 void* passThru, int32 maxCount)
1235 {
1236 return EachEntryRefCommon(message, func, passThru, maxCount);
1237 }
1238
1239
1240 const entry_ref *
EachEntryRef(const BMessage * message,const entry_ref * (* func)(const entry_ref *,void *),void * passThru,int32 maxCount)1241 EachEntryRef(const BMessage* message,
1242 const entry_ref *(*func)(const entry_ref *, void *), void* passThru,
1243 int32 maxCount)
1244 {
1245 return EachEntryRefCommon(const_cast<BMessage *>(message),
1246 (EachEntryIteratee)func, passThru, maxCount);
1247 }
1248
1249
1250 void
TruncateLeaf(BString * string)1251 TruncateLeaf(BString* string)
1252 {
1253 for (int32 index = string->Length(); index >= 0; index--) {
1254 if ((*string)[index] == '/') {
1255 string->Truncate(index + 1);
1256 return;
1257 }
1258 }
1259 }
1260
1261
1262 int64
StringToScalar(const char * text)1263 StringToScalar(const char* text)
1264 {
1265 char* end;
1266 int64 val;
1267
1268 char* buffer = new char [strlen(text) + 1];
1269 strcpy(buffer, text);
1270
1271 if (strstr(buffer, "k") || strstr(buffer, "K")) {
1272 val = strtoll(buffer, &end, 10);
1273 val *= kKBSize;
1274 } else if (strstr(buffer, "mb") || strstr(buffer, "MB")) {
1275 val = strtoll(buffer, &end, 10);
1276 val *= kMBSize;
1277 } else if (strstr(buffer, "gb") || strstr(buffer, "GB")) {
1278 val = strtoll(buffer, &end, 10);
1279 val *= kGBSize;
1280 } else if (strstr(buffer, "byte") || strstr(buffer, "BYTE")) {
1281 val = strtoll(buffer, &end, 10);
1282 val *= kGBSize;
1283 } else {
1284 // no suffix, try plain byte conversion
1285 val = strtoll(buffer, &end, 10);
1286 }
1287 delete[] buffer;
1288
1289 return val;
1290 }
1291
1292
1293 int32
ListIconSize()1294 ListIconSize()
1295 {
1296 static int32 sIconSize = be_control_look->ComposeIconSize(B_MINI_ICON)
1297 .IntegerWidth() + 1;
1298 return sIconSize;
1299 }
1300
1301
1302 static BRect
LineBounds(BPoint where,float length,bool vertical)1303 LineBounds(BPoint where, float length, bool vertical)
1304 {
1305 BRect rect;
1306 rect.SetLeftTop(where);
1307 rect.SetRightBottom(where + BPoint(2, 2));
1308 if (vertical)
1309 rect.bottom = rect.top + length;
1310 else
1311 rect.right = rect.left + length;
1312
1313 return rect;
1314 }
1315
1316
SeparatorLine(BPoint where,float length,bool vertical,const char * name)1317 SeparatorLine::SeparatorLine(BPoint where, float length, bool vertical,
1318 const char* name)
1319 :
1320 BView(LineBounds(where, length, vertical), name,
1321 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW)
1322 {
1323 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
1324 SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
1325 }
1326
1327
1328 void
Draw(BRect)1329 SeparatorLine::Draw(BRect)
1330 {
1331 BRect bounds(Bounds());
1332 rgb_color hiliteColor = tint_color(ViewColor(), 1.5f);
1333
1334 bool vertical = (bounds.left > bounds.right - 3);
1335 BeginLineArray(2);
1336 if (vertical) {
1337 AddLine(bounds.LeftTop(), bounds.LeftBottom(), hiliteColor);
1338 AddLine(bounds.LeftTop() + BPoint(1, 0),
1339 bounds.LeftBottom() + BPoint(1, 0), kWhite);
1340 } else {
1341 AddLine(bounds.LeftTop(), bounds.RightTop(), hiliteColor);
1342 AddLine(bounds.LeftTop() + BPoint(0, 1),
1343 bounds.RightTop() + BPoint(0, 1), kWhite);
1344 }
1345 EndLineArray();
1346 }
1347
1348
1349 void
HexDump(const void * buf,int32 length)1350 HexDump(const void* buf, int32 length)
1351 {
1352 const int32 kBytesPerLine = 16;
1353 int32 offset;
1354 unsigned char* buffer = (unsigned char*)buf;
1355
1356 for (offset = 0; ; offset += kBytesPerLine, buffer += kBytesPerLine) {
1357 int32 remain = length;
1358 int32 index;
1359
1360 printf( "0x%06x: ", (int)offset);
1361
1362 for (index = 0; index < kBytesPerLine; index++) {
1363 if (remain-- > 0)
1364 printf("%02x%c", buffer[index], remain > 0 ? ',' : ' ');
1365 else
1366 printf(" ");
1367 }
1368
1369 remain = length;
1370 printf(" \'");
1371 for (index = 0; index < kBytesPerLine; index++) {
1372 if (remain-- > 0)
1373 printf("%c", buffer[index] > ' ' ? buffer[index] : '.');
1374 else
1375 printf(" ");
1376 }
1377 printf("\'\n");
1378
1379 length -= kBytesPerLine;
1380 if (length <= 0)
1381 break;
1382 }
1383 fflush(stdout);
1384 }
1385
1386
1387 int
CompareLabels(const BMenuItem * item1,const BMenuItem * item2)1388 CompareLabels(const BMenuItem* item1, const BMenuItem* item2)
1389 {
1390 return strcasecmp(item1->Label(), item2->Label());
1391 }
1392
1393
1394 void
EnableNamedMenuItem(BMenu * menu,const char * itemName,bool on)1395 EnableNamedMenuItem(BMenu* menu, const char* itemName, bool on)
1396 {
1397 BMenuItem* item = menu->FindItem(itemName);
1398 if (item != NULL)
1399 item->SetEnabled(on);
1400 }
1401
1402
1403 void
MarkNamedMenuItem(BMenu * menu,const char * itemName,bool on)1404 MarkNamedMenuItem(BMenu* menu, const char* itemName, bool on)
1405 {
1406 BMenuItem* item = menu->FindItem(itemName);
1407 if (item != NULL)
1408 item->SetMarked(on);
1409 }
1410
1411
1412 void
EnableNamedMenuItem(BMenu * menu,uint32 commandName,bool on)1413 EnableNamedMenuItem(BMenu* menu, uint32 commandName, bool on)
1414 {
1415 BMenuItem* item = menu->FindItem(commandName);
1416 if (item != NULL)
1417 item->SetEnabled(on);
1418 }
1419
1420
1421 void
MarkNamedMenuItem(BMenu * menu,uint32 commandName,bool on)1422 MarkNamedMenuItem(BMenu* menu, uint32 commandName, bool on)
1423 {
1424 BMenuItem* item = menu->FindItem(commandName);
1425 if (item != NULL)
1426 item->SetMarked(on);
1427 }
1428
1429
1430 void
DeleteSubmenu(BMenuItem * submenuItem)1431 DeleteSubmenu(BMenuItem* submenuItem)
1432 {
1433 if (submenuItem == NULL)
1434 return;
1435
1436 BMenu* submenu = submenuItem->Submenu();
1437 if (submenu == NULL)
1438 return;
1439
1440 // delete all submenu items
1441 submenu->RemoveItems(0, submenu->CountItems(), true);
1442 }
1443
1444
1445 status_t
GetAppSignatureFromAttr(BFile * file,char * attr)1446 GetAppSignatureFromAttr(BFile* file, char* attr)
1447 {
1448 // This call is a performance improvement that
1449 // avoids using the BAppFileInfo API when retrieving the
1450 // app signature -- the call is expensive because by default
1451 // the resource fork is scanned to read the attribute
1452
1453 #ifdef B_APP_FILE_INFO_IS_FAST
1454 BAppFileInfo appFileInfo(file);
1455 return appFileInfo.GetSignature(attr);
1456 #else
1457 ssize_t readResult = file->ReadAttr(kAttrAppSignature, B_MIME_STRING_TYPE,
1458 0, attr, B_MIME_TYPE_LENGTH);
1459
1460 if (readResult <= 0)
1461 return (status_t)readResult;
1462
1463 return B_OK;
1464 #endif // B_APP_FILE_INFO_IS_FAST
1465 }
1466
1467
1468 status_t
GetAppIconFromAttr(BFile * file,BBitmap * icon,icon_size which)1469 GetAppIconFromAttr(BFile* file, BBitmap* icon, icon_size which)
1470 {
1471 // This call is a performance improvement that
1472 // avoids using the BAppFileInfo API when retrieving the
1473 // app icons -- the call is expensive because by default
1474 // the resource fork is scanned to read the icons
1475
1476 //#ifdef B_APP_FILE_INFO_IS_FAST
1477 BAppFileInfo appFileInfo(file);
1478 return appFileInfo.GetIcon(icon, which);
1479 //#else
1480 //
1481 // const char* attrName = kAttrIcon;
1482 // uint32 type = B_VECTOR_ICON_TYPE;
1483 //
1484 // // try vector icon
1485 // attr_info ainfo;
1486 // status_t result = file->GetAttrInfo(attrName, &ainfo);
1487 //
1488 // if (result == B_OK) {
1489 // uint8 buffer[ainfo.size];
1490 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer,
1491 // ainfo.size);
1492 // if (readResult == ainfo.size) {
1493 // if (BIconUtils::GetVectorIcon(buffer, ainfo.size, icon) == B_OK)
1494 // return B_OK;
1495 // }
1496 // }
1497 //
1498 // // try again with R5 icons
1499 // attrName = which == B_LARGE_ICON ? kAttrLargeIcon : kAttrMiniIcon;
1500 // type = which == B_LARGE_ICON ? LARGE_ICON_TYPE : MINI_ICON_TYPE;
1501 //
1502 // result = file->GetAttrInfo(attrName, &ainfo);
1503 // if (result < B_OK)
1504 // return result;
1505 //
1506 // uint8 buffer[ainfo.size];
1507 //
1508 // ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, ainfo.size);
1509 // if (readResult <= 0)
1510 // return (status_t)readResult;
1511 //
1512 // if (icon->ColorSpace() != B_CMAP8)
1513 // result = BIconUtils::ConvertFromCMAP8(buffer, which, which, which, icon);
1514 // else
1515 // icon->SetBits(buffer, icon->BitsLength(), 0, B_CMAP8);
1516 //
1517 // return result;
1518 //#endif // B_APP_FILE_INFO_IS_FAST
1519 }
1520
1521
1522 status_t
GetFileIconFromAttr(BNode * node,BBitmap * icon,icon_size which)1523 GetFileIconFromAttr(BNode* node, BBitmap* icon, icon_size which)
1524 {
1525 // get icon from the node info
1526 BNodeInfo nodeInfo(node);
1527 return nodeInfo.GetIcon(icon, which);
1528 }
1529
1530
1531 // #pragma mark - PrintToStream
1532
1533
1534 void
PrintToStream(rgb_color color)1535 PrintToStream(rgb_color color)
1536 {
1537 printf("r:%x, g:%x, b:%x, a:%x\n",
1538 color.red, color.green, color.blue, color.alpha);
1539 }
1540
1541
1542 // #pragma mark - EachMenuItem
1543
1544
1545 extern BMenuItem*
EachMenuItem(BMenu * menu,bool recursive,BMenuItem * (* func)(BMenuItem *))1546 EachMenuItem(BMenu* menu, bool recursive, BMenuItem* (*func)(BMenuItem *))
1547 {
1548 int32 count = menu->CountItems();
1549 for (int32 index = 0; index < count; index++) {
1550 BMenuItem* item = menu->ItemAt(index);
1551 BMenuItem* newItem = (func)(item);
1552 if (newItem != NULL)
1553 return newItem;
1554
1555 if (recursive) {
1556 BMenu* submenu = menu->SubmenuAt(index);
1557 if (submenu != NULL)
1558 return EachMenuItem(submenu, true, func);
1559 }
1560 }
1561
1562 return NULL;
1563 }
1564
1565
1566 extern const BMenuItem*
EachMenuItem(const BMenu * menu,bool recursive,BMenuItem * (* func)(const BMenuItem *))1567 EachMenuItem(const BMenu* menu, bool recursive,
1568 BMenuItem* (*func)(const BMenuItem *))
1569 {
1570 int32 count = menu->CountItems();
1571 for (int32 index = 0; index < count; index++) {
1572 BMenuItem* item = menu->ItemAt(index);
1573 BMenuItem* newItem = (func)(item);
1574 if (newItem != NULL)
1575 return newItem;
1576
1577 if (recursive) {
1578 BMenu* submenu = menu->SubmenuAt(index);
1579 if (submenu != NULL)
1580 return EachMenuItem(submenu, true, func);
1581 }
1582 }
1583
1584 return NULL;
1585 }
1586
1587
1588 // #pragma mark - PositionPassingMenuItem
1589
1590
PositionPassingMenuItem(const char * title,BMessage * message,char shortcut,uint32 modifiers)1591 PositionPassingMenuItem::PositionPassingMenuItem(const char* title,
1592 BMessage* message, char shortcut, uint32 modifiers)
1593 :
1594 BMenuItem(title, message, shortcut, modifiers)
1595 {
1596 }
1597
1598
PositionPassingMenuItem(BMenu * menu,BMessage * message)1599 PositionPassingMenuItem::PositionPassingMenuItem(BMenu* menu, BMessage* message)
1600 :
1601 BMenuItem(menu, message)
1602 {
1603 }
1604
1605
PositionPassingMenuItem(BMessage * data)1606 PositionPassingMenuItem::PositionPassingMenuItem(BMessage* data)
1607 :
1608 BMenuItem(data)
1609 {
1610 }
1611
1612
1613 BArchivable*
Instantiate(BMessage * data)1614 PositionPassingMenuItem::Instantiate(BMessage* data)
1615 {
1616 if (validate_instantiation(data, "PositionPassingMenuItem"))
1617 return new PositionPassingMenuItem(data);
1618
1619 return NULL;
1620 }
1621
1622
1623 status_t
Invoke(BMessage * message)1624 PositionPassingMenuItem::Invoke(BMessage* message)
1625 {
1626 if (Menu() == NULL)
1627 return B_ERROR;
1628
1629 if (!IsEnabled())
1630 return B_ERROR;
1631
1632 if (message == NULL)
1633 message = Message();
1634
1635 if (message == NULL)
1636 return B_BAD_VALUE;
1637
1638 BMessage clone(*message);
1639 clone.AddInt32("index", Menu()->IndexOf(this));
1640 clone.AddInt64("when", system_time());
1641 clone.AddPointer("source", this);
1642
1643 // embed the invoke location of the menu so that we can create
1644 // a new folder, etc. on the spot
1645 BMenu* menu = Menu();
1646
1647 for (;;) {
1648 if (!menu->Supermenu())
1649 break;
1650
1651 menu = menu->Supermenu();
1652 }
1653
1654 // use the window position only, if the item was invoked from the menu
1655 // menu->Window() points to the window the item was invoked from
1656 if (dynamic_cast<BContainerWindow*>(menu->Window()) == NULL) {
1657 AutoLocker<BLooper> lock(menu->Looper());
1658 if (lock.IsLocked()) {
1659 BPoint invokeOrigin(menu->Window()->Frame().LeftTop());
1660 clone.AddPoint("be:invoke_origin", invokeOrigin);
1661 }
1662 }
1663
1664 return BInvoker::Invoke(&clone);
1665 }
1666
1667
1668 // #pragma mark - BPrivate functions
1669
1670
1671 bool
BootedInSafeMode()1672 BootedInSafeMode()
1673 {
1674 const char* safeMode = getenv("SAFEMODE");
1675 return (safeMode && strcmp(safeMode, "yes") == 0);
1676 }
1677
1678
1679 float
ComputeTypeAheadScore(const char * text,const char * match,bool wordMode)1680 ComputeTypeAheadScore(const char* text, const char* match, bool wordMode)
1681 {
1682 // highest score: exact match
1683 const char* found = strcasestr(text, match);
1684 if (found != NULL) {
1685 if (found == text)
1686 return kExactMatchScore;
1687
1688 return 1.f / (found - text);
1689 }
1690
1691 // there was no exact match
1692
1693 // second best: all characters at word beginnings
1694 if (wordMode) {
1695 float score = 0;
1696 for (int32 j = 0, k = 0; match[j]; j++) {
1697 while (text[k]
1698 && tolower(text[k]) != tolower(match[j])) {
1699 k++;
1700 }
1701 if (text[k] == '\0') {
1702 score = 0;
1703 break;
1704 }
1705
1706 bool wordStart = k == 0 || isspace(text[k - 1]);
1707 if (wordStart)
1708 score++;
1709 if (j > 0) {
1710 bool wordEnd = !text[k + 1] || isspace(text[k + 1]);
1711 if (wordEnd)
1712 score += 0.3;
1713 if (match[j - 1] == text[k - 1])
1714 score += 0.7;
1715 }
1716
1717 score += 1.f / (k + 1);
1718 k++;
1719 }
1720
1721 return score;
1722 }
1723
1724 return -1;
1725 }
1726
1727
1728 // #pragma mark - throw on error functions.
1729
1730
1731 void
_ThrowOnError(status_t result,const char * DEBUG_ONLY (file),int32 DEBUG_ONLY (line))1732 _ThrowOnError(status_t result, const char* DEBUG_ONLY(file),
1733 int32 DEBUG_ONLY(line))
1734 {
1735 if (result != B_OK) {
1736 PRINT(("%s at %s:%d\n", strerror(result), file, (int)line));
1737 throw result;
1738 }
1739 }
1740
1741
1742 void
_ThrowIfNotSize(ssize_t size,const char * DEBUG_ONLY (file),int32 DEBUG_ONLY (line))1743 _ThrowIfNotSize(ssize_t size, const char* DEBUG_ONLY(file),
1744 int32 DEBUG_ONLY(line))
1745 {
1746 if (size < B_OK) {
1747 PRINT(("%s at %s:%d\n", strerror((status_t)size), file, (int)line));
1748 throw (status_t)size;
1749 }
1750 }
1751
1752
1753 void
_ThrowOnAssert(bool success,const char * DEBUG_ONLY (file),int32 DEBUG_ONLY (line))1754 _ThrowOnAssert(bool success, const char* DEBUG_ONLY(file),
1755 int32 DEBUG_ONLY(line))
1756 {
1757 if (!success) {
1758 PRINT(("Assert failed at %s:%d\n", file, (int)line));
1759 throw B_ERROR;
1760 }
1761 }
1762
1763 } // namespace BPrivate
1764