xref: /haiku/src/servers/registrar/RecentApps.cpp (revision dd2a1e350b303b855a50fd64e6cb55618be1ae6a)
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 */
50 RecentApps::RecentApps()
51 {
52 }
53 
54 
55 /*!	\brief Frees all resources associated with the object.
56 
57 	Currently does nothing.
58 */
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
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
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
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
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
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
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
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