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