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 char* ascii; 200 // Type = 0 201 int32 num; 202 // Type = 1 203 }; 204 205 Chunk a; 206 Chunk b; 207 208 size_t len1 = strlen(s1); 209 size_t len2 = strlen(s2); 210 211 char bufferA[len1 + 1]; 212 char bufferB[len2 + 1]; 213 214 uint32 i = 0; 215 uint32 j = 0; 216 217 while (true) { 218 // determine type of next chunks in each string based on first char 219 if (i == len1) 220 a.type = -1; 221 else if (IsDigit(s1[i])) 222 a.type = 1; 223 else 224 a.type = 0; 225 226 if (j == len2) 227 b.type = -1; 228 else if (IsDigit(s2[j])) 229 b.type = 1; 230 else 231 b.type = 0; 232 233 // check if we reached the end of either string 234 if (a.type == b.type && a.type == -1) 235 return 0; 236 if (a.type == -1) 237 return -1; 238 if (b.type == -1) 239 return 1; 240 241 if (a.type != b.type) { 242 // different chunk types, just compare the remaining strings 243 return strcasecmp(&s1[i], &s2[j]); 244 } 245 246 // fetch the next chunk for a 247 if (a.type == 0) { 248 // string chunk 249 int32 k = i; 250 while (!IsDigit(s1[k]) && s1[k] != 0) { 251 bufferA[k - i] = s1[k]; 252 k++; 253 } 254 bufferA[k - i] = 0; 255 a.ascii = bufferA; 256 i += k - i; 257 } else { 258 // number chunk 259 int32 k = i; 260 while (IsDigit(s1[k]) && s1[k] != 0) { 261 bufferA[k - i] = s1[k]; 262 k++; 263 } 264 bufferA[k - i] = 0; 265 a.ascii = bufferA; 266 a.num = atoi(bufferA); 267 i += k - i; 268 } 269 270 // fetch the next chunk for b 271 if (b.type == 0) { 272 // string chunk 273 int32 k = j; 274 while (!IsDigit(s2[k]) && s2[k] != 0) { 275 bufferB[k - j] = s2[k]; 276 k++; 277 } 278 bufferB[k - j] = 0; 279 b.ascii = bufferB; 280 j += k - j; 281 } else { 282 // number chunk 283 int32 k = j; 284 while (IsDigit(s2[k]) && s2[k] != 0) { 285 bufferB[k - j] = s2[k]; 286 k++; 287 } 288 bufferB[k - j] = 0; 289 b.ascii = bufferB; 290 b.num = atoi(bufferB); 291 j += k - j; 292 } 293 294 // compare the two chunks based on their type 295 if (a.type == 0) { 296 // string chunks 297 int stringCompareResult = strcasecmp(a.ascii, b.ascii); 298 // if the chunk strings are the same, keep using natural 299 // sorting for the next chunks 300 if (stringCompareResult != 0) 301 return stringCompareResult; 302 } else { 303 // number chunks 304 if (a.num != b.num) { 305 if (a.num < b.num) 306 return -1; 307 if (a.num > b.num) 308 return 1; 309 } 310 } 311 } 312 313 return 0; 314 } 315 316 317 bool ValidateStream(BMallocIO *, uint32, int32 version); 318 319 320 uint32 HashString(const char *string, uint32 seed); 321 uint32 AttrHashString(const char *string, uint32 type); 322 323 324 class OffscreenBitmap { 325 // a utility class for setting up offscreen bitmaps 326 public: 327 OffscreenBitmap(BRect bounds); 328 OffscreenBitmap(); 329 ~OffscreenBitmap(); 330 331 BView *BeginUsing(BRect bounds); 332 void DoneUsing(); 333 BBitmap *Bitmap() const; 334 // blit this to your view when you are done rendering 335 BView *View() const; 336 // use this to render your image 337 338 private: 339 void NewBitmap(BRect frame); 340 BBitmap *fBitmap; 341 }; 342 343 344 // bitmap functions 345 extern void FadeRGBA32Horizontal(uint32 *bits, int32 width, int32 height, int32 from, int32 to); 346 extern void FadeRGBA32Vertical(uint32 *bits, int32 width, int32 height, int32 from, int32 to); 347 348 349 class FlickerFreeStringView : public BStringView { 350 // Adds support for offscreen bitmap drawing for string views that update often 351 // this would be better implemented as an option of BStringView 352 public: 353 FlickerFreeStringView(BRect bounds, const char *name, 354 const char *text, uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, 355 uint32 flags = B_WILL_DRAW); 356 FlickerFreeStringView(BRect bounds, const char *name, 357 const char *text, BBitmap *existingOffscreen, 358 uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, 359 uint32 flags = B_WILL_DRAW); 360 virtual ~FlickerFreeStringView(); 361 virtual void Draw(BRect); 362 virtual void AttachedToWindow(); 363 virtual void SetViewColor(rgb_color); 364 virtual void SetLowColor(rgb_color); 365 366 private: 367 OffscreenBitmap *fBitmap; 368 rgb_color fViewColor; 369 rgb_color fLowColor; 370 BBitmap *fOrigBitmap; 371 372 typedef BStringView _inherited; 373 }; 374 375 376 class DraggableIcon : public BView { 377 // used to determine a save location for a file 378 public: 379 DraggableIcon(BRect, const char *, const char *mimeType, icon_size, 380 const BMessage *, BMessenger, 381 uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP, 382 uint32 flags = B_WILL_DRAW); 383 virtual ~DraggableIcon(); 384 385 static BRect PreferredRect(BPoint offset, icon_size); 386 void SetTarget(BMessenger); 387 388 protected: 389 virtual void AttachedToWindow(); 390 virtual void MouseDown(BPoint); 391 virtual void Draw(BRect); 392 393 virtual bool DragStarted(BMessage *dragMessage); 394 395 protected: 396 BBitmap *fBitmap; 397 BMessage fMessage; 398 BMessenger fTarget; 399 }; 400 401 402 class PositionPassingMenuItem : public BMenuItem { 403 public: 404 PositionPassingMenuItem(const char *title, BMessage *, char shortcut = 0, 405 uint32 modifiers = 0); 406 407 PositionPassingMenuItem(BMenu *, BMessage *); 408 409 protected: 410 virtual status_t Invoke(BMessage * = 0); 411 // appends the invoke location for NewFolder, etc. to use 412 413 private: 414 typedef BMenuItem _inherited; 415 }; 416 417 418 class Benaphore { 419 // aka benaphore 420 public: 421 Benaphore(const char *name = "Light Lock") 422 : fSemaphore(create_sem(0, name)), 423 fCount(1) 424 { 425 } 426 427 ~Benaphore() 428 { 429 delete_sem(fSemaphore); 430 } 431 432 bool Lock() 433 { 434 if (atomic_add(&fCount, -1) <= 0) 435 return acquire_sem(fSemaphore) == B_OK; 436 437 return true; 438 } 439 440 void Unlock() 441 { 442 if (atomic_add(&fCount, 1) < 0) 443 release_sem(fSemaphore); 444 } 445 446 bool IsLocked() const 447 { 448 return fCount <= 0; 449 } 450 451 private: 452 sem_id fSemaphore; 453 int32 fCount; 454 }; 455 456 457 class SeparatorLine : public BView { 458 public: 459 SeparatorLine(BPoint , float , bool vertical, const char *name = ""); 460 virtual void Draw(BRect bounds); 461 }; 462 463 464 class TitledSeparatorItem : public BMenuItem { 465 public: 466 TitledSeparatorItem(const char *); 467 virtual ~TitledSeparatorItem(); 468 469 virtual void SetEnabled(bool state); 470 471 protected: 472 virtual void GetContentSize(float *width, float *height); 473 virtual void Draw(); 474 475 private: 476 typedef BMenuItem _inherited; 477 }; 478 479 480 class LooperAutoLocker { 481 public: 482 LooperAutoLocker(BHandler *handler) 483 : fHandler(handler), 484 fHasLock(handler->LockLooper()) 485 { 486 } 487 488 ~LooperAutoLocker() 489 { 490 if (fHasLock) 491 fHandler->UnlockLooper(); 492 } 493 494 bool operator!() const 495 { 496 return !fHasLock; 497 } 498 499 bool IsLocked() const 500 { 501 return fHasLock; 502 } 503 504 private: 505 BHandler *fHandler; 506 bool fHasLock; 507 }; 508 509 510 class MessengerAutoLocker { 511 // move this into AutoLock.h 512 public: 513 MessengerAutoLocker(BMessenger *messenger) 514 : fMessenger(messenger), 515 fHasLock(messenger->LockTarget()) 516 { } 517 518 ~MessengerAutoLocker() 519 { 520 Unlock(); 521 } 522 523 bool operator!() const 524 { 525 return !fHasLock; 526 } 527 528 bool IsLocked() const 529 { 530 return fHasLock; 531 } 532 533 void Unlock() 534 { 535 if (fHasLock) { 536 BLooper *looper; 537 fMessenger->Target(&looper); 538 if (looper) 539 looper->Unlock(); 540 fHasLock = false; 541 } 542 } 543 544 private: 545 BMessenger *fMessenger; 546 bool fHasLock; 547 }; 548 549 550 class ShortcutFilter : public BMessageFilter { 551 public: 552 ShortcutFilter(uint32 shortcutKey, uint32 shortcutModifier, 553 uint32 shortcutWhat, BHandler *target); 554 555 protected: 556 filter_result Filter(BMessage *, BHandler **); 557 558 private: 559 uint32 fShortcutKey; 560 uint32 fShortcutModifier; 561 uint32 fShortcutWhat; 562 BHandler *fTarget; 563 }; 564 565 // iterates over all the refs in a message 566 entry_ref *EachEntryRef(BMessage *, entry_ref *(*)(entry_ref *, void *), 567 void *passThru = 0); 568 const entry_ref *EachEntryRef(const BMessage *, 569 const entry_ref *(*)(const entry_ref *, void *), void *passThru = 0); 570 571 entry_ref *EachEntryRef(BMessage *, entry_ref *(*)(entry_ref *, void *), 572 void *passThru, int32 maxCount); 573 const entry_ref *EachEntryRef(const BMessage *, 574 const entry_ref *(*)(const entry_ref *, void *), void *passThru, int32 maxCount); 575 576 577 bool ContainsEntryRef(const BMessage *, const entry_ref *); 578 int32 CountRefs(const BMessage *); 579 580 BMenuItem *EachMenuItem(BMenu *menu, bool recursive, BMenuItem *(*func)(BMenuItem *)); 581 const BMenuItem *EachMenuItem(const BMenu *menu, bool recursive, 582 BMenuItem *(*func)(const BMenuItem *)); 583 584 int64 StringToScalar(const char *text); 585 // string to num, understands kB, MB, etc. 586 587 // misc calls 588 void EmbedUniqueVolumeInfo(BMessage *, const BVolume *); 589 status_t MatchArchivedVolume(BVolume *, const BMessage *, int32 index = 0); 590 void TruncateLeaf(BString *string); 591 592 void StringFromStream(BString *, BMallocIO *, bool endianSwap = false); 593 void StringToStream(const BString *, BMallocIO *); 594 int32 ArchiveSize(const BString *); 595 596 extern void EnableNamedMenuItem(BMenu *menu, const char *itemName, bool on); 597 extern void MarkNamedMenuItem(BMenu *menu, const char *itemName, bool on); 598 extern void EnableNamedMenuItem(BMenu *menu, uint32 commandName, bool on); 599 extern void MarkNamedMenuItem(BMenu *menu, uint32 commandName, bool on); 600 extern void DeleteSubmenu(BMenuItem *submenuItem); 601 602 extern bool BootedInSafeMode(); 603 604 // Now is in kits 605 #if B_BEOS_VERSION <= B_BEOS_VERSION_MAUI && !defined(__HAIKU__) 606 607 // Should be in kits 608 bool operator==(const rgb_color &, const rgb_color &); 609 bool operator!=(const rgb_color &, const rgb_color &); 610 611 #endif 612 613 inline rgb_color 614 Color(int32 r, int32 g, int32 b, int32 alpha = 255) 615 { 616 rgb_color result; 617 result.red = (uchar)r; 618 result.green = (uchar)g; 619 result.blue = (uchar)b; 620 result.alpha = (uchar)alpha; 621 622 return result; 623 } 624 625 void PrintToStream(rgb_color color); 626 627 template <class InitCheckable> 628 void 629 ThrowOnInitCheckError(InitCheckable *item) 630 { 631 if (!item) 632 throw B_ERROR; 633 status_t error = item->InitCheck(); 634 if (error != B_OK) 635 throw error; 636 } 637 638 #if DEBUG 639 #define ThrowOnError(error) _ThrowOnError(error, __FILE__, __LINE__) 640 #define ThrowIfNotSize(error) _ThrowIfNotSize(error, __FILE__, __LINE__) 641 #define ThrowOnErrorWithMessage(error, debugStr) _ThrowOnError(error, debugStr, __FILE__, __LINE__) 642 #else 643 #define ThrowOnError(x) _ThrowOnError(x, 0, 0) 644 #define ThrowIfNotSize(x) _ThrowIfNotSize(x, 0, 0) 645 #define ThrowOnErrorWithMessage(error, debugStr) _ThrowOnError(error, debugStr, __FILE__, __LINE__) 646 #endif 647 648 void _ThrowOnError(status_t, const char *, int32); 649 void _ThrowIfNotSize(ssize_t, const char *, int32); 650 void _ThrowOnError(status_t, const char *debugStr, const char *, int32); 651 652 // stub calls that work around BAppFile info inefficiency 653 status_t GetAppSignatureFromAttr(BFile *, char *); 654 status_t GetAppIconFromAttr(BFile *, BBitmap *, icon_size); 655 status_t GetFileIconFromAttr(BNode *, BBitmap *, icon_size); 656 657 658 // debugging 659 void HexDump(const void *buffer, int32 length); 660 661 #if xDEBUG 662 663 inline void 664 PrintRefToStream(const entry_ref *ref, const char *trailer = "\n") 665 { 666 if (!ref) { 667 PRINT(("NULL entry_ref%s", trailer)); 668 return; 669 } 670 BPath path; 671 BEntry entry(ref); 672 entry.GetPath(&path); 673 PRINT(("%s%s", path.Path(), trailer)); 674 } 675 676 inline void 677 PrintEntryToStream(const BEntry *entry, const char *trailer = "\n") 678 { 679 if (!entry) { 680 PRINT(("NULL entry%s", trailer)); 681 return; 682 } 683 BPath path; 684 entry->GetPath(&path); 685 PRINT(("%s%s", path.Path(), trailer)); 686 } 687 688 inline void 689 PrintDirToStream(const BDirectory *dir, const char *trailer = "\n") 690 { 691 if (!dir) { 692 PRINT(("NULL entry_ref%s", trailer)); 693 return; 694 } 695 BPath path; 696 BEntry entry; 697 dir->GetEntry(&entry); 698 entry.GetPath(&path); 699 PRINT(("%s%s", path.Path(), trailer)); 700 } 701 702 #else 703 704 inline void PrintRefToStream(const entry_ref *, const char * = 0) {} 705 inline void PrintEntryToStream(const BEntry *, const char * = 0) {} 706 inline void PrintDirToStream(const BDirectory *, const char * = 0) {} 707 708 #endif 709 710 #ifdef xDEBUG 711 712 extern FILE *logFile; 713 714 inline void PrintToLogFile(const char *fmt, ...) 715 { 716 va_list ap; 717 va_start(ap, fmt); 718 vfprintf(logFile, fmt, ap); 719 va_end(ap); 720 } 721 722 #define WRITELOG(_ARGS_) \ 723 if (logFile == 0) \ 724 logFile = fopen("/var/log/tracker.log", "a+"); \ 725 if (logFile != 0) { \ 726 thread_info info; \ 727 get_thread_info(find_thread(NULL), &info); \ 728 PrintToLogFile("[t %Ld] \"%s\" (%s:%i) ", system_time(), \ 729 info.name, __FILE__, __LINE__); \ 730 PrintToLogFile _ARGS_; \ 731 PrintToLogFile("\n"); \ 732 fflush(logFile); \ 733 } 734 735 #else 736 737 #define WRITELOG(_ARGS_) 738 739 #endif 740 741 // fancy casting macros 742 743 template <typename NewType, typename OldType> 744 inline NewType assert_cast(OldType castedPointer) { 745 ASSERT(dynamic_cast<NewType>(castedPointer) != NULL); 746 return static_cast<NewType>(castedPointer); 747 } 748 749 // B_SWAP_INT32 have broken signedness, simple cover calls to fix that 750 // should fix up in ByteOrder.h 751 752 inline int32 SwapInt32(int32 value) { return (int32)B_SWAP_INT32((uint32)value); } 753 inline uint32 SwapUInt32(uint32 value) { return B_SWAP_INT32(value); } 754 inline int64 SwapInt64(int64 value) { return (int64)B_SWAP_INT64((uint64)value); } 755 inline uint64 SwapUInt64(uint64 value) { return B_SWAP_INT64(value); } 756 757 758 extern const float kExactMatchScore; 759 float ComputeTypeAheadScore(const char *text, const char *match, 760 size_t matchLength, bool wordMode = false); 761 762 } // namespace BPrivate 763 764 #endif // _UTILITIES_H 765