From 0934499c5d64ab26c5a977ef6c30d4184542e809 Mon Sep 17 00:00:00 2001 From: DarkWyrm Date: Fri, 24 Jan 2003 14:36:15 +0000 Subject: [PATCH] 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 --- src/servers/app/server/FontServer.h | 2 +- src/servers/app/server/Jamfile | 6 + src/servers/app/server/PortLink.cpp | 757 +++++++++++++++++++++++++++ src/servers/app/server/ServerApp.cpp | 436 +++++++++++++++ src/servers/app/server/ServerApp.h | 84 +++ 5 files changed, 1284 insertions(+), 1 deletion(-) create mode 100644 src/servers/app/server/PortLink.cpp create mode 100644 src/servers/app/server/ServerApp.cpp create mode 100644 src/servers/app/server/ServerApp.h diff --git a/src/servers/app/server/FontServer.h b/src/servers/app/server/FontServer.h index 772e712b6a..0281ffe425 100644 --- a/src/servers/app/server/FontServer.h +++ b/src/servers/app/server/FontServer.h @@ -70,11 +70,11 @@ public: bool SetSystemFixed(const char *family, const char *style, float size); bool FontsNeedUpdated(void) { return need_update; } + void FontsUpdated(void) { need_update=false; } protected: /*! \brief Called when the fonts list has been updated */ - void FontsUpdated(void) { need_update=false; } FontFamily *_FindFamily(const char *name); FT_CharMap _GetSupportedCharmap(const FT_Face &face); bool init; diff --git a/src/servers/app/server/Jamfile b/src/servers/app/server/Jamfile index cdbfc5028c..2616d88dbc 100644 --- a/src/servers/app/server/Jamfile +++ b/src/servers/app/server/Jamfile @@ -2,12 +2,17 @@ SubDir OBOS_TOP src servers app server ; AddResources app_server : app_server.rsrc ; +UsePrivateHeaders app ; UseFreeTypeHeaders ; Server app_server : # Misc. Sources Angle.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 # against libopenbeos @@ -20,6 +25,7 @@ Server app_server : # Manager Classes AppServer.cpp CursorManager.cpp + ServerApp.cpp # Font Classes FontFamily.cpp diff --git a/src/servers/app/server/PortLink.cpp b/src/servers/app/server/PortLink.cpp new file mode 100644 index 0000000000..c82f820d41 --- /dev/null +++ b/src/servers/app/server/PortLink.cpp @@ -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 +#include +#include + +//#define PLDEBUG +//#define PLD_DEBUG + +//#define CAPACITY_CHECKING + +#ifdef PLDEBUG +#include +#endif + +#ifdef PLD_DEBUG +#include +#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;ibuffer, 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;ibuffer, 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;ibuffer, 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; i0 && 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; +} diff --git a/src/servers/app/server/ServerApp.cpp b/src/servers/app/server/ServerApp.cpp new file mode 100644 index 0000000000..038ff4b8e2 --- /dev/null +++ b/src/servers/app/server/ServerApp.cpp @@ -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 +// Description: Server-side BApplication counterpart +// +//------------------------------------------------------------------------------ +#include +#include +#include +#include +#include + +#include +#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; + } + } +} diff --git a/src/servers/app/server/ServerApp.h b/src/servers/app/server/ServerApp.h new file mode 100644 index 0000000000..1d04a3b4bf --- /dev/null +++ b/src/servers/app/server/ServerApp.h @@ -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 +// Description: Server-side BApplication counterpart +// +//------------------------------------------------------------------------------ +#ifndef _SERVERAPP_H_ +#define _SERVERAPP_H_ + +#include +#include +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 \ No newline at end of file