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