//------------------------------------------------------------------------------ // 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: ServerWindow.cpp // Author: DarkWyrm // Adi Oanca // Description: Shadow BWindow class // //------------------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include #include #include "AppServer.h" #include "BGet++.h" #include "Desktop.h" #include "Layer.h" #include "RAMLinkMsgReader.h" #include "RootLayer.h" #include "ServerWindow.h" #include "ServerApp.h" #include "ServerProtocol.h" #include "WinBorder.h" #include "TokenHandler.h" #include "Utils.h" #include "DisplayDriver.h" #include "ServerPicture.h" #include "Workspace.h" #include "MessagePrivate.h" //#define DEBUG_SERVERWINDOW //#define DEBUG_SERVERWINDOW_MOUSE //#define DEBUG_SERVERWINDOW_KEYBOARD //#define DEBUG_SERVERWINDOW_GRAPHICS #ifdef DEBUG_SERVERWINDOW # include # define STRACE(x) printf x #else # define STRACE(x) ; #endif #ifdef DEBUG_SERVERWINDOW_KEYBOARD # include # define STRACE_KEY(x) printf x #else # define STRACE_KEY(x) ; #endif #ifdef DEBUG_SERVERWINDOW_MOUSE # include # define STRACE_MOUSE(x) printf x #else # define STRACE_MOUSE(x) ; #endif #ifdef DEBUG_SERVERWINDOW_GRAPHICS # include # define DTRACE(x) printf x #else # define DTRACE(x) ; #endif //------------------------------------------------------------------------------ template Type read_from_buffer(int8 **_buffer) { Type *typedBuffer = (Type *)(*_buffer); Type value = *typedBuffer; typedBuffer++; *_buffer = (int8 *)(typedBuffer); return value; } //------------------------------------------------------------------------------ /* static int8 *read_pattern_from_buffer(int8 **_buffer) { int8 *pattern = *_buffer; *_buffer += AS_PATTERN_SIZE; return pattern; } */ //------------------------------------------------------------------------------ template void write_to_buffer(int8 **_buffer, Type value) { Type *typedBuffer = (Type *)(*_buffer); *typedBuffer = value; typedBuffer++; *_buffer = (int8 *)(typedBuffer); } //------------------------------------------------------------------------------ /*! \brief Contructor Does a lot of stuff to set up for the window - new decorator, new winborder, spawn a monitor thread. */ ServerWindow::ServerWindow(BRect rect, const char *string, uint32 wlook, uint32 wfeel, uint32 wflags, ServerApp *winapp, port_id winport, port_id looperPort, port_id replyport, uint32 index, int32 handlerID) { STRACE(("ServerWindow(%s)::ServerWindow()\n",string? string: "NULL")); fServerApp = winapp; if(string) fTitle.SetTo(string); else fTitle.SetTo(B_EMPTY_STRING); fFrame = rect; fFlags = wflags; fLook = wlook; fFeel = wfeel; fHandlerToken = handlerID; fClientLooperPort = looperPort; fClientTeamID = winapp->ClientTeamID(); fWorkspaces = index; // floating and modal windows must appear in every workspace where // their main window is present. Thus their wksIndex will be set to // '0x0' and they will be made visible when needed. switch (fFeel) { case B_MODAL_APP_WINDOW_FEEL: case B_MODAL_SUBSET_WINDOW_FEEL: case B_FLOATING_APP_WINDOW_FEEL: case B_FLOATING_SUBSET_WINDOW_FEEL: fWorkspaces = 0x0UL; break; case B_MODAL_ALL_WINDOW_FEEL: case B_FLOATING_ALL_WINDOW_FEEL: case B_SYSTEM_LAST: case B_SYSTEM_FIRST: fWorkspaces = 0xffffffffUL; break; case B_NORMAL_WINDOW_FEEL: if (fWorkspaces == 0x0UL) ;; // TODO: get RootLayer's ActiveWorkspaceIndex } fWinBorder = NULL; cl = NULL; //current layer // fClientWinPort is the port to which the app awaits messages from the server fClientWinPort = winport; // fMessagePort is the port to which the app sends messages for the server fMessagePort = create_port(30,fTitle.String()); fMsgSender=new LinkMsgSender(fClientWinPort); fMsgReader=new LinkMsgReader(fMessagePort); // Send a reply to our window - it is expecting fMessagePort port. fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(fMessagePort); fMsgSender->Flush(); STRACE(("ServerWindow %s:\n",fTitle.String())); STRACE(("\tFrame (%.1f,%.1f,%.1f,%.1f)\n",rect.left,rect.top,rect.right,rect.bottom)); STRACE(("\tPort: %ld\n",fMessagePort)); STRACE(("\tWorkspace: %ld\n",index)); } //------------------------------------------------------------------------------ void ServerWindow::Init(void) { char newName[256]; sprintf(newName, "%ld: %s", fClientTeamID, fTitle.String()); fWinBorder = new WinBorder( fFrame, newName, fLook, fFeel, 0UL, this, desktop->GetDisplayDriver()); // Spawn our message-monitoring thread fMonitorThreadID = spawn_thread(MonitorWin, fTitle.String(), B_NORMAL_PRIORITY, this); if(fMonitorThreadID != B_NO_MORE_THREADS && fMonitorThreadID != B_NO_MEMORY) resume_thread(fMonitorThreadID); } //------------------------------------------------------------------------------ //!Tears down all connections the main app_server objects, and deletes some internals. ServerWindow::~ServerWindow(void) { STRACE(("*ServerWindow (%s):~ServerWindow()\n",fTitle.String())); if (fWinBorder) { delete fWinBorder; fWinBorder = NULL; } cl = NULL; if(fMsgSender) { delete fMsgSender; fMsgSender=NULL; } if(fMsgReader) { delete fMsgReader; fMsgReader=NULL; } STRACE(("#ServerWindow(%s) will exit NOW\n", fTitle.String())); } //! Forces the window border to update its decorator void ServerWindow::ReplaceDecorator(void) { if (!IsLocked()) debugger("you must lock a ServerWindow object before calling ::ReplaceDecorator()\n"); STRACE(("ServerWindow %s: Replace Decorator\n",fTitle.String())); fWinBorder->UpdateDecorator(); } //------------------------------------------------------------------------------ //! Requests that the ServerWindow's BWindow quit void ServerWindow::Quit(void) { // NOTE: if you do something else, other than sending a port message, PLEASE lock STRACE(("ServerWindow %s: Quit\n",fTitle.String())); BMessage msg; msg.what = B_QUIT_REQUESTED; SendMessageToClient(&msg); } //------------------------------------------------------------------------------ //! Shows the window's WinBorder void ServerWindow::Show(void) { // NOTE: if you do something else, other than sending a port message, PLEASE lock STRACE(("ServerWindow %s: Show\n",fTitle.String())); if(!fWinBorder->IsHidden()) return; fWinBorder->GetRootLayer()->ShowWinBorder(fWinBorder); } //------------------------------------------------------------------------------ //! Hides the window's WinBorder void ServerWindow::Hide(void) { // NOTE: if you do something else, other than sending a port message, PLEASE lock STRACE(("ServerWindow %s: Hide\n",fTitle.String())); if(fWinBorder->IsHidden()) return; fWinBorder->GetRootLayer()->HideWinBorder(fWinBorder); } //------------------------------------------------------------------------------ /* \brief Determines whether the window is hidden or not \return true if hidden, false if not */ bool ServerWindow::IsHidden(void) const { return fWinBorder->IsHidden(); } //------------------------------------------------------------------------------ void ServerWindow::Minimize(bool status) { // NOTE: if you do something else, other than sending a port message, PLEASE lock // This function doesn't need much -- check to make sure that we should and // send the message to the client. According to the BeBook, the BWindow hook function // does all the heavy lifting for us. :) bool sendMessages = false; if (status) { if (!IsHidden()) { Hide(); sendMessages = true; } } else { if (IsHidden()) { Show(); sendMessages = true; } } if (sendMessages) { BMessage msg; msg.what = B_MINIMIZE; msg.AddInt64("when", real_time_clock_usecs()); msg.AddBool("minimize", status); SendMessageToClient(&msg); } } //------------------------------------------------------------------------------ // Sends a message to the client to perform a Zoom void ServerWindow::Zoom(void) { // NOTE: if you do something else, other than sending a port message, PLEASE lock BMessage msg; msg.what=B_ZOOM; SendMessageToClient(&msg); } //------------------------------------------------------------------------------ /*! \brief Notifies window of workspace (de)activation \param workspace Index of the workspace changed \param active New active status of the workspace */ void ServerWindow::WorkspaceActivated(int32 workspace, bool active) { STRACE(("ServerWindow %s: WorkspaceActivated(%ld,%s)\n",fTitle.String(), workspace,(active)?"active":"inactive")); BMessage msg; msg.what = B_WORKSPACE_ACTIVATED; msg.AddInt32("workspace", workspace); msg.AddBool("active", active); SendMessageToClient(&msg); } //------------------------------------------------------------------------------ /*! \brief Notifies window of a workspace switch \param oldone index of the previous workspace \param newone index of the new workspace */ void ServerWindow::WorkspacesChanged(int32 oldone,int32 newone) { STRACE(("ServerWindow %s: WorkspacesChanged(%ld,%ld)\n",fTitle.String(),oldone,newone)); BMessage msg; msg.what = B_WORKSPACES_CHANGED; msg.AddInt32("old", oldone); msg.AddInt32("new", newone); SendMessageToClient(&msg); } //------------------------------------------------------------------------------ /*! \brief Notifies window of a change in focus \param active New active status of the window */ void ServerWindow::WindowActivated(bool active) { STRACE(("ServerWindow %s: WindowActivated(%s)\n",fTitle.String(),(active)?"active":"inactive")); BMessage msg; msg.what = B_WINDOW_ACTIVATED; msg.AddBool("active", active); SendMessageToClient(&msg); } //------------------------------------------------------------------------------ /*! \brief Notifies window of a change in screen resolution \param frame Size of the new resolution \param color_space Color space of the new screen mode */ void ServerWindow::ScreenModeChanged(const BRect frame, const color_space cspace) { STRACE(("ServerWindow %s: ScreenModeChanged\n",fTitle.String())); BMessage msg; msg.what = B_SCREEN_CHANGED; msg.AddRect("frame", frame); msg.AddInt32("mode", (int32)cspace); SendMessageToClient(&msg); } //------------------------------------------------------------------------------ /*! \brief Locks the window \return B_OK if everything is ok, B_ERROR if something went wrong */ status_t ServerWindow::Lock(void) { STRACE(("\nServerWindow %s: Lock\n",fTitle.String())); return (fLocker.Lock())?B_OK:B_ERROR; } //------------------------------------------------------------------------------ //! Unlocks the window void ServerWindow::Unlock(void) { STRACE(("ServerWindow %s: Unlock\n\n",fTitle.String())); fLocker.Unlock(); } //------------------------------------------------------------------------------ /*! \brief Determines whether or not the window is locked \return True if locked, false if not. */ bool ServerWindow::IsLocked(void) const { return fLocker.IsLocked(); } //------------------------------------------------------------------------------ /*! \brief Sets the font state for a layer \param layer The layer to set the font */ void ServerWindow::SetLayerFontState(Layer *layer, LinkMsgReader &link) { STRACE(("ServerWindow %s: SetLayerFontStateMessage for layer %s\n", fTitle.String(), layer->fName->String())); // NOTE: no need to check for a lock. This is a private method. uint16 mask; link.Read(&mask); if (mask & B_FONT_FAMILY_AND_STYLE) { uint32 fontID; link.Read((int32*)&fontID); layer->fLayerData->font.SetFamilyAndStyle(fontID); } if (mask & B_FONT_SIZE) { float size; link.Read(&size); layer->fLayerData->font.SetSize(size); } if (mask & B_FONT_SHEAR) { float shear; link.Read(&shear); layer->fLayerData->font.SetShear(shear); } if (mask & B_FONT_ROTATION) { float rotation; link.Read(&rotation); layer->fLayerData->font.SetRotation(rotation); } if (mask & B_FONT_SPACING) { uint8 spacing; link.Read(&spacing); layer->fLayerData->font.SetSpacing(spacing); } if (mask & B_FONT_ENCODING) { uint8 encoding; link.Read((uint8*)&encoding); layer->fLayerData->font.SetEncoding(encoding); } if (mask & B_FONT_FACE) { uint16 face; link.Read(&face); layer->fLayerData->font.SetFace(face); } if (mask & B_FONT_FLAGS) { uint32 flags; link.Read(&flags); layer->fLayerData->font.SetFlags(flags); } } //------------------------------------------------------------------------------ void ServerWindow::SetLayerState(Layer *layer, LinkMsgReader &link) { STRACE(("ServerWindow %s: SetLayerState for layer %s\n",fTitle.String(), layer->fName->String())); // NOTE: no need to check for a lock. This is a private method. rgb_color highColor, lowColor, viewColor; pattern patt; int32 clipRegRects; link.Read( &(layer->fLayerData->penlocation)); link.Read( &(layer->fLayerData->pensize)); link.Read( &highColor, sizeof(rgb_color)); link.Read( &lowColor, sizeof(rgb_color)); link.Read( &viewColor, sizeof(rgb_color)); link.Read( &patt, sizeof(pattern)); link.Read((int8*) &(layer->fLayerData->draw_mode)); link.Read( &(layer->fLayerData->coordOrigin)); link.Read((int8*) &(layer->fLayerData->lineJoin)); link.Read((int8*) &(layer->fLayerData->lineCap)); link.Read( &(layer->fLayerData->miterLimit)); link.Read((int8*) &(layer->fLayerData->alphaSrcMode)); link.Read((int8*) &(layer->fLayerData->alphaFncMode)); link.Read( &(layer->fLayerData->scale)); link.Read( &(layer->fLayerData->fontAliasing)); link.Read( &clipRegRects); layer->fLayerData->patt.Set(*((uint64*)&patt)); layer->fLayerData->highcolor.SetColor(highColor); layer->fLayerData->lowcolor.SetColor(lowColor); layer->fLayerData->viewcolor.SetColor(viewColor); if(clipRegRects != 0) { if(layer->fLayerData->clipReg == NULL) layer->fLayerData->clipReg = new BRegion(); else layer->fLayerData->clipReg->MakeEmpty(); BRect rect; for(int32 i = 0; i < clipRegRects; i++) { link.Read(&rect); layer->fLayerData->clipReg->Include(rect); } } else { if (layer->fLayerData->clipReg) { delete layer->fLayerData->clipReg; layer->fLayerData->clipReg = NULL; } } } //------------------------------------------------------------------------------ Layer * ServerWindow::CreateLayerTree(Layer *localRoot, LinkMsgReader &link) { // NOTE: no need to check for a lock. This is a private method. int32 token; BRect frame; uint32 resizeMask; uint32 eventMask; uint32 eventOptions; uint32 flags; bool hidden; int32 childCount; char *name = NULL; link.Read(&token); link.ReadString(&name); link.Read(&frame); link.Read(&resizeMask); link.Read(&eventMask); link.Read(&eventOptions); link.Read(&flags); link.Read(&hidden); link.Read(&childCount); STRACE(("ServerWindow(%s)::CreateLayerTree()-> layer %s, token %ld\n", fTitle.String(),name,token)); Layer *newLayer; newLayer = new Layer(frame, name, token, resizeMask, flags, desktop->GetDisplayDriver()); if (name) free(name); // there is no way of setting this, other than manually :-) newLayer->fHidden = hidden; newLayer->fEventMask = eventMask; newLayer->fEventOptions = eventOptions; newLayer->fOwner = fWinBorder; // add the new Layer to the tree structure. if(localRoot) localRoot->AddChild(newLayer, NULL); return newLayer; } //------------------------------------------------------------------------------ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link) { if (cl == NULL && code != AS_LAYER_CREATE_ROOT) { printf("ServerWindow %s received unexpected code - message offset %ld before top_view attached.\n",fTitle.String(), code - SERVER_TRUE); return; } RootLayer *myRootLayer = fWinBorder->GetRootLayer(); switch(code) { //--------- BView Messages ----------------- case AS_LAYER_DRAW_BITMAP_SYNC_AT_POINT: { DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP_SYNC_AT_POINT: Layer name: %s\n", fTitle.String(), cl->fName->String())); int32 bitmapToken; BPoint point; link.Read(&bitmapToken); link.Read(&point); ServerBitmap *sbmp = fServerApp->FindBitmap(bitmapToken); if(sbmp) { BRect src, dst; BRegion region; src = sbmp->Bounds(); dst = cl->fParent->ConvertFromParent(cl->fFull.Frame()); region = cl->fParent->ConvertFromParent(&(cl->fFull)); dst.OffsetBy(point); cl->fDriver->DrawBitmap(®ion, sbmp, src, dst, cl->fLayerData); } // TODO: Adi -- shouldn't AS_LAYER_DRAW_BITMAP_SYNC_AT_POINT sync with the client? break; } case AS_LAYER_DRAW_BITMAP_ASYNC_AT_POINT: { DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP_ASYNC_AT_POINT: Layer name: %s\n", fTitle.String(), cl->fName->String())); int32 bitmapToken; BPoint point; link.Read(&bitmapToken); link.Read(&point); ServerBitmap *sbmp = fServerApp->FindBitmap(bitmapToken); if(sbmp) { BRect src, dst; BRegion region; src = sbmp->Bounds(); dst = cl->fParent->ConvertFromParent(cl->fFull.Frame()); region = cl->fParent->ConvertFromParent(&(cl->fFull)); dst.OffsetBy(point); cl->fDriver->DrawBitmap(®ion, sbmp, src, dst, cl->fLayerData); } break; } case AS_LAYER_DRAW_BITMAP_SYNC_IN_RECT: { DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP_SYNC_IN_RECT: Layer name: %s\n", fTitle.String(), cl->fName->String())); int32 bitmapToken; BRect srcRect, dstRect; link.Read(&bitmapToken); link.Read(&dstRect); link.Read(&srcRect); ServerBitmap *sbmp = fServerApp->FindBitmap(bitmapToken); if(sbmp) { BRegion region; BRect dst; region = cl->fParent->ConvertFromParent(&(cl->fFull)); dst = cl->fParent->ConvertFromParent(cl->fFull.Frame()); dstRect.OffsetBy(dst.left, dst.top); cl->fDriver->DrawBitmap(®ion, sbmp, srcRect, dstRect, cl->fLayerData); } // TODO: Adi -- shouldn't AS_LAYER_DRAW_BITMAP_SYNC_IN_RECT sync with the client? break; } case AS_LAYER_DRAW_BITMAP_ASYNC_IN_RECT: { DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP_ASYNC_IN_RECT: Layer name: %s\n", fTitle.String(), cl->fName->String())); int32 bitmapToken; BRect srcRect, dstRect; link.Read(&bitmapToken); link.Read(&dstRect); link.Read(&srcRect); ServerBitmap *sbmp = fServerApp->FindBitmap(bitmapToken); if(sbmp) { BRegion region; BRect dst; region = cl->fParent->ConvertFromParent(&(cl->fFull)); dst = cl->fParent->ConvertFromParent(cl->fFull.Frame()); dstRect.OffsetBy(dst.left, dst.top); cl->fDriver->DrawBitmap(®ion, sbmp, srcRect, dstRect, cl->fLayerData); } break; } case AS_SET_CURRENT_LAYER: { int32 token; link.Read(&token); Layer *current = FindLayer(fWinBorder->fTopLayer, token); if(current) { DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: %s, token %ld\n", fTitle.String(), current->fName->String(), token)); } else { DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: layer not found, token %ld\n", fTitle.String(), token)); } if (current) cl=current; else // hope this NEVER happens! :-) debugger("Server PANIC: window cannot find Layer with ID\n"); break; } case AS_LAYER_CREATE_ROOT: { STRACE(("ServerWindow %s: Message AS_LAYER_CREATE_ROOT\n", fTitle.String())); // Start receiving top_view data -- pass NULL as the parent view. // This should be the *only* place where this happens. if (cl != NULL) break; // fWinBorder->fTopLayer = CreateLayerTree(NULL); fWinBorder->fTopLayer = CreateLayerTree(NULL, link); fWinBorder->fTopLayer->SetAsTopLayer(true); cl = fWinBorder->fTopLayer; // connect decorator and top layer. fWinBorder->AddChild(fWinBorder->fTopLayer, NULL); break; } case AS_LAYER_CREATE: { STRACE(("ServerWindow %s: Message AS_LAYER_CREATE: Layer name: %s\n", fTitle.String(), cl->fName->String())); Layer *newLayer; if (cl == NULL) break; // newLayer = CreateLayerTree(NULL); newLayer = CreateLayerTree(NULL, link); cl->AddChild(newLayer, this); if (!(newLayer->IsHidden())){ myRootLayer->GoInvalidate(newLayer, newLayer->fFull); } break; } case AS_LAYER_DELETE: { // Received when a view is detached from a window. This is definitely // the less taxing operation - we call PruneTree() on the removed // layer, detach the layer itself, delete it, and invalidate the // area assuming that the view was visible when removed STRACE(("ServerWindow %s: AS_LAYER_DELETE(self)...\n", fTitle.String())); Layer *parent; parent = cl->fParent; // here we remove current layer from list. cl->RemoveSelf(); cl->PruneTree(); if (parent) myRootLayer->GoInvalidate(parent, BRegion(cl->Frame())); #ifdef DEBUG_SERVERWINDOW parent->PrintTree(); #endif STRACE(("DONE: ServerWindow %s: Message AS_DELETE_LAYER: Parent: %s Layer: %s\n", fTitle.String(), parent->fName->String(), cl->fName->String())); delete cl; cl=parent; break; } case AS_LAYER_SET_STATE: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: Layer name: %s\n", fTitle.String(), cl->fName->String())); // SetLayerState(cl); SetLayerState(cl,link); cl->RebuildFullRegion(); break; } case AS_LAYER_SET_FONT_STATE: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: Layer name: %s\n", fTitle.String(), cl->fName->String())); // SetLayerFontState(cl); SetLayerFontState(cl,link); cl->RebuildFullRegion(); break; } case AS_LAYER_GET_STATE: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_STATE: Layer name: %s\n", fTitle.String(), cl->fName->String())); LayerData *ld; // these 4 are here because of a compiler warning. Maybe he's right... :-) rgb_color hc, lc, vc; // high, low and view colors uint64 patt; ld = cl->fLayerData; // now we write fewer characters. :-) hc = ld->highcolor.GetColor32(); lc = ld->lowcolor.GetColor32(); vc = ld->viewcolor.GetColor32(); patt = ld->patt.GetInt64(); // TODO: Implement when ServerFont::SetfamilyAndStyle(int32) exists // TODO: Implement *what*? SetFamilyAndStyle exists. :) fMsgSender->StartMessage(SERVER_TRUE); // Attach font state fMsgSender->Attach(ld->font.GetFamilyAndStyle()); fMsgSender->Attach(ld->font.Size()); fMsgSender->Attach(ld->font.Shear()); fMsgSender->Attach(ld->font.Rotation()); fMsgSender->Attach(ld->font.Spacing()); fMsgSender->Attach(ld->font.Encoding()); fMsgSender->Attach(ld->font.Face()); fMsgSender->Attach(ld->font.Flags()); // Attach view state fMsgSender->Attach(ld->penlocation); fMsgSender->Attach(ld->pensize); fMsgSender->Attach(&hc, sizeof(rgb_color)); fMsgSender->Attach(&lc, sizeof(rgb_color)); fMsgSender->Attach(&vc, sizeof(rgb_color)); fMsgSender->Attach(patt); fMsgSender->Attach(ld->coordOrigin); fMsgSender->Attach((uint8)(ld->draw_mode)); fMsgSender->Attach((uint8)(ld->lineCap)); fMsgSender->Attach((uint8)(ld->lineJoin)); fMsgSender->Attach(ld->miterLimit); fMsgSender->Attach((uint8)(ld->alphaSrcMode)); fMsgSender->Attach((uint8)(ld->alphaFncMode)); fMsgSender->Attach(ld->scale); fMsgSender->Attach(ld->fontAliasing); int32 noOfRects = 0; if (ld->clipReg) noOfRects = ld->clipReg->CountRects(); fMsgSender->Attach(noOfRects); for(int i = 0; i < noOfRects; i++) fMsgSender->Attach(ld->clipReg->RectAt(i)); fMsgSender->Attach(cl->fFrame.left); fMsgSender->Attach(cl->fFrame.top); fMsgSender->Attach(cl->fFrame.OffsetToCopy(cl->fBoundsLeftTop)); fMsgSender->Flush(); break; } case AS_LAYER_MOVETO: { STRACE(("ServerWindow %s: Message AS_LAYER_MOVETO: Layer name: %s\n", fTitle.String(), cl->fName->String())); float x, y; link.Read(&x); link.Read(&y); cl->MoveBy(x, y); break; } case AS_LAYER_RESIZETO: { STRACE(("ServerWindow %s: Message AS_LAYER_RESIZETO: Layer name: %s\n", fTitle.String(), cl->fName->String())); float newWidth, newHeight; link.Read(&newWidth); link.Read(&newHeight); // TODO: Check for minimum size allowed. Need WinBorder::GetSizeLimits cl->ResizeBy(newWidth, newHeight); break; } case AS_LAYER_GET_COORD: { STRACE(("ServerWindow %s: Message AS_LAYER_GET_COORD: Layer: %s\n",fTitle.String(), cl->fName->String())); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(cl->fFrame.left); fMsgSender->Attach(cl->fFrame.top); fMsgSender->Attach(cl->fFrame.OffsetToCopy(cl->fBoundsLeftTop)); fMsgSender->Flush(); break; } case AS_LAYER_SET_ORIGIN: { STRACE(("ServerWindow %s: Message AS_LAYER_SET_ORIGIN: Layer: %s\n",fTitle.String(), cl->fName->String())); float x, y; link.Read(&x); link.Read(&y); cl->fLayerData->coordOrigin.Set(x, y); break; } case AS_LAYER_GET_ORIGIN: { STRACE(("ServerWindow %s: Message AS_LAYER_GET_ORIGIN: Layer: %s\n",fTitle.String(), cl->fName->String())); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(cl->fLayerData->coordOrigin); fMsgSender->Flush(); break; } case AS_LAYER_RESIZE_MODE: { STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_MODE: Layer: %s\n",fTitle.String(), cl->fName->String())); link.Read(&(cl->fResizeMode)); break; } case AS_LAYER_CURSOR: { DTRACE(("ServerWindow %s: Message AS_LAYER_CURSOR: Layer: %s - NOT IMPLEMENTED\n",fTitle.String(), cl->fName->String())); int32 token; link.Read(&token); // TODO: implement; I think each Layer should have a member pointing // to this requested cursor. break; } case AS_LAYER_SET_FLAGS: { link.Read(&(cl->fFlags)); STRACE(("ServerWindow %s: Message AS_LAYER_SET_FLAGS: Layer: %s\n",fTitle.String(), cl->fName->String())); break; } case AS_LAYER_HIDE: { STRACE(("ServerWindow %s: Message AS_LAYER_HIDE: Layer: %s\n",fTitle.String(), cl->fName->String())); cl->Hide(); break; } case AS_LAYER_SHOW: { STRACE(("ServerWindow %s: Message AS_LAYER_SHOW: Layer: %s\n",fTitle.String(), cl->fName->String())); cl->Show(); break; } case AS_LAYER_SET_LINE_MODE: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LINE_MODE: Layer: %s\n",fTitle.String(), cl->fName->String())); int8 lineCap, lineJoin; // TODO: Look into locking scheme relating to Layers and modifying redraw-related members link.Read(&lineCap); link.Read(&lineJoin); link.Read(&(cl->fLayerData->miterLimit)); cl->fLayerData->lineCap = (cap_mode)lineCap; cl->fLayerData->lineJoin = (join_mode)lineJoin; break; } case AS_LAYER_GET_LINE_MODE: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LINE_MODE: Layer: %s\n",fTitle.String(), cl->fName->String())); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach((int8)(cl->fLayerData->lineCap)); fMsgSender->Attach((int8)(cl->fLayerData->lineJoin)); fMsgSender->Attach(cl->fLayerData->miterLimit); fMsgSender->Flush(); break; } case AS_LAYER_PUSH_STATE: { DTRACE(("ServerWindow %s: Message AS_LAYER_PUSH_STATE: Layer: %s\n",fTitle.String(), cl->fName->String())); LayerData *ld = new LayerData(); ld->prevState = cl->fLayerData; cl->fLayerData = ld; cl->RebuildFullRegion(); break; } case AS_LAYER_POP_STATE: { DTRACE(("ServerWindow %s: Message AS_LAYER_POP_STATE: Layer: %s\n",fTitle.String(), cl->fName->String())); if (!(cl->fLayerData->prevState)) { DTRACE(("WARNING: SW(%s): User called BView(%s)::PopState(), but there is NO state on stack!\n", fTitle.String(), cl->fName->String())); break; } LayerData *ld = cl->fLayerData; cl->fLayerData = cl->fLayerData->prevState; ld->prevState = NULL; delete ld; cl->RebuildFullRegion(); break; } case AS_LAYER_SET_SCALE: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_SCALE: Layer: %s\n",fTitle.String(), cl->fName->String())); link.Read(&(cl->fLayerData->scale)); break; } case AS_LAYER_GET_SCALE: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_SCALE: Layer: %s\n",fTitle.String(), cl->fName->String())); LayerData *ld = cl->fLayerData; float scale = ld->scale; while((ld = ld->prevState)) scale *= ld->scale; fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(scale); fMsgSender->Flush(); break; } case AS_LAYER_SET_PEN_LOC: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_LOC: Layer: %s\n",fTitle.String(), cl->fName->String())); float x, y; link.Read(&x); link.Read(&y); cl->fLayerData->penlocation.Set(x, y); break; } case AS_LAYER_GET_PEN_LOC: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_LOC: Layer: %s\n",fTitle.String(), cl->fName->String())); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(cl->fLayerData->penlocation); fMsgSender->Flush(); break; } case AS_LAYER_SET_PEN_SIZE: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_SIZE: Layer: %s\n",fTitle.String(), cl->fName->String())); link.Read(&(cl->fLayerData->pensize)); break; } case AS_LAYER_GET_PEN_SIZE: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_SIZE: Layer: %s\n",fTitle.String(), cl->fName->String())); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(cl->fLayerData->pensize); fMsgSender->Flush(); break; } case AS_LAYER_SET_VIEW_COLOR: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_VIEW_COLOR: Layer: %s\n",fTitle.String(), cl->fName->String())); rgb_color c; link.Read(&c, sizeof(rgb_color)); cl->fLayerData->viewcolor.SetColor(c); myRootLayer->GoRedraw(cl, cl->fVisible); break; } case AS_LAYER_GET_COLORS: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_COLORS: Layer: %s\n",fTitle.String(), cl->fName->String())); rgb_color highColor, lowColor, viewColor; highColor = cl->fLayerData->highcolor.GetColor32(); lowColor = cl->fLayerData->lowcolor.GetColor32(); viewColor = cl->fLayerData->viewcolor.GetColor32(); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(&highColor, sizeof(rgb_color)); fMsgSender->Attach(&lowColor, sizeof(rgb_color)); fMsgSender->Attach(&viewColor, sizeof(rgb_color)); fMsgSender->Flush(); break; } case AS_LAYER_SET_BLEND_MODE: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_BLEND_MODE: Layer: %s\n",fTitle.String(), cl->fName->String())); int8 srcAlpha, alphaFunc; link.Read(&srcAlpha); link.Read(&alphaFunc); cl->fLayerData->alphaSrcMode = (source_alpha)srcAlpha; cl->fLayerData->alphaFncMode = (alpha_function)alphaFunc; break; } case AS_LAYER_GET_BLEND_MODE: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_BLEND_MODE: Layer: %s\n",fTitle.String(), cl->fName->String())); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach((int8)(cl->fLayerData->alphaSrcMode)); fMsgSender->Attach((int8)(cl->fLayerData->alphaFncMode)); fMsgSender->Flush(); break; } case AS_LAYER_SET_DRAW_MODE: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_DRAW_MODE: Layer: %s\n",fTitle.String(), cl->fName->String())); int8 drawingMode; link.Read(&drawingMode); cl->fLayerData->draw_mode = (drawing_mode)drawingMode; break; } case AS_LAYER_GET_DRAW_MODE: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_DRAW_MODE: Layer: %s\n",fTitle.String(), cl->fName->String())); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach((int8)(cl->fLayerData->draw_mode)); fMsgSender->Flush(); break; } case AS_LAYER_PRINT_ALIASING: { DTRACE(("ServerWindow %s: Message AS_LAYER_PRINT_ALIASING: Layer: %s\n",fTitle.String(), cl->fName->String())); link.Read(&(cl->fLayerData->fontAliasing)); break; } case AS_LAYER_CLIP_TO_PICTURE: { DTRACE(("ServerWindow %s: Message AS_LAYER_CLIP_TO_PICTURE: Layer: %s\n",fTitle.String(), cl->fName->String())); // TODO: you are not allowed to use Layer regions here!!! // If there is no other way, then first lock RootLayer object first. // TODO: Watch out for the coordinate system in AS_LAYER_CLIP_TO_PICTURE int32 pictureToken; BPoint where; link.Read(&pictureToken); link.Read(&where); BRegion reg; bool redraw = false; // if we had a picture to clip to, include the FULL visible region(if any) in the area to be redrawn // in other words: invalidate what ever is visible for this layer and his children. if (cl->clipToPicture && cl->fFullVisible.CountRects() > 0) { reg.Include(&cl->fFullVisible); redraw = true; } // search for a picture with the specified token. ServerPicture *sp = NULL; int32 i = 0; while(1) { sp=static_cast(cl->fServerWin->fServerApp->fPictureList->ItemAt(i++)); if (!sp) break; if(sp->GetToken() == pictureToken) { //cl->clipToPicture = sp; // TODO: Increase that picture's reference count.(~ allocate a picture) break; } } // avoid compiler warning i = 0; // we have a new picture to clip to, so rebuild our full region if(cl->clipToPicture) { cl->clipToPictureInverse = false; cl->RebuildFullRegion(); } // we need to rebuild the visible region, we may have a valid one. if (cl->fParent && !(cl->fHidden)) { //cl->fParent->RebuildChildRegions(cl->fFull.Frame(), cl); } else { // will this happen? Maybe... //cl->RebuildRegions(cl->fFull.Frame()); } // include our full visible region in the region to be redrawn if (!(cl->fHidden) && (cl->fFullVisible.CountRects() > 0)) { reg.Include(&(cl->fFullVisible)); redraw = true; } // redraw if we previously had or if we have acquired a picture to clip to. if (redraw) myRootLayer->GoRedraw(cl, reg); break; } case AS_LAYER_CLIP_TO_INVERSE_PICTURE: { DTRACE(("ServerWindow %s: Message AS_LAYER_CLIP_TO_INVERSE_PICTURE: Layer: %s\n",fTitle.String(), cl->fName->String())); // TODO: Watch out for the coordinate system in AS_LAYER_CLIP_TO_INVERSE_PICTURE int32 pictureToken; BPoint where; link.Read(&pictureToken); link.Read(&where); ServerPicture *sp = NULL; int32 i = 0; while(1) { sp= static_cast(cl->fServerWin->fServerApp->fPictureList->ItemAt(i++)); if (!sp) break; if(sp->GetToken() == pictureToken) { //cl->clipToPicture = sp; // TODO: Increase that picture's reference count.(~ allocate a picture) break; } } // avoid compiler warning i = 0; // if a picture has been found... if(cl->clipToPicture) { cl->clipToPictureInverse = true; cl->RebuildFullRegion(); //cl->RequestDraw(cl->clipToPicture->Frame()); } break; } case AS_LAYER_GET_CLIP_REGION: { DTRACE(("ServerWindow %s: Message AS_LAYER_GET_CLIP_REGION: Layer: %s\n",fTitle.String(), cl->fName->String())); // if this Layer is hidden, it is clear that its visible region is void. if (cl->IsHidden()) { fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(0L); fMsgSender->Flush(); } else { // TODO: Watch out for the coordinate system in AS_LAYER_GET_CLIP_REGION BRegion reg; LayerData *ld; int32 noOfRects; ld = cl->fLayerData; reg = cl->ConvertFromParent(&(cl->fVisible)); if(ld->clipReg) reg.IntersectWith(ld->clipReg); while((ld = ld->prevState)) { if(ld->clipReg) reg.IntersectWith(ld->clipReg); } noOfRects = reg.CountRects(); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Attach(noOfRects); for(int i = 0; i < noOfRects; i++) fMsgSender->Attach(reg.RectAt(i)); } break; } case AS_LAYER_SET_CLIP_REGION: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_CLIP_REGION: Layer: %s\n",fTitle.String(), cl->fName->String())); // TODO: Watch out for the coordinate system in AS_LAYER_SET_CLIP_REGION int32 noOfRects; BRect r; if(cl->fLayerData->clipReg) cl->fLayerData->clipReg->MakeEmpty(); else cl->fLayerData->clipReg = new BRegion(); link.Read(&noOfRects); for(int i = 0; i < noOfRects; i++) { link.Read(&r); cl->fLayerData->clipReg->Include(r); } cl->RebuildFullRegion(); if (!(cl->IsHidden())) myRootLayer->GoInvalidate(cl, cl->fFull); break; } case AS_LAYER_INVAL_RECT: { DTRACE(("ServerWindow %s: Message AS_LAYER_INVAL_RECT: Layer: %s\n",fTitle.String(), cl->fName->String())); // TODO: Watch out for the coordinate system in AS_LAYER_INVAL_RECT BRect invalRect; link.Read(&invalRect); myRootLayer->GoRedraw(cl, BRegion(invalRect)); break; } case AS_LAYER_INVAL_REGION: { DTRACE(("ServerWindow %s: Message AS_LAYER_INVAL_RECT: Layer: %s\n",fTitle.String(), cl->fName->String())); // TODO: Watch out for the coordinate system AS_LAYER_INVAL_REGION BRegion invalReg; int32 noOfRects; BRect rect; link.Read(&noOfRects); for(int i = 0; i < noOfRects; i++) { link.Read(&rect); invalReg.Include(rect); } myRootLayer->GoRedraw(cl, invalReg); break; } case AS_BEGIN_UPDATE: { DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n",fTitle.String())); cl->UpdateStart(); break; } case AS_END_UPDATE: { DTRACE(("ServerWindowo %s: AS_END_UPDATE\n",fTitle.String())); cl->UpdateEnd(); break; } // ********** END: BView Messages *********** // ********* BWindow Messages *********** case AS_LAYER_DELETE_ROOT: { // Received when a window deletes its internal top view // TODO: Implement AS_LAYER_DELETE_ROOT STRACE(("ServerWindow %s: Message Delete_Layer_Root unimplemented\n",fTitle.String())); break; } case AS_SHOW_WINDOW: { STRACE(("ServerWindow %s: Message AS_SHOW_WINDOW\n",fTitle.String())); Show(); break; } case AS_HIDE_WINDOW: { STRACE(("ServerWindow %s: Message AS_HIDE_WINDOW\n",fTitle.String())); Hide(); break; } case AS_SEND_BEHIND: { // TODO: Implement AS_SEND_BEHIND STRACE(("ServerWindow %s: Message Send_Behind unimplemented\n",fTitle.String())); break; } case AS_ENABLE_UPDATES: { // TODO: Implement AS_ENABLE_UPDATES STRACE(("ServerWindow %s: Message Enable_Updates unimplemented\n",fTitle.String())); break; } case AS_DISABLE_UPDATES: { // TODO: Implement AS_DISABLE_UPDATES STRACE(("ServerWindow %s: Message Disable_Updates unimplemented\n",fTitle.String())); break; } case AS_NEEDS_UPDATE: { // TODO: Implement AS_NEEDS_UPDATE STRACE(("ServerWindow %s: Message Needs_Update unimplemented\n",fTitle.String())); break; } case AS_WINDOW_TITLE: { // TODO: Implement AS_WINDOW_TITLE STRACE(("ServerWindow %s: Message Set_Title unimplemented\n",fTitle.String())); break; } case AS_ADD_TO_SUBSET: { STRACE(("ServerWindow %s: Message AS_ADD_TO_SUBSET\n",fTitle.String())); WinBorder *wb; int32 mainToken; team_id teamID; link.Read(&mainToken); link.Read(&teamID, sizeof(team_id)); wb = desktop->FindWinBorderByServerWindowTokenAndTeamID(mainToken, teamID); if(wb) { fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Flush(); BPortLink msg(-1, -1); msg.StartMessage(AS_ROOTLAYER_ADD_TO_SUBSET); msg.Attach(fWinBorder); msg.Attach(wb); fWinBorder->GetRootLayer()->EnqueueMessage(msg); } else { fMsgSender->StartMessage(SERVER_FALSE); fMsgSender->Flush(); } break; } case AS_REM_FROM_SUBSET: { STRACE(("ServerWindow %s: Message AS_REM_FROM_SUBSET\n",fTitle.String())); WinBorder *wb; int32 mainToken; team_id teamID; link.Read(&mainToken); link.Read(&teamID, sizeof(team_id)); wb = desktop->FindWinBorderByServerWindowTokenAndTeamID(mainToken, teamID); if(wb) { fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Flush(); BPortLink msg(-1, -1); msg.StartMessage(AS_ROOTLAYER_REMOVE_FROM_SUBSET); msg.Attach(fWinBorder); msg.Attach(wb); fWinBorder->GetRootLayer()->EnqueueMessage(msg); } else { fMsgSender->StartMessage(SERVER_FALSE); fMsgSender->Flush(); } break; } case AS_SET_LOOK: { // TODO: Implement AS_SET_LOOK STRACE(("ServerWindow %s: Message Set_Look unimplemented\n",fTitle.String())); break; } case AS_SET_FLAGS: { // TODO: Implement AS_SET_FLAGS STRACE(("ServerWindow %s: Message Set_Flags unimplemented\n",fTitle.String())); break; } case AS_SET_FEEL: { // TODO: Implement AS_SET_FEEL STRACE(("ServerWindow %s: Message Set_Feel unimplemented\n",fTitle.String())); break; } case AS_SET_ALIGNMENT: { // TODO: Implement AS_SET_ALIGNMENT STRACE(("ServerWindow %s: Message Set_Alignment unimplemented\n",fTitle.String())); break; } case AS_GET_ALIGNMENT: { // TODO: Implement AS_GET_ALIGNMENT STRACE(("ServerWindow %s: Message Get_Alignment unimplemented\n",fTitle.String())); break; } case AS_GET_WORKSPACES: { // TODO: Implement AS_GET_WORKSPACES STRACE(("ServerWindow %s: Message Get_Workspaces unimplemented\n",fTitle.String())); break; } case AS_SET_WORKSPACES: { // TODO: Implement AS_SET_WORKSPACES STRACE(("ServerWindow %s: Message Set_Workspaces unimplemented\n",fTitle.String())); break; } case AS_WINDOW_RESIZE: { STRACE(("ServerWindow %s: Message AS_WINDOW_RESIZE\n",fTitle.String())); float xResizeBy; float yResizeBy; link.Read(&xResizeBy); link.Read(&yResizeBy); fWinBorder->ResizeBy(xResizeBy, yResizeBy); break; } case AS_WINDOW_MOVE: { STRACE(("ServerWindow %s: Message AS_WINDOW_MOVE\n",fTitle.String())); float xMoveBy; float yMoveBy; link.Read(&xMoveBy); link.Read(&yMoveBy); fWinBorder->MoveBy(xMoveBy, yMoveBy); break; } case AS_SET_SIZE_LIMITS: { // Attached Data: // 1) float minimum width // 2) float maximum width // 3) float minimum height // 4) float maximum height float wmin,wmax,hmin,hmax; link.Read(&wmin); link.Read(&wmax); link.Read(&hmin); link.Read(&hmax); fWinBorder->SetSizeLimits(wmin,wmax,hmin,hmax); fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Flush(); break; } case B_MINIMIZE: { // TODO: Implement B_MINIMIZE STRACE(("ServerWindow %s: Message Minimize unimplemented\n",fTitle.String())); break; } case B_WINDOW_ACTIVATED: { // TODO: Implement B_WINDOW_ACTIVATED STRACE(("ServerWindow %s: Message Window_Activated unimplemented\n",fTitle.String())); break; } case B_ZOOM: { // TODO: Implement B_ZOOM STRACE(("ServerWindow %s: Message Zoom unimplemented\n",fTitle.String())); break; } // -------------------- Graphics messages ---------------------------------- case AS_LAYER_SET_HIGH_COLOR: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_HIGH_COLOR: Layer: %s\n",fTitle.String(), cl->fName->String())); rgb_color c; link.Read(&c, sizeof(rgb_color)); cl->fLayerData->highcolor.SetColor(c); break; } case AS_LAYER_SET_LOW_COLOR: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LOW_COLOR: Layer: %s\n",fTitle.String(), cl->fName->String())); rgb_color c; link.Read(&c, sizeof(rgb_color)); cl->fLayerData->lowcolor.SetColor(c); break; } case AS_LAYER_SET_PATTERN: { DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PATTERN: Layer: %s\n", fTitle.String(), cl->fName->String())); pattern pat; link.Read(&pat, sizeof(pattern)); cl->fLayerData->patt = pat; break; } case AS_STROKE_LINE: { DTRACE(("ServerWindow %s: Message AS_STROKE_LINE\n",fTitle.String())); // TODO: Add clipping TO AS_STROKE_LINE float x1, y1, x2, y2; link.Read(&x1); link.Read(&y1); link.Read(&x2); link.Read(&y2); if (cl && cl->fLayerData) { BPoint p1(x1,y1); BPoint p2(x2,y2); desktop->GetDisplayDriver()->StrokeLine(cl->ConvertToTop(p1),cl->ConvertToTop(p2), cl->fLayerData); // We update the pen here because many DisplayDriver calls which do not update the // pen position actually call StrokeLine cl->fLayerData->penlocation=p2; } break; } case AS_LAYER_INVERT_RECT: { DTRACE(("ServerWindow %s: Message AS_INVERT_RECT\n",fTitle.String())); // TODO: Add clipping TO AS_INVERT_RECT BRect rect; link.Read(&rect); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->InvertRect(cl->ConvertToTop(rect)); break; } case AS_STROKE_RECT: { DTRACE(("ServerWindow %s: Message AS_STROKE_RECT\n",fTitle.String())); // TODO: Add clipping TO AS_STROKE_RECT float left, top, right, bottom; link.Read(&left); link.Read(&top); link.Read(&right); link.Read(&bottom); BRect rect(left,top,right,bottom); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->StrokeRect(cl->ConvertToTop(rect),cl->fLayerData); break; } case AS_FILL_RECT: { DTRACE(("ServerWindow %s: Message AS_FILL_RECT\n",fTitle.String())); // TODO: Add clipping TO AS_FILL_RECT BRect rect; link.Read(&rect); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->FillRect(cl->ConvertToTop(rect),cl->fLayerData); break; } case AS_STROKE_ARC: { DTRACE(("ServerWindow %s: Message AS_STROKE_ARC\n",fTitle.String())); // TODO: Add clipping to AS_STROKE_ARC float angle, span; BRect r; link.Read(&r); link.Read(&angle); link.Read(&span); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->StrokeArc(cl->ConvertToTop(r),angle,span,cl->fLayerData); break; } case AS_FILL_ARC: { DTRACE(("ServerWindow %s: Message AS_FILL_ARC\n",fTitle.String())); // TODO: Add clipping to AS_FILL_ARC float angle, span; BRect r; link.Read(&r); link.Read(&angle); link.Read(&span); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->FillArc(cl->ConvertToTop(r),angle,span,cl->fLayerData); break; } case AS_STROKE_BEZIER: { DTRACE(("ServerWindow %s: Message AS_STROKE_BEZIER\n",fTitle.String())); // TODO: Add clipping to AS_STROKE_BEZIER BPoint *pts; int i; pts = new BPoint[4]; for (i=0; i<4; i++) link.Read(&(pts[i])); if (cl && cl->fLayerData) { for (i=0; i<4; i++) pts[i]=cl->ConvertToTop(pts[i]); desktop->GetDisplayDriver()->StrokeBezier(pts,cl->fLayerData); } delete [] pts; break; } case AS_FILL_BEZIER: { DTRACE(("ServerWindow %s: Message AS_FILL_BEZIER\n",fTitle.String())); // TODO: Add clipping to AS_STROKE_BEZIER BPoint *pts; int i; pts = new BPoint[4]; for (i=0; i<4; i++) link.Read(&(pts[i])); if (cl && cl->fLayerData) { for (i=0; i<4; i++) pts[i]=cl->ConvertToTop(pts[i]); desktop->GetDisplayDriver()->FillBezier(pts,cl->fLayerData); } delete [] pts; break; } case AS_STROKE_ELLIPSE: { DTRACE(("ServerWindow %s: Message AS_STROKE_ELLIPSE\n",fTitle.String())); // TODO: Add clipping AS_STROKE_ELLIPSE BRect rect; link.Read(&rect); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->StrokeEllipse(cl->ConvertToTop(rect),cl->fLayerData); break; } case AS_FILL_ELLIPSE: { DTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE\n",fTitle.String())); // TODO: Add clipping AS_STROKE_ELLIPSE BRect rect; link.Read(&rect); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->FillEllipse(cl->ConvertToTop(rect),cl->fLayerData); break; } case AS_STROKE_ROUNDRECT: { DTRACE(("ServerWindow %s: Message AS_STROKE_ROUNDRECT\n",fTitle.String())); // TODO: Add clipping AS_STROKE_ROUNDRECT BRect rect; float xrad,yrad; link.Read(&rect); link.Read(&xrad); link.Read(&yrad); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->StrokeRoundRect(cl->ConvertToTop(rect),xrad,yrad,cl->fLayerData); break; } case AS_FILL_ROUNDRECT: { DTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT\n",fTitle.String())); // TODO: Add clipping AS_STROKE_ROUNDRECT BRect rect; float xrad,yrad; link.Read(&rect); link.Read(&xrad); link.Read(&yrad); if (cl && cl->fLayerData) desktop->GetDisplayDriver()->FillRoundRect(cl->ConvertToTop(rect),xrad,yrad,cl->fLayerData); break; } case AS_STROKE_TRIANGLE: { DTRACE(("ServerWindow %s: Message AS_STROKE_TRIANGLE\n",fTitle.String())); // TODO:: Add clipping to AS_STROKE_TRIANGLE BPoint pts[3]; BRect rect; for (int i=0; i<3; i++) link.Read(&(pts[i])); link.Read(&rect); if (cl && cl->fLayerData) { for(int i=0;i<3;i++) pts[i]=cl->ConvertToTop(pts[i]); desktop->GetDisplayDriver()->StrokeTriangle(pts,cl->ConvertToTop(rect),cl->fLayerData); } break; } case AS_FILL_TRIANGLE: { DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE\n",fTitle.String())); // TODO:: Add clipping to AS_FILL_TRIANGLE BPoint pts[3]; BRect rect; for (int i=0; i<3; i++) link.Read(&(pts[i])); link.Read(&rect); if (cl && cl->fLayerData) { for(int i=0;i<3;i++) pts[i]=cl->ConvertToTop(pts[i]); desktop->GetDisplayDriver()->FillTriangle(pts,cl->ConvertToTop(rect),cl->fLayerData); } break; } case AS_STROKE_POLYGON: { DTRACE(("ServerWindow %s: Message AS_STROKE_POLYGON\n",fTitle.String())); BRect polyframe; bool isclosed; int32 pointcount; BPoint *pointlist; link.Read(&polyframe); link.Read(&isclosed); link.Read(&pointcount); pointlist=new BPoint[pointcount]; link.Read(pointlist, sizeof(BPoint)*pointcount); for(int32 i=0; iConvertToTop(pointlist[i]); desktop->GetDisplayDriver()->StrokePolygon(pointlist,pointcount,polyframe, cl->fLayerData,isclosed); delete [] pointlist; break; } case AS_FILL_POLYGON: { DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON\n",fTitle.String())); BRect polyframe; int32 pointcount; BPoint *pointlist; link.Read(&polyframe); link.Read(&pointcount); pointlist=new BPoint[pointcount]; link.Read(pointlist, sizeof(BPoint)*pointcount); for(int32 i=0; iConvertToTop(pointlist[i]); desktop->GetDisplayDriver()->FillPolygon(pointlist,pointcount,polyframe,cl->fLayerData); delete [] pointlist; break; } case AS_STROKE_SHAPE: { DTRACE(("ServerWindow %s: Message AS_STROKE_SHAPE\n",fTitle.String())); BRect shaperect; int32 opcount; int32 ptcount; int32 *oplist; BPoint *ptlist; link.Read(&shaperect); link.Read(&opcount); link.Read(&ptcount); oplist=new int32[opcount]; ptlist=new BPoint[ptcount]; link.Read(oplist,sizeof(int32)*opcount); link.Read(ptlist,sizeof(BPoint)*ptcount); for(int32 i=0; iConvertToTop(ptlist[i]); desktop->GetDisplayDriver()->StrokeShape(shaperect, opcount, oplist, ptcount, ptlist, cl->fLayerData); delete oplist; delete ptlist; break; } case AS_FILL_SHAPE: { DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE\n",fTitle.String())); BRect shaperect; int32 opcount; int32 ptcount; int32 *oplist; BPoint *ptlist; link.Read(&shaperect); link.Read(&opcount); link.Read(&ptcount); oplist=new int32[opcount]; ptlist=new BPoint[ptcount]; link.Read(oplist,sizeof(int32)*opcount); link.Read(ptlist,sizeof(BPoint)*ptcount); for(int32 i=0; iConvertToTop(ptlist[i]); desktop->GetDisplayDriver()->FillShape(shaperect, opcount, oplist, ptcount, ptlist, cl->fLayerData); delete oplist; delete ptlist; break; } case AS_FILL_REGION: { DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n",fTitle.String())); int32 rectcount; BRect *rectlist; link.Read(&rectcount); rectlist=new BRect[rectcount]; link.Read(rectlist, sizeof(BRect)*rectcount); // Between the client-side conversion to BRects from clipping_rects to the overhead // in repeatedly calling FillRect(), this is definitely in need of optimization. At // least it works for now. :) for(int32 i=0; iGetDisplayDriver()->FillRect(cl->ConvertToTop(rectlist[i]),cl->fLayerData); delete [] rectlist; // TODO: create support for clipping_rect usage for faster BRegion display. // Tweaks to DisplayDriver are necessary along with conversion routines in Layer break; } case AS_STROKE_LINEARRAY: { DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n",fTitle.String())); // Attached Data: // 1) int32 Number of lines in the array // 2) array of struct _array_data_ objects, as defined in ViewAux.h int32 linecount; link.Read(&linecount); if(linecount>0) { LineArrayData linedata[linecount], *index; for(int32 i=0; i(&(index->pt1.x)); link.Read(&(index->pt1.y)); link.Read(&(index->pt2.x)); link.Read(&(index->pt2.y)); link.Read(&(index->color)); index->pt1=cl->ConvertToTop(index->pt1); index->pt2=cl->ConvertToTop(index->pt2); } desktop->GetDisplayDriver()->StrokeLineArray(linecount,linedata,cl->fLayerData); } break; } case AS_DRAW_STRING: { DTRACE(("ServerWindow %s: Message AS_DRAW_STRING\n",fTitle.String())); char *string; int32 length; BPoint location; escapement_delta delta; link.Read(&length); link.Read(&location); link.Read(&delta); link.ReadString(&string); if(cl && cl->fLayerData) desktop->GetDisplayDriver()->DrawString(string,length,cl->ConvertToTop(location), cl->fLayerData); free(string); break; } case AS_MOVEPENTO: { DTRACE(("ServerWindow %s: Message AS_MOVEPENTO\n",fTitle.String())); float x,y; link.Read(&x); link.Read(&y); if(cl && cl->fLayerData) cl->fLayerData->penlocation.Set(x,y); break; } case AS_SETPENSIZE: { DTRACE(("ServerWindow %s: Message AS_SETPENSIZE\n",fTitle.String())); float size; link.Read(&size); if(cl && cl->fLayerData) cl->fLayerData->pensize=size; break; } case AS_SET_FONT: { DTRACE(("ServerWindow %s: Message AS_SET_FONT\n",fTitle.String())); // TODO: Implement AS_SET_FONT? break; } case AS_SET_FONT_SIZE: { DTRACE(("ServerWindow %s: Message AS_SET_FONT_SIZE\n",fTitle.String())); // TODO: Implement AS_SET_FONT_SIZE? break; } case AS_AREA_MESSAGE: { STRACE(("ServerWindow %s: Message AS_AREA_MESSAGE\n",fTitle.String())); // This occurs in only one kind of case: a message is too big to send over a port. This // is really an edge case, so this shouldn't happen *too* often // Attached Data: // 1) area_id id of an area already owned by the server containing the message // 2) size_t offset of the pointer in the area // 3) size_t size of the message area_id area; size_t offset; size_t msgsize; area_info ai; int8 *msgpointer; link.Read(&area); link.Read(&offset); link.Read(&msgsize); // Part sanity check, part get base pointer :) if(get_area_info(area,&ai)!=B_OK) break; msgpointer=(int8*)ai.address + offset; RAMLinkMsgReader mlink(msgpointer); DispatchMessage(mlink.Code(),mlink); // This is a very special case in the sense that when ServerMemIO is used for this // purpose, it will be set to NOT automatically free the memory which it had // requested. This is the server's job once the message has been dispatched. fServerApp->fSharedMem->ReleaseBuffer(msgpointer); break; } case AS_SYNC: { // TODO: AS_SYNC is a no-op for now, just to get things working fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Flush(); break; } case AS_LAYER_DRAG_IMAGE: { // TODO: Implement AS_LAYER_DRAG_IMAGE STRACE(("ServerWindow %s: Message AS_DRAG_IMAGE unimplemented\n",fTitle.String())); DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE unimplemented\n",fTitle.String())); break; } case AS_LAYER_DRAG_RECT: { // TODO: Implement AS_LAYER_DRAG_RECT STRACE(("ServerWindow %s: Message AS_DRAG_RECT unimplemented\n",fTitle.String())); DTRACE(("ServerWindow %s: Message AS_DRAG_RECT unimplemented\n",fTitle.String())); break; } case AS_LAYER_GET_MOUSE_COORDS: { DTRACE(("ServerWindow %s: Message AS_GET_MOUSE_COORDS\n",fTitle.String())); // Attached Data: // 1) port_id reply port // Returns // 1) BPoint mouse location // 2) int32 button state // For now, it's unimplemented, but this is a synchronous call, so to prevent debugging of // applications which make this call, we'll reply with a SERVER_FALSE until it is implemeneted port_id replyport; link.Read(&replyport); int32 buttons=desktop->ActiveRootLayer()->Buttons(); BPortLink replylink(replyport); replylink.StartMessage(SERVER_TRUE); replylink.Attach(desktop->GetDisplayDriver()->GetCursorPosition()); replylink.Attach(buttons); replylink.Flush(); break; } default: { printf("ServerWindow %s received unexpected code - message offset %ld\n",fTitle.String(), code - SERVER_TRUE); break; } } } //------------------------------------------------------------------------------ /*! \brief Message-dispatching loop for the ServerWindow MonitorWin() watches the ServerWindow's message port and dispatches as necessary \param data The thread's ServerWindow \return Throwaway code. Always 0. */ int32 ServerWindow::MonitorWin(void *data) { ServerWindow *win = (ServerWindow *)data; LinkMsgReader *ses = win->fMsgReader; bool quitting = false; int32 code; status_t err = B_OK; while(!quitting) { // printf("info: ServerWindow::MonitorWin listening on port %ld.\n", win->fMessagePort); code = AS_CLIENT_DEAD; err = ses->GetNextMessage(&code); if (err < B_OK) return err; win->Lock(); switch(code) { case AS_DELETE_WINDOW: case AS_CLIENT_DEAD: { // this means the client has been killed STRACE(("ServerWindow %s received 'AS_CLIENT_DEAD/AS_DELETE_WINDOW' message code\n",win->Title())); // RootLayer *myRootLayer = win->fWinBorder->GetRootLayer(); // quitting = true; // we are preparing to delete a ServerWindow, RootLayer should be aware // of that and stop for a moment. // also we must wait a bit for the associated WinBorder to become hidden // while(1) // { // myRootLayer->Lock(); // if (win->IsHidden()) // break; // else // myRootLayer->Unlock(); // } // ServerWindow's destructor takes care of pulling this object off the desktop. if (!win->IsHidden()) debugger("ServerWindow: a window must be hidden before it's deleted\n"); delete win; // myRootLayer->Unlock(); exit_thread(0); break; } case B_QUIT_REQUESTED: { STRACE(("ServerWindow %s received Quit request\n",win->Title())); win->Quit(); break; } default: { win->DispatchMessage(code, *ses); break; } } win->Unlock(); } return err; } //------------------------------------------------------------------------------ Layer* ServerWindow::FindLayer(const Layer* start, int32 token) const { if (!IsLocked()) debugger("you must lock a ServerWindow object before calling ::FindLayer()\n"); if(!start) return NULL; // see if we're looking for 'start' if(start->fViewToken == token) return const_cast(start); Layer *c = start->fTopChild; //c = short for: current if(c != NULL) while(true) { // action block { if(c->fViewToken == token) return c; } // go deep if( c->fTopChild) { c = c->fTopChild; } // go right or up else // go right if(c->fLowerSibling) { c = c->fLowerSibling; } // go up else { while(!c->fParent->fLowerSibling && c->fParent != start) { c = c->fParent; } // that enough! We've reached the start layer. if(c->fParent == start) break; c = c->fParent->fLowerSibling; } } return NULL; } //------------------------------------------------------------------------------ void ServerWindow::SendMessageToClient(const BMessage* msg, int32 target, bool usePreferred) const { ssize_t size; char *buffer; size = msg->FlattenedSize(); buffer = new char[size]; if (msg->Flatten(buffer, size) == B_OK) BMessage::Private::SendFlattenedMessage(buffer, size, fClientLooperPort, target, usePreferred, B_INFINITE_TIMEOUT); else printf("PANIC: ServerWindow %s: can't flatten message in 'SendMessageToClient()'\n", fTitle.String()); delete [] buffer; } //------------------------------------------------------------------------------