/* * Copyright 2001-2016, Haiku. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm * Adrian Oanca * Stephan Aßmus * Stefano Ceccherini (burton666@libero.it) * Axel Dörfler, axeld@pinc-software.de * Jérôme Duval, jerome.duval@free.fr * Andrej Spielmann, * Philippe Saint-Pierre, stpere@gmail.com * Wim van der Meer, * Joseph Groover */ /*! \class ServerApp ServerApp.h \brief Counterpart to BApplication within the app_server */ #include "ServerApp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AppFontManager.h" #include "AppServer.h" #include "BitmapManager.h" #include "CursorManager.h" #include "CursorSet.h" #include "Desktop.h" #include "DecorManager.h" #include "DrawingEngine.h" #include "EventStream.h" #include "GlobalFontManager.h" #include "HWInterface.h" #include "InputManager.h" #include "OffscreenServerWindow.h" #include "Screen.h" #include "ServerBitmap.h" #include "ServerConfig.h" #include "ServerCursor.h" #include "ServerPicture.h" #include "ServerTokenSpace.h" #include "ServerWindow.h" #include "SystemPalette.h" #include "Window.h" //#define DEBUG_SERVERAPP #ifdef DEBUG_SERVERAPP # define STRACE(x) debug_printf x #else # define STRACE(x) ; #endif //#define DEBUG_SERVERAPP_FONT #ifdef DEBUG_SERVERAPP_FONT # define FTRACE(x) debug_printf x #else # define FTRACE(x) ; #endif using std::nothrow; static const uint32 kMsgUpdateShowAllDraggers = '_adg'; static const uint32 kMsgAppQuit = 'appQ'; ServerApp::ServerApp(Desktop* desktop, port_id clientReplyPort, port_id clientLooperPort, team_id clientTeam, int32 clientToken, const char* signature) : MessageLooper("application"), fMessagePort(-1), fClientReplyPort(clientReplyPort), fDesktop(desktop), fSignature(signature), fClientTeam(clientTeam), fWindowListLock("window list"), fInitialWorkspace(desktop->CurrentWorkspace()), // TODO: this should probably be retrieved when the app is loaded! fTemporaryDisplayModeChange(0), fMapLocker("server app maps"), fAppCursor(NULL), fViewCursor(NULL), fCursorHideLevel(0), fIsActive(false), fMemoryAllocator(new (std::nothrow) ClientMemoryAllocator(this), true), fAppFontManager(NULL) { if (fSignature.IsEmpty()) fSignature = "application/no-signature"; char name[B_OS_NAME_LENGTH]; snprintf(name, sizeof(name), "a<%" B_PRId32 ":%s", fClientTeam, SignatureLeaf()); fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name); if (fMessagePort < B_OK) return; fLink.SetSenderPort(fClientReplyPort); fLink.SetReceiverPort(fMessagePort); fLink.SetTargetTeam(fClientTeam); // we let the application own the port, so that we get aware when it's gone if (set_port_owner(fMessagePort, fClientTeam) < B_OK) { delete_port(fMessagePort); fMessagePort = -1; return; } BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam, clientLooperPort, clientToken); // record the current system wide fonts.. desktop->LockSingleWindow(); DesktopSettings settings(desktop); settings.GetDefaultPlainFont(fPlainFont); settings.GetDefaultBoldFont(fBoldFont); settings.GetDefaultFixedFont(fFixedFont); desktop->UnlockSingleWindow(); fAppFontManager = new AppFontManager(); STRACE(("ServerApp %s:\n", Signature())); STRACE(("\tBApp port: %" B_PRId32 "\n", fClientReplyPort)); STRACE(("\tReceiver port: %" B_PRId32 "\n", fMessagePort)); } ServerApp::~ServerApp() { STRACE(("*ServerApp %s:~ServerApp()\n", Signature())); ASSERT(fQuitting); // quit all server windows fWindowListLock.Lock(); for (int32 i = fWindowList.CountItems(); i-- > 0;) { ServerWindow* window = fWindowList.ItemAt(i); window->Quit(); } fWindowListLock.Unlock(); // wait for the windows to quit snooze(20000); fDesktop->RevertScreenModes(fTemporaryDisplayModeChange); fWindowListLock.Lock(); for (int32 i = fWindowList.CountItems(); i-- > 0;) { ServerWindow* window = fWindowList.ItemAt(i); // A window could have been removed in the mean time // (if those 20 milli seconds from above weren't enough) if (window == NULL) continue; sem_id deathSemaphore = window->DeathSemaphore(); fWindowListLock.Unlock(); // wait 3 seconds for our window to quit - that's quite a long // time, but killing it might have desastrous effects if (MessageLooper::WaitForQuit(deathSemaphore, 3000000) != B_OK) { // This really shouldn't happen, as it shows we're buggy #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST syslog(LOG_ERR, "ServerApp %s: ServerWindow doesn't respond!\n", Signature()); #else debugger("ServerWindow doesn't respond!\n"); #endif } fWindowListLock.Lock(); } if (fMemoryAllocator != NULL) fMemoryAllocator->Detach(); fMapLocker.Lock(); while (!fBitmapMap.empty()) _DeleteBitmap(fBitmapMap.begin()->second); while (!fPictureMap.empty()) fPictureMap.begin()->second->SetOwner(NULL); fDesktop->GetCursorManager().DeleteCursors(fClientTeam); delete fAppFontManager; STRACE(("ServerApp %s::~ServerApp(): Exiting\n", Signature())); } /*! \brief Checks if the application was initialized correctly */ status_t ServerApp::InitCheck() { if (fMessagePort < B_OK) return fMessagePort; if (fClientReplyPort < B_OK) return fClientReplyPort; if (fWindowListLock.InitCheck() < B_OK) return fWindowListLock.InitCheck(); if (fMemoryAllocator == NULL) return B_NO_MEMORY; return B_OK; } void ServerApp::Quit() { Quit(-1); } /*! \brief This quits the application and deletes it. You're not supposed to call its destructor directly. At the point you're calling this method, the application should already be removed from the application list. */ void ServerApp::Quit(sem_id shutdownSemaphore) { if (fThread < B_OK) { delete this; return; } // execute application deletion in the message looper thread fQuitting = true; PostMessage(kMsgAppQuit); send_data(fThread, 'QUIT', &shutdownSemaphore, sizeof(sem_id)); } /*! \brief Sets the ServerApp's active status \param value The new status of the ServerApp. This changes an internal flag and also sets the current cursor to the one specified by the application */ void ServerApp::Activate(bool value) { if (fIsActive == value) return; fIsActive = value; if (fIsActive) { // notify registrar about the active app BRoster::Private roster; roster.UpdateActiveApp(ClientTeam()); if (_HasWindowUnderMouse()) { // Set the cursor to the application cursor, if any fDesktop->SetCursor(CurrentCursor()); } fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0); } } void ServerApp::SetCurrentCursor(ServerCursor* cursor) { fViewCursor.SetTo(cursor, false); fDesktop->SetCursor(CurrentCursor()); } ServerCursor* ServerApp::CurrentCursor() const { if (fViewCursor != NULL) return fViewCursor; return fAppCursor; } bool ServerApp::AddWindow(ServerWindow* window) { BAutolock locker(fWindowListLock); return fWindowList.AddItem(window); } void ServerApp::RemoveWindow(ServerWindow* window) { BAutolock locker(fWindowListLock); fWindowList.RemoveItem(window); } bool ServerApp::InWorkspace(int32 index) const { BAutolock locker(fWindowListLock); // we could cache this, but then we'd have to recompute the cached // value everytime a window has closed or changed workspaces // TODO: support initial application workspace! for (int32 i = fWindowList.CountItems(); i-- > 0;) { ServerWindow* serverWindow = fWindowList.ItemAt(i); const Window* window = serverWindow->Window(); if (window == NULL || window->IsOffscreenWindow()) continue; // only normal and unhidden windows count if (window->IsNormal() && !window->IsHidden() && window->InWorkspace(index)) return true; } return false; } uint32 ServerApp::Workspaces() const { uint32 workspaces = 0; BAutolock locker(fWindowListLock); // we could cache this, but then we'd have to recompute the cached // value everytime a window has closed or changed workspaces for (int32 i = fWindowList.CountItems(); i-- > 0;) { ServerWindow* serverWindow = fWindowList.ItemAt(i); const Window* window = serverWindow->Window(); if (window == NULL || window->IsOffscreenWindow()) continue; // only normal and unhidden windows count if (window->IsNormal() && !window->IsHidden()) workspaces |= window->Workspaces(); } // TODO: add initial application workspace! return workspaces; } /*! \brief Acquires a reference of the desired bitmap, if available. \param token ID token of the bitmap to find \return The bitmap having that ID or NULL if not found */ ServerBitmap* ServerApp::GetBitmap(int32 token) const { if (token < 1) return NULL; BAutolock _(fMapLocker); ServerBitmap* bitmap = _FindBitmap(token); if (bitmap == NULL) return NULL; bitmap->AcquireReference(); return bitmap; } ServerPicture* ServerApp::CreatePicture(const ServerPicture* original) { BReference picture; if (original != NULL) picture.SetTo(new(std::nothrow) ServerPicture(*original), true); else picture.SetTo(new(std::nothrow) ServerPicture(), true); if (picture != NULL && !picture->SetOwner(this)) return NULL; return picture.Detach(); } ServerPicture* ServerApp::GetPicture(int32 token) const { if (token < 1) return NULL; BAutolock _(fMapLocker); ServerPicture* picture = _FindPicture(token); if (picture == NULL) return NULL; picture->AcquireReference(); return picture; } /*! To be called only by ServerPicture itself.*/ bool ServerApp::AddPicture(ServerPicture* picture) { BAutolock _(fMapLocker); ASSERT(picture->Owner() == NULL); try { fPictureMap.insert(std::make_pair(picture->Token(), BReference(picture, false))); } catch (std::bad_alloc& exception) { return false; } return true; } /*! To be called only by ServerPicture itself.*/ void ServerApp::RemovePicture(ServerPicture* picture) { BAutolock _(fMapLocker); ASSERT(picture->Owner() == this); fPictureMap.erase(picture->Token()); } /*! Called from the ClientMemoryAllocator whenever a server area could be deleted. A message is then sent to the client telling it that it can delete its client area, too. */ void ServerApp::NotifyDeleteClientArea(area_id serverArea) { BMessage notify(kMsgDeleteServerMemoryArea); notify.AddInt32("server area", serverArea); SendMessageToClient(¬ify); } /*! \brief Send a message to the ServerApp's BApplication \param message The message to send */ void ServerApp::SendMessageToClient(BMessage* message) const { status_t status = fHandlerMessenger.SendMessage(message, (BHandler*)NULL, 100000); if (status != B_OK) { syslog(LOG_ERR, "app %s send to client failed: %s\n", Signature(), strerror(status)); } } // #pragma mark - private methods void ServerApp::_GetLooperName(char* name, size_t length) { snprintf(name, length, "a:%" B_PRId32 ":%s", ClientTeam(), SignatureLeaf()); } /*! \brief Handler function for BApplication API messages \param code Identifier code for the message. Equivalent to BMessage::what \param buffer Any attachments Note that the buffer's exact format is determined by the particular message. All attachments are placed in the buffer via a PortLink, so it will be a matter of casting and incrementing an index variable to access them. */ void ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) { switch (code) { case AS_REGISTER_INPUT_SERVER: { EventStream* stream = new(std::nothrow) InputServerStream(fHandlerMessenger); if (stream != NULL && (!stream->IsValid() || !gInputManager->AddStream(stream))) { delete stream; break; } // TODO: this should be done using notifications (so that an // abandoned stream will get noticed directly) if (fDesktop->EventDispatcher().InitCheck() != B_OK) fDesktop->EventDispatcher().SetTo(gInputManager->GetStream()); break; } case AS_APP_CRASHED: // Allow the debugger to show its window: if needed, remove any // kWindowScreenFeels from the windows of this application if (fDesktop->LockAllWindows()) { if (fWindowListLock.Lock()) { for (int32 i = fWindowList.CountItems(); i-- > 0;) { ServerWindow* serverWindow = fWindowList.ItemAt(i); Window* window = serverWindow->Window(); if (window == NULL || window->IsOffscreenWindow()) continue; if (window->Feel() == kWindowScreenFeel) fDesktop->SetWindowFeel(window, B_NORMAL_WINDOW_FEEL); } fWindowListLock.Unlock(); } fDesktop->UnlockAllWindows(); } break; case AS_DUMP_ALLOCATOR: fMemoryAllocator->Dump(); break; case AS_DUMP_BITMAPS: { fMapLocker.Lock(); debug_printf("Application %" B_PRId32 ", %s: %d bitmaps:\n", ClientTeam(), Signature(), (int)fBitmapMap.size()); BitmapMap::const_iterator iterator = fBitmapMap.begin(); for (; iterator != fBitmapMap.end(); iterator++) { ServerBitmap* bitmap = iterator->second; debug_printf(" [%" B_PRId32 "] %" B_PRId32 "x%" B_PRId32 ", " "area %" B_PRId32 ", size %" B_PRId32 "\n", bitmap->Token(), bitmap->Width(), bitmap->Height(), bitmap->Area(), bitmap->BitsLength()); } fMapLocker.Unlock(); break; } case AS_CREATE_WINDOW: case AS_CREATE_OFFSCREEN_WINDOW: { port_id clientReplyPort = -1; status_t status = _CreateWindow(code, link, clientReplyPort); // if sucessful, ServerWindow::Run() will already have replied if (status < B_OK) { // window creation failed, we need to notify the client BPrivate::LinkSender reply(clientReplyPort); reply.StartMessage(status); reply.Flush(); } break; } case AS_GET_WINDOW_LIST: { team_id team; if (link.Read(&team) == B_OK) fDesktop->WriteWindowList(team, fLink.Sender()); break; } case AS_GET_WINDOW_INFO: { int32 serverToken; if (link.Read(&serverToken) == B_OK) fDesktop->WriteWindowInfo(serverToken, fLink.Sender()); break; } case AS_GET_WINDOW_ORDER: { int32 workspace; if (link.Read(&workspace) == B_OK) fDesktop->WriteWindowOrder(workspace, fLink.Sender()); break; } case AS_GET_APPLICATION_ORDER: { int32 workspace; if (link.Read(&workspace) == B_OK) fDesktop->WriteApplicationOrder(workspace, fLink.Sender()); break; } case AS_MINIMIZE_TEAM: { team_id team; if (link.Read(&team) == B_OK) fDesktop->MinimizeApplication(team); break; } case AS_BRING_TEAM_TO_FRONT: { team_id team; if (link.Read(&team) == B_OK) fDesktop->BringApplicationToFront(team); break; } case AS_WINDOW_ACTION: { int32 token; int32 action; link.Read(&token); if (link.Read(&action) != B_OK) break; fDesktop->WindowAction(token, action); break; } // Decorator commands case AS_SET_DECORATOR: { // Attached Data: // path to decorator add-on BString path; link.ReadString(path); status_t error = gDecorManager.SetDecorator(path, fDesktop); fLink.Attach(error); fLink.Flush(); if (error == B_OK) fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR); break; } case AS_GET_DECORATOR: { fLink.StartMessage(B_OK); fLink.AttachString(gDecorManager.GetCurrentDecorator().String()); fLink.Flush(); break; } case AS_SET_CONTROL_LOOK: { STRACE(("ServerApp %s: Set ControlLook\n", Signature())); BString path; status_t error = B_ERROR; if (link.ReadString(path) == B_OK) { LockedDesktopSettings settings(fDesktop); error = settings.SetControlLook(path.String()); } fLink.StartMessage(error); fLink.Flush(); break; } case AS_GET_CONTROL_LOOK: { STRACE(("ServerApp %s: Get ControlLook\n", Signature())); if (fDesktop->LockSingleWindow()) { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.AttachString(settings.ControlLook().String()); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_CREATE_BITMAP: { STRACE(("ServerApp %s: Received BBitmap creation request\n", Signature())); // Allocate a bitmap for an application // Attached Data: // 1) BRect bounds // 2) color_space space // 3) int32 bitmap_flags // 4) int32 bytes_per_row // 5) int32 screen_id // Reply Data: // 1) int32 server token // 2) area_id id of the area in which the bitmap data resides // 3) int32 area pointer offset used to calculate fBasePtr // First, let's attempt to allocate the bitmap BReference bitmap; uint8 allocationFlags = kAllocator; BRect frame; color_space colorSpace; uint32 flags; int32 bytesPerRow; int32 screenID; link.Read(&frame); link.Read(&colorSpace); link.Read(&flags); link.Read(&bytesPerRow); if (link.Read(&screenID) == B_OK) { // TODO: choose the right HWInterface with regards to the // screenID bitmap.SetTo(gBitmapManager->CreateBitmap(fMemoryAllocator, *fDesktop->HWInterface(), frame, colorSpace, flags, bytesPerRow, screenID, &allocationFlags), true); } STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n", Signature(), frame.Width() + 1, frame.Height() + 1)); if (bitmap != NULL && _AddBitmap(bitmap)) { fLink.StartMessage(B_OK); fLink.Attach(bitmap->Token()); fLink.Attach(allocationFlags); fLink.Attach(bitmap->Area()); fLink.Attach(bitmap->AreaOffset()); if ((allocationFlags & kFramebuffer) != 0) fLink.Attach(bitmap->BytesPerRow()); } else { fLink.StartMessage(B_NO_MEMORY); } fLink.Flush(); break; } case AS_DELETE_BITMAP: { STRACE(("ServerApp %s: received BBitmap delete request\n", Signature())); // Attached Data: // 1) int32 token int32 token; link.Read(&token); fMapLocker.Lock(); ServerBitmap* bitmap = _FindBitmap(token); if (bitmap != NULL) { STRACE(("ServerApp %s: Deleting Bitmap %" B_PRId32 "\n", Signature(), token)); _DeleteBitmap(bitmap); } fMapLocker.Unlock(); break; } case AS_GET_BITMAP_OVERLAY_RESTRICTIONS: { overlay_restrictions restrictions; status_t status = B_ERROR; int32 token; if (link.Read(&token) != B_OK) break; BReference bitmap(GetBitmap(token), true); if (bitmap != NULL) { STRACE(("ServerApp %s: Get overlay restrictions for bitmap " "%" B_PRId32 "\n", Signature(), token)); status = fDesktop->HWInterface()->GetOverlayRestrictions( bitmap->Overlay(), &restrictions); } fLink.StartMessage(status); if (status == B_OK) fLink.Attach(&restrictions, sizeof(overlay_restrictions)); fLink.Flush(); break; } case AS_GET_BITMAP_SUPPORT_FLAGS: { uint32 colorSpace; if (link.Read(&colorSpace) != B_OK) break; bool overlay = fDesktop->HWInterface()->CheckOverlayRestrictions( 64, 64, (color_space)colorSpace); uint32 flags = overlay ? B_BITMAPS_SUPPORT_OVERLAY : 0; fLink.StartMessage(B_OK); fLink.Attach(flags); fLink.Flush(); break; } case AS_RECONNECT_BITMAP: { // First, let's attempt to allocate the bitmap BReference bitmap; BRect frame; color_space colorSpace; uint32 flags; int32 bytesPerRow; int32 screenID; area_id clientArea; int32 areaOffset; link.Read(&frame); link.Read(&colorSpace); link.Read(&flags); link.Read(&bytesPerRow); link.Read(&screenID); link.Read(&clientArea); if (link.Read(&areaOffset) == B_OK) { // TODO: choose the right HWInterface with regards to the // screenID bitmap.SetTo(gBitmapManager->CloneFromClient(clientArea, areaOffset, frame, colorSpace, flags, bytesPerRow), true); } if (bitmap != NULL && _AddBitmap(bitmap)) { fLink.StartMessage(B_OK); fLink.Attach(bitmap->Token()); fLink.Attach(bitmap->Area()); } else { fLink.StartMessage(B_NO_MEMORY); } fLink.Flush(); break; } // Picture ops case AS_CREATE_PICTURE: { // TODO: Maybe rename this to AS_UPLOAD_PICTURE ? STRACE(("ServerApp %s: Create Picture\n", Signature())); status_t status = B_NO_MEMORY; BReference picture(CreatePicture()); if (picture != NULL) { int32 subPicturesCount = 0; link.Read(&subPicturesCount); for (int32 i = 0; i < subPicturesCount; i++) { int32 token = -1; link.Read(&token); BAutolock _(fMapLocker); if (ServerPicture* subPicture = _FindPicture(token)) picture->NestPicture(subPicture); } status = picture->ImportData(link); } if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(picture->Token()); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_DELETE_PICTURE: { STRACE(("ServerApp %s: Delete Picture\n", Signature())); int32 token; if (link.Read(&token) == B_OK) { BAutolock _(fMapLocker); ServerPicture* picture = _FindPicture(token); if (picture != NULL) picture->SetOwner(NULL); } break; } case AS_CLONE_PICTURE: { STRACE(("ServerApp %s: Clone Picture\n", Signature())); int32 token; BReference original; if (link.Read(&token) == B_OK) original.SetTo(GetPicture(token), true); if (original != NULL) { BReference cloned(CreatePicture(original), true); if (cloned != NULL) { fLink.StartMessage(B_OK); fLink.Attach(cloned->Token()); } else fLink.StartMessage(B_NO_MEMORY); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_DOWNLOAD_PICTURE: { STRACE(("ServerApp %s: Download Picture\n", Signature())); int32 token; link.Read(&token); BReference picture(GetPicture(token), true); if (picture != NULL) { picture->ExportData(fLink); // ExportData() calls StartMessage() already } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_CURRENT_WORKSPACE: STRACE(("ServerApp %s: get current workspace\n", Signature())); if (fDesktop->LockSingleWindow()) { fLink.StartMessage(B_OK); fLink.Attach(fDesktop->CurrentWorkspace()); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; case AS_ACTIVATE_WORKSPACE: { STRACE(("ServerApp %s: activate workspace\n", Signature())); // TODO: See above int32 index; link.Read(&index); bool takeFocusWindowThere; link.Read(&takeFocusWindowThere); fDesktop->SetWorkspace(index, takeFocusWindowThere); break; } case AS_SET_WORKSPACE_LAYOUT: { int32 newColumns; int32 newRows; if (link.Read(&newColumns) == B_OK && link.Read(&newRows) == B_OK) fDesktop->SetWorkspacesLayout(newColumns, newRows); break; } case AS_GET_WORKSPACE_LAYOUT: { if (fDesktop->LockSingleWindow()) { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach(settings.WorkspacesColumns()); fLink.Attach(settings.WorkspacesRows()); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_IDLE_TIME: STRACE(("ServerApp %s: idle time\n", Signature())); fLink.StartMessage(B_OK); fLink.Attach(fDesktop->EventDispatcher().IdleTime()); fLink.Flush(); break; case AS_SHOW_CURSOR: { STRACE(("ServerApp %s: Show Cursor\n", Signature())); fCursorHideLevel--; if (fCursorHideLevel < 0) fCursorHideLevel = 0; fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0); break; } case AS_HIDE_CURSOR: { STRACE(("ServerApp %s: Hide Cursor\n", Signature())); fCursorHideLevel++; fDesktop->HWInterface()->SetCursorVisible(fCursorHideLevel == 0); break; } case AS_OBSCURE_CURSOR: { STRACE(("ServerApp %s: Obscure Cursor\n", Signature())); fDesktop->HWInterface()->ObscureCursor(); break; } case AS_QUERY_CURSOR_HIDDEN: { STRACE(("ServerApp %s: Received IsCursorHidden request\n", Signature())); fLink.StartMessage(fCursorHideLevel > 0 ? B_OK : B_ERROR); fLink.Flush(); break; } case AS_SET_CURSOR: { STRACE(("ServerApp %s: SetCursor\n", Signature())); // Attached data: // 1) bool flag to send a reply // 2) int32 token ID of the cursor to set // 3) port_id port to receive a reply. Only exists if the sync flag // is true. bool sync; int32 token; link.Read(&sync); if (link.Read(&token) != B_OK) break; if (!fDesktop->GetCursorManager().Lock()) break; fAppCursor.SetTo(fDesktop->GetCursorManager().FindCursor(token), false); if (_HasWindowUnderMouse()) fDesktop->SetCursor(CurrentCursor()); fDesktop->GetCursorManager().Unlock(); if (sync) { // The application is expecting a reply fLink.StartMessage(B_OK); fLink.Flush(); } break; } case AS_SET_VIEW_CURSOR: { STRACE(("ServerApp %s: AS_SET_VIEW_CURSOR:\n", Signature())); ViewSetViewCursorInfo info; if (link.Read(&info) != B_OK) break; if (fDesktop->GetCursorManager().Lock()) { BReference cursor(fDesktop->GetCursorManager().FindCursor( info.cursorToken), false); fDesktop->GetCursorManager().Unlock(); // We need to acquire the write lock here, since we cannot // afford that the window thread to which the view belongs // is running and messing with that same view. fDesktop->LockAllWindows(); // Find the corresponding view by the given token. It's ok // if this view does not exist anymore, since it may have // already be deleted in the window thread before this // message got here. View* view; if (fViewTokens.GetToken(info.viewToken, B_HANDLER_TOKEN, (void**)&view) == B_OK) { // Set the cursor on the view. view->SetCursor(cursor); // The cursor might need to be updated now. Window* window = view->Window(); if (window != NULL && window->IsFocus()) { if (fDesktop->ViewUnderMouse(window) == view->Token()) SetCurrentCursor(cursor); } } fDesktop->UnlockAllWindows(); } if (info.sync) { // sync the client (it can now delete the cursor) fLink.StartMessage(B_OK); fLink.Flush(); } break; } case AS_CREATE_CURSOR: { STRACE(("ServerApp %s: Create Cursor\n", Signature())); // Attached data: // 1) 68 bytes of fAppCursor data // 2) port_id reply port status_t status = B_ERROR; uint8 cursorData[68]; ServerCursor* cursor = NULL; // if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) { // cursor = new (nothrow) ServerCursor(cursorData); // if (cursor == NULL) // status = B_NO_MEMORY; // } // // if (cursor != NULL) { // cursor->SetOwningTeam(fClientTeam); // fDesktop->GetCursorManager().AddCursor(cursor); // // // Synchronous message - BApplication is waiting on the cursor's ID // fLink.StartMessage(B_OK); // fLink.Attach(cursor->Token()); // } else // fLink.StartMessage(status); if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) { cursor = fDesktop->GetCursorManager().CreateCursor(fClientTeam, cursorData); if (cursor == NULL) status = B_NO_MEMORY; } if (cursor != NULL) { // Synchronous message - BApplication is waiting on the // cursor's ID fLink.StartMessage(B_OK); fLink.Attach(cursor->Token()); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_CREATE_CURSOR_BITMAP: { STRACE(("ServerApp %s: Create Cursor bitmap\n", Signature())); status_t status = B_ERROR; int32 size = 0, bytesPerRow = 0; BRect cursorRect; color_space colorspace = B_RGBA32; BPoint hotspot; ServerCursor* cursor = NULL; if (link.Read(&cursorRect) == B_OK && link.Read(&hotspot) == B_OK && link.Read(&colorspace) == B_OK && link.Read(&bytesPerRow) == B_OK && link.Read(&size) == B_OK && size > 0) { BStackOrHeapArray byteArray(size); if (!byteArray.IsValid()) { status = B_NO_MEMORY; } else if (link.Read(byteArray, size) == B_OK) { cursor = fDesktop->GetCursorManager().CreateCursor( fClientTeam, cursorRect, colorspace, 0, hotspot); if (cursor == NULL) status = B_NO_MEMORY; else cursor->ImportBits(byteArray, size, bytesPerRow, colorspace); } } if (cursor != NULL) { // Synchronous message - BApplication is waiting on the // cursor's ID fLink.StartMessage(B_OK); fLink.Attach(cursor->Token()); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_REFERENCE_CURSOR: { STRACE(("ServerApp %s: Reference BCursor\n", Signature())); // Attached data: // 1) int32 token ID of the cursor to reference int32 token; if (link.Read(&token) != B_OK) break; if (!fDesktop->GetCursorManager().Lock()) break; ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token); if (cursor != NULL) cursor->AcquireReference(); fDesktop->GetCursorManager().Unlock(); break; } case AS_DELETE_CURSOR: { STRACE(("ServerApp %s: Delete BCursor\n", Signature())); // Attached data: // 1) int32 token ID of the cursor to delete int32 token; if (link.Read(&token) != B_OK) break; if (!fDesktop->GetCursorManager().Lock()) break; ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token); if (cursor != NULL) cursor->ReleaseReference(); fDesktop->GetCursorManager().Unlock(); break; } case AS_GET_CURSOR_POSITION: { STRACE(("ServerApp %s: Get Cursor position\n", Signature())); // Returns // 1) BPoint mouse location // 2) int32 button state BPoint where; int32 buttons; fDesktop->GetLastMouseState(&where, &buttons); fLink.StartMessage(B_OK); fLink.Attach(where); fLink.Attach(buttons); fLink.Flush(); break; } case AS_GET_CURSOR_BITMAP: { STRACE(("ServerApp %s: Get Cursor bitmap\n", Signature())); // Returns // 1) uint32 number of data bytes of the bitmap // 2) uint32 cursor width in number of pixels // 3) uint32 cursor height in number of pixels // 4) BPoint cursor hot spot // 5) cursor bitmap data ServerCursorReference cursorRef = fDesktop->Cursor(); ServerCursor* cursor = cursorRef.Get(); if (cursor != NULL) { uint32 size = cursor->BitsLength(); fLink.StartMessage(B_OK); fLink.Attach(size); fLink.Attach(cursor->Width()); fLink.Attach(cursor->Height()); fLink.Attach(cursor->ColorSpace()); fLink.Attach(cursor->GetHotSpot()); fLink.Attach(cursor->Bits(), size); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_GET_SCROLLBAR_INFO: { STRACE(("ServerApp %s: Get ScrollBar info\n", Signature())); if (fDesktop->LockSingleWindow()) { scroll_bar_info info; DesktopSettings settings(fDesktop); settings.GetScrollBarInfo(info); fLink.StartMessage(B_OK); fLink.Attach(info); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_SET_SCROLLBAR_INFO: { STRACE(("ServerApp %s: Set ScrollBar info\n", Signature())); // Attached Data: // 1) scroll_bar_info scroll bar info structure scroll_bar_info info; if (link.Read(&info) == B_OK) { LockedDesktopSettings settings(fDesktop); settings.SetScrollBarInfo(info); } fLink.StartMessage(B_OK); fLink.Flush(); break; } case AS_GET_MENU_INFO: { STRACE(("ServerApp %s: Get menu info\n", Signature())); if (fDesktop->LockSingleWindow()) { menu_info info; DesktopSettings settings(fDesktop); settings.GetMenuInfo(info); fLink.StartMessage(B_OK); fLink.Attach(info); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_SET_MENU_INFO: { STRACE(("ServerApp %s: Set menu info\n", Signature())); menu_info info; if (link.Read(&info) == B_OK) { LockedDesktopSettings settings(fDesktop); settings.SetMenuInfo(info); // TODO: SetMenuInfo() should do some validity check, so // that the answer we're giving can actually be useful } fLink.StartMessage(B_OK); fLink.Flush(); break; } case AS_SET_MOUSE_MODE: { STRACE(("ServerApp %s: Set Mouse Focus mode\n", Signature())); // Attached Data: // 1) enum mode_mouse mouse focus mode mode_mouse mouseMode; if (link.Read(&mouseMode) == B_OK) { LockedDesktopSettings settings(fDesktop); settings.SetMouseMode(mouseMode); } break; } case AS_GET_MOUSE_MODE: { STRACE(("ServerApp %s: Get Mouse Focus mode\n", Signature())); if (fDesktop->LockSingleWindow()) { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach(settings.MouseMode()); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_SET_FOCUS_FOLLOWS_MOUSE_MODE: { STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n", Signature())); // Attached Data: // 1) enum mode_focus_follows_mouse FFM mouse mode mode_focus_follows_mouse focusFollowsMousMode; if (link.Read(&focusFollowsMousMode) == B_OK) { LockedDesktopSettings settings(fDesktop); settings.SetFocusFollowsMouseMode(focusFollowsMousMode); } break; } case AS_GET_FOCUS_FOLLOWS_MOUSE_MODE: { STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", Signature())); if (fDesktop->LockSingleWindow()) { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach( settings.FocusFollowsMouseMode()); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_SET_ACCEPT_FIRST_CLICK: { STRACE(("ServerApp %s: Set Accept First Click\n", Signature())); // Attached Data: // 1) bool accept_first_click bool acceptFirstClick; if (link.Read(&acceptFirstClick) == B_OK) { LockedDesktopSettings settings(fDesktop); settings.SetAcceptFirstClick(acceptFirstClick); } break; } case AS_GET_ACCEPT_FIRST_CLICK: { STRACE(("ServerApp %s: Get Accept First Click\n", Signature())); if (fDesktop->LockSingleWindow()) { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach(settings.AcceptFirstClick()); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_GET_SHOW_ALL_DRAGGERS: { STRACE(("ServerApp %s: Get Show All Draggers\n", Signature())); if (fDesktop->LockSingleWindow()) { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach(settings.ShowAllDraggers()); fDesktop->UnlockSingleWindow(); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_SET_SHOW_ALL_DRAGGERS: { STRACE(("ServerApp %s: Set Show All Draggers\n", Signature())); bool changed = false; bool show; if (link.Read(&show) == B_OK) { LockedDesktopSettings settings(fDesktop); if (show != settings.ShowAllDraggers()) { settings.SetShowAllDraggers(show); changed = true; } } if (changed) fDesktop->BroadcastToAllApps(kMsgUpdateShowAllDraggers); break; } case kMsgUpdateShowAllDraggers: { bool show = false; if (fDesktop->LockSingleWindow()) { DesktopSettings settings(fDesktop); show = settings.ShowAllDraggers(); fDesktop->UnlockSingleWindow(); } BMessage update(_SHOW_DRAG_HANDLES_); update.AddBool("show", show); SendMessageToClient(&update); break; } /* font messages */ case AS_ADD_FONT_FILE: { FTRACE(("ServerApp %s: Received BFont creation request\n", Signature())); // Add a font for an application from a file // Attached Data: // 1) char* - path to font on disk // 2) uint16 - index in font file // 3) uint16 - instance // Returns: // 1) uint16 - family ID of added font // 2) uint16 - style ID of added font // 3) uint16 - face of added font AutoLocker< ::FontManager> fontLock(fAppFontManager); if (fAppFontManager->CountFamilies() > MAX_USER_FONTS) { fLink.StartMessage(B_NOT_ALLOWED); fLink.Flush(); break; } uint16 familyID, styleID; char* fontPath; uint16 index, instance; link.ReadString(&fontPath); link.Read(&index); link.Read(&instance); status_t status = fAppFontManager->AddUserFontFromFile(fontPath, index, instance, familyID, styleID); if (status != B_OK) { fLink.StartMessage(status); } else { ServerFont font; status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); fLink.StartMessage(status); if (status == B_OK) { fLink.Attach(font.FamilyID()); fLink.Attach(font.StyleID()); fLink.Attach(font.Face()); } } fLink.Flush(); break; } case AS_ADD_FONT_MEMORY: { FTRACE(("ServerApp %s: Received BFont memory creation request\n", Signature())); // Add a font for an application from a memory area // Attached Data: // 1) area_id - id of memory area where font resides // 2) size_t - size of memory area for font // 3) size_t - offset to start of font memory // 4) uint16 - index in font buffer // 5) uint16 - instance // Returns: // 1) uint16 - family ID of added font // 2) uint16 - style ID of added font // 3) uint16 - face of added font AutoLocker< ::FontManager> fontLock(fAppFontManager); if (fAppFontManager->CountFamilies() > MAX_USER_FONTS) { fLink.StartMessage(B_NOT_ALLOWED); fLink.Flush(); break; } area_id fontAreaID, fontAreaCloneID; area_info fontAreaInfo; char* area_addr; size_t size, offset; uint16 index, instance; link.Read(&fontAreaID); link.Read(&size); link.Read(&offset); link.Read(&index); link.Read(&instance); fontAreaCloneID = clone_area("user font", (void **)&area_addr, B_ANY_ADDRESS, B_READ_AREA, fontAreaID); if (fontAreaCloneID < B_OK) { fLink.StartMessage(fontAreaCloneID); fLink.Flush(); break; } status_t status = get_area_info(fontAreaCloneID, &fontAreaInfo); if (status != B_OK) { fLink.StartMessage(status); fLink.Flush(); delete_area(fontAreaCloneID); break; } size_t fontMemorySize = fontAreaInfo.size - offset; if (size == 0) size = fontMemorySize; // Check size of font area and reject if it's too large if (size > MAX_FONT_DATA_SIZE_BYTES || size > fontMemorySize) { fLink.StartMessage(B_BAD_DATA); fLink.Flush(); delete_area(fontAreaCloneID); break; } FT_Byte* fontData = (FT_Byte*)(malloc (sizeof(FT_Byte) * size)); if (fontData == NULL) { delete_area(fontAreaCloneID); fLink.StartMessage(B_BAD_DATA); fLink.Flush(); break; } memcpy(fontData, (FT_Byte*)fontAreaInfo.address + offset, size); delete_area(fontAreaCloneID); uint16 familyID, styleID; status = fAppFontManager->AddUserFontFromMemory(fontData, size, index, instance, familyID, styleID); if (status != B_OK) { fLink.StartMessage(status); free(fontData); } else { ServerFont font; status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { font.SetFontData(fontData, size); fLink.StartMessage(B_OK); fLink.Attach(font.FamilyID()); fLink.Attach(font.StyleID()); fLink.Attach(font.Face()); } else { fLink.StartMessage(status); free(fontData); } } fLink.Flush(); break; } case AS_REMOVE_FONT: { STRACE(("ServerApp %s: Received BFont removal request\n", Signature())); // Remove an application-added font // Attached Data: // 1) uint16 - familyID of font to remove // 2) uint16 - styleID of font to remove uint16 familyID, styleID; link.Read(&familyID); link.Read(&styleID); status_t status = B_OK; AutoLocker< ::FontManager> fontLock(fAppFontManager); status = fAppFontManager->RemoveUserFont(familyID, styleID); fLink.StartMessage(status); fLink.Flush(); break; } case AS_SET_SYSTEM_FONT: { FTRACE(("ServerApp %s: AS_SET_SYSTEM_FONT\n", Signature())); // gets: // 1) string - font type ("plain", ...) // 2) string - family // 3) string - style // 4) float - size char type[B_OS_NAME_LENGTH]; font_family familyName; font_style styleName; float size; if (link.ReadString(type, sizeof(type)) == B_OK && link.ReadString(familyName, sizeof(familyName)) == B_OK && link.ReadString(styleName, sizeof(styleName)) == B_OK && link.Read(&size) == B_OK) { gFontManager->Lock(); FontStyle* style = gFontManager->GetStyle(familyName, styleName); if (style != NULL) { ServerFont font(*style, size); gFontManager->Unlock(); // We must not have locked the font manager when // locking the desktop (through LockedDesktopSettings // below) LockedDesktopSettings settings(fDesktop); // TODO: Should we also update our internal copies now? if (strcmp(type, "plain") == 0) settings.SetDefaultPlainFont(font); else if (strcmp(type, "bold") == 0) settings.SetDefaultBoldFont(font); else if (strcmp(type, "fixed") == 0) settings.SetDefaultFixedFont(font); } else gFontManager->Unlock(); } break; } case AS_GET_SYSTEM_DEFAULT_FONT: { // input: // 1) string - font type ("plain", ...) ServerFont font; char type[B_OS_NAME_LENGTH]; status_t status = link.ReadString(type, sizeof(type)); if (status == B_OK) { if (strcmp(type, "plain") == 0) font = *gFontManager->DefaultPlainFont(); else if (strcmp(type, "bold") == 0) font = *gFontManager->DefaultBoldFont(); else if (strcmp(type, "fixed") == 0) font = *gFontManager->DefaultFixedFont(); else status = B_BAD_VALUE; } if (status == B_OK) { // returns: // 1) string - family // 2) string - style // 3) float - size fLink.StartMessage(B_OK); fLink.AttachString(font.Family()); fLink.AttachString(font.Style()); fLink.Attach(font.Size()); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_SYSTEM_FONTS: { FTRACE(("ServerApp %s: AS_GET_SYSTEM_FONTS\n", Signature())); // Returns: // 1) uint16 - family ID // 2) uint16 - style ID // 3) float - size in points // 4) uint16 - face flags // 5) uint32 - font flags if (!fDesktop->LockSingleWindow()) { fLink.StartMessage(B_OK); fLink.Flush(); break; } // The client is requesting the system fonts, this // could have happened either at application start up, // or because the client is resyncing with the global // fonts. So we record the current system wide fonts // into our own copies at this point. DesktopSettings settings(fDesktop); settings.GetDefaultPlainFont(fPlainFont); settings.GetDefaultBoldFont(fBoldFont); settings.GetDefaultFixedFont(fFixedFont); fLink.StartMessage(B_OK); for (int32 i = 0; i < 3; i++) { ServerFont* font = NULL; switch (i) { case 0: font = &fPlainFont; fLink.AttachString("plain"); break; case 1: font = &fBoldFont; fLink.AttachString("bold"); break; case 2: font = &fFixedFont; fLink.AttachString("fixed"); break; } fLink.Attach(font->FamilyID()); fLink.Attach(font->StyleID()); fLink.Attach(font->Size()); fLink.Attach(font->Face()); fLink.Attach(font->Flags()); } fDesktop->UnlockSingleWindow(); fLink.Flush(); break; } case AS_GET_FONT_LIST_REVISION: { FTRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature())); fLink.StartMessage(B_OK); fLink.Attach( gFontManager->CheckRevision(fDesktop->UserID())); fLink.Flush(); break; } case AS_GET_FAMILY_AND_STYLES: { FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLES\n", Signature())); // Attached Data: // 1) int32 the index of the font family to get // Returns: // 1) string - name of family // 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT) // 3) count of styles in that family // For each style: // 1) string - name of style // 2) uint16 - face of style // 3) uint32 - flags of style int32 index; link.Read(&index); AutoLocker< ::FontManager> fontLock(gFontManager); FontFamily* family = gFontManager->FamilyAt(index); if (family == NULL) { fontLock.SetTo(fAppFontManager, false); family = fAppFontManager->FamilyAt(index); } if (family) { fLink.StartMessage(B_OK); fLink.AttachString(family->Name()); fLink.Attach(family->Flags()); int32 count = family->CountStyles(); fLink.Attach(count); for (int32 i = 0; i < count; i++) { FontStyle* style = family->StyleAt(i); fLink.AttachString(style->Name()); fLink.Attach(style->Face()); fLink.Attach(style->Flags()); } } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_FAMILY_AND_STYLE: { FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // Returns: // 1) font_family The name of the font family // 2) font_style - name of the style uint16 familyID, styleID; link.Read(&familyID); link.Read(&styleID); AutoLocker< ::FontManager> fontLock(gFontManager); FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID); if (fontStyle == NULL) { fontLock.SetTo(fAppFontManager, false); fontStyle = fAppFontManager->GetStyle(familyID, styleID); } if (fontStyle != NULL) { fLink.StartMessage(B_OK); fLink.AttachString(fontStyle->Family()->Name()); fLink.AttachString(fontStyle->Name()); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_FAMILY_AND_STYLE_IDS: { FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE_IDS\n", Signature())); // Attached Data: // 1) font_family - name of font family to use // 2) font_style - name of style in family // 3) family ID - only used if 1) is empty // 4) style ID - only used if 2) is empty // 5) face - the font's current face // Returns: // 1) uint16 - family ID // 2) uint16 - style ID // 3) uint16 - face font_family family; font_style style; uint16 familyID, styleID; uint16 face; if (link.ReadString(family, sizeof(font_family)) == B_OK && link.ReadString(style, sizeof(font_style)) == B_OK && link.Read(&familyID) == B_OK && link.Read(&styleID) == B_OK && link.Read(&face) == B_OK) { // get the font and return IDs and face AutoLocker< ::FontManager> fontLock(gFontManager); FontStyle* fontStyle = gFontManager->GetStyle(family, style, familyID, styleID, face); if (fontStyle == NULL) { fontLock.SetTo(fAppFontManager, false); fontStyle = fAppFontManager->GetStyle(family, style, familyID, styleID, face); } if (fontStyle != NULL) { fLink.StartMessage(B_OK); fLink.Attach(fontStyle->Family()->ID()); fLink.Attach(fontStyle->ID()); // we try to keep the font face close to what we got face = fontStyle->PreservedFace(face); fLink.Attach(face); } else fLink.StartMessage(B_NAME_NOT_FOUND); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_FONT_FILE_FORMAT: { FTRACE(("ServerApp %s: AS_GET_FONT_FILE_FORMAT\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // Returns: // 1) uint16 font_file_format of font int32 familyID, styleID; link.Read(&familyID); link.Read(&styleID); AutoLocker< ::FontManager> fontLock(gFontManager); FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID); if (fontStyle == NULL) { fontLock.SetTo(fAppFontManager, false); fontStyle = fAppFontManager->GetStyle(familyID, styleID); } if (fontStyle != NULL) { fLink.StartMessage(B_OK); fLink.Attach((uint16)fontStyle->FileFormat()); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_STRING_WIDTHS: { FTRACE(("ServerApp %s: AS_GET_STRING_WIDTHS\n", Signature())); // Attached Data: // 1) uint16 ID of family // 2) uint16 ID of style // 3) float point size of font // 4) uint8 spacing to use // 5) int32 numStrings // 6) int32 string length to measure (numStrings times) // 7) string String to measure (numStrings times) // Returns: // 1) float - width of the string in pixels (numStrings times) uint16 familyID, styleID; float size; uint8 spacing; link.Read(&familyID); link.Read(&styleID); link.Read(&size); link.Read(&spacing); int32 numStrings; if (link.Read(&numStrings) != B_OK) { // this results in a B_BAD_VALUE return numStrings = 0; size = 0.0f; } BStackOrHeapArray widthArray(numStrings); BStackOrHeapArray lengthArray(numStrings); BStackOrHeapArray stringArray(numStrings); if (!widthArray.IsValid() || !lengthArray.IsValid() || !stringArray.IsValid()) { fLink.StartMessage(B_NO_MEMORY); fLink.Flush(); break; } for (int32 i = 0; i < numStrings; i++) { // This version of ReadString allocates the strings, we free // them below link.ReadString(&stringArray[i], (size_t *)&lengthArray[i]); } ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK && size > 0) { font.SetSize(size); font.SetSpacing(spacing); for (int32 i = 0; i < numStrings; i++) { if (!stringArray[i] || lengthArray[i] <= 0) widthArray[i] = 0.0; else { widthArray[i] = font.StringWidth(stringArray[i], lengthArray[i]); } } fLink.StartMessage(B_OK); fLink.Attach(widthArray, numStrings * sizeof(float)); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); for (int32 i = 0; i < numStrings; i++) free(stringArray[i]); break; } case AS_GET_FONT_BOUNDING_BOX: { FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) float - font size // Returns: // 1) BRect - box holding entire font uint16 familyID, styleID; float size; link.Read(&familyID); link.Read(&styleID); link.Read(&size); ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK && size > 0) { font.SetSize(size); fLink.StartMessage(B_OK); fLink.Attach(font.BoundingBox()); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_TUNED_COUNT: { FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // Returns: // 1) int32 - number of font strikes available uint16 familyID, styleID; link.Read(&familyID); link.Read(&styleID); AutoLocker< ::FontManager> fontLock(gFontManager); FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID); if (fontStyle == NULL) { fontLock.SetTo(fAppFontManager, false); fontStyle = fAppFontManager->GetStyle(familyID, styleID); } if (fontStyle != NULL) { fLink.StartMessage(B_OK); fLink.Attach(fontStyle->TunedCount()); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_TUNED_INFO: { FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) uint32 - index of the particular font strike // Returns: // 1) tuned_font_info - info on the strike specified // ToDo: implement me! fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_GET_EXTRA_FONT_FLAGS: { FTRACE(("ServerApp %s: AS_GET_EXTRA_FONT_FLAGS\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // Returns: // 1) uint32 - extra font flags uint16 familyID, styleID; link.Read(&familyID); link.Read(&styleID); AutoLocker< ::FontManager> fontLock(gFontManager); FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID); if (fontStyle == NULL) { fontLock.SetTo(fAppFontManager, false); fontStyle = fAppFontManager->GetStyle(familyID, styleID); } if (fontStyle != NULL) { fLink.StartMessage(B_OK); fLink.Attach(fontStyle->Flags()); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_FONT_HEIGHT: { FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n", Signature())); // Attached Data: // 1) uint16 family ID // 2) uint16 style ID // 3) float size uint16 familyID, styleID; float size; link.Read(&familyID); link.Read(&styleID); link.Read(&size); AutoLocker< ::FontManager> fontLock(gFontManager); FontStyle* fontStyle = gFontManager->GetStyle(familyID, styleID); if (fontStyle == NULL) { fontLock.SetTo(fAppFontManager, false); fontStyle = fAppFontManager->GetStyle(familyID, styleID); } if (fontStyle != NULL) { font_height height; fontStyle->GetHeight(size, height); fLink.StartMessage(B_OK); fLink.Attach(height); } else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_UNICODE_BLOCKS: { FTRACE(("ServerApp %s: AS_GET_UNICODE_BLOCKS\n", Signature())); // Attached Data: // 1) uint16 family ID // 2) uint16 style ID // Returns: // 1) unicode_block - bitfield of Unicode blocks in font uint16 familyID, styleID; link.Read(&familyID); link.Read(&styleID); ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { unicode_block blocksForFont; font.GetUnicodeBlocks(blocksForFont); fLink.StartMessage(B_OK); fLink.Attach(blocksForFont); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_HAS_UNICODE_BLOCK: { FTRACE(("ServerApp %s: AS_INCLUDES_UNICODE_BLOCK\n", Signature())); // Attached Data: // 1) uint16 family ID // 2) uint16 style ID // 3) uint32 start of unicode block // 4) uint32 end of unicode block // Returns: // 1) bool - whether or not font includes specified block range uint16 familyID, styleID; uint32 start, end; link.Read(&familyID); link.Read(&styleID); link.Read(&start); link.Read(&end); ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { bool hasBlock; status = font.IncludesUnicodeBlock(start, end, hasBlock); fLink.StartMessage(status); fLink.Attach(hasBlock); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_GLYPH_SHAPES: { FTRACE(("ServerApp %s: AS_GET_GLYPH_SHAPES\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) float - point size // 4) float - shear // 5) float - rotation // 6) float - false bold width // 6) uint32 - flags // 7) int32 - numChars // 8) int32 - numBytes // 8) char - chars (numBytes times) // Returns: // 1) BShape - glyph shape // numChars times uint16 familyID, styleID; uint32 flags; float size, shear, rotation, falseBoldWidth; link.Read(&familyID); link.Read(&styleID); link.Read(&size); link.Read(&shear); link.Read(&rotation); link.Read(&falseBoldWidth); link.Read(&flags); int32 numChars, numBytes; link.Read(&numChars); link.Read(&numBytes); BStackOrHeapArray charArray(numBytes); BStackOrHeapArray shapes(numChars); if (!charArray.IsValid() || !shapes.IsValid()) { fLink.StartMessage(B_NO_MEMORY); fLink.Flush(); break; } link.Read(charArray, numBytes); ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { font.SetSize(size); font.SetShear(shear); font.SetRotation(rotation); font.SetFalseBoldWidth(falseBoldWidth); font.SetFlags(flags); status = font.GetGlyphShapes(charArray, numChars, shapes); if (status == B_OK) { fLink.StartMessage(B_OK); for (int32 i = 0; i < numChars; i++) { fLink.AttachShape(*shapes[i]); delete shapes[i]; } } } if (status != B_OK) fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_HAS_GLYPHS: { FTRACE(("ServerApp %s: AS_GET_HAS_GLYPHS\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) int32 - numChars // 4) int32 - numBytes // 5) char - the char buffer with size numBytes uint16 familyID, styleID; link.Read(&familyID); link.Read(&styleID); int32 numChars, numBytes; link.Read(&numChars); link.Read(&numBytes); BStackOrHeapArray charArray(numBytes); BStackOrHeapArray hasArray(numChars); if (!charArray.IsValid() || !hasArray.IsValid()) { fLink.StartMessage(B_NO_MEMORY); fLink.Flush(); break; } link.Read(charArray, numBytes); ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { status = font.GetHasGlyphs(charArray, numBytes, numChars, hasArray); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(hasArray, numChars * sizeof(bool)); } } if (status != B_OK) fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_EDGES: { FTRACE(("ServerApp %s: AS_GET_EDGES\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) int32 - numChars // 4) int32 - numBytes // 5) char - the char buffer with size numBytes uint16 familyID, styleID; link.Read(&familyID); link.Read(&styleID); int32 numChars; link.Read(&numChars); uint32 numBytes; link.Read(&numBytes); BStackOrHeapArray charArray(numBytes); BStackOrHeapArray edgeArray(numChars); if (!charArray.IsValid() || !edgeArray.IsValid()) { fLink.StartMessage(B_NO_MEMORY); fLink.Flush(); break; } link.Read(charArray, numBytes); ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { status = font.GetEdges(charArray, numBytes, numChars, edgeArray); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(edgeArray, numChars * sizeof(edge_info)); } } if (status != B_OK) fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_ESCAPEMENTS: { FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) float - point size // 4) uint8 - spacing // 5) float - rotation // 6) uint32 - flags // 7) int32 - numChars // 8) char - char -\ both // 9) BPoint - offset -/ (numChars times) // Returns: // 1) BPoint - escapement // numChars times uint16 familyID, styleID; uint32 flags; float size, rotation; uint8 spacing; link.Read(&familyID); link.Read(&styleID); link.Read(&size); link.Read(&spacing); link.Read(&rotation); link.Read(&flags); escapement_delta delta; link.Read(&delta.nonspace); link.Read(&delta.space); bool wantsOffsets; link.Read(&wantsOffsets); int32 numChars; link.Read(&numChars); uint32 numBytes; link.Read(&numBytes); BStackOrHeapArray charArray(numBytes); BStackOrHeapArray escapements(numChars); BPoint* offsets = NULL; if (wantsOffsets) offsets = new(std::nothrow) BPoint[numChars]; if (!charArray.IsValid() || !escapements.IsValid() || (offsets == NULL && wantsOffsets)) { delete[] offsets; fLink.StartMessage(B_NO_MEMORY); fLink.Flush(); break; } link.Read(charArray, numBytes); ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { font.SetSize(size); font.SetSpacing(spacing); font.SetRotation(rotation); font.SetFlags(flags); status = font.GetEscapements(charArray, numBytes, numChars, delta, escapements, offsets); if (status == B_OK) { fLink.StartMessage(B_OK); for (int32 i = 0; i < numChars; i++) fLink.Attach(escapements[i]); if (wantsOffsets) { for (int32 i = 0; i < numChars; i++) fLink.Attach(offsets[i]); } } } if (status != B_OK) fLink.StartMessage(status); delete[] offsets; fLink.Flush(); break; } case AS_GET_ESCAPEMENTS_AS_FLOATS: { FTRACE(("ServerApp %s: AS_GET_ESCAPEMENTS_AS_FLOATS\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) float - point size // 4) uint8 - spacing // 5) float - rotation // 6) uint32 - flags // 7) float - additional "nonspace" delta // 8) float - additional "space" delta // 9) int32 - numChars // 10) int32 - numBytes // 11) char - the char buffer with size numBytes // Returns: // 1) float - escapement buffer with numChar entries uint16 familyID, styleID; uint32 flags; float size, rotation; uint8 spacing; link.Read(&familyID); link.Read(&styleID); link.Read(&size); link.Read(&spacing); link.Read(&rotation); link.Read(&flags); escapement_delta delta; link.Read(&delta.nonspace); link.Read(&delta.space); int32 numChars; link.Read(&numChars); uint32 numBytes; link.Read(&numBytes); BStackOrHeapArray charArray(numBytes); BStackOrHeapArray escapements(numChars); if (!charArray.IsValid() || !escapements.IsValid()) { fLink.StartMessage(B_NO_MEMORY); fLink.Flush(); break; } link.Read(charArray, numBytes); // figure out escapements ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { font.SetSize(size); font.SetSpacing(spacing); font.SetRotation(rotation); font.SetFlags(flags); status = font.GetEscapements(charArray, numBytes, numChars, delta, escapements); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(escapements, numChars * sizeof(float)); } } if (status != B_OK) fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_BOUNDINGBOXES_CHARS: case AS_GET_BOUNDINGBOXES_STRING: { FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_CHARS\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) float - point size // 4) float - rotation // 5) float - shear // 6) float - false bold width // 7) uint8 - spacing // 8) uint32 - flags // 9) font_metric_mode - mode // 10) bool - string escapement // 11) escapement_delta - additional delta // 12) int32 - numChars // 13) int32 - numBytes // 14) char - the char buffer with size numBytes // Returns: // 1) BRect - rects with numChar entries uint16 familyID, styleID; uint32 flags; float size, rotation, shear, falseBoldWidth; uint8 spacing; font_metric_mode mode; bool stringEscapement; link.Read(&familyID); link.Read(&styleID); link.Read(&size); link.Read(&rotation); link.Read(&shear); link.Read(&falseBoldWidth); link.Read(&spacing); link.Read(&flags); link.Read(&mode); link.Read(&stringEscapement); escapement_delta delta; link.Read(&delta); int32 numChars; link.Read(&numChars); uint32 numBytes; link.Read(&numBytes); BStackOrHeapArray charArray(numBytes); BStackOrHeapArray rectArray(numChars); if (!charArray.IsValid() || !rectArray.IsValid()) { fLink.StartMessage(B_NO_MEMORY); fLink.Flush(); break; } link.Read(charArray, numBytes); // figure out escapements ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { font.SetSize(size); font.SetRotation(rotation); font.SetShear(shear); font.SetFalseBoldWidth(falseBoldWidth); font.SetSpacing(spacing); font.SetFlags(flags); // TODO: implement for real status = font.GetBoundingBoxes(charArray, numBytes, numChars, rectArray, stringEscapement, mode, delta, code == AS_GET_BOUNDINGBOXES_STRING); if (status == B_OK) { fLink.StartMessage(B_OK); for (int32 i = 0; i < numChars; i++) fLink.Attach(rectArray[i]); } } if (status != B_OK) fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_BOUNDINGBOXES_STRINGS: { FTRACE(("ServerApp %s: AS_GET_BOUNDINGBOXES_STRINGS\n", Signature())); // Attached Data: // 1) uint16 - family ID // 2) uint16 - style ID // 3) float - point size // 4) float - rotation // 5) float - shear // 6) float - false bold width // 7) uint8 - spacing // 8) uint32 - flags // 9) font_metric_mode - mode // 10) int32 numStrings // 11) escapement_delta - additional delta (numStrings times) // 12) int32 string length to measure (numStrings times) // 13) string - string (numStrings times) // Returns: // 1) BRect - rects with numStrings entries uint16 familyID, styleID; uint32 flags; float ptsize, rotation, shear, falseBoldWidth; uint8 spacing; font_metric_mode mode; link.Read(&familyID); link.Read(&styleID); link.Read(&ptsize); link.Read(&rotation); link.Read(&shear); link.Read(&falseBoldWidth); link.Read(&spacing); link.Read(&flags); link.Read(&mode); int32 numStrings; link.Read(&numStrings); BStackOrHeapArray deltaArray(numStrings); BStackOrHeapArray stringArray(numStrings); BStackOrHeapArray lengthArray(numStrings); BStackOrHeapArray rectArray(numStrings); if (!deltaArray.IsValid() || !stringArray.IsValid() || !lengthArray.IsValid() || !rectArray.IsValid()) { fLink.StartMessage(B_NO_MEMORY); fLink.Flush(); break; } for (int32 i = 0; i < numStrings; i++) { // This version of ReadString allocates the strings, we free // them below link.ReadString(&stringArray[i], &lengthArray[i]); link.Read(&deltaArray[i]); } ServerFont font; status_t status = font.SetFamilyAndStyle(familyID, styleID, fAppFontManager); if (status == B_OK) { font.SetSize(ptsize); font.SetRotation(rotation); font.SetShear(shear); font.SetFalseBoldWidth(falseBoldWidth); font.SetSpacing(spacing); font.SetFlags(flags); status = font.GetBoundingBoxesForStrings(stringArray, lengthArray, numStrings, rectArray, mode, deltaArray); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(rectArray, numStrings * sizeof(BRect)); } } for (int32 i = 0; i < numStrings; i++) free(stringArray[i]); if (status != B_OK) fLink.StartMessage(status); fLink.Flush(); break; } // Screen commands case AS_VALID_SCREEN_ID: { // Attached data // 1) int32 screen int32 id; if (link.Read(&id) == B_OK && id == B_MAIN_SCREEN_ID.id) fLink.StartMessage(B_OK); else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_GET_NEXT_SCREEN_ID: { // Attached data // 1) int32 screen int32 id; link.Read(&id); // TODO: for now, just say we're the last one fLink.StartMessage(B_ENTRY_NOT_FOUND); fLink.Flush(); break; } case AS_GET_SCREEN_ID_FROM_WINDOW: { status_t status = B_BAD_VALUE; // Attached data // 1) int32 - window client token int32 clientToken; if (link.Read(&clientToken) != B_OK) status = B_BAD_DATA; else { BAutolock locker(fWindowListLock); for (int32 i = fWindowList.CountItems(); i-- > 0;) { ServerWindow* serverWindow = fWindowList.ItemAt(i); if (serverWindow->ClientToken() == clientToken) { AutoReadLocker _(fDesktop->ScreenLocker()); // found it! Window* window = serverWindow->Window(); const Screen* screen = NULL; if (window != NULL) screen = window->Screen(); if (screen == NULL) { // The window hasn't been added to the desktop yet, // or it's an offscreen window break; } fLink.StartMessage(B_OK); fLink.Attach(screen->ID()); status = B_OK; break; } } } if (status != B_OK) fLink.StartMessage(status); fLink.Flush(); break; } case AS_SCREEN_GET_MODE: { STRACE(("ServerApp %s: AS_SCREEN_GET_MODE\n", Signature())); // Attached data // 1) int32 screen // 2) uint32 workspace index int32 id; link.Read(&id); uint32 workspace; link.Read(&workspace); display_mode mode; status_t status = fDesktop->GetScreenMode(workspace, id, mode); fLink.StartMessage(status); if (status == B_OK) fLink.Attach(mode); fLink.Flush(); break; } case AS_SCREEN_SET_MODE: { STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature())); // Attached data // 1) int32 screen // 2) workspace index // 3) display_mode to set // 4) 'makeDefault' boolean int32 id; link.Read(&id); uint32 workspace; link.Read(&workspace); display_mode mode; link.Read(&mode); bool makeDefault = false; status_t status = link.Read(&makeDefault); if (status == B_OK) { status = fDesktop->SetScreenMode(workspace, id, mode, makeDefault); } if (status == B_OK) { if (workspace == (uint32)B_CURRENT_WORKSPACE_INDEX && fDesktop->LockSingleWindow()) { workspace = fDesktop->CurrentWorkspace(); fDesktop->UnlockSingleWindow(); } if (!makeDefault) { // Memorize the screen change, so that it can be reverted // later fTemporaryDisplayModeChange |= 1 << workspace; } else fTemporaryDisplayModeChange &= ~(1 << workspace); } fLink.StartMessage(status); fLink.Flush(); break; } case AS_PROPOSE_MODE: { STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature())); int32 id; link.Read(&id); display_mode target, low, high; link.Read(&target); link.Read(&low); link.Read(&high); status_t status = fDesktop->HWInterface()->ProposeMode(&target, &low, &high); // ProposeMode() returns B_BAD_VALUE to hint that the candidate is // not within the given limits (but is supported) if (status == B_OK || status == B_BAD_VALUE) { fLink.StartMessage(B_OK); fLink.Attach(target); fLink.Attach(status == B_OK); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_MODE_LIST: { int32 id; link.Read(&id); // TODO: use this screen id display_mode* modeList; uint32 count; status_t status = fDesktop->HWInterface()->GetModeList(&modeList, &count); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(count); fLink.Attach(modeList, sizeof(display_mode) * count); delete[] modeList; } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_SCREEN_FRAME: { STRACE(("ServerApp %s: AS_GET_SCREEN_FRAME\n", Signature())); // Attached data // 1) int32 screen // 2) uint32 workspace index int32 id; link.Read(&id); uint32 workspace; link.Read(&workspace); BRect frame; status_t status = fDesktop->GetScreenFrame(workspace, id, frame); fLink.StartMessage(status); if (status == B_OK) fLink.Attach(frame); fLink.Flush(); break; } case AS_SCREEN_GET_COLORMAP: { STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature())); int32 id; link.Read(&id); const color_map* colorMap = SystemColorMap(); if (colorMap != NULL) { fLink.StartMessage(B_OK); fLink.Attach(*colorMap); } else fLink.StartMessage(B_ERROR); fLink.Flush(); break; } case AS_GET_DESKTOP_COLOR: { STRACE(("ServerApp %s: get desktop color\n", Signature())); uint32 index; link.Read(&index); fLink.StartMessage(B_OK); fDesktop->LockSingleWindow(); // we're nice to our children (and also take the default case // into account which asks for the current workspace) if (index >= (uint32)kMaxWorkspaces) index = fDesktop->CurrentWorkspace(); Workspace workspace(*fDesktop, index, true); fLink.Attach(workspace.Color()); fDesktop->UnlockSingleWindow(); fLink.Flush(); break; } case AS_SET_DESKTOP_COLOR: { STRACE(("ServerApp %s: set desktop color\n", Signature())); rgb_color color; uint32 index; bool makeDefault; link.Read(&color); link.Read(&index); if (link.Read(&makeDefault) != B_OK) break; fDesktop->LockAllWindows(); // we're nice to our children (and also take the default case // into account which asks for the current workspace) if (index >= (uint32)kMaxWorkspaces) index = fDesktop->CurrentWorkspace(); Workspace workspace(*fDesktop, index); workspace.SetColor(color, makeDefault); fDesktop->UnlockAllWindows(); break; } case AS_GET_ACCELERANT_INFO: { STRACE(("ServerApp %s: get accelerant info\n", Signature())); // We aren't using the screen_id for now... int32 id; link.Read(&id); accelerant_device_info accelerantInfo; // TODO: I wonder if there should be a "desktop" lock... status_t status = fDesktop->HWInterface()->GetDeviceInfo(&accelerantInfo); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(accelerantInfo); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_MONITOR_INFO: { STRACE(("ServerApp %s: get monitor info\n", Signature())); // We aren't using the screen_id for now... int32 id; link.Read(&id); monitor_info info; // TODO: I wonder if there should be a "desktop" lock... status_t status = fDesktop->HWInterface()->GetMonitorInfo(&info); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(info); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_FRAME_BUFFER_CONFIG: { STRACE(("ServerApp %s: get frame buffer config\n", Signature())); // We aren't using the screen_id for now... int32 id; link.Read(&id); frame_buffer_config config; // TODO: I wonder if there should be a "desktop" lock... status_t status = fDesktop->HWInterface()->GetFrameBufferConfig(config); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(config); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_RETRACE_SEMAPHORE: { STRACE(("ServerApp %s: get retrace semaphore\n", Signature())); // We aren't using the screen_id for now... int32 id; link.Read(&id); fLink.StartMessage(B_OK); fLink.Attach(fDesktop->HWInterface()->RetraceSemaphore()); fLink.Flush(); break; } case AS_GET_TIMING_CONSTRAINTS: { STRACE(("ServerApp %s: get timing constraints\n", Signature())); // We aren't using the screen_id for now... int32 id; link.Read(&id); display_timing_constraints constraints; status_t status = fDesktop->HWInterface()->GetTimingConstraints( &constraints); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(constraints); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_PIXEL_CLOCK_LIMITS: { STRACE(("ServerApp %s: get pixel clock limits\n", Signature())); // We aren't using the screen_id for now... int32 id; link.Read(&id); display_mode mode; link.Read(&mode); uint32 low, high; status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode, &low, &high); if (status == B_OK) { fLink.StartMessage(B_OK); fLink.Attach(low); fLink.Attach(high); } else fLink.StartMessage(status); fLink.Flush(); break; } case AS_SET_DPMS: { STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature())); int32 id; link.Read(&id); uint32 mode; link.Read(&mode); status_t status = fDesktop->HWInterface()->SetDPMSMode(mode); fLink.StartMessage(status); fLink.Flush(); break; } case AS_GET_DPMS_STATE: { STRACE(("ServerApp %s: AS_GET_DPMS_STATE\n", Signature())); int32 id; link.Read(&id); uint32 state = fDesktop->HWInterface()->DPMSMode(); fLink.StartMessage(B_OK); fLink.Attach(state); fLink.Flush(); break; } case AS_GET_DPMS_CAPABILITIES: { STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature())); int32 id; link.Read(&id); uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities(); fLink.StartMessage(B_OK); fLink.Attach(capabilities); fLink.Flush(); break; } case AS_SCREEN_SET_BRIGHTNESS: { STRACE(("ServerApp %s: AS_SCREEN_SET_BRIGHTNESS\n", Signature())); int32 id; link.Read(&id); float brightness; link.Read(&brightness); status_t status = fDesktop->SetBrightness(id, brightness); fLink.StartMessage(status); fLink.Flush(); break; } case AS_SCREEN_GET_BRIGHTNESS: { STRACE(("ServerApp %s: AS_SCREEN_GET_BRIGHTNESS\n", Signature())); int32 id; link.Read(&id); float brightness; status_t result = fDesktop->HWInterface()->GetBrightness(&brightness); fLink.StartMessage(result); if (result == B_OK) fLink.Attach(brightness); fLink.Flush(); break; } case AS_READ_BITMAP: { STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature())); int32 token; link.Read(&token); bool drawCursor = true; link.Read(&drawCursor); BRect bounds; link.Read(&bounds); bool success = false; BReference bitmap(GetBitmap(token), true); if (bitmap != NULL) { if (fDesktop->GetDrawingEngine()->LockExclusiveAccess()) { success = fDesktop->GetDrawingEngine()->ReadBitmap(bitmap, drawCursor, bounds) == B_OK; fDesktop->GetDrawingEngine()->UnlockExclusiveAccess(); } } if (success) fLink.StartMessage(B_OK); else fLink.StartMessage(B_BAD_VALUE); fLink.Flush(); break; } case AS_GET_ACCELERANT_PATH: { int32 id; fLink.Read(&id); BString path; status_t status = fDesktop->HWInterface()->GetAccelerantPath(path); fLink.StartMessage(status); if (status == B_OK) fLink.AttachString(path.String()); fLink.Flush(); break; } case AS_GET_DRIVER_PATH: { int32 id; fLink.Read(&id); BString path; status_t status = fDesktop->HWInterface()->GetDriverPath(path); fLink.StartMessage(status); if (status == B_OK) fLink.AttachString(path.String()); fLink.Flush(); break; } // BWindowScreen communication case AS_DIRECT_SCREEN_LOCK: { bool lock; link.Read(&lock); status_t status; if (lock) status = fDesktop->LockDirectScreen(ClientTeam()); else status = fDesktop->UnlockDirectScreen(ClientTeam()); fLink.StartMessage(status); fLink.Flush(); break; } // Hinting and aliasing case AS_SET_SUBPIXEL_ANTIALIASING: { bool subpix; if (link.Read(&subpix) == B_OK) { LockedDesktopSettings settings(fDesktop); settings.SetSubpixelAntialiasing(subpix); } fDesktop->Redraw(); break; } case AS_GET_SUBPIXEL_ANTIALIASING: { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach(settings.SubpixelAntialiasing()); fLink.Flush(); break; } case AS_SET_HINTING: { uint8 hinting; if (link.Read(&hinting) == B_OK && hinting < 3) { LockedDesktopSettings settings(fDesktop); if (hinting != settings.Hinting()) { settings.SetHinting(hinting); fDesktop->Redraw(); } } break; } case AS_GET_HINTING: { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach(settings.Hinting()); fLink.Flush(); break; } case AS_SET_SUBPIXEL_AVERAGE_WEIGHT: { uint8 averageWeight; if (link.Read(&averageWeight) == B_OK) { LockedDesktopSettings settings(fDesktop); settings.SetSubpixelAverageWeight(averageWeight); } fDesktop->Redraw(); break; } case AS_GET_SUBPIXEL_AVERAGE_WEIGHT: { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach(settings.SubpixelAverageWeight()); fLink.Flush(); break; } case AS_SET_SUBPIXEL_ORDERING: { bool subpixelOrdering; if (link.Read(&subpixelOrdering) == B_OK) { LockedDesktopSettings settings(fDesktop); settings.SetSubpixelOrderingRegular(subpixelOrdering); } fDesktop->Redraw(); break; } case AS_GET_SUBPIXEL_ORDERING: { DesktopSettings settings(fDesktop); fLink.StartMessage(B_OK); fLink.Attach(settings.IsSubpixelOrderingRegular()); fLink.Flush(); break; } default: printf("ServerApp %s received unhandled message code %" B_PRId32 "\n", Signature(), code); if (link.NeedsReply()) { // the client is now blocking and waiting for a reply! fLink.StartMessage(B_ERROR); fLink.Flush(); } else puts("message doesn't need a reply!"); break; } } /*! \brief The thread function ServerApps use to monitor messages */ void ServerApp::_MessageLooper() { // Message-dispatching loop for the ServerApp // get our own team ID thread_info threadInfo; get_thread_info(fThread, &threadInfo); // First let's tell the client how to talk with us. fLink.StartMessage(B_OK); fLink.Attach(fMessagePort); fLink.Attach(fDesktop->SharedReadOnlyArea()); fLink.Attach(threadInfo.team); fLink.Flush(); BPrivate::LinkReceiver &receiver = fLink.Receiver(); int32 code; status_t err = B_OK; while (!fQuitting) { STRACE(("info: ServerApp::_MessageLooper() listening on port %" B_PRId32 ".\n", fMessagePort)); err = receiver.GetNextMessage(code); if (err != B_OK || code == B_QUIT_REQUESTED) { STRACE(("ServerApp: application seems to be gone...\n")); // Tell desktop to quit us BPrivate::LinkSender link(fDesktop->MessagePort()); link.StartMessage(AS_DELETE_APP); link.Attach(Thread()); link.Flush(); break; } switch (code) { case kMsgAppQuit: // we receive this from our destructor on quit fQuitting = true; break; case AS_QUIT_APP: { // This message is received only when the app_server is asked // to shut down in test/debug mode. Of course, if we are testing // while using AccelerantDriver, we do NOT want to shut down // client applications. The server can be quit in this fashion // through the driver's interface, such as closing the // ViewDriver's window. STRACE(("ServerApp %s:Server shutdown notification received\n", Signature())); // If we are using the real, accelerated version of the // DrawingEngine, we do NOT want the user to be able shut down // the server. The results would NOT be pretty #if TEST_MODE BMessage pleaseQuit(B_QUIT_REQUESTED); SendMessageToClient(&pleaseQuit); #endif break; } default: STRACE(("ServerApp %s: Got a Message to dispatch\n", Signature())); _DispatchMessage(code, receiver); break; } } // Quit() will send us a message; we're handling the exiting procedure thread_id sender; sem_id shutdownSemaphore; receive_data(&sender, &shutdownSemaphore, sizeof(sem_id)); delete this; if (shutdownSemaphore >= B_OK) release_sem(shutdownSemaphore); } status_t ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link, port_id& clientReplyPort) { // Attached data: // 1) int32 bitmap token (only for AS_CREATE_OFFSCREEN_WINDOW) // 2) BRect window frame // 3) uint32 window look // 4) uint32 window feel // 5) uint32 window flags // 6) uint32 workspace index // 7) int32 BHandler token of the window // 8) port_id window's reply port // 9) port_id window's looper port // 10) const char * title BRect frame; int32 bitmapToken; uint32 look; uint32 feel; uint32 flags; uint32 workspaces; int32 token; port_id looperPort; char* title; if (code == AS_CREATE_OFFSCREEN_WINDOW) link.Read(&bitmapToken); link.Read(&frame); link.Read(&look); link.Read(&feel); link.Read(&flags); link.Read(&workspaces); link.Read(&token); link.Read(&clientReplyPort); link.Read(&looperPort); if (link.ReadString(&title) != B_OK) return B_ERROR; if (!frame.IsValid()) { // make sure we pass a valid rectangle to ServerWindow frame.right = frame.left + 1; frame.bottom = frame.top + 1; } status_t status = B_NO_MEMORY; ServerWindow *window = NULL; if (code == AS_CREATE_OFFSCREEN_WINDOW) { ServerBitmap* bitmap = GetBitmap(bitmapToken); if (bitmap != NULL) { window = new (nothrow) OffscreenServerWindow(title, this, clientReplyPort, looperPort, token, bitmap); } else status = B_ERROR; } else { window = new (nothrow) ServerWindow(title, this, clientReplyPort, looperPort, token); STRACE(("\nServerApp %s: New Window %s (%g:%g, %g:%g)\n", Signature(), title, frame.left, frame.top, frame.right, frame.bottom)); } free(title); // NOTE: the reply to the client is handled in ServerWindow::Run() if (window != NULL) { status = window->Init(frame, (window_look)look, (window_feel)feel, flags, workspaces); if (status == B_OK) { status = window->Run(); if (status != B_OK) { syslog(LOG_ERR, "ServerApp::_CreateWindow() - failed to run " "the window thread\n"); } } if (status != B_OK) delete window; } return status; } bool ServerApp::_HasWindowUnderMouse() { BAutolock locker(fWindowListLock); for (int32 i = fWindowList.CountItems(); i-- > 0;) { ServerWindow* serverWindow = fWindowList.ItemAt(i); if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN) return true; } return false; } bool ServerApp::_AddBitmap(ServerBitmap* bitmap) { BAutolock _(fMapLocker); try { fBitmapMap.insert(std::make_pair(bitmap->Token(), BReference(bitmap, false))); } catch (std::bad_alloc& exception) { return false; } bitmap->SetOwner(this); return true; } void ServerApp::_DeleteBitmap(ServerBitmap* bitmap) { ASSERT(fMapLocker.IsLocked()); gBitmapManager->BitmapRemoved(bitmap); fBitmapMap.erase(bitmap->Token()); } ServerBitmap* ServerApp::_FindBitmap(int32 token) const { ASSERT(fMapLocker.IsLocked()); BitmapMap::const_iterator iterator = fBitmapMap.find(token); if (iterator == fBitmapMap.end()) return NULL; return iterator->second; } ServerPicture* ServerApp::_FindPicture(int32 token) const { ASSERT(fMapLocker.IsLocked()); PictureMap::const_iterator iterator = fPictureMap.find(token); if (iterator == fPictureMap.end()) return NULL; return iterator->second; }