Added ServerApp, fully documented and 99% implemented

Made FontServer::FontsUpdated public


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2546 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
DarkWyrm 2003-01-24 14:36:15 +00:00
parent 0933894bf7
commit 0934499c5d
5 changed files with 1284 additions and 1 deletions

View File

@ -70,11 +70,11 @@ public:
bool SetSystemFixed(const char *family, const char *style, float size); bool SetSystemFixed(const char *family, const char *style, float size);
bool FontsNeedUpdated(void) { return need_update; } bool FontsNeedUpdated(void) { return need_update; }
void FontsUpdated(void) { need_update=false; }
protected: protected:
/*! /*!
\brief Called when the fonts list has been updated \brief Called when the fonts list has been updated
*/ */
void FontsUpdated(void) { need_update=false; }
FontFamily *_FindFamily(const char *name); FontFamily *_FindFamily(const char *name);
FT_CharMap _GetSupportedCharmap(const FT_Face &face); FT_CharMap _GetSupportedCharmap(const FT_Face &face);
bool init; bool init;

View File

@ -2,12 +2,17 @@ SubDir OBOS_TOP src servers app server ;
AddResources app_server : app_server.rsrc ; AddResources app_server : app_server.rsrc ;
UsePrivateHeaders app ;
UseFreeTypeHeaders ; UseFreeTypeHeaders ;
Server app_server : Server app_server :
# Misc. Sources # Misc. Sources
Angle.cpp Angle.cpp
TokenHandler.cpp TokenHandler.cpp
# PortLink will disappear as soon as I can figure out how to link the server
# against libopenbeos
PortLink.cpp
# ColorUtils will disappear as soon as I can figure out how to link the server # ColorUtils will disappear as soon as I can figure out how to link the server
# against libopenbeos # against libopenbeos
@ -20,6 +25,7 @@ Server app_server :
# Manager Classes # Manager Classes
AppServer.cpp AppServer.cpp
CursorManager.cpp CursorManager.cpp
ServerApp.cpp
# Font Classes # Font Classes
FontFamily.cpp FontFamily.cpp

View File

@ -0,0 +1,757 @@
/*
PortLink.cpp:
A helper class for port-based messaging
------------------------------------------------------------------------
How it works:
The class utilizes a fixed-size array of PortLinkData object pointers. When
data is attached, a new PortLinkData object is allocated and a copy of the
passed data is created inside it. When the time comes for the message to be sent,
the data is pieced together into a flattened array and written to the port.
------------------------------------------------------------------------
Data members:
*attachments[] - fixed-size array of pointers used to hold the attached data
opcode - message value which is sent along with any data
target - port to which the message is sent when Flush() is called
replyport - port used with synchronous messaging - FlushWithReply()
bufferlength - total bytes taken up by attachments
num_attachments - internal variable which is used to track which "slot"
will be the next one to receive an attachment object
port_ok - flag to signal whether it's ok to send a message
capacity - contains the storage capacity of the target port.
*/
#include "PortLink.h"
#include <string.h>
#include <stdio.h>
#include <malloc.h>
//#define PLDEBUG
//#define PLD_DEBUG
//#define CAPACITY_CHECKING
#ifdef PLDEBUG
#include <stdio.h>
#endif
#ifdef PLD_DEBUG
#include <stdio.h>
#endif
// Internal data storage class for holding attached data whilst it is waiting
// to be Flattened() and then Flushed(). There is no need for this to be called outside
// the PortLink class.
class PortLinkData
{
public:
PortLinkData(void);
~PortLinkData(void);
status_t Set(void *data, size_t size);
char *buffer;
size_t buffersize;
};
PortLink::PortLink(port_id port)
{
#ifdef PLDEBUG
printf("PortLink(%lu)\n",port);
#endif
// For this class to be useful (and to prevent a lot of init problems)
// we require a port in the constructor
target=port;
port_info pi;
port_ok=(get_port_info(target,&pi)==B_OK)?true:false;
capacity=pi.capacity;
// We start out without any data attached to the port message
num_attachments=0;
opcode=0;
bufferlength=0;
replyport=create_port(30,"PortLink reply port");
#ifdef PLDEBUG
printf("\tPort valid: %s\n",(port_ok)?"true":"false");
printf("\tReply port: %lu\n",replyport);
#endif
// TODO: initialize all attachments pointers to NULL
}
PortLink::PortLink(const PortLink &link)
{
#ifdef PLDEBUG
printf("PortLink(PortLink*)\n");
#endif
// The copy constructor copies everything except a PortLink's attachments. If there
// is some reason why someday I might need to change this behavior, I will, but
// for now there is no real reason I can think of.
target=link.target;
opcode=link.opcode;
port_ok=link.port_ok;
capacity=link.capacity;
bufferlength=0;
num_attachments=0;
replyport=create_port(30,"PortLink reply port");
#ifdef PLDEBUG
printf("\tOpcode: %lu\n",opcode);
printf("\tTarget port: %lu\n",target);
printf("\tCapacity: %lu\n",capacity);
printf("\tPort valid: %s\n",(port_ok)?"true":"false");
printf("\tReply port: %lu\n",replyport);
#endif
// TODO: initialize all attachments pointers to NULL
}
PortLink::~PortLink(void)
{
#ifdef PLDEBUG
printf("~PortLink()\n");
#endif
// If, for some odd reason, this is deleted with something attached,
// free the memory used by the attachments. We do not flush the queue
// because the port may no longer be valid in cases such as the app
// is in the process of quitting
if(num_attachments || bufferlength)
MakeEmpty();
//TODO: Inline the MakeEmpty call in a way such that it ignores num_attachments
// and deletes all non-NULL pointers, setting them to NULL afterward.
}
void PortLink::SetOpCode(int32 code)
{
#ifdef PLDEBUG
printf("PortLink::SetOpCode(%c%c%c%c)\n",
(char)((code & 0xFF000000) >> 24),
(char)((code & 0x00FF0000) >> 16),
(char)((code & 0x0000FF00) >> 8),
(char)((code & 0x000000FF)) );
#endif
// Sets the message code. This does not change once the message is sent.
// Another call to SetOpCode() is required for such things.
opcode=code;
}
void PortLink::SetPort(port_id port)
{
#ifdef PLDEBUG
printf("PortLink::SetPort(%lu)\n",port);
#endif
// Sets the target port. While not necessary in most uses, this exists
// mostly to prevent flexibility problems
target=port;
port_info pi;
port_ok=(get_port_info(target,&pi)==B_OK)?true:false;
capacity=pi.capacity;
}
port_id PortLink::GetPort(void)
{
#ifdef PLDEBUG
printf("PortLink::GetPort() returned %lu\n",target);
#endif
// Simply returns the port at which the object is pointed.
return target;
}
status_t PortLink::Flush(bigtime_t timeout=B_INFINITE_TIMEOUT)
{
#ifdef PLDEBUG
printf("PortLink::Flush()\n");
#endif
// Fires a message off to the target, complete with attachments.
int8 *msgbuffer;
int32 size;
status_t write_stat=B_OK;
if(!port_ok)
{
#ifdef PLDEBUG
printf("\tFlush(): invalid port\n");
#endif
return B_BAD_VALUE;
}
if(num_attachments>0)
{
#ifdef PLDEBUG
printf("\tFlush(): flushing %d attachments\n",num_attachments);
#endif
FlattenData(&msgbuffer,&size);
// Dump message to port, reset attachments, and clean up
if(timeout!=B_INFINITE_TIMEOUT)
write_stat=write_port_etc(target,opcode,msgbuffer,size,B_TIMEOUT, timeout);
else
write_stat=write_port(target,opcode,msgbuffer,size);
MakeEmpty();
}
else
{
#ifdef PLDEBUG
printf("\tFlush(): flushing without attachments\n");
#endif
if(timeout!=B_INFINITE_TIMEOUT)
write_stat=write_port_etc(target,opcode,NULL,0,B_TIMEOUT, timeout);
else
write_stat=write_port(target,opcode,NULL,0);
}
return write_stat;
}
int8* PortLink::FlushWithReply(int32 *code, status_t *status, ssize_t *buffersize, bigtime_t timeout=B_INFINITE_TIMEOUT)
{
// Deprecated call which functions exactly like PortLink(PortLink::ReplyData *data)
#ifdef PLDEBUG
printf("PortLink::FlushWithReply(int32*,status_t*,ssize_t*,bigtime_t)\n");
#endif
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
{
#ifdef PLDEBUG
printf("PortLink::FlushWithReply(): too many attachments\n");
#endif
*status=B_ERROR;
return NULL;
}
if(!port_ok)
{
#ifdef PLDEBUG
printf("PortLink::FlushWithReply(): bad port\n");
#endif
*status=B_BAD_VALUE;
return NULL;
}
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&replyport,sizeof(port_id))==B_OK)
{
bufferlength+=sizeof(port_id);
}
else
{
delete pld;
*status=B_ERROR;
return NULL;
}
// Flatten() inlined to make some necessary changes
int8 *buffer=new int8[bufferlength];
int8 *bufferindex=buffer;
size_t size=0;
// attach our port_id first
memcpy(bufferindex, pld->buffer, pld->buffersize);
bufferindex += pld->buffersize;
size+=pld->buffersize;
// attach everything else
for(int i=0;i<num_attachments;i++)
{
pld=attachments[i];
memcpy(bufferindex, pld->buffer, pld->buffersize);
bufferindex += pld->buffersize;
size+=pld->buffersize;
}
// Flush the thing....FOOSH! :P
write_port(target,opcode,buffer,size);
MakeEmpty();
delete buffer;
// Now we wait for the reply
buffer=NULL;
if(timeout==B_INFINITE_TIMEOUT)
{
*buffersize=port_buffer_size(replyport);
if(*buffersize>0)
buffer=(int8*)new int8[*buffersize];
read_port(replyport,code, buffer, *buffersize);
}
else
{
*buffersize=port_buffer_size_etc(replyport,0,timeout);
if(*buffersize==B_TIMED_OUT)
{
*status=*buffersize;
return NULL;
}
if(*buffersize>0)
buffer=(int8*)new int8[*buffersize];
read_port(replyport,code, buffer, *buffersize);
}
// We got this far, so we apparently have some data
*status=B_OK;
return buffer;
}
status_t PortLink::FlushWithReply(PortLink::ReplyData *data,bigtime_t timeout=B_INFINITE_TIMEOUT)
{
#ifdef PLDEBUG
printf("PortLink::FlushWithReply(ReplyData*,bigtime_t)\n");
#endif
// Fires a message to the target and then waits for a reply. The target will
// receive a message with the first item being the port_id to reply to.
// NOTE: like Flush(), any attached data must be deleted.
// Effectively, an Attach() call inlined for changes
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
{
#ifdef PLDEBUG
printf("\tFlushWithReply(): too many attachments\n");
#endif
return B_ERROR;
}
if(!port_ok)
{
#ifdef PLDEBUG
printf("\tFlushWithReply(): invalid port\n");
#endif
return B_BAD_VALUE;
}
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&replyport,sizeof(port_id))==B_OK)
{
bufferlength+=sizeof(port_id);
}
else
{
#ifdef PLDEBUG
printf("\tFlushWithReply(): unable to assign reply port to data\n");
#endif
delete pld;
return B_ERROR;
}
// Flatten() inlined to make some necessary changes
int8 *buffer=new int8[bufferlength];
int8 *bufferindex=buffer;
size_t size=0;
// attach our port_id first
memcpy(bufferindex, pld->buffer, pld->buffersize);
bufferindex += pld->buffersize;
size+=pld->buffersize;
// attach everything else
for(int i=0;i<num_attachments;i++)
{
pld=attachments[i];
memcpy(bufferindex, pld->buffer, pld->buffersize);
bufferindex += pld->buffersize;
size+=pld->buffersize;
}
// Flush the thing....FOOSH! :P
write_port(target,opcode,buffer,size);
MakeEmpty();
delete buffer;
// Now we wait for the reply
if(timeout==B_INFINITE_TIMEOUT)
{
data->buffersize=port_buffer_size(replyport);
if(data->buffersize>0)
data->buffer=(int8*)new int8[data->buffersize];
read_port(replyport,&(data->code),data->buffer, data->buffersize);
}
else
{
data->buffersize=port_buffer_size_etc(replyport,0,timeout);
if(data->buffersize==B_TIMED_OUT)
return B_TIMED_OUT;
if(data->buffersize>0)
data->buffer=(int8*)new int8[data->buffersize];
read_port(replyport,&(data->code),data->buffer, data->buffersize);
}
// We got this far, so we apparently have some data
return B_OK;
}
status_t PortLink::Attach(void *data, size_t size)
{
#ifdef PLDEBUG
printf("Attach(%p,%ld)\n",data,size);
#endif
// This is the member called to attach data to a message. Attachments are
// treated to be in 'Append' mode, tacking on each attached piece of data
// to the end of the list.
// Prevent parameter problems
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
{
#ifdef PLDEBUG
printf("\tAttach(): too many attachments\n");
#endif
return B_ERROR;
}
if(size==0)
{
#ifdef PLDEBUG
printf("\tAttach(): size invalid -> size=0\n");
#endif
return B_ERROR;
}
#ifdef CAPACITY_CHECKING
if(bufferlength+size>capacity)
{
#ifdef PLDEBUG
printf("\tAttach(): bufferlength+size > port capacity\n");
#endif
return B_NO_MEMORY;
}
#endif
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(data,size)==B_OK)
{
num_attachments++;
attachments[num_attachments-1]=pld;
bufferlength+=size;
#ifdef PLDEBUG
printf("\tAttach(): successful\n");
printf("\t\tAttach(): attachments now %u\n", num_attachments);
printf("\t\tAttach(): buffer length is %lu\n", bufferlength);
#endif
}
else
{
#ifdef PLDEBUG
printf("\tAttach(): Couldn't assign data to PortLinkData object\n");
#endif
delete pld;
}
return B_OK;
}
// These functions were added for a major convenience in passing common types
// Eventually, I'd like to templatize these, but for now, this'll do
status_t PortLink::Attach(int32 data)
{
#ifdef PLDEBUG
printf("Attach(%ld)\n",data);
#endif
// Prevent parameter problems
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
return B_ERROR;
int32 size=sizeof(int32);
#ifdef CAPACITY_CHECKING
if(bufferlength+size>capacity)
return B_NO_MEMORY;
#endif
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&data,size)==B_OK)
{
num_attachments++;
attachments[num_attachments-1]=pld;
bufferlength+=size;
}
else
{
delete pld;
}
return B_OK;
}
status_t PortLink::Attach(int16 data)
{
#ifdef PLDEBUG
printf("Attach(%d)\n",data);
#endif
// Prevent parameter problems
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
return B_ERROR;
int32 size=sizeof(int16);
#ifdef CAPACITY_CHECKING
if(bufferlength+size>capacity)
return B_NO_MEMORY;
#endif
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&data,size)==B_OK)
{
num_attachments++;
attachments[num_attachments-1]=pld;
bufferlength+=size;
}
else
{
delete pld;
}
return B_OK;
}
status_t PortLink::Attach(int8 data)
{
#ifdef PLDEBUG
printf("Attach(%d)\n",data);
#endif
// Prevent parameter problems
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
return B_ERROR;
int32 size=sizeof(int8);
#ifdef CAPACITY_CHECKING
if(bufferlength+size>capacity)
return B_NO_MEMORY;
#endif
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&data,size)==B_OK)
{
num_attachments++;
attachments[num_attachments-1]=pld;
bufferlength+=size;
}
else
{
delete pld;
}
return B_OK;
}
status_t PortLink::Attach(float data)
{
#ifdef PLDEBUG
printf("Attach(%f)\n",data);
#endif
// Prevent parameter problems
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
return B_ERROR;
int32 size=sizeof(float);
#ifdef CAPACITY_CHECKING
if(bufferlength+size>capacity)
return B_NO_MEMORY;
#endif
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&data,size)==B_OK)
{
num_attachments++;
attachments[num_attachments-1]=pld;
bufferlength+=size;
}
else
{
delete pld;
}
return B_OK;
}
status_t PortLink::Attach(bool data)
{
#ifdef PLDEBUG
printf("Attach(%s)\n",(data)?"true":"false");
#endif
// Prevent parameter problems
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
return B_ERROR;
int32 size=sizeof(bool);
#ifdef CAPACITY_CHECKING
if(bufferlength+size>capacity)
return B_NO_MEMORY;
#endif
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&data,size)==B_OK)
{
num_attachments++;
attachments[num_attachments-1]=pld;
bufferlength+=size;
}
else
{
delete pld;
}
return B_OK;
}
status_t PortLink::Attach(BRect data)
{
#ifdef PLDEBUG
printf("Attach(BRect(%f,%f,%f,%f))\n",data.left,data.top,data.right,data.bottom);
#endif
// Prevent parameter problems
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
return B_ERROR;
int32 size=sizeof(BRect);
#ifdef CAPACITY_CHECKING
if(bufferlength+size>capacity)
return B_NO_MEMORY;
#endif
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&data,size)==B_OK)
{
num_attachments++;
attachments[num_attachments-1]=pld;
bufferlength+=size;
}
else
{
delete pld;
}
return B_OK;
}
status_t PortLink::Attach(BPoint data)
{
#ifdef PLDEBUG
printf("Attach(BPoint(%f,%f))\n",data.x,data.y);
#endif
// Prevent parameter problems
if(num_attachments>=_PORTLINK_MAX_ATTACHMENTS)
return B_ERROR;
int32 size=sizeof(BPoint);
#ifdef CAPACITY_CHECKING
if(bufferlength+size>capacity)
return B_NO_MEMORY;
#endif
// create a new storage object and stash the data
PortLinkData *pld=new PortLinkData;
if(pld->Set(&data,size)==B_OK)
{
num_attachments++;
attachments[num_attachments-1]=pld;
bufferlength+=size;
}
else
{
delete pld;
}
return B_OK;
}
void PortLink::FlattenData(int8 **buffer,int32 *size)
{
// This function is where all the magic happens, but it is strictly internal.
// It iterates through each PortLinkData object and copies it to the main buffer
// which ends up, ultimately, being written to the PortLink's target port.
// skip if there aree no attachments
if(bufferlength<1)
{
#ifdef PLDEBUG
printf("PortLink::FlattenData: bufferlength<1\n");
#endif
return;
}
*buffer=new int8[bufferlength];
int8 *bufferindex=*buffer;
PortLinkData *pld;
*size=0;
for(int i=0;i<num_attachments;i++)
{
pld=attachments[i];
memcpy(bufferindex, pld->buffer, pld->buffersize);
bufferindex += pld->buffersize;
*size+=pld->buffersize;
}
}
void PortLink::MakeEmpty(void)
{
#ifdef PLDEBUG
printf("PortLink::MakeEmpty\n");
#endif
// Nukes all the attachments currently held by the PortLink class
if(num_attachments!=0)
{
for(int i=0; i<num_attachments; i++)
{
delete attachments[i];
}
}
num_attachments=0;
bufferlength=0;
}
PortLinkData::PortLinkData(void)
{
// Initialize object to empty
buffersize=0;
buffer=NULL;
}
PortLinkData::~PortLinkData(void)
{
// Frees the buffer if we actually used the class to store data
if(buffersize>0 && buffer!=NULL)
free(buffer);
}
status_t PortLinkData::Set(void *data, size_t size)
{
#ifdef PLD_DEBUG
printf("PortLinkData::Set(%p,%lu)\n",data,size);
#endif
// Function copies the passed to the internal buffers for storage
if(size>0 && buffersize==0 && data!=NULL)
{
buffer=(char *)malloc(size);
if(!buffer)
{
#ifdef PLD_DEBUG
printf("\tSet(): Couldn't allocate buffer\n");
#endif
return B_NO_MEMORY;
}
memcpy(buffer, data, size);
buffersize=size;
#ifdef PLD_DEBUG
printf("\tSet(): SUCCESS\n");
#endif
return B_OK;
}
#ifdef PLD_DEBUG
if(size==0)
printf("\tSet(): given an invalid size\n");
if(buffersize>0)
printf("\tSet(): buffersize is nonzero\n");
if(buffersize>0)
printf("\tSet(): data is NULL\n");
#endif
return B_ERROR;
}

View File

@ -0,0 +1,436 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2002, OpenBeOS
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: ServerApp.cpp
// Author: DarkWyrm <bpmagic@columbus.rr.com>
// Description: Server-side BApplication counterpart
//
//------------------------------------------------------------------------------
#include <AppDefs.h>
#include <List.h>
#include <String.h>
#include <stdio.h>
#include <string.h>
#include <PortLink.h>
#include "CursorManager.h"
//#include "Desktop.h"
#include "DisplayDriver.h"
#include "FontServer.h"
#include "ServerApp.h"
//#include "ServerWindow.h"
#include "ServerCursor.h"
#include "ServerBitmap.h"
#include "ServerProtocol.h"
#include "ServerConfig.h"
#include "LayerData.h"
/*!
\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 _signature NULL-terminated string which contains the BApplication's
MIME _signature.
*/
ServerApp::ServerApp(port_id sendport, port_id rcvport, char *signature)
{
// need to copy the _signature because the message buffer
// owns the copy which we are passed as a parameter.
_signature=(signature)?signature:"BeApplication";
// _sender is the our BApplication's event port
_sender=sendport;
_applink=new PortLink(_sender);
_applink->SetPort(_sender);
// Gotta get the team ID so we can ping the application
port_info pinfo;
get_port_info(_sender,&pinfo);
_target_id=pinfo.team;
// _receiver is the port we receive messages from our BApplication
_receiver=rcvport;
_winlist=new BList(0);
_bmplist=new BList(0);
_isactive=false;
ServerCursor *defaultc=cursormanager->GetCursor(B_CURSOR_DEFAULT);
_appcursor=(defaultc)?new ServerCursor(defaultc):NULL;
_lock=create_sem(1,"ServerApp sem");
// TODO: uncomment this and include Desktop.h when the desktop classes are done
// _driver=get_gfxdriver();
}
//! Does all necessary teardown for application
ServerApp::~ServerApp(void)
{
int32 i;
// TODO: Enable this when we have ServerWindow implemented
/* ServerWindow *tempwin;
for(i=0;i<_winlist->CountItems();i++)
{
tempwin=(ServerWindow*)_winlist->ItemAt(i);
if(tempwin)
delete tempwin;
}
_winlist->MakeEmpty();
delete _winlist;
*/
ServerBitmap *tempbmp;
for(i=0;i<_bmplist->CountItems();i++)
{
tempbmp=(ServerBitmap*)_bmplist->ItemAt(i);
if(tempbmp)
delete tempbmp;
}
_bmplist->MakeEmpty();
delete _bmplist;
delete _applink;
_applink=NULL;
if(_appcursor)
delete _appcursor;
// Kill the monitor thread if it exists
thread_info info;
if(get_thread_info(_monitor_thread,&info)==B_OK)
kill_thread(_monitor_thread);
cursormanager->RemoveAppCursors(_signature.String());
delete_sem(_lock);
}
/*!
\brief Starts the ServerApp monitoring for messages
\return false if the application couldn't start, true if everything went OK.
*/
bool ServerApp::Run(void)
{
// Unlike a BApplication, a ServerApp is *supposed* to return immediately
// when its Run() function is called.
_monitor_thread=spawn_thread(MonitorApp,_signature.String(),B_NORMAL_PRIORITY,this);
if(_monitor_thread==B_NO_MORE_THREADS || _monitor_thread==B_NO_MEMORY)
return false;
resume_thread(_monitor_thread);
return true;
}
/*!
\brief Pings the target app to make sure it's still working
\return true if target is still "alive" and false if "He's dead, Jim."
"But that's impossible..."
This function is called by the app_server thread to ensure that
the target app still exists. We do this not by sending a message
but by calling get_port_info. We don't want to send ping messages
just because the app might simply be hung. If this is the case, it
should be up to the user to kill it. If the app has been killed, its
ports will be invalid. Thus, if get_port_info returns an error, we
tell the app_server to delete the respective ServerApp.
*/
bool ServerApp::PingTarget(void)
{
team_info tinfo;
if(get_team_info(_target_id,&tinfo)==B_BAD_TEAM_ID)
{
port_id serverport=find_port(SERVER_PORT_NAME);
if(serverport==B_NAME_NOT_FOUND)
{
printf("PANIC: ServerApp %s could not find the app_server port in PingTarget()!\n",_signature.String());
return false;
}
_applink->SetPort(serverport);
_applink->SetOpCode(DELETE_APP);
_applink->Attach(&_monitor_thread,sizeof(thread_id));
_applink->Flush();
return false;
}
return true;
}
/*!
\brief The thread function ServerApps use to monitor messages
\param data Pointer to the thread's ServerApp object
\return Throwaway value - always 0
*/
int32 ServerApp::MonitorApp(void *data)
{
ServerApp *app=(ServerApp *)data;
// Message-dispatching loop for the ServerApp
int32 msgcode;
int8 *msgbuffer=NULL;
ssize_t buffersize,bytesread;
for(;;)
{
buffersize=port_buffer_size(app->_receiver);
if(buffersize>0)
{
// buffers are PortLink messages. Allocate necessary buffer and
// we'll cast it as a BMessage.
msgbuffer=new int8[buffersize];
bytesread=read_port(app->_receiver,&msgcode,msgbuffer,buffersize);
}
else
bytesread=read_port(app->_receiver,&msgcode,NULL,0);
if (bytesread != B_BAD_PORT_ID && bytesread != B_TIMED_OUT && bytesread != B_WOULD_BLOCK)
{
switch(msgcode)
{
// -------------- Messages received from the Server ------------------------
// Mouse messages simply get passed onto the active app for now
case B_MOUSE_UP:
case B_MOUSE_DOWN:
case B_MOUSE_MOVED:
{
// everything is formatted as it should be, so just call
// write_port.
write_port(app->_sender, msgcode, msgbuffer, buffersize);
break;
}
case QUIT_APP:
{
// If we are using the real, accelerated version of the
// DisplayDriver, we do NOT want the user to be able shut down
// the server. The results would NOT be pretty
if(DISPLAYDRIVER==HWDRIVER)
{
// This message is received from the app_server thread
// because the server was asked to quit. Thus, we
// ask all apps to quit. This is NOT the same as system
// shutdown and will happen only in testing
app->_applink->SetOpCode(B_QUIT_REQUESTED);
app->_applink->Flush();
}
break;
}
// -------------- Messages received from the Application ------------------
case B_QUIT_REQUESTED:
{
// Our BApplication sent us this message when it quit.
// We need to ask the app_server to delete our monitor
port_id serverport=find_port(SERVER_PORT_NAME);
if(serverport==B_NAME_NOT_FOUND)
{
printf("PANIC: ServerApp %s could not find the app_server port!\n",app->_signature.String());
break;
}
app->_applink->SetPort(serverport);
app->_applink->SetOpCode(DELETE_APP);
app->_applink->Attach(&app->_monitor_thread,sizeof(thread_id));
app->_applink->Flush();
break;
}
default:
{
app->DispatchMessage(msgcode, msgbuffer);
break;
}
}
}
if(buffersize>0)
delete msgbuffer;
if(msgcode==B_QUIT_REQUESTED)
break;
}
exit_thread(0);
return 0;
}
/*!
\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, int8 *buffer)
{
int8 *index=buffer;
LayerData ld;
switch(code)
{
case UPDATED_CLIENT_FONTLIST:
{
// received when the client-side global font list has been
// refreshed
fontserver->Lock();
fontserver->FontsUpdated();
fontserver->Unlock();
break;
}
case CREATE_WINDOW:
{
// TODO: Uncomment when ServerWindow has been implemented
/*
// Create the ServerWindow to node monitor a new OBWindow
// Attached data:
// 1) port_id reply port
// 2) BRect window frame
// 3) uint32 window flags
// 4) port_id window's message port
// 5) uint32 workspace index
// 6) const char * title
// Find the necessary data
port_id reply_port=*((port_id*)index); index+=sizeof(port_id);
BRect rect=*((BRect*)index); index+=sizeof(BRect);
uint32 winlook=*((uint32*)index); index+=sizeof(uint32);
uint32 winfeel=*((uint32*)index); index+=sizeof(uint32);
uint32 winflags=*((uint32*)index); index+=sizeof(uint32);
port_id win_port=*((port_id*)index); index+=sizeof(port_id);
uint32 workspace=*((uint32*)index); index+=sizeof(uint32);
// Create the ServerWindow object for this window
ServerWindow *newwin=new ServerWindow(rect,(const char *)index,
winlook, winfeel, winflags,this,win_port,workspace);
_winlist->AddItem(newwin);
// Window looper is waiting for our reply. Send back the
// ServerWindow's message port
PortLink *replylink=new PortLink(reply_port);
replylink->SetOpCode(SET_SERVER_PORT);
replylink->Attach((int32)newwin->_receiver);
replylink->Flush();
delete replylink;
*/ break;
}
case DELETE_WINDOW:
{
// TODO: Uncomment when ServerWindow has been implemented
/*
// Received from a ServerWindow when its window quits
// Attached data:
// 1) thread_id ServerWindow ID
thread_id winid;
ServerWindow *w;
for(int32 i=0;i<_winlist->CountItems();i++)
{
w=(ServerWindow*)_winlist->ItemAt(i);
if(w->thread==winid)
{
_winlist->RemoveItem(w);
delete w;
break;
}
}
*/ break;
}
case GFX_SET_SCREEN_MODE:
{
// TODO: Enable when we have Desktop.h
/*
// Attached data
// 1) int32 workspace #
// 2) uint32 screen mode
// 3) bool make default
int32 workspace=*((int32*)index); index+=sizeof(int32);
uint32 mode=*((uint32*)index); index+=sizeof(uint32);
SetScreenSpace(workspace,mode,*((bool*)index));
*/
break;
}
case GFX_ACTIVATE_WORKSPACE:
{
// TODO: Enable when we have Desktop.h
/*
// Attached data
// 1) int32 workspace index
// Error-checking is done in ActivateWorkspace, so this is a safe call
ActivateWorkspace(*((int32*)index));
*/ break;
}
// Theoretically, we could just call the driver directly, but we will
// call the CursorManager's version to allow for future expansion
case SHOW_CURSOR:
{
cursormanager->ShowCursor();
break;
}
case HIDE_CURSOR:
{
cursormanager->HideCursor();
break;
}
case OBSCURE_CURSOR:
{
cursormanager->ObscureCursor();
break;
}
case SET_CURSOR_DATA:
{
// Attached data: 68 bytes of _appcursor data
// Get the data, update the app's _appcursor, and update the
// app's _appcursor if active.
int8 cdata[68];
memcpy(cdata, buffer, 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(_appcursor)
cursormanager->DeleteCursor(_appcursor->_token);
_appcursor=new ServerCursor(cdata);
cursormanager->AddCursor(_appcursor);
cursormanager->SetCursor(_appcursor->_token);
break;
}
case SET_CURSOR_BCURSOR:
{
// TODO: Implement
break;
}
default:
{
printf("ServerApp %s received unhandled message code %lx\n",
_signature.String(),code);
break;
}
}
}

View File

@ -0,0 +1,84 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2002, OpenBeOS
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: ServerApp.h
// Author: DarkWyrm <bpmagic@columbus.rr.com>
// Description: Server-side BApplication counterpart
//
//------------------------------------------------------------------------------
#ifndef _SERVERAPP_H_
#define _SERVERAPP_H_
#include <OS.h>
#include <String.h>
class BMessage;
class PortLink;
class BList;
class DisplayDriver;
/*!
\class ServerApp ServerApp.h
\brief Counterpart to BApplication within the app_server
*/
class ServerApp
{
public:
ServerApp(port_id sendport, port_id rcvport, char *signature);
~ServerApp(void);
bool Run(void);
static int32 MonitorApp(void *data);
void Lock(void);
void Unlock(void);
bool IsLocked(void);
/*!
\brief Determines whether the application is the active one
\return true if active, false if not.
*/
bool IsActive(void) const { return _isactive; }
/*!
\brief Sets the ServerApp's active status
\param value The new status of the ServerApp.
Note that this function only changes a flag.
*/
void Activate(bool value) { _isactive=value; }
bool PingTarget(void);
protected:
void DispatchMessage(int32 code, int8 *buffer);
port_id _sender,_receiver;
BString _signature;
thread_id _monitor_thread;
team_id _target_id;
PortLink *_applink;
BList *_winlist, *_bmplist;
DisplayDriver *_driver;
ServerCursor *_appcursor;
sem_id _lock;
bool _isactive;
};
#endif