mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
pgui: fix deadlock in PGScrollFrame/PGSliderBar
This commit is contained in:
parent
670047b4b0
commit
cf4f8b35b6
@ -19,19 +19,18 @@ TypeHandle PGScrollFrame::_type_handle;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
PGScrollFrame::
|
PGScrollFrame::
|
||||||
PGScrollFrame(const std::string &name) : PGVirtualFrame(name)
|
PGScrollFrame(const std::string &name) :
|
||||||
|
PGVirtualFrame(name),
|
||||||
|
_needs_remanage(false),
|
||||||
|
_needs_recompute_clip(false),
|
||||||
|
_has_virtual_frame(false),
|
||||||
|
_virtual_frame(0.0f, 0.0f, 0.0f, 0.0f),
|
||||||
|
_manage_pieces(false),
|
||||||
|
_auto_hide(false)
|
||||||
{
|
{
|
||||||
set_cull_callback();
|
_canvas_computed.test_and_set();
|
||||||
|
|
||||||
_needs_remanage = false;
|
set_cull_callback();
|
||||||
_needs_recompute_canvas = false;
|
|
||||||
_needs_recompute_clip = false;
|
|
||||||
_has_virtual_frame = false;
|
|
||||||
_virtual_frame.set(0.0f, 0.0f, 0.0f, 0.0f);
|
|
||||||
_manage_pieces = false;
|
|
||||||
_auto_hide = false;
|
|
||||||
_horizontal_slider = nullptr;
|
|
||||||
_vertical_slider = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,8 +54,8 @@ PGScrollFrame(const PGScrollFrame ©) :
|
|||||||
_auto_hide(copy._auto_hide)
|
_auto_hide(copy._auto_hide)
|
||||||
{
|
{
|
||||||
_needs_remanage = false;
|
_needs_remanage = false;
|
||||||
_needs_recompute_canvas = true;
|
|
||||||
_needs_recompute_clip = true;
|
_needs_recompute_clip = true;
|
||||||
|
_canvas_computed.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +96,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||||||
if (_needs_recompute_clip) {
|
if (_needs_recompute_clip) {
|
||||||
recompute_clip();
|
recompute_clip();
|
||||||
}
|
}
|
||||||
if (_needs_recompute_canvas) {
|
if (!_canvas_computed.test_and_set()) {
|
||||||
recompute_canvas();
|
recompute_canvas();
|
||||||
}
|
}
|
||||||
return PGVirtualFrame::cull_callback(trav, data);
|
return PGVirtualFrame::cull_callback(trav, data);
|
||||||
@ -257,7 +256,7 @@ remanage() {
|
|||||||
// Showing or hiding one of the scroll bars might have set this flag again
|
// Showing or hiding one of the scroll bars might have set this flag again
|
||||||
// indirectly; we clear it again to avoid a feedback loop.
|
// indirectly; we clear it again to avoid a feedback loop.
|
||||||
_needs_remanage = false;
|
_needs_remanage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are either or both of the scroll bars hidden?
|
// Are either or both of the scroll bars hidden?
|
||||||
if (got_horizontal && _horizontal_slider->is_overall_hidden()) {
|
if (got_horizontal && _horizontal_slider->is_overall_hidden()) {
|
||||||
@ -329,19 +328,20 @@ item_draw_mask_changed(PGItem *) {
|
|||||||
*/
|
*/
|
||||||
void PGScrollFrame::
|
void PGScrollFrame::
|
||||||
slider_bar_adjust(PGSliderBar *) {
|
slider_bar_adjust(PGSliderBar *) {
|
||||||
LightReMutexHolder holder(_lock);
|
// Indicate that recompute_canvas() needs to be called.
|
||||||
_needs_recompute_canvas = true;
|
_canvas_computed.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recomputes the clipping window of the PGScrollFrame, based on the position
|
* Recomputes the clipping window of the PGScrollFrame, based on the position
|
||||||
* of the slider bars.
|
* of the slider bars.
|
||||||
|
*
|
||||||
|
* Assumes the lock is held.
|
||||||
*/
|
*/
|
||||||
void PGScrollFrame::
|
void PGScrollFrame::
|
||||||
recompute_clip() {
|
recompute_clip() {
|
||||||
LightReMutexHolder holder(_lock);
|
|
||||||
_needs_recompute_clip = false;
|
_needs_recompute_clip = false;
|
||||||
_needs_recompute_canvas = true;
|
_canvas_computed.clear();
|
||||||
|
|
||||||
// Figure out how to remove the scroll bars from the clip region.
|
// Figure out how to remove the scroll bars from the clip region.
|
||||||
LVecBase4 clip = get_frame_style(get_state()).get_internal_frame(get_frame());
|
LVecBase4 clip = get_frame_style(get_state()).get_internal_frame(get_frame());
|
||||||
@ -361,34 +361,40 @@ recompute_clip() {
|
|||||||
/**
|
/**
|
||||||
* Recomputes the portion of the virtual canvas that is visible within the
|
* Recomputes the portion of the virtual canvas that is visible within the
|
||||||
* PGScrollFrame, based on the values of the slider bars.
|
* PGScrollFrame, based on the values of the slider bars.
|
||||||
|
*
|
||||||
|
* Assumes the lock is held.
|
||||||
*/
|
*/
|
||||||
void PGScrollFrame::
|
void PGScrollFrame::
|
||||||
recompute_canvas() {
|
recompute_canvas() {
|
||||||
LightReMutexHolder holder(_lock);
|
const LVecBase4 &clip = _has_clip_frame ? _clip_frame : get_frame();
|
||||||
_needs_recompute_canvas = false;
|
|
||||||
|
|
||||||
const LVecBase4 &clip = get_clip_frame();
|
// Set this to true before we sample the slider bar ratios.
|
||||||
|
// If slider_bar_adjust happens to get called while we do this, no big deal,
|
||||||
|
// this method will just be called again next frame.
|
||||||
|
_canvas_computed.test_and_set();
|
||||||
|
|
||||||
PN_stdfloat x = interpolate_canvas(clip[0], clip[1],
|
PN_stdfloat cx, cy;
|
||||||
|
cx = interpolate_canvas(clip[0], clip[1],
|
||||||
_virtual_frame[0], _virtual_frame[1],
|
_virtual_frame[0], _virtual_frame[1],
|
||||||
_horizontal_slider);
|
_horizontal_slider);
|
||||||
|
|
||||||
PN_stdfloat y = interpolate_canvas(clip[3], clip[2],
|
cy = interpolate_canvas(clip[3], clip[2],
|
||||||
_virtual_frame[3], _virtual_frame[2],
|
_virtual_frame[3], _virtual_frame[2],
|
||||||
_vertical_slider);
|
_vertical_slider);
|
||||||
|
|
||||||
get_canvas_node()->set_transform(TransformState::make_pos(LVector3::rfu(x, 0, y)));
|
_canvas_node->set_transform(TransformState::make_pos(LVector3::rfu(cx, 0, cy)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the linear translation that should be applied to the virtual
|
* Computes the linear translation that should be applied to the virtual
|
||||||
* canvas node, based on the corresponding slider bar's position.
|
* canvas node, based on the corresponding slider bar's position.
|
||||||
|
*
|
||||||
|
* Assumes the lock is held.
|
||||||
*/
|
*/
|
||||||
PN_stdfloat PGScrollFrame::
|
PN_stdfloat PGScrollFrame::
|
||||||
interpolate_canvas(PN_stdfloat clip_min, PN_stdfloat clip_max,
|
interpolate_canvas(PN_stdfloat clip_min, PN_stdfloat clip_max,
|
||||||
PN_stdfloat canvas_min, PN_stdfloat canvas_max,
|
PN_stdfloat canvas_min, PN_stdfloat canvas_max,
|
||||||
PGSliderBar *slider_bar) {
|
PGSliderBar *slider_bar) {
|
||||||
LightReMutexHolder holder(_lock);
|
|
||||||
PN_stdfloat t = 0.0f;
|
PN_stdfloat t = 0.0f;
|
||||||
if (slider_bar != nullptr) {
|
if (slider_bar != nullptr) {
|
||||||
t = slider_bar->get_ratio();
|
t = slider_bar->get_ratio();
|
||||||
|
@ -20,6 +20,10 @@
|
|||||||
#include "pgSliderBarNotify.h"
|
#include "pgSliderBarNotify.h"
|
||||||
#include "pgSliderBar.h"
|
#include "pgSliderBar.h"
|
||||||
|
|
||||||
|
#ifdef PHAVE_ATOMIC
|
||||||
|
#include <atomic>
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a special kind of frame that pretends to be much larger than it
|
* This is a special kind of frame that pretends to be much larger than it
|
||||||
* actually is. You can scroll through the frame, as if you're looking
|
* actually is. You can scroll through the frame, as if you're looking
|
||||||
@ -92,7 +96,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
bool _needs_remanage;
|
bool _needs_remanage;
|
||||||
bool _needs_recompute_clip;
|
bool _needs_recompute_clip;
|
||||||
bool _needs_recompute_canvas;
|
std::atomic_flag _canvas_computed;
|
||||||
|
|
||||||
bool _has_virtual_frame;
|
bool _has_virtual_frame;
|
||||||
LVecBase4 _virtual_frame;
|
LVecBase4 _virtual_frame;
|
||||||
|
@ -72,7 +72,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void setup_child_nodes();
|
void setup_child_nodes();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
bool _has_clip_frame;
|
bool _has_clip_frame;
|
||||||
LVecBase4 _clip_frame;
|
LVecBase4 _clip_frame;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user