1 /* 2 * MainApp.cpp - Media Player for the Haiku Operating System 3 * 4 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> 5 * Copyright (C) 2008 Stephan Aßmus <superstippi@gmx.de> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * version 2 as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 * 20 */ 21 #include "MainApp.h" 22 23 #include <Alert.h> 24 #include <Autolock.h> 25 #include <Entry.h> 26 #include <MediaRoster.h> 27 #include <Path.h> 28 #include <Roster.h> 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 34 #include "EventQueue.h" 35 #include "SettingsWindow.h" 36 37 38 MainApp *gMainApp; 39 const char* kAppSig = "application/x-vnd.Haiku-MediaPlayer"; 40 41 static const char* kMediaServerSig = "application/x-vnd.Be.media-server"; 42 static const char* kMediaServerAddOnSig = "application/x-vnd.Be.addon-host"; 43 44 45 MainApp::MainApp() 46 : BApplication(kAppSig), 47 fPlayerCount(0), 48 fFirstWindow(NewWindow()), 49 fSettingsWindow(NULL), 50 51 fMediaServerRunning(false), 52 fMediaAddOnServerRunning(false) 53 { 54 } 55 56 57 MainApp::~MainApp() 58 { 59 } 60 61 62 bool 63 MainApp::QuitRequested() 64 { 65 // TODO: When doing this in the destructor, the MainApp does not 66 // quit properly. Is this a Haiku bug? (SettingsWindow::QuitRequested() 67 // returns "false" always.) 68 if (fSettingsWindow && fSettingsWindow->Lock()) 69 fSettingsWindow->Quit(); 70 fSettingsWindow = NULL; 71 72 return BApplication::QuitRequested(); 73 } 74 75 76 BWindow* 77 MainApp::NewWindow() 78 { 79 BAutolock _(this); 80 fPlayerCount++; 81 return new MainWin(); 82 } 83 84 85 int32 86 MainApp::PlayerCount() const 87 { 88 BAutolock _(const_cast<MainApp*>(this)); 89 return fPlayerCount; 90 } 91 92 93 // #pragma mark - 94 95 96 void 97 MainApp::ReadyToRun() 98 { 99 // setup the settings window now, we need to have it 100 fSettingsWindow = new SettingsWindow(BRect(150, 150, 450, 520)); 101 fSettingsWindow->Hide(); 102 fSettingsWindow->Show(); 103 104 // Now tell the application roster, that we're interested 105 // in getting notifications of apps being launched or quit. 106 // In this way we are going to detect a media_server restart. 107 be_roster->StartWatching(BMessenger(this, this), 108 B_REQUEST_LAUNCHED | B_REQUEST_QUIT); 109 // we will keep track of the status of media_server 110 // and media_addon_server 111 fMediaServerRunning = be_roster->IsRunning(kMediaServerSig); 112 fMediaAddOnServerRunning = be_roster->IsRunning(kMediaServerAddOnSig); 113 } 114 115 116 void 117 MainApp::RefsReceived(BMessage *msg) 118 { 119 // The user dropped a file (or files) on this app's icon, 120 // or double clicked a file that's handled by this app. 121 // Command line arguments are also redirected to here by 122 // ArgvReceived() but without MIME type check. 123 // For each file we create a new window and send it a 124 // B_REFS_RECEIVED message with a single file. 125 // If IsLaunching() is true, we use fFirstWindow as first 126 // window. 127 printf("MainApp::RefsReceived\n"); 128 129 entry_ref ref; 130 for (int i = 0; B_OK == msg->FindRef("refs", i, &ref); i++) { 131 BWindow *win; 132 win = (i == 0 && IsLaunching()) ? fFirstWindow : NewWindow(); 133 BMessage m(B_REFS_RECEIVED); 134 m.AddRef("refs", &ref); 135 win->PostMessage(&m); 136 } 137 } 138 139 140 void 141 MainApp::ArgvReceived(int32 argc, char **argv) 142 { 143 char cwd[B_PATH_NAME_LENGTH]; 144 getcwd(cwd, sizeof(cwd)); 145 146 BMessage m(B_REFS_RECEIVED); 147 148 for (int i = 1; i < argc; i++) { 149 printf("MainApp::ArgvReceived %s\n", argv[i]); 150 BPath path; 151 if (argv[i][0] != '/') 152 path.SetTo(cwd, argv[i]); 153 else 154 path.SetTo(argv[i]); 155 BEntry entry(path.Path(), true); 156 if (!entry.Exists() || !entry.IsFile()) 157 continue; 158 159 entry_ref ref; 160 if (B_OK == entry.GetRef(&ref)) 161 m.AddRef("refs", &ref); 162 } 163 164 if (m.HasRef("refs")) { 165 printf("MainApp::ArgvReceived calling RefsReceived\n"); 166 RefsReceived(&m); 167 } 168 } 169 170 171 void 172 MainApp::MessageReceived(BMessage* message) 173 { 174 switch (message->what) { 175 case M_PLAYER_QUIT: 176 fPlayerCount--; 177 if (fPlayerCount == 0) 178 PostMessage(B_QUIT_REQUESTED); 179 break; 180 181 case B_SOME_APP_LAUNCHED: 182 case B_SOME_APP_QUIT: 183 { 184 const char* mimeSig; 185 if (message->FindString("be:signature", &mimeSig) < B_OK) 186 break; 187 188 bool isMediaServer = strcmp(mimeSig, kMediaServerSig) == 0; 189 bool isAddonServer = strcmp(mimeSig, kMediaServerAddOnSig) == 0; 190 if (!isMediaServer && !isAddonServer) 191 break; 192 193 bool running = (message->what == B_SOME_APP_LAUNCHED); 194 if (isMediaServer) 195 fMediaServerRunning = running; 196 if (isAddonServer) 197 fMediaAddOnServerRunning = running; 198 199 if (!fMediaServerRunning && !fMediaAddOnServerRunning) { 200 fprintf(stderr, "media server has quit.\n"); 201 // trigger closing of media nodes 202 BMessage broadcast(M_MEDIA_SERVER_QUIT); 203 _BroadcastMessage(broadcast); 204 } else if (fMediaServerRunning && fMediaAddOnServerRunning) { 205 fprintf(stderr, "media server has launched.\n"); 206 // HACK! 207 // quit our now invalid instance of the media roster 208 // so that before new nodes are created, 209 // we get a new roster (it is a normal looper) 210 // TODO: This functionality could become part of 211 // BMediaRoster. It could detect the start/quit of 212 // the servers like it is done here, and either quit 213 // itself, or re-establish the connection, and send some 214 // notification to the app... something along those lines. 215 BMediaRoster* roster = BMediaRoster::CurrentRoster(); 216 if (roster) { 217 roster->Lock(); 218 roster->Quit(); 219 } 220 // give the servers some time to init... 221 snooze(3000000); 222 // trigger re-init of media nodes 223 BMessage broadcast(M_MEDIA_SERVER_STARTED); 224 _BroadcastMessage(broadcast); 225 } 226 break; 227 } 228 case M_SETTINGS: 229 _ShowSettingsWindow(); 230 break; 231 232 default: 233 BApplication::MessageReceived(message); 234 break; 235 } 236 } 237 238 239 void 240 MainApp::AboutRequested() 241 { 242 fFirstWindow->PostMessage(B_ABOUT_REQUESTED); 243 } 244 245 246 void 247 MainApp::_BroadcastMessage(const BMessage& _message) 248 { 249 for (int32 i = 0; BWindow* window = WindowAt(i); i++) { 250 BMessage message(_message); 251 window->PostMessage(&message); 252 } 253 } 254 255 256 void 257 MainApp::_ShowSettingsWindow() 258 { 259 if (fSettingsWindow->Lock()) { 260 if (fSettingsWindow->IsHidden()) 261 fSettingsWindow->Show(); 262 else 263 fSettingsWindow->Activate(); 264 fSettingsWindow->Unlock(); 265 } 266 } 267 268 269 // #pragma mark - 270 271 272 int 273 main() 274 { 275 EventQueue::CreateDefault(); 276 277 srand(system_time()); 278 279 gMainApp = new MainApp; 280 gMainApp->Run(); 281 delete gMainApp; 282 283 EventQueue::DeleteDefault(); 284 285 return 0; 286 } 287