mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-10-31 15:20:13 +00:00
a29bfe9c42
Fixes: https://github.com/dankamongmen/notcurses/issues/1009 Whenever a widget is created with its `*_create` function it currently claims full ownership of the passed panel, including its destruction. However, the C++ wrapper around the panel is not aware of this and will attempt to destroy the native panel in the destructor, leading to segfaults. Fix this by introduction of a `Widget` class which contains the logic to properly modify the `Panel` instance to not double-destroy the native panel. The solution is a bit fragile since the `Panel` instance is left intact (we can't free it for the user) in a state that's safe for the C++ wrapper, but calling any C function via the wrapper **will** pass a `NULL` pointer in the panel argument - therefore the C functions MUST be proofed against this. The proofing belongs in the C backend code since this protects also C and other language binding users from such abuse. The Widget class will first verify that the passed `Plane` instance hasn't already been "disowned" and will throw an exception to the effect if it was. Next, it will proceed to take over ownership of the native panel instance and mark the passed `Panel` as "invalid" (i.e. not owning any native panel instance anymore) The above changes require modification of `Panel` instances and so all the widget constructors taking `const*` or `const&` have been removed from widget classes.
97 lines
2.1 KiB
C++
97 lines
2.1 KiB
C++
#ifndef __NCPP_READER_HH
|
|
#define __NCPP_READER_HH
|
|
|
|
#include <notcurses/notcurses.h>
|
|
|
|
#include "NCAlign.hh"
|
|
#include "Plane.hh"
|
|
#include "Utilities.hh"
|
|
#include "Widget.hh"
|
|
|
|
namespace ncpp
|
|
{
|
|
class NCPP_API_EXPORT Reader : public Widget
|
|
{
|
|
public:
|
|
explicit Reader (Plane *plane, const ncreader_options *opts)
|
|
: Widget (Utilities::get_notcurses_cpp (plane))
|
|
{
|
|
ensure_valid_plane (plane);
|
|
common_init (Utilities::to_ncplane (plane), opts);
|
|
take_plane_ownership (plane);
|
|
}
|
|
|
|
explicit Reader (Plane &plane, const ncreader_options *opts)
|
|
: Widget (Utilities::get_notcurses_cpp (plane))
|
|
{
|
|
ensure_valid_plane (plane);
|
|
common_init (Utilities::to_ncplane (plane), opts);
|
|
take_plane_ownership (plane);
|
|
}
|
|
|
|
~Reader ()
|
|
{
|
|
if (!is_notcurses_stopped ())
|
|
ncreader_destroy (reader, nullptr);
|
|
}
|
|
|
|
bool clear () const NOEXCEPT_MAYBE
|
|
{
|
|
bool ret = ncreader_clear (reader) != 0;
|
|
return error_guard_cond<bool, bool> (ret, ret);
|
|
}
|
|
|
|
//
|
|
// None of the move* methods should throw since their return value (0 - moved, -1 - not moved) appear to be
|
|
// purely informational, not errors per se. If we had `can_move*` functions then `move*` could throw exceptions,
|
|
// potentially.
|
|
//
|
|
int move_left () const noexcept
|
|
{
|
|
return ncreader_move_left (reader);
|
|
}
|
|
|
|
int move_right () const noexcept
|
|
{
|
|
return ncreader_move_right (reader);
|
|
}
|
|
|
|
int move_up () const noexcept
|
|
{
|
|
return ncreader_move_up (reader);
|
|
}
|
|
|
|
int move_down () const noexcept
|
|
{
|
|
return ncreader_move_down (reader);
|
|
}
|
|
|
|
bool write_egc (const char *egc) const NOEXCEPT_MAYBE
|
|
{
|
|
return error_guard (ncreader_write_egc (reader, egc), -1);
|
|
}
|
|
|
|
char* get_contents () const noexcept
|
|
{
|
|
return ncreader_contents(reader);
|
|
}
|
|
|
|
Plane* get_plane () const noexcept
|
|
{
|
|
return Plane::map_plane (ncreader_plane (reader));
|
|
}
|
|
|
|
private:
|
|
void common_init (ncplane *n, const ncreader_options *opts)
|
|
{
|
|
reader = ncreader_create (n, opts);
|
|
if (reader == nullptr)
|
|
throw init_error ("Notcurses failed to create a new reader");
|
|
}
|
|
|
|
private:
|
|
ncreader *reader;
|
|
};
|
|
}
|
|
#endif
|