xref: /haiku/src/apps/mediaplayer/MainApp.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
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