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 return B_OK; 109 } 110 111 112 /*! \brief Adds the signature of the application referred to by \a ref at 113 the front of the recent apps list. 114 115 The entry is checked for a BEOS:APP_SIG attribute. If that fails, the 116 app's resources are checked. If no signature can be found, the call 117 fails. 118 */ 119 status_t 120 RecentApps::Add(const entry_ref *ref, int32 appFlags) 121 { 122 if (ref == NULL) 123 return B_BAD_VALUE; 124 125 BFile file; 126 BAppFileInfo info; 127 char signature[B_MIME_TYPE_LENGTH]; 128 129 status_t err = file.SetTo(ref, B_READ_ONLY); 130 if (!err) 131 err = info.SetTo(&file); 132 if (!err) 133 err = info.GetSignature(signature); 134 if (!err) 135 err = Add(signature, appFlags); 136 return err; 137 } 138 139 140 /*! \brief Returns the first \a maxCount recent apps in the \c BMessage 141 pointed to by \a list. 142 143 The message is cleared first, and \c entry_refs for the the apps are 144 stored in the \c "refs" field of the message (\c B_REF_TYPE). 145 146 If there are fewer than \a maxCount items in the list, the entire 147 list is returned. 148 149 Since BRoster::GetRecentApps() returns \c void, the message pointed 150 to by \a list is simply cleared if maxCount is invalid (i.e. <= 0). 151 */ 152 status_t 153 RecentApps::Get(int32 maxCount, BMessage *list) 154 { 155 if (list == NULL) 156 return B_BAD_VALUE; 157 158 // Clear 159 list->MakeEmpty(); 160 161 // Fill 162 std::list<std::string>::iterator item; 163 status_t status = B_OK; 164 int counter = 0; 165 for (item = fAppList.begin(); 166 status == B_OK && counter < maxCount && item != fAppList.end(); 167 counter++, item++) { 168 entry_ref ref; 169 if (GetRefForApp(item->c_str(), &ref) == B_OK) 170 status = list->AddRef("refs", &ref); 171 else { 172 D(PRINT("WARNING: RecentApps::Get(): No ref found for app '%s'\n", 173 item->c_str())); 174 } 175 } 176 177 return status; 178 } 179 180 181 /*! \brief Clears the list of recently launched apps 182 */ 183 status_t 184 RecentApps::Clear() 185 { 186 fAppList.clear(); 187 return B_OK; 188 } 189 190 191 /*! \brief Dumps the the current list of apps to stdout. 192 */ 193 status_t 194 RecentApps::Print() 195 { 196 std::list<std::string>::iterator item; 197 int counter = 1; 198 for (item = fAppList.begin(); item != fAppList.end(); item++) { 199 printf("%d: '%s'\n", counter++, item->c_str()); 200 } 201 return B_OK; 202 } 203 204 205 /*! \brief Outputs a textual representation of the current recent 206 apps list to the given file stream. 207 208 */ 209 status_t 210 RecentApps::Save(FILE* file) 211 { 212 status_t error = file ? B_OK : B_BAD_VALUE; 213 if (!error) { 214 fprintf(file, "# Recent applications\n"); 215 std::list<std::string>::iterator item; 216 for (item = fAppList.begin(); item != fAppList.end(); item++) { 217 fprintf(file, "RecentApp %s\n", item->c_str()); 218 } 219 fprintf(file, "\n"); 220 } 221 return error; 222 } 223 224 225 /*! \brief Fetches an \c entry_ref for the application with the 226 given signature. 227 228 First the MIME database is checked for a matching application type 229 with a valid app hint attribute. If that fails, a query is established 230 to track down such an application, if there is one available. 231 */ 232 status_t 233 RecentApps::GetRefForApp(const char *appSig, entry_ref *result) 234 { 235 if (appSig == NULL || result == NULL) 236 return B_BAD_VALUE; 237 238 // We'll use BMimeType to check for the app hint, since I'm lazy 239 // and Ingo's on vacation :-P :-) 240 BMimeType mime(appSig); 241 status_t err = mime.InitCheck(); 242 if (!err) 243 err = mime.GetAppHint(result); 244 return err; 245 } 246 247