BCursor: add a constructor with bitmap and point

* enhancement #15169
* get_mouse_bitmap(): also reads the colorspace from app_server.
* docs and tests

Change-Id: Iba63f8a2789530ae596c30b92f14828f31761d98
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3292
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
Jérôme Duval 2020-10-05 20:28:43 +02:00
parent e5af52cede
commit 06ed32b8c4
13 changed files with 315 additions and 4 deletions

View File

@ -6,8 +6,8 @@
* John Scipione, jscipione@gmail.com * John Scipione, jscipione@gmail.com
* *
* Corresponds to: * Corresponds to:
* headers/os/app/Cursor.h hrev47355 * headers/os/app/Cursor.h hrev54621
* src/kits/app/Cursor.cpp hrev47355 * 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() \fn BCursor::~BCursor()
\brief Destroy the cursor and free its memory. \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 \fn status_t BCursor::Archive(BMessage *into, bool deep) const
\brief Archive the cursor. Not implemented. \brief Archive the cursor. Not implemented.

View File

@ -50,8 +50,12 @@ public:
BCursor(const BCursor& other); BCursor(const BCursor& other);
BCursor(BCursorID id); BCursor(BCursorID id);
BCursor(BMessage* data); BCursor(BMessage* data);
BCursor(const BBitmap* bitmap,
const BPoint& hotspot);
virtual ~BCursor(); virtual ~BCursor();
status_t InitCheck() const;
virtual status_t Archive(BMessage* archive, virtual status_t Archive(BMessage* archive,
bool deep = true) const; bool deep = true) const;
static BArchivable* Instantiate(BMessage* archive); static BArchivable* Instantiate(BMessage* archive);

View File

@ -73,6 +73,7 @@ enum {
AS_QUERY_CURSOR_HIDDEN, AS_QUERY_CURSOR_HIDDEN,
AS_CREATE_CURSOR, AS_CREATE_CURSOR,
AS_CREATE_CURSOR_BITMAP,
AS_REFERENCE_CURSOR, AS_REFERENCE_CURSOR,
AS_DELETE_CURSOR, AS_DELETE_CURSOR,

View File

@ -15,7 +15,9 @@
to see a nice shadowes one, we will need to extend this one. to see a nice shadowes one, we will need to extend this one.
*/ */
#include <AppDefs.h> #include <AppDefs.h>
#include <Bitmap.h>
#include <Cursor.h> #include <Cursor.h>
#include <AppServerLink.h> #include <AppServerLink.h>
@ -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<int32>(size);
link.Attach<BRect>(bounds);
link.Attach<color_space>(colorspace);
link.Attach<BPoint>(hotspot);
link.Attach(bits, size);
status_t status;
if (link.FlushWithReply(status) == B_OK) {
if (status == B_OK) {
link.Read<int32>(&fServerToken);
fNeedToFree = true;
} else
fServerToken = status;
}
}
BCursor::~BCursor() BCursor::~BCursor()
{ {
_FreeCursorData(); _FreeCursorData();
} }
status_t
BCursor::InitCheck() const
{
return fServerToken >= 0 ? B_OK : fServerToken;
}
status_t status_t
BCursor::Archive(BMessage *into, bool deep) const BCursor::Archive(BMessage *into, bool deep) const
{ {

View File

@ -1115,12 +1115,14 @@ get_mouse_bitmap(BBitmap** bitmap, BPoint* hotspot)
uint32 size = 0; uint32 size = 0;
uint32 cursorWidth = 0; uint32 cursorWidth = 0;
uint32 cursorHeight = 0; uint32 cursorHeight = 0;
color_space colorspace = B_RGBA32;
// if link.Read() returns an error, the same error will be returned on // 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 // subsequent calls, so we'll check only the return value of the last call
link.Read<uint32>(&size); link.Read<uint32>(&size);
link.Read<uint32>(&cursorWidth); link.Read<uint32>(&cursorWidth);
link.Read<uint32>(&cursorHeight); link.Read<uint32>(&cursorHeight);
link.Read<color_space>(&colorspace);
if (hotspot == NULL) { if (hotspot == NULL) {
BPoint dummy; BPoint dummy;
link.Read<BPoint>(&dummy); link.Read<BPoint>(&dummy);
@ -1140,7 +1142,7 @@ get_mouse_bitmap(BBitmap** bitmap, BPoint* hotspot)
} }
BBitmap* cursorBitmap = new (std::nothrow) BBitmap(BRect(0, 0, BBitmap* cursorBitmap = new (std::nothrow) BBitmap(BRect(0, 0,
cursorWidth - 1, cursorHeight - 1), B_RGBA32); cursorWidth - 1, cursorHeight - 1), colorspace);
if (cursorBitmap == NULL) { if (cursorBitmap == NULL) {
free(data); free(data);
@ -1148,7 +1150,7 @@ get_mouse_bitmap(BBitmap** bitmap, BPoint* hotspot)
} }
status = cursorBitmap->InitCheck(); status = cursorBitmap->InitCheck();
if (status == B_OK) if (status == B_OK)
cursorBitmap->SetBits(data, size, 0, B_RGBA32); cursorBitmap->SetBits(data, size, 0, colorspace);
free(data); free(data);

View File

@ -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. /*! \brief Registers a cursor with the manager.
\param cursor ServerCursor object to register \param cursor ServerCursor object to register
\return The token assigned to the cursor or B_ERROR if cursor is NULL \return The token assigned to the cursor or B_ERROR if cursor is NULL

View File

@ -35,6 +35,9 @@ public:
ServerCursor* CreateCursor(team_id clientTeam, ServerCursor* CreateCursor(team_id clientTeam,
const uint8* cursorData); 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 AddCursor(ServerCursor* cursor,
int32 token = -1); int32 token = -1);

View File

@ -54,6 +54,7 @@ string_for_message_code(uint32 code)
CODE(AS_QUERY_CURSOR_HIDDEN); CODE(AS_QUERY_CURSOR_HIDDEN);
CODE(AS_CREATE_CURSOR); CODE(AS_CREATE_CURSOR);
CODE(AS_CREATE_CURSOR_BITMAP);
CODE(AS_REFERENCE_CURSOR); CODE(AS_REFERENCE_CURSOR);
CODE(AS_DELETE_CURSOR); CODE(AS_DELETE_CURSOR);

View File

@ -1235,6 +1235,49 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
break; 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<int32>(&size) == B_OK
&& link.Read<BRect>(&cursorRect) == B_OK
&& link.Read<color_space>(&colorspace) == B_OK
&& link.Read<BPoint>(&hotspot) == B_OK
&& size > 0) {
BStackOrHeapArray<uint8, 256> 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<int32>(cursor->Token());
} else
fLink.StartMessage(status);
fLink.Flush();
break;
}
case AS_REFERENCE_CURSOR: case AS_REFERENCE_CURSOR:
{ {
STRACE(("ServerApp %s: Reference BCursor\n", Signature())); STRACE(("ServerApp %s: Reference BCursor\n", Signature()));
@ -1320,6 +1363,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
fLink.Attach<uint32>(size); fLink.Attach<uint32>(size);
fLink.Attach<uint32>(cursor->Width()); fLink.Attach<uint32>(cursor->Width());
fLink.Attach<uint32>(cursor->Height()); fLink.Attach<uint32>(cursor->Height());
fLink.Attach<color_space>(cursor->ColorSpace());
fLink.Attach<BPoint>(cursor->GetHotSpot()); fLink.Attach<BPoint>(cursor->GetHotSpot());
fLink.Attach(cursor->Bits(), size); fLink.Attach(cursor->Bits(), size);
} else } else

View File

@ -7,6 +7,7 @@
// System Includes ------------------------------------------------------------ // System Includes ------------------------------------------------------------
#include <Application.h> #include <Application.h>
#include <Bitmap.h>
#include <Cursor.h> #include <Cursor.h>
#include <Message.h> #include <Message.h>
@ -103,6 +104,24 @@ void BCursorTester::BCursor5()
BCursor cur(&msg); 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) static BArchivable *Instantiate(BMessage *archive)
@case 1 @case 1

View File

@ -30,6 +30,7 @@ class BCursorTester : public TestCase
void BCursor3(); void BCursor3();
void BCursor4(); void BCursor4();
void BCursor5(); void BCursor5();
void BCursor6();
void Instantiate1(); void Instantiate1();
void Instantiate2(); void Instantiate2();
void Archive1(); void Archive1();

View File

@ -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 <Application.h>
#include <Bitmap.h>
#include <Cursor.h>
#include <Debug.h>
#include <String.h>
#include <View.h>
#include <Window.h>
#include <algorithm>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}

View File

@ -4,12 +4,18 @@ AddSubDirSupportedPlatforms libbe_test ;
UseHeaders [ FDirName os app ] ; UseHeaders [ FDirName os app ] ;
UseHeaders [ FDirName os interface ] ; UseHeaders [ FDirName os interface ] ;
UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) bitmap_drawing ] ;
Application CursorTest : Application CursorTest :
CursorTest.cpp CursorTest.cpp
: be [ TargetLibstdc++ ] [ TargetLibsupc++ ] : be [ TargetLibstdc++ ] [ TargetLibsupc++ ]
; ;
Application CursorBitmapTest :
CursorBitmapTest.cpp
: be [ TargetLibstdc++ ] [ TargetLibsupc++ ]
;
if $(TARGET_PLATFORM) = libbe_test { if $(TARGET_PLATFORM) = libbe_test {
HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : CursorTest HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : CursorTest
: tests!apps ; : tests!apps ;