xref: /haiku/src/servers/app/AppServer.cpp (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
1 /*
2  * Copyright (c) 2001-2007, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Stephan Aßmus <superstippi@gmx.de>
9  */
10 
11 
12 #include "AppServer.h"
13 
14 #include "BitmapManager.h"
15 #include "Desktop.h"
16 #include "FontManager.h"
17 #include "InputManager.h"
18 #include "ScreenManager.h"
19 #include "ServerProtocol.h"
20 
21 #include <PortLink.h>
22 
23 #include <syslog.h>
24 
25 //#define DEBUG_SERVER
26 #ifdef DEBUG_SERVER
27 #	include <stdio.h>
28 #	define STRACE(x) printf x
29 #else
30 #	define STRACE(x) ;
31 #endif
32 
33 
34 // Globals
35 port_id gAppServerPort;
36 static AppServer *sAppServer;
37 BTokenSpace gTokenSpace;
38 
39 
40 /*!
41 	\brief Constructor
42 
43 	This loads the default fonts, allocates all the major global variables, spawns the main housekeeping
44 	threads, loads user preferences for the UI and decorator, and allocates various locks.
45 */
46 AppServer::AppServer()
47 	: MessageLooper("app_server"),
48 	fMessagePort(-1),
49 	fDesktops(),
50 	fDesktopLock("AppServerDesktopLock")
51 {
52 	openlog("app_server", 0, LOG_DAEMON);
53 
54 	fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, SERVER_PORT_NAME);
55 	if (fMessagePort < B_OK)
56 		debugger("app_server could not create message port");
57 
58 	fLink.SetReceiverPort(fMessagePort);
59 
60 	sAppServer = this;
61 
62 	gInputManager = new InputManager();
63 
64 	// Create the font server and scan the proper directories.
65 	gFontManager = new FontManager;
66 	if (gFontManager->InitCheck() != B_OK)
67 		debugger("font manager could not be initialized!");
68 
69 	gFontManager->Run();
70 
71 	gScreenManager = new ScreenManager();
72 	gScreenManager->Run();
73 
74 	// Create the bitmap allocator. Object declared in BitmapManager.cpp
75 	gBitmapManager = new BitmapManager();
76 
77 #if 0
78 	_LaunchCursorThread();
79 #endif
80 }
81 
82 /*!
83 	\brief Destructor
84 	Reached only when the server is asked to shut down in Test mode.
85 */
86 AppServer::~AppServer()
87 {
88 	delete gBitmapManager;
89 
90 	gScreenManager->Lock();
91 	gScreenManager->Quit();
92 
93 	gFontManager->Lock();
94 	gFontManager->Quit();
95 
96 	closelog();
97 }
98 
99 
100 /*!
101 	\brief The call that starts it all...
102 */
103 void
104 AppServer::RunLooper()
105 {
106 	rename_thread(find_thread(NULL), "picasso");
107 	_message_thread((void *)this);
108 }
109 
110 
111 /*!
112 	\brief Creates a desktop object for an authorized user
113 */
114 Desktop *
115 AppServer::_CreateDesktop(uid_t userID)
116 {
117 	BAutolock locker(fDesktopLock);
118 	Desktop* desktop = NULL;
119 	try {
120 		desktop = new Desktop(userID);
121 
122 		status_t status = desktop->Init();
123 		if (status == B_OK) {
124 			if (!desktop->Run())
125 				status = B_ERROR;
126 		}
127 		if (status == B_OK && !fDesktops.AddItem(desktop))
128 			status = B_NO_MEMORY;
129 
130 		if (status < B_OK) {
131 			fprintf(stderr, "Cannot initialize Desktop object: %s\n", strerror(status));
132 			delete desktop;
133 			return NULL;
134 		}
135 	} catch (...) {
136 		// there is obviously no memory left
137 		return NULL;
138 	}
139 
140 	return desktop;
141 }
142 
143 
144 /*!
145 	\brief Finds the desktop object that belongs to a certain user
146 */
147 Desktop *
148 AppServer::_FindDesktop(uid_t userID)
149 {
150 	BAutolock locker(fDesktopLock);
151 
152 	for (int32 i = 0; i < fDesktops.CountItems(); i++) {
153 		Desktop* desktop = fDesktops.ItemAt(i);
154 
155 		if (desktop->UserID() == userID)
156 			return desktop;
157 	}
158 
159 	return NULL;
160 }
161 
162 
163 /*!
164 	\brief Message handling function for all messages sent to the app_server
165 	\param code ID of the message sent
166 	\param buffer Attachment buffer for the message.
167 
168 */
169 void
170 AppServer::_DispatchMessage(int32 code, BPrivate::LinkReceiver& msg)
171 {
172 	switch (code) {
173 		case AS_GET_DESKTOP:
174 		{
175 			port_id replyPort;
176 			if (msg.Read<port_id>(&replyPort) < B_OK)
177 				break;
178 
179 			int32 userID;
180 			msg.Read<int32>(&userID);
181 
182 			Desktop* desktop = _FindDesktop(userID);
183 			if (desktop == NULL) {
184 				// we need to create a new desktop object for this user
185 				// ToDo: test if the user exists on the system
186 				// ToDo: maybe have a separate AS_START_DESKTOP_SESSION for authorizing the user
187 				desktop = _CreateDesktop(userID);
188 			}
189 
190 			BPrivate::LinkSender reply(replyPort);
191 			if (desktop != NULL) {
192 				reply.StartMessage(B_OK);
193 				reply.Attach<port_id>(desktop->MessagePort());
194 			} else
195 				reply.StartMessage(B_ERROR);
196 
197 			reply.Flush();
198 			break;
199 		}
200 
201 #if TEST_MODE
202 		case B_QUIT_REQUESTED:
203 		{
204 			// We've been asked to quit, so (for now) broadcast to all
205 			// desktops to quit. This situation will occur only when the server
206 			// is compiled as a regular Be application.
207 
208 			fQuitting = true;
209 
210 			while (fDesktops.CountItems() > 0) {
211 				Desktop *desktop = fDesktops.RemoveItemAt(0);
212 
213 				thread_id thread = desktop->Thread();
214 				desktop->PostMessage(B_QUIT_REQUESTED);
215 
216 				// we just wait for the desktop to kill itself
217 				status_t status;
218 				wait_for_thread(thread, &status);
219 			}
220 
221 			delete this;
222 
223 			// we are now clear to exit
224 			exit(0);
225 			break;
226 		}
227 #endif
228 
229 		default:
230 			STRACE(("Server::MainLoop received unexpected code %ld (offset %ld)\n",
231 				code, code - SERVER_TRUE));
232 			break;
233 	}
234 }
235 
236 
237 //	#pragma mark -
238 
239 
240 int
241 main(int argc, char** argv)
242 {
243 	// There can be only one....
244 	if (find_port(SERVER_PORT_NAME) >= B_OK)
245 		return -1;
246 
247 	srand(real_time_clock_usecs());
248 
249 	AppServer* server = new AppServer;
250 	server->RunLooper();
251 
252 	return 0;
253 }
254