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