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