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