haiku/src/servers/app/ServerApp.cpp
Axel Dörfler 27adb96962 Massive RootLayer & Workspace tearing:
* workspace switch and subset windows functionality temporarily removed
  (away with that mess!).
* no more RevealWMState() - we now have methods like ActivateWindow()
  and SendWindowBehind() that do all the work - just a little cleaner
  and with less overhead.
* Workspace is now a pretty passive class - it only stores configurations
  of the windows and screens.
* added an evil work-around for a locking problem (in RootLayer::_SetFocus()).
* I'll plan to move pretty much all of the remaining root layer functionality
  to Desktop - so that the all regions lock is only held in case clipping
  regions are affected.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15207 a95241bf-73f2-0310-859d-f6bbb57e9c96
2005-11-28 23:36:59 +00:00

2438 lines
60 KiB
C++

/*
* Copyright 2001-2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adrian Oanca <adioanca@cotty.iren.ro>
* Stephan Aßmus <superstippi@gmx.de>
* Stefano Ceccherini (burton666@libero.it)
* Axel Dörfler, axeld@pinc-software.de
* Jérôme Duval, jerome.duval@free.fr
*/
/*!
\class ServerApp ServerApp.h
\brief Counterpart to BApplication within the app_server
*/
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <AppDefs.h>
#include <Autolock.h>
#include <List.h>
#include <ScrollBar.h>
#include <Shape.h>
#include <String.h>
#include <ColorSet.h>
#include <FontPrivate.h>
#include <MessengerPrivate.h>
#include <ServerProtocol.h>
#include "AppServer.h"
#include "BGet++.h"
#include "BitmapManager.h"
#include "CursorManager.h"
#include "CursorSet.h"
#include "Desktop.h"
#include "DecorManager.h"
#include "DrawingEngine.h"
#include "EventStream.h"
#include "FontManager.h"
#include "HWInterface.h"
#include "InputManager.h"
#include "OffscreenServerWindow.h"
#include "RAMLinkMsgReader.h"
#include "RootLayer.h"
#include "ServerApp.h"
#include "ServerBitmap.h"
#include "ServerConfig.h"
#include "ServerCursor.h"
#include "ServerPicture.h"
#include "ServerScreen.h"
#include "ServerTokenSpace.h"
#include "ServerWindow.h"
#include "SystemPalette.h"
#include "WindowLayer.h"
//#define DEBUG_SERVERAPP
#ifdef DEBUG_SERVERAPP
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
//#define DEBUG_SERVERAPP_FONT
#ifdef DEBUG_SERVERAPP_FONT
# define FTRACE(x) printf x
#else
# define FTRACE(x) ;
#endif
using std::nothrow;
static const uint32 kMsgAppQuit = 'appQ';
/*!
\brief Constructor
\param sendport port ID for the BApplication which will receive the ServerApp's messages
\param rcvport port by which the ServerApp will receive messages from its BApplication.
\param fSignature NULL-terminated string which contains the BApplication's
MIME fSignature.
*/
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"),
fAppCursor(NULL),
fCursorHidden(false),
fIsActive(false),
fSharedMem("shared memory")
{
if (fSignature == "")
fSignature = "application/no-signature";
char name[B_OS_NAME_LENGTH];
snprintf(name, sizeof(name), "a<%s", Signature());
fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name);
if (fMessagePort < B_OK)
return;
fLink.SetSenderPort(fClientReplyPort);
fLink.SetReceiverPort(fMessagePort);
// we let the application own the port, so that we get aware when it's gone
if (set_port_owner(fMessagePort, clientTeam) < B_OK) {
delete_port(fMessagePort);
fMessagePort = -1;
return;
}
BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
clientLooperPort, clientToken);
ServerCursor *defaultCursor =
fDesktop->GetCursorManager().GetCursor(B_CURSOR_DEFAULT);
if (defaultCursor) {
fAppCursor = new ServerCursor(defaultCursor);
fAppCursor->SetOwningTeam(fClientTeam);
}
STRACE(("ServerApp %s:\n", Signature()));
STRACE(("\tBApp port: %ld\n", fClientReplyPort));
STRACE(("\tReceiver port: %ld\n", fMessagePort));
}
//! Does all necessary teardown for application
ServerApp::~ServerApp(void)
{
STRACE(("*ServerApp %s:~ServerApp()\n", Signature()));
if (!fQuitting)
CRITICAL("ServerApp: destructor called after Run()!\n");
// 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);
fWindowListLock.Lock();
for (int32 i = fWindowList.CountItems(); i-- > 0;) {
sem_id deathSemaphore = fWindowList.ItemAt(i)->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
#if __HAIKU__
syslog(LOG_ERR, "ServerApp %s needs to kill some server windows!\n",
Signature());
#else
printf("ServerApp %s needs to kill some server windows!\n",
Signature());
#endif
// there still seem to be some windows left - kill them!
fWindowListLock.Lock();
for (int32 i = 0; i < fWindowList.CountItems(); i++) {
ServerWindow* window = fWindowList.ItemAt(i);
printf("kill window \"%s\"\n", window->Title());
kill_thread(window->Thread());
window->Hide();
delete window;
}
fWindowListLock.Unlock();
}
fWindowListLock.Lock();
}
// first, make sure our monitor thread doesn't
for (int32 i = 0; i < fBitmapList.CountItems(); i++) {
gBitmapManager->DeleteBitmap(static_cast<ServerBitmap *>(fBitmapList.ItemAt(i)));
}
for (int32 i = 0; i < fPictureList.CountItems(); i++) {
delete (ServerPicture*)fPictureList.ItemAt(i);
}
fDesktop->GetCursorManager().RemoveAppCursors(fClientTeam);
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.Sem() < B_OK)
return fWindowListLock.Sem();
return B_OK;
}
/*!
\brief Starts the ServerApp monitoring for messages
\return false if the application couldn't start, true if everything went OK.
*/
bool
ServerApp::Run()
{
if (!MessageLooper::Run())
return false;
// Let's tell the client how to talk with us
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<int32>(fMessagePort);
fLink.Flush();
return true;
}
/*!
\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 Send a message to the ServerApp's BApplication
\param msg The message to send
*/
void
ServerApp::SendMessageToClient(BMessage *msg) const
{
status_t status = fHandlerMessenger.SendMessage(msg, (BHandler*)NULL, 100000);
if (status != B_OK)
printf("app %s send to client failed: %s\n", Signature(), strerror(status));
}
/*!
\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)
{
fIsActive = value;
SetAppCursor();
}
//! Sets the cursor to the application cursor, if any.
void
ServerApp::SetAppCursor()
{
if (fAppCursor)
fDesktop->HWInterface()->SetCursor(fAppCursor);
fDesktop->HWInterface()->SetCursorVisible(!fCursorHidden);
}
void
ServerApp::_GetLooperName(char* name, size_t length)
{
#ifdef __HAIKU__
strlcpy(name, Signature(), length);
#else
strncpy(name, Signature(), length);
name[length - 1] = '\0';
#endif
}
/*!
\brief The thread function ServerApps use to monitor messages
*/
void
ServerApp::_MessageLooper()
{
// Message-dispatching loop for the ServerApp
BPrivate::LinkReceiver &receiver = fLink.Receiver();
int32 code;
status_t err = B_OK;
while (!fQuitting) {
STRACE(("info: ServerApp::_MessageLooper() listening on port %ld.\n", fMessagePort));
err = receiver.GetNextMessage(code, B_INFINITE_TIMEOUT);
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_id>(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 o 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);
}
/*!
\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 (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_CREATE_WINDOW:
case AS_CREATE_OFFSCREEN_WINDOW:
{
// Create a ServerWindow/OffscreenServerWindow
// 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 = B_NULL_TOKEN;
port_id clientReplyPort = -1;
port_id looperPort = -1;
char *title = NULL;
if (code == AS_CREATE_OFFSCREEN_WINDOW)
link.Read<int32>(&bitmapToken);
link.Read<BRect>(&frame);
link.Read<uint32>(&look);
link.Read<uint32>(&feel);
link.Read<uint32>(&flags);
link.Read<uint32>(&workspaces);
link.Read<int32>(&token);
link.Read<port_id>(&clientReplyPort);
link.Read<port_id>(&looperPort);
if (link.ReadString(&title) != B_OK)
break;
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_ERROR;
ServerWindow *window = NULL;
if (code == AS_CREATE_OFFSCREEN_WINDOW) {
ServerBitmap* bitmap = FindBitmap(bitmapToken);
if (bitmap != NULL) {
window = new OffscreenServerWindow(title, this, clientReplyPort,
looperPort, token, bitmap);
}
} else {
window = new ServerWindow(title, this, clientReplyPort, looperPort, token);
STRACE(("\nServerApp %s: New Window %s (%.1f,%.1f,%.1f,%.1f)\n",
fSignature(), 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, look, feel, flags, workspaces);
if (status == B_OK && !window->Run())
status = B_ERROR;
// add the window to the list
if (status == B_OK && fWindowListLock.Lock()) {
status = fWindowList.AddItem(window) ? B_OK : B_NO_MEMORY;
fWindowListLock.Unlock();
}
if (status < B_OK)
delete window;
}
// 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;
link.Read<team_id>(&team);
fDesktop->WriteWindowList(team, fLink.Sender());
break;
case AS_GET_WINDOW_INFO:
int32 serverToken;
link.Read<int32>(&serverToken);
fDesktop->WriteWindowInfo(serverToken, fLink.Sender());
break;
case AS_UPDATE_COLORS:
{
// NOTE: R2: Eventually we will have windows which will notify their children of changes in
// system colors
/* STRACE(("ServerApp %s: Received global UI color update notification\n", Signature()));
ServerWindow *win;
BMessage msg(_COLORS_UPDATED);
for(int32 i = 0; i < fWindowList.CountItems(); i++) {
win=(ServerWindow*)fWindowList.ItemAt(i);
win->GetWindowLayer()->UpdateColors();
win->SendMessageToClient(AS_UPDATE_COLORS, msg);
}
*/ break;
}
case AS_UPDATE_FONTS:
{
// NOTE: R2: Eventually we will have windows which will notify their children of changes in
// system fonts
/* STRACE(("ServerApp %s: Received global font update notification\n", Signature()));
ServerWindow *win;
BMessage msg(_FONTS_UPDATED);
for(int32 i=0; i<fSWindowList->CountItems(); i++)
{
win=(ServerWindow*)fSWindowList->ItemAt(i);
win->GetWindowLayer()->UpdateFont();
win->SendMessageToClient(AS_UPDATE_FONTS, msg);
}
*/ break;
}
case AS_AREA_MESSAGE:
{
// This occurs in only one kind of case: a message is too big to send over a port. This
// is really an edge case, so this shouldn't happen *too* often
// Attached Data:
// 1) area_id id of an area already owned by the server containing the message
// 2) size_t offset of the pointer in the area
// 3) size_t size of the message
area_id area;
size_t offset;
size_t msgsize;
area_info ai;
int8 *msgpointer;
link.Read<area_id>(&area);
link.Read<size_t>(&offset);
link.Read<size_t>(&msgsize);
// Part sanity check, part get base pointer :)
if (get_area_info(area, &ai) < B_OK)
break;
msgpointer = (int8*)ai.address + offset;
RAMLinkMsgReader mlink(msgpointer);
_DispatchMessage(mlink.Code(), mlink);
// This is a very special case in the sense that when ServerMemIO is used for this
// purpose, it will be set to NOT automatically free the memory which it had
// requested. This is the server's job once the message has been dispatched.
fSharedMem.ReleaseBuffer(msgpointer);
break;
}
case AS_ACQUIRE_SERVERMEM:
{
// This particular call is more than a bit of a pain in the neck. We are given a
// size of a chunk of memory needed. We need to (1) allocate it, (2) get the area for
// this particular chunk, (3) find the offset in the area for this chunk, and (4)
// tell the client about it. Good thing this particular call isn't used much
// Received from a ServerMemIO object requesting operating memory
// Attached Data:
// 1) size_t requested size
// 2) port_id reply_port
size_t memsize;
link.Read<size_t>(&memsize);
// TODO: I wonder if ACQUIRE_SERVERMEM should have a minimum size requirement?
void *sharedmem = fSharedMem.GetBuffer(memsize);
if (memsize < 1 || sharedmem == NULL) {
fLink.StartMessage(SERVER_FALSE);
fLink.Flush();
break;
}
area_id owningArea = area_for(sharedmem);
area_info info;
if (owningArea == B_ERROR || get_area_info(owningArea, &info) < B_OK) {
fLink.StartMessage(SERVER_FALSE);
fLink.Flush();
break;
}
int32 areaoffset = (addr_t)sharedmem - (addr_t)info.address;
STRACE(("Successfully allocated shared memory of size %ld\n",memsize));
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<area_id>(owningArea);
fLink.Attach<int32>(areaoffset);
fLink.Flush();
break;
}
case AS_RELEASE_SERVERMEM:
{
// Received when a ServerMemIO object on destruction
// Attached Data:
// 1) area_id owning area
// 2) int32 area offset
area_id owningArea;
int32 areaoffset;
link.Read<area_id>(&owningArea);
link.Read<int32>(&areaoffset);
area_info areaInfo;
if (owningArea < 0 || get_area_info(owningArea, &areaInfo) != B_OK)
break;
STRACE(("Successfully freed shared memory\n"));
void *sharedmem = ((int32*)areaInfo.address) + areaoffset;
fSharedMem.ReleaseBuffer(sharedmem);
break;
}
case AS_UPDATE_DECORATOR:
{
STRACE(("ServerApp %s: Received decorator update notification\n", Signature()));
for (int32 i = 0; i < fWindowList.CountItems(); i++) {
ServerWindow *window = fWindowList.ItemAt(i);
window->Lock();
const_cast<WindowLayer *>(window->GetWindowLayer())->UpdateDecorator();
window->Unlock();
}
break;
}
case AS_SET_DECORATOR:
{
// Received from an application when the user wants to set the window
// decorator to a new one
// Attached Data:
// int32 the index of the decorator to use
int32 index;
link.Read<int32>(&index);
if (gDecorManager.SetDecorator(index))
fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR);
break;
}
case AS_COUNT_DECORATORS:
{
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<int32>(gDecorManager.CountDecorators());
fLink.Flush();
break;
}
case AS_GET_DECORATOR:
{
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<int32>(gDecorManager.GetDecorator());
fLink.Flush();
break;
}
case AS_GET_DECORATOR_NAME:
{
int32 index;
link.Read<int32>(&index);
BString str(gDecorManager.GetDecoratorName(index));
if (str.CountChars() > 0)
{
fLink.StartMessage(SERVER_TRUE);
fLink.AttachString(str.String());
}
else
fLink.StartMessage(SERVER_FALSE);
fLink.Flush();
break;
}
case AS_R5_SET_DECORATOR:
{
// Sort of supports Tracker's nifty Easter Egg. It was easy to do and
// it's kind of neat, so why not?
// Attached Data:
// int32 value of the decorator to use
// 0: BeOS
// 1: Amiga
// 2: Windows
// 3: MacOS
int32 decindex = 0;
link.Read<int32>(&decindex);
if (gDecorManager.SetR5Decorator(decindex))
fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR);
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::id
// 6) port_id reply port
// Reply Code: SERVER_TRUE
// 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
ServerBitmap *bitmap = NULL;
BRect frame;
color_space colorSpace;
int32 flags, bytesPerRow;
screen_id screenID;
link.Read<BRect>(&frame);
link.Read<color_space>(&colorSpace);
link.Read<int32>(&flags);
link.Read<int32>(&bytesPerRow);
if (link.Read<screen_id>(&screenID) == B_OK) {
bitmap = gBitmapManager->CreateBitmap(frame, colorSpace, flags,
bytesPerRow, screenID);
}
STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n",
Signature(), frame.Width(), frame.Height()));
if (bitmap && fBitmapList.AddItem((void*)bitmap)) {
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<int32>(bitmap->Token());
fLink.Attach<area_id>(bitmap->Area());
fLink.Attach<int32>(bitmap->AreaOffset());
} else {
// alternatively, if something went wrong, we reply with SERVER_FALSE
fLink.StartMessage(SERVER_FALSE);
}
fLink.Flush();
break;
}
case AS_DELETE_BITMAP:
{
STRACE(("ServerApp %s: received BBitmap delete request\n", Signature()));
// Delete a bitmap's allocated memory
// Attached Data:
// 1) int32 token
// 2) int32 reply port
// Reply Code: SERVER_TRUE if successful,
// SERVER_FALSE if the buffer was already deleted or was not found
int32 id;
link.Read<int32>(&id);
ServerBitmap *bitmap = FindBitmap(id);
if (bitmap && fBitmapList.RemoveItem((void*)bitmap)) {
STRACE(("ServerApp %s: Deleting Bitmap %ld\n", Signature(), id));
gBitmapManager->DeleteBitmap(bitmap);
fLink.StartMessage(SERVER_TRUE);
} else
fLink.StartMessage(SERVER_FALSE);
fLink.Flush();
break;
}
#if 0
case AS_CREATE_PICTURE:
{
// TODO: Implement AS_CREATE_PICTURE
STRACE(("ServerApp %s: Create Picture unimplemented\n", Signature()));
break;
}
case AS_DELETE_PICTURE:
{
// TODO: Implement AS_DELETE_PICTURE
STRACE(("ServerApp %s: Delete Picture unimplemented\n", Signature()));
break;
}
case AS_CLONE_PICTURE:
{
// TODO: Implement AS_CLONE_PICTURE
STRACE(("ServerApp %s: Clone Picture unimplemented\n", Signature()));
break;
}
case AS_DOWNLOAD_PICTURE:
{
// TODO; Implement AS_DOWNLOAD_PICTURE
STRACE(("ServerApp %s: Download Picture unimplemented\n", Signature()));
// What is this particular function call for, anyway?
// DW: I think originally it might have been to support
// the undocumented Flatten function.
break;
}
#endif
case AS_CURRENT_WORKSPACE:
{
STRACE(("ServerApp %s: get current workspace\n", Signature()));
fLink.StartMessage(B_OK);
fLink.Attach<int32>(fDesktop->CurrentWorkspace());
fLink.Flush();
break;
}
case AS_ACTIVATE_WORKSPACE:
{
STRACE(("ServerApp %s: activate workspace\n", Signature()));
// TODO: See above
int32 index;
link.Read<int32>(&index);
fDesktop->SetWorkspace(index);
break;
}
case AS_SHOW_CURSOR:
{
STRACE(("ServerApp %s: Show Cursor\n", Signature()));
// TODO: support nested showing/hiding
fDesktop->HWInterface()->SetCursorVisible(true);
fCursorHidden = false;
break;
}
case AS_HIDE_CURSOR:
{
STRACE(("ServerApp %s: Hide Cursor\n", Signature()));
// TODO: support nested showing/hiding
fDesktop->HWInterface()->SetCursorVisible(false);
fCursorHidden = true;
break;
}
case AS_OBSCURE_CURSOR:
{
STRACE(("ServerApp %s: Obscure Cursor\n", Signature()));
// ToDo: Enable ObscureCursor
//fDesktop->HWInterface()->ObscureCursor();
break;
}
case AS_QUERY_CURSOR_HIDDEN:
{
STRACE(("ServerApp %s: Received IsCursorHidden request\n", Signature()));
fLink.StartMessage(fCursorHidden ? SERVER_TRUE : SERVER_FALSE);
fLink.Flush();
break;
}
case AS_SET_CURSOR_DATA:
{
STRACE(("ServerApp %s: SetCursor via cursor data\n", Signature()));
// Attached data: 68 bytes of fAppCursor data
int8 cdata[68];
link.Read(cdata,68);
// Because we don't want an overaccumulation of these particular
// cursors, we will delete them if there is an existing one. It would
// otherwise be easy to crash the server by calling SetCursor a
// sufficient number of times
if(fAppCursor)
fDesktop->GetCursorManager().DeleteCursor(fAppCursor->ID());
fAppCursor = new ServerCursor(cdata);
fAppCursor->SetOwningTeam(fClientTeam);
fAppCursor->SetAppSignature(Signature());
// ToDo: These two should probably both be done in Desktop directly
fDesktop->GetCursorManager().AddCursor(fAppCursor);
fDesktop->HWInterface()->SetCursor(fAppCursor);
break;
}
case AS_SET_CURSOR_BCURSOR:
{
STRACE(("ServerApp %s: SetCursor via BCursor\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 ctoken = B_NULL_TOKEN;
link.Read<bool>(&sync);
link.Read<int32>(&ctoken);
ServerCursor *cursor = fDesktop->GetCursorManager().FindCursor(ctoken);
if (cursor)
fDesktop->HWInterface()->SetCursor(cursor);
if (sync) {
// the application is expecting a reply, but plans to do literally nothing
// with the data, so we'll just reuse the cursor token variable
fLink.StartMessage(SERVER_TRUE);
fLink.Flush();
}
break;
}
case AS_CREATE_BCURSOR:
{
STRACE(("ServerApp %s: Create BCursor\n", Signature()));
// Attached data:
// 1) 68 bytes of fAppCursor data
// 2) port_id reply port
int8 cursorData[68];
link.Read(cursorData, sizeof(cursorData));
// Because we don't want an overaccumulation of these particular
// cursors, we will delete them if there is an existing one. It would
// otherwise be easy to crash the server by calling CreateCursor a
// sufficient number of times
if (fAppCursor)
fDesktop->GetCursorManager().DeleteCursor(fAppCursor->ID());
fAppCursor = new ServerCursor(cursorData);
fAppCursor->SetOwningTeam(fClientTeam);
fAppCursor->SetAppSignature(Signature());
fDesktop->GetCursorManager().AddCursor(fAppCursor);
// Synchronous message - BApplication is waiting on the cursor's ID
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<int32>(fAppCursor->ID());
fLink.Flush();
break;
}
case AS_DELETE_BCURSOR:
{
STRACE(("ServerApp %s: Delete BCursor\n", Signature()));
// Attached data:
// 1) int32 token ID of the cursor to delete
int32 ctoken = B_NULL_TOKEN;
link.Read<int32>(&ctoken);
if (fAppCursor && fAppCursor->ID() == ctoken)
fAppCursor = NULL;
fDesktop->GetCursorManager().DeleteCursor(ctoken);
break;
}
case AS_GET_SCROLLBAR_INFO:
{
STRACE(("ServerApp %s: Get ScrollBar info\n", Signature()));
scroll_bar_info info;
DesktopSettings settings(fDesktop);
settings.GetScrollBarInfo(info);
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<scroll_bar_info>(info);
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<scroll_bar_info>(&info) == B_OK) {
DesktopSettings settings(fDesktop);
settings.SetScrollBarInfo(info);
}
fLink.StartMessage(SERVER_TRUE);
fLink.Flush();
break;
}
case AS_GET_MENU_INFO:
{
STRACE(("ServerApp %s: Get menu info\n", Signature()));
menu_info info;
DesktopSettings settings(fDesktop);
settings.GetMenuInfo(info);
fLink.StartMessage(B_OK);
fLink.Attach<menu_info>(info);
fLink.Flush();
break;
}
case AS_SET_MENU_INFO:
{
STRACE(("ServerApp %s: Set menu info\n", Signature()));
menu_info info;
if (link.Read<menu_info>(&info) == B_OK) {
DesktopSettings 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 Focus Follows Mouse mode\n", Signature()));
// Attached Data:
// 1) enum mode_mouse FFM mouse mode
mode_mouse mouseMode;
if (link.Read<mode_mouse>(&mouseMode) == B_OK) {
DesktopSettings settings(fDesktop);
settings.SetMouseMode(mouseMode);
}
break;
}
case AS_GET_MOUSE_MODE:
{
STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", Signature()));
DesktopSettings settings(fDesktop);
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<mode_mouse>(settings.MouseMode());
fLink.Flush();
break;
}
case AS_GET_UI_COLORS:
{
// Client application is asking for all the system colors at once
// using a ColorSet object
gGUIColorSet.Lock();
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<ColorSet>(gGUIColorSet);
fLink.Flush();
gGUIColorSet.Unlock();
break;
}
case AS_SET_UI_COLORS:
{
// Client application is asking to set all the system colors at once
// using a ColorSet object
// Attached data:
// 1) ColorSet new colors to use
gGUIColorSet.Lock();
link.Read<ColorSet>(&gGUIColorSet);
gGUIColorSet.Unlock();
fDesktop->BroadcastToAllApps(AS_UPDATE_COLORS);
break;
}
case AS_GET_UI_COLOR:
{
STRACE(("ServerApp %s: Get UI color\n", Signature()));
RGBColor color;
int32 whichColor;
link.Read<int32>(&whichColor);
gGUIColorSet.Lock();
color = gGUIColorSet.AttributeToColor(whichColor);
gGUIColorSet.Unlock();
fLink.StartMessage(SERVER_TRUE);
fLink.Attach<rgb_color>(color.GetColor32());
fLink.Flush();
break;
}
/* font messages */
case AS_SET_SYSTEM_FONT:
{
// 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<float>(&size) == B_OK) {
BAutolock locker(gFontManager);
FontStyle* style = gFontManager->GetStyle(familyName, styleName);
if (style != NULL) {
ServerFont font(*style, size);
DesktopSettings settings(fDesktop);
if (!strcmp(type, "plain"))
settings.SetDefaultPlainFont(font);
else if (!strcmp(type, "bold"))
settings.SetDefaultBoldFont(font);
else if (!strcmp(type, "fixed"))
settings.SetDefaultFixedFont(font);
}
}
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")) {
font = *gFontManager->DefaultPlainFont();
} else if (!strcmp(type, "bold")) {
font = *gFontManager->DefaultBoldFont();
} else if (!strcmp(type, "fixed")) {
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<float>(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
DesktopSettings settings(fDesktop);
fLink.StartMessage(B_OK);
for (int32 i = 0; i < 3; i++) {
ServerFont font;
switch (i) {
case 0:
settings.GetDefaultPlainFont(font);
fLink.AttachString("plain");
break;
case 1:
settings.GetDefaultBoldFont(font);
fLink.AttachString("bold");
break;
case 2:
settings.GetDefaultFixedFont(font);
fLink.AttachString("fixed");
break;
}
fLink.Attach<uint16>(font.FamilyID());
fLink.Attach<uint16>(font.StyleID());
fLink.Attach<float>(font.Size());
fLink.Attach<uint16>(font.Face());
fLink.Attach<uint32>(font.Flags());
}
fLink.Flush();
break;
}
case AS_GET_FONT_LIST_REVISION:
{
STRACE(("ServerApp %s: AS_GET_FONT_LIST_REVISION\n", Signature()));
fLink.StartMessage(B_OK);
fLink.Attach<int32>(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<int32>(&index);
gFontManager->Lock();
FontFamily* family = gFontManager->FamilyAt(index);
if (family) {
fLink.StartMessage(B_OK);
fLink.AttachString(family->Name());
fLink.Attach<uint32>(family->Flags());
int32 count = family->CountStyles();
fLink.Attach<int32>(count);
for (int32 i = 0; i < count; i++) {
FontStyle* style = family->StyleAt(i);
fLink.AttachString(style->Name());
fLink.Attach<uint16>(style->Face());
fLink.Attach<uint32>(style->Flags());
}
} else
fLink.StartMessage(B_BAD_VALUE);
gFontManager->Unlock();
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<uint16>(&familyID);
link.Read<uint16>(&styleID);
gFontManager->Lock();
FontStyle *fontStyle = gFontManager->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();
gFontManager->Unlock();
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<uint16>(&familyID) == B_OK
&& link.Read<uint16>(&styleID) == B_OK
&& link.Read<uint16>(&face) == B_OK) {
// get the font and return IDs and face
gFontManager->Lock();
FontStyle *fontStyle = gFontManager->GetStyle(family, style,
familyID, styleID, face);
if (fontStyle != NULL) {
fLink.StartMessage(B_OK);
fLink.Attach<uint16>(fontStyle->Family()->ID());
fLink.Attach<uint16>(fontStyle->ID());
// we try to keep the font face close to what we got
face = fontStyle->PreservedFace(face);
fLink.Attach<uint16>(face);
} else
fLink.StartMessage(B_NAME_NOT_FOUND);
gFontManager->Unlock();
} 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<int32>(&familyID);
link.Read<int32>(&styleID);
gFontManager->Lock();
FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
if (fontStyle) {
fLink.StartMessage(B_OK);
fLink.Attach<uint16>((uint16)fontStyle->FileFormat());
} else
fLink.StartMessage(B_BAD_VALUE);
gFontManager->Unlock();
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 family, style;
float size;
uint8 spacing;
link.Read<uint16>(&family);
link.Read<uint16>(&style);
link.Read<float>(&size);
link.Read<uint8>(&spacing);
int32 numStrings;
link.Read<int32>(&numStrings);
float widthArray[numStrings];
int32 lengthArray[numStrings];
char *stringArray[numStrings];
for (int32 i = 0; i < numStrings; i++) {
// TODO: the length is actually encoded twice here
// It would be nicer to only send as much from the string as needed
link.Read<int32>(&lengthArray[i]);
link.ReadString(&stringArray[i]);
}
ServerFont font;
if (font.SetFamilyAndStyle(family, style) == 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] = fDesktop->GetDrawingEngine()->StringWidth(stringArray[i], lengthArray[i], font);
// NOTE: The line below will return the exact same thing. However,
// the line above uses the AGG rendering backend, for which glyph caching
// actually works. It is about 20 times faster!
// TODO: I've disabled the AGG version for now, as it produces a dead lock
// (font use), that I am currently too lazy to investigate...
widthArray[i] = font.StringWidth(stringArray[i], lengthArray[i]);
}
}
fLink.StartMessage(B_OK);
fLink.Attach(widthArray, sizeof(widthArray));
} 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 unimplemented\n",
Signature()));
// Attached Data:
// 1) uint16 - family ID
// 2) uint16 - style ID
// Returns:
// 1) BRect - box holding entire font
// ToDo: implement me!
fLink.StartMessage(B_ERROR);
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<uint16>(&familyID);
link.Read<uint16>(&styleID);
gFontManager->Lock();
FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
if (fontStyle != NULL) {
fLink.StartMessage(B_OK);
fLink.Attach<int32>(fontStyle->TunedCount());
} else
fLink.StartMessage(B_BAD_VALUE);
gFontManager->Unlock();
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<uint16>(&familyID);
link.Read<uint16>(&styleID);
gFontManager->Lock();
FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
if (fontStyle != NULL) {
fLink.StartMessage(B_OK);
fLink.Attach<uint32>(fontStyle->Flags());
} else
fLink.StartMessage(B_BAD_VALUE);
gFontManager->Unlock();
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<uint16>(&familyID);
link.Read<uint16>(&styleID);
link.Read<float>(&size);
gFontManager->Lock();
FontStyle *fontStyle = gFontManager->GetStyle(familyID, styleID);
if (fontStyle != NULL) {
font_height height;
fontStyle->GetHeight(size, height);
fLink.StartMessage(B_OK);
fLink.Attach<font_height>(height);
} else
fLink.StartMessage(B_BAD_VALUE);
gFontManager->Unlock();
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) uint32 - flags
// 7) int32 - numChars
// 8) char - chars (numChars times)
// Returns:
// 1) BShape - glyph shape
// numChars times
uint16 familyID, styleID;
uint32 flags;
float size, shear, rotation;
link.Read<uint16>(&familyID);
link.Read<uint16>(&styleID);
link.Read<float>(&size);
link.Read<float>(&shear);
link.Read<float>(&rotation);
link.Read<uint32>(&flags);
int32 numChars;
link.Read<int32>(&numChars);
char charArray[numChars];
link.Read(&charArray, numChars);
ServerFont font;
status_t status = font.SetFamilyAndStyle(familyID, styleID);
if (status == B_OK) {
font.SetSize(size);
font.SetShear(shear);
font.SetRotation(rotation);
font.SetFlags(flags);
BShape **shapes = font.GetGlyphShapes(charArray, numChars);
if (shapes) {
fLink.StartMessage(B_OK);
for (int32 i = 0; i < numChars; i++) {
fLink.AttachShape(*shapes[i]);
delete shapes[i];
}
delete shapes;
} else
fLink.StartMessage(B_ERROR);
} else
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<uint16>(&familyID);
link.Read<uint16>(&styleID);
int32 numChars;
link.Read<int32>(&numChars);
uint32 numBytes;
link.Read<uint32>(&numBytes);
char* charArray = new char[numBytes];
link.Read(charArray, numBytes);
ServerFont font;
status_t status = font.SetFamilyAndStyle(familyID, styleID);
if (status == B_OK) {
bool hasArray[numChars];
font.GetHasGlyphs(charArray, numChars, hasArray);
fLink.StartMessage(B_OK);
fLink.Attach(hasArray, sizeof(hasArray));
} else
fLink.StartMessage(status);
delete[] charArray;
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<uint16>(&familyID);
link.Read<uint16>(&styleID);
int32 numChars;
link.Read<int32>(&numChars);
uint32 numBytes;
link.Read<uint32>(&numBytes);
char* charArray = new char[numBytes];
link.Read(charArray, numBytes);
ServerFont font;
status_t status = font.SetFamilyAndStyle(familyID, styleID);
if (status == B_OK) {
edge_info edgeArray[numChars];
font.GetEdges(charArray, numChars, edgeArray);
fLink.StartMessage(B_OK);
fLink.Attach(edgeArray, sizeof(edgeArray));
} else
fLink.StartMessage(status);
delete[] charArray;
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) float - rotation
// 5) uint32 - flags
// 6) int32 - numChars
// 7) char - char -\ both
// 8) BPoint - offset -/ (numChars times)
// Returns:
// 1) BPoint - escapement
// numChars times
uint16 familyID, styleID;
uint32 flags;
float size, rotation;
link.Read<uint16>(&familyID);
link.Read<uint16>(&styleID);
link.Read<float>(&size);
link.Read<float>(&rotation);
link.Read<uint32>(&flags);
int32 numChars;
link.Read<int32>(&numChars);
char charArray[numChars];
BPoint offsetArray[numChars];
for (int32 i = 0; i < numChars; i++) {
link.Read<char>(&charArray[i]);
link.Read<BPoint>(&offsetArray[i]);
}
ServerFont font;
status_t status = font.SetFamilyAndStyle(familyID, styleID);
if (status == B_OK) {
font.SetSize(size);
font.SetRotation(rotation);
font.SetFlags(flags);
BPoint *escapements = font.GetEscapements(charArray, numChars, offsetArray);
if (escapements) {
fLink.StartMessage(B_OK);
for (int32 i = 0; i < numChars; i++) {
fLink.Attach<BPoint>(escapements[i]);
}
delete escapements;
} else
fLink.StartMessage(B_ERROR);
} else
fLink.StartMessage(status);
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) float - rotation
// 5) uint32 - flags
// 6) float - additional "nonspace" delta
// 7) float - additional "space" delta
// 8) int32 - numChars
// 9) int32 - numBytes
// 10) char - the char buffer with size numBytes
// Returns:
// 1) float - escapement buffer with numChar entries
uint16 familyID, styleID;
uint32 flags;
float size, rotation;
link.Read<uint16>(&familyID);
link.Read<uint16>(&styleID);
link.Read<float>(&size);
link.Read<float>(&rotation);
link.Read<uint32>(&flags);
escapement_delta delta;
link.Read<float>(&delta.nonspace);
link.Read<float>(&delta.space);
int32 numChars;
link.Read<int32>(&numChars);
uint32 numBytes;
link.Read<uint32>(&numBytes);
char* charArray = new char[numBytes];
link.Read(charArray, numBytes);
float* escapements = new float[numChars];
// figure out escapements
ServerFont font;
status_t status = font.SetFamilyAndStyle(familyID, styleID);
if (status == B_OK) {
font.SetSize(size);
font.SetRotation(rotation);
font.SetFlags(flags);
if (font.GetEscapements(charArray, numChars, numBytes, escapements, delta)) {
fLink.StartMessage(B_OK);
fLink.Attach(escapements, numChars * sizeof(float));
} else
status = B_ERROR;
}
delete[] charArray;
delete[] escapements;
if (status != B_OK)
fLink.StartMessage(status);
fLink.Flush();
break;
}
case AS_GET_BOUNDINGBOXES_CHARS:
{
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) uint8 - spacing
// 7) uint32 - flags
// 8) font_metric_mode - mode
// 9) bool - string escapement
// 10) escapement_delta - additional delta
// 11) int32 - numChars
// 12) int32 - numBytes
// 13) char - the char buffer with size numBytes
// Returns:
// 1) BRect - rects with numChar entries
uint16 famid, styid;
uint32 flags;
float ptsize, rotation, shear;
uint8 spacing;
font_metric_mode mode;
bool string_escapement;
link.Read<uint16>(&famid);
link.Read<uint16>(&styid);
link.Read<float>(&ptsize);
link.Read<float>(&rotation);
link.Read<float>(&shear);
link.Read<uint8>(&spacing);
link.Read<uint32>(&flags);
link.Read<font_metric_mode>(&mode);
link.Read<bool>(&string_escapement);
escapement_delta delta;
link.Read<escapement_delta>(&delta);
int32 numChars;
link.Read<int32>(&numChars);
uint32 numBytes;
link.Read<uint32>(&numBytes);
char charArray[numBytes];
link.Read(charArray, numBytes);
BRect rectArray[numChars];
// figure out escapements
ServerFont font;
bool success = false;
if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
font.SetSize(ptsize);
font.SetRotation(rotation);
font.SetShear(shear);
font.SetSpacing(spacing);
font.SetFlags(flags);
// TODO implement for real
if (font.GetBoundingBoxesAsString(charArray, numChars, rectArray, string_escapement, mode, delta)) {
fLink.StartMessage(SERVER_TRUE);
fLink.Attach(rectArray, sizeof(rectArray));
success = true;
}
}
if (!success)
fLink.StartMessage(SERVER_FALSE);
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) uint8 - spacing
// 7) uint32 - flags
// 8) font_metric_mode - mode
// 9) int32 numStrings
// 10) escapement_delta - additional delta (numStrings times)
// 11) int32 string length to measure (numStrings times)
// 12) string - string (numStrings times)
// Returns:
// 1) BRect - rects with numStrings entries
uint16 famid, styid;
uint32 flags;
float ptsize, rotation, shear;
uint8 spacing;
font_metric_mode mode;
link.Read<uint16>(&famid);
link.Read<uint16>(&styid);
link.Read<float>(&ptsize);
link.Read<float>(&rotation);
link.Read<float>(&shear);
link.Read<uint8>(&spacing);
link.Read<uint32>(&flags);
link.Read<font_metric_mode>(&mode);
int32 numStrings;
link.Read<int32>(&numStrings);
escapement_delta deltaArray[numStrings];
char *stringArray[numStrings];
int32 lengthArray[numStrings];
for(int32 i=0; i<numStrings; i++) {
link.Read<int32>(&lengthArray[i]);
link.Read<escapement_delta>(&deltaArray[i]);
link.ReadString(&stringArray[i]);
}
BRect rectArray[numStrings];
ServerFont font;
bool success = false;
if (font.SetFamilyAndStyle(famid, styid) == B_OK) {
font.SetSize(ptsize);
font.SetRotation(rotation);
font.SetShear(shear);
font.SetSpacing(spacing);
font.SetFlags(flags);
// TODO implement for real
if (font.GetBoundingBoxesForStrings(stringArray, lengthArray, numStrings, rectArray, mode, deltaArray)) {
fLink.StartMessage(SERVER_TRUE);
fLink.Attach(rectArray, sizeof(rectArray));
success = true;
}
}
for (int32 i = 0; i < numStrings; i++)
free(stringArray[i]);
if (!success)
fLink.StartMessage(SERVER_FALSE);
fLink.Flush();
break;
}
/* screen commands */
case AS_VALID_SCREEN_ID:
{
// Attached data
// 1) screen_id screen
screen_id id;
if (link.Read<screen_id>(&id) == B_OK
&& id.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) screen_id screen
screen_id id;
link.Read<screen_id>(&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_ENTRY_NOT_FOUND;
// Attached data
// 1) int32 - window client token
int32 clientToken;
if (link.Read<int32>(&clientToken) != B_OK)
status = B_BAD_DATA;
else {
BAutolock locker(fWindowListLock);
for (int32 i = fWindowList.CountItems(); i-- > 0;) {
ServerWindow* window = fWindowList.ItemAt(i);
if (window->ClientToken() == clientToken) {
// got it!
fLink.StartMessage(B_OK);
fLink.Attach<screen_id>(B_MAIN_SCREEN_ID);
// TODO: for now...
status = B_OK;
}
}
}
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) screen_id screen
// 2) uint32 workspace index
screen_id id;
link.Read<screen_id>(&id);
uint32 workspace;
link.Read<uint32>(&workspace);
// TODO: the display_mode can be different between
// the various screens.
// We have the screen_id and the workspace number, with these
// we need to find the corresponding "driver", and call getmode on it
display_mode mode;
fDesktop->ScreenAt(0)->GetMode(&mode);
// actually this isn't still enough as different workspaces can
// have different display_modes
fLink.StartMessage(B_OK);
fLink.Attach<display_mode>(mode);
fLink.Flush();
break;
}
case AS_SCREEN_SET_MODE:
{
STRACE(("ServerApp %s: AS_SCREEN_SET_MODE\n", Signature()));
// Attached data
// 1) screen_id
// 2) workspace index
// 3) display_mode to set
// 4) 'makedefault' boolean
// TODO: See above: workspaces support, etc.
screen_id id;
link.Read<screen_id>(&id);
uint32 workspace;
link.Read<uint32>(&workspace);
display_mode mode;
link.Read<display_mode>(&mode);
bool makedefault = false;
link.Read<bool>(&makedefault);
RootLayer* rootLayer = fDesktop->RootLayer();
rootLayer->Lock();
status_t status = fDesktop->ScreenAt(0)->SetMode(mode);
if (status == B_OK) {
BRect bounds = rootLayer->Bounds();
rootLayer->ResizeBy(mode.virtual_width - 1 - bounds.Width(),
mode.virtual_height - 1 - bounds.Height());
gInputManager->UpdateScreenBounds(rootLayer->Bounds());
fDesktop->ScreenChanged(fDesktop->ScreenAt(0));
}
rootLayer->Unlock();
fLink.StartMessage(status);
fLink.Flush();
break;
}
case AS_PROPOSE_MODE:
{
STRACE(("ServerApp %s: AS_PROPOSE_MODE\n", Signature()));
screen_id id;
link.Read<screen_id>(&id);
display_mode target, low, high;
link.Read<display_mode>(&target);
link.Read<display_mode>(&low);
link.Read<display_mode>(&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<display_mode>(target);
fLink.Attach<bool>(status == B_OK);
} else
fLink.StartMessage(status);
fLink.Flush();
break;
}
case AS_GET_MODE_LIST:
{
screen_id id;
link.Read<screen_id>(&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<uint32>(count);
fLink.Attach(modeList, sizeof(display_mode) * count);
delete[] modeList;
} else
fLink.StartMessage(status);
fLink.Flush();
break;
}
case AS_SCREEN_GET_COLORMAP:
{
STRACE(("ServerApp %s: AS_SCREEN_GET_COLORMAP\n", Signature()));
screen_id id;
link.Read<screen_id>(&id);
const color_map *colorMap = SystemColorMap();
if (colorMap != NULL) {
fLink.StartMessage(B_OK);
fLink.Attach<color_map>(*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<uint32>(&index);
fLink.StartMessage(B_OK);
fDesktop->Lock();
// 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->WorkspaceAt(index);
fLink.Attach<rgb_color>(workspace.Color().GetColor32());
fDesktop->Unlock();
fLink.Flush();
break;
}
case AS_GET_ACCELERANT_INFO:
{
STRACE(("ServerApp %s: get accelerant info\n", Signature()));
// We aren't using the screen_id for now...
screen_id id;
link.Read<screen_id>(&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<accelerant_device_info>(accelerantInfo);
} 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...
screen_id id;
link.Read<screen_id>(&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<frame_buffer_config>(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...
screen_id id;
link.Read<screen_id>(&id);
sem_id semaphore = fDesktop->HWInterface()->RetraceSemaphore();
fLink.StartMessage(semaphore);
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...
screen_id id;
link.Read<screen_id>(&id);
display_timing_constraints constraints;
status_t status = fDesktop->HWInterface()->GetTimingConstraints(
&constraints);
if (status == B_OK) {
fLink.StartMessage(B_OK);
fLink.Attach<display_timing_constraints>(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...
screen_id id;
link.Read<screen_id>(&id);
display_mode mode;
link.Read<display_mode>(&mode);
uint32 low, high;
status_t status = fDesktop->HWInterface()->GetPixelClockLimits(&mode,
&low, &high);
if (status == B_OK) {
fLink.StartMessage(B_OK);
fLink.Attach<uint32>(low);
fLink.Attach<uint32>(high);
} else
fLink.StartMessage(status);
fLink.Flush();
break;
}
case AS_SET_DPMS:
{
STRACE(("ServerApp %s: AS_SET_DPMS\n", Signature()));
screen_id id;
link.Read<screen_id>(&id);
uint32 mode;
link.Read<uint32>(&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()));
screen_id id;
link.Read<screen_id>(&id);
uint32 state = fDesktop->HWInterface()->DPMSMode();
fLink.StartMessage(B_OK);
fLink.Attach<uint32>(state);
fLink.Flush();
break;
}
case AS_GET_DPMS_CAPABILITIES:
{
STRACE(("ServerApp %s: AS_GET_DPMS_CAPABILITIES\n", Signature()));
screen_id id;
link.Read<screen_id>(&id);
uint32 capabilities = fDesktop->HWInterface()->DPMSCapabilities();
fLink.StartMessage(B_OK);
fLink.Attach<uint32>(capabilities);
fLink.Flush();
break;
}
case AS_READ_BITMAP:
{
STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
int32 bitmapToken;
link.Read<int32>(&bitmapToken);
bool drawCursor = true;
link.Read<bool>(&drawCursor);
BRect bounds;
link.Read<BRect>(&bounds);
ServerBitmap *bitmap = FindBitmap(bitmapToken);
if (bitmap != NULL) {
fLink.StartMessage(B_OK);
// TODO: Implement for real
} else
fLink.StartMessage(B_BAD_VALUE);
fLink.Flush();
break;
}
default:
printf("ServerApp %s received unhandled message code %ld\n",
Signature(), code);
if (link.NeedsReply()) {
// the client is now blocking and waiting for a reply!
fLink.StartMessage(SERVER_FALSE);
fLink.Flush();
} else
puts("message doesn't need a reply!");
break;
}
}
void
ServerApp::RemoveWindow(ServerWindow* window)
{
BAutolock locker(fWindowListLock);
fWindowList.RemoveItem(window);
}
int32
ServerApp::CountBitmaps() const
{
return fBitmapList.CountItems();
}
/*!
\brief Looks up a ServerApp's ServerBitmap in its list
\param token ID token of the bitmap to find
\return The bitmap having that ID or NULL if not found
*/
ServerBitmap*
ServerApp::FindBitmap(int32 token) const
{
// TODO: we need to make sure the bitmap is ours?!
ServerBitmap* bitmap;
if (gTokenSpace.GetToken(token, kBitmapToken, (void**)&bitmap) == B_OK)
return bitmap;
return NULL;
}
int32
ServerApp::CountPictures() const
{
return fPictureList.CountItems();
}
ServerPicture *
ServerApp::FindPicture(int32 token) const
{
// TODO: we need to make sure the picture is ours?!
ServerPicture* picture;
if (gTokenSpace.GetToken(token, kPictureToken, (void**)&picture) == B_OK)
return picture;
return NULL;
}
team_id
ServerApp::ClientTeam() const
{
return fClientTeam;
}