diff --git a/src/tests/apps/Jamfile b/src/tests/apps/Jamfile index 0e966d5311..9cd4a18cc5 100644 --- a/src/tests/apps/Jamfile +++ b/src/tests/apps/Jamfile @@ -1,3 +1,4 @@ SubDir OBOS_TOP src tests apps ; SubInclude OBOS_TOP src tests apps miniterminal ; +SubInclude OBOS_TOP src tests apps fake_app_server ; diff --git a/src/tests/apps/fake_app_server/AppServer.cpp b/src/tests/apps/fake_app_server/AppServer.cpp new file mode 100644 index 0000000000..152ea91b0d --- /dev/null +++ b/src/tests/apps/fake_app_server/AppServer.cpp @@ -0,0 +1,358 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2005, Haiku, Inc. +// +// 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: AppServer.cpp +// Author: DarkWyrm +// Description: main manager object for the app_server +// +//------------------------------------------------------------------------------ +#include +#include +#include +#include +#include +#include + +#include +#include +#include "AppServer.h" +#include "ServerProtocol.h" +#include "ServerApp.h" +#include +#if 0 +#include "ColorSet.h" +#include "DisplayDriver.h" +#include "ServerCursor.h" +#include "ServerWindow.h" +#include "DefaultDecorator.h" +#include "RGBColor.h" +#include "BitmapManager.h" +#include "CursorManager.h" +#include "Utils.h" +#include "FontServer.h" +#include "Desktop.h" +#include "RootLayer.h" +#endif +#include + +#ifdef DEBUG_KEYHANDLING +# include +# define KBTRACE(x) printf x +#else +# define KBTRACE(x) ; +#endif + +//#define DEBUG_SERVER +#ifdef DEBUG_SERVER +# define DEBUG 1 +# include +# define STRACE(x) _sPrintf x +#else +# define STRACE(x) ; +#endif + +// Globals + +AppServer::AppServer(void) +{ + fMessagePort = create_port(200, SERVER_PORT_NAME); + + fAppList = new BList(0); + fQuittingServer= false; + + // This is necessary to mediate access between the Poller and app_server threads + fActiveAppLock= create_sem(1,"app_server_active_sem"); + + // This locker is for app_server and Picasso to vy for control of the ServerApp list + fAppListLock= create_sem(1,"app_server_applist_sem"); + + // Spawn our thread-monitoring thread + fPicassoThreadID= spawn_thread(PicassoThread,"picasso", B_NORMAL_PRIORITY, this); + if (fPicassoThreadID >= 0) + resume_thread(fPicassoThreadID); +} + + +AppServer::~AppServer(void) +{ +} + + +int32 +AppServer::PicassoThread(void *data) +{ + int32 i; + AppServer *appserver=(AppServer*)data; + ServerApp *app; + for(;;) + { + i = 0; +#if 1 + acquire_sem(appserver->fAppListLock); + for(;;) + { + app=(ServerApp*)appserver->fAppList->ItemAt(i++); + if(!app) + break; + + app->PingTarget(); + } + release_sem(appserver->fAppListLock); +#endif + // we do this every other second so as not to suck *too* many CPU cycles + snooze(1000000); + } + return 0; +} + + +thread_id +AppServer::Run(void) +{ + MainLoop(); + kill_thread(fPicassoThreadID); + return 0; +} + + +//! Main message-monitoring loop for the regular message port - no input messages! +void +AppServer::MainLoop(void) +{ + BPortLink pmsg(-1,fMessagePort); + int32 code=0; + status_t err=B_OK; + + while(1) + { + STRACE(("info: AppServer::MainLoop listening on port %ld.\n", fMessagePort)); + err=pmsg.GetNextReply(&code); + + if(err(&app_port); + msg.Read(&clientLooperPort); + msg.Read(&clientTeamID); + msg.Read(&htoken); + msg.ReadString(&app_signature); + + // Create the ServerApp subthread for this app + acquire_sem(fAppListLock); + + port_id server_listen=create_port(DEFAULT_MONITOR_PORT_SIZE, app_signature); + if(server_listenAddItem(newapp); + + release_sem(fAppListLock); + + BPortLink replylink(app_port); + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(newapp->fMessagePort); + replylink.Flush(); + + // This is necessary because BPortLink::ReadString allocates memory + if(app_signature) + free(app_signature); + + break; + } + case AS_DELETE_APP: + { + // Delete a ServerApp. Received only from the respective ServerApp when a + // BApplication asks it to quit. + + // Attached Data: + // 1) thread_id - thread ID of the ServerApp to be deleted + + int32 i=0, + appnum=fAppList->CountItems(); + + ServerApp *srvapp=NULL; + thread_id srvapp_id=-1; + + if(msg.Read(&srvapp_id)ItemAt(i); + + if(srvapp != NULL && srvapp->fMonitorThreadID== srvapp_id) + { + srvapp=(ServerApp *)fAppList->RemoveItem(i); + if(srvapp) + { + status_t temp; + wait_for_thread(srvapp_id, &temp); + delete srvapp; + srvapp= NULL; + } + break; // jump out of our for() loop + } + } + + release_sem(fAppListLock); + break; + } +#endif + case AS_QUERY_FONTS_CHANGED: + { + // Seeing how the client merely wants an answer, we'll skip the BPortLink + // and all its overhead and just write the code to port. + port_id replyport; + if (msg.Read(&replyport) < B_OK) + break; + BPortLink replylink(replyport); + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_GET_DECORATOR: + { + // Attached Data: + // 1) port_id reply port + + port_id replyport=-1; + if(msg.Read(&replyport)(&replyport)(dmode); + replylink.Flush(); + break; + } + + case AS_UPDATED_CLIENT_FONTLIST: + case AS_SET_UI_COLORS: + case AS_SET_DECORATOR: + case AS_R5_SET_DECORATOR: + case AS_SET_SYSCURSOR_DEFAULTS: + default: + break; + } +} + + +int +main(int argc, char **argv) +{ + // There can be only one.... + if (find_port(SERVER_PORT_NAME) != B_NAME_NOT_FOUND) + return -1; + + AppServer app_server; + app_server.Run(); + return 0; +} diff --git a/src/tests/apps/fake_app_server/AppServer.h b/src/tests/apps/fake_app_server/AppServer.h new file mode 100644 index 0000000000..7b7f6204b9 --- /dev/null +++ b/src/tests/apps/fake_app_server/AppServer.h @@ -0,0 +1,46 @@ +#ifndef _OPENBEOS_APP_SERVER_H_ +#define _OPENBEOS_APP_SERVER_H_ + +#include +#include +#include +#include +#include +#include +#include "Decorator.h" +#include "ServerConfig.h" + +class Layer; +class BMessage; +class ServerApp; +class DisplayDriver; +class BPortLink; +class CursorManager; +class BitmapManager; + +class AppServer +{ +public: + AppServer(void); + ~AppServer(void); + + static int32 PollerThread(void *data); + static int32 PicassoThread(void *data); + thread_id Run(void); + void MainLoop(void); + + void DispatchMessage(int32 code, BPortLink &link); + +private: + port_id fMessagePort; + bool fQuittingServer; + + BList *fAppList; + thread_id fPicassoThreadID; + + sem_id fActiveAppLock, fAppListLock; +}; + +extern AppServer *app_server; + +#endif diff --git a/src/tests/apps/fake_app_server/BGet++.cpp b/src/tests/apps/fake_app_server/BGet++.cpp new file mode 100644 index 0000000000..1148942f70 --- /dev/null +++ b/src/tests/apps/fake_app_server/BGet++.cpp @@ -0,0 +1,854 @@ +/*------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, Haiku, Inc. +// +// 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: bget++.cpp +// Author: John Walker +// DarkWyrm +// Description: public domain BGET pool allocator converted to C++ +// Distributed with Haiku under MIT license +// +//------------------------------------------------------------------------------*/ + +/* + This class is based on the BGET pool allocator. Original code was in standard + ANSI C with a bunch of static variables. The original code was placed into the + MemPool class and the original allocation, release, and compacting functions + were made into virtual members. MemPool also, unlike the original code, makes + use of malloc() and free() to handle dynamic memory needs. AreaPool is a MemPool + subclass which uses areas to handle memory management needs in large chunks. +*/ + + +// Buffer allocation size quantum: all buffers allocated are a multiple of this size. ' +// This MUST be a power of two. +#define SizeQuant 4 + +#include +#include +#include +#include +#include +#include + +// Declare the interface, including the requested buffer size type, ssize_t. +#include "BGet++.h" + +// Queue links +struct qlinks +{ + struct bfhead *flink; // Forward link + struct bfhead *blink; // Backward link +}; + +// Header in allocated and free buffers +struct bhead +{ + // Relative link back to previous free buffer in memory or 0 if previous + // buffer is allocated. + ssize_t prevfree; + + // Buffer size: positive if free, negative if allocated. + ssize_t bsize; +}; + +#define BH(p) ((struct bhead *) (p)) + +// Header in directly allocated buffers (by acqfcn) +struct bdhead +{ + ssize_t tsize; // Total size, including overhead + struct bhead bh; // Common header +}; + +#define BDH(p) ((struct bdhead *) (p)) + +// Header in free buffers +struct bfhead +{ + // Common allocated/free header + struct bhead bh; + + // Links on free list + struct qlinks ql; +}; + +#define BFH(p) ((struct bfhead *) (p)) + +static struct bfhead freelist = +{ + // List of free buffers + {0, 0}, + {&freelist, &freelist} +}; + + +// Minimum allocation quantum: +#define QLSize (sizeof(struct qlinks)) +#define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize) + +// End sentinel: value placed in bsize field of dummy block delimiting end of +// pool block. The most negative number which will fit in a ssize_t, +// defined in a way that the compiler will accept. +#define ESent ((ssize_t) (-(((1L << (sizeof(ssize_t) * 8 - 2)) - 1) * 2) - 2)) + + +MemPool::MemPool(void) + : totalloc(0), + numget(0), + numrel(0), + numpblk(0), + numpget(0), + numprel(0), + numdget(0), + numdrel(0), + exp_incr(0), + pool_len(0) +{ +} + +MemPool::~MemPool(void) +{ +} + +// Allocate a buffer from the available space in the memory pool +void *MemPool::GetBuffer(ssize_t requested_size, bool zero) +{ + ssize_t size = requested_size; + struct bfhead *b; + + struct bfhead *best; + void *buf; + + int compactseq = 0; + + assert(size > 0); + + if (size < (ssize_t)SizeQ) + { + // Need at least room for the queue links. + size = SizeQ; + } + +#if SizeQuant > 1 + size = (size + (SizeQuant - 1)) & (~(SizeQuant - 1)); +#endif + + // Add overhead in allocated buffer to size required. + size += sizeof(struct bhead); + + // If a compact function was provided in the call to bectl(), wrap + // a loop around the allocation process to allow compaction to + // intervene in case we don't find a suitable buffer in the chain. + while (1) + { + b = freelist.ql.flink; + best = &freelist; + + + // Scan the free list searching for the first buffer big enough + // to hold the requested size buffer. + + while (b != &freelist) + { + if (b->bh.bsize >= size) + { + if ((best == &freelist) || (b->bh.bsize < best->bh.bsize)) + { + best = b; + } + } + + b = b->ql.flink; // Link to next buffer + } + b = best; + + while (b != &freelist) + { + if ((ssize_t) b->bh.bsize >= size) + { + + // Buffer is big enough to satisfy the request. Allocate it to the caller. + // We must decide whether the buffer is large enough to split into the part + // given to the caller and a free buffer that remains on the free list, or + // whether the entire buffer should be removed from the free list and given + // to the caller in its entirety. We only split the buffer if enough room + // remains for a header plus the minimum quantum of allocation. + + if ((b->bh.bsize - size) > (ssize_t)(SizeQ + (sizeof(struct bhead)))) + { + struct bhead *ba, *bn; + + ba = BH(((char *) b) + (b->bh.bsize - size)); + bn = BH(((char *) ba) + size); + assert(bn->prevfree == b->bh.bsize); + + // Subtract size from length of free block. + b->bh.bsize -= size; + + // Link allocated buffer to the previous free buffer. + ba->prevfree = b->bh.bsize; + + // Plug negative size into user buffer. + ba->bsize = -(ssize_t) size; + + // Mark buffer after this one not preceded by free block. + bn->prevfree = 0; + + totalloc += size; + numget++; // Increment number of GetBuffer() calls + + buf = (void *) ((((char *) ba) + sizeof(struct bhead))); + return buf; + } + else + { + struct bhead *ba; + + ba = BH(((char *) b) + b->bh.bsize); + assert(ba->prevfree == b->bh.bsize); + + // The buffer isn't big enough to split. Give the whole + // shebang to the caller and remove it from the free list. + + assert(b->ql.blink->ql.flink == b); + assert(b->ql.flink->ql.blink == b); + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + + totalloc += b->bh.bsize; + numget++; // Increment number of GetBuffer() calls + + // Negate size to mark buffer allocated. + b->bh.bsize = -(b->bh.bsize); + + // Zero the back pointer in the next buffer in memory + // to indicate that this buffer is allocated. + ba->prevfree = 0; + + // Give user buffer starting at queue links. + buf = (void *) &(b->ql); + return buf; + } + } + b = b->ql.flink; // Link to next buffer + } + + + // We failed to find a buffer. If there's a compact function + // defined, notify it of the size requested. If it returns + // TRUE, try the allocation again. + + if(!CompactMem(size, ++compactseq)) + break; + } + + // No buffer available with requested size free. + + // Don't give up yet -- look in the reserve supply. + if (size > (ssize_t)(exp_incr - sizeof(struct bhead))) + { + // Request is too large to fit in a single expansion + // block. Try to satisy it by a direct buffer acquisition. + struct bdhead *bdh; + + size += sizeof(struct bdhead) - sizeof(struct bhead); + if ((bdh = BDH(AcquireMem((ssize_t) size))) != NULL) + { + // Mark the buffer special by setting the size field + // of its header to zero. + bdh->bh.bsize = 0; + bdh->bh.prevfree = 0; + bdh->tsize = size; + + totalloc += size; + + // Increment number of GetBuffer() calls + numget++; + + // Direct GetBuffer() call count + numdget++; + + buf = (void *) (bdh + 1); + return buf; + } + + } + else + { + + // Try to obtain a new expansion block + void *newpool; + + if ((newpool = AcquireMem((ssize_t) exp_incr)) != NULL) + { + AddToPool(newpool, exp_incr); + + // This can't, I say, can't get into a loop + buf = GetBuffer(requested_size); + + return buf; + } + } + + // Still no buffer available + return NULL; + + // Code from bgetz -- zeroing code +/* + char *buf = (char *) GetBuffer(size); + + if (buf != NULL) + { + struct bhead *b; + ssize_t rsize; + + b = BH(buf - sizeof(struct bhead)); + rsize = -(b->bsize); + + if (rsize == 0) + { + struct bdhead *bd; + + bd = BDH(buf - sizeof(struct bdhead)); + rsize = bd->tsize - sizeof(struct bdhead); + } + else + { + rsize -= sizeof(struct bhead); + } + + assert(rsize >= size); + memset(buf, 0, (MemSize) rsize); + } + return ((void *) buf); +*/ + +} + +// Reallocate a buffer. This is a minimal implementation, simply in terms +// of ReleaseBuffer() and GetBuffer(). It could be enhanced to allow the +// buffer to grow into adjacent free blocks and to avoid moving data unnecessarily. +void *MemPool::ReallocateBuffer(void *buf, ssize_t size) +{ + void *nbuf; + + // Old size of buffer + ssize_t osize; + struct bhead *b; + + if ((nbuf = GetBuffer(size)) == NULL) + { + // Acquire new buffer + return NULL; + } + + if (buf == NULL) + { + return nbuf; + } + b = BH(((char *) buf) - sizeof(struct bhead)); + osize = -b->bsize; + + if (osize == 0) + { + // Buffer acquired directly through acqfcn. + struct bdhead *bd; + + bd = BDH(((char *) buf) - sizeof(struct bdhead)); + osize = bd->tsize - sizeof(struct bdhead); + } + else + osize -= sizeof(struct bhead); + assert(osize > 0); + + // Copy the data + memcpy((char *) nbuf, (char *) buf, (int) ((size < osize) ? size : osize)); + ReleaseBuffer(buf); + return nbuf; +} + +// BREL -- Release a buffer. +void MemPool::ReleaseBuffer(void *buf) +{ + struct bfhead *b, *bn; + + b = BFH(((char *) buf) - sizeof(struct bhead)); + + // Increment number of ReleaseBuffer() calls + numrel++; + + assert(buf != NULL); + + // Directly-acquired buffer? + if (b->bh.bsize == 0) + { + struct bdhead *bdh; + + bdh = BDH(((char *) buf) - sizeof(struct bdhead)); + assert(b->bh.prevfree == 0); + + totalloc -= bdh->tsize; + assert(totalloc >= 0); + + // Number of direct releases + numdrel++; + + memset((char *) buf, 0x55, (int) (bdh->tsize - sizeof(struct bdhead))); + + // Release it directly. + ReleaseMem((void *) bdh); + return; + } + + + // Buffer size must be negative, indicating that the buffer is allocated. + if (b->bh.bsize >= 0) + { + bn = NULL; + } + assert(b->bh.bsize < 0); + + // Back pointer in next buffer must be zero, indicating the same thing: + assert(BH((char *) b - b->bh.bsize)->prevfree == 0); + + totalloc += b->bh.bsize; + assert(totalloc >= 0); + + + // If the back link is nonzero, the previous buffer is free. + + if (b->bh.prevfree != 0) + { + // The previous buffer is free. Consolidate this buffer with it + // by adding the length of this buffer to the previous free + // buffer. Note that we subtract the size in the buffer being + // released, since it's negative to indicate that the buffer is allocated. + + register ssize_t size = b->bh.bsize; + + // Make the previous buffer the one we're working on. + assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree); + b = BFH(((char *) b) - b->bh.prevfree); + b->bh.bsize -= size; + } + else + { + // The previous buffer isn't allocated. Insert this buffer on the + // free list as an isolated free block. + assert(freelist.ql.blink->ql.flink == &freelist); + assert(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + b->bh.bsize = -b->bh.bsize; + } + + // Now we look at the next buffer in memory, located by advancing from + // the start of this buffer by its size, to see if that buffer is + // free. If it is, we combine this buffer with the next one in + // memory, dechaining the second buffer from the free list. + + bn = BFH(((char *) b) + b->bh.bsize); + if (bn->bh.bsize > 0) + { + // The buffer is free. Remove it from the free list and add + // its size to that of our buffer. + assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize); + assert(bn->ql.blink->ql.flink == bn); + assert(bn->ql.flink->ql.blink == bn); + bn->ql.blink->ql.flink = bn->ql.flink; + bn->ql.flink->ql.blink = bn->ql.blink; + b->bh.bsize += bn->bh.bsize; + + // Finally, advance to the buffer that follows the newly + // consolidated free block. We must set its backpointer to the + // head of the consolidated free block. We know the next block + // must be an allocated block because the process of recombination + // guarantees that two free blocks will never be contiguous in + // memory. + bn = BFH(((char *) b) + b->bh.bsize); + } + + memset(((char *) b) + sizeof(struct bfhead), 0x55,(int) (b->bh.bsize - sizeof(struct bfhead))); + + assert(bn->bh.bsize < 0); + + // The next buffer is allocated. Set the backpointer in it to point + // to this buffer; the previous free buffer in memory. + bn->bh.prevfree = b->bh.bsize; + + // If a block-release function is defined, and this free buffer + // constitutes the entire block, release it. Note that pool_len + // is defined in such a way that the test will fail unless all + // pool blocks are the same size. + + if (((ssize_t) b->bh.bsize) == (ssize_t)(pool_len - sizeof(struct bhead))) + { + assert(b->bh.prevfree == 0); + assert(BH((char *) b + b->bh.bsize)->bsize == ESent); + assert(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize); + + // Unlink the buffer from the free list + b->ql.blink->ql.flink = b->ql.flink; + b->ql.flink->ql.blink = b->ql.blink; + + ReleaseMem(b); + + // Nr of expansion block releases + numprel++; + + // Total number of blocks + numpblk--; + assert(numpblk == numpget - numprel); + } +} + +// Add a region of memory to the buffer pool. +void MemPool::AddToPool(void *buf, ssize_t len) +{ + struct bfhead *b = BFH(buf); + struct bhead *bn; + + len &= ~(SizeQuant - 1); + + if (pool_len == 0) + { + pool_len = len; + } + else + if (len != pool_len) + { + pool_len = -1; + } + + // Number of block acquisitions + numpget++; + + // Number of blocks total + numpblk++; + assert(numpblk == numpget - numprel); + + // Since the block is initially occupied by a single free buffer, + // it had better not be (much) larger than the largest buffer + // whose size we can store in bhead.bsize. + assert(len - sizeof(struct bhead) <= -((ssize_t) ESent + 1)); + + // Clear the backpointer at the start of the block to indicate that + // there is no free block prior to this one. That blocks + // recombination when the first block in memory is released. + b->bh.prevfree = 0; + + // Chain the new block to the free list. + assert(freelist.ql.blink->ql.flink == &freelist); + assert(freelist.ql.flink->ql.blink == &freelist); + b->ql.flink = &freelist; + b->ql.blink = freelist.ql.blink; + freelist.ql.blink = b; + b->ql.blink->ql.flink = b; + + // Create a dummy allocated buffer at the end of the pool. This dummy + // buffer is seen when a buffer at the end of the pool is released and + // blocks recombination of the last buffer with the dummy buffer at + // the end. The length in the dummy buffer is set to the largest + // negative number to denote the end of the pool for diagnostic + // routines (this specific value is not counted on by the actual + // allocation and release functions). + + len -= sizeof(struct bhead); + b->bh.bsize = (ssize_t) len; + + memset(((char *) b) + sizeof(struct bfhead), 0x55,(int) (len - sizeof(struct bfhead))); + + bn = BH(((char *) b) + len); + bn->prevfree = (ssize_t) len; + + // Definition of ESent assumes two's complement! + assert((~0) == -1); + bn->bsize = ESent; +} + + +// Return buffer allocation free space statistics. +void MemPool::Stats(ssize_t *curalloc, ssize_t *totfree, ssize_t *maxfree, + long *nget, long *nrel) +{ + struct bfhead *b = freelist.ql.flink; + + *nget = numget; + *nrel = numrel; + *curalloc = totalloc; + *totfree = 0; + *maxfree = -1; + while (b != &freelist) + { + assert(b->bh.bsize > 0); + *totfree += b->bh.bsize; + if (b->bh.bsize > *maxfree) + { + *maxfree = b->bh.bsize; + } + + // Link to next buffer + b = b->ql.flink; + } +} + + +// Return extended statistics +void MemPool::ExtendedStats(ssize_t *pool_incr, long *npool, long *npget, long *nprel, + long *ndget, long *ndrel) +{ + *pool_incr = (pool_len < 0) ? -exp_incr : exp_incr; + *npool = numpblk; + *npget = numpget; + *nprel = numprel; + *ndget = numdget; + *ndrel = numdrel; +} + + + +// Dump the data in a buffer. This is called with the user data pointer, +// and backs up to the buffer header. It will dump either a free block +// or an allocated one. +void MemPool::BufferDump(void *buf) +{ + struct bfhead *b; + unsigned char *bdump; + ssize_t bdlen; + + b = BFH(((char *) buf) - sizeof(struct bhead)); + assert(b->bh.bsize != 0); + if (b->bh.bsize < 0) + { + bdump = (unsigned char *) buf; + bdlen = (-b->bh.bsize) - sizeof(struct bhead); + } + else + { + bdump = (unsigned char *) (((char *) b) + sizeof(struct bfhead)); + bdlen = b->bh.bsize - sizeof(struct bfhead); + } + + while (bdlen > 0) + { + int i, dupes = 0; + ssize_t l = bdlen; + char bhex[50], bascii[20]; + + if (l > 16) + { + l = 16; + } + + for (i = 0; i < l; i++) + { + sprintf(bhex + i * 3, "%02X ", bdump[i]); + bascii[i] = isprint(bdump[i]) ? bdump[i] : ' '; + } + bascii[i] = 0; + printf("%-48s %s\n", bhex, bascii); + bdump += l; + bdlen -= l; + while ((bdlen > 16) && (memcmp((char *) (bdump - 16),(char *) bdump, 16) == 0)) + { + dupes++; + bdump += 16; + bdlen -= 16; + } + + if (dupes > 1) + { + printf(" (%d lines [%d bytes] identical to above line skipped)\n", + dupes, dupes * 16); + } + else + { + if (dupes == 1) + { + bdump -= 16; + bdlen += 16; + } + } + } +} + +// Dump a buffer pool. The buffer headers are always listed. If DUMPALLOC is +// nonzero, the contents of allocated buffers are dumped. If DUMPFREE is +// nonzero, free blocks are dumped as well. If FreeWipe checking is enabled, +// free blocks which have been clobbered will always be dumped. +void MemPool::PoolDump(void *buf, bool dumpalloc, bool dumpfree) +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) + { + ssize_t bs = b->bh.bsize; + + if (bs < 0) + { + bs = -bs; + printf("Allocated buffer: size %6ld bytes.\n", (long) bs); + if (dumpalloc) + { + BufferDump((void *) (((char *) b) + sizeof(struct bhead))); + } + } + else + { + char *lerr = ""; + + assert(bs > 0); + if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) + { + lerr = " (Bad free list links)"; + } + printf("Free block: size %6ld bytes.%s\n", + (long) bs, lerr); + + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > (ssize_t)sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1, (int) (bs - (sizeof(struct bfhead) + 1))) != 0))) + { + printf("(Contents of above free block have been overstored.)\n"); + BufferDump((void *) (((char *) b) + sizeof(struct bhead))); + } + else + { + if (dumpfree) + { + BufferDump((void *) (((char *) b) + sizeof(struct bhead))); + } + } + } + b = BFH(((char *) b) + bs); + } +} + +// Validate a buffer pool. +int MemPool::Validate(void *buf) +{ + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) + { + ssize_t bs = b->bh.bsize; + + if (bs < 0) + { + bs = -bs; + } + else + { + char *lerr = ""; + + assert(bs > 0); + if (bs <= 0) + { + return 0; + } + + if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) + { + printf("Free block: size %6ld bytes. (Bad free list links)\n", + (long) bs); + assert(0); + return 0; + } + + lerr = ((char *) b) + sizeof(struct bfhead); + if ((bs > (ssize_t)sizeof(struct bfhead)) && ((*lerr != 0x55) || + (memcmp(lerr, lerr + 1,(int) (bs - (sizeof(struct bfhead) + 1))) != 0))) + { + printf("(Contents of above free block have been overstored.)\n"); + BufferDump((void *) (((char *) b) + sizeof(struct bhead))); + assert(0); + return 0; + } + + } + b = BFH(((char *) b) + bs); + } + return 1; +} + +int *MemPool::CompactMem(ssize_t sizereq, int sequence) +{ + return NULL; +} + +void *MemPool::AcquireMem(ssize_t size) +{ + return malloc(size); +} + +void MemPool::ReleaseMem(void *buffer) +{ + free(buffer); +} + +AreaPool::AreaPool(void) +{ +} + +AreaPool::~AreaPool(void) +{ +} + +void *AreaPool::AcquireMem(ssize_t size) +{ + long areasize=0; + area_id a; + int *parea; + + if(size + +class MemPool +{ +public: + MemPool(void); + virtual ~MemPool(void); + + void AddToPool(void *buffer, ssize_t len); + void *GetBuffer(ssize_t size, bool zero=false); + void *ReallocateBuffer(void *buffer, ssize_t size); + void ReleaseBuffer(void *buffer); + + virtual int *CompactMem(ssize_t sizereq, int sequence); + virtual void *AcquireMem(ssize_t size); + virtual void ReleaseMem(void *buffer); + void SetPoolIncrement(ssize_t increment); + ssize_t PoolIncrement(void); + + void Stats(ssize_t *curalloc, ssize_t *totfree, ssize_t *maxfree, + long *nget, long *nrel); + + void ExtendedStats(ssize_t *pool_incr, long *npool, long *npget, + long *nprel, long *ndget, long *ndrel); + + void BufferDump(void *buf); + void PoolDump(void *pool, bool dumpalloc, bool dumpfree); + int Validate(void *buffer); + +private: + ssize_t totalloc; + long numget, numrel; + long numpblk; + long numpget, numprel; + long numdget, numdrel; + ssize_t exp_incr; + ssize_t pool_len; + +}; + +class AreaPool : public MemPool +{ +public: + AreaPool(void); + virtual ~AreaPool(void); + virtual void *AcquireMem(ssize_t size); + virtual void ReleaseMem(void *buffer); +}; + +#endif diff --git a/src/tests/apps/fake_app_server/Jamfile b/src/tests/apps/fake_app_server/Jamfile new file mode 100644 index 0000000000..d48a669b6d --- /dev/null +++ b/src/tests/apps/fake_app_server/Jamfile @@ -0,0 +1,17 @@ +SubDir OBOS_TOP src tests apps fake_app_server ; + +UseLibraryHeaders agg png zlib ; +UsePrivateHeaders app interface [ FDirName servers app ] ; +UseHeaders [ FDirName $(OBOS_TOP) src servers app drawing ] ; +UseHeaders [ FDirName $(OBOS_TOP) src servers app drawing Painter ] ; +UseHeaders [ FDirName $(OBOS_TOP) src servers app drawing Painter drawing_modes ] ; +UseHeaders [ FDirName $(OBOS_TOP) src servers app drawing Painter font_support ] ; +UseFreeTypeHeaders ; + +Server fake_app_server : + AppServer.cpp + ServerApp.cpp + BGet++.cpp + Utils.cpp + : libroot.so libbe.so + ; diff --git a/src/tests/apps/fake_app_server/ServerApp.cpp b/src/tests/apps/fake_app_server/ServerApp.cpp new file mode 100644 index 0000000000..4ba63ec7b8 --- /dev/null +++ b/src/tests/apps/fake_app_server/ServerApp.cpp @@ -0,0 +1,1150 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2005, Haiku, Inc. +// +// 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 +#include +#include +#include + +#include "AppServer.h" +#include "BGet++.h" +#if 0 +#include "BitmapManager.h" +#include "CursorManager.h" + +#include "Desktop.h" +#include "DisplayDriver.h" +#include "FontServer.h" +#include "RAMLinkMsgReader.h" +#include "RootLayer.h" +#endif +#include "ServerApp.h" +#include "ServerConfig.h" +#include "Utils.h" +#if 0 +#include "ServerScreen.h" +#include "ServerWindow.h" +#include "ServerCursor.h" +#include "ServerBitmap.h" +#include "ServerPicture.h" +#include "WinBorder.h" +#include "LayerData.h" +#endif + +//#define DEBUG_SERVERAPP +#ifdef DEBUG_SERVERAPP +# define DEBUG 1 +# include +# define STRACE(x) _sPrintf x +#else +# define STRACE(x) ; +#endif + +//#define DEBUG_SERVERAPP_FONT + +#ifdef DEBUG_SERVERAPP_FONT +# include +# define FTRACE(x) printf x +#else +# define FTRACE(x) ; +#endif + +/*! + \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(port_id sendport, port_id rcvport, port_id clientLooperPort, + team_id clientTeamID, int32 handlerID, char *signature) +{ + // it will be of *very* musch use in correct window order + fClientTeamID = clientTeamID; + + // what to send a message to the client? Write a BMessage to this port. + fClientLooperPort = clientLooperPort; + + // need to copy the fSignature because the message buffer + // owns the copy which we are passed as a parameter. + fSignature=(signature)?signature:"application/x-vnd.NULL-application-signature"; + + // token ID of the BApplication's BHandler object. Used for BMessage target specification + fHandlerToken=handlerID; + + // fClientAppPort is the our BApplication's event port + fClientAppPort=sendport; + + // fMessagePort is the port we receive messages from our BApplication + fMessagePort=rcvport; + + fMsgReader = new LinkMsgReader(fMessagePort); + fMsgSender = new LinkMsgSender(fClientAppPort); + + fIsActive=false; + + fSharedMem=new AreaPool; + fLockSem=create_sem(1,"ServerApp sem"); + + Run(); + + STRACE(("ServerApp %s:\n",fSignature.String())); + STRACE(("\tBApp port: %ld\n",fClientAppPort)); + STRACE(("\tReceiver port: %ld\n",fMessagePort)); +} + +//! Does all necessary teardown for application +ServerApp::~ServerApp(void) +{ + STRACE(("*ServerApp %s:~ServerApp()\n",fSignature.String())); + + delete fMsgReader; + delete fMsgSender; + + delete_sem(fLockSem); + + STRACE(("#ServerApp %s:~ServerApp()\n",fSignature.String())); + + // Kill the monitor thread if it exists + thread_info info; + if(get_thread_info(fMonitorThreadID,&info)==B_OK) + kill_thread(fMonitorThreadID); + + delete fSharedMem; +} + +/*! + \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. + fMonitorThreadID=spawn_thread(MonitorApp,fSignature.String(),B_NORMAL_PRIORITY,this); + if(fMonitorThreadID==B_NO_MORE_THREADS || fMonitorThreadID==B_NO_MEMORY) + return false; + + resume_thread(fMonitorThreadID); + return true; +} + + +bool +ServerApp::PingTarget(void) +{ + team_info tinfo; + if(get_team_info(fClientTeamID,&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",fSignature.String()); + return false; + } + fMsgSender->SetPort(serverport); + fMsgSender->StartMessage(AS_DELETE_APP); + fMsgSender->Attach(&fMonitorThreadID,sizeof(thread_id)); + fMsgSender->Flush(); + return false; + } + return true; +} + +/*! + \brief Send a message to the ServerApp with no attachments + \param code ID code of the message to post +*/ +void ServerApp::PostMessage(int32 code) +{ + BPortLink link(fMessagePort); + link.StartMessage(code); + link.Flush(); +} + +/*! + \brief Send a message to the ServerApp's BApplication + \param msg The message to send +*/ +void ServerApp::SendMessageToClient(const BMessage *msg) const +{ + ssize_t size; + char *buffer; + + size=msg->FlattenedSize(); + buffer=new char[size]; + + if (msg->Flatten(buffer, size) == B_OK) + write_port(fClientLooperPort, msg->what, buffer, size); + else + printf("PANIC: ServerApp: '%s': can't flatten message in 'SendMessageToClient()'\n", fSignature.String()); + + delete [] buffer; +} + +/*! + \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(void) +{ +} + +/*! + \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) +{ + // Message-dispatching loop for the ServerApp + + ServerApp *app = (ServerApp *)data; + LinkMsgReader msgqueue(app->fMessagePort); + + bool quitting = false; + int32 code; + status_t err = B_OK; + + while(!quitting) + { + STRACE(("info: ServerApp::MonitorApp listening on port %ld.\n", app->fMessagePort)); +// err = msgqueue.GetNextReply(&code); + err = msgqueue.GetNextMessage(&code); + if (err < B_OK) + break; + + switch(code) + { + case AS_CREATE_WINDOW: + { + BRect frame; + uint32 look, feel, flags, wkspaces; + int32 token = B_NULL_TOKEN; + port_id sendPort = -1; + port_id looperPort = -1; + char *title = NULL; + + msgqueue.Read(&frame); + msgqueue.Read(&look); + msgqueue.Read(&feel); + msgqueue.Read(&flags); + msgqueue.Read(&wkspaces); + msgqueue.Read(&token); + msgqueue.Read(&sendPort); + msgqueue.Read(&looperPort); + msgqueue.ReadString(&title); + + STRACE(("ServerApp %s: Got 'New Window' message, trying to do smething...\n",app->fSignature.String())); + + if (title) + free(title); + + 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",app->fSignature.String())); + + // 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 + break; + } + + case B_QUIT_REQUESTED: + { + STRACE(("ServerApp %s: B_QUIT_REQUESTED\n",app->fSignature.String())); + // Our BApplication sent us this message when it quit. + // We need to ask the app_server to delete our monitor + // ADI: No! This is a bad solution. A thead should continue its + // execution until its exit point, and this can *very* easily be done + quitting=true; + // see... no need to ask the main thread to kill us. + // still... it will delete this ServerApp object. + 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->fSignature.String()); + break; + } + app->fMsgSender->SetPort(serverport); + app->fMsgSender->StartMessage(AS_DELETE_APP); + app->fMsgSender->Attach(&app->fMonitorThreadID, sizeof(thread_id)); + app->fMsgSender->Flush(); + break; + } + default: + { + STRACE(("ServerApp %s: Got a Message to dispatch\n",app->fSignature.String())); + app->DispatchMessage(code, msgqueue); + break; + } + } + + } // end for + + // clean exit. + 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, LinkMsgReader &msg) +{ + BPortLink replylink; + + switch(code) + { +// case AS_UPDATE_COLORS: +// case AS_UPDATE_FONTS: +// 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; + port_id replyport; + + msg.Read(&memsize); + msg.Read(&replyport); + + // TODO: I wonder if ACQUIRE_SERVERMEM should have a minimum size requirement? + + void *sharedmem=fSharedMem->GetBuffer(memsize); + + replylink.SetSendPort(replyport); + if(memsize<1 || sharedmem==NULL) + { + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + + area_id owningArea=area_for(sharedmem); + area_info ai; + + if(owningArea==B_ERROR || get_area_info(owningArea,&ai)!=B_OK) + { + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + + int32 areaoffset=((int32*)sharedmem)-((int32*)ai.address); + STRACE(("Successfully allocated shared memory of size %ld\n",memsize)); + + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(owningArea); + replylink.Attach(areaoffset); + replylink.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; + area_info ai; + int32 areaoffset; + void *sharedmem; + + msg.Read(&owningArea); + msg.Read(&areaoffset); + + if(owningArea<0 || get_area_info(owningArea,&ai)!=B_OK) + break; + + STRACE(("Successfully freed shared memory\n")); + sharedmem=((int32*)ai.address)+areaoffset; + + fSharedMem->ReleaseBuffer(sharedmem); + + break; + } + case AS_CREATE_BITMAP: + { + STRACE(("ServerApp %s: Received BBitmap creation request\n",fSignature.String())); + // 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 + port_id replyport = -1; + BRect r; + color_space cs; + int32 f,bpr; + screen_id s; + + msg.Read(&r); + msg.Read(&cs); + msg.Read(&f); + msg.Read(&bpr); + msg.Read(&s); + msg.Read(&replyport); + + STRACE(("ServerApp %s: Create Bitmap (%.1f,%.1f,%.1f,%.1f)\n", + fSignature.String(),r.left,r.top,r.right,r.bottom)); + + replylink.SetSendPort(replyport); +/* if(sbmp) + { + fBitmapList->AddItem(sbmp); + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(sbmp->Token()); + replylink.Attach(sbmp->Area()); + replylink.Attach(sbmp->AreaOffset()); + } + else*/ + { + // alternatively, if something went wrong, we reply with SERVER_FALSE + replylink.StartMessage(SERVER_FALSE); + } + replylink.Flush(); + + break; + } + case AS_DELETE_BITMAP: + { + STRACE(("ServerApp %s: received BBitmap delete request\n",fSignature.String())); + // 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 + port_id replyport = -1; + int32 bmp_id; + + msg.Read(&bmp_id); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_TRUE); + replylink.Flush(); + break; + } + case AS_CREATE_PICTURE: + { + // TODO: Implement AS_CREATE_PICTURE + STRACE(("ServerApp %s: Create Picture unimplemented\n",fSignature.String())); + + break; + } + case AS_DELETE_PICTURE: + { + // TODO: Implement AS_DELETE_PICTURE + STRACE(("ServerApp %s: Delete Picture unimplemented\n",fSignature.String())); + + break; + } + case AS_CLONE_PICTURE: + { + // TODO: Implement AS_CLONE_PICTURE + STRACE(("ServerApp %s: Clone Picture unimplemented\n",fSignature.String())); + + break; + } + case AS_DOWNLOAD_PICTURE: + { + // TODO; Implement AS_DOWNLOAD_PICTURE + + // What is this particular function call for, anyway? + STRACE(("ServerApp %s: Download Picture unimplemented\n",fSignature.String())); + + break; + } + case AS_SET_SCREEN_MODE: + case AS_ACTIVATE_WORKSPACE: + break; + + case AS_SHOW_CURSOR: + fCursorHidden=false; + break; + case AS_HIDE_CURSOR: + fCursorHidden=true; + break; + case AS_OBSCURE_CURSOR: + break; + case AS_QUERY_CURSOR_HIDDEN: + { + STRACE(("ServerApp %s: Received IsCursorHidden request\n",fSignature.String())); + // Attached data + // 1) int32 port to reply to + int32 replyport; + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(fCursorHidden ? SERVER_TRUE : SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_SET_CURSOR_DATA: + case AS_SET_CURSOR_BCURSOR: + break; + case AS_CREATE_BCURSOR: + { + STRACE(("ServerApp %s: Create BCursor\n",fSignature.String())); + // Attached data: + // 1) 68 bytes of fAppCursor data + // 2) port_id reply port + + port_id replyport = -1; + int8 cdata[68]; + + msg.Read(cdata,68); + msg.Read(&replyport); + + // Synchronous message - BApplication is waiting on the cursor's ID + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(-1); + replylink.Flush(); + break; + } + case AS_DELETE_BCURSOR: + { + STRACE(("ServerApp %s: Delete BCursor\n",fSignature.String())); + // Attached data: + // 1) int32 token ID of the cursor to delete + int32 ctoken = B_NULL_TOKEN; + msg.Read(&ctoken); + break; + } + case AS_GET_SCROLLBAR_INFO: + { + STRACE(("ServerApp %s: Get ScrollBar info\n",fSignature.String())); + // Attached data: + // 1) port_id reply port - synchronous message + + scroll_bar_info sbi; + + port_id replyport; + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(sbi); + replylink.Flush(); + break; + } + case AS_SET_SCROLLBAR_INFO: + { + STRACE(("ServerApp %s: Set ScrollBar info\n",fSignature.String())); + // Attached Data: + // 1) scroll_bar_info scroll bar info structure + scroll_bar_info sbi; + msg.Read(&sbi); + break; + } + case AS_FOCUS_FOLLOWS_MOUSE: + { + STRACE(("ServerApp %s: query Focus Follow Mouse in use\n",fSignature.String())); + // Attached data: + // 1) port_id reply port - synchronous message + + port_id replyport; + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(true); + replylink.Flush(); + break; + } + case AS_SET_FOCUS_FOLLOWS_MOUSE: + { + STRACE(("ServerApp %s: Set Focus Follows Mouse in use\n",fSignature.String())); +/* // Attached Data: + // 1) scroll_bar_info scroll bar info structure + scroll_bar_info sbi; + msg.Read(&sbi); + + desktop->SetScrollBarInfo(sbi);*/ + break; + } + case AS_SET_MOUSE_MODE: + { + STRACE(("ServerApp %s: Set Focus Follows Mouse mode\n",fSignature.String())); + // Attached Data: + // 1) enum mode_mouse FFM mouse mode + mode_mouse mmode; + msg.Read(&mmode); + break; + } + case AS_GET_MOUSE_MODE: + { + STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n",fSignature.String())); + // Attached data: + // 1) port_id reply port - synchronous message + + mode_mouse mmode = (mode_mouse)0; + + port_id replyport = -1; + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(mmode); + replylink.Flush(); + break; + } + case AS_GET_UI_COLOR: + { + STRACE(("ServerApp %s: Get UI color\n",fSignature.String())); + + rgb_color color = {0,0,0,0}; + int32 whichcolor; + port_id replyport = -1; + + msg.Read(&whichcolor); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(color); + replylink.Flush(); + break; + } + case AS_UPDATED_CLIENT_FONTLIST: + { + STRACE(("ServerApp %s: Acknowledged update of client-side font list\n",fSignature.String())); + break; + } + case AS_QUERY_FONTS_CHANGED: + { + FTRACE(("ServerApp %s: AS_QUERY_FONTS_CHANGED unimplemented\n",fSignature.String())); + // Attached Data: + // 1) bool check flag + // 2) port_id reply_port + + // if just checking, just give an answer, + // if not and needs updated, + // sync the font list and return true else return false + break; + } + case AS_GET_FAMILY_NAME: + { + FTRACE(("ServerApp %s: AS_GET_FAMILY_NAME\n",fSignature.String())); + // Attached Data: + // 1) int32 the ID of the font family to get + // 2) port_id reply port + + // Returns: + // 1) font_family - name of family + // 2) uint32 - flags of font family (B_IS_FIXED || B_HAS_TUNED_FONT) + int32 famid; + port_id replyport; + + msg.Read(&famid); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_GET_STYLE_NAME: + { + FTRACE(("ServerApp %s: AS_GET_STYLE_NAME\n",fSignature.String())); + // Attached Data: + // 1) font_family The name of the font family + // 2) int32 ID of the style to get + // 3) port_id reply port + + // Returns: + // 1) font_style - name of the style + // 2) uint16 - appropriate face values + // 3) uint32 - flags of font style (B_IS_FIXED || B_HAS_TUNED_FONT) + + font_family fam; + int32 styid; + port_id replyport; + + msg.Read(fam,sizeof(font_family)); + msg.Read(&styid); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_GET_FAMILY_AND_STYLE: + { + FTRACE(("ServerApp %s: AS_GET_FAMILY_AND_STYLE\n",fSignature.String())); + // Attached Data: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) port_id reply port + + // Returns: + // 1) font_family The name of the font family + // 2) font_style - name of the style + uint16 famid, styid; + port_id replyport; + + msg.Read(&famid); + msg.Read(&styid); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_GET_FONT_DIRECTION: + { + FTRACE(("ServerApp %s: AS_GET_FONT_DIRECTION unimplemented\n",fSignature.String())); + // Attached Data: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) port_id reply port + + // Returns: + // 1) font_direction direction of font + + // NOTE: While this may be unimplemented, we can safely return + // SERVER_FALSE. This will force the BFont code to default to + // B_LEFT_TO_RIGHT, which is what the vast majority of fonts will be. + // This will be fixed later. + int32 famid, styid; + port_id replyport; + + msg.Read(&famid); + msg.Read(&styid); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + +/* fontserver->Lock(); + FontStyle *fstyle=fontserver->GetStyle(famid,styid); + if(fstyle) + { + font_direction dir=fstyle->GetDirection(); + + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(dir); + replylink.Flush(); + } + else + { +*/ replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); +// } + +// fontserver->Unlock(); + break; + } + case AS_GET_STRING_WIDTH: + { + FTRACE(("ServerApp %s: AS_GET_STRING_WIDTH\n",fSignature.String())); + // Attached Data: + // 1) string String to measure + // 2) int32 string length to measure + // 3) uint16 ID of family + // 4) uint16 ID of style + // 5) float point size of font + // 6) uint8 spacing to use + // 7) port_id reply port + + // Returns: + // 1) float - width of the string in pixels + char *string=NULL; + int32 length; + uint16 family,style; + float size; + uint8 spacing; + port_id replyport; + + msg.ReadString(&string); + msg.Read(&length); + msg.Read(&family); + msg.Read(&style); + msg.Read(&size); + msg.Read(&spacing); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_GET_FONT_BOUNDING_BOX: + { + FTRACE(("ServerApp %s: AS_GET_BOUNDING_BOX unimplemented\n",fSignature.String())); + // Attached Data: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) port_id reply port + + // Returns: + // 1) BRect - box holding entire font + + break; + } + case AS_GET_TUNED_COUNT: + { + FTRACE(("ServerApp %s: AS_GET_TUNED_COUNT\n",fSignature.String())); + // Attached Data: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) port_id reply port + + // Returns: + // 1) int32 - number of font strikes available + int32 famid, styid; + port_id replyport; + + msg.Read(&famid); + msg.Read(&styid); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_GET_TUNED_INFO: + { + FTRACE(("ServerApp %s: AS_GET_TUNED_INFO unimplmemented\n",fSignature.String())); + // Attached Data: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) uint32 - index of the particular font strike + // 4) port_id reply port + + // Returns: + // 1) tuned_font_info - info on the strike specified + break; + } + case AS_QUERY_FONT_FIXED: + { + FTRACE(("ServerApp %s: AS_QUERY_FONT_FIXED unimplmemented\n",fSignature.String())); + // Attached Data: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) port_id reply port + + // Returns: + // 1) bool - font is/is not fixed + int32 famid, styid; + port_id replyport; + + msg.Read(&famid); + msg.Read(&styid); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_SET_FAMILY_NAME: + { + FTRACE(("ServerApp %s: AS_SET_FAMILY_NAME\n",fSignature.String())); + // Attached Data: + // 1) font_family - name of font family to use + // 2) port_id - reply port + + // Returns: + // 1) uint16 - family ID + + port_id replyport; + font_family fam; + + msg.Read(fam,sizeof(font_family)); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_SET_FAMILY_AND_STYLE: + { + FTRACE(("ServerApp %s: AS_SET_FAMILY_AND_STYLE\n",fSignature.String())); + // Attached Data: + // 1) font_family - name of font family to use + // 2) font_style - name of style in family + // 3) port_id - reply port + + // Returns: + // 1) uint16 - family ID + // 2) uint16 - style ID + + port_id replyport; + font_family fam; + font_style sty; + + msg.Read(fam,sizeof(font_family)); + msg.Read(sty,sizeof(font_style)); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_SET_FAMILY_AND_STYLE_FROM_ID: + { + FTRACE(("ServerApp %s: AS_SET_FAMILY_AND_STYLE_FROM_ID\n",fSignature.String())); + // Attached Data: + // 1) uint16 - ID of font family to use + // 2) uint16 - ID of style in family + // 3) port_id - reply port + + // Returns: + // 1) uint16 - face of the font + + port_id replyport; + uint16 fam, sty; + + msg.Read(&fam); + msg.Read(&sty); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_SET_FAMILY_AND_FACE: + { + FTRACE(("ServerApp %s: AS_SET_FAMILY_AND_FACE unimplmemented\n",fSignature.String())); + // Attached Data: + // 1) font_family - name of font family to use + // 2) uint16 - font face + // 3) port_id - reply port + + // Returns: + // 1) uint16 - family ID + // 2) uint16 - style ID + + // TODO: Check R5 for error condition behavior in SET_FAMILY_AND_FACE + break; + } + case AS_COUNT_FONT_FAMILIES: + { + FTRACE(("ServerApp %s: AS_COUNT_FONT_FAMILIES\n",fSignature.String())); + // Attached Data: + // 1) port_id - reply port + + // Returns: + // 1) int32 - # of font families + port_id replyport; + + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(0); + replylink.Flush(); + break; + } + case AS_COUNT_FONT_STYLES: + { + FTRACE(("ServerApp %s: AS_COUNT_FONT_STYLES\n",fSignature.String())); + // Attached Data: + // 1) font_family - name of font family + // 2) port_id - reply port + + // Returns: + // 1) int32 - # of font styles + port_id replyport; + font_family fam; + + msg.Read(fam,sizeof(font_family)); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_SET_SYSFONT_PLAIN: + { + FTRACE(("ServerApp %s: AS_SET_SYSFONT_PLAIN\n",fSignature.String())); + // Attached Data: + // port_id reply port + + // Returns: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) float - size in points + // 4) uint16 - face flags + // 5) uint32 - font flags + + port_id replyport; + msg.Read(&replyport); + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_GET_FONT_HEIGHT: + { + FTRACE(("ServerApp %s: AS_GET_FONT_HEIGHT\n",fSignature.String())); + // Attached Data: + // 1) uint16 family ID + // 2) uint16 style ID + // 3) float size + // 4) port_id reply port + uint16 famid,styid; + float ptsize; + port_id replyport; + + msg.Read(&famid); + msg.Read(&styid); + msg.Read(&ptsize); + msg.Read(&replyport); + + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_SET_SYSFONT_BOLD: + { + FTRACE(("ServerApp %s: AS_SET_SYSFONT_BOLD\n",fSignature.String())); + // Attached Data: + // port_id reply port + + // Returns: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) float - size in points + // 4) uint16 - face flags + // 5) uint32 - font flags + + port_id replyport; + msg.Read(&replyport); + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + case AS_SET_SYSFONT_FIXED: + { + FTRACE(("ServerApp %s: AS_SET_SYSFONT_FIXED\n",fSignature.String())); + // Attached Data: + // port_id reply port + + // Returns: + // 1) uint16 - family ID + // 2) uint16 - style ID + // 3) float - size in points + // 4) uint16 - face flags + // 5) uint32 - font flags + + port_id replyport; + msg.Read(&replyport); + replylink.SetSendPort(replyport); + + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + default: + { + STRACE(("ServerApp %s received unhandled message code offset %s\n",fSignature.String(), + MsgCodeToBString(code).String())); + break; + } + } +} + + +team_id +ServerApp::ClientTeamID() +{ + return fClientTeamID; +} + diff --git a/src/tests/apps/fake_app_server/ServerApp.h b/src/tests/apps/fake_app_server/ServerApp.h new file mode 100644 index 0000000000..032bfb6171 --- /dev/null +++ b/src/tests/apps/fake_app_server/ServerApp.h @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2005, Haiku, Inc. +// +// 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 +// Adi Oanca +// Description: Server-side BApplication counterpart +// +//------------------------------------------------------------------------------ +#ifndef _SERVERAPP_H_ +#define _SERVERAPP_H_ + +#include +#include +#include +#include +//#include "FMWList.h" + +class AppServer; +class BMessage; +class BPortLink; +class BList; +class DisplayDriver; +class ServerCursor; +class ServerBitmap; +class AreaPool; + +/*! + \class ServerApp ServerApp.h + \brief Counterpart to BApplication within the app_server +*/ +class ServerApp +{ +public: + ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort, + team_id clientTeamID, int32 handlerID, char *signature); + virtual ~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 fIsActive; } + + void Activate(bool value); + bool PingTarget(void); + + void PostMessage(int32 code); + + void SendMessageToClient( const BMessage* msg ) const; + void SetAppCursor(void); + + team_id ClientTeamID(); + +const char * Title() const { return fSignature.String(); } +protected: + friend class AppServer; + friend class ServerWindow; + + void DispatchMessage(int32 code, LinkMsgReader &link); + + port_id fClientAppPort, + fMessagePort, + // TODO: find out why there is both the app port and the looper port. Do + // we really need both? + fClientLooperPort; + + BString fSignature; + thread_id fMonitorThreadID; + + team_id fClientTeamID; + + LinkMsgReader *fMsgReader; + LinkMsgSender *fMsgSender; + +/* BList *fSWindowList, + *fBitmapList, + *fPictureList; +*/ sem_id fLockSem; + bool fCursorHidden; + bool fIsActive; + int32 fHandlerToken; + AreaPool *fSharedMem; +}; + +#endif diff --git a/src/tests/apps/fake_app_server/Utils.cpp b/src/tests/apps/fake_app_server/Utils.cpp new file mode 100644 index 0000000000..f33a6b7d16 --- /dev/null +++ b/src/tests/apps/fake_app_server/Utils.cpp @@ -0,0 +1,327 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, Haiku +// +// 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: Utils.cpp +// Author: DarkWyrm +// Description: Miscellaneous utility functions +// +//------------------------------------------------------------------------------ +#include +#include +#include "Utils.h" +#include + +/*! + \brief Send a BMessage to a Looper target + \param port Receiver port of the targeted Looper + \param BMessage to send + + This SendMessage takes ownership of the message sent, so deleting them after this + call is unnecessary. Passing an invalid port will have unpredictable results. +*/ +void SendMessage(port_id port, BMessage *message, int32 target) +{ + if(!message) + return; + + if(target==-1) + _set_message_target_(message,target,true); + else + _set_message_target_(message,target,false); + + ssize_t flatsize=message->FlattenedSize(); + char *buffer=new char[flatsize]; + + if(message->Flatten(buffer,flatsize)==B_OK) + write_port(port, message->what, buffer,flatsize); + + delete [] buffer; + delete message; +} + +/* + Below are friend functions for BMessage which currently are not in the Message.cpp + that we need to send messages to BLoopers and such. Placed here to allow compilation. +*/ +void _set_message_target_(BMessage *msg, int32 target, bool preferred) +{ + if (preferred) + { + msg->fTarget = -1; + msg->fPreferred = true; + } + else + { + msg->fTarget = target; + msg->fPreferred = false; + } +} + +int32 _get_message_target_(BMessage *msg) +{ + if (msg->fPreferred) + return -1; + else + return msg->fTarget; +} + +bool _use_preferred_target_(BMessage *msg) +{ + return msg->fPreferred; +} + +const char *MsgCodeToString(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + char string [10]; + sprintf(string,"'%x%x%x%x'",(char)((code & 0xFF000000) >> 24), + (char)((code & 0x00FF0000) >> 16), + (char)((code & 0x0000FF00) >> 8), + (char)((code & 0x000000FF)) ); + return string; +} + +BString MsgCodeToBString(int32 code) +{ + // Used to translate BMessage message codes back to a character + // format + char string [10]; + sprintf(string,"'%x%x%x%x'",(char)((code & 0xFF000000) >> 24), + (char)((code & 0x00FF0000) >> 16), + (char)((code & 0x0000FF00) >> 8), + (char)((code & 0x000000FF)) ); + + BString bstring(string); + return bstring; +} + +status_t ConvertModeToDisplayMode(uint32 mode, display_mode *dmode) +{ + if(!mode) + return B_BAD_VALUE; + + switch(mode) + { + case B_8_BIT_640x400: + { + dmode->virtual_width=640; + dmode->virtual_height=400; + dmode->space=B_CMAP8; + break; + } + case B_8_BIT_640x480: + { + dmode->virtual_width=640; + dmode->virtual_height=480; + dmode->space=B_CMAP8; + break; + } + case B_15_BIT_640x480: + { + dmode->virtual_width=640; + dmode->virtual_height=480; + dmode->space=B_RGB15; + break; + } + case B_16_BIT_640x480: + { + dmode->virtual_width=640; + dmode->virtual_height=480; + dmode->space=B_RGB16; + break; + } + case B_32_BIT_640x480: + { + dmode->virtual_width=640; + dmode->virtual_height=480; + dmode->space=B_RGB32; + break; + } + case B_8_BIT_800x600: + { + dmode->virtual_width=800; + dmode->virtual_height=600; + dmode->space=B_CMAP8; + break; + } + case B_15_BIT_800x600: + { + dmode->virtual_width=800; + dmode->virtual_height=600; + dmode->space=B_RGB15; + break; + } + case B_16_BIT_800x600: + { + dmode->virtual_width=800; + dmode->virtual_height=600; + dmode->space=B_RGB16; + break; + } + case B_32_BIT_800x600: + { + dmode->virtual_width=800; + dmode->virtual_height=600; + dmode->space=B_RGB32; + break; + } + case B_8_BIT_1024x768: + { + dmode->virtual_width=1024; + dmode->virtual_height=768; + dmode->space=B_CMAP8; + break; + } + case B_15_BIT_1024x768: + { + dmode->virtual_width=1024; + dmode->virtual_height=768; + dmode->space=B_RGB15; + break; + } + case B_16_BIT_1024x768: + { + dmode->virtual_width=1024; + dmode->virtual_height=768; + dmode->space=B_RGB16; + break; + } + case B_32_BIT_1024x768: + { + dmode->virtual_width=1024; + dmode->virtual_height=768; + dmode->space=B_RGB32; + break; + } + case B_8_BIT_1152x900: + { + dmode->virtual_width=1152; + dmode->virtual_height=900; + dmode->space=B_CMAP8; + break; + } + case B_15_BIT_1152x900: + { + dmode->virtual_width=1152; + dmode->virtual_height=900; + dmode->space=B_RGB15; + break; + } + case B_16_BIT_1152x900: + { + dmode->virtual_width=1152; + dmode->virtual_height=900; + dmode->space=B_RGB16; + break; + } + case B_32_BIT_1152x900: + { + dmode->virtual_width=1152; + dmode->virtual_height=900; + dmode->space=B_RGB32; + break; + } + case B_8_BIT_1280x1024: + { + dmode->virtual_width=1280; + dmode->virtual_height=1024; + dmode->space=B_CMAP8; + break; + } + case B_15_BIT_1280x1024: + { + dmode->virtual_width=1280; + dmode->virtual_height=1024; + dmode->space=B_RGB15; + break; + } + case B_16_BIT_1280x1024: + { + dmode->virtual_width=1280; + dmode->virtual_height=1024; + dmode->space=B_RGB16; + break; + } + case B_32_BIT_1280x1024: + { + dmode->virtual_width=1280; + dmode->virtual_height=1024; + dmode->space=B_RGB32; + break; + } + case B_8_BIT_1600x1200: + { + dmode->virtual_width=1600; + dmode->virtual_height=1200; + dmode->space=B_CMAP8; + break; + } + case B_15_BIT_1600x1200: + { + dmode->virtual_width=1600; + dmode->virtual_height=1200; + dmode->space=B_RGB15; + break; + } + case B_16_BIT_1600x1200: + { + dmode->virtual_width=1600; + dmode->virtual_height=1200; + dmode->space=B_RGB16; + break; + } + case B_32_BIT_1600x1200: + { + dmode->virtual_width=1600; + dmode->virtual_height=1200; + dmode->space=B_RGB32; + break; + } + default: + return B_ERROR; + } + return B_OK; +} + +BRect CalculatePolygonBounds(BPoint *pts, int32 pointcount) +{ + if(!pts) + return BRect(0,0,0,0); + + BRect r(0,0,0,0); + + // shamelessly stolen from Marc's BPolygon code and tweaked to fit. :P + r = BRect(pts[0], pts[0]); + + for (int32 i = 1; i < 4; i++) + { + if (pts[i].x < r.left) + r.left = pts[i].x; + if (pts[i].y < r.top) + r.top = pts[i].y; + if (pts[i].x > r.right) + r.right = pts[i].x; + if (pts[i].y > r.bottom) + r.bottom = pts[i].y; + } + return r; +} diff --git a/src/tests/apps/fake_app_server/Utils.h b/src/tests/apps/fake_app_server/Utils.h new file mode 100644 index 0000000000..974e1ff543 --- /dev/null +++ b/src/tests/apps/fake_app_server/Utils.h @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2002, Haiku +// +// 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: Utils.h +// Author: DarkWyrm +// Description: Miscellaneous utility functions +// +//------------------------------------------------------------------------------ +#ifndef UTILS_H_ +#define UTILS_H_ + +#include +#include +#include + +void SendMessage(port_id port, BMessage *message, int32 target=-1); +const char *MsgCodeToString(int32 code); +BString MsgCodeToBString(int32 code); +status_t ConvertModeToDisplayMode(uint32 mode, display_mode *dmode); +BRect CalculatePolygonBounds(BPoint *pts, int32 pointcount); +#endif