xref: /haiku/src/kits/interface/Deskbar.cpp (revision d5cd5d63ff0ad395989db6cf4841a64d5b545d1d)
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