//------------------------------------------------------------------------------ // 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: DirectDriver.h // Author: DarkWyrm // // Description: BDirectWindow graphics module // //------------------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Angle.h" #include "PortLink.h" #include "RectUtils.h" #include "ServerProtocol.h" #include "ServerBitmap.h" #include "DirectDriver.h" #include "ServerConfig.h" #include "ServerCursor.h" #include "ServerFont.h" #include "FontFamily.h" #include "LayerData.h" #include "PNGDump.h" //#define DEBUG_DRIVER_ALL #ifdef DEBUG_DRIVER_ALL # include # define ATRACE(x) printf x # define STRACE(x) printf x # define DTRACE(x) printf x #else # define ATRACE(x) ; #endif //#define DEBUG_DRIVER_MODULE #ifdef DEBUG_DRIVER_MODULE # include # define STRACE(x) printf x #else # ifndef STRACE # define STRACE(x) ; # endif #endif //#define DEBUG_DRIVER_THREAD #ifdef DEBUG_DRIVER_THREAD # include # define DTRACE(x) printf x #else # ifndef DTRACE # define DTRACE(x) ; # endif #endif extern RGBColor workspace_default_color; /* --------------------------------------------------------------------------------------- DW's NOTES: The current state of the driver still operates somewhat like ViewDriver in that it still uses the app_server to draw on the BBitmap. The advantage to this temporary state is that the driver can be quickly taken from not-at-all-working to works-but- still-needs-work. Code which uses the R5 server can be replaced with code which directly manipulates the buffer one function at a time for an even greater speed boost. Simply not using DrawBitmap() to display the framebuffer will allow for a speed gain by a couple orders of magnitude --------------------------------------------------------------------------------------- */ DirectDriver::DirectDriver() : DisplayDriverImpl() { ATRACE(("DirectDriver::DirectDriver\n")); screenwin=NULL; ATRACE(("\tCreating framebuffer bitmap\n")); framebuffer=new BBitmap(BRect(0,0,639,479),B_RGB32,true); ATRACE(("\tCreating child view for framebuffer\n")); drawview=new BView(framebuffer->Bounds(),"drawview",0,0); framebuffer->AddChild(drawview); BScreen screen; screen.GetMode(&fCurrentScreenMode); ATRACE(("\tCurrent Mode:%u x %u\n",fCurrentScreenMode.virtual_width,fCurrentScreenMode.virtual_height)); // We'll save this so that if we change the bit depth of the screen, we // can change it back when the driver is shut down. fSavedScreenMode=fCurrentScreenMode; #ifdef ENABLE_INPUT_SERVER_EMULATION port_id serverInputPort = create_port(200, SERVER_INPUT_PORT); if (serverInputPort == B_NO_MORE_PORTS) { debugger("DirectDriver: out of ports\n"); return; } #endif } DirectDriver::~DirectDriver() { ATRACE(("DirectDriver::~DirectDriver\n")); Lock(); ATRACE(("\tDeleting the framebuffer\n")); delete framebuffer; screenwin->framebuffer=NULL; Unlock(); } bool DirectDriver::Initialize() { if (DisplayDriver::Initialize()) { ATRACE(("DirectDriver::Initialize\n")); screenwin=new DDWindow(640,480,B_RGB32,this); while(find_thread("drawing_thread")==B_NAME_NOT_FOUND) { ATRACE(("\tWaiting for the drawing thread to spawn\n")); snooze(100); } return true; } return false; } void DirectDriver::Shutdown() { DisplayDriver::Shutdown(); ATRACE(("DirectDriver::Shutdown\n")); screenwin->PostMessage(B_QUIT_REQUESTED); if(fSavedScreenMode.space!=fCurrentScreenMode.space) BScreen().SetMode(&fSavedScreenMode); } /* void DirectDriver::DrawBitmap(ServerBitmap *bmp, const BRect &src, const BRect &dest, const DrawData *d) { STRACE(("DirectDriver::DrawBitmap\n")); if(!bmp || !d) { printf("CopyBitmap returned - not init or NULL bitmap\n"); return; } SetDrawData(d); // Oh, wow, is this going to be slow. Gotta write the real DrawBitmap code sometime... BBitmap *mediator=new BBitmap(bmp->Bounds(),bmp->ColorSpace()); memcpy(mediator->Bits(),bmp->Bits(),bmp->BitsLength()); Lock(); framebuffer->Lock(); drawview->DrawBitmap(mediator,src,dest); drawview->Sync(); framebuffer->Unlock(); screenwin->rectpipe.PutRect(dest); Unlock(); delete mediator; }*/ void DirectDriver::InvertRect(const BRect &r) { STRACE(("DirectDriver::InvertRect\n")); // Shamelessly stolen from AccelerantDriver.cpp Lock(); switch (framebuffer->ColorSpace()) { case B_RGB32_BIG: case B_RGBA32_BIG: case B_RGB32_LITTLE: case B_RGBA32_LITTLE: { uint16 width=r.IntegerWidth(); uint16 height=r.IntegerHeight(); uint32 *start=(uint32*)framebuffer->Bits(); uint32 *index; start = (uint32 *)((uint8 *)start+(int32)r.top*framebuffer->BytesPerRow()); start+=(int32)r.left; index = start; for(int32 i=0;iBytesPerRow()); } } break; case B_RGB16_BIG: case B_RGB16_LITTLE: { uint16 width=r.IntegerWidth(); uint16 height=r.IntegerHeight(); uint16 *start=(uint16*)framebuffer->Bits(); uint16 *index; start = (uint16 *)((uint8 *)start+(int32)r.top*framebuffer->BytesPerRow()); start+=(int32)r.left; index = start; for(int32 i=0;iBytesPerRow()); } } break; case B_RGB15_BIG: case B_RGBA15_BIG: case B_RGB15_LITTLE: case B_RGBA15_LITTLE: { uint16 width=r.IntegerWidth(); uint16 height=r.IntegerHeight(); uint16 *start=(uint16*)framebuffer->Bits(); uint16 *index; start = (uint16 *)((uint8 *)start+(int32)r.top*framebuffer->BytesPerRow()); start+=(int32)r.left; index = start; for(int32 i=0;iBytesPerRow()); } } break; case B_CMAP8: case B_GRAY8: { uint16 width=r.IntegerWidth(); uint16 height=r.IntegerHeight(); uint8 *start=(uint8*)framebuffer->Bits(); uint8 *index; start = (uint8 *)start+(int32)r.top*framebuffer->BytesPerRow(); start+=(int32)r.left; index = start; for(int32 i=0;iBytesPerRow(); } } break; default: break; } Unlock(); } void DirectDriver::StrokeLineArray(const int32 &numlines, const LineArrayData *linedata, const DrawData *d) { STRACE(("DirectDriver::StrokeLineArray\n")); if( !numlines || !linedata || !d) return; const LineArrayData *data; Lock(); framebuffer->Lock(); drawview->SetPenSize(d->pensize); drawview->SetDrawingMode(d->draw_mode); drawview->BeginLineArray(numlines); for(int32 i=0; iAddLine(data->pt1,data->pt2,data->color); } drawview->EndLineArray(); drawview->Sync(); screenwin->rectpipe.PutRect(framebuffer->Bounds()); framebuffer->Unlock(); Unlock(); } void DirectDriver::SetMode(const display_mode &mode) { STRACE(("DirectDriver::SetMode(%u x %u)\n",mode.virtual_width,mode.virtual_height)); Lock(); // Supports all modes all modes >= 640x480 and < supported resolutions in // all supported color depths // Because we don't support modes with the same height and different widths, we can // use the height to determine what we're going to do. if(mode.virtual_height>fCurrentScreenMode.virtual_height) { STRACE(("DirectDriver::SetMode: height requested greater than current screen height\n")); Unlock(); return; } switch(mode.virtual_height) { // These mode heights are kosher, so filter out any others case 400: case 480: case 600: case 768: case 864: case 1024: case 1200: break; default: STRACE(("DirectDriver::SetMode:invalid mode height\n")); Unlock(); return; } // If we're running in a really crappy resolution, allow the user to set the mode // to full-screen non-exclusive mode. if(fCurrentScreenMode.virtual_height>480 && mode.virtual_height==fCurrentScreenMode.virtual_height) { STRACE(("DirectDriver::SetMode: height requested equal to current screen height " "and greater than 640x480\n")); Unlock(); return; } // We got this far, so apparently the mode requested is smaller than the current screen's // mode OR is one of our two exceptions, so now we check for supported bit depth. // Because we're directly accessing the framebuffer, changing bit depths for the driver // also means changing the user's actual screen bit depth. Realistically, we *could* // fake output and change to the user's current bit depth, but considering that (1) it // would be a *lot* more work, (2) this driver isn't the real thing, (3) there would // be a performance hit, and (4) I'm too lazy to mess with it, we'll change the screen's // depth, not make it default, and save the old ont so that we can change it back when // the driver is shut down. /* BScreen screen; display_mode candidate=mode; if(screen.ProposeMode(&candidate,&mode,&mode)!=B_OK) { STRACE(("DirectDriver::SetMode:ProposeMode failed\n")); return; } */ // It would seem that everything passed the error check, so actually set the mode DTRACE(("Locking screen window\n")); screenwin->Lock(); DTRACE(("Hiding screen window\n")); screenwin->Hide(); screenwin->Unlock(); DTRACE(("Locking screen window\n")); screenwin->Lock(); DTRACE(("Quitting old screen window\n")); screenwin->Quit(); DTRACE(("deleting framebuffer\n")); delete framebuffer; DTRACE(("creating new framebuffer\n")); framebuffer=new BBitmap(BRect(0,0,mode.virtual_width-1, mode.virtual_height-1),(color_space)mode.space,true); drawview=new BView(framebuffer->Bounds(),"drawview",0,0); framebuffer->AddChild(drawview); DTRACE(("creating new window\n")); screenwin=new DDWindow(mode.virtual_width, mode.virtual_height,(color_space)mode.space,this); while(find_thread("drawing_thread")==B_NAME_NOT_FOUND) { STRACE(("\tSetMode::Waiting for the drawing thread to spawn\n")); snooze(100); } Unlock(); } bool DirectDriver::DumpToFile(const char *path) { STRACE(("DirectDriver::DumpToFile\n")); Lock(); SaveToPNG(path,framebuffer->Bounds(),framebuffer->ColorSpace(), framebuffer->Bits(),framebuffer->BitsLength(),framebuffer->BytesPerRow()); Unlock(); return true; } status_t DirectDriver::SetDPMSMode(const uint32 &state) { STRACE(("DirectDriver::SetDPMSMode\n")); // This is a hack, but should do enough to be ok for our purposes return BScreen().SetDPMS(state); } uint32 DirectDriver::DPMSMode() const { STRACE(("DirectDriver::DPMSMode\n")); // This is a hack, but should do enough to be ok for our purposes return BScreen().DPMSState(); } uint32 DirectDriver::DPMSCapabilities() const { STRACE(("DirectDriver::DPMSCapabilities\n")); // This is a hack, but should do enough to be ok for our purposes return BScreen().DPMSCapabilites(); } status_t DirectDriver::GetDeviceInfo(accelerant_device_info *info) { STRACE(("DirectDriver::GetDeviceInfo\n")); if(!info) return B_ERROR; Lock(); status_t error=BScreen().GetDeviceInfo(info); Unlock(); return error; } status_t DirectDriver::GetModeList(display_mode **mode_list, uint32 *count) { STRACE(("DirectDriver::GetModeList\n")); if(!mode_list || !count) return B_ERROR; Lock(); status_t error=BScreen().GetModeList(mode_list,count); Unlock(); return error; } status_t DirectDriver::GetPixelClockLimits(display_mode *mode, uint32 *low, uint32 *high) { STRACE(("DirectDriver::GetPixelClockLimits\n")); if(!mode || !low || !high) return B_ERROR; Lock(); status_t error=BScreen().GetPixelClockLimits(mode,low,high); Unlock(); return error; } status_t DirectDriver::GetTimingConstraints(display_timing_constraints *dtc) { STRACE(("DirectDriver::GetTimingConstraints\n")); if(!dtc) return B_ERROR; Lock(); status_t error=BScreen().GetTimingConstraints(dtc); Unlock(); return error; } status_t DirectDriver::ProposeMode(display_mode *candidate, const display_mode *low, const display_mode *high) { STRACE(("DirectDriver::ProposeMode UNIMPLEMENTED\n")); // This could get sticky here. Theoretically, we should support the subset of modes // which the hardware can display and is not fullscreen unless the mode is 640x480 and // the current screen mode is also 640x480. //TODO: Implement this properly or get a "gotcha" sometime down the road. return B_OK; } status_t DirectDriver::WaitForRetrace(bigtime_t timeout=B_INFINITE_TIMEOUT) { STRACE(("DirectDriver::WaitForRetrace\n")); // There shouldn't be a need for a Lock call on this one... return BScreen().WaitForRetrace(timeout); } void DirectDriver::FillSolidRect(const BRect &rect, const RGBColor &color) { STRACE(("DirectDriver::FillSolidRect\n")); Lock(); framebuffer->Lock(); drawview->SetHighColor(color.GetColor32()); drawview->FillRect(rect); drawview->Sync(); screenwin->rectpipe.PutRect(rect); framebuffer->Unlock(); Unlock(); } void DirectDriver::FillPatternRect(const BRect &rect, const DrawData *d) { STRACE(("DirectDriver::FillPatternRect\n")); if(!d) return; Lock(); framebuffer->Lock(); drawview->SetHighColor(d->highcolor.GetColor32()); drawview->SetLowColor(d->lowcolor.GetColor32()); drawview->FillRect(rect,*((pattern*)d->patt.GetInt8())); drawview->Sync(); screenwin->rectpipe.PutRect(rect); framebuffer->Unlock(); Unlock(); } void DirectDriver::StrokeSolidRect(const BRect &rect, const RGBColor &color) { STRACE(("DirectDriver::StrokeSolidRect\n")); Lock(); framebuffer->Lock(); drawview->SetHighColor(color.GetColor32()); drawview->StrokeRect(rect); drawview->Sync(); screenwin->rectpipe.PutRect(rect); framebuffer->Unlock(); Unlock(); } void DirectDriver::StrokeSolidLine(int32 x1, int32 y1, int32 x2, int32 y2, const RGBColor &color) { STRACE(("DirectDriver::StrokeSolidLine\n")); Lock(); framebuffer->Lock(); drawview->SetHighColor(color.GetColor32()); drawview->StrokeLine(BPoint(x1,y1),BPoint(x2,y2)); drawview->Sync(); screenwin->rectpipe.PutRect(BRect(x1,y1,x2,y2)); framebuffer->Unlock(); Unlock(); } void DirectDriver::StrokePatternLine(int32 x1, int32 y1, int32 x2, int32 y2, const DrawData *d) { STRACE(("DirectDriver::StrokePatternLine\n")); if(!d) return; Lock(); framebuffer->Lock(); drawview->SetHighColor(d->highcolor.GetColor32()); drawview->SetLowColor(d->lowcolor.GetColor32()); drawview->StrokeLine(BPoint(x1,y1),BPoint(x2,y2),*((pattern*)d->patt.GetInt8())); drawview->Sync(); screenwin->rectpipe.PutRect(BRect(x1,y1,x2,y2)); framebuffer->Unlock(); Unlock(); } void DirectDriver::CopyBitmap(ServerBitmap *bitmap, const BRect &source,const BRect &dest, const DrawData *d) { if(!bitmap) { STRACE(("DirectDriver::CopyBitmap returned - NULL bitmap\n")); } if(!d) { STRACE(("DirectDriver::CopyBitmap returned - NULL DrawData\n")); return; } SetDrawData(d); // Oh, wow, is this going to be slow. Then again, ViewDriver was never meant to be very fast. It could // be made significantly faster by directly copying from the source to the destination, but that would // require implementing a lot of code. Eventually, this should be replaced, but for now, using // DrawBitmap will at least work with a minimum of effort. BBitmap *mediator=new BBitmap(bitmap->Bounds(),bitmap->ColorSpace()); memcpy(mediator->Bits(),bitmap->Bits(),bitmap->BitsLength()); Lock(); framebuffer->Lock(); drawview->DrawBitmap(mediator,source,dest); drawview->Sync(); framebuffer->Unlock(); screenwin->rectpipe.PutRect(dest); Unlock(); delete mediator; } void DirectDriver::SetDrawData(const DrawData *d, bool set_font_data) { STRACE(("DirectDriver::SetDrawData\n")); if(!d) return; bool unlock=false; if(!framebuffer->IsLocked()) { framebuffer->Lock(); unlock=true; } drawview->SetPenSize(d->pensize); drawview->SetDrawingMode(d->draw_mode); drawview->SetHighColor(d->highcolor.GetColor32()); drawview->SetLowColor(d->lowcolor.GetColor32()); drawview->SetScale(d->scale); drawview->MovePenTo(d->penlocation); if(set_font_data) { BFont font; const ServerFont *sf=&(d->font); if(!sf) return; font.SetFamilyAndStyle(sf->GetFamily(),sf->GetStyle()); font.SetFlags(sf->Flags()); font.SetEncoding(sf->Encoding()); font.SetSize(sf->Size()); font.SetRotation(sf->Rotation()); font.SetShear(sf->Shear()); font.SetSpacing(sf->Spacing()); drawview->SetFont(&font); } if(unlock) framebuffer->Unlock(); } void DirectDriver::CopyToBitmap(ServerBitmap *destbmp, const BRect &sourcerect) { STRACE(("DirectDriver::CopyToBitmap\n")); if(!destbmp) { printf("CopyToBitmap returned - not init or NULL bitmap\n"); return; } if((destbmp->ColorSpace() & 0x000F) != (framebuffer->ColorSpace() & 0x000F)) { printf("CopyToBitmap returned - unequal buffer pixel depth\n"); return; } BRect destrect(destbmp->Bounds()), source(sourcerect); uint8 colorspace_size=destbmp->BitsPerPixel()/8; // First, clip source rect to destination if(source.Width() > destrect.Width()) source.right=source.left+destrect.Width(); if(source.Height() > destrect.Height()) source.bottom=source.top+destrect.Height(); // Second, check rectangle bounds against their own bitmaps BRect work_rect(destbmp->Bounds()); if( !(work_rect.Contains(destrect)) ) { // something in selection must be clipped if(destrect.left < 0) destrect.left = 0; if(destrect.right > work_rect.right) destrect.right = work_rect.right; if(destrect.top < 0) destrect.top = 0; if(destrect.bottom > work_rect.bottom) destrect.bottom = work_rect.bottom; } work_rect.Set(0,0,fDisplayMode.virtual_width-1,fDisplayMode.virtual_height-1); if(!work_rect.Contains(sourcerect)) return; if( !(work_rect.Contains(source)) ) { // something in selection must be clipped if(source.left < 0) source.left = 0; if(source.right > work_rect.right) source.right = work_rect.right; if(source.top < 0) source.top = 0; if(source.bottom > work_rect.bottom) source.bottom = work_rect.bottom; } // Set pointers to the actual data uint8 *dest_bits = (uint8*) destbmp->Bits(); uint8 *src_bits = (uint8*) framebuffer->Bits(); // Get row widths for offset looping uint32 dest_width = uint32 (destbmp->BytesPerRow()); uint32 src_width = uint32 (framebuffer->BytesPerRow()); // Offset bitmap pointers to proper spot in each bitmap src_bits += uint32 ( (source.top * src_width) + (source.left * colorspace_size) ); dest_bits += uint32 ( (destrect.top * dest_width) + (destrect.left * colorspace_size) ); uint32 line_length = uint32 ((destrect.right - destrect.left+1)*colorspace_size); uint32 lines = uint32 (source.bottom-source.top+1); for (uint32 pos_y=0; pos_yLock(); // screenwin->view->ConstrainClippingRegion(reg); drawview->ConstrainClippingRegion(reg); framebuffer->Unlock(); Unlock(); } rgb_color DirectDriver::GetBlitColor(rgb_color src, rgb_color dest,DrawData *d, bool use_high) { rgb_color returncolor={0,0,0,0}; int16 value; if(!d) return returncolor; switch(d->draw_mode) { case B_OP_COPY: { return src; } case B_OP_ADD: { value=src.red+dest.red; returncolor.red=(value>255)?255:value; value=src.green+dest.green; returncolor.green=(value>255)?255:value; value=src.blue+dest.blue; returncolor.blue=(value>255)?255:value; return returncolor; } case B_OP_SUBTRACT: { value=src.red-dest.red; returncolor.red=(value<0)?0:value; value=src.green-dest.green; returncolor.green=(value<0)?0:value; value=src.blue-dest.blue; returncolor.blue=(value<0)?0:value; return returncolor; } case B_OP_BLEND: { value=int16(src.red+dest.red)>>1; returncolor.red=value; value=int16(src.green+dest.green)>>1; returncolor.green=value; value=int16(src.blue+dest.blue)>>1; returncolor.blue=value; return returncolor; } case B_OP_MIN: { return ( uint16(src.red+src.blue+src.green) > uint16(dest.red+dest.blue+dest.green) )?dest:src; } case B_OP_MAX: { return ( uint16(src.red+src.blue+src.green) < uint16(dest.red+dest.blue+dest.green) )?dest:src; } case B_OP_OVER: { return (use_high && src.alpha>127)?src:dest; } case B_OP_INVERT: { returncolor.red=dest.red ^ 255; returncolor.green=dest.green ^ 255; returncolor.blue=dest.blue ^ 255; return (use_high && src.alpha>127)?returncolor:dest; } case B_OP_ALPHA: { //TODO: Implement return src; } case B_OP_ERASE: { // This one's tricky. return (use_high && src.alpha>127)?d->lowcolor.GetColor32():dest; } case B_OP_SELECT: { // This one's tricky, too. We are passed a color in src. If it's the layer's // high color or low color, we check for a swap. if(d->highcolor==src) return (use_high && d->highcolor==dest)?d->lowcolor.GetColor32():dest; if(d->lowcolor==src) return (use_high && d->lowcolor==dest)?d->highcolor.GetColor32():dest; return dest; } default: { break; } } return returncolor; } //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- DDView::DDView(BRect bounds) : BView(bounds,"viewdriver_view",B_FOLLOW_ALL, B_WILL_DRAW), serverlink(0L) { SetViewColor(B_TRANSPARENT_32_BIT); #ifdef ENABLE_INPUT_SERVER_EMULATION port_id serverInputPort = find_port(SERVER_INPUT_PORT); if (serverInputPort<0) { debugger("DirectDriver:DDView couldn't find input port\n"); return; } serverlink.SetSendPort(serverInputPort); #endif } // These functions emulate the Input Server by sending the *exact* same kind of messages // to the server's port. Being we're using a regular window, it would make little sense // to do anything else. void DDView::MouseDown(BPoint pt) { #ifdef ENABLE_INPUT_SERVER_EMULATION // Attach data: // 1) int64 - time of mouse click // 2) float - x coordinate of mouse click // 3) float - y coordinate of mouse click // 4) int32 - modifier keys down // 5) int32 - buttons down // 6) int32 - clicks uint32 buttons, mod, clicks=1; int64 time=(int64)real_time_clock(); BMessage *msg=Window()->CurrentMessage(); msg->FindPoint("where",&pt); msg->FindInt32("modifiers",(int32*)&mod); msg->FindInt32("buttons",(int32*)&buttons); msg->FindInt32("clicks",(int32*)&clicks); serverlink.StartMessage(B_MOUSE_DOWN); serverlink.Attach(&time, sizeof(int64)); serverlink.Attach(&pt.x,sizeof(float)); serverlink.Attach(&pt.y,sizeof(float)); serverlink.Attach(&mod, sizeof(uint32)); serverlink.Attach(&buttons, sizeof(uint32)); serverlink.Attach(&clicks, sizeof(uint32)); serverlink.Flush(); #endif } void DDView::MouseMoved(BPoint pt, uint32 transit, const BMessage *msg) { #ifdef ENABLE_INPUT_SERVER_EMULATION // Attach data: // 1) int64 - time of mouse click // 2) float - x coordinate of mouse click // 3) float - y coordinate of mouse click // 4) int32 - buttons down BPoint p; uint32 buttons; int64 time=(int64)real_time_clock(); serverlink.StartMessage(B_MOUSE_MOVED); serverlink.Attach(&time,sizeof(int64)); serverlink.Attach(&pt.x,sizeof(float)); serverlink.Attach(&pt.y,sizeof(float)); GetMouse(&p,&buttons); serverlink.Attach(&buttons,sizeof(int32)); serverlink.Flush(); #endif } void DDView::MouseUp(BPoint pt) { #ifdef ENABLE_INPUT_SERVER_EMULATION // Attach data: // 1) int64 - time of mouse click // 2) float - x coordinate of mouse click // 3) float - y coordinate of mouse click // 4) int32 - modifier keys down BPoint p; uint32 buttons, mod=modifiers(); int64 time=(int64)real_time_clock(); GetMouse(&p,&buttons); serverlink.StartMessage(B_MOUSE_UP); serverlink.Attach(&time, sizeof(int64)); serverlink.Attach(&pt.x,sizeof(float)); serverlink.Attach(&pt.y,sizeof(float)); serverlink.Attach(&mod, sizeof(uint32)); serverlink.Flush(); #endif } void DDView::MessageReceived(BMessage *msg) { switch(msg->what) { #ifdef ENABLE_INPUT_SERVER_EMULATION case B_MOUSE_WHEEL_CHANGED: { float x,y; msg->FindFloat("be:wheel_delta_x",&x); msg->FindFloat("be:wheel_delta_y",&y); int64 time=real_time_clock(); serverlink.StartMessage(B_MOUSE_WHEEL_CHANGED); serverlink.Attach(&time,sizeof(int64)); serverlink.Attach(x); serverlink.Attach(y); serverlink.Flush(); break; } #endif default: BView::MessageReceived(msg); break; } } DDWindow::DDWindow(uint16 width, uint16 height, color_space space, DirectDriver *owner) : BDirectWindow(BRect(0,0,width-1,height-1), "Haiku App Server",B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NOT_MOVABLE) { AddChild(new DDView(Bounds())); fOwner=owner; fConnected=false; fConnectionDisabled=false; fClipList=NULL; fNumClipRects=0; fDirty=true; fDrawThreadID=-1; if(!owner) debugger("DDWindow requires a non-NULL owner."); framebuffer=owner->framebuffer; if(SupportsWindowMode()) { BRect sframe(BScreen().Frame()); screensize.left=(int32)sframe.left; screensize.right=(int32)sframe.right; screensize.top=(int32)sframe.top; screensize.bottom=(int32)sframe.bottom; MoveTo( (int32)(sframe.Width()-width)/2, (int32)(sframe.Height()-height)/2 ); } else { SetFullScreen(true); } Show(); } DDWindow::~DDWindow() { int32 result; fConnectionDisabled=true; // Sync(); if(fDrawThreadID!=-1) wait_for_thread(fDrawThreadID,&result); free(fClipList); } void DDWindow::DirectConnected(direct_buffer_info *info) { if(!fConnected && fConnectionDisabled) return; locker.Lock(); switch(info->buffer_state & B_DIRECT_MODE_MASK) { case B_DIRECT_START: { fConnected=true; fDrawThreadID=spawn_thread(DrawingThread,"drawing_thread", B_NORMAL_PRIORITY,(void*)this); resume_thread(fDrawThreadID); // fall through to B_DIRECT_MODIFY case } case B_DIRECT_MODIFY: { fBits=(uint8*)info->bits; fRowBytes=info->bytes_per_row; fFormat=info->pixel_format; fBounds=info->window_bounds; if(fClipList) { free(fClipList); fClipList=NULL; } fNumClipRects=info->clip_list_count; fClipList=(clipping_rect*)malloc(fNumClipRects*sizeof(clipping_rect)); if(fClipList) { memcpy(fClipList, info->clip_list, fNumClipRects*sizeof(clipping_rect)); fDirty=true; } break; } case B_DIRECT_STOP: { fConnected=false; break; } } locker.Unlock(); } bool DDWindow::QuitRequested() { port_id serverport=find_port(SERVER_PORT_NAME); if(serverport>=0) { BPortLink link(serverport); link.StartMessage(B_QUIT_REQUESTED); link.Flush(); } else printf("ERROR: couldn't find the app_server's main port!"); return true; } void DDWindow::WindowActivated(bool active) { // This is just to hide the regular system cursor so we can see our own if(active) be_app->HideCursor(); else be_app->ShowCursor(); } int32 DDWindow::DrawingThread(void *data) { ATRACE(("DrawingThread started\n")); DDWindow *w; w=(DDWindow *)data; bool wait_for_good_mode=true; while(wait_for_good_mode) { switch(w->fFormat) { case B_RGB32: case B_RGBA32: case B_RGB32_BIG: case B_RGBA32_BIG: case B_GRAY8: case B_CMAP8: { DTRACE(("\tFound a good mode. Exiting wait loop\n")); wait_for_good_mode=false; break; } default: DTRACE(("\tWaiting for a good mode\n")); break; } } switch(w->fFormat) { case B_RGB32: case B_RGBA32: case B_RGB32_BIG: case B_RGBA32_BIG: { DTRACE(("\tEntering while loop\n")); while(!w->fConnectionDisabled) { DTRACE(("\tacquiring window lock\n")); w->locker.Lock(); if(w->fConnected) { int32 winleft=(int32)w->Frame().left,wintop=(int32)w->Frame().top; DTRACE(("\tcheck to see if window is dirty\n")); if(w->fDirty) { DTRACE(("\twindow is dirty\n")); int32 y,bytes_to_copy,height; uint8 *srcbits, *destbits; clipping_rect *clip; uint32 i; DTRACE(("\tClipping rectangles to copy: %lu\n",w->fNumClipRects)); for(i=0; ifNumClipRects; i++) { DTRACE(("\tcopying clipping rectangle %lu\n",i)); clip=&(w->fClipList[i]); bytes_to_copy=((clip->right-clip->left)+1)<<2; height=(clip->bottom-clip->top)+1; destbits=w->fBits+ (clip->top*w->fRowBytes)+ (clip->left<<2); srcbits=(uint8*)w->framebuffer->Bits()+ ((clip->top-wintop)*w->framebuffer->BytesPerRow())+ ( (clip->left-winleft)<<2); y=0; while(yfRowBytes; srcbits+=w->framebuffer->BytesPerRow(); } } w->fDirty=false; } else DTRACE(("\tWindow is not dirty\n")); if(!w->fConnected) { DTRACE(("\twindow is no longer connected. Exiting draw case\n")); break; } // This will be true if the driver has changed the contents of // the framebuffer bitmap DTRACE(("\tFramebuffer bitmap has %ld invalid regions\n",w->rectpipe.CountRects())); while(w->rectpipe.HasRects()) { clipping_rect rect; int32 y,bytes_to_copy,height; uint8 *srcbits, *destbits; w->rectpipe.GetRect(&rect); bytes_to_copy=((rect.right-rect.left)+1)<<2; height=(rect.bottom-rect.top)+1; destbits=w->fBits+ ( (rect.top+wintop)*w->fRowBytes)+ ( (rect.left+winleft)<<2); srcbits=(uint8*)w->framebuffer->Bits()+ (rect.top*w->framebuffer->BytesPerRow())+ (rect.left<<2); y=0; DTRACE(("Copying data from bitmap to screen\n")); while(yfRowBytes; srcbits+=w->framebuffer->BytesPerRow(); } } } DTRACE(("\tReleasing window lock\n")); w->locker.Unlock(); snooze(16000); } break; } case B_GRAY8: case B_CMAP8: { while(!w->fConnectionDisabled) { w->locker.Lock(); if(w->fConnected) { if(w->fDirty) { int32 y,width,height,adder; uint8 *p; clipping_rect *clip; uint32 i; adder=w->fRowBytes; for(i=0; ifNumClipRects; i++) { clip=&(w->fClipList[i]); width=(clip->right-clip->left)+1; height=(clip->bottom-clip->top)+1; p=w->fBits+(clip->top*w->fRowBytes)+clip->left; y=0; while(yfDirty=false; } } w->locker.Unlock(); snooze(16000); } break; } default: debugger("DirectDriver was given an unsupported color mode."); break; } w->fDrawThreadID=-1; return 0; } RectPipe::RectPipe() { list.MakeEmpty(); } RectPipe::~RectPipe() { lock.Lock(); clipping_rect *rect; for(int32 i=0; ileft=(int32)rect.left; clip->right=(int32)rect.right; clip->top=(int32)rect.top; clip->bottom=(int32)rect.bottom; list.AddItem(clip); lock.Unlock(); } void RectPipe::PutRect(const clipping_rect &rect) { lock.Lock(); has_rects=true; clipping_rect *clip=new clipping_rect; *clip=rect; list.AddItem(clip); lock.Unlock(); } bool RectPipe::GetRect(clipping_rect *rect) { lock.Lock(); clipping_rect *clip=(clipping_rect*)list.RemoveItem(0L); if(clip) { *rect=*clip; delete clip; if(list.IsEmpty()) has_rects=false; lock.Unlock(); return true; } // If we returned NULL, it means that the list is empty has_rects=false; lock.Unlock(); return false; } bool RectPipe::HasRects() { lock.Lock(); bool value=has_rects; lock.Unlock(); return value; }