xref: /haiku/src/servers/registrar/RecentApps.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
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 	return B_OK;
109 }
110 
111 
112 /*! \brief Adds the signature of the application referred to by \a ref at
113 	the front of the recent apps list.
114 
115 	The entry is checked for a BEOS:APP_SIG attribute. If that fails, the
116 	app's resources are checked. If no signature can be found, the call
117 	fails.
118 */
119 status_t
120 RecentApps::Add(const entry_ref *ref, int32 appFlags)
121 {
122 	if (ref == NULL)
123 		return B_BAD_VALUE;
124 
125 	BFile file;
126 	BAppFileInfo info;
127 	char signature[B_MIME_TYPE_LENGTH];
128 
129 	status_t err = file.SetTo(ref, B_READ_ONLY);
130 	if (!err)
131 		err = info.SetTo(&file);
132 	if (!err)
133 		err = info.GetSignature(signature);
134 	if (!err)
135 		err = Add(signature, appFlags);
136 	return err;
137 }
138 
139 
140 /*! \brief Returns the first \a maxCount recent apps in the \c BMessage
141 	pointed to by \a list.
142 
143 	The message is cleared first, and \c entry_refs for the the apps are
144 	stored in the \c "refs" field of the message (\c B_REF_TYPE).
145 
146 	If there are fewer than \a maxCount items in the list, the entire
147 	list is returned.
148 
149 	Since BRoster::GetRecentApps() returns \c void, the message pointed
150 	to by \a list is simply cleared if maxCount is invalid (i.e. <= 0).
151 */
152 status_t
153 RecentApps::Get(int32 maxCount, BMessage *list)
154 {
155 	if (list == NULL)
156 		return B_BAD_VALUE;
157 
158 	// Clear
159 	list->MakeEmpty();
160 
161 	// Fill
162 	std::list<std::string>::iterator item;
163 	status_t status = B_OK;
164 	int counter = 0;
165 	for (item = fAppList.begin();
166 			status == B_OK && counter < maxCount && item != fAppList.end();
167 			counter++, item++) {
168 		entry_ref ref;
169 		if (GetRefForApp(item->c_str(), &ref) == B_OK)
170 			status = list->AddRef("refs", &ref);
171 		else {
172 			D(PRINT("WARNING: RecentApps::Get(): No ref found for app '%s'\n",
173 				item->c_str()));
174 		}
175 	}
176 
177 	return status;
178 }
179 
180 
181 /*! \brief Clears the list of recently launched apps
182 */
183 status_t
184 RecentApps::Clear()
185 {
186 	fAppList.clear();
187 	return B_OK;
188 }
189 
190 
191 /*! \brief Dumps the the current list of apps to stdout.
192 */
193 status_t
194 RecentApps::Print()
195 {
196 	std::list<std::string>::iterator item;
197 	int counter = 1;
198 	for (item = fAppList.begin(); item != fAppList.end(); item++) {
199 		printf("%d: '%s'\n", counter++, item->c_str());
200 	}
201 	return B_OK;
202 }
203 
204 
205 /*! \brief Outputs a textual representation of the current recent
206 	apps list to the given file stream.
207 
208 */
209 status_t
210 RecentApps::Save(FILE* file)
211 {
212 	status_t error = file ? B_OK : B_BAD_VALUE;
213 	if (!error) {
214 		fprintf(file, "# Recent applications\n");
215 		std::list<std::string>::iterator item;
216 		for (item = fAppList.begin(); item != fAppList.end(); item++) {
217 			fprintf(file, "RecentApp %s\n", item->c_str());
218 		}
219 		fprintf(file, "\n");
220 	}
221 	return error;
222 }
223 
224 
225 /*! \brief Fetches an \c entry_ref for the application with the
226 	given signature.
227 
228 	First the MIME database is checked for a matching application type
229 	with a valid app hint attribute. If that fails, a query is established
230 	to track down such an application, if there is one available.
231 */
232 status_t
233 RecentApps::GetRefForApp(const char *appSig, entry_ref *result)
234 {
235 	if (appSig == NULL || result == NULL)
236 		return B_BAD_VALUE;
237 
238 	// We'll use BMimeType to check for the app hint, since I'm lazy
239 	// and Ingo's on vacation :-P :-)
240 	BMimeType mime(appSig);
241 	status_t err = mime.InitCheck();
242 	if (!err)
243 		err = mime.GetAppHint(result);
244 	return err;
245 }
246 
247