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