1 /*
2 * Copyright 2001-2009, Haiku Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Tyler Dauwalder
7 * Ingo Weinhold, bonefish@users.sf.net
8 * Axel Dörfler, axeld@pinc-software.de
9 */
10
11
12 //! Recently launched apps list
13
14
15 #include "RecentApps.h"
16
17 #include <tracker_private.h>
18
19 #include <AppFileInfo.h>
20 #include <Entry.h>
21 #include <File.h>
22 #include <Message.h>
23 #include <Mime.h>
24 #include <Roster.h>
25 #include <storage_support.h>
26
27 #include <strings.h>
28
29 #include "Debug.h"
30
31
32 /*! \class RecentApps
33 \brief Manages the roster's list of recently launched applications
34
35 */
36
37
38 /*! \var std::list<std::string> RecentApps::fAppList
39 \brief The list of app sigs, most recent first
40
41 The signatures are expected to be stored all lowercase, as MIME
42 signatures are case-independent.
43 */
44
45
46 /*! \brief Creates a new list.
47
48 The list is initially empty.
49 */
RecentApps()50 RecentApps::RecentApps()
51 {
52 }
53
54
55 /*! \brief Frees all resources associated with the object.
56
57 Currently does nothing.
58 */
~RecentApps()59 RecentApps::~RecentApps()
60 {
61 }
62
63
64 /*! \brief Places the app with the given signature at the front of
65 the recent apps list.
66
67 If the app already exists elsewhere in the list, that item is
68 removed so only one instance exists in the list at any time.
69
70 \param appSig The application's signature
71 \param appFlags The application's flags. If \a appFlags contains
72 either \c B_ARGV_ONLY or \c B_BACKGROUND_APP, the
73 application is \b not added to the list (but \c B_OK
74 is still returned).
75 \return
76 - \c B_OK: success (even if the app was not added due to appFlags)
77 - error code: failure
78 */
79 status_t
Add(const char * appSig,int32 appFlags)80 RecentApps::Add(const char *appSig, int32 appFlags)
81 {
82 if (appSig == NULL)
83 return B_BAD_VALUE;
84
85 // don't add background apps, as well as Tracker and Deskbar to the list
86 // of recent apps
87 if (!strcasecmp(appSig, kTrackerSignature)
88 || !strcasecmp(appSig, kDeskbarSignature)
89 || (appFlags & (B_ARGV_ONLY | B_BACKGROUND_APP)) != 0)
90 return B_OK;
91
92 // Remove any previous instance
93 std::list<std::string>::iterator i;
94 for (i = fAppList.begin(); i != fAppList.end(); i++) {
95 if (!strcasecmp((*i).c_str(), appSig)) {
96 fAppList.erase(i);
97 break;
98 }
99 }
100
101 try {
102 // Add to the front
103 fAppList.push_front(appSig);
104 } catch (...) {
105 return B_NO_MEMORY;
106 }
107
108 int32 remove = fAppList.size() - kMaxRecentApps;
109 while (remove > 0) {
110 fAppList.pop_back();
111 remove--;
112 }
113
114 return B_OK;
115 }
116
117
118 /*! \brief Adds the signature of the application referred to by \a ref at
119 the front of the recent apps list.
120
121 The entry is checked for a BEOS:APP_SIG attribute. If that fails, the
122 app's resources are checked. If no signature can be found, the call
123 fails.
124 */
125 status_t
Add(const entry_ref * ref,int32 appFlags)126 RecentApps::Add(const entry_ref *ref, int32 appFlags)
127 {
128 if (ref == NULL)
129 return B_BAD_VALUE;
130
131 BFile file;
132 BAppFileInfo info;
133 char signature[B_MIME_TYPE_LENGTH];
134
135 status_t err = file.SetTo(ref, B_READ_ONLY);
136 if (!err)
137 err = info.SetTo(&file);
138 if (!err)
139 err = info.GetSignature(signature);
140 if (!err)
141 err = Add(signature, appFlags);
142 return err;
143 }
144
145
146 /*! \brief Returns the first \a maxCount recent apps in the \c BMessage
147 pointed to by \a list.
148
149 The message is cleared first, and \c entry_refs for the the apps are
150 stored in the \c "refs" field of the message (\c B_REF_TYPE).
151
152 If there are fewer than \a maxCount items in the list, the entire
153 list is returned.
154
155 Since BRoster::GetRecentApps() returns \c void, the message pointed
156 to by \a list is simply cleared if maxCount is invalid (i.e. <= 0).
157 */
158 status_t
Get(int32 maxCount,BMessage * list)159 RecentApps::Get(int32 maxCount, BMessage *list)
160 {
161 if (list == NULL)
162 return B_BAD_VALUE;
163
164 // Clear
165 list->MakeEmpty();
166
167 // Fill
168 std::list<std::string>::iterator item;
169 status_t status = B_OK;
170 int counter = 0;
171 for (item = fAppList.begin();
172 status == B_OK && counter < maxCount && item != fAppList.end();
173 counter++, item++) {
174 entry_ref ref;
175 if (GetRefForApp(item->c_str(), &ref) == B_OK)
176 status = list->AddRef("refs", &ref);
177 else {
178 D(PRINT("WARNING: RecentApps::Get(): No ref found for app '%s'\n",
179 item->c_str()));
180 }
181 }
182
183 return status;
184 }
185
186
187 /*! \brief Clears the list of recently launched apps
188 */
189 status_t
Clear()190 RecentApps::Clear()
191 {
192 fAppList.clear();
193 return B_OK;
194 }
195
196
197 /*! \brief Dumps the the current list of apps to stdout.
198 */
199 status_t
Print()200 RecentApps::Print()
201 {
202 std::list<std::string>::iterator item;
203 int counter = 1;
204 for (item = fAppList.begin(); item != fAppList.end(); item++) {
205 printf("%d: '%s'\n", counter++, item->c_str());
206 }
207 return B_OK;
208 }
209
210
211 /*! \brief Outputs a textual representation of the current recent
212 apps list to the given file stream.
213
214 */
215 status_t
Save(FILE * file)216 RecentApps::Save(FILE* file)
217 {
218 status_t error = file ? B_OK : B_BAD_VALUE;
219 if (!error) {
220 fprintf(file, "# Recent applications\n");
221 std::list<std::string>::iterator item;
222 for (item = fAppList.begin(); item != fAppList.end(); item++) {
223 fprintf(file, "RecentApp %s\n", item->c_str());
224 }
225 fprintf(file, "\n");
226 }
227 return error;
228 }
229
230
231 /*! \brief Fetches an \c entry_ref for the application with the
232 given signature.
233
234 First the MIME database is checked for a matching application type
235 with a valid app hint attribute. If that fails, a query is established
236 to track down such an application, if there is one available.
237 */
238 status_t
GetRefForApp(const char * appSig,entry_ref * result)239 RecentApps::GetRefForApp(const char *appSig, entry_ref *result)
240 {
241 if (appSig == NULL || result == NULL)
242 return B_BAD_VALUE;
243
244 // We'll use BMimeType to check for the app hint, since I'm lazy
245 // and Ingo's on vacation :-P :-)
246 BMimeType mime(appSig);
247 status_t err = mime.InitCheck();
248 if (!err)
249 err = mime.GetAppHint(result);
250 return err;
251 }
252
253