xref: /haiku/src/apps/haikudepot/ui/App.cpp (revision 44d19f4d32b8f7e9c01f00294c87ca5cc2e057f7)
1 /*
2  * Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "App.h"
8 
9 #include <stdio.h>
10 
11 #include <Alert.h>
12 #include <Catalog.h>
13 #include <Entry.h>
14 #include <Message.h>
15 #include <package/PackageInfo.h>
16 #include <Path.h>
17 #include <Roster.h>
18 #include <Screen.h>
19 #include <String.h>
20 
21 #include "support.h"
22 
23 #include "FeaturedPackagesView.h"
24 #include "MainWindow.h"
25 
26 
27 #undef B_TRANSLATION_CONTEXT
28 #define B_TRANSLATION_CONTEXT "App"
29 
30 
31 App::App()
32 	:
33 	BApplication("application/x-vnd.Haiku-HaikuDepot"),
34 	fMainWindow(NULL),
35 	fWindowCount(0),
36 	fSettingsRead(false)
37 {
38 	_CheckPackageDaemonRuns();
39 }
40 
41 
42 App::~App()
43 {
44 	// We cannot let global destructors cleanup static BitmapRef objects,
45 	// since calling BBitmap destructors needs a valid BApplication still
46 	// around. That's why we do it here.
47 	PackageInfo::CleanupDefaultIcon();
48 	FeaturedPackagesView::CleanupIcons();
49 }
50 
51 
52 bool
53 App::QuitRequested()
54 {
55 	if (fMainWindow != NULL
56 		&& fMainWindow->LockLooperWithTimeout(1500000) == B_OK) {
57 		BMessage windowSettings;
58 		fMainWindow->StoreSettings(windowSettings);
59 
60 		fMainWindow->UnlockLooper();
61 
62 		_StoreSettings(windowSettings);
63 	}
64 
65 	return true;
66 }
67 
68 
69 void
70 App::ReadyToRun()
71 {
72 	if (fWindowCount > 0)
73 		return;
74 
75 	BMessage settings;
76 	_LoadSettings(settings);
77 
78 	fMainWindow = new MainWindow(settings);
79 	_ShowWindow(fMainWindow);
80 }
81 
82 
83 void
84 App::MessageReceived(BMessage* message)
85 {
86 	switch (message->what) {
87 		case MSG_MAIN_WINDOW_CLOSED:
88 		{
89 			BMessage windowSettings;
90 			if (message->FindMessage("window settings",
91 					&windowSettings) == B_OK) {
92 				_StoreSettings(windowSettings);
93 			}
94 
95 			fWindowCount--;
96 			if (fWindowCount == 0)
97 				Quit();
98 			break;
99 		}
100 
101 		default:
102 			BApplication::MessageReceived(message);
103 			break;
104 	}
105 }
106 
107 
108 void
109 App::RefsReceived(BMessage* message)
110 {
111 	entry_ref ref;
112 	int32 index = 0;
113 	while (message->FindRef("refs", index++, &ref) == B_OK) {
114 		BEntry entry(&ref, true);
115 		_Open(entry);
116 	}
117 }
118 
119 
120 void
121 App::ArgvReceived(int32 argc, char* argv[])
122 {
123 	for (int i = 1; i < argc;) {
124 		if (0 == strcmp("--webappbaseurl", argv[i])) {
125 			if (i == argc-1) {
126 				fprintf(stderr, "unexpected end of arguments; missing web app base url\n");
127 				Quit();
128 			}
129 
130 			if (WebAppInterface::SetBaseUrl(argv[i + 1]) != B_OK) {
131 				fprintf(stderr, "malformed web app base url; %s\n", argv[i + 1]);
132 				Quit();
133 			}
134 			else
135 				fprintf(stderr, "did configure the web base url; %s\n",argv[i + 1]);
136 
137 			i += 2;
138 		} else {
139 			BEntry entry(argv[i], true);
140 			_Open(entry);
141 			i++;
142 		}
143 	}
144 }
145 
146 
147 // #pragma mark - private
148 
149 
150 void
151 App::_Open(const BEntry& entry)
152 {
153 	BPath path;
154 	if (!entry.Exists() || !entry.GetPath(&path) == B_OK) {
155 		fprintf(stderr, "Package file not found: %s\n", path.Path());
156 		return;
157 	}
158 
159 	// Try to parse package file via Package Kit
160 	BPackageKit::BPackageInfo info;
161 	status_t status = info.ReadFromPackageFile(path.Path());
162 	if (status != B_OK) {
163 		fprintf(stderr, "Failed to parse package file: %s\n",
164 			strerror(status));
165 		return;
166 	}
167 
168 	// Transfer information into PackageInfo
169 	PackageInfoRef package(new(std::nothrow) PackageInfo(info), true);
170 	if (package.Get() == NULL) {
171 		fprintf(stderr, "Could not allocate PackageInfo\n");
172 		return;
173 	}
174 
175 	package->SetLocalFilePath(path.Path());
176 
177 	BMessage settings;
178 	_LoadSettings(settings);
179 
180 	MainWindow* window = new MainWindow(settings, package);
181 	_ShowWindow(window);
182 }
183 
184 
185 void
186 App::_ShowWindow(MainWindow* window)
187 {
188 	window->Show();
189 	fWindowCount++;
190 }
191 
192 
193 bool
194 App::_LoadSettings(BMessage& settings)
195 {
196 	if (!fSettingsRead) {
197 		fSettings = true;
198 		if (load_settings(&fSettings, "main_settings", "HaikuDepot") != B_OK)
199 			fSettings.MakeEmpty();
200 	}
201 	settings = fSettings;
202 	return !fSettings.IsEmpty();
203 }
204 
205 
206 void
207 App::_StoreSettings(const BMessage& settings)
208 {
209 	// Take what is in settings and replace data under the same name in
210 	// fSettings, leaving anything in fSettings that is not contained in
211 	// settings.
212 	int32 i = 0;
213 
214 	char* name;
215 	type_code type;
216 	int32 count;
217 
218 	while (settings.GetInfo(B_ANY_TYPE, i++, &name, &type, &count) == B_OK) {
219 		fSettings.RemoveName(name);
220 		for (int32 j = 0; j < count; j++) {
221 			const void* data;
222 			ssize_t size;
223 			if (settings.FindData(name, type, j, &data, &size) != B_OK)
224 				break;
225 			fSettings.AddData(name, type, data, size);
226 		}
227 	}
228 
229 	save_settings(&fSettings, "main_settings", "HaikuDepot");
230 }
231 
232 
233 // #pragma mark -
234 
235 
236 static const char* kPackageDaemonSignature
237 	= "application/x-vnd.haiku-package_daemon";
238 
239 void
240 App::_CheckPackageDaemonRuns()
241 {
242 	while (!be_roster->IsRunning(kPackageDaemonSignature)) {
243 		BAlert* alert = new BAlert("start_package_daemon",
244 			B_TRANSLATE("HaikuDepot needs the package daemon to function, "
245 				"and it appears to be not running.\n"
246 				"Would you like to start it now?"),
247 			B_TRANSLATE("No, quit HaikuDepot"),
248 			B_TRANSLATE("Start package daemon"), NULL, B_WIDTH_AS_USUAL,
249 			B_WARNING_ALERT);
250 		alert->SetShortcut(0, B_ESCAPE);
251 
252 		if (alert->Go() == 0)
253 			exit(1);
254 
255 		if (!_LaunchPackageDaemon())
256 			break;
257 	}
258 }
259 
260 
261 bool
262 App::_LaunchPackageDaemon()
263 {
264 	status_t ret = be_roster->Launch(kPackageDaemonSignature);
265 	if (ret != B_OK) {
266 		BString errorMessage
267 			= B_TRANSLATE("Starting the package daemon failed:\n\n%Error%");
268 		errorMessage.ReplaceAll("%Error%", strerror(ret));
269 
270 		BAlert* alert = new BAlert("package_daemon_problem",
271 			errorMessage,
272 			B_TRANSLATE("Quit HaikuDepot"),
273 			B_TRANSLATE("Try again"), NULL, B_WIDTH_AS_USUAL,
274 			B_WARNING_ALERT);
275 		alert->SetShortcut(0, B_ESCAPE);
276 
277 		if (alert->Go() == 0)
278 			return false;
279 	}
280 	// TODO: Would be nice to send a message to the package daemon instead
281 	// and get a reply once it is ready.
282 	snooze(2000000);
283 	return true;
284 }
285 
286