6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
37 #include "StatusView.h"
49 #include <Application.h>
53 #include <ControlLook.h>
55 #include <Directory.h>
56 #include <FindDirectory.h>
60 #include <NodeMonitor.h>
62 #include <PopUpMenu.h>
66 #include <VolumeRoster.h>
72 #include "DeskbarUtils.h"
73 #include "ResourceSet.h"
74 #include "StatusViewShelf.h"
81 // Item - internal item list (node, eref, etc)
82 // Icon - physical replicant handed to the DeskbarClass class
83 // AddOn - attribute based add-on
85 const char* const kInstantiateItemCFunctionName
= "instantiate_deskbar_item";
86 const char* const kInstantiateEntryCFunctionName
= "instantiate_deskbar_entry";
87 const char* const kReplicantSettingsFile
= "replicants";
88 const char* const kReplicantPathField
= "replicant_path";
90 float gMinimumWindowWidth
= kGutter
+ kMinimumTrayWidth
+ kDragRegionWidth
;
91 float gMaximumWindowWidth
= gMinimumWindowWidth
* 2;
95 DumpItem(DeskbarItemInfo
* item
)
97 printf("is addon: %i, id: %" B_PRId32
"\n", item
->isAddOn
, item
->id
);
98 printf("entry_ref: %" B_PRIdDEV
", %" B_PRIdINO
", %s\n",
99 item
->entryRef
.device
, item
->entryRef
.directory
, item
->entryRef
.name
);
100 printf("node_ref: %" B_PRIdDEV
", %" B_PRIdINO
"\n", item
->nodeRef
.device
,
106 DumpList(BList
* itemlist
)
108 int32 count
= itemlist
->CountItems() - 1;
110 printf("no items in list\n");
113 for (int32 i
= count
; i
>= 0; i
--) {
114 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)itemlist
->ItemAt(i
);
121 #endif /* DB_ADDONS */
124 #undef B_TRANSLATION_CONTEXT
125 #define B_TRANSLATION_CONTEXT "Tray"
127 // don't change the name of this view to anything other than "Status"!
129 TReplicantTray::TReplicantTray(TBarView
* parent
, bool vertical
)
131 BView(BRect(0, 0, 1, 1), "Status", B_FOLLOW_LEFT
| B_FOLLOW_TOP
,
132 B_WILL_DRAW
| B_FRAME_EVENTS
),
135 fShelf(new TReplicantShelf(this)),
136 fMultiRowMode(vertical
),
137 fAlignmentSupport(false)
140 fMinimumTrayWidth
= gMinimumWindowWidth
- kGutter
- kDragRegionWidth
;
142 fMinimumTrayWidth
= kMinimumTrayWidth
;
144 // Create the time view
145 fTime
= new TTimeView(fMinimumTrayWidth
, kMaxReplicantHeight
- 1.0);
149 TReplicantTray::~TReplicantTray()
157 TReplicantTray::AttachedToWindow()
159 BView::AttachedToWindow();
161 if (be_control_look
!= NULL
) {
164 SetViewUIColor(B_MENU_BACKGROUND_COLOR
, B_DARKEN_1_TINT
);
166 SetDrawingMode(B_OP_COPY
);
168 Window()->SetPulseRate(1000000);
170 clock_settings
* clock
= ((TBarApp
*)be_app
)->ClockSettings();
171 fTime
->SetShowSeconds(clock
->showSeconds
);
172 fTime
->SetShowDayOfWeek(clock
->showDayOfWeek
);
173 fTime
->SetShowTimeZone(clock
->showTimeZone
);
177 fTime
->MoveTo(Bounds().right
- fTime
->Bounds().Width() - kTrayPadding
, 2);
179 if (!((TBarApp
*)be_app
)->Settings()->showClock
)
183 // load addons and rehydrate archives
184 #if !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST)
193 TReplicantTray::DetachedFromWindow()
196 // clean up add-on support
197 #if !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST)
198 DeleteAddOnSupport();
201 BView::DetachedFromWindow();
205 /*! Width is set to a minimum of kMinimumReplicantCount by kMaxReplicantWidth
206 if not in multirowmode and greater than kMinimumReplicantCount
207 the width should be calculated based on the actual replicant widths
210 TReplicantTray::GetPreferredSize(float* preferredWidth
, float* preferredHeight
)
213 float height
= kMinimumTrayHeight
;
216 width
= static_cast<TBarApp
*>(be_app
)->Settings()->width
217 - kDragWidth
- kGutter
;
218 if (fRightBottomReplicant
.IsValid())
219 height
= fRightBottomReplicant
.bottom
;
220 else if (ReplicantCount() > 0) {
221 // The height will be uniform for the number of rows necessary
222 // to show all the replicants and gutters.
223 int32 rowCount
= (int32
)(height
/ kMaxReplicantHeight
);
224 height
= kGutter
+ (rowCount
* kMaxReplicantHeight
)
225 + ((rowCount
- 1) * kIconGap
) + kGutter
;
226 height
= std::max(kMinimumTrayHeight
, height
);
228 height
= kMinimumTrayHeight
;
230 // if last replicant overruns clock then resize to accomodate
231 if (ReplicantCount() > 0) {
232 if (!fTime
->IsHidden() && Bounds().right
- kTrayPadding
- 2
233 - fTime
->Frame().Width() - kClockMargin
234 < fRightBottomReplicant
.right
+ kClockMargin
) {
235 width
= fRightBottomReplicant
.right
+ kClockMargin
236 + fTime
->Frame().Width() + kTrayPadding
+ 2;
238 width
= fRightBottomReplicant
.right
+ kIconGap
+ kGutter
;
241 // this view has a fixed minimum width
242 width
= std::max(fMinimumTrayWidth
, width
);
243 height
= kGutter
+ static_cast<TBarApp
*>(be_app
)->IconSize() + kGutter
;
246 *preferredWidth
= width
;
247 // add 1 for the border
248 *preferredHeight
= height
+ 1;
253 TReplicantTray::AdjustPlacement()
255 // called when an add-on has been added or removed
256 // need to resize the parent of this accordingly
258 BRect bounds
= Bounds();
260 GetPreferredSize(&width
, &height
);
262 if (width
== bounds
.Width() && height
== bounds
.Height()) {
263 // no need to change anything
267 Parent()->ResizeToPreferred();
268 fBarView
->UpdatePlacement();
269 Parent()->Invalidate();
275 TReplicantTray::MessageReceived(BMessage
* message
)
277 switch (message
->what
) {
278 case B_LOCALE_CHANGED
:
282 fTime
->UpdateTimeFormat();
284 // time string reformat -> realign
285 goto realignReplicants
;
288 // from context menu in clock and in this view
296 fTime
->SetShowSeconds(!fTime
->ShowSeconds());
298 // time string reformat -> realign
299 goto realignReplicants
;
305 fTime
->SetShowDayOfWeek(!fTime
->ShowDayOfWeek());
307 // time string reformat -> realign
308 goto realignReplicants
;
314 fTime
->SetShowTimeZone(!fTime
->ShowTimeZone());
316 // time string reformat -> realign
317 goto realignReplicants
;
319 case kGetClockSettings
:
324 bool showClock
= !fTime
->IsHidden();
325 bool showSeconds
= fTime
->ShowSeconds();
326 bool showDayOfWeek
= fTime
->ShowDayOfWeek();
327 bool showTimeZone
= fTime
->ShowTimeZone();
329 BMessage
reply(kGetClockSettings
);
330 reply
.AddBool("showClock", showClock
);
331 reply
.AddBool("showSeconds", showSeconds
);
332 reply
.AddBool("showDayOfWeek", showDayOfWeek
);
333 reply
.AddBool("showTimeZone", showTimeZone
);
334 message
->SendReply(&reply
);
340 HandleEntryUpdate(message
);
344 case kRealignReplicants
:
351 BView::MessageReceived(message
);
358 TReplicantTray::MouseDown(BPoint where
)
361 if (modifiers() & B_CONTROL_KEY
)
367 Window()->CurrentMessage()->FindInt32("buttons", (int32
*)&buttons
);
368 if (buttons
== B_SECONDARY_MOUSE_BUTTON
) {
369 ShowReplicantMenu(where
);
372 bigtime_t doubleClickSpeed
;
373 bigtime_t start
= system_time();
376 get_click_speed(&doubleClickSpeed
);
379 if (fabs(where
.x
- save
.x
) > 4 || fabs(where
.y
- save
.y
) > 4)
380 // user moved out of bounds of click area
383 if ((system_time() - start
) > (2 * doubleClickSpeed
)) {
384 ShowReplicantMenu(where
);
389 GetMouse(&where
, &buttons
);
392 BView::MouseDown(where
);
397 TReplicantTray::ShowReplicantMenu(BPoint point
)
399 BPopUpMenu
* menu
= new BPopUpMenu("", false, false);
400 menu
->SetFont(be_plain_font
);
402 // If clock is visible show the extended menu, otherwise show "Show clock"
404 if (!fTime
->IsHidden())
405 fTime
->ShowTimeOptions(ConvertToScreen(point
));
407 BMenuItem
* item
= new BMenuItem(B_TRANSLATE("Show clock"),
408 new BMessage(kShowHideTime
));
410 menu
->SetTargetForItems(this);
411 BPoint where
= ConvertToScreen(point
);
412 menu
->Go(where
, true, true, BRect(where
- BPoint(4, 4),
413 where
+ BPoint(4, 4)), true);
419 TReplicantTray::SetMultiRow(bool state
)
421 fMultiRowMode
= state
;
426 TReplicantTray::ShowHideTime()
431 // Check from the point of view of fTime because we need to ignore
432 // whether or not the parent window is hidden.
433 if (fTime
->IsHidden(fTime
))
441 // Check from the point of view of fTime ignoring parent's state.
442 bool showClock
= !fTime
->IsHidden(fTime
);
444 // Update showClock setting that gets saved to disk on quit
445 static_cast<TBarApp
*>(be_app
)->Settings()->showClock
= showClock
;
447 // Send a message to Time preferences telling it to update
448 BMessenger
messenger("application/x-vnd.Haiku-Time");
449 BMessage
message(kShowHideTime
);
450 message
.AddBool("showClock", showClock
);
451 messenger
.SendMessage(&message
);
459 TReplicantTray::InitAddOnSupport()
461 // list to maintain refs to each rep added/deleted
462 fItemList
= new BList();
465 if (GetDeskbarSettingsDirectory(path
, true) == B_OK
) {
466 path
.Append(kReplicantSettingsFile
);
468 BFile
file(path
.Path(), B_READ_ONLY
);
469 if (file
.InitCheck() == B_OK
) {
474 if (fAddOnSettings
.Unflatten(&file
) == B_OK
) {
475 for (int32 i
= 0; fAddOnSettings
.FindString(kReplicantPathField
,
476 i
, &path
) == B_OK
; i
++) {
477 if (entry
.SetTo(path
.String()) == B_OK
&& entry
.Exists()) {
478 result
= LoadAddOn(&entry
, &id
, false);
480 result
= B_ENTRY_NOT_FOUND
;
482 if (result
!= B_OK
) {
483 fAddOnSettings
.RemoveData(kReplicantPathField
, i
);
494 TReplicantTray::DeleteAddOnSupport()
498 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
499 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->RemoveItem(i
);
502 watch_node(&(item
->nodeRef
), B_STOP_WATCHING
, this, Window());
509 // stop the volume mount/unmount watch
510 stop_watching(this, Window());
515 TReplicantTray::DeskbarItemFor(node_ref
& nodeRef
)
517 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
518 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->ItemAt(i
);
522 if (item
->nodeRef
== nodeRef
)
531 TReplicantTray::DeskbarItemFor(int32 id
)
533 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
534 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->ItemAt(i
);
547 TReplicantTray::NodeExists(node_ref
& nodeRef
)
549 return DeskbarItemFor(nodeRef
) != NULL
;
553 /*! This handles B_NODE_MONITOR & B_QUERY_UPDATE messages received
554 for the registered add-ons.
557 TReplicantTray::HandleEntryUpdate(BMessage
* message
)
560 if (message
->FindInt32("opcode", &opcode
) != B_OK
)
571 if (message
->FindString("name", &name
) == B_OK
572 && message
->FindInt64("from directory", &(ref
.directory
))
574 && message
->FindInt64("to directory", &todirectory
) == B_OK
575 && message
->FindInt32("device", &(ref
.device
)) == B_OK
576 && message
->FindInt64("node", &node
) == B_OK
) {
582 // change the directory reference to
584 MoveItem(&ref
, todirectory
);
589 case B_ENTRY_REMOVED
:
591 // entry was rm'd from the device
593 if (message
->FindInt32("device", &(nodeRef
.device
)) == B_OK
594 && message
->FindInt64("node", &(nodeRef
.node
)) == B_OK
) {
595 DeskbarItemInfo
* item
= DeskbarItemFor(nodeRef
);
599 // If there is a team running where the add-on comes from,
600 // we don't want to remove the icon yet.
601 if (be_roster
->IsRunning(&item
->entryRef
))
604 UnloadAddOn(&nodeRef
, NULL
, true, false);
612 /*! The add-ons must support the exported C function API
613 if they do, they will be loaded and added to deskbar
614 primary function is the Instantiate function
617 TReplicantTray::LoadAddOn(BEntry
* entry
, int32
* id
, bool addToSettings
)
623 entry
->GetNodeRef(&nodeRef
);
625 if (NodeExists(nodeRef
))
630 status_t status
= entry
->GetPath(&path
);
635 image_id image
= load_add_on(path
.Path());
639 // get the view loading function symbol
640 // we first look for a symbol that takes an image_id
641 // and entry_ref pointer, if not found, go with normal
642 // instantiate function
643 BView
* (*entryFunction
)(image_id
, const entry_ref
*);
644 BView
* (*itemFunction
)(void);
650 if (get_image_symbol(image
, kInstantiateEntryCFunctionName
,
651 B_SYMBOL_TYPE_TEXT
, (void**)&entryFunction
) >= B_OK
) {
652 view
= (*entryFunction
)(image
, &ref
);
653 } else if (get_image_symbol(image
, kInstantiateItemCFunctionName
,
654 B_SYMBOL_TYPE_TEXT
, (void**)&itemFunction
) >= B_OK
) {
655 view
= (*itemFunction
)();
657 unload_add_on(image
);
661 if (view
== NULL
|| IconExists(view
->Name())) {
663 unload_add_on(image
);
667 BMessage
* data
= new BMessage
;
671 // add the rep; adds info to list
672 if (AddIcon(data
, id
, &ref
) != B_OK
)
676 fAddOnSettings
.AddString(kReplicantPathField
, path
.Path());
685 TReplicantTray::AddItem(int32 id
, node_ref nodeRef
, BEntry
& entry
, bool isAddOn
)
687 DeskbarItemInfo
* item
= new DeskbarItemInfo
;
692 item
->isAddOn
= isAddOn
;
694 if (entry
.GetRef(&item
->entryRef
) != B_OK
) {
695 item
->entryRef
.device
= -1;
696 item
->entryRef
.directory
= -1;
697 item
->entryRef
.name
= NULL
;
699 item
->nodeRef
= nodeRef
;
701 fItemList
->AddItem(item
);
704 watch_node(&nodeRef
, B_WATCH_NAME
| B_WATCH_ATTR
, this, Window());
710 /** from entry_removed message, when attribute removed
711 * or when a device is unmounted (use removeall, by device)
715 TReplicantTray::UnloadAddOn(node_ref
* nodeRef
, dev_t
* device
, bool which
,
718 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
719 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->ItemAt(i
);
723 if ((which
&& nodeRef
!= NULL
&& item
->nodeRef
== *nodeRef
)
724 || (device
!= NULL
&& item
->nodeRef
.device
== *device
)) {
726 if (device
!= NULL
&& be_roster
->IsRunning(&item
->entryRef
))
729 RemoveIcon(item
->id
);
739 TReplicantTray::RemoveItem(int32 id
)
741 DeskbarItemInfo
* item
= DeskbarItemFor(id
);
745 // attribute was added via Deskbar API (AddItem(entry_ref*, int32*)
747 BPath
path(&item
->entryRef
);
750 fAddOnSettings
.FindString(kReplicantPathField
, i
, &storedPath
)
752 if (storedPath
== path
.Path()) {
753 fAddOnSettings
.RemoveData(kReplicantPathField
, i
);
759 BNode
node(&item
->entryRef
);
760 watch_node(&item
->nodeRef
, B_STOP_WATCHING
, this, Window());
763 fItemList
->RemoveItem(item
);
768 /** ENTRY_MOVED message, moving only occurs on a device
769 * copying will occur (ENTRY_CREATED) between devices
773 TReplicantTray::MoveItem(entry_ref
* ref
, ino_t toDirectory
)
778 // scan for a matching entry_ref and update it
780 // don't need to change node info as it does not change
782 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
783 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->ItemAt(i
);
787 if (strcmp(item
->entryRef
.name
, ref
->name
) == 0
788 && item
->entryRef
.device
== ref
->device
789 && item
->entryRef
.directory
== ref
->directory
) {
790 item
->entryRef
.directory
= toDirectory
;
796 #endif // add-on support
798 // external add-on API routines
799 // called using the new BDeskbar class
801 // existence of icon/replicant by name or ID
803 // note: name and id are semi-private limiting
804 // the ability of non-host apps to remove
805 // icons without a little bit of work
807 /** for a specific id
808 * return the name of the replicant (name of view)
812 TReplicantTray::ItemInfo(int32 id
, const char** name
)
819 BView
* view
= ViewAt(&index
, &temp
, id
, false);
821 *name
= view
->Name();
829 /** for a specific name
830 * return the id (internal to Deskbar)
834 TReplicantTray::ItemInfo(const char* name
, int32
* id
)
836 if (name
== NULL
|| *name
== '\0')
840 BView
* view
= ViewAt(&index
, id
, name
);
842 return view
!= NULL
? B_OK
: B_ERROR
;
846 /** at a specific index
847 * return both the name and the id of the replicant
851 TReplicantTray::ItemInfo(int32 index
, const char** name
, int32
* id
)
857 fShelf
->ReplicantAt(index
, &view
, (uint32
*)id
, NULL
);
859 *name
= view
->Name();
867 /** replicant exists, by id/index */
870 TReplicantTray::IconExists(int32 target
, bool byIndex
)
874 BView
* view
= ViewAt(&index
, &id
, target
, byIndex
);
876 return view
&& index
>= 0;
880 /** replicant exists, by name */
883 TReplicantTray::IconExists(const char* name
)
885 if (name
== NULL
|| *name
== '\0')
890 BView
* view
= ViewAt(&index
, &id
, name
);
892 return view
!= NULL
&& index
>= 0;
897 TReplicantTray::ReplicantCount() const
899 return fShelf
->CountReplicants();
903 /*! Message must contain an archivable view for later rehydration.
904 This function takes over ownership of the provided message on success
906 Returns the current replicant ID.
909 TReplicantTray::AddIcon(BMessage
* archive
, int32
* id
, const entry_ref
* addOn
)
911 if (archive
== NULL
|| id
== NULL
)
918 // Use it if we got it
921 const char* signature
;
923 status_t status
= archive
->FindString("add_on", &signature
);
924 if (status
== B_OK
) {
926 status
= roster
.FindApp(signature
, &ref
);
933 status_t status
= file
.SetTo(&ref
, B_READ_ONLY
);
938 status
= file
.GetNodeRef(&nodeRef
);
942 BEntry
entry(&ref
, true);
943 // TODO: this resolves an eventual link for the item being added - this
944 // is okay for now, but in multi-user environments, one might want to
945 // have links that carry the be:deskbar_item_status attribute
946 status
= entry
.InitCheck();
951 if (archive
->what
== B_ARCHIVED_OBJECT
)
954 BRect originalBounds
= archive
->FindRect("_frame");
955 // this is a work-around for buggy replicants that change their size in
956 // AttachedToWindow() (such as "SVM")
958 // TODO: check for name collisions?
959 status
= fShelf
->AddReplicant(archive
, BPoint(1, 1));
963 int32 count
= ReplicantCount();
965 fShelf
->ReplicantAt(count
- 1, &view
, (uint32
*)id
, NULL
);
967 if (view
!= NULL
&& originalBounds
!= view
->Bounds()) {
968 // The replicant changed its size when added to the window, so we need
969 // to recompute all over again (it's already done once via
970 // BShelf::AddReplicant() and TReplicantShelf::CanAcceptReplicantView())
974 float oldWidth
= Bounds().Width();
975 float oldHeight
= Bounds().Height();
977 GetPreferredSize(&width
, &height
);
978 if (oldWidth
!= width
|| oldHeight
!= height
)
981 // add the item to the add-on list
983 AddItem(*id
, nodeRef
, entry
, addOn
!= NULL
);
989 TReplicantTray::RemoveIcon(int32 target
, bool byIndex
)
996 BView
* view
= ViewAt(&index
, &id
, target
, byIndex
);
997 if (view
!= NULL
&& index
>= 0) {
998 // remove the reference from the item list & the shelf
1000 fShelf
->DeleteReplicant(index
);
1002 // force a placement update, !! need to fix BShelf
1003 RealReplicantAdjustment(index
);
1009 TReplicantTray::RemoveIcon(const char* name
)
1011 if (name
== NULL
|| *name
== '\0')
1016 BView
* view
= ViewAt(&index
, &id
, name
);
1017 if (view
!= NULL
&& index
>= 0) {
1018 // remove the reference from the item list & shelf
1020 fShelf
->DeleteReplicant(index
);
1022 // force a placement update, !! need to fix BShelf
1023 RealReplicantAdjustment(index
);
1029 TReplicantTray::RealReplicantAdjustment(int32 startIndex
)
1034 if (startIndex
== fLastReplicant
)
1037 // reset the locations of all replicants after the one deleted
1038 RealignReplicants(startIndex
);
1040 float oldWidth
= Bounds().Width();
1041 float oldHeight
= Bounds().Height();
1042 float width
, height
;
1043 GetPreferredSize(&width
, &height
);
1044 if (oldWidth
!= width
|| oldHeight
!= height
) {
1045 // resize view to accomodate the replicants, redraw as necessary
1051 /** looking for a replicant by id/index
1052 * return the view and index
1056 TReplicantTray::ViewAt(int32
* index
, int32
* id
, int32 target
, bool byIndex
)
1062 if (fShelf
->ReplicantAt(target
, &view
, (uint32
*)id
)) {
1070 int32 count
= ReplicantCount() - 1;
1072 for (int32 repIndex
= count
; repIndex
>= 0; repIndex
--) {
1073 fShelf
->ReplicantAt(repIndex
, &view
, (uint32
*)&localid
);
1074 if (localid
== target
&& view
!= NULL
) {
1087 /** looking for a replicant with a view by name
1088 * return the view, index and the id of the replicant
1092 TReplicantTray::ViewAt(int32
* index
, int32
* id
, const char* name
)
1098 int32 count
= ReplicantCount() - 1;
1099 for (int32 repIndex
= count
; repIndex
>= 0; repIndex
--) {
1100 fShelf
->ReplicantAt(repIndex
, &view
, (uint32
*)id
);
1101 if (view
!= NULL
&& view
->Name() != NULL
1102 && strcmp(name
, view
->Name()) == 0) {
1113 /** Shelf will call to determine where and if
1114 * the replicant is to be added
1118 TReplicantTray::AcceptAddon(BRect replicantFrame
, BMessage
* message
)
1120 if (message
== NULL
)
1123 if (replicantFrame
.Height() > kMaxReplicantHeight
)
1126 alignment align
= B_ALIGN_LEFT
;
1127 if (fAlignmentSupport
&& message
->HasBool("deskbar:dynamic_align")) {
1128 if (!fBarView
->Vertical())
1129 align
= B_ALIGN_RIGHT
;
1131 align
= fBarView
->Left() ? B_ALIGN_LEFT
: B_ALIGN_RIGHT
;
1132 } else if (message
->HasInt32("deskbar:align"))
1133 message
->FindInt32("deskbar:align", (int32
*)&align
);
1135 if (message
->HasInt32("deskbar:private_align"))
1136 message
->FindInt32("deskbar:private_align", (int32
*)&align
);
1138 align
= B_ALIGN_LEFT
;
1140 BPoint loc
= LocationForReplicant(ReplicantCount(),
1141 replicantFrame
.Width());
1142 message
->AddPoint("_pjp_loc", loc
);
1148 /** based on the previous (index - 1) replicant in the list
1149 * calculate where the left point should be for this
1150 * replicant. replicant will flow to the right on its own
1154 TReplicantTray::LocationForReplicant(int32 index
, float replicantWidth
)
1156 BPoint
loc(kTrayPadding
, 2);
1157 if (fBarView
->Vertical()) {
1158 if (!fBarView
->Left())
1159 loc
.x
+= kDragWidth
; // move past dragger
1161 loc
.x
+= 1; // keeps everything lined up nicely
1163 if (fMultiRowMode
) {
1164 // try to find free space in every row
1165 for (int32 row
= 0; ; loc
.y
+= kMaxReplicantHeight
+ kIconGap
, row
++) {
1166 // determine free space in this row
1167 BRect
rowRect(loc
.x
, loc
.y
,
1168 loc
.x
+ static_cast<TBarApp
*>(be_app
)->Settings()->width
1169 - (kTrayPadding
+ kDragWidth
+ kGutter
) * 2,
1170 loc
.y
+ kMaxReplicantHeight
);
1171 if (row
== 0 && !fTime
->IsHidden())
1172 rowRect
.right
-= kClockMargin
+ fTime
->Frame().Width();
1174 BRect replicantRect
= rowRect
;
1175 for (int32 i
= 0; i
< index
; i
++) {
1177 fShelf
->ReplicantAt(i
, &view
);
1178 if (view
== NULL
|| view
->Frame().top
!= rowRect
.top
)
1181 // push this replicant placement past the last one
1182 replicantRect
.left
= view
->Frame().right
+ kIconGap
+ 1;
1185 // calculated left position, add replicantWidth to get right position
1186 replicantRect
.right
= replicantRect
.left
+ replicantWidth
;
1188 // check if replicant fits in this row
1189 if (replicantRect
.right
< rowRect
.right
) {
1190 // replicant fits in this row
1191 loc
= replicantRect
.LeftTop();
1197 } else if (index
> 0) {
1198 // get the last replicant added for placement reference
1200 fShelf
->ReplicantAt(index
- 1, &view
);
1202 // push this replicant placement past the last one
1203 loc
.x
= view
->Frame().right
+ kIconGap
+ 1;
1204 loc
.y
= view
->Frame().top
;
1208 if (loc
.y
> fRightBottomReplicant
.top
1209 || (loc
.y
== fRightBottomReplicant
.top
1210 && loc
.x
> fRightBottomReplicant
.left
)) {
1211 fRightBottomReplicant
.Set(loc
.x
, loc
.y
, loc
.x
+ replicantWidth
,
1212 loc
.y
+ kMaxReplicantHeight
);
1213 fLastReplicant
= index
;
1221 TReplicantTray::IconFrame(int32 target
, bool byIndex
)
1225 BView
* view
= ViewAt(&index
, &id
, target
, byIndex
);
1227 return view
!= NULL
? view
->Frame() : BRect(0, 0, 0, 0);
1232 TReplicantTray::IconFrame(const char* name
)
1235 return BRect(0, 0, 0, 0);
1239 BView
* view
= ViewAt(&index
, &id
, name
);
1241 return view
!= NULL
? view
->Frame() : BRect(0, 0, 0, 0);
1245 /** Scan from the startIndex and reset the location
1246 * as defined in LocationForReplicant()
1250 TReplicantTray::RealignReplicants(int32 startIndex
)
1255 int32 replicantCount
= ReplicantCount();
1256 if (replicantCount
<= 0)
1259 if (startIndex
== 0)
1260 fRightBottomReplicant
.Set(0, 0, 0, 0);
1263 for (int32 index
= startIndex
; index
< replicantCount
; index
++) {
1264 fShelf
->ReplicantAt(index
, &view
);
1268 float replicantWidth
= view
->Frame().Width();
1269 BPoint loc
= LocationForReplicant(index
, replicantWidth
);
1270 if (view
->Frame().LeftTop() != loc
)
1277 TReplicantTray::_SaveSettings()
1281 if ((result
= GetDeskbarSettingsDirectory(path
, true)) == B_OK
) {
1282 path
.Append(kReplicantSettingsFile
);
1284 BFile
file(path
.Path(), B_READ_WRITE
| B_CREATE_FILE
| B_ERASE_FILE
);
1285 if ((result
= file
.InitCheck()) == B_OK
)
1286 result
= fAddOnSettings
.Flatten(&file
);
1294 TReplicantTray::SaveTimeSettings()
1299 clock_settings
* settings
= ((TBarApp
*)be_app
)->ClockSettings();
1300 settings
->showSeconds
= fTime
->ShowSeconds();
1301 settings
->showDayOfWeek
= fTime
->ShowDayOfWeek();
1302 settings
->showTimeZone
= fTime
->ShowTimeZone();
1306 // #pragma mark - TDragRegion
1309 /*! Draggable region that is asynchronous so that dragging does not block
1312 TDragRegion::TDragRegion(TBarView
* parent
, BView
* replicantTray
)
1314 BControl(BRect(0, 0, 0, 0), "", "", NULL
, B_FOLLOW_NONE
,
1315 B_WILL_DRAW
| B_FRAME_EVENTS
),
1317 fReplicantTray(replicantTray
),
1318 fDragLocation(kAutoPlaceDragRegion
)
1324 TDragRegion::AttachedToWindow()
1326 BView::AttachedToWindow();
1328 if (be_control_look
!= NULL
)
1329 SetViewUIColor(B_MENU_BACKGROUND_COLOR
, 1.1);
1331 SetViewUIColor(B_MENU_BACKGROUND_COLOR
);
1333 ResizeToPreferred();
1338 TDragRegion::GetPreferredSize(float* width
, float* height
)
1340 fReplicantTray
->ResizeToPreferred();
1341 *width
= fReplicantTray
->Bounds().Width();
1342 *height
= fReplicantTray
->Bounds().Height();
1344 if (fDragLocation
!= kNoDragRegion
)
1345 *width
+= kDragWidth
+ kGutter
;
1354 TDragRegion::Draw(BRect updateRect
)
1356 rgb_color menuColor
= ViewColor();
1357 rgb_color hilite
= tint_color(menuColor
, B_DARKEN_1_TINT
);
1358 rgb_color ldark
= tint_color(menuColor
, 1.02);
1359 rgb_color dark
= tint_color(menuColor
, B_DARKEN_2_TINT
);
1360 rgb_color vvdark
= tint_color(menuColor
, B_DARKEN_4_TINT
);
1361 rgb_color light
= tint_color(menuColor
, B_LIGHTEN_2_TINT
);
1363 BRect
frame(Bounds());
1366 if (be_control_look
!= NULL
) {
1367 if (fBarView
->Vertical()) {
1368 AddLine(frame
.LeftTop(), frame
.RightTop(), dark
);
1369 AddLine(BPoint(frame
.left
, frame
.top
+ 1),
1370 BPoint(frame
.right
, frame
.top
+ 1), ldark
);
1371 AddLine(frame
.LeftBottom(), frame
.RightBottom(), hilite
);
1372 } else if (fBarView
->AcrossTop() || fBarView
->AcrossBottom()) {
1373 AddLine(frame
.LeftTop(),
1374 BPoint(frame
.left
, frame
.bottom
), dark
);
1375 AddLine(BPoint(frame
.left
+ 1, frame
.top
+ 1),
1376 BPoint(frame
.right
- 1, frame
.top
+ 1), light
);
1377 AddLine(BPoint(frame
.right
, frame
.top
+ 2),
1378 BPoint(frame
.right
, frame
.bottom
), hilite
);
1379 AddLine(BPoint(frame
.left
+ 1, frame
.bottom
),
1380 BPoint(frame
.right
- 1, frame
.bottom
), hilite
);
1383 if (fBarView
->Vertical()) {
1384 AddLine(frame
.LeftTop(), frame
.RightTop(), light
);
1385 AddLine(frame
.LeftTop(), frame
.LeftBottom(), light
);
1386 AddLine(frame
.RightBottom(), frame
.RightTop(), hilite
);
1387 } else if (fBarView
->AcrossTop()) {
1388 AddLine(BPoint(frame
.left
, frame
.top
+ 1),
1389 BPoint(frame
.right
- 1, frame
.top
+ 1), light
);
1390 AddLine(frame
.RightTop(), frame
.RightBottom(), vvdark
);
1391 AddLine(BPoint(frame
.right
- 1, frame
.top
+ 2),
1392 BPoint(frame
.right
- 1, frame
.bottom
- 1), hilite
);
1393 AddLine(frame
.LeftBottom(),
1394 BPoint(frame
.right
- 1, frame
.bottom
), hilite
);
1395 } else if (fBarView
->AcrossBottom()) {
1396 AddLine(BPoint(frame
.left
, frame
.top
+ 1),
1397 BPoint(frame
.right
- 1, frame
.top
+ 1), light
);
1398 AddLine(frame
.LeftBottom(), frame
.RightBottom(), hilite
);
1399 AddLine(frame
.RightTop(), frame
.RightBottom(), vvdark
);
1400 AddLine(BPoint(frame
.right
- 1, frame
.top
+ 1),
1401 BPoint(frame
.right
- 1, frame
.bottom
- 1), hilite
);
1407 if (fDragLocation
!= kDontDrawDragRegion
|| fDragLocation
!= kNoDragRegion
)
1413 TDragRegion::DrawDragRegion()
1415 BRect
dragRegion(DragRegion());
1417 rgb_color menuColor
= ViewColor();
1418 rgb_color menuHilite
= menuColor
;
1420 // draw drag region highlighted if tracking mouse
1421 menuHilite
= tint_color(menuColor
, B_HIGHLIGHT_BACKGROUND_TINT
);
1422 SetHighColor(menuHilite
);
1423 FillRect(dragRegion
);
1425 SetHighColor(menuColor
);
1426 FillRect(dragRegion
);
1429 rgb_color vdark
= tint_color(menuHilite
, B_DARKEN_3_TINT
);
1430 rgb_color light
= tint_color(menuHilite
, B_LIGHTEN_2_TINT
);
1432 BeginLineArray(dragRegion
.IntegerHeight());
1434 where
.x
= floorf((dragRegion
.left
+ dragRegion
.right
) / 2 + 0.5) - 1;
1435 where
.y
= dragRegion
.top
+ 2;
1437 while (where
.y
+ 1 <= dragRegion
.bottom
) {
1438 AddLine(where
, where
, vdark
);
1439 AddLine(where
+ BPoint(1, 1), where
+ BPoint(1, 1), light
);
1448 TDragRegion::DragRegion() const
1450 float kTopBottomInset
= 2;
1451 float kLeftRightInset
= 1;
1452 if (be_control_look
!= NULL
) {
1453 kTopBottomInset
= 1;
1454 kLeftRightInset
= 0;
1457 BRect
dragRegion(Bounds());
1458 dragRegion
.top
+= kTopBottomInset
;
1459 dragRegion
.bottom
-= kTopBottomInset
;
1461 bool placeOnLeft
= false;
1462 if (fDragLocation
== kAutoPlaceDragRegion
) {
1463 if (fBarView
->Vertical() && fBarView
->Left())
1466 placeOnLeft
= false;
1468 placeOnLeft
= fDragLocation
== kDragRegionLeft
;
1471 dragRegion
.left
+= kLeftRightInset
;
1472 dragRegion
.right
= dragRegion
.left
+ kDragWidth
;
1474 dragRegion
.right
+= kLeftRightInset
;
1475 dragRegion
.left
= dragRegion
.right
- kDragWidth
;
1483 TDragRegion::MouseDown(BPoint where
)
1488 BRect
dragRegion(DragRegion());
1489 dragRegion
.InsetBy(-2, -2);
1490 // DragRegion() is designed for drawing, not clicking
1492 if (!dragRegion
.Contains(where
))
1496 GetMouse(&mouseLoc
, &buttons
);
1500 if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS
) != 0) {
1501 fPreviousPosition
= where
;
1503 SetMouseEventMask(B_POINTER_EVENTS
,
1504 B_NO_POINTER_HISTORY
| B_LOCK_WINDOW_FOCUS
);
1505 Invalidate(DragRegion());
1515 TDragRegion::MouseUp(BPoint where
)
1519 Invalidate(DragRegion());
1521 BControl::MouseUp(where
);
1526 TDragRegion::SwitchModeForRect(BPoint where
, BRect rect
,
1527 bool newVertical
, bool newLeft
, bool newTop
, int32 newState
)
1529 if (!rect
.Contains(where
)) {
1534 if (newVertical
== fBarView
->Vertical() && newLeft
== fBarView
->Left()
1535 && newTop
== fBarView
->Top() && newState
== fBarView
->State()) {
1536 // already in the correct mode
1540 fBarView
->ChangeState(newState
, newVertical
, newLeft
, newTop
, true);
1547 TDragRegion::MouseMoved(BPoint where
, uint32 code
, const BMessage
* message
)
1551 BRect frame
= screen
.Frame();
1553 float hDivider
= frame
.Width() / 6;
1554 hDivider
= (hDivider
< gMinimumWindowWidth
+ 10)
1555 ? gMinimumWindowWidth
+ 10 : hDivider
;
1556 float miniDivider
= frame
.top
+ kMiniHeight
+ 10;
1557 float vDivider
= frame
.Height() / 2;
1559 float thirdScreen
= frame
.Height() / 3;
1561 BRect
topLeft(frame
.left
, frame
.top
, frame
.left
+ hDivider
,
1563 BRect
topMiddle(frame
.left
+ hDivider
, frame
.top
, frame
.right
1564 - hDivider
, vDivider
);
1565 BRect
topRight(frame
.right
- hDivider
, frame
.top
, frame
.right
,
1569 vDivider
= miniDivider
+ thirdScreen
;
1571 BRect
middleLeft(frame
.left
, miniDivider
, frame
.left
+ hDivider
,
1573 BRect
middleRight(frame
.right
- hDivider
, miniDivider
, frame
.right
,
1577 BRect
leftSide(frame
.left
, vDivider
, frame
.left
+ hDivider
,
1578 frame
.bottom
- thirdScreen
);
1579 BRect
rightSide(frame
.right
- hDivider
, vDivider
, frame
.right
,
1580 frame
.bottom
- thirdScreen
);
1582 vDivider
= frame
.bottom
- thirdScreen
;
1584 BRect
bottomLeft(frame
.left
, vDivider
, frame
.left
+ hDivider
,
1586 BRect
bottomMiddle(frame
.left
+ hDivider
, vDivider
, frame
.right
1587 - hDivider
, frame
.bottom
);
1588 BRect
bottomRight(frame
.right
- hDivider
, vDivider
, frame
.right
,
1591 if (where
!= fPreviousPosition
) {
1592 fPreviousPosition
= where
;
1593 ConvertToScreen(&where
);
1595 // use short circuit evaluation for convenience
1596 if (SwitchModeForRect(where
, topLeft
, true, true, true, kMiniState
)
1597 || SwitchModeForRect(where
, topMiddle
, false, true, true,
1599 || SwitchModeForRect(where
, topRight
, true, false, true,
1601 || SwitchModeForRect(where
, middleLeft
, true, true, true,
1603 || SwitchModeForRect(where
, middleRight
, true, false, true,
1607 || SwitchModeForRect(where
, leftSide
, true, true, true,
1609 || SwitchModeForRect(where
, rightSide
, true, false, true,
1612 || SwitchModeForRect(where
, bottomLeft
, true, true, false,
1614 || SwitchModeForRect(where
, bottomMiddle
, false, true, false,
1616 || SwitchModeForRect(where
, bottomRight
, true, false, false,
1621 BControl::MouseMoved(where
, code
, message
);
1626 TDragRegion::DragRegionLocation() const
1628 return fDragLocation
;
1633 TDragRegion::SetDragRegionLocation(int32 location
)
1635 if (location
== fDragLocation
)
1638 fDragLocation
= location
;
1643 // #pragma mark - TResizeControl
1646 /*! Draggable region that is asynchronous so that resizing does not block.
1648 TResizeControl::TResizeControl(TBarView
* barView
)
1650 BControl(BRect(0, kDragWidth
, 0, kMenuBarHeight
), "", "", NULL
,
1651 B_FOLLOW_NONE
, B_WILL_DRAW
| B_FRAME_EVENTS
),
1657 TResizeControl::~TResizeControl()
1663 TResizeControl::AttachedToWindow()
1665 BView::AttachedToWindow();
1667 if (be_control_look
!= NULL
)
1668 SetViewUIColor(B_MENU_BACKGROUND_COLOR
, 1.1);
1670 SetViewUIColor(B_MENU_BACKGROUND_COLOR
);
1675 TResizeControl::Draw(BRect updateRect
)
1677 if (!fBarView
->Vertical())
1680 BRect
dragRegion(Bounds());
1682 int32 height
= dragRegion
.IntegerHeight();
1686 rgb_color menuColor
= ViewColor();
1687 rgb_color menuHilite
= menuColor
;
1689 // draw drag region highlighted if tracking mouse
1690 menuHilite
= tint_color(menuColor
, B_HIGHLIGHT_BACKGROUND_TINT
);
1691 SetHighColor(menuHilite
);
1692 FillRect(dragRegion
);
1694 SetHighColor(menuColor
);
1695 FillRect(dragRegion
);
1698 rgb_color vdark
= tint_color(menuHilite
, B_DARKEN_3_TINT
);
1699 rgb_color light
= tint_color(menuHilite
, B_LIGHTEN_2_TINT
);
1701 BeginLineArray(height
);
1703 where
.x
= floorf((dragRegion
.left
+ dragRegion
.right
) / 2 + 0.5) - 1;
1704 where
.y
= dragRegion
.top
+ 2;
1706 while (where
.y
+ 1 <= dragRegion
.bottom
) {
1707 AddLine(where
, where
, vdark
);
1708 AddLine(where
+ BPoint(1, 1), where
+ BPoint(1, 1), light
);
1717 TResizeControl::MouseDown(BPoint where
)
1723 GetMouse(&mouseLoc
, &buttons
);
1727 if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS
) != 0) {
1729 SetMouseEventMask(B_POINTER_EVENTS
,
1730 B_NO_POINTER_HISTORY
| B_LOCK_WINDOW_FOCUS
);
1741 TResizeControl::MouseUp(BPoint where
)
1747 BControl::MouseUp(where
);
1752 TResizeControl::MouseMoved(BPoint where
, uint32 code
,
1753 const BMessage
* dragMessage
)
1755 if (fBarView
->Vertical()) {
1757 float windowWidth
= Window()->Frame().Width();
1759 BPoint whereScreen
= ConvertToScreen(where
);
1761 if (fBarView
->Left()) {
1762 delta
= whereScreen
.x
- Window()->Frame().right
;
1763 if (delta
> 0 && windowWidth
>= gMaximumWindowWidth
)
1765 else if (delta
< 0 && windowWidth
<= gMinimumWindowWidth
)
1768 Window()->ResizeBy(delta
, 0);
1770 delta
= Window()->Frame().left
- whereScreen
.x
;
1771 if (delta
> 0 && windowWidth
>= gMaximumWindowWidth
)
1773 else if (delta
< 0 && windowWidth
<= gMinimumWindowWidth
)
1776 Window()->MoveBy(delta
, 0);
1777 Window()->ResizeBy(delta
, 0);
1781 windowWidth
= Window()->Frame().Width();
1785 BControl::MouseMoved(where
, code
, dragMessage
);