Skip to content

Commit b2bde9b

Browse files
committed
The asynchronous widget redraw is now handled by an Event::Draw, which calls FApplication::onDraw()
1 parent 0ad6f1a commit b2bde9b

10 files changed

Lines changed: 86 additions & 17 deletions

File tree

‎ChangeLog‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
2026-10-06 Markus Gans <guru.mail@muenster.de>
2+
* The asynchronous widget redraw is now handled by an Event::Draw,
3+
which calls FApplication::onDraw()
4+
15
2026-09-23 Markus Gans <guru.mail@muenster.de>
26
* Widget redraw() now runs asynchronously in the main event loop to
37
prevent blocking event processing

‎doc/event-processing.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ enum class Event : uInt8
8282
WindowLowered, // Lower window
8383
Accelerator, // Keyboard accelerator
8484
Resize, // Terminal resize
85+
Draw, // Widget redraw
8586
Show, // Widget is shown
8687
Hide, // Widget is hidden
8788
Close, // Widget close

‎examples/choice.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* *
44
* This file is part of the FINAL CUT widget toolkit *
55
* *
6-
* Copyright 2017-2022 Markus Gans *
6+
* Copyright 2017-2026 Markus Gans *
77
* *
88
* FINAL CUT is free software; you can redistribute it and/or modify *
99
* it under the terms of the GNU Lesser General Public License as *
@@ -132,8 +132,8 @@ auto main (int argc, char* argv[]) -> int
132132
preset(os);
133133

134134
// Scroll to the focused child element
135-
finalcut::FFocusEvent cfi (finalcut::Event::ChildFocusIn);
136-
app.queueEvent(&checkButtonGroup, &cfi);
135+
auto cfi = std::make_unique<finalcut::FFocusEvent>(finalcut::Event::ChildFocusIn);
136+
app.queueEvent(&checkButtonGroup, std::move(cfi));
137137

138138
// Create a OK button
139139
finalcut::FButton ok("&OK", &dgl);

‎final/fapplication.cpp‎

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,14 @@ auto FApplication::sendEvent (FObject* receiver, FEvent* event ) -> bool
251251
}
252252

253253
//----------------------------------------------------------------------
254-
void FApplication::queueEvent (FObject* receiver, FEvent* event)
254+
void FApplication::queueEvent (FObject* receiver, std::unique_ptr<FEvent>&& event)
255255
{
256-
if ( ! (bool(receiver) && bool(event)) )
256+
if ( ! (bool(receiver) && bool(event.get())) )
257257
return;
258258

259259
// queue this event
260260
setQueued(*event);
261-
event_queue.emplace_back (receiver, event);
261+
event_queue.emplace_back (receiver, std::move(event));
262262
}
263263

264264
//----------------------------------------------------------------------
@@ -268,7 +268,7 @@ void FApplication::sendQueuedEvents()
268268
{
269269
const auto& event_pair = event_queue.front();
270270
setQueued(*event_pair.second, false);
271-
sendEvent(event_pair.first, event_pair.second);
271+
sendEvent(event_pair.first, event_pair.second.get());
272272
event_queue.pop_front();
273273
}
274274
}
@@ -285,10 +285,7 @@ auto FApplication::eventInQueue() const -> bool
285285
//----------------------------------------------------------------------
286286
auto FApplication::removeQueuedEvent (const FObject* receiver) -> bool
287287
{
288-
if ( ! eventInQueue() )
289-
return false;
290-
291-
if ( ! receiver )
288+
if ( ! receiver || ! eventInQueue() )
292289
return false;
293290

294291
bool retval{false};
@@ -313,6 +310,31 @@ void FApplication::queueDraw (FWidget* widget)
313310
{
314311
// Queue the widget for redrawing
315312
draw_queue.push_back(widget);
313+
314+
// We only need one draw event to redraw all the widgets in the queue
315+
if ( need_widget_redraw )
316+
return;
317+
318+
need_widget_redraw = true;
319+
320+
auto ev = std::make_unique<FEvent>(Event::Draw);
321+
FApplication::queueEvent(this, std::move(ev));
322+
}
323+
324+
//----------------------------------------------------------------------
325+
auto FApplication::removeQueuedDraw (const FWidget* widget) -> bool
326+
{
327+
if ( ! widget || draw_queue.empty() )
328+
return false;
329+
330+
const auto queue_end = draw_queue.end();
331+
const auto last = std::remove (draw_queue.begin(), queue_end, widget);
332+
draw_queue.erase(last, queue_end);
333+
334+
if ( draw_queue.empty() )
335+
need_widget_redraw = false;
336+
337+
return true;
316338
}
317339

318340
//----------------------------------------------------------------------
@@ -425,6 +447,30 @@ void FApplication::processExternalUserEvent()
425447
// This method can be overloaded and replaced by own code
426448
}
427449

450+
//----------------------------------------------------------------------
451+
auto FApplication::event (FEvent* ev) -> bool
452+
{
453+
const auto event_type = ev->getType();
454+
455+
if ( event_type == Event::Draw )
456+
{
457+
onDraw (ev);
458+
return true;
459+
}
460+
461+
return FWidget::event(ev);
462+
}
463+
464+
//----------------------------------------------------------------------
465+
void FApplication::onDraw (FEvent*)
466+
{
467+
// This event handler can be reimplemented in a subclass
468+
// to receive draw events
469+
470+
processRedraw();
471+
need_widget_redraw = false;
472+
}
473+
428474

429475
// private methods of FApplication
430476
//----------------------------------------------------------------------
@@ -1378,7 +1424,7 @@ void FApplication::processRedraw()
13781424
// Sort the queue by hierarchy depth
13791425
std::sort ( processing_queue.begin()
13801426
, processing_queue.end()
1381-
, [] (FWidget* lhs, FWidget* rhs)
1427+
, [] (const FWidget* lhs, const FWidget* rhs)
13821428
{
13831429
return lhs->getDepth() < rhs->getDepth();
13841430
} );
@@ -1445,7 +1491,6 @@ auto FApplication::processNextEvent() -> bool
14451491
processResizeEvent(); // when the terminal size has changed
14461492
processDialogResizeMove();
14471493
sendQueuedEvents();
1448-
processRedraw();
14491494
processTerminalUpdate(); // for changed regions on the terminal
14501495
flush(); // Flush output buffer (via an instance of FOutput)
14511496
processLogger();

‎final/fapplication.h‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,12 @@ class FApplication : public FWidget
142142
static void exit (int = EXIT_SUCCESS);
143143
void quit() const;
144144
static auto sendEvent (FObject*, FEvent*) -> bool;
145-
void queueEvent (FObject*, FEvent*);
145+
void queueEvent (FObject*, std::unique_ptr<FEvent>&&);
146146
void sendQueuedEvents();
147147
auto eventInQueue() const -> bool;
148148
auto removeQueuedEvent (const FObject*) -> bool;
149149
void queueDraw (FWidget*);
150+
auto removeQueuedDraw (const FWidget*) -> bool;
150151
void registerMouseHandler (const FMouseHandler&);
151152
void initTerminal() override;
152153
static void setDefaultTheme();
@@ -161,10 +162,14 @@ class FApplication : public FWidget
161162
protected:
162163
virtual void processExternalUserEvent();
163164

165+
// Event handlers
166+
auto event (FEvent*) -> bool override;
167+
virtual void onDraw (FEvent*);
168+
164169
private:
165170
// Using-declaration
166171
using CmdOption = struct option;
167-
using EventPair = std::pair<FObject*, FEvent*>;
172+
using EventPair = std::pair<FObject*, std::unique_ptr<FEvent>>;
168173
using FEventQueue = std::deque<EventPair>;
169174
using FDrawQueue = std::vector<FWidget*>;
170175
using FMouseHandlerList = std::vector<FMouseHandler>;
@@ -249,6 +254,7 @@ class FApplication : public FWidget
249254
FDrawQueue draw_queue{};
250255
FMouseHandlerList mouse_handler_list{};
251256
bool has_terminal_resized{false};
257+
bool need_widget_redraw{false};
252258
static uInt64 next_event_wait;
253259
static TimeValue time_last_event;
254260
static rdbuf default_clog_rdbuf;

‎final/fc.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ enum class Event : uInt8
7575
WindowLowered, // Lower window
7676
Accelerator, // Keyboard accelerator
7777
Resize, // Terminal resize
78+
Draw, // Widget redraw
7879
Show, // Widget is shown
7980
Hide, // Widget is hidden
8081
Close, // Widget close

‎final/fobject.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ auto FObject::getDepth() const noexcept -> std::size_t
9999
depth++;
100100
}
101101

102-
return depth; // 0 means it has no parent (root object)
102+
return depth; // 0 means it has no parent (root object)
103103
}
104104

105105
//----------------------------------------------------------------------

‎final/fwidget.cpp‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ FWidget::~FWidget() // destructor
112112
processDestroy();
113113
delCallback();
114114
removeQueuedEvent();
115+
removeQueuedDraw();
115116

116117
// unset clicked widget
117118
if ( this == getClickedWidget() )
@@ -1516,7 +1517,7 @@ inline void FWidget::mapKeyEvents()
15161517
{ Event::KeyDown,
15171518
[this] (FEvent* ev)
15181519
{
1519-
KeyDownEvent(static_cast<FKeyEvent*>(ev));
1520+
KeyDownEvent (static_cast<FKeyEvent*>(ev));
15201521
}
15211522
}
15221523
} );
@@ -2279,6 +2280,15 @@ void FWidget::removeQueuedEvent() const
22792280
app_object->removeQueuedEvent(this);
22802281
}
22812282

2283+
//----------------------------------------------------------------------
2284+
void FWidget::removeQueuedDraw() const
2285+
{
2286+
auto app_object = FApplication::getApplicationObject();
2287+
2288+
if ( app_object )
2289+
app_object->removeQueuedDraw(this);
2290+
}
2291+
22822292
//----------------------------------------------------------------------
22832293
void FWidget::setStatusBarText (bool enable) const
22842294
{

‎final/fwidget.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ class FWidget : public FVTerm
484484
static auto isDefaultTheme() -> bool;
485485
static void initColorTheme();
486486
void removeQueuedEvent() const;
487+
void removeQueuedDraw() const;
487488
void setStatusBarText (bool = true) const;
488489

489490
// Data members

‎test/fwidget-test.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,7 @@ void FWidgetTest::noArgumentTest()
792792
CPPUNIT_ASSERT ( wdgt.getFlags().feature.minimizable == false );
793793
CPPUNIT_ASSERT ( wdgt.getFlags().visibility.modal == false );
794794
CPPUNIT_ASSERT ( wdgt.getFlags().visibility.visible_cursor == false );
795+
CPPUNIT_ASSERT ( ! wdgt.needsRedraw() );
795796
CPPUNIT_ASSERT ( wdgt.getFlags().visibility.needs_redraw == false );
796797
CPPUNIT_ASSERT ( ! wdgt.hasVisibleCursor() );
797798
CPPUNIT_ASSERT ( wdgt.getFlags().type.window_widget == false );

0 commit comments

Comments
 (0)