1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, OpenBeOS 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Deskbar.cpp 23 // Author: Jeremy Rand (jrand@magma.ca), Jérôme Duval 24 // Description: BDeskbar allows one to control the deskbar from an 25 // application. 26 //------------------------------------------------------------------------------ 27 28 // Standard Includes ----------------------------------------------------------- 29 #include <string.h> 30 31 // System Includes ------------------------------------------------------------- 32 #include <Deskbar.h> 33 #include <Messenger.h> 34 #include <Message.h> 35 #include <View.h> 36 #include <Rect.h> 37 #include <InterfaceDefs.h> 38 #include <Node.h> 39 40 // Project Includes ------------------------------------------------------------ 41 42 // Local Includes -------------------------------------------------------------- 43 44 // Local Defines --------------------------------------------------------------- 45 46 // Globals --------------------------------------------------------------------- 47 static const char *gDeskbarSignature = "application/x-vnd.Be-TSKB"; 48 static const uint32 gAddItemViewWhat = 'icon'; 49 static const uint32 gAddItemAddonWhat = 'adon'; 50 static const uint32 gHasItemWhat = 'exst'; 51 static const uint32 gGetItemInfoWhat = 'info'; 52 static const uint32 gCountItemsWhat = 'cwnt'; 53 static const uint32 gRemoveItemWhat = 'remv'; 54 static const uint32 gLocationWhat = 'gloc'; 55 static const uint32 gIsExpandedWhat = 'gexp'; 56 static const uint32 gSetLocationWhat = 'sloc'; 57 static const uint32 gExpandWhat = 'sexp'; 58 59 60 status_t get_deskbar_frame(BRect *frame) 61 { 62 BMessenger deskbarMessenger(gDeskbarSignature); 63 BMessage requestMessage(B_GET_PROPERTY); 64 BMessage replyMessage; 65 status_t result; 66 67 result = requestMessage.AddSpecifier("Frame"); 68 if (result == B_OK) { 69 result = requestMessage.AddSpecifier("Window", "Deskbar"); 70 if (result == B_OK) { 71 result = deskbarMessenger.SendMessage(&requestMessage, &replyMessage); 72 if ((result == B_OK) && 73 (replyMessage.what == B_REPLY)) { 74 result = replyMessage.FindRect("result", frame); 75 } 76 } 77 } 78 return(result); 79 } 80 81 82 //------------------------------------------------------------------------------ 83 BDeskbar::BDeskbar() 84 : fMessenger(new BMessenger(gDeskbarSignature)) 85 { 86 } 87 //------------------------------------------------------------------------------ 88 BDeskbar::~BDeskbar() 89 { 90 delete fMessenger; 91 } 92 //------------------------------------------------------------------------------ 93 BRect BDeskbar::Frame(void) const 94 { 95 BMessage requestMessage(B_GET_PROPERTY); 96 BMessage replyMessage; 97 BRect result(0.0, 0.0, 0.0, 0.0); 98 99 if ((requestMessage.AddSpecifier("Frame") == B_OK) && 100 (requestMessage.AddSpecifier("Window", "Deskbar") == B_OK) && 101 (fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK) && 102 (replyMessage.what == B_REPLY)) { 103 replyMessage.FindRect("result", &result); 104 } 105 return(result); 106 } 107 //------------------------------------------------------------------------------ 108 deskbar_location BDeskbar::Location(bool *isExpanded) const 109 { 110 BMessage requestMessage(gLocationWhat); 111 BMessage replyMessage; 112 int32 result = 0; 113 114 if ((fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK) && 115 (replyMessage.what == 'rply') && 116 (replyMessage.FindInt32("location", &result) == B_OK) && 117 (isExpanded != NULL)) { 118 replyMessage.FindBool("expanded", isExpanded); 119 } 120 return(static_cast<deskbar_location>(result)); 121 } 122 //------------------------------------------------------------------------------ 123 status_t BDeskbar::SetLocation(deskbar_location location, bool expanded) 124 { 125 BMessage requestMessage(gSetLocationWhat); 126 BMessage replyMessage; 127 status_t result; 128 129 result = requestMessage.AddInt32("location", static_cast<int32>(location)); 130 if (result == B_OK) { 131 result = requestMessage.AddBool("expand", expanded); 132 if (result == B_OK) { 133 result = fMessenger->SendMessage(&requestMessage, &replyMessage); 134 } 135 } 136 return(result); 137 } 138 //------------------------------------------------------------------------------ 139 bool BDeskbar::IsExpanded(void) const 140 { 141 BMessage requestMessage(gIsExpandedWhat); 142 BMessage replyMessage; 143 bool result = false; 144 145 if ((fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK) && 146 (replyMessage.what == 'rply')) { 147 replyMessage.FindBool("expanded", &result); 148 } 149 return(result); 150 } 151 //------------------------------------------------------------------------------ 152 status_t BDeskbar::Expand(bool expand) 153 { 154 BMessage requestMessage(gExpandWhat); 155 BMessage replyMessage; 156 status_t result; 157 158 result = requestMessage.AddBool("expand", expand); 159 if (result == B_OK) { 160 result = fMessenger->SendMessage(&requestMessage, &replyMessage); 161 } 162 return(result); 163 } 164 //------------------------------------------------------------------------------ 165 status_t BDeskbar::GetItemInfo(int32 id, const char **name) const 166 { 167 /* NOTE: Be's implementation returned B_BAD_VALUE if *name was NULL, 168 not just if name was NULL. This doesn't make much sense. Be's 169 implementation means you cannot do the following: 170 171 const char *buffer = NULL; 172 myDeskbar.GetItemInfo(id, &buffer); 173 174 Instead, you are forced to write code that looks like: 175 176 char tmpBuf[10]; 177 const char *buffer = tmpBuf; 178 myDeskbar.GetItemInfo(id, &buffer); 179 180 There are a couple of issues with this: 181 - Be's implementation does not use the space pointed to in buffer. 182 It cannot since it can't tell how big that space is and it won't 183 know whether the item's name will fit without overflowing the 184 buffer. 185 - Worse, if the code looked like: 186 187 const char *buffer = new char[5]; 188 myDeskbar.GetItemInfo(id, &buffer); 189 190 The code will result in a memory leak. The problem here is that 191 what buffer points to is changed by GetItemInfo(). If buffer 192 points to dynamically allocated memory, there is a good chance 193 the result is a memory leak. 194 195 The OpenBeOS implementation will allow *name to point to NULL or 196 non-NULL. If anything, we should consider forcing *name to point to 197 NULL for safety. 198 */ 199 if (name == NULL) { 200 return(B_BAD_VALUE); 201 } 202 203 BMessage requestMessage(gGetItemInfoWhat); 204 BMessage replyMessage; 205 status_t result; 206 207 result = requestMessage.AddInt32("id", id); 208 if (result == B_OK) { 209 result = fMessenger->SendMessage(&requestMessage, &replyMessage); 210 if (result == B_OK) { 211 const char *tmpName; 212 result = replyMessage.FindString("name", &tmpName); 213 if (result == B_OK) { 214 *name = strdup(tmpName); 215 } 216 } 217 } 218 return(result); 219 } 220 //------------------------------------------------------------------------------ 221 status_t BDeskbar::GetItemInfo(const char *name, int32 *id) const 222 { 223 if (name == NULL) { 224 return(B_BAD_VALUE); 225 } 226 227 BMessage requestMessage(gGetItemInfoWhat); 228 BMessage replyMessage; 229 status_t result; 230 231 result = requestMessage.AddString("name", name); 232 if (result == B_OK) { 233 result = fMessenger->SendMessage(&requestMessage, &replyMessage); 234 if (result == B_OK) { 235 result = replyMessage.FindInt32("id", id); 236 } 237 } 238 return(result); 239 } 240 //------------------------------------------------------------------------------ 241 bool BDeskbar::HasItem(int32 id) const 242 { 243 BMessage requestMessage(gHasItemWhat); 244 BMessage replyMessage; 245 bool result = false; 246 247 if ((requestMessage.AddInt32("id", id) == B_OK) && 248 (fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK)) { 249 replyMessage.FindBool("exists", &result); 250 } 251 return(result); 252 } 253 //------------------------------------------------------------------------------ 254 bool BDeskbar::HasItem(const char *name) const 255 { 256 BMessage requestMessage(gHasItemWhat); 257 BMessage replyMessage; 258 bool result = false; 259 260 if ((requestMessage.AddString("name", name) == B_OK) && 261 (fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK)) { 262 replyMessage.FindBool("exists", &result); 263 } 264 return(result); 265 } 266 //------------------------------------------------------------------------------ 267 uint32 BDeskbar::CountItems(void) const 268 { 269 BMessage requestMessage(gCountItemsWhat); 270 BMessage replyMessage; 271 int32 result = 0; 272 273 if ((fMessenger->SendMessage(&requestMessage, &replyMessage) == B_OK) && 274 (replyMessage.what == 'rply')) { 275 replyMessage.FindInt32("count", &result); 276 } 277 return(static_cast<uint32>(result)); 278 } 279 //------------------------------------------------------------------------------ 280 status_t BDeskbar::AddItem(BView *archivableView, int32 *id) 281 { 282 BMessage requestMessage(gAddItemViewWhat); 283 BMessage viewMessage; 284 BMessage replyMessage; 285 status_t result; 286 287 result = archivableView->Archive(&viewMessage); 288 if (result == B_OK) { 289 result = requestMessage.AddMessage("view", &viewMessage); 290 if (result == B_OK) { 291 result = fMessenger->SendMessage(&requestMessage, &replyMessage); 292 if ((result == B_OK) && 293 (id != NULL)) { 294 result = replyMessage.FindInt32("id", id); 295 } 296 } 297 } 298 return(result); 299 } 300 //------------------------------------------------------------------------------ 301 status_t BDeskbar::AddItem(entry_ref *addon, int32 *id) 302 { 303 BMessage requestMessage(gAddItemViewWhat); 304 BMessage replyMessage; 305 status_t result; 306 307 result = requestMessage.AddRef("addon", addon); 308 if (result == B_OK) { 309 result = fMessenger->SendMessage(&requestMessage, &replyMessage); 310 if ((result == B_OK) && 311 (id != NULL)) { 312 result = replyMessage.FindInt32("id", id); 313 314 /* NOTE: I add this because the persistent state of the item 315 is not set by the Deskbar itself and it needs to be done somewhere. 316 In fact, telling the Deskbar about the addon ref is not enough and 317 adding this attribute is mandatory. 318 !! Deskbar seems to remove the attribute in RemoveItem though !! 319 */ 320 if (result == B_OK) { 321 BNode node(addon); 322 node.WriteAttr("be:deskbar_item_status", 323 B_STRING_TYPE, 0, "enabled", strlen("enabled")); 324 } 325 } 326 } 327 return(result); 328 } 329 //------------------------------------------------------------------------------ 330 status_t BDeskbar::RemoveItem(int32 id) 331 { 332 BMessage requestMessage(gRemoveItemWhat); 333 BMessage replyMessage; 334 status_t result; 335 336 result = requestMessage.AddInt32("id", id); 337 if (result == B_OK) { 338 result = fMessenger->SendMessage(&requestMessage, &replyMessage); 339 } 340 /* here R5 returns B_OK always (probably the result of SendMessage()) 341 * Deskbar itself also always return B_NO_REPLY, so ... 342 * here add some more checks for the future. 343 */ 344 if (result != B_OK) 345 return(result); 346 if (replyMessage.what == B_NO_REPLY) 347 return(B_OK); /* we can only speculate */ 348 result = B_ERROR; 349 replyMessage.FindInt32("error", &result); 350 return(result); 351 } 352 //------------------------------------------------------------------------------ 353 status_t BDeskbar::RemoveItem(const char *name) 354 { 355 BMessage requestMessage(gRemoveItemWhat); 356 BMessage replyMessage; 357 status_t result; 358 359 result = requestMessage.AddString("name", name); 360 if (result == B_OK) { 361 result = fMessenger->SendMessage(&requestMessage, &replyMessage); 362 } 363 /* same as above */ 364 if (result != B_OK) 365 return(result); 366 if (replyMessage.what == B_NO_REPLY) 367 return(B_OK); 368 result = B_ERROR; 369 replyMessage.FindInt32("error", &result); 370 return(result); 371 372 } 373 //------------------------------------------------------------------------------ 374 375 /* 376 * $Log $ 377 * 378 * $Id $ 379 * 380 */ 381