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 #ifndef _UTILITIES_H 36 #define _UTILITIES_H 37 38 #include <ByteOrder.h> 39 #include <Bitmap.h> 40 #include <DataIO.h> 41 #include <Directory.h> 42 #include <Entry.h> 43 #include <Font.h> 44 #include <GraphicsDefs.h> 45 #include <Looper.h> 46 #include <MenuItem.h> 47 #include <MessageFilter.h> 48 #include <Mime.h> 49 #include <ObjectList.h> 50 #include <Point.h> 51 #include <Path.h> 52 #include <String.h> 53 #include <StringView.h> 54 55 #include <stdarg.h> 56 57 class BMessage; 58 class BVolume; 59 class BBitmap; 60 class BTextView; 61 class BView; 62 63 namespace BPrivate { 64 65 class Benaphore; 66 class BPose; 67 class BPoseView; 68 69 // global variables 70 extern const rgb_color kBlack; 71 extern const rgb_color kWhite; 72 73 const int64 kHalfKBSize = 512; 74 const int64 kKBSize = 1024; 75 const int64 kMBSize = 1048576; 76 const int64 kGBSize = 1073741824; 77 const int64 kTBSize = kGBSize * kKBSize; 78 79 const int32 kMiniIconSeparator = 3; 80 81 #ifdef __HAIKU__ 82 const color_space kDefaultIconDepth = B_RGBA32; 83 #else 84 const color_space kDefaultIconDepth = B_CMAP8; 85 #endif 86 87 // misc typedefs, constants and structs 88 89 // Periodically updated poses (ones with a volume space bar) register 90 // themselfs in this global list. This way they can be iterated over instead 91 // of sending around update messages. 92 93 class PeriodicUpdatePoses { 94 public: 95 PeriodicUpdatePoses(); 96 ~PeriodicUpdatePoses(); 97 98 typedef bool (*PeriodicUpdateCallback)(BPose *pose, void *cookie); 99 100 void AddPose(BPose *pose, BPoseView *poseView, 101 PeriodicUpdateCallback callback, void *cookie); 102 bool RemovePose(BPose *pose, void **cookie); 103 104 void DoPeriodicUpdate(bool forceRedraw); 105 106 private: 107 struct periodic_pose { 108 BPose *pose; 109 BPoseView *pose_view; 110 PeriodicUpdateCallback callback; 111 void *cookie; 112 }; 113 114 Benaphore *fLock; 115 BObjectList<periodic_pose> fPoseList; 116 }; 117 118 extern PeriodicUpdatePoses gPeriodicUpdatePoses; 119 120 121 // PoseInfo is the structure that gets saved as attributes for every node on 122 // disk, defining the node's position and visibility 123 class PoseInfo { 124 public: 125 static void EndianSwap(void *castToThis); 126 void PrintToStream(); 127 128 bool fInvisible; 129 ino_t fInitedDirectory; 130 // for a location to be valid, fInitedDirectory has to contain the inode 131 // of the items parent directory 132 // This makes it impossible to for instance zip up files and extract 133 // them in the same location. This should probably be reworked -- Tracker 134 // could say strip the file location attributes when dropping files into 135 // a closed folder 136 BPoint fLocation; 137 }; 138 139 140 // extends PoseInfo adding workspace support; used for desktop 141 // poses only 142 class ExtendedPoseInfo { 143 public: 144 size_t Size() const; 145 static size_t Size(int32); 146 size_t SizeWithHeadroom() const; 147 static size_t SizeWithHeadroom(size_t); 148 bool HasLocationForFrame(BRect) const; 149 BPoint LocationForFrame(BRect) const; 150 bool SetLocationForFrame(BPoint, BRect); 151 152 static void EndianSwap(void *castToThis); 153 void PrintToStream(); 154 155 uint32 fWorkspaces; 156 bool fInvisible; 157 bool fShowFromBootOnly; 158 bool fReservedBool1; 159 bool fReservedBool2; 160 int32 fReservedInt1; 161 int32 fReservedInt2; 162 int32 fReservedInt3; 163 int32 fReservedInt4; 164 int32 fReservedInt5; 165 166 int32 fNumFrames; 167 struct FrameLocation { 168 BPoint fLocation; 169 BRect fFrame; 170 uint32 fWorkspaces; 171 }; 172 173 FrameLocation fLocations[0]; 174 }; 175 176 // misc functions 177 void DisallowMetaKeys(BTextView *); 178 void DisallowFilenameKeys(BTextView *); 179 180 181 inline bool 182 IsDigit(const char c) 183 { 184 if ((c >= 48 && c <= 57) || c == 32) 185 return true; 186 else 187 return false; 188 } 189 190 191 //! Compares two strings naturally, as opposed to lexicographically 192 inline int 193 NaturalCompare(const char *s1, const char *s2) 194 { 195 struct Chunk { 196 int32 type; 197 char* ascii; 198 // Type = 0 199 int32 num; 200 // Type = 1 201 }; 202 203 Chunk a; 204 Chunk b; 205 206 size_t len1 = strlen(s1); 207 size_t len2 = strlen(s2); 208 209 char bufferA[len1 + 1]; 210 char bufferB[len2 + 1]; 211 212 uint32 i = 0; 213 uint32 j = 0; 214 215 while (true) { 216 // determine type of next chunks in each string based on first char 217 if (i == len1) 218 a.type = -1; 219 else if (IsDigit(s1[i])) 220 a.type = 1; 221 else 222 a.type = 0; 223 224 if (j == len2) 225 b.type = -1; 226 else if (IsDigit(s2[j])) 227 b.type = 1; 228 else 229 b.type = 0; 230 231 // check if we reached the end of either string 232 if (a.type == b.type && a.type == -1) 233 return 0; 234 if (a.type == -1) 235 return -1; 236 if (b.type == -1) 237 return 1; 238 239 if (a.type != b.type) { 240 // different chunk types, just compare the remaining strings 241 return strcasecmp(&s1[i], &s2[j]); 242 } 243 244 // fetch the next chunk for a 245 if (a.type == 0) { 246 // string chunk 247 int32 k = i; 248 while (!IsDigit(s1[k]) && s1[k] != 0) { 249 bufferA[k - i] = s1[k]; 250 k++; 251 } 252 bufferA[k - i] = 0; 253 a.ascii = bufferA; 254 i += k - i; 255 } else { 256 // number chunk 257 int32 k = i; 258 while (IsDigit(s1[k]) && s1[k] != 0) { 259 bufferA[k - i] = s1[k]; 260 k++; 261 } 262 bufferA[k - i] = 0; 263 a.ascii = bufferA; 264 a.num = atoi(bufferA); 265 i += k - i; 266 } 267 268 // fetch the next chunk for b 269 if (b.type == 0) { 270 // string chunk 271 int32 k = j; 272 while (!IsDigit(s2[k]) && s2[k] != 0) { 273 bufferB[k - j] = s2[k]; 274 k++; 275 } 276 bufferB[k - j] = 0; 277 b.ascii = bufferB; 278 j += k - j; 279 } else { 280 // number chunk 281 int32 k = j; 282 while (IsDigit(s2[k]) && s2[k] != 0) { 283 bufferB[k - j] = s2[k]; 284 k++; 285 } 286 bufferB[k - j] = 0; 287 b.ascii = bufferB; 288 b.num = atoi(bufferB); 289 j += k - j; 290 } 291 292 // compare the two chunks based on their type 293 if (a.type == 0) { 294 // string chunks 295 int stringCompareResult = strcasecmp(a.ascii, b.ascii); 296 // if the chunk strings are the same, keep using natural 297 // sorting for the next chunks 298 if (stringCompareResult != 0) 299 return stringCompareResult; 300 } else { 301 // number chunks 302 if (a.num != b.num) { 303 if (a.num < b.num) 304 return -1; 305 if (a.num > b.num) 306 return 1; 307 } 308 } 309 } 310 311 return 0; 312 } 313 314 315 bool ValidateStream(BMallocIO *, uint32, int32 version); 316 317 318 uint32 HashString(const char *string, uint32 seed); 319 uint32 AttrHashString(const char *string, uint32 type); 320 321 322 class OffscreenBitmap { 323 // a utility class for setting up offscreen bitmaps 324 public: 325 OffscreenBitmap(BRect bounds); 326 OffscreenBitmap(); 327 ~OffscreenBitmap(); 328 329 BView *BeginUsing(BRect bounds); 330 void DoneUsing(); 331 BBitmap *Bitmap() const; 332 // blit this to your view when you are done rendering 333 BView *View() const; 334 // use this to render your image 335 336 private: 337 void NewBitmap(BRect frame); 338 BBitmap *fBitmap; 339 }; 340 341 342 // bitmap functions 343 extern void FadeRGBA32Horizontal(uint32 *bits, int32 width, int32 height, int32 from, int32 to); 344 extern void FadeRGBA32Vertical(uint32 *bits, int32 width, int32 height, int32 from, int32 to); 345 346 347 class FlickerFreeStringView : public BStringView { 348 // Adds support for offscreen bitmap drawing for string views that update often 349 // this would be better implemented as an option of BStringView 350 public: 351 FlickerFreeStringView(BRect bounds, const char *name, 352 const char *text, uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, 353 uint32 flags = B_WILL_DRAW); 354 FlickerFreeStringView(BRect bounds, const char *name, 355 const char *text, BBitmap *existingOffscreen, 356 uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, 357 uint32 flags = B_WILL_DRAW); 358 virtual ~FlickerFreeStringView(); 359 virtual void Draw(BRect); 360 virtual void AttachedToWindow(); 361 virtual void SetViewColor(rgb_color); 362 virtual void SetLowColor(rgb_color); 363 364 private: 365 OffscreenBitmap *fBitmap; 366 rgb_color fViewColor; 367 rgb_color fLowColor; 368 BBitmap *fOrigBitmap; 369 370 typedef BStringView _inherited; 371 }; 372 373 374 class DraggableIcon : public BView { 375 // used to determine a save location for a file 376 public: 377 DraggableIcon(BRect, const char *, const char *mimeType, icon_size, 378 const BMessage *, BMessenger, 379 uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, 380 uint32 flags = B_WILL_DRAW); 381 virtual ~DraggableIcon(); 382 383 static BRect PreferredRect(BPoint offset, icon_size); 384 void SetTarget(BMessenger); 385 386 protected: 387 virtual void AttachedToWindow(); 388 virtual void MouseDown(BPoint); 389 virtual void Draw(BRect); 390 391 virtual bool DragStarted(BMessage *dragMessage); 392 393 protected: 394 BBitmap *fBitmap; 395 BMessage fMessage; 396 BMessenger fTarget; 397 }; 398 399 400 class PositionPassingMenuItem : public BMenuItem { 401 public: 402 PositionPassingMenuItem(const char *title, BMessage *, char shortcut = 0, 403 uint32 modifiers = 0); 404 405 PositionPassingMenuItem(BMenu *, BMessage *); 406 407 protected: 408 virtual status_t Invoke(BMessage * = 0); 409 // appends the invoke location for NewFolder, etc. to use 410 411 private: 412 typedef BMenuItem _inherited; 413 }; 414 415 416 class Benaphore { 417 // aka benaphore 418 public: 419 Benaphore(const char *name = "Light Lock") 420 : fSemaphore(create_sem(0, name)), 421 fCount(1) 422 { 423 } 424 425 ~Benaphore() 426 { 427 delete_sem(fSemaphore); 428 } 429 430 bool Lock() 431 { 432 if (atomic_add(&fCount, -1) <= 0) 433 return acquire_sem(fSemaphore) == B_OK; 434 435 return true; 436 } 437 438 void Unlock() 439 { 440 if (atomic_add(&fCount, 1) < 0) 441 release_sem(fSemaphore); 442 } 443 444 bool IsLocked() const 445 { 446 return fCount <= 0; 447 } 448 449 private: 450 sem_id fSemaphore; 451 int32 fCount; 452 }; 453 454 455 class SeparatorLine : public BView { 456 public: 457 SeparatorLine(BPoint , float , bool vertical, const char *name = ""); 458 virtual void Draw(BRect bounds); 459 }; 460 461 462 class TitledSeparatorItem : public BMenuItem { 463 public: 464 TitledSeparatorItem(const char *); 465 virtual ~TitledSeparatorItem(); 466 467 virtual void SetEnabled(bool state); 468 469 protected: 470 virtual void GetContentSize(float *width, float *height); 471 virtual void Draw(); 472 473 private: 474 typedef BMenuItem _inherited; 475 }; 476 477 478 class LooperAutoLocker { 479 public: 480 LooperAutoLocker(BHandler *handler) 481 : fHandler(handler), 482 fHasLock(handler->LockLooper()) 483 { 484 } 485 486 ~LooperAutoLocker() 487 { 488 if (fHasLock) 489 fHandler->UnlockLooper(); 490 } 491 492 bool operator!() const 493 { 494 return !fHasLock; 495 } 496 497 bool IsLocked() const 498 { 499 return fHasLock; 500 } 501 502 private: 503 BHandler *fHandler; 504 bool fHasLock; 505 }; 506 507 508 class MessengerAutoLocker { 509 // move this into AutoLock.h 510 public: 511 MessengerAutoLocker(BMessenger *messenger) 512 : fMessenger(messenger), 513 fHasLock(messenger->LockTarget()) 514 { } 515 516 ~MessengerAutoLocker() 517 { 518 Unlock(); 519 } 520 521 bool operator!() const 522 { 523 return !fHasLock; 524 } 525 526 bool IsLocked() const 527 { 528 return fHasLock; 529 } 530 531 void Unlock() 532 { 533 if (fHasLock) { 534 BLooper *looper; 535 fMessenger->Target(&looper); 536 if (looper) 537 looper->Unlock(); 538 fHasLock = false; 539 } 540 } 541 542 private: 543 BMessenger *fMessenger; 544 bool fHasLock; 545 }; 546 547 548 class ShortcutFilter : public BMessageFilter { 549 public: 550 ShortcutFilter(uint32 shortcutKey, uint32 shortcutModifier, 551 uint32 shortcutWhat, BHandler *target); 552 553 protected: 554 filter_result Filter(BMessage *, BHandler **); 555 556 private: 557 uint32 fShortcutKey; 558 uint32 fShortcutModifier; 559 uint32 fShortcutWhat; 560 BHandler *fTarget; 561 }; 562 563 // iterates over all the refs in a message 564 entry_ref *EachEntryRef(BMessage *, entry_ref *(*)(entry_ref *, void *), 565 void *passThru = 0); 566 const entry_ref *EachEntryRef(const BMessage *, 567 const entry_ref *(*)(const entry_ref *, void *), void *passThru = 0); 568 569 entry_ref *EachEntryRef(BMessage *, entry_ref *(*)(entry_ref *, void *), 570 void *passThru, int32 maxCount); 571 const entry_ref *EachEntryRef(const BMessage *, 572 const entry_ref *(*)(const entry_ref *, void *), void *passThru, int32 maxCount); 573 574 575 bool ContainsEntryRef(const BMessage *, const entry_ref *); 576 int32 CountRefs(const BMessage *); 577 578 BMenuItem *EachMenuItem(BMenu *menu, bool recursive, BMenuItem *(*func)(BMenuItem *)); 579 const BMenuItem *EachMenuItem(const BMenu *menu, bool recursive, 580 BMenuItem *(*func)(const BMenuItem *)); 581 582 int64 StringToScalar(const char *text); 583 // string to num, understands kB, MB, etc. 584 585 // misc calls 586 void EmbedUniqueVolumeInfo(BMessage *, const BVolume *); 587 status_t MatchArchivedVolume(BVolume *, const BMessage *, int32 index = 0); 588 void TruncateLeaf(BString *string); 589 590 void StringFromStream(BString *, BMallocIO *, bool endianSwap = false); 591 void StringToStream(const BString *, BMallocIO *); 592 int32 ArchiveSize(const BString *); 593 594 extern void EnableNamedMenuItem(BMenu *menu, const char *itemName, bool on); 595 extern void MarkNamedMenuItem(BMenu *menu, const char *itemName, bool on); 596 extern void EnableNamedMenuItem(BMenu *menu, uint32 commandName, bool on); 597 extern void MarkNamedMenuItem(BMenu *menu, uint32 commandName, bool on); 598 extern void DeleteSubmenu(BMenuItem *submenuItem); 599 600 extern bool BootedInSafeMode(); 601 602 // Now is in kits 603 #if B_BEOS_VERSION <= B_BEOS_VERSION_MAUI && !defined(__HAIKU__) 604 605 // Should be in kits 606 bool operator==(const rgb_color &, const rgb_color &); 607 bool operator!=(const rgb_color &, const rgb_color &); 608 609 #endif 610 611 inline rgb_color 612 Color(int32 r, int32 g, int32 b, int32 alpha = 255) 613 { 614 rgb_color result; 615 result.red = (uchar)r; 616 result.green = (uchar)g; 617 result.blue = (uchar)b; 618 result.alpha = (uchar)alpha; 619 620 return result; 621 } 622 623 void PrintToStream(rgb_color color); 624 625 template <class InitCheckable> 626 void 627 ThrowOnInitCheckError(InitCheckable *item) 628 { 629 if (!item) 630 throw B_ERROR; 631 status_t error = item->InitCheck(); 632 if (error != B_OK) 633 throw error; 634 } 635 636 #if DEBUG 637 #define ThrowOnError(error) _ThrowOnError(error, __FILE__, __LINE__) 638 #define ThrowIfNotSize(error) _ThrowIfNotSize(error, __FILE__, __LINE__) 639 #define ThrowOnErrorWithMessage(error, debugStr) _ThrowOnError(error, debugStr, __FILE__, __LINE__) 640 #else 641 #define ThrowOnError(x) _ThrowOnError(x, 0, 0) 642 #define ThrowIfNotSize(x) _ThrowIfNotSize(x, 0, 0) 643 #define ThrowOnErrorWithMessage(error, debugStr) _ThrowOnError(error, debugStr, __FILE__, __LINE__) 644 #endif 645 646 void _ThrowOnError(status_t, const char *, int32); 647 void _ThrowIfNotSize(ssize_t, const char *, int32); 648 void _ThrowOnError(status_t, const char *debugStr, const char *, int32); 649 650 // stub calls that work around BAppFile info inefficiency 651 status_t GetAppSignatureFromAttr(BFile *, char *); 652 status_t GetAppIconFromAttr(BFile *, BBitmap *, icon_size); 653 status_t GetFileIconFromAttr(BNode *, BBitmap *, icon_size); 654 655 656 // debugging 657 void HexDump(const void *buffer, int32 length); 658 659 #if xDEBUG 660 661 inline void 662 PrintRefToStream(const entry_ref *ref, const char *trailer = "\n") 663 { 664 if (!ref) { 665 PRINT(("NULL entry_ref%s", trailer)); 666 return; 667 } 668 BPath path; 669 BEntry entry(ref); 670 entry.GetPath(&path); 671 PRINT(("%s%s", path.Path(), trailer)); 672 } 673 674 inline void 675 PrintEntryToStream(const BEntry *entry, const char *trailer = "\n") 676 { 677 if (!entry) { 678 PRINT(("NULL entry%s", trailer)); 679 return; 680 } 681 BPath path; 682 entry->GetPath(&path); 683 PRINT(("%s%s", path.Path(), trailer)); 684 } 685 686 inline void 687 PrintDirToStream(const BDirectory *dir, const char *trailer = "\n") 688 { 689 if (!dir) { 690 PRINT(("NULL entry_ref%s", trailer)); 691 return; 692 } 693 BPath path; 694 BEntry entry; 695 dir->GetEntry(&entry); 696 entry.GetPath(&path); 697 PRINT(("%s%s", path.Path(), trailer)); 698 } 699 700 #else 701 702 inline void PrintRefToStream(const entry_ref *, const char * = 0) {} 703 inline void PrintEntryToStream(const BEntry *, const char * = 0) {} 704 inline void PrintDirToStream(const BDirectory *, const char * = 0) {} 705 706 #endif 707 708 #ifdef xDEBUG 709 710 extern FILE *logFile; 711 712 inline void PrintToLogFile(const char *fmt, ...) 713 { 714 va_list ap; 715 va_start(ap, fmt); 716 vfprintf(logFile, fmt, ap); 717 va_end(ap); 718 } 719 720 #define WRITELOG(_ARGS_) \ 721 if (logFile == 0) \ 722 logFile = fopen("/var/log/tracker.log", "a+"); \ 723 if (logFile != 0) { \ 724 thread_info info; \ 725 get_thread_info(find_thread(NULL), &info); \ 726 PrintToLogFile("[t %Ld] \"%s\" (%s:%i) ", system_time(), \ 727 info.name, __FILE__, __LINE__); \ 728 PrintToLogFile _ARGS_; \ 729 PrintToLogFile("\n"); \ 730 fflush(logFile); \ 731 } 732 733 #else 734 735 #define WRITELOG(_ARGS_) 736 737 #endif 738 739 // fancy casting macros 740 741 template <typename NewType, typename OldType> 742 inline NewType assert_cast(OldType castedPointer) { 743 ASSERT(dynamic_cast<NewType>(castedPointer) != NULL); 744 return static_cast<NewType>(castedPointer); 745 } 746 747 // B_SWAP_INT32 have broken signedness, simple cover calls to fix that 748 // should fix up in ByteOrder.h 749 750 inline int32 SwapInt32(int32 value) { return (int32)B_SWAP_INT32((uint32)value); } 751 inline uint32 SwapUInt32(uint32 value) { return B_SWAP_INT32(value); } 752 inline int64 SwapInt64(int64 value) { return (int64)B_SWAP_INT64((uint64)value); } 753 inline uint64 SwapUInt64(uint64 value) { return B_SWAP_INT64(value); } 754 755 756 extern const float kExactMatchScore; 757 float ComputeTypeAheadScore(const char *text, const char *match, 758 size_t matchLength, bool wordMode = false); 759 760 } // namespace BPrivate 761 762 #endif // _UTILITIES_H 763