1 /*
2 * Copyright 2001-2016, 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 * Christian Packmann
10 */
11
12
13 #include "AppServer.h"
14
15 #include <syslog.h>
16
17 #include <AutoDeleter.h>
18 #include <LaunchRoster.h>
19 #include <PortLink.h>
20
21 #include "BitmapManager.h"
22 #include "Desktop.h"
23 #include "GlobalFontManager.h"
24 #include "InputManager.h"
25 #include "ScreenManager.h"
26 #include "ServerProtocol.h"
27
28
29 //#define DEBUG_SERVER
30 #ifdef DEBUG_SERVER
31 # include <stdio.h>
32 # define STRACE(x) printf x
33 #else
34 # define STRACE(x) ;
35 #endif
36
37
38 // Globals
39 port_id gAppServerPort;
40 BTokenSpace gTokenSpace;
41 uint32 gAppServerSIMDFlags = 0;
42
43
44 /*! \brief Constructor
45
46 This loads the default fonts, allocates all the major global variables,
47 spawns the main housekeeping threads, loads user preferences for the UI
48 and decorator, and allocates various locks.
49 */
AppServer(status_t * status)50 AppServer::AppServer(status_t* status)
51 :
52 SERVER_BASE("application/x-vnd.Haiku-app_server", "picasso", -1, false,
53 status),
54 fDesktopLock("AppServerDesktopLock")
55 {
56 openlog("app_server", 0, LOG_DAEMON);
57
58 gInputManager = new InputManager();
59
60 // Create the font server and scan the proper directories.
61 gFontManager = new GlobalFontManager;
62 if (gFontManager->InitCheck() != B_OK)
63 debugger("font manager could not be initialized!");
64
65 gFontManager->Run();
66
67 gScreenManager = new ScreenManager();
68 gScreenManager->Run();
69
70 // Create the bitmap allocator. Object declared in BitmapManager.cpp
71 gBitmapManager = new BitmapManager();
72
73 #if 0
74 // This is not presently needed, as app_server is launched from the login session.
75 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
76 // TODO: check the attached displays, and launch login session for them
77 BMessage data;
78 data.AddString("name", "app_server");
79 data.AddInt32("session", 0);
80 BLaunchRoster().Target("login", data);
81 #endif
82 #endif
83 }
84
85
86 /*! \brief Destructor
87 Reached only when the server is asked to shut down in Test mode.
88 */
~AppServer()89 AppServer::~AppServer()
90 {
91 delete gBitmapManager;
92
93 gScreenManager->Lock();
94 gScreenManager->Quit();
95
96 gFontManager->Lock();
97 gFontManager->Quit();
98
99 closelog();
100 }
101
102
103 void
MessageReceived(BMessage * message)104 AppServer::MessageReceived(BMessage* message)
105 {
106 switch (message->what) {
107 case AS_GET_DESKTOP:
108 {
109 Desktop* desktop = NULL;
110
111 int32 userID = message->GetInt32("user", 0);
112 int32 version = message->GetInt32("version", 0);
113 const char* targetScreen = message->GetString("target");
114
115 if (version != AS_PROTOCOL_VERSION) {
116 syslog(LOG_ERR, "Application for user %" B_PRId32 " does not "
117 "support the current server protocol (%" B_PRId32 ").\n",
118 userID, version);
119 } else {
120 desktop = _FindDesktop(userID, targetScreen);
121 if (desktop == NULL) {
122 // we need to create a new desktop object for this user
123 // TODO: test if the user exists on the system
124 // TODO: maybe have a separate AS_START_DESKTOP_SESSION for
125 // authorizing the user
126 desktop = _CreateDesktop(userID, targetScreen);
127 }
128 }
129
130 BMessage reply;
131 if (desktop != NULL)
132 reply.AddInt32("port", desktop->MessagePort());
133 else
134 reply.what = (uint32)B_ERROR;
135
136 message->SendReply(&reply);
137 break;
138 }
139
140 default:
141 // We don't allow application scripting
142 STRACE(("AppServer received unexpected code %" B_PRId32 "\n",
143 message->what));
144 break;
145 }
146 }
147
148
149 bool
QuitRequested()150 AppServer::QuitRequested()
151 {
152 #if TEST_MODE
153 while (fDesktops.CountItems() > 0) {
154 Desktop *desktop = fDesktops.RemoveItemAt(0);
155
156 thread_id thread = desktop->Thread();
157 desktop->PostMessage(B_QUIT_REQUESTED);
158
159 // we just wait for the desktop to kill itself
160 status_t status;
161 wait_for_thread(thread, &status);
162 }
163
164 delete this;
165 exit(0);
166
167 return SERVER_BASE::QuitRequested();
168 #else
169 return false;
170 #endif
171
172 }
173
174
175 /*! \brief Creates a desktop object for an authorized user
176 */
177 Desktop*
_CreateDesktop(uid_t userID,const char * targetScreen)178 AppServer::_CreateDesktop(uid_t userID, const char* targetScreen)
179 {
180 BAutolock locker(fDesktopLock);
181 ObjectDeleter<Desktop> desktop;
182 try {
183 desktop.SetTo(new Desktop(userID, targetScreen));
184
185 status_t status = desktop->Init();
186 if (status == B_OK)
187 status = desktop->Run();
188 if (status == B_OK && !fDesktops.AddItem(desktop.Get()))
189 status = B_NO_MEMORY;
190
191 if (status != B_OK) {
192 syslog(LOG_ERR, "Cannot initialize Desktop object: %s\n",
193 strerror(status));
194 return NULL;
195 }
196 } catch (...) {
197 // there is obviously no memory left
198 return NULL;
199 }
200
201 return desktop.Detach();
202 }
203
204
205 /*! \brief Finds the desktop object that belongs to a certain user
206 */
207 Desktop*
_FindDesktop(uid_t userID,const char * targetScreen)208 AppServer::_FindDesktop(uid_t userID, const char* targetScreen)
209 {
210 BAutolock locker(fDesktopLock);
211
212 for (int32 i = 0; i < fDesktops.CountItems(); i++) {
213 Desktop* desktop = fDesktops.ItemAt(i);
214
215 if (desktop->UserID() == userID
216 && ((desktop->TargetScreen() == NULL && targetScreen == NULL)
217 || (desktop->TargetScreen() != NULL && targetScreen != NULL
218 && strcmp(desktop->TargetScreen(), targetScreen) == 0))) {
219 return desktop;
220 }
221 }
222
223 return NULL;
224 }
225
226
227 // #pragma mark -
228
229
230 int
main(int argc,char ** argv)231 main(int argc, char** argv)
232 {
233 srand(real_time_clock_usecs());
234
235 status_t status;
236 AppServer* server = new AppServer(&status);
237 if (status == B_OK)
238 server->Run();
239
240 return status == B_OK ? EXIT_SUCCESS : EXIT_FAILURE;
241 }
242