From 860b32520c070ec7ea650222dcb5da1316b24cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 6 Jun 2005 14:23:06 +0000 Subject: [PATCH] Almost rewrote BDeskbar. Fixed some bugs. Added some ToDo comments - the functions will currently deadlock when called from within the Deskbar. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12962 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/interface/Deskbar.cpp | 642 +++++++++++++++------------------ 1 file changed, 297 insertions(+), 345 deletions(-) diff --git a/src/kits/interface/Deskbar.cpp b/src/kits/interface/Deskbar.cpp index 1b646cc94f..a655fe5ad4 100644 --- a/src/kits/interface/Deskbar.cpp +++ b/src/kits/interface/Deskbar.cpp @@ -1,34 +1,14 @@ -//------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, OpenBeOS -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// -// File Name: Deskbar.cpp -// Author: Jeremy Rand (jrand@magma.ca), Jérôme Duval -// Description: BDeskbar allows one to control the deskbar from an -// application. -//------------------------------------------------------------------------------ +/* + * Copyright 2001-2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Jeremy Rand (jrand@magma.ca) + * Jérôme Duval + * Axel Dörfler + */ -// Standard Includes ----------------------------------------------------------- -#include -// System Includes ------------------------------------------------------------- #include #include #include @@ -37,338 +17,310 @@ #include #include -// Project Includes ------------------------------------------------------------ +#include -// Local Includes -------------------------------------------------------------- +// ToDo: in case the BDeskbar methods are called from a Deskbar add-on, +// they will currently deadlock most of the time (only those that do +// not need a reply will work). +// That should be fixed in the Deskbar itself, even if the Be API found +// a way around that (that doesn't work too well, BTW) -// Local Defines --------------------------------------------------------------- +// The API in this file should be considered as part of OpenTracker - but +// should work with all versions of Tracker available for Haiku. -// Globals --------------------------------------------------------------------- -static const char *gDeskbarSignature = "application/x-vnd.Be-TSKB"; -static const uint32 gAddItemViewWhat = 'icon'; -static const uint32 gAddItemAddonWhat = 'adon'; -static const uint32 gHasItemWhat = 'exst'; -static const uint32 gGetItemInfoWhat = 'info'; -static const uint32 gCountItemsWhat = 'cwnt'; -static const uint32 gRemoveItemWhat = 'remv'; -static const uint32 gLocationWhat = 'gloc'; -static const uint32 gIsExpandedWhat = 'gexp'; -static const uint32 gSetLocationWhat = 'sloc'; -static const uint32 gExpandWhat = 'sexp'; +static const char *kDeskbarSignature = "application/x-vnd.Be-TSKB"; + +static const uint32 kMsgAddView = 'icon'; +static const uint32 kMsgAddAddOn = 'adon'; +static const uint32 kMsgHasItem = 'exst'; +static const uint32 kMsgGetItemInfo = 'info'; +static const uint32 kMsgCountItems = 'cwnt'; +static const uint32 kMsgRemoveItem = 'remv'; +static const uint32 kMsgLocation = 'gloc'; +static const uint32 kMsgIsExpanded = 'gexp'; +static const uint32 kMsgSetLocation = 'sloc'; +static const uint32 kMsgExpand = 'sexp'; -status_t get_deskbar_frame(BRect *frame) +status_t +get_deskbar_frame(BRect *frame) { - BMessenger deskbarMessenger(gDeskbarSignature); - BMessage requestMessage(B_GET_PROPERTY); - BMessage replyMessage; + BMessenger deskbar(kDeskbarSignature); + status_t result; - - result = requestMessage.AddSpecifier("Frame"); - if (result == B_OK) { - result = requestMessage.AddSpecifier("Window", "Deskbar"); - if (result == B_OK) { - result = deskbarMessenger.SendMessage(&requestMessage, &replyMessage); - if ((result == B_OK) && - (replyMessage.what == B_REPLY)) { - result = replyMessage.FindRect("result", frame); - } - } - } - return(result); + + BMessage request(B_GET_PROPERTY); + request.AddSpecifier("Frame"); + request.AddSpecifier("Window", "Deskbar"); + + BMessage reply; + result = deskbar.SendMessage(&request, &reply); + if (result == B_OK) + result = reply.FindRect("result", frame); + + return result; } -//------------------------------------------------------------------------------ +// #pragma mark - + + BDeskbar::BDeskbar() - : fMessenger(new BMessenger(gDeskbarSignature)) + : fMessenger(new BMessenger(kDeskbarSignature)) { } -//------------------------------------------------------------------------------ + + BDeskbar::~BDeskbar() { delete fMessenger; } -//------------------------------------------------------------------------------ -BRect BDeskbar::Frame(void) const -{ - BMessage requestMessage(B_GET_PROPERTY); - BMessage replyMessage; - BRect result(0.0, 0.0, 0.0, 0.0); - if ((requestMessage.AddSpecifier("Frame") == B_OK) && - (requestMessage.AddSpecifier("Window", "Deskbar") == B_OK) && - (fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK) && - (replyMessage.what == B_REPLY)) { - replyMessage.FindRect("result", &result); - } - return(result); -} -//------------------------------------------------------------------------------ -deskbar_location BDeskbar::Location(bool *isExpanded) const -{ - BMessage requestMessage(gLocationWhat); - BMessage replyMessage; - int32 result = 0; - - if ((fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK) && - (replyMessage.what == 'rply') && - (replyMessage.FindInt32("location", &result) == B_OK) && - (isExpanded != NULL)) { - replyMessage.FindBool("expanded", isExpanded); - } - return(static_cast(result)); -} -//------------------------------------------------------------------------------ -status_t BDeskbar::SetLocation(deskbar_location location, bool expanded) -{ - BMessage requestMessage(gSetLocationWhat); - BMessage replyMessage; - status_t result; - - result = requestMessage.AddInt32("location", static_cast(location)); - if (result == B_OK) { - result = requestMessage.AddBool("expand", expanded); - if (result == B_OK) { - result = fMessenger->SendMessage(&requestMessage, &replyMessage); - } - } - return(result); -} -//------------------------------------------------------------------------------ -bool BDeskbar::IsExpanded(void) const -{ - BMessage requestMessage(gIsExpandedWhat); - BMessage replyMessage; - bool result = false; - - if ((fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK) && - (replyMessage.what == 'rply')) { - replyMessage.FindBool("expanded", &result); - } - return(result); -} -//------------------------------------------------------------------------------ -status_t BDeskbar::Expand(bool expand) -{ - BMessage requestMessage(gExpandWhat); - BMessage replyMessage; - status_t result; - - result = requestMessage.AddBool("expand", expand); - if (result == B_OK) { - result = fMessenger->SendMessage(&requestMessage, &replyMessage); - } - return(result); -} -//------------------------------------------------------------------------------ -status_t BDeskbar::GetItemInfo(int32 id, const char **name) const -{ - /* NOTE: Be's implementation returned B_BAD_VALUE if *name was NULL, - not just if name was NULL. This doesn't make much sense. Be's - implementation means you cannot do the following: - - const char *buffer = NULL; - myDeskbar.GetItemInfo(id, &buffer); - - Instead, you are forced to write code that looks like: - - char tmpBuf[10]; - const char *buffer = tmpBuf; - myDeskbar.GetItemInfo(id, &buffer); - - There are a couple of issues with this: - - Be's implementation does not use the space pointed to in buffer. - It cannot since it can't tell how big that space is and it won't - know whether the item's name will fit without overflowing the - buffer. - - Worse, if the code looked like: - - const char *buffer = new char[5]; - myDeskbar.GetItemInfo(id, &buffer); - - The code will result in a memory leak. The problem here is that - what buffer points to is changed by GetItemInfo(). If buffer - points to dynamically allocated memory, there is a good chance - the result is a memory leak. - - The OpenBeOS implementation will allow *name to point to NULL or - non-NULL. If anything, we should consider forcing *name to point to - NULL for safety. - */ - if (name == NULL) { - return(B_BAD_VALUE); - } - - BMessage requestMessage(gGetItemInfoWhat); - BMessage replyMessage; - status_t result; - - result = requestMessage.AddInt32("id", id); - if (result == B_OK) { - result = fMessenger->SendMessage(&requestMessage, &replyMessage); - if (result == B_OK) { - const char *tmpName; - result = replyMessage.FindString("name", &tmpName); - if (result == B_OK) { - *name = strdup(tmpName); - } - } - } - return(result); -} -//------------------------------------------------------------------------------ -status_t BDeskbar::GetItemInfo(const char *name, int32 *id) const -{ - if (name == NULL) { - return(B_BAD_VALUE); - } - - BMessage requestMessage(gGetItemInfoWhat); - BMessage replyMessage; - status_t result; - - result = requestMessage.AddString("name", name); - if (result == B_OK) { - result = fMessenger->SendMessage(&requestMessage, &replyMessage); - if (result == B_OK) { - result = replyMessage.FindInt32("id", id); - } - } - return(result); -} -//------------------------------------------------------------------------------ -bool BDeskbar::HasItem(int32 id) const -{ - BMessage requestMessage(gHasItemWhat); - BMessage replyMessage; - bool result = false; - - if ((requestMessage.AddInt32("id", id) == B_OK) && - (fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK)) { - replyMessage.FindBool("exists", &result); - } - return(result); -} -//------------------------------------------------------------------------------ -bool BDeskbar::HasItem(const char *name) const -{ - BMessage requestMessage(gHasItemWhat); - BMessage replyMessage; - bool result = false; - - if ((requestMessage.AddString("name", name) == B_OK) && - (fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK)) { - replyMessage.FindBool("exists", &result); - } - return(result); -} -//------------------------------------------------------------------------------ -uint32 BDeskbar::CountItems(void) const -{ - BMessage requestMessage(gCountItemsWhat); - BMessage replyMessage; - int32 result = 0; - - if ((fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK) && - (replyMessage.what == 'rply')) { - replyMessage.FindInt32("count", &result); - } - return(static_cast(result)); -} -//------------------------------------------------------------------------------ -status_t BDeskbar::AddItem(BView *archivableView, int32 *id) -{ - BMessage requestMessage(gAddItemViewWhat); - BMessage viewMessage; - BMessage replyMessage; - status_t result; - - result = archivableView->Archive(&viewMessage); - if (result == B_OK) { - result = requestMessage.AddMessage("view", &viewMessage); - if (result == B_OK) { - result = fMessenger->SendMessage(&requestMessage, &replyMessage); - if ((result == B_OK) && - (id != NULL)) { - result = replyMessage.FindInt32("id", id); - } - } - } - return(result); -} -//------------------------------------------------------------------------------ -status_t BDeskbar::AddItem(entry_ref *addon, int32 *id) -{ - BMessage requestMessage(gAddItemViewWhat); - BMessage replyMessage; - status_t result; - - result = requestMessage.AddRef("addon", addon); - if (result == B_OK) { - result = fMessenger->SendMessage(&requestMessage, &replyMessage); - if ((result == B_OK) && - (id != NULL)) { - result = replyMessage.FindInt32("id", id); - - /* NOTE: I add this because the persistent state of the item - is not set by the Deskbar itself and it needs to be done somewhere. - In fact, telling the Deskbar about the addon ref is not enough and - adding this attribute is mandatory. - !! Deskbar seems to remove the attribute in RemoveItem though !! - */ - if (result == B_OK) { - BNode node(addon); - node.WriteAttr("be:deskbar_item_status", - B_STRING_TYPE, 0, "enabled", strlen("enabled")); - } - } - } - return(result); -} -//------------------------------------------------------------------------------ -status_t BDeskbar::RemoveItem(int32 id) -{ - BMessage requestMessage(gRemoveItemWhat); - BMessage replyMessage; - status_t result; - - result = requestMessage.AddInt32("id", id); - if (result == B_OK) { - result = fMessenger->SendMessage(&requestMessage, &replyMessage); - } - /* here R5 returns B_OK always (probably the result of SendMessage()) - * Deskbar itself also always return B_NO_REPLY, so ... - * here add some more checks for the future. - */ - if (result != B_OK) - return(result); - if (replyMessage.what == B_NO_REPLY) - return(B_OK); /* we can only speculate */ - result = B_ERROR; - replyMessage.FindInt32("error", &result); - return(result); -} -//------------------------------------------------------------------------------ -status_t BDeskbar::RemoveItem(const char *name) -{ - BMessage requestMessage(gRemoveItemWhat); - BMessage replyMessage; - status_t result; - - result = requestMessage.AddString("name", name); - if (result == B_OK) { - result = fMessenger->SendMessage(&requestMessage, &replyMessage); - } - /* same as above */ - if (result != B_OK) - return(result); - if (replyMessage.what == B_NO_REPLY) - return(B_OK); - result = B_ERROR; - replyMessage.FindInt32("error", &result); - return(result); - -} -//------------------------------------------------------------------------------ + +BRect +BDeskbar::Frame(void) const +{ + BRect frame(0.0, 0.0, 0.0, 0.0); + get_deskbar_frame(&frame); + + return frame; +} + + +deskbar_location +BDeskbar::Location(bool *_isExpanded) const +{ + deskbar_location location = B_DESKBAR_RIGHT_TOP; + BMessage request(kMsgLocation); + BMessage reply; + + if (_isExpanded) + *_isExpanded = true; + + if (fMessenger->IsTargetLocal()) { + // ToDo: do something about this! + // (if we just ask the Deskbar in this case, we would deadlock) + return location; + } + + if (fMessenger->SendMessage(&request, &reply) == B_OK) { + int32 value; + if (reply.FindInt32("location", &value) == B_OK) + location = static_cast(value); + + if (_isExpanded + && reply.FindBool("expanded", _isExpanded) != B_OK) + *_isExpanded = true; + } + + return location; +} + + +status_t +BDeskbar::SetLocation(deskbar_location location, bool expanded) +{ + BMessage request(kMsgSetLocation); + request.AddInt32("location", static_cast(location)); + request.AddBool("expand", expanded); + + return fMessenger->SendMessage(&request); +} + + +bool +BDeskbar::IsExpanded(void) const +{ + BMessage request(kMsgIsExpanded); + BMessage reply; + bool isExpanded; + + if (fMessenger->SendMessage(&request, &reply) != B_OK + || reply.FindBool("expanded", &isExpanded) != B_OK) + isExpanded = true; + + return isExpanded; +} + + +status_t +BDeskbar::Expand(bool expand) +{ + BMessage request(kMsgExpand); + request.AddBool("expand", expand); + + return fMessenger->SendMessage(&request); +} + + +status_t +BDeskbar::GetItemInfo(int32 id, const char **_name) const +{ + if (_name == NULL) + return B_BAD_VALUE; + + // Note: Be's implementation returns B_BAD_VALUE if *_name was NULL, + // not just if _name was NULL. This doesn't make much sense, so we + // do not imitate this behaviour. + + BMessage request(kMsgGetItemInfo); + request.AddInt32("id", id); + + BMessage reply; + status_t result = fMessenger->SendMessage(&request, &reply); + if (result == B_OK) { + const char *name; + result = reply.FindString("name", &name); + if (result == B_OK) { + *_name = strdup(name); + if (*_name == NULL) + result = B_NO_MEMORY; + } + } + return result; +} + + +status_t +BDeskbar::GetItemInfo(const char *name, int32 *_id) const +{ + if (name == NULL) + return B_BAD_VALUE; + + BMessage request(kMsgGetItemInfo); + request.AddString("name", name); + + BMessage reply; + status_t result = fMessenger->SendMessage(&request, &reply); + if (result == B_OK) + result = reply.FindInt32("id", _id); + + return result; +} + + +bool +BDeskbar::HasItem(int32 id) const +{ + BMessage request(kMsgHasItem); + request.AddInt32("id", id); + + BMessage reply; + if (fMessenger->SendMessage(&request, &reply) == B_OK) + return reply.FindBool("exists"); + + return false; +} + + +bool +BDeskbar::HasItem(const char *name) const +{ + BMessage request(kMsgHasItem); + request.AddString("name", name); + + BMessage reply; + if (fMessenger->SendMessage(&request, &reply) == B_OK) + return reply.FindBool("exists"); + + return false; +} + + +uint32 +BDeskbar::CountItems(void) const +{ + BMessage request(kMsgCountItems); + BMessage reply; + + if (fMessenger->SendMessage(&request, &reply) == B_OK) + return reply.FindInt32("count"); + + return 0; +} + + +status_t +BDeskbar::AddItem(BView *view, int32 *_id) +{ + BMessage archive; + status_t result = view->Archive(&archive); + if (result < B_OK) + return result; + + BMessage request(kMsgAddView); + request.AddMessage("view", &archive); + + BMessage reply; + result = fMessenger->SendMessage(&request, &reply); + if (result == B_OK) { + if (_id != NULL) + result = reply.FindInt32("id", _id); + else + reply.FindInt32("error", &result); + } + + return result; +} + + +status_t +BDeskbar::AddItem(entry_ref *addon, int32 *_id) +{ + BMessage request(kMsgAddAddOn); + request.AddRef("addon", addon); + + // Note: to make Deskbar items persistent, they need to have the attribute + // set. The Deskbar will remove the attribute automatically when needed. + // ToDo: move this functionality into the Deskbar itself! + + BNode node; + status_t status = node.SetTo(addon); + if (status < B_OK) + return status; + + if ((status = node.WriteAttr("be:deskbar_item_status", B_STRING_TYPE, + 0, "enabled", strlen("enabled"))) < B_OK) + return status; + + BMessage reply; + status = fMessenger->SendMessage(&request, &reply); + if (status == B_OK) { + if (_id != NULL) + status = reply.FindInt32("id", _id); + else + reply.FindInt32("error", &status); + } + + return status; +} + + +status_t +BDeskbar::RemoveItem(int32 id) +{ + BMessage request(kMsgRemoveItem); + request.AddInt32("id", id); + + // ToDo: the Deskbar does not reply to this message, so we don't + // know if it really succeeded - we can just acknowledge that the + // message was sent to the Deskbar + + return fMessenger->SendMessage(&request); +} + + +status_t +BDeskbar::RemoveItem(const char *name) +{ + BMessage request(kMsgRemoveItem); + request.AddString("name", name); + + // ToDo: the Deskbar does not reply to this message, so we don't + // know if it really succeeded - we can just acknowledge that the + // message was sent to the Deskbar + + return fMessenger->SendMessage(&request); + +}