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"
83 // Item - internal item list (node, eref, etc)
84 // Icon - physical replicant handed to the DeskbarClass class
85 // AddOn - attribute based add-on
87 const char* const kInstantiateItemCFunctionName
= "instantiate_deskbar_item";
88 const char* const kInstantiateEntryCFunctionName
= "instantiate_deskbar_entry";
89 const char* const kReplicantSettingsFile
= "replicants";
90 const char* const kReplicantPathField
= "replicant_path";
92 float gMinimumWindowWidth
= kGutter
+ kMinimumTrayWidth
+ kDragRegionWidth
;
96 DumpItem(DeskbarItemInfo
* item
)
98 printf("is addon: %i, id: %" B_PRId32
"\n", item
->isAddOn
, item
->id
);
99 printf("entry_ref: %" B_PRIdDEV
", %" B_PRIdINO
", %s\n",
100 item
->entryRef
.device
, item
->entryRef
.directory
, item
->entryRef
.name
);
101 printf("node_ref: %" B_PRIdDEV
", %" B_PRIdINO
"\n", item
->nodeRef
.device
,
107 DumpList(BList
* itemlist
)
109 int32 count
= itemlist
->CountItems() - 1;
111 printf("no items in list\n");
114 for (int32 i
= count
; i
>= 0; i
--) {
115 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)itemlist
->ItemAt(i
);
122 #endif /* DB_ADDONS */
125 #undef B_TRANSLATION_CONTEXT
126 #define B_TRANSLATION_CONTEXT "Tray"
128 // don't change the name of this view to anything other than "Status"!
130 TReplicantTray::TReplicantTray(TBarView
* parent
, bool vertical
)
132 BView(BRect(0, 0, 1, 1), "Status", B_FOLLOW_LEFT
| B_FOLLOW_TOP
,
133 B_WILL_DRAW
| B_FRAME_EVENTS
),
136 fShelf(new TReplicantShelf(this)),
137 fMultiRowMode(vertical
),
138 fMinimumTrayWidth(kMinimumTrayWidth
),
139 fAlignmentSupport(false)
141 // init the minimum window width according to the logo.
142 const BBitmap
* logoBitmap
= AppResSet()->FindBitmap(B_MESSAGE_TYPE
,
144 if (logoBitmap
!= NULL
) {
145 gMinimumWindowWidth
= std::max(gMinimumWindowWidth
,
146 2 * (logoBitmap
->Bounds().Width() + 8));
147 fMinimumTrayWidth
= gMinimumWindowWidth
- kGutter
- kDragRegionWidth
;
150 // Create the time view
151 fTime
= new TTimeView(fMinimumTrayWidth
, kMaxReplicantHeight
- 1.0);
155 TReplicantTray::~TReplicantTray()
163 TReplicantTray::AttachedToWindow()
165 BView::AttachedToWindow();
167 if (be_control_look
!= NULL
) {
168 SetViewColor(Parent()->ViewColor());
170 SetViewColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR
),
173 SetDrawingMode(B_OP_COPY
);
175 Window()->SetPulseRate(1000000);
177 clock_settings
* clock
= ((TBarApp
*)be_app
)->ClockSettings();
178 fTime
->SetShowSeconds(clock
->showSeconds
);
179 fTime
->SetShowDayOfWeek(clock
->showDayOfWeek
);
180 fTime
->SetShowTimeZone(clock
->showTimeZone
);
183 fTime
->MoveTo(Bounds().right
- fTime
->Bounds().Width() - 1, 2);
185 if (!((TBarApp
*)be_app
)->Settings()->showClock
)
189 // load addons and rehydrate archives
190 #if !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST)
199 TReplicantTray::DetachedFromWindow()
202 // clean up add-on support
203 #if !defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST)
204 DeleteAddOnSupport();
207 BView::DetachedFromWindow();
211 /*! Width is set to a minimum of kMinimumReplicantCount by kMaxReplicantWidth
212 if not in multirowmode and greater than kMinimumReplicantCount
213 the width should be calculated based on the actual replicant widths
216 TReplicantTray::GetPreferredSize(float* preferredWidth
, float* preferredHeight
)
218 float width
= 0, height
= kMinimumTrayHeight
;
221 if (fShelf
->CountReplicants() > 0)
222 height
= fRightBottomReplicant
.bottom
;
224 // the height will be uniform for the number of rows necessary to show
225 // all the reps + any gutters necessary for spacing
226 int32 rowCount
= (int32
)(height
/ kMaxReplicantHeight
);
227 height
= kGutter
+ (rowCount
* kMaxReplicantHeight
)
228 + ((rowCount
- 1) * kIconGap
) + kGutter
;
229 height
= max(kMinimumTrayHeight
, height
);
230 width
= fMinimumTrayWidth
;
232 // if last replicant overruns clock then resize to accomodate
233 if (fShelf
->CountReplicants() > 0) {
234 if (!fTime
->IsHidden() && fTime
->Frame().left
235 < fRightBottomReplicant
.right
+ 6) {
236 width
= fRightBottomReplicant
.right
+ 6
237 + fTime
->Frame().Width();
239 width
= fRightBottomReplicant
.right
+ 3;
242 // this view has a fixed minimum width
243 width
= max(fMinimumTrayWidth
, width
);
244 height
= kGutter
+ static_cast<TBarApp
*>(be_app
)->IconSize() + kGutter
;
247 *preferredWidth
= width
;
248 // add 1 for the border
249 *preferredHeight
= height
+ 1;
254 TReplicantTray::AdjustPlacement()
256 // called when an add-on has been added or removed
257 // need to resize the parent of this accordingly
259 BRect bounds
= Bounds();
261 GetPreferredSize(&width
, &height
);
263 if (width
== bounds
.Width() && height
== bounds
.Height()) {
264 // no need to change anything
268 Parent()->ResizeToPreferred();
269 fBarView
->UpdatePlacement();
270 Parent()->Invalidate();
276 TReplicantTray::MessageReceived(BMessage
* message
)
278 switch (message
->what
) {
279 case B_LOCALE_CHANGED
:
286 // time string reformat -> realign
293 // from context menu in clock and in this view
301 fTime
->SetShowSeconds(!fTime
->ShowSeconds());
303 // time string reformat -> realign
312 fTime
->SetShowDayOfWeek(!fTime
->ShowDayOfWeek());
314 // time string reformat -> realign
323 fTime
->SetShowTimeZone(!fTime
->ShowTimeZone());
325 // time string reformat -> realign
330 case kGetClockSettings
:
335 bool showClock
= !fTime
->IsHidden();
336 bool showSeconds
= fTime
->ShowSeconds();
337 bool showDayOfWeek
= fTime
->ShowDayOfWeek();
338 bool showTimeZone
= fTime
->ShowTimeZone();
340 BMessage
reply(kGetClockSettings
);
341 reply
.AddBool("showClock", showClock
);
342 reply
.AddBool("showSeconds", showSeconds
);
343 reply
.AddBool("showDayOfWeek", showDayOfWeek
);
344 reply
.AddBool("showTimeZone", showTimeZone
);
345 message
->SendReply(&reply
);
351 HandleEntryUpdate(message
);
356 BView::MessageReceived(message
);
363 TReplicantTray::MouseDown(BPoint where
)
366 if (modifiers() & B_CONTROL_KEY
)
372 Window()->CurrentMessage()->FindInt32("buttons", (int32
*)&buttons
);
373 if (buttons
== B_SECONDARY_MOUSE_BUTTON
) {
374 ShowReplicantMenu(where
);
377 bigtime_t doubleClickSpeed
;
378 bigtime_t start
= system_time();
381 get_click_speed(&doubleClickSpeed
);
384 if (fabs(where
.x
- save
.x
) > 4 || fabs(where
.y
- save
.y
) > 4)
385 // user moved out of bounds of click area
388 if ((system_time() - start
) > (2 * doubleClickSpeed
)) {
389 ShowReplicantMenu(where
);
394 GetMouse(&where
, &buttons
);
397 BView::MouseDown(where
);
402 TReplicantTray::ShowReplicantMenu(BPoint point
)
404 BPopUpMenu
* menu
= new BPopUpMenu("", false, false);
405 menu
->SetFont(be_plain_font
);
407 // If clock is visible show the extended menu, otherwise show "Show clock"
409 if (!fTime
->IsHidden())
410 fTime
->ShowTimeOptions(ConvertToScreen(point
));
412 BMenuItem
* item
= new BMenuItem(B_TRANSLATE("Show clock"),
413 new BMessage(kShowHideTime
));
415 menu
->SetTargetForItems(this);
416 BPoint where
= ConvertToScreen(point
);
417 menu
->Go(where
, true, true, BRect(where
- BPoint(4, 4),
418 where
+ BPoint(4, 4)), true);
424 TReplicantTray::SetMultiRow(bool state
)
426 fMultiRowMode
= state
;
431 TReplicantTray::ShowHideTime()
436 // Check from the point of view of fTime because we need to ignore
437 // whether or not the parent window is hidden.
438 if (fTime
->IsHidden(fTime
))
446 // Check from the point of view of fTime ignoring parent's state.
447 bool showClock
= !fTime
->IsHidden(fTime
);
449 // Update showClock setting that gets saved to disk on quit
450 ((TBarApp
*)be_app
)->Settings()->showClock
= showClock
;
452 // Send a message to Time preferences telling it to update
453 BMessenger
messenger("application/x-vnd.Haiku-Time");
454 BMessage
message(kShowHideTime
);
455 message
.AddBool("showClock", showClock
);
456 messenger
.SendMessage(&message
);
464 TReplicantTray::InitAddOnSupport()
466 // list to maintain refs to each rep added/deleted
467 fItemList
= new BList();
470 if (GetDeskbarSettingsDirectory(path
, true) == B_OK
) {
471 path
.Append(kReplicantSettingsFile
);
473 BFile
file(path
.Path(), B_READ_ONLY
);
474 if (file
.InitCheck() == B_OK
) {
479 if (fAddOnSettings
.Unflatten(&file
) == B_OK
) {
480 for (int32 i
= 0; fAddOnSettings
.FindString(kReplicantPathField
,
481 i
, &path
) == B_OK
; i
++) {
482 if (entry
.SetTo(path
.String()) == B_OK
&& entry
.Exists()) {
483 result
= LoadAddOn(&entry
, &id
, false);
485 result
= B_ENTRY_NOT_FOUND
;
487 if (result
!= B_OK
) {
488 fAddOnSettings
.RemoveData(kReplicantPathField
, i
);
499 TReplicantTray::DeleteAddOnSupport()
503 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
504 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->RemoveItem(i
);
507 watch_node(&(item
->nodeRef
), B_STOP_WATCHING
, this, Window());
514 // stop the volume mount/unmount watch
515 stop_watching(this, Window());
520 TReplicantTray::DeskbarItemFor(node_ref
& nodeRef
)
522 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
523 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->ItemAt(i
);
527 if (item
->nodeRef
== nodeRef
)
536 TReplicantTray::DeskbarItemFor(int32 id
)
538 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
539 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->ItemAt(i
);
552 TReplicantTray::NodeExists(node_ref
& nodeRef
)
554 return DeskbarItemFor(nodeRef
) != NULL
;
558 /*! This handles B_NODE_MONITOR & B_QUERY_UPDATE messages received
559 for the registered add-ons.
562 TReplicantTray::HandleEntryUpdate(BMessage
* message
)
565 if (message
->FindInt32("opcode", &opcode
) != B_OK
)
576 if (message
->FindString("name", &name
) == B_OK
577 && message
->FindInt64("from directory", &(ref
.directory
))
579 && message
->FindInt64("to directory", &todirectory
) == B_OK
580 && message
->FindInt32("device", &(ref
.device
)) == B_OK
581 && message
->FindInt64("node", &node
) == B_OK
) {
587 // change the directory reference to
589 MoveItem(&ref
, todirectory
);
594 case B_ENTRY_REMOVED
:
596 // entry was rm'd from the device
598 if (message
->FindInt32("device", &(nodeRef
.device
)) == B_OK
599 && message
->FindInt64("node", &(nodeRef
.node
)) == B_OK
) {
600 DeskbarItemInfo
* item
= DeskbarItemFor(nodeRef
);
604 // If there is a team running where the add-on comes from,
605 // we don't want to remove the icon yet.
606 if (be_roster
->IsRunning(&item
->entryRef
))
609 UnloadAddOn(&nodeRef
, NULL
, true, false);
617 /*! The add-ons must support the exported C function API
618 if they do, they will be loaded and added to deskbar
619 primary function is the Instantiate function
622 TReplicantTray::LoadAddOn(BEntry
* entry
, int32
* id
, bool addToSettings
)
628 entry
->GetNodeRef(&nodeRef
);
630 if (NodeExists(nodeRef
))
635 status_t status
= entry
->GetPath(&path
);
640 image_id image
= load_add_on(path
.Path());
644 // get the view loading function symbol
645 // we first look for a symbol that takes an image_id
646 // and entry_ref pointer, if not found, go with normal
647 // instantiate function
648 BView
* (*entryFunction
)(image_id
, const entry_ref
*);
649 BView
* (*itemFunction
)(void);
655 if (get_image_symbol(image
, kInstantiateEntryCFunctionName
,
656 B_SYMBOL_TYPE_TEXT
, (void**)&entryFunction
) >= B_OK
) {
657 view
= (*entryFunction
)(image
, &ref
);
658 } else if (get_image_symbol(image
, kInstantiateItemCFunctionName
,
659 B_SYMBOL_TYPE_TEXT
, (void**)&itemFunction
) >= B_OK
) {
660 view
= (*itemFunction
)();
662 unload_add_on(image
);
666 if (view
== NULL
|| IconExists(view
->Name())) {
668 unload_add_on(image
);
672 BMessage
* data
= new BMessage
;
676 // add the rep; adds info to list
677 if (AddIcon(data
, id
, &ref
) != B_OK
)
681 fAddOnSettings
.AddString(kReplicantPathField
, path
.Path());
690 TReplicantTray::AddItem(int32 id
, node_ref nodeRef
, BEntry
& entry
, bool isAddOn
)
692 DeskbarItemInfo
* item
= new DeskbarItemInfo
;
697 item
->isAddOn
= isAddOn
;
699 if (entry
.GetRef(&item
->entryRef
) < B_OK
) {
700 item
->entryRef
.device
= -1;
701 item
->entryRef
.directory
= -1;
702 item
->entryRef
.name
= NULL
;
704 item
->nodeRef
= nodeRef
;
706 fItemList
->AddItem(item
);
709 watch_node(&nodeRef
, B_WATCH_NAME
| B_WATCH_ATTR
, this, Window());
715 /** from entry_removed message, when attribute removed
716 * or when a device is unmounted (use removeall, by device)
720 TReplicantTray::UnloadAddOn(node_ref
* nodeRef
, dev_t
* device
,
721 bool which
, bool removeAll
)
723 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
724 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->ItemAt(i
);
728 if ((which
&& nodeRef
&& item
->nodeRef
== *nodeRef
)
729 || (device
&& item
->nodeRef
.device
== *device
)) {
731 if (device
&& be_roster
->IsRunning(&item
->entryRef
))
734 RemoveIcon(item
->id
);
744 TReplicantTray::RemoveItem(int32 id
)
746 DeskbarItemInfo
* item
= DeskbarItemFor(id
);
750 // attribute was added via Deskbar API (AddItem(entry_ref*, int32*)
752 BPath
path(&item
->entryRef
);
755 fAddOnSettings
.FindString(kReplicantPathField
, i
, &storedPath
)
757 if (storedPath
== path
.Path()) {
758 fAddOnSettings
.RemoveData(kReplicantPathField
, i
);
764 BNode
node(&item
->entryRef
);
765 watch_node(&item
->nodeRef
, B_STOP_WATCHING
, this, Window());
768 fItemList
->RemoveItem(item
);
773 /** ENTRY_MOVED message, moving only occurs on a device
774 * copying will occur (ENTRY_CREATED) between devices
778 TReplicantTray::MoveItem(entry_ref
* ref
, ino_t toDirectory
)
783 // scan for a matching entry_ref and update it
785 // don't need to change node info as it does not change
787 for (int32 i
= fItemList
->CountItems() - 1; i
>= 0; i
--) {
788 DeskbarItemInfo
* item
= (DeskbarItemInfo
*)fItemList
->ItemAt(i
);
792 if (!strcmp(item
->entryRef
.name
, ref
->name
)
793 && item
->entryRef
.device
== ref
->device
794 && item
->entryRef
.directory
== ref
->directory
) {
795 item
->entryRef
.directory
= toDirectory
;
801 #endif // add-on support
803 // external add-on API routines
804 // called using the new BDeskbar class
806 // existence of icon/replicant by name or ID
808 // note: name and id are semi-private limiting
809 // the ability of non-host apps to remove
810 // icons without a little bit of work
812 /** for a specific id
813 * return the name of the replicant (name of view)
817 TReplicantTray::ItemInfo(int32 id
, const char** name
)
823 BView
* view
= ViewAt(&index
, &temp
, id
, false);
825 *name
= view
->Name();
833 /** for a specific name
834 * return the id (internal to Deskbar)
838 TReplicantTray::ItemInfo(const char* name
, int32
* id
)
840 if (!name
|| strlen(name
) <= 0)
844 BView
* view
= ViewAt(&index
, id
, name
);
852 /** at a specific index
853 * return both the name and the id of the replicant
857 TReplicantTray::ItemInfo(int32 index
, const char** name
, int32
* id
)
863 fShelf
->ReplicantAt(index
, &view
, (uint32
*)id
, NULL
);
865 *name
= view
->Name();
873 /** replicant exists, by id/index */
876 TReplicantTray::IconExists(int32 target
, bool byIndex
)
879 BView
* view
= ViewAt(&index
, &id
, target
, byIndex
);
881 return view
&& index
>= 0;
885 /** replicant exists, by name */
888 TReplicantTray::IconExists(const char* name
)
890 if (!name
|| strlen(name
) == 0)
894 BView
* view
= ViewAt(&index
, &id
, name
);
896 return view
&& index
>= 0;
901 TReplicantTray::IconCount() const
903 return fShelf
->CountReplicants();
907 /*! Message must contain an archivable view for later rehydration.
908 This function takes over ownership of the provided message on success
910 Returns the current replicant ID.
913 TReplicantTray::AddIcon(BMessage
* archive
, int32
* id
, const entry_ref
* addOn
)
915 if (archive
== NULL
|| id
== NULL
)
922 // Use it if we got it
925 const char* signature
;
927 status_t status
= archive
->FindString("add_on", &signature
);
928 if (status
== B_OK
) {
930 status
= roster
.FindApp(signature
, &ref
);
937 status_t status
= file
.SetTo(&ref
, B_READ_ONLY
);
942 status
= file
.GetNodeRef(&nodeRef
);
946 BEntry
entry(&ref
, true);
947 // TODO: this resolves an eventual link for the item being added - this
948 // is okay for now, but in multi-user environments, one might want to
949 // have links that carry the be:deskbar_item_status attribute
950 status
= entry
.InitCheck();
955 if (archive
->what
== B_ARCHIVED_OBJECT
)
958 BRect originalBounds
= archive
->FindRect("_frame");
959 // this is a work-around for buggy replicants that change their size in
960 // AttachedToWindow() (such as "SVM")
962 // TODO: check for name collisions?
963 status
= fShelf
->AddReplicant(archive
, BPoint(1, 1));
967 int32 count
= fShelf
->CountReplicants();
969 fShelf
->ReplicantAt(count
- 1, &view
, (uint32
*)id
, NULL
);
971 if (originalBounds
!= view
->Bounds()) {
972 // The replicant changed its size when added to the window, so we need
973 // to recompute all over again (it's already done once via
974 // BShelf::AddReplicant() and TReplicantShelf::CanAcceptReplicantView())
978 float oldWidth
= Bounds().Width();
979 float oldHeight
= Bounds().Height();
981 GetPreferredSize(&width
, &height
);
982 if (oldWidth
!= width
|| oldHeight
!= height
)
985 // add the item to the add-on list
987 AddItem(*id
, nodeRef
, entry
, addOn
!= NULL
);
993 TReplicantTray::RemoveIcon(int32 target
, bool byIndex
)
999 BView
* view
= ViewAt(&index
, &id
, target
, byIndex
);
1000 if (view
&& index
>= 0) {
1001 // remove the reference from the item list & the shelf
1003 fShelf
->DeleteReplicant(index
);
1005 // force a placement update, !! need to fix BShelf
1006 RealReplicantAdjustment(index
);
1012 TReplicantTray::RemoveIcon(const char* name
)
1014 if (!name
|| strlen(name
) <= 0)
1018 BView
* view
= ViewAt(&index
, &id
, name
);
1019 if (view
&& index
>= 0) {
1020 // remove the reference from the item list & shelf
1022 fShelf
->DeleteReplicant(index
);
1024 // force a placement update, !! need to fix BShelf
1025 RealReplicantAdjustment(index
);
1031 TReplicantTray::RealReplicantAdjustment(int32 startIndex
)
1036 if (startIndex
== fLastReplicant
)
1039 // reset the locations of all replicants after the one deleted
1040 RealignReplicants(startIndex
);
1042 float oldWidth
= Bounds().Width();
1043 float oldHeight
= Bounds().Height();
1044 float width
, height
;
1045 GetPreferredSize(&width
, &height
);
1046 if (oldWidth
!= width
|| oldHeight
!= height
) {
1047 // resize view to accomodate the replicants, redraw as necessary
1053 /** looking for a replicant by id/index
1054 * return the view and index
1058 TReplicantTray::ViewAt(int32
* index
, int32
* id
, int32 target
, bool byIndex
)
1064 if (fShelf
->ReplicantAt(target
, &view
, (uint32
*)id
)) {
1071 int32 count
= fShelf
->CountReplicants() - 1;
1073 for (int32 repIndex
= count
; repIndex
>= 0 ; repIndex
--) {
1074 fShelf
->ReplicantAt(repIndex
, &view
, (uint32
*)&localid
);
1075 if (localid
== target
&& view
) {
1086 /** looking for a replicant with a view by name
1087 * return the view, index and the id of the replicant
1091 TReplicantTray::ViewAt(int32
* index
, int32
* id
, const char* name
)
1097 int32 count
= fShelf
->CountReplicants()-1;
1098 for (int32 repIndex
= count
; repIndex
>= 0 ; repIndex
--) {
1099 fShelf
->ReplicantAt(repIndex
, &view
, (uint32
*)id
);
1100 if (view
&& view
->Name() && strcmp(name
, view
->Name()) == 0) {
1109 /** Shelf will call to determine where and if
1110 * the replicant is to be added
1114 TReplicantTray::AcceptAddon(BRect replicantFrame
, BMessage
* message
)
1119 if (replicantFrame
.Height() > kMaxReplicantHeight
)
1122 alignment align
= B_ALIGN_LEFT
;
1123 if (fAlignmentSupport
&& message
->HasBool("deskbar:dynamic_align")) {
1124 if (!fBarView
->Vertical())
1125 align
= B_ALIGN_RIGHT
;
1127 align
= fBarView
->Left() ? B_ALIGN_LEFT
: B_ALIGN_RIGHT
;
1128 } else if (message
->HasInt32("deskbar:align"))
1129 message
->FindInt32("deskbar:align", (int32
*)&align
);
1131 if (message
->HasInt32("deskbar:private_align"))
1132 message
->FindInt32("deskbar:private_align", (int32
*)&align
);
1134 align
= B_ALIGN_LEFT
;
1136 BPoint loc
= LocationForReplicant(fShelf
->CountReplicants(),
1137 replicantFrame
.Width());
1139 message
->AddPoint("_pjp_loc", loc
);
1144 /** based on the previous (index - 1) replicant in the list
1145 * calculate where the left point should be for this
1146 * replicant. replicant will flow to the right on its own
1150 TReplicantTray::LocationForReplicant(int32 index
, float width
)
1152 BPoint
loc(kIconGap
+ 1, kGutter
+ 1);
1154 if (fMultiRowMode
) {
1155 // try to find free space in every row
1156 for (int32 row
= 0; ; loc
.y
+= kMaxReplicantHeight
+ kIconGap
, row
++) {
1157 // determine free space in this row
1158 BRect
rect(loc
.x
, loc
.y
, loc
.x
+ fMinimumTrayWidth
- kIconGap
1159 - 2.0, loc
.y
+ kMaxReplicantHeight
);
1160 if (row
== 0 && !fTime
->IsHidden())
1161 rect
.right
-= fTime
->Frame().Width() + kIconGap
;
1163 for (int32 i
= 0; i
< index
; i
++) {
1165 fShelf
->ReplicantAt(i
, &view
);
1166 if (view
== NULL
|| view
->Frame().top
!= rect
.top
)
1169 rect
.left
= view
->Frame().right
+ kIconGap
+ 1;
1172 if (rect
.Width() >= width
) {
1173 // the icon fits in this row
1174 loc
= rect
.LeftTop();
1180 // get the last replicant added for placement reference
1182 fShelf
->ReplicantAt(index
- 1, &view
);
1184 // push this rep placement past the last one
1185 loc
.x
= view
->Frame().right
+ kIconGap
+ 1;
1186 loc
.y
= view
->Frame().top
;
1191 if ((loc
.y
== fRightBottomReplicant
.top
&& loc
.x
1192 > fRightBottomReplicant
.left
) || loc
.y
> fRightBottomReplicant
.top
) {
1193 fRightBottomReplicant
.Set(loc
.x
, loc
.y
, loc
.x
+ width
, loc
.y
1194 + kMaxReplicantHeight
);
1195 fLastReplicant
= index
;
1203 TReplicantTray::IconFrame(int32 target
, bool byIndex
)
1206 BView
* view
= ViewAt(&index
, &id
, target
, byIndex
);
1208 return view
->Frame();
1210 return BRect(0, 0, 0, 0);
1215 TReplicantTray::IconFrame(const char* name
)
1218 return BRect(0, 0, 0, 0);
1221 BView
* view
= ViewAt(&index
, &id
, name
);
1223 return view
->Frame();
1225 return BRect(0, 0, 0, 0);
1229 /** Scan from the startIndex and reset the location
1230 * as defined in LocationForReplicant()
1234 TReplicantTray::RealignReplicants(int32 startIndex
)
1239 int32 count
= fShelf
->CountReplicants();
1243 if (startIndex
== 0)
1244 fRightBottomReplicant
.Set(0, 0, 0, 0);
1247 for (int32 i
= startIndex
; i
< count
; i
++) {
1248 fShelf
->ReplicantAt(i
, &view
);
1250 BPoint loc
= LocationForReplicant(i
, view
->Frame().Width());
1251 if (view
->Frame().LeftTop() != loc
)
1259 TReplicantTray::_SaveSettings()
1263 if ((result
= GetDeskbarSettingsDirectory(path
, true)) == B_OK
) {
1264 path
.Append(kReplicantSettingsFile
);
1266 BFile
file(path
.Path(), B_READ_WRITE
| B_CREATE_FILE
| B_ERASE_FILE
);
1267 if ((result
= file
.InitCheck()) == B_OK
)
1268 result
= fAddOnSettings
.Flatten(&file
);
1276 TReplicantTray::SaveTimeSettings()
1281 clock_settings
* settings
= ((TBarApp
*)be_app
)->ClockSettings();
1282 settings
->showSeconds
= fTime
->ShowSeconds();
1283 settings
->showDayOfWeek
= fTime
->ShowDayOfWeek();
1284 settings
->showTimeZone
= fTime
->ShowTimeZone();
1291 /*! Draggable region that is asynchronous so that dragging does not block
1294 TDragRegion::TDragRegion(TBarView
* parent
, BView
* child
)
1296 BControl(BRect(0, 0, 0, 0), "", "", NULL
, B_FOLLOW_NONE
,
1297 B_WILL_DRAW
| B_FRAME_EVENTS
),
1300 fDragLocation(kAutoPlaceDragRegion
)
1306 TDragRegion::AttachedToWindow()
1308 BView::AttachedToWindow();
1309 if (be_control_look
!= NULL
)
1310 SetViewColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR
), 1.1));
1312 SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR
));
1313 ResizeToPreferred();
1318 TDragRegion::GetPreferredSize(float* width
, float* height
)
1320 fChild
->ResizeToPreferred();
1321 *width
= fChild
->Bounds().Width();
1322 *height
= fChild
->Bounds().Height();
1324 if (fDragLocation
!= kNoDragRegion
)
1334 TDragRegion::FrameMoved(BPoint
)
1336 if (fBarView
->Left() && fBarView
->Vertical()
1337 && fDragLocation
!= kNoDragRegion
)
1338 fChild
->MoveTo(5, 2);
1340 fChild
->MoveTo(2, 2);
1345 TDragRegion::Draw(BRect
)
1347 rgb_color menuColor
= ViewColor();
1348 rgb_color hilite
= tint_color(menuColor
, B_DARKEN_1_TINT
);
1349 rgb_color ldark
= tint_color(menuColor
, 1.02);
1350 rgb_color dark
= tint_color(menuColor
, B_DARKEN_2_TINT
);
1351 rgb_color vvdark
= tint_color(menuColor
, B_DARKEN_4_TINT
);
1352 rgb_color light
= tint_color(menuColor
, B_LIGHTEN_2_TINT
);
1354 BRect
frame(Bounds());
1357 if (be_control_look
!= NULL
) {
1358 if (fBarView
->Vertical()) {
1359 AddLine(frame
.LeftTop(), frame
.RightTop(), dark
);
1360 AddLine(BPoint(frame
.left
, frame
.top
+ 1),
1361 BPoint(frame
.right
, frame
.top
+ 1), ldark
);
1362 AddLine(frame
.LeftBottom(), frame
.RightBottom(), hilite
);
1363 } else if (fBarView
->AcrossTop() || fBarView
->AcrossBottom()) {
1364 AddLine(frame
.LeftTop(),
1365 BPoint(frame
.left
, frame
.bottom
), dark
);
1366 AddLine(BPoint(frame
.left
+ 1, frame
.top
+ 1),
1367 BPoint(frame
.right
- 1, frame
.top
+ 1), light
);
1368 AddLine(BPoint(frame
.right
, frame
.top
+ 2),
1369 BPoint(frame
.right
, frame
.bottom
), hilite
);
1370 AddLine(BPoint(frame
.left
+ 1, frame
.bottom
),
1371 BPoint(frame
.right
- 1, frame
.bottom
), hilite
);
1374 if (fBarView
->Vertical()) {
1375 AddLine(frame
.LeftTop(), frame
.RightTop(), light
);
1376 AddLine(frame
.LeftTop(), frame
.LeftBottom(), light
);
1377 AddLine(frame
.RightBottom(), frame
.RightTop(), hilite
);
1378 } else if (fBarView
->AcrossTop()) {
1379 AddLine(BPoint(frame
.left
, frame
.top
+ 1),
1380 BPoint(frame
.right
- 1, frame
.top
+ 1), light
);
1381 AddLine(frame
.RightTop(), frame
.RightBottom(), vvdark
);
1382 AddLine(BPoint(frame
.right
- 1, frame
.top
+ 2),
1383 BPoint(frame
.right
- 1, frame
.bottom
- 1), hilite
);
1384 AddLine(frame
.LeftBottom(),
1385 BPoint(frame
.right
- 1, frame
.bottom
), hilite
);
1386 } else if (fBarView
->AcrossBottom()) {
1387 AddLine(BPoint(frame
.left
, frame
.top
+ 1),
1388 BPoint(frame
.right
- 1, frame
.top
+ 1), light
);
1389 AddLine(frame
.LeftBottom(), frame
.RightBottom(), hilite
);
1390 AddLine(frame
.RightTop(), frame
.RightBottom(), vvdark
);
1391 AddLine(BPoint(frame
.right
- 1, frame
.top
+ 1),
1392 BPoint(frame
.right
- 1, frame
.bottom
- 1), hilite
);
1398 if (fDragLocation
!= kDontDrawDragRegion
|| fDragLocation
!= kNoDragRegion
)
1404 TDragRegion::DrawDragRegion()
1406 BRect
dragRegion(DragRegion());
1408 rgb_color menuColor
= ViewColor();
1409 rgb_color menuHilite
= menuColor
;
1411 // Draw drag region highlighted if tracking mouse
1412 menuHilite
= tint_color(menuColor
, B_HIGHLIGHT_BACKGROUND_TINT
);
1413 SetHighColor(menuHilite
);
1414 FillRect(dragRegion
);
1416 rgb_color vdark
= tint_color(menuHilite
, B_DARKEN_3_TINT
);
1417 rgb_color light
= tint_color(menuHilite
, B_LIGHTEN_2_TINT
);
1419 BeginLineArray(dragRegion
.IntegerHeight());
1421 pt
.x
= floorf((dragRegion
.left
+ dragRegion
.right
) / 2 + 0.5) - 1;
1422 pt
.y
= dragRegion
.top
+ 2;
1424 while (pt
.y
+ 1 <= dragRegion
.bottom
) {
1425 AddLine(pt
, pt
, vdark
);
1426 AddLine(pt
+ BPoint(1, 1), pt
+ BPoint(1, 1), light
);
1435 TDragRegion::DragRegion() const
1437 float kTopBottomInset
= 2;
1438 float kLeftRightInset
= 1;
1439 float kDragWidth
= 3;
1440 if (be_control_look
!= NULL
) {
1441 kTopBottomInset
= 1;
1442 kLeftRightInset
= 0;
1446 BRect
dragRegion(Bounds());
1447 dragRegion
.top
+= kTopBottomInset
;
1448 dragRegion
.bottom
-= kTopBottomInset
;
1450 bool placeOnLeft
= false;
1451 if (fDragLocation
== kAutoPlaceDragRegion
) {
1452 if (fBarView
->Vertical() && fBarView
->Left())
1455 placeOnLeft
= false;
1456 } else if (fDragLocation
== kDragRegionLeft
)
1458 else if (fDragLocation
== kDragRegionRight
)
1459 placeOnLeft
= false;
1462 dragRegion
.left
+= kLeftRightInset
;
1463 dragRegion
.right
= dragRegion
.left
+ kDragWidth
;
1465 dragRegion
.right
-= kLeftRightInset
;
1466 dragRegion
.left
= dragRegion
.right
- kDragWidth
;
1474 TDragRegion::MouseDown(BPoint thePoint
)
1478 BRect
dragRegion(DragRegion());
1480 dragRegion
.InsetBy(-2.0f
, -2.0f
);
1481 // DragRegion() is designed for drawing, not clicking
1483 if (!dragRegion
.Contains(thePoint
))
1487 GetMouse(&where
, &buttons
);
1491 if ((Window()->Flags() & B_ASYNCHRONOUS_CONTROLS
) != 0) {
1492 fPreviousPosition
= thePoint
;
1494 SetMouseEventMask(B_POINTER_EVENTS
,
1495 B_NO_POINTER_HISTORY
| B_LOCK_WINDOW_FOCUS
);
1496 Invalidate(DragRegion());
1506 TDragRegion::MouseUp(BPoint pt
)
1510 Invalidate(DragRegion());
1512 BControl::MouseUp(pt
);
1517 TDragRegion::SwitchModeForRect(BPoint mouse
, BRect rect
,
1518 bool newVertical
, bool newLeft
, bool newTop
, int32 newState
)
1520 if (!rect
.Contains(mouse
)) {
1525 if (newVertical
== fBarView
->Vertical() && newLeft
== fBarView
->Left()
1526 && newTop
== fBarView
->Top() && newState
== fBarView
->State()) {
1527 // already in the correct mode
1531 fBarView
->ChangeState(newState
, newVertical
, newLeft
, newTop
, true);
1537 TDragRegion::MouseMoved(BPoint where
, uint32 code
, const BMessage
* message
)
1541 BRect frame
= screen
.Frame();
1543 float hDivider
= frame
.Width() / 6;
1544 hDivider
= (hDivider
< gMinimumWindowWidth
+ 10.0f
)
1545 ? gMinimumWindowWidth
+ 10.0f
: hDivider
;
1546 float miniDivider
= frame
.top
+ kMiniHeight
+ 10.0f
;
1547 float vDivider
= frame
.Height() / 2;
1549 float thirdScreen
= frame
.Height() / 3;
1551 BRect
topLeft(frame
.left
, frame
.top
, frame
.left
+ hDivider
,
1553 BRect
topMiddle(frame
.left
+ hDivider
, frame
.top
, frame
.right
1554 - hDivider
, vDivider
);
1555 BRect
topRight(frame
.right
- hDivider
, frame
.top
, frame
.right
,
1559 vDivider
= miniDivider
+ thirdScreen
;
1561 BRect
middleLeft(frame
.left
, miniDivider
, frame
.left
+ hDivider
,
1563 BRect
middleRight(frame
.right
- hDivider
, miniDivider
, frame
.right
,
1567 BRect
leftSide(frame
.left
, vDivider
, frame
.left
+ hDivider
,
1568 frame
.bottom
- thirdScreen
);
1569 BRect
rightSide(frame
.right
- hDivider
, vDivider
, frame
.right
,
1570 frame
.bottom
- thirdScreen
);
1572 vDivider
= frame
.bottom
- thirdScreen
;
1574 BRect
bottomLeft(frame
.left
, vDivider
, frame
.left
+ hDivider
,
1576 BRect
bottomMiddle(frame
.left
+ hDivider
, vDivider
, frame
.right
1577 - hDivider
, frame
.bottom
);
1578 BRect
bottomRight(frame
.right
- hDivider
, vDivider
, frame
.right
,
1581 if (where
!= fPreviousPosition
) {
1582 fPreviousPosition
= where
;
1583 ConvertToScreen(&where
);
1585 // use short circuit evaluation for convenience
1586 if (SwitchModeForRect(where
, topLeft
, true, true, true, kMiniState
)
1587 || SwitchModeForRect(where
, topMiddle
, false, true, true,
1589 || SwitchModeForRect(where
, topRight
, true, false, true,
1591 || SwitchModeForRect(where
, middleLeft
, true, true, true,
1593 || SwitchModeForRect(where
, middleRight
, true, false, true,
1597 || SwitchModeForRect(where
, leftSide
, true, true, true,
1599 || SwitchModeForRect(where
, rightSide
, true, false, true,
1602 || SwitchModeForRect(where
, bottomLeft
, true, true, false,
1604 || SwitchModeForRect(where
, bottomMiddle
, false, true, false,
1606 || SwitchModeForRect(where
, bottomRight
, true, false, false,
1611 BControl::MouseMoved(where
, code
, message
);
1616 TDragRegion::DragRegionLocation() const
1618 return fDragLocation
;
1623 TDragRegion::SetDragRegionLocation(int32 location
)
1625 if (location
== fDragLocation
)
1628 fDragLocation
= location
;