diff --git a/docs/user/app/Cursor.dox b/docs/user/app/Cursor.dox index 7f4e91fe70..818b262c2e 100644 --- a/docs/user/app/Cursor.dox +++ b/docs/user/app/Cursor.dox @@ -6,8 +6,8 @@ * John Scipione, jscipione@gmail.com * * Corresponds to: - * headers/os/app/Cursor.h hrev47355 - * src/kits/app/Cursor.cpp hrev47355 + * headers/os/app/Cursor.h hrev54621 + * src/kits/app/Cursor.cpp hrev54621 */ @@ -315,6 +315,18 @@ */ +/*! + \fn BCursor::BCursor(const BBitmap* bitmap, const BPoint& hotspot) + \brief Initializes a new cursor object from a bitmap object and a point + object. + + \param bitmap The bitmap object to initialize from. + \param hotspot The cursor hotspot. + + \since Haiku R1 +*/ + + /*! \fn BCursor::~BCursor() \brief Destroy the cursor and free its memory. @@ -323,6 +335,17 @@ */ +/*! + \fn status_t BCursor::InitCheck() const + \brief Returns the initialization status. + + \return \c B_OK if the object was properly initialized or an error code + otherwise. + + \since Haiku R1 +*/ + + /*! \fn status_t BCursor::Archive(BMessage *into, bool deep) const \brief Archive the cursor. Not implemented. diff --git a/headers/os/app/Cursor.h b/headers/os/app/Cursor.h index 484db3c31a..de24179a53 100644 --- a/headers/os/app/Cursor.h +++ b/headers/os/app/Cursor.h @@ -50,8 +50,12 @@ public: BCursor(const BCursor& other); BCursor(BCursorID id); BCursor(BMessage* data); + BCursor(const BBitmap* bitmap, + const BPoint& hotspot); virtual ~BCursor(); + status_t InitCheck() const; + virtual status_t Archive(BMessage* archive, bool deep = true) const; static BArchivable* Instantiate(BMessage* archive); diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index a6795e6ba3..2c74242512 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -73,6 +73,7 @@ enum { AS_QUERY_CURSOR_HIDDEN, AS_CREATE_CURSOR, + AS_CREATE_CURSOR_BITMAP, AS_REFERENCE_CURSOR, AS_DELETE_CURSOR, diff --git a/src/kits/app/Cursor.cpp b/src/kits/app/Cursor.cpp index 0623d0a50d..b5f3cf6695 100644 --- a/src/kits/app/Cursor.cpp +++ b/src/kits/app/Cursor.cpp @@ -15,7 +15,9 @@ to see a nice shadowes one, we will need to extend this one. */ + #include +#include #include #include @@ -86,12 +88,54 @@ BCursor::BCursor(BMessage *data) } +BCursor::BCursor(const BBitmap* bitmap, const BPoint& hotspot) + : + fServerToken(-1), + fNeedToFree(false) +{ + if (bitmap == NULL) + return; + + int32 size = bitmap->BitsLength(); + BRect bounds = bitmap->Bounds(); + color_space colorspace = bitmap->ColorSpace(); + void* bits = bitmap->Bits(); + if (bits == NULL || size <= 0) + return; + + // Send data directly to server + BPrivate::AppServerLink link; + link.StartMessage(AS_CREATE_CURSOR_BITMAP); + link.Attach(size); + link.Attach(bounds); + link.Attach(colorspace); + link.Attach(hotspot); + link.Attach(bits, size); + + status_t status; + if (link.FlushWithReply(status) == B_OK) { + if (status == B_OK) { + link.Read(&fServerToken); + fNeedToFree = true; + } else + fServerToken = status; + } +} + + BCursor::~BCursor() { _FreeCursorData(); } +status_t +BCursor::InitCheck() const +{ + return fServerToken >= 0 ? B_OK : fServerToken; +} + + status_t BCursor::Archive(BMessage *into, bool deep) const { diff --git a/src/kits/interface/InterfaceDefs.cpp b/src/kits/interface/InterfaceDefs.cpp index ac89efaa59..bdeb204b39 100644 --- a/src/kits/interface/InterfaceDefs.cpp +++ b/src/kits/interface/InterfaceDefs.cpp @@ -1115,12 +1115,14 @@ get_mouse_bitmap(BBitmap** bitmap, BPoint* hotspot) uint32 size = 0; uint32 cursorWidth = 0; uint32 cursorHeight = 0; + color_space colorspace = B_RGBA32; // if link.Read() returns an error, the same error will be returned on // subsequent calls, so we'll check only the return value of the last call link.Read(&size); link.Read(&cursorWidth); link.Read(&cursorHeight); + link.Read(&colorspace); if (hotspot == NULL) { BPoint dummy; link.Read(&dummy); @@ -1140,7 +1142,7 @@ get_mouse_bitmap(BBitmap** bitmap, BPoint* hotspot) } BBitmap* cursorBitmap = new (std::nothrow) BBitmap(BRect(0, 0, - cursorWidth - 1, cursorHeight - 1), B_RGBA32); + cursorWidth - 1, cursorHeight - 1), colorspace); if (cursorBitmap == NULL) { free(data); @@ -1148,7 +1150,7 @@ get_mouse_bitmap(BBitmap** bitmap, BPoint* hotspot) } status = cursorBitmap->InitCheck(); if (status == B_OK) - cursorBitmap->SetBits(data, size, 0, B_RGBA32); + cursorBitmap->SetBits(data, size, 0, colorspace); free(data); diff --git a/src/servers/app/CursorManager.cpp b/src/servers/app/CursorManager.cpp index 71baafa022..35cac756db 100644 --- a/src/servers/app/CursorManager.cpp +++ b/src/servers/app/CursorManager.cpp @@ -128,6 +128,29 @@ CursorManager::CreateCursor(team_id clientTeam, const uint8* cursorData) } +ServerCursor* +CursorManager::CreateCursor(team_id clientTeam, BRect r, color_space format, + int32 flags, BPoint hotspot, int32 bytesPerRow) +{ + if (!Lock()) + return NULL; + + ServerCursor* cursor = new (std::nothrow) ServerCursor(r, format, flags, + hotspot, bytesPerRow); + if (cursor != NULL) { + cursor->SetOwningTeam(clientTeam); + if (AddCursor(cursor) < B_OK) { + delete cursor; + cursor = NULL; + } + } + + Unlock(); + + return cursor; +} + + /*! \brief Registers a cursor with the manager. \param cursor ServerCursor object to register \return The token assigned to the cursor or B_ERROR if cursor is NULL diff --git a/src/servers/app/CursorManager.h b/src/servers/app/CursorManager.h index 9a9156cadf..1572570be2 100644 --- a/src/servers/app/CursorManager.h +++ b/src/servers/app/CursorManager.h @@ -35,6 +35,9 @@ public: ServerCursor* CreateCursor(team_id clientTeam, const uint8* cursorData); + ServerCursor* CreateCursor(team_id clientTeam, + BRect r, color_space format, int32 flags, + BPoint hotspot, int32 bytesPerRow = -1); int32 AddCursor(ServerCursor* cursor, int32 token = -1); diff --git a/src/servers/app/ProfileMessageSupport.cpp b/src/servers/app/ProfileMessageSupport.cpp index e8126dbbbe..1021778ef5 100644 --- a/src/servers/app/ProfileMessageSupport.cpp +++ b/src/servers/app/ProfileMessageSupport.cpp @@ -54,6 +54,7 @@ string_for_message_code(uint32 code) CODE(AS_QUERY_CURSOR_HIDDEN); CODE(AS_CREATE_CURSOR); + CODE(AS_CREATE_CURSOR_BITMAP); CODE(AS_REFERENCE_CURSOR); CODE(AS_DELETE_CURSOR); diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 6f30c98246..1bf20a082f 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -1235,6 +1235,49 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) break; } + case AS_CREATE_CURSOR_BITMAP: + { + STRACE(("ServerApp %s: Create Cursor bitmap\n", Signature())); + + status_t status = B_ERROR; + + int32 size = 0; + BRect cursorRect; + color_space colorspace = B_RGBA32; + BPoint hotspot; + ServerCursor* cursor = NULL; + + if (link.Read(&size) == B_OK + && link.Read(&cursorRect) == B_OK + && link.Read(&colorspace) == B_OK + && link.Read(&hotspot) == B_OK + && size > 0) { + + BStackOrHeapArray byteArray(size); + if (!byteArray.IsValid()) { + status = B_NO_MEMORY; + } else if (link.Read(byteArray, size) == B_OK) { + cursor = fDesktop->GetCursorManager().CreateCursor( + fClientTeam, cursorRect, colorspace, 0, hotspot); + if (cursor == NULL) + status = B_NO_MEMORY; + else + memcpy(cursor->Bits(), byteArray, size); + } + } + + if (cursor != NULL) { + // Synchronous message - BApplication is waiting on the + // cursor's ID + fLink.StartMessage(B_OK); + fLink.Attach(cursor->Token()); + } else + fLink.StartMessage(status); + + fLink.Flush(); + break; + } + case AS_REFERENCE_CURSOR: { STRACE(("ServerApp %s: Reference BCursor\n", Signature())); @@ -1320,6 +1363,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) fLink.Attach(size); fLink.Attach(cursor->Width()); fLink.Attach(cursor->Height()); + fLink.Attach(cursor->ColorSpace()); fLink.Attach(cursor->GetHotSpot()); fLink.Attach(cursor->Bits(), size); } else diff --git a/src/tests/kits/app/bcursor/BCursorTester.cpp b/src/tests/kits/app/bcursor/BCursorTester.cpp index c585855c8d..5846189c88 100644 --- a/src/tests/kits/app/bcursor/BCursorTester.cpp +++ b/src/tests/kits/app/bcursor/BCursorTester.cpp @@ -7,6 +7,7 @@ // System Includes ------------------------------------------------------------ #include +#include #include #include @@ -103,6 +104,24 @@ void BCursorTester::BCursor5() BCursor cur(&msg); } +/* + BCursor(BBitmap *bitmap, BPoint* hotspot) + @case 1 + @results nothing apparent (empty cursor) + */ +void BCursorTester::BCursor6() +{ + BApplication app("application/x-vnd.cursortest"); + + BBitmap *bitmap; + BPoint hotspot(0, 0); + + get_mouse_bitmap(&bitmap, &hotspot); + hotspot.x += 1; + hotspot.y += 1; + BCursor cur(bitmap, hotspot); +} + /* static BArchivable *Instantiate(BMessage *archive) @case 1 diff --git a/src/tests/kits/app/bcursor/BCursorTester.h b/src/tests/kits/app/bcursor/BCursorTester.h index 94bc0e209e..aee49c5baf 100644 --- a/src/tests/kits/app/bcursor/BCursorTester.h +++ b/src/tests/kits/app/bcursor/BCursorTester.h @@ -30,6 +30,7 @@ class BCursorTester : public TestCase void BCursor3(); void BCursor4(); void BCursor5(); + void BCursor6(); void Instantiate1(); void Instantiate2(); void Archive1(); diff --git a/src/tests/servers/app/cursor_test/CursorBitmapTest.cpp b/src/tests/servers/app/cursor_test/CursorBitmapTest.cpp new file mode 100644 index 0000000000..9c39ecfb50 --- /dev/null +++ b/src/tests/servers/app/cursor_test/CursorBitmapTest.cpp @@ -0,0 +1,140 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "bitmap.h" + + +class View : public BView { + public: + View(BRect rect); + virtual ~View(); + + virtual void AttachedToWindow(); +}; + + +bool gHide = false; + + +View::View(BRect rect) + : BView(rect, "desktop view", B_FOLLOW_ALL, B_WILL_DRAW) +{ + SetViewColor(0, 150, 0); +} + + +View::~View() +{ +} + + +void +View::AttachedToWindow() +{ +} + + +// #pragma mark - + + +class Window : public BWindow { + public: + Window(); + virtual ~Window(); + + virtual bool QuitRequested(); +}; + + +Window::Window() + : BWindow(BRect(100, 100, 400, 400), "Cursor-Test", + B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS) +{ + BView *view = new View(Bounds().InsetByCopy(30, 30)); + AddChild(view); +} + + +Window::~Window() +{ +} + + +bool +Window::QuitRequested() +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + + +// #pragma mark - + + +class Application : public BApplication { + public: + Application(); + + virtual void ReadyToRun(); +}; + + +Application::Application() + : BApplication("application/x-vnd.haiku-cursor_test") +{ +} + + +void +Application::ReadyToRun() +{ + Window *window = new Window(); + window->Show(); + + if (gHide) + HideCursor(); + else { + BBitmap* bitmap = new BBitmap( + BRect(0, 0, kBitmapWidth - 1, kBitmapHeight - 1), 0,kBitmapFormat); + bitmap->ImportBits(kBitmapBits, sizeof(kBitmapBits), kBitmapWidth * 4, + 0, kBitmapFormat); + BPoint hotspot(8, 8); + BCursor cursor(bitmap, hotspot); + SetCursor(&cursor); + } +} + + +// #pragma mark - + + +int +main(int argc, char **argv) +{ + if (argc > 1 && !strcmp(argv[1], "hide")) + gHide = true; + + Application app; + + app.Run(); + return 0; +} diff --git a/src/tests/servers/app/cursor_test/Jamfile b/src/tests/servers/app/cursor_test/Jamfile index 5068ffa05b..10e2579a8d 100644 --- a/src/tests/servers/app/cursor_test/Jamfile +++ b/src/tests/servers/app/cursor_test/Jamfile @@ -4,12 +4,18 @@ AddSubDirSupportedPlatforms libbe_test ; UseHeaders [ FDirName os app ] ; UseHeaders [ FDirName os interface ] ; +UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) bitmap_drawing ] ; Application CursorTest : CursorTest.cpp : be [ TargetLibstdc++ ] [ TargetLibsupc++ ] ; +Application CursorBitmapTest : + CursorBitmapTest.cpp + : be [ TargetLibstdc++ ] [ TargetLibsupc++ ] +; + if $(TARGET_PLATFORM) = libbe_test { HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : CursorTest : tests!apps ;