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