Bug Summary

File:src/apps/deskbar/DeskbarMenu.cpp
Warning:line 201, column 3
Potential memory leak

Annotated Source Code

1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30trademarks of Be Incorporated in the United States and other countries. Other
31brand product names are registered trademarks or trademarks of their respective
32holders.
33All rights reserved.
34*/
35
36
37#include "DeskbarMenu.h"
38
39#include <Debug.h>
40#include <Bitmap.h>
41#include <Catalog.h>
42#include <Dragger.h>
43#include <Locale.h>
44#include <Menu.h>
45#include <MenuItem.h>
46#include <Roster.h>
47
48#include "BarApp.h"
49#include "BarView.h"
50#include "DeskbarUtils.h"
51#include "IconMenuItem.h"
52#include "MountMenu.h"
53#include "RecentItems.h"
54#include "StatusView.h"
55
56#include "tracker_private.h"
57
58#undef B_TRANSLATION_CONTEXT"DeskbarMenu"
59#define B_TRANSLATION_CONTEXT"DeskbarMenu" "DeskbarMenu"
60
61#define ROSTER_SIG"application/x-vnd.Be-ROST" "application/x-vnd.Be-ROST"
62
63#ifdef MOUNT_MENU_IN_DESKBAR1
64class DeskbarMountMenu : public BPrivate::MountMenu {
65public:
66 DeskbarMountMenu(const char* name);
67 virtual bool AddDynamicItem(add_state s);
68};
69#endif // MOUNT_MENU_IN_DESKBAR
70
71//#define SHOW_RECENT_FIND_ITEMS
72
73namespace BPrivate {
74 BMenu* TrackerBuildRecentFindItemsMenu(const char*);
75}
76
77using namespace BPrivate;
78
79
80// #pragma mark - TDeskbarMenu
81
82
83TDeskbarMenu::TDeskbarMenu(TBarView* barView)
84 :
85 BNavMenu("DeskbarMenu", B_REFS_RECEIVED, DefaultTarget()),
86 fAddState(kStart),
87 fBarView(barView)
88{
89}
90
91
92void
93TDeskbarMenu::AttachedToWindow()
94{
95 if (fBarView != NULL__null && fBarView->LockLooper()) {
96 if (fBarView->Dragging()) {
97 SetTypesList(fBarView->CachedTypesList());
98 SetTarget(BMessenger(fBarView));
99 SetTrackingHookDeep(this, fBarView->MenuTrackingHook,
100 fBarView->GetTrackingHookData());
101 fBarView->DragStart();
102 } else {
103 SetTypesList(NULL__null);
104 SetTarget(DefaultTarget());
105 SetTrackingHookDeep(this, NULL__null, NULL__null);
106 }
107
108 fBarView->UnlockLooper();
109 }
110
111 BNavMenu::AttachedToWindow();
112}
113
114
115void
116TDeskbarMenu::DetachedFromWindow()
117{
118 if (fBarView != NULL__null) {
119 BLooper* looper = fBarView->Looper();
120 if (looper != NULL__null && looper->Lock()) {
121 fBarView->DragStop();
122 looper->Unlock();
123 }
124 }
125
126 // don't call BNavMenu::DetachedFromWindow
127 // it sets the TypesList to NULL
128 BMenu::DetachedFromWindow();
129}
130
131
132bool
133TDeskbarMenu::StartBuildingItemList()
134{
135 RemoveItems(0, CountItems(), true);
136 fAddState = kStart;
137 return BNavMenu::StartBuildingItemList();
138}
139
140
141void
142TDeskbarMenu::DoneBuildingItemList()
143{
144 if (fItemList->CountItems() <= 0) {
145 BMenuItem* item
146 = new BMenuItem(B_TRANSLATE("<Deskbar folder is empty>")BLocaleRoster::Default()->GetCatalog()->GetString(("<Deskbar folder is empty>"
), "DeskbarMenu")
, 0);
147 item->SetEnabled(false);
148 AddItem(item);
149 } else
150 BNavMenu::DoneBuildingItemList();
151}
152
153
154bool
155TDeskbarMenu::AddNextItem()
156{
157 if (fAddState == kStart)
1
Assuming the condition is false
2
Taking false branch
158 return AddStandardDeskbarMenuItems();
159
160 TrackingHookData* data = fBarView->GetTrackingHookData();
161 if (fAddState == kAddingRecents) {
3
Assuming the condition is true
4
Taking true branch
162 static const char* recentTitle[] = {
163 B_TRANSLATE_MARK("Recent documents")("Recent documents"),
164 B_TRANSLATE_MARK("Recent folders")("Recent folders"),
165 B_TRANSLATE_MARK("Recent applications")("Recent applications")};
166 const int recentType[] = {kRecentDocuments, kRecentFolders,
167 kRecentApplications};
168 const int recentTypes = 3;
169 TRecentsMenu* recentItem[recentTypes];
170
171 bool enabled = false;
172
173 for (int i = 0; i < recentTypes; i++) {
5
Loop condition is true. Entering loop body
7
Loop condition is true. Entering loop body
10
Loop condition is true. Entering loop body
12
Loop condition is false. Execution continues on line 181
174 recentItem[i]
175 = new TRecentsMenu(B_TRANSLATE_NOCOLLECT(recentTitle[i])BLocaleRoster::Default()->GetCatalog()->GetString((recentTitle
[i]), "DeskbarMenu")
,
8
Memory is allocated
176 fBarView, recentType[i]);
177
178 if (recentItem[i])
6
Taking true branch
9
Taking true branch
11
Taking true branch
179 enabled |= recentItem[i]->RecentsEnabled();
180 }
181 if (enabled) {
13
Assuming 'enabled' is 0
14
Taking false branch
182 AddSeparatorItem();
183
184 for (int i = 0; i < recentTypes; i++) {
185 if (!recentItem[i])
186 continue;
187
188 if (recentItem[i]->RecentsEnabled()) {
189 recentItem[i]->SetTypesList(TypesList());
190 recentItem[i]->SetTarget(Target());
191 AddItem(recentItem[i]);
192 }
193
194 if (data && fBarView && fBarView->Dragging()) {
195 recentItem[i]->InitTrackingHook(data->fTrackingHook,
196 &data->fTarget, data->fDragMessage);
197 }
198 }
199 }
200
201 AddSeparatorItem();
15
Potential memory leak
202 fAddState = kAddingDeskbarMenu;
203 return true;
204 }
205
206 if (fAddState == kAddingDeskbarMenu) {
207 // keep reentering and adding items
208 // until this returns false
209 bool done = BNavMenu::AddNextItem();
210 BMenuItem* item = ItemAt(CountItems() - 1);
211 if (item) {
212 BNavMenu* menu = dynamic_cast<BNavMenu*>(item->Menu());
213 if (menu) {
214 if (data && fBarView->Dragging()) {
215 menu->InitTrackingHook(data->fTrackingHook,
216 &data->fTarget, data->fDragMessage);
217 } else
218 menu->InitTrackingHook(0, NULL__null, NULL__null);
219 }
220 }
221
222 if (!done)
223 fAddState = kDone;
224 return done;
225 }
226
227 return false;
228}
229
230
231bool
232TDeskbarMenu::AddStandardDeskbarMenuItems()
233{
234 bool dragging = false;
235 if (fBarView)
236 dragging = fBarView->Dragging();
237
238 BMenuItem* item;
239
240// One of them is used if HAIKU_DISTRO_COMPATIBILITY_OFFICIAL, and the other if
241// not. However, we want both of them to end up in the catalog, so we have to
242// make them visible to collectcatkeys in either case.
243B_TRANSLATE_MARK_VOID("About Haiku")
244B_TRANSLATE_MARK_VOID("About this system")
245
246 item = new BMenuItem(
247#ifdef HAIKU_DISTRO_COMPATIBILITY_OFFICIAL
248 B_TRANSLATE_NOCOLLECT("About Haiku")BLocaleRoster::Default()->GetCatalog()->GetString(("About Haiku"
), "DeskbarMenu")
249#else
250 B_TRANSLATE_NOCOLLECT("About this system")BLocaleRoster::Default()->GetCatalog()->GetString(("About this system"
), "DeskbarMenu")
251#endif
252 , new BMessage(kShowSplash));
253 item->SetEnabled(!dragging);
254 AddItem(item);
255
256 static const char* kFindMenuItemStr
257 = B_TRANSLATE_MARK("Find" B_UTF8_ELLIPSIS)("Find" "\xE2\x80\xA6");
258
259#ifdef SHOW_RECENT_FIND_ITEMS
260 item = new BMenuItem(
261 TrackerBuildRecentFindItemsMenu(kFindMenuItemStr),
262 new BMessage(kFindButton));
263#else
264 item = new BMenuItem(B_TRANSLATE_NOCOLLECT(kFindMenuItemStr)BLocaleRoster::Default()->GetCatalog()->GetString((kFindMenuItemStr
), "DeskbarMenu")
,
265 new BMessage(kFindButton));
266#endif
267 item->SetEnabled(!dragging);
268 AddItem(item);
269
270 item = new BMenuItem(B_TRANSLATE("Show replicants")BLocaleRoster::Default()->GetCatalog()->GetString(("Show replicants"
), "DeskbarMenu")
,
271 new BMessage(kToggleDraggers));
272 item->SetEnabled(!dragging);
273 item->SetMarked(BDragger::AreDraggersDrawn());
274 AddItem(item);
275
276 static const char* kMountMenuStr = B_TRANSLATE_MARK("Mount")("Mount");
277
278#ifdef MOUNT_MENU_IN_DESKBAR1
279 DeskbarMountMenu* mountMenu = new DeskbarMountMenu(
280 B_TRANSLATE_NOCOLLECT(kMountMenuStr)BLocaleRoster::Default()->GetCatalog()->GetString((kMountMenuStr
), "DeskbarMenu")
);
281 mountMenu->SetEnabled(!dragging);
282 AddItem(mountMenu);
283#endif
284
285 item = new BMenuItem(B_TRANSLATE("Deskbar preferences" B_UTF8_ELLIPSIS)BLocaleRoster::Default()->GetCatalog()->GetString(("Deskbar preferences"
"\xE2\x80\xA6"), "DeskbarMenu")
,
286 new BMessage(kConfigShow));
287 item->SetTarget(be_app);
288 AddItem(item);
289
290 AddSeparatorItem();
291
292 BMenu* shutdownMenu = new BMenu(B_TRANSLATE("Shutdown" B_UTF8_ELLIPSIS)BLocaleRoster::Default()->GetCatalog()->GetString(("Shutdown"
"\xE2\x80\xA6"), "DeskbarMenu")
);
293
294 item = new BMenuItem(B_TRANSLATE("Restart system")BLocaleRoster::Default()->GetCatalog()->GetString(("Restart system"
), "DeskbarMenu")
,
295 new BMessage(kRebootSystem));
296 item->SetEnabled(!dragging);
297 shutdownMenu->AddItem(item);
298
299 B_TRANSLATE_MARK_VOID("Suspend");
300
301#ifdef APM_SUPPORT
302 if (_kapm_control_(APM_CHECK_ENABLED) == B_OK((int)0)) {
303 item = new BMenuItem(B_TRANSLATE_NOCOLLECT("Suspend")BLocaleRoster::Default()->GetCatalog()->GetString(("Suspend"
), "DeskbarMenu")
,
304 new BMessage(kSuspendSystem));
305 item->SetEnabled(!dragging);
306 shutdownMenu->AddItem(item);
307 }
308#endif
309
310 item = new BMenuItem(B_TRANSLATE("Power off")BLocaleRoster::Default()->GetCatalog()->GetString(("Power off"
), "DeskbarMenu")
,
311 new BMessage(kShutdownSystem));
312 item->SetEnabled(!dragging);
313 shutdownMenu->AddItem(item);
314 shutdownMenu->SetFont(be_plain_font);
315
316 shutdownMenu->SetTargetForItems(be_app);
317 BMessage* message = new BMessage(kShutdownSystem);
318 message->AddBool("confirm", true);
319 AddItem(new BMenuItem(shutdownMenu, message));
320
321 fAddState = kAddingRecents;
322
323 return true;
324}
325
326
327void
328TDeskbarMenu::ClearMenuBuildingState()
329{
330 fAddState = kDone;
331 fMenuBuilt = false;
332 // force the menu to get rebuilt each time
333 BNavMenu::ClearMenuBuildingState();
334}
335
336
337void
338TDeskbarMenu::ResetTargets()
339{
340 // This method does not recurse into submenus
341 // and does not affect menu items in submenus.
342 // (e.g. "Restart System" and "Power Off")
343
344 BNavMenu::ResetTargets();
345
346 // if we are dragging, set the target to whatever was set
347 // else set it to the default (Tracker)
348 if (!fBarView->Dragging())
349 SetTarget(DefaultTarget());
350
351 // now set the target for the menuitems to the currently
352 // set target, which may or may not be tracker
353 SetTargetForItems(Target());
354
355 for (int32 i = 0; ; i++) {
356 BMenuItem* item = ItemAt(i);
357 if (item == NULL__null)
358 break;
359
360 if (item->Message()) {
361 switch (item->Message()->what) {
362 case kFindButton:
363 item->SetTarget(BMessenger(kTrackerSignature"application/x-vnd.Be-TRAK"));
364 break;
365
366 case kShowSplash:
367 case kToggleDraggers:
368 case kConfigShow:
369 case kConfigQuit:
370 case kAlwaysTop:
371 case kExpandNewTeams:
372 case kHideLabels:
373 case kResizeTeamIcons:
374 case kSortRunningApps:
375 case kTrackerFirst:
376 case kRebootSystem:
377 case kSuspendSystem:
378 case kShutdownSystem:
379 case kShowHideTime:
380 case kShowSeconds:
381 case kShowDayOfWeek:
382 case kShowTimeZone:
383 case kGetClockSettings:
384 item->SetTarget(be_app);
385 break;
386 }
387 }
388 }
389}
390
391
392BPoint
393TDeskbarMenu::ScreenLocation()
394{
395 bool vertical = fBarView->Vertical();
396 int32 expando = (fBarView->State() == kExpandoState);
397 BPoint point;
398
399 BRect rect = Supermenu()->Bounds();
400 Supermenu()->ConvertToScreen(&rect);
401
402 if (expando && vertical && fBarView->Left()) {
403 PRINT(("Left\n"))_debugPrintf ("Left\n");
404 point = rect.RightTop() + BPoint(0, 3);
405 } else if (expando && vertical && !fBarView->Left()) {
406 PRINT(("Right\n"))_debugPrintf ("Right\n");
407 point = rect.LeftTop() - BPoint(Bounds().Width(), 0) + BPoint(0, 3);
408 } else
409 point = BMenu::ScreenLocation();
410
411 return point;
412}
413
414
415/*static*/
416BMessenger
417TDeskbarMenu::DefaultTarget()
418{
419 // if Tracker is not available we target the BarApp
420 BMessenger target(kTrackerSignature"application/x-vnd.Be-TRAK");
421 if (target.IsValid())
422 return target;
423
424 return BMessenger(be_app);
425}
426
427
428// #pragma mark -
429
430
431TRecentsMenu::TRecentsMenu(const char* name, TBarView* bar, int32 which,
432 const char* signature, entry_ref* appRef)
433 : BNavMenu(name, B_REFS_RECEIVED, TDeskbarMenu::DefaultTarget()),
434 fWhich(which),
435 fAppRef(NULL__null),
436 fSignature(NULL__null),
437 fRecentsCount(0),
438 fRecentsEnabled(false),
439 fItemIndex(0),
440 fBarView(bar)
441{
442 TBarApp* app = dynamic_cast<TBarApp*>(be_app);
443 if (app == NULL__null)
444 return;
445
446 switch (which) {
447 case kRecentDocuments:
448 fRecentsCount = app->Settings()->recentDocsCount;
449 fRecentsEnabled = app->Settings()->recentDocsEnabled;
450 break;
451 case kRecentApplications:
452 fRecentsCount = app->Settings()->recentAppsCount;
453 fRecentsEnabled = app->Settings()->recentAppsEnabled;
454 break;
455 case kRecentAppDocuments:
456 fRecentsCount = app->Settings()->recentDocsCount;
457 fRecentsEnabled = app->Settings()->recentDocsEnabled;
458 if (signature != NULL__null)
459 fSignature = strdup(signature);
460 if (appRef != NULL__null)
461 fAppRef = new entry_ref(*appRef);
462 break;
463 case kRecentFolders:
464 fRecentsCount = app->Settings()->recentFoldersCount;
465 fRecentsEnabled = app->Settings()->recentFoldersEnabled;
466 break;
467 }
468}
469
470
471TRecentsMenu::~TRecentsMenu()
472{
473 delete fAppRef;
474 free(fSignature);
475}
476
477
478void
479TRecentsMenu::DetachedFromWindow()
480{
481 // BNavMenu::DetachedFromWindow sets the TypesList to NULL
482 BMenu::DetachedFromWindow();
483}
484
485
486bool
487TRecentsMenu::StartBuildingItemList()
488{
489 RemoveItems(0, CountItems(), true);
490
491 // !! note: don't call inherited from here
492 // the navref is not set for this menu
493 // but it still needs to be a draggable navmenu
494 // simply return true so that AddNextItem is called
495 //
496 // return BNavMenu::StartBuildingItemList();
497 return true;
498}
499
500
501bool
502TRecentsMenu::AddNextItem()
503{
504 if (fRecentsCount > 0 && fRecentsEnabled && AddRecents(fRecentsCount))
505 return true;
506
507 fItemIndex = 0;
508 return false;
509}
510
511
512bool
513TRecentsMenu::AddRecents(int32 count)
514{
515 if (fItemIndex == 0) {
516 fRecentList.MakeEmpty();
517 BRoster roster;
518
519 switch (fWhich) {
520 case kRecentDocuments:
521 roster.GetRecentDocuments(&fRecentList, count);
522 break;
523 case kRecentApplications:
524 roster.GetRecentApps(&fRecentList, count);
525 break;
526 case kRecentAppDocuments:
527 roster.GetRecentDocuments(&fRecentList, count, NULL__null,
528 fSignature);
529 break;
530 case kRecentFolders:
531 roster.GetRecentFolders(&fRecentList, count);
532 break;
533 default:
534 return false;
535 }
536 }
537
538 for (;;) {
539 entry_ref ref;
540 if (fRecentList.FindRef("refs", fItemIndex++, &ref) != B_OK((int)0))
541 break;
542
543 if (ref.name && strlen(ref.name) > 0) {
544 Model model(&ref, true);
545
546 if (fWhich != kRecentApplications) {
547 BMessage* message = new BMessage(B_REFS_RECEIVED);
548 if (fWhich == kRecentAppDocuments) {
549 // add application as handler
550 message->AddRef("handler", fAppRef);
551 }
552
553 ModelMenuItem* item = BNavMenu::NewModelItem(&model,
554 message, Target(), false, NULL__null, TypesList());
555
556 if (item)
557 AddItem(item);
558 } else {
559 // The application items expand to a list of recent documents
560 // for that application - so they must be handled extra
561 BFile file(&ref, B_READ_ONLY0x0000);
562 char signature[B_MIME_TYPE_LENGTH(((256) - 1) - 15)];
563
564 BAppFileInfo appInfo(&file);
565 if (appInfo.InitCheck() != B_OK((int)0)
566 || appInfo.GetSignature(signature) != B_OK((int)0))
567 continue;
568
569 ModelMenuItem* item = NULL__null;
570 BMessage doc;
571 be_roster->GetRecentDocuments(&doc, 1, NULL__null, signature);
572 // ToDo: check if the documents do exist at all to
573 // avoid the creation of the submenu.
574
575 if (doc.CountNames(B_REF_TYPE) > 0) {
576 // create recents menu that will contain the recent docs of
577 // this app
578 TRecentsMenu* docs = new TRecentsMenu(model.Name(),
579 fBarView, kRecentAppDocuments, signature, &ref);
580 docs->SetTypesList(TypesList());
581 docs->SetTarget(Target());
582
583 item = new ModelMenuItem(&model, docs);
584 } else
585 item = new ModelMenuItem(&model, model.Name(), NULL__null);
586
587 if (item) {
588 // add refs-message so that the recent app can be launched
589 BMessage* msg = new BMessage(B_REFS_RECEIVED);
590 msg->AddRef("refs", &ref);
591 item->SetMessage(msg);
592 item->SetTarget(Target());
593
594 AddItem(item);
595 }
596 }
597
598 // return true so that we know to reenter this list
599 return true;
600 }
601 }
602
603 // return false if we are done with this list
604 return false;
605}
606
607
608void
609TRecentsMenu::DoneBuildingItemList()
610{
611 // !! note: don't call inherited here
612 // the object list is not built
613 // and this list does not need to be sorted
614 // BNavMenu::DoneBuildingItemList();
615
616 if (CountItems() > 0)
617 SetTargetForItems(Target());
618}
619
620
621void
622TRecentsMenu::ClearMenuBuildingState()
623{
624 fMenuBuilt = false;
625 BNavMenu::ClearMenuBuildingState();
626}
627
628
629void
630TRecentsMenu::ResetTargets()
631{
632 BNavMenu::ResetTargets();
633
634 // if we are dragging, set the target to whatever was set
635 // else set it to the default (Tracker)
636 if (!fBarView->Dragging())
637 SetTarget(TDeskbarMenu::DefaultTarget());
638
639 // now set the target for the menuitems to the currently
640 // set target, which may or may not be tracker
641 SetTargetForItems(Target());
642}
643
644
645// #pragma mark - DeskbarMountMenu
646
647
648#ifdef MOUNT_MENU_IN_DESKBAR1
649DeskbarMountMenu::DeskbarMountMenu(const char* name)
650 : BPrivate::MountMenu(name)
651{
652 SetFont(be_plain_font);
653}
654
655
656bool
657DeskbarMountMenu::AddDynamicItem(add_state s)
658{
659 BPrivate::MountMenu::AddDynamicItem(s);
660
661 SetTargetForItems(BMessenger(kTrackerSignature"application/x-vnd.Be-TRAK"));
662
663 return false;
664}
665#endif // MOUNT_MENU_IN_DESKBAR