Bug Summary

File:src/servers/notification/NotificationWindow.cpp
Warning:line 208, column 6
Potential leak of memory pointed to by 'view'

Annotated Source Code

1/*
2 * Copyright 2010, Haiku, Inc. All Rights Reserved.
3 * Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
4 * Copyright 2004-2008, Michael Davidson. All Rights Reserved.
5 * Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
6 * Distributed under the terms of the MIT License.
7 *
8 * Authors:
9 * Michael Davidson, slaad@bong.com.au
10 * Mikael Eiman, mikael@eiman.tv
11 * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
12 */
13#include "NotificationWindow.h"
14
15#include <algorithm>
16
17#include <Alert.h>
18#include <Application.h>
19#include <Catalog.h>
20#include <Deskbar.h>
21#include <Directory.h>
22#include <File.h>
23#include <FindDirectory.h>
24#include <GroupLayout.h>
25#include <NodeMonitor.h>
26#include <Notifications.h>
27#include <Path.h>
28#include <PropertyInfo.h>
29
30#include "AppGroupView.h"
31#include "AppUsage.h"
32
33
34#undef B_TRANSLATION_CONTEXT"NotificationWindow"
35#define B_TRANSLATION_CONTEXT"NotificationWindow" "NotificationWindow"
36
37
38property_info main_prop_list[] = {
39 {"message", {B_GET_PROPERTY, 0}, {B_INDEX_SPECIFIER, 0},
40 "get a message"},
41 {"message", {B_COUNT_PROPERTIES, 0}, {B_DIRECT_SPECIFIER, 0},
42 "count messages"},
43 {"message", {B_CREATE_PROPERTY, 0}, {B_DIRECT_SPECIFIER, 0},
44 "create a message"},
45 {"message", {B_SET_PROPERTY, 0}, {B_INDEX_SPECIFIER, 0},
46 "modify a message"},
47 {0}
48};
49
50
51const float kCloseSize = 6;
52const float kExpandSize = 8;
53const float kPenSize = 1;
54const float kEdgePadding = 2;
55const float kSmallPadding = 2;
56
57NotificationWindow::NotificationWindow()
58 :
59 BWindow(BRect(0, 0, -1, -1), B_TRANSLATE_MARK("Notification")("Notification"),
60 B_BORDERED_WINDOW_LOOK, B_FLOATING_ALL_WINDOW_FEEL, B_AVOID_FRONT
61 | B_AVOID_FOCUS | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE
62 | B_NOT_RESIZABLE | B_NOT_MOVABLE | B_AUTO_UPDATE_SIZE_LIMITS,
63 B_ALL_WORKSPACES0xffffffff)
64{
65 SetLayout(new BGroupLayout(B_VERTICAL, 0));
66
67 _LoadSettings(true);
68
69 // Start the message loop
70 Hide();
71 Show();
72}
73
74
75NotificationWindow::~NotificationWindow()
76{
77 appfilter_t::iterator aIt;
78 for (aIt = fAppFilters.begin(); aIt != fAppFilters.end(); aIt++)
79 delete aIt->second;
80}
81
82
83bool
84NotificationWindow::QuitRequested()
85{
86 appview_t::iterator aIt;
87 for (aIt = fAppViews.begin(); aIt != fAppViews.end(); aIt++) {
88 aIt->second->RemoveSelf();
89 delete aIt->second;
90 }
91
92 BMessenger(be_app).SendMessage(B_QUIT_REQUESTED);
93 return BWindow::QuitRequested();
94}
95
96
97void
98NotificationWindow::WorkspaceActivated(int32 /*workspace*/, bool active)
99{
100 // Ensure window is in the correct position
101 if (active)
102 SetPosition();
103}
104
105
106void
107NotificationWindow::FrameResized(float width, float height)
108{
109 SetPosition();
110}
111
112
113void
114NotificationWindow::ScreenChanged(BRect frame, color_space mode)
115{
116 SetPosition();
117}
118
119
120void
121NotificationWindow::MessageReceived(BMessage* message)
122{
123 switch (message->what) {
1
Control jumps to 'case 1853059949:' at line 154
124 case B_NODE_MONITOR:
125 {
126 _LoadSettings();
127 break;
128 }
129 case B_COUNT_PROPERTIES:
130 {
131 BMessage reply(B_REPLY);
132 BMessage specifier;
133 const char* property = NULL__null;
134 bool messageOkay = true;
135
136 if (message->FindMessage("specifiers", 0, &specifier) != B_OK((int)0))
137 messageOkay = false;
138 if (specifier.FindString("property", &property) != B_OK((int)0))
139 messageOkay = false;
140 if (strcmp(property, "message") != 0)
141 messageOkay = false;
142
143 if (messageOkay)
144 reply.AddInt32("result", fViews.size());
145 else {
146 reply.what = B_MESSAGE_NOT_UNDERSTOOD;
147 reply.AddInt32("error", B_ERROR(-1));
148 }
149
150 message->SendReply(&reply);
151 break;
152 }
153 case B_CREATE_PROPERTY:
154 case kNotificationMessage:
155 {
156 BMessage reply(B_REPLY);
157 BNotification* notification = new BNotification(message);
158
159 if (notification->InitCheck() == B_OK((int)0)) {
2
Assuming the condition is true
3
Taking true branch
160 bigtime_t timeout;
161 if (message->FindInt64("timeout", &timeout) != B_OK((int)0))
4
Assuming the condition is false
5
Taking false branch
162 timeout = -1;
163 BMessenger messenger = message->ReturnAddress();
164 app_info info;
165
166 if (messenger.IsValid())
6
Assuming the condition is false
7
Taking false branch
167 be_roster->GetRunningAppInfo(messenger.Team(), &info);
168 else
169 be_roster->GetAppInfo("application/x-vnd.Be-SHEL", &info);
170
171 NotificationView* view = new NotificationView(this,
8
Memory is allocated
172 notification, timeout);
173
174 bool allow = false;
175 appfilter_t::iterator it = fAppFilters.find(info.signature);
176
177 if (it == fAppFilters.end()) {
9
Assuming the condition is false
10
Taking false branch
178 AppUsage* appUsage = new AppUsage(notification->Group(),
179 true);
180
181 appUsage->Allowed(notification->Title(),
182 notification->Type());
183 fAppFilters[info.signature] = appUsage;
184 allow = true;
185 } else {
186 allow = it->second->Allowed(notification->Title(),
187 notification->Type());
188 }
189
190 if (allow) {
11
Assuming 'allow' is 0
12
Taking false branch
191 BString groupName(notification->Group());
192 appview_t::iterator aIt = fAppViews.find(groupName);
193 AppGroupView* group = NULL__null;
194 if (aIt == fAppViews.end()) {
195 group = new AppGroupView(this,
196 groupName == "" ? NULL__null : groupName.String());
197 fAppViews[groupName] = group;
198 GetLayout()->AddView(group);
199 } else
200 group = aIt->second;
201
202 group->AddInfo(view);
203
204 _ShowHide();
205
206 reply.AddInt32("error", B_OK((int)0));
207 } else
208 reply.AddInt32("error", B_NOT_ALLOWED((-2147483647 - 1) + 15));
13
Potential leak of memory pointed to by 'view'
209 } else {
210 reply.what = B_MESSAGE_NOT_UNDERSTOOD;
211 reply.AddInt32("error", B_ERROR(-1));
212 }
213
214 message->SendReply(&reply);
215 break;
216 }
217 case kRemoveView:
218 {
219 NotificationView* view = NULL__null;
220 if (message->FindPointer("view", (void**)&view) != B_OK((int)0))
221 return;
222
223 views_t::iterator it = find(fViews.begin(), fViews.end(), view);
224
225 if (it != fViews.end())
226 fViews.erase(it);
227 break;
228 }
229 case kRemoveGroupView:
230 {
231 AppGroupView* view = NULL__null;
232 if (message->FindPointer("view", (void**)&view) != B_OK((int)0))
233 return;
234
235 // It's possible that between sending this message, and us receiving
236 // it, the view has become used again, in which case we shouldn't
237 // delete it.
238 if (view->HasChildren())
239 return;
240
241 // this shouldn't happen
242 if (fAppViews.erase(view->Group()) < 1)
243 break;
244
245 view->RemoveSelf();
246 delete view;
247
248 _ShowHide();
249 break;
250 }
251 default:
252 BWindow::MessageReceived(message);
253 }
254}
255
256
257BHandler*
258NotificationWindow::ResolveSpecifier(BMessage* msg, int32 index,
259 BMessage* spec, int32 form, const char* prop)
260{
261 BPropertyInfo prop_info(main_prop_list);
262 BHandler* handler = NULL__null;
263
264 if (strcmp(prop,"message") == 0) {
265 switch (msg->what) {
266 case B_CREATE_PROPERTY:
267 {
268 msg->PopSpecifier();
269 handler = this;
270 break;
271 }
272 case B_SET_PROPERTY:
273 case B_GET_PROPERTY:
274 {
275 int32 i;
276
277 if (spec->FindInt32("index", &i) != B_OK((int)0))
278 i = -1;
279
280 if (i >= 0 && i < (int32)fViews.size()) {
281 msg->PopSpecifier();
282 handler = fViews[i];
283 } else
284 handler = NULL__null;
285 break;
286 }
287 case B_COUNT_PROPERTIES:
288 msg->PopSpecifier();
289 handler = this;
290 break;
291 default:
292 break;
293 }
294 }
295
296 if (!handler)
297 handler = BWindow::ResolveSpecifier(msg, index, spec, form, prop);
298
299 return handler;
300}
301
302
303icon_size
304NotificationWindow::IconSize()
305{
306 return fIconSize;
307}
308
309
310int32
311NotificationWindow::Timeout()
312{
313 return fTimeout;
314}
315
316
317float
318NotificationWindow::Width()
319{
320 return fWidth;
321}
322
323
324void
325NotificationWindow::_ShowHide()
326{
327 if (fAppViews.empty() && !IsHidden()) {
328 Hide();
329 return;
330 }
331
332 if (IsHidden()) {
333 SetPosition();
334 Show();
335 }
336}
337
338
339void
340NotificationWindow::NotificationViewSwapped(NotificationView* stale,
341 NotificationView* fresh)
342{
343 views_t::iterator it = find(fViews.begin(), fViews.end(), stale);
344
345 if (it != fViews.end())
346 *it = fresh;
347}
348
349
350void
351NotificationWindow::SetPosition()
352{
353 Layout(true);
354
355 BRect bounds = DecoratorFrame();
356 float width = Bounds().Width() + 1;
357 float height = Bounds().Height() + 1;
358
359 float leftOffset = Frame().left - bounds.left;
360 float topOffset = Frame().top - bounds.top + 1;
361 float rightOffset = bounds.right - Frame().right;
362 float bottomOffset = bounds.bottom - Frame().bottom;
363 // Size of the borders around the window
364
365 float x = Frame().left, y = Frame().top;
366 // If we can't guess, don't move...
367
368 BDeskbar deskbar;
369 BRect frame = deskbar.Frame();
370
371 switch (deskbar.Location()) {
372 case B_DESKBAR_TOP:
373 // Put it just under, top right corner
374 y = frame.bottom + topOffset;
375 x = frame.right - width + rightOffset;
376 break;
377 case B_DESKBAR_BOTTOM:
378 // Put it just above, lower left corner
379 y = frame.top - height - bottomOffset;
380 x = frame.right - width + rightOffset;
381 break;
382 case B_DESKBAR_RIGHT_TOP:
383 x = frame.left - width - rightOffset;
384 y = frame.top - topOffset + 1;
385 break;
386 case B_DESKBAR_LEFT_TOP:
387 x = frame.right + leftOffset;
388 y = frame.top - topOffset + 1;
389 break;
390 case B_DESKBAR_RIGHT_BOTTOM:
391 y = frame.bottom - height + bottomOffset;
392 x = frame.left - width - rightOffset;
393 break;
394 case B_DESKBAR_LEFT_BOTTOM:
395 y = frame.bottom - height + bottomOffset;
396 x = frame.right + leftOffset;
397 break;
398 default:
399 break;
400 }
401
402 MoveTo(x, y);
403}
404
405
406void
407NotificationWindow::_LoadSettings(bool startMonitor)
408{
409 BPath path;
410 BMessage settings;
411
412 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK((int)0))
413 return;
414
415 path.Append(kSettingsFile);
416
417 BFile file(path.Path(), B_READ_ONLY0x0000);
418 settings.Unflatten(&file);
419
420 _LoadGeneralSettings(settings);
421 _LoadDisplaySettings(settings);
422 _LoadAppFilters(settings);
423
424 if (startMonitor) {
425 node_ref nref;
426 BEntry entry(path.Path());
427 entry.GetNodeRef(&nref);
428
429 if (watch_node(&nref, B_WATCH_ALL, BMessenger(this)) != B_OK((int)0)) {
430 BAlert* alert = new BAlert(B_TRANSLATE("Warning")BLocaleRoster::Default()->GetCatalog()->GetString(("Warning"
), "NotificationWindow")
,
431 B_TRANSLATE("Couldn't start general settings monitor.\n"BLocaleRoster::Default()->GetCatalog()->GetString(("Couldn't start general settings monitor.\n"
"Live filter changes disabled."), "NotificationWindow")
432 "Live filter changes disabled.")BLocaleRoster::Default()->GetCatalog()->GetString(("Couldn't start general settings monitor.\n"
"Live filter changes disabled."), "NotificationWindow")
, B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "NotificationWindow")
);
433 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
434 alert->Go();
435 }
436 }
437}
438
439
440void
441NotificationWindow::_LoadAppFilters(BMessage& settings)
442{
443 type_code type;
444 int32 count = 0;
445
446 if (settings.GetInfo("app_usage", &type, &count) != B_OK((int)0))
447 return;
448
449 for (int32 i = 0; i < count; i++) {
450 AppUsage* app = new AppUsage();
451 settings.FindFlat("app_usage", i, app);
452 fAppFilters[app->Name()] = app;
453 }
454}
455
456
457void
458NotificationWindow::_LoadGeneralSettings(BMessage& settings)
459{
460 bool shouldRun;
461 if (settings.FindBool(kAutoStartName, &shouldRun) == B_OK((int)0)) {
462 if (shouldRun == false) {
463 // We should not start. Quit the app!
464 be_app_messenger.SendMessage(B_QUIT_REQUESTED);
465 }
466 }
467 if (settings.FindInt32(kTimeoutName, &fTimeout) != B_OK((int)0))
468 fTimeout = kDefaultTimeout;
469
470 // Notify the view about the change
471 views_t::iterator it;
472 for (it = fViews.begin(); it != fViews.end(); ++it) {
473 NotificationView* view = (*it);
474 view->Invalidate();
475 }
476}
477
478
479void
480NotificationWindow::_LoadDisplaySettings(BMessage& settings)
481{
482 int32 setting;
483
484 if (settings.FindFloat(kWidthName, &fWidth) != B_OK((int)0))
485 fWidth = kDefaultWidth;
486 GetLayout()->SetExplicitMaxSize(BSize(fWidth, B_SIZE_UNSET));
487 GetLayout()->SetExplicitMinSize(BSize(fWidth, B_SIZE_UNSET));
488
489 if (settings.FindInt32(kIconSizeName, &setting) != B_OK((int)0))
490 fIconSize = kDefaultIconSize;
491 else
492 fIconSize = (icon_size)setting;
493
494 // Notify the view about the change
495 views_t::iterator it;
496 for (it = fViews.begin(); it != fViews.end(); ++it) {
497 NotificationView* view = (*it);
498 view->Invalidate();
499 }
500}