FINAL CUT
fvterm.h
1 /***********************************************************************
2 * fvterm.h - Virtual terminal implementation *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2016-2026 Markus Gans *
7 * *
8 * FINAL CUT is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as *
10 * published by the Free Software Foundation; either version 3 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * FINAL CUT is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this program. If not, see *
20 * <http://www.gnu.org/licenses/>. *
21 ***********************************************************************/
22 
23 /* Inheritance diagram
24  * ═══════════════════
25  *
26  * ▕▔▔▔▔▔▔▔▔▔▏1 *▕▔▔▔▔▔▔▔▏
27  * ▕ FVTerm ▏- - -┬- - -▕ FTerm ▏
28  * ▕▁▁▁▁▁▁▁▁▁▏ : ▕▁▁▁▁▁▁▁▏
29  * :
30  * : *▕▔▔▔▔▔▔▔▔▔▏
31  * :- - -▕ FString ▏
32  * : ▕▁▁▁▁▁▁▁▁▁▏
33  * :
34  * : *▕▔▔▔▔▔▔▔▔▏
35  * └- - -▕ FPoint ▏
36  * : ▕▁▁▁▁▁▁▁▁▏
37  * :
38  * : *▕▔▔▔▔▔▔▔▏
39  * └- - -▕ FRect ▏
40  * ▕▁▁▁▁▁▁▁▏
41  */
42 
43 #ifndef FVTERM_H
44 #define FVTERM_H
45 
46 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
47  #error "Only <final/final.h> can be included directly."
48 #endif
49 
50 #include <sys/time.h> // need for timeval (cygwin)
51 
52 #include <algorithm>
53 #include <memory>
54 #include <mutex>
55 #include <string>
56 #include <tuple>
57 #include <utility>
58 #include <vector>
59 
60 #include "final/fc.h"
61 #include "final/output/tty/fterm_functions.h"
62 #include "final/util/fdata.h"
63 #include "final/util/fpoint.h"
64 #include "final/util/frect.h"
65 #include "final/util/fsize.h"
66 #include "final/util/fstringstream.h"
67 #include "final/vterm/fvtermattribute.h"
68 #include "final/vterm/fvtermbuffer.h"
69 
70 #define F_PREPROC_HANDLER(i,h) \
71  reinterpret_cast<FVTerm*>((i)), \
72  std::bind ( reinterpret_cast<FVTerm::FPreprocessingHandler>((h)) \
73  , reinterpret_cast<FVTerm*>((i)) )
74 
75 namespace finalcut
76 {
77 
78 // class forward declaration
79 class FColorPair;
80 class FOutput;
81 class FSize;
82 class FString;
83 class FStyle;
84 class FVTermBuffer;
85 class FWidget;
86 
87 template <typename FOutputType>
89 {
90  using type = std::remove_cv_t<FOutputType>;
91 };
92 
93 //----------------------------------------------------------------------
94 // class FVTerm
95 //----------------------------------------------------------------------
96 
97 class FVTerm : public FVTermAttribute
98 {
99  public:
100  struct FTermRegion; // forward declaration
101  struct FVTermPreprocessing; // forward declaration
102 
103  // Using-declarations
104  using FVTermAttribute::print;
105  using FCharVector = std::vector<FChar>;
106  using FPreprocessingHandler = void (FVTerm::*)();
107  using FPreprocessingFunction = std::function<void()>;
108  using FPreprocVector = std::vector<std::unique_ptr<FVTermPreprocessing>>;
109  using FVTermList = std::vector<FVTerm*>;
110  using FTermRegionList = std::vector<const FTermRegion*>;
111 
112  // Enumeration
113  enum class TerminalUpdate : uInt8
114  {
115  Stop, // No terminal refresh
116  Continue, // Resuming terminal refresh
117  Start // Allowing terminal refresh
118  };
119 
120  // Disable copy constructor
121  FVTerm (const FVTerm&) = delete;
122 
123  // Disable move constructor
124  FVTerm (FVTerm&&) noexcept = delete;
125 
126  // Constructor
127  FVTerm();
128 
129  template <typename FOutputType>
130  explicit FVTerm (outputClass<FOutputType>);
131 
132  // Disable copy assignment operator (=)
133  auto operator = (const FVTerm&) -> FVTerm& = delete;
134 
135  // Disable move assignment operator (=)
136  auto operator = (FVTerm&&) noexcept -> FVTerm& = delete;
137 
138  // Destructor
139  ~FVTerm() override;
140 
141  // Overloaded operators
142  template <typename NumT
143  , enable_if_arithmetic_without_char_t<NumT> = nullptr>
144  auto operator << (const NumT&) noexcept -> FVTerm&;
145 
146  template <typename CharT
147  , enable_if_CString_t<CharT> = nullptr>
148  auto operator << (const CharT&) noexcept -> FVTerm&;
149  auto operator << (char) noexcept -> FVTerm&;
150  auto operator << (wchar_t) noexcept -> FVTerm&;
151  auto operator << (const wchar_t*) noexcept -> FVTerm&;
152  auto operator << (const UniChar&) noexcept -> FVTerm&;
153  auto operator << (const std::string&) noexcept -> FVTerm&;
154  auto operator << (const std::wstring&) noexcept -> FVTerm&;
155  auto operator << (const FString&) noexcept -> FVTerm&;
156  auto operator << (FVTermBuffer&) noexcept -> FVTerm&;
157  auto operator << (const FVTermBuffer&) noexcept -> FVTerm&;
158  auto operator << (const FChar&) noexcept -> FVTerm&;
159  auto operator << (const FCharVector&) noexcept -> FVTerm&;
160  auto operator << (const FPoint&) noexcept -> FVTerm&;
161  auto operator << (const FStyle&) noexcept -> FVTerm&;
162  auto operator << (const FColorPair&) noexcept -> FVTerm&;
163 
164  // Accessors
165  auto getClassName() const -> FString override;
166  static auto getFOutput() -> std::shared_ptr<FOutput>;
167  auto getVWin() noexcept -> FTermRegion*;
168  auto getVWin() const noexcept -> const FTermRegion*;
169  auto getPrintCursor() -> FPoint;
170  static auto getWindowList() noexcept -> FVTermList*;
171 
172  // Mutators
173  void setTerminalUpdates (TerminalUpdate) const;
174  void setCursor (const FPoint&) noexcept;
175  void setVWin (std::unique_ptr<FTermRegion>&&) noexcept;
176  static void setNonBlockingRead (bool = true);
177  static void unsetNonBlockingRead();
178 
179  // Predicates
180  static auto isDrawingFinished() noexcept -> bool;
181  static auto isTerminalUpdateForced() noexcept -> bool;
182  static auto areTerminalUpdatesPaused() noexcept -> bool;
183  static auto hasPendingTerminalUpdates() noexcept -> bool;
184  auto hasPreprocessingHandler (const FVTerm*) noexcept -> bool;
185 
186  // Methods
187  virtual void clearRegion (wchar_t = L' ');
188  void createVDesktop (const FSize& size) noexcept;
189  void createVTerm (const FSize&) noexcept;
190  void resizeVTerm (const FSize&) const noexcept;
191  void putVTerm() const;
192  auto updateTerminal() const -> bool;
193  static void reduceTerminalLineUpdates (uInt);
194  virtual void addPreprocessingHandler ( const FVTerm*
195  , FPreprocessingFunction&& );
196  virtual void delPreprocessingHandler (const FVTerm*);
197  template <typename... Args>
198  auto printf (const FString&, Args&&...) -> int;
199  auto print (const FString&) noexcept -> int;
200  auto print (FTermRegion*, const FString&) noexcept -> int;
201  auto print (const std::vector<FChar>&) noexcept -> int;
202  auto print (FTermRegion*, const std::vector<FChar>&) noexcept -> int;
203  auto print (FVTermBuffer&) noexcept -> int;
204  auto print (const FVTermBuffer&) noexcept -> int;
205  auto print (FTermRegion*, FVTermBuffer&) const noexcept -> int;
206  auto print (FTermRegion*, const FVTermBuffer&) const noexcept -> int;
207  auto print (wchar_t) noexcept -> int;
208  auto print (FTermRegion*, wchar_t) noexcept -> int;
209  auto print (const FChar&) noexcept -> int;
210  auto print (FTermRegion*, const FChar&) const noexcept -> int;
211  virtual void print (const FPoint&);
212  auto print() noexcept -> FVTerm&;
213  void flush() const;
214 
215  protected:
216  // Using-declaration
217  using FChar_iterator = std::vector<FChar>::iterator;
218  using FChar_const_iterator = std::vector<FChar>::const_iterator;
219 
220  struct FShadowBox
221  {
222  FRect box{};
223  FSize shadow{};
224  };
225 
226  // Accessor
227  virtual auto getPrintRegion() -> FTermRegion*;
228  auto getChildPrintRegion() const noexcept -> FTermRegion*;
229  auto getCurrentPrintRegion() const noexcept -> FTermRegion*;
230  auto getVirtualDesktop() const noexcept -> FTermRegion*;
231  auto getVirtualTerminal() const noexcept -> FTermRegion*;
232 
233  // Mutators
234  void setPrintRegion (FTermRegion*) noexcept;
235  void setChildPrintRegion (FTermRegion*) noexcept;
236  void setActiveRegion (FTermRegion*) const noexcept;
237 
238  // Predicates
239  auto isActive (const FTermRegion*) const noexcept -> bool;
240  auto hasPrintRegion() const noexcept -> bool;
241  auto hasChildPrintRegion() const noexcept -> bool;
242  auto isVirtualWindow() const noexcept -> bool;
243  auto isCursorHideable() const noexcept -> bool;
244 
245  // Methods
246  auto createRegion (const FShadowBox&) -> std::unique_ptr<FTermRegion>;
247  auto createRegion (const FRect&) -> std::unique_ptr<FTermRegion>;
248  void resizeRegion (const FShadowBox&, FTermRegion*) const;
249  void resizeRegion (const FRect&, FTermRegion*) const;
250  void restoreVTerm (const FRect&) const noexcept;
251  auto updateVTermCursor (const FTermRegion*) const noexcept -> bool;
252  void hideVTermCursor() const noexcept;
253  void setRegionCursor (const FPoint&, bool, FTermRegion*) const noexcept;
254  void getRegion (const FPoint&, FTermRegion*) const noexcept;
255  void getRegion (const FRect&, FTermRegion*) const noexcept;
256  void addLayer (FTermRegion*) const noexcept;
257  void putRegion (const FPoint&, FTermRegion*) const noexcept;
258  void copyRegion (FTermRegion*, const FPoint&, FTermRegion*) const noexcept;
259  static auto getLayer (FVTerm&) noexcept -> int;
260  static void determineWindowLayers() noexcept;
261  void scrollRegionForward (FTermRegion*);
262  void scrollRegionReverse (FTermRegion*);
263  void clearRegion (FTermRegion*, wchar_t = L' ') noexcept;
264  void forceTerminalUpdate() const;
265  auto processTerminalUpdate() const -> bool;
266  static void startDrawing() noexcept;
267  static void finishDrawing() noexcept;
268  virtual void initTerminal();
269 
270  private:
271  struct LayerGeometry
272  {
273  int region_x;
274  int region_y;
275  int ol; // Outside-left
276  int vterm_width;
277  int vterm_height;
278  int ax; // Clipped region x (>=0)
279  int width; // Full region width
280  int height; // Effective region height (minimized or full)
281  int xmax_inside_vterm;
282  int y_start;
283  int y_end;
284  };
285 
286  struct RegionLine
287  {
288  FChar_const_iterator iter; // Source drawing region line
289  std::ptrdiff_t offset; // Source data offset
290  std::ptrdiff_t start_idx; // Start index
291  std::ptrdiff_t end_idx; // End index
292  };
293 
294  enum class NoTrans : sInt8
295  {
296  Undefined = -1,
297  Set,
298  Unset
299  };
300 
301  struct LineChanges
302  {
303  int count;
304  int ypos;
305  int xmin;
306  int xmax;
307  NoTrans has_no_transparency;
308  };
309 
310  // Constants
311  static constexpr int DEFAULT_MINIMIZED_HEIGHT = 1;
312 
313  // Enumeration
314  enum class CoveredState : uInt8
315  {
316  None,
317  Half,
318  Full
319  };
320 
321  enum class SearchState : uInt8 // Character search state
322  {
323  start, // The overlaid characters are not parsed
324  printable, // Search for a printable character
325  overlay, // Search for the next printable character for color overlay
326  background, // Search for the next printable character to inherit the background color
327  ready // Overlaid character was fully printed
328  };
329 
330  // Using-declaration
331  using FOverlaySearchBuffer = std::vector<SearchState>;
332  using FOverlayLineBuffer = std::vector<RegionLine>;
333  using FLineChangesBatch = std::vector<LineChanges>;
334 
335  // Methods
336  static void setGlobalFVTermInstance (FVTerm*) noexcept;
337  static auto getGlobalFVTermInstance() noexcept -> FVTerm*&;
338  static auto isInitialized() noexcept -> bool;
339  void resetRegionEncoding() const;
340  void resetTextRegionToDefault (FTermRegion*, const FSize&) const noexcept;
341  auto resizeTextRegion (FTermRegion*, std::size_t, std::size_t ) const -> bool;
342  auto resizeTextRegion (FTermRegion*, std::size_t) const -> bool;
343  auto isCovered (const FPoint&, const FTermRegion*) const noexcept -> CoveredState;
344  auto isRegionValid (const FShadowBox&) const noexcept -> bool;
345  auto isSizeEqual (const FTermRegion*, const FShadowBox&) const noexcept -> bool;
346  constexpr auto needsHeightResize (const FTermRegion*, const std::size_t) const noexcept -> bool;
347  constexpr auto needsWidthResize (const FTermRegion*, const std::size_t) const noexcept -> bool;
348  auto tryResizeRegion (FTermRegion*, const std::size_t, const std::size_t) const -> bool;
349  void updateRegionProperties (FTermRegion*, const FShadowBox&) const noexcept;
350  constexpr auto getFullRegionWidth (const FTermRegion*) const noexcept -> int;
351  constexpr auto getFullRegionHeight (const FTermRegion*) const noexcept -> int;
352  void passChangesToOverlap (const FTermRegion*) const;
353  void processOverlappingWindows (const FTermRegion*, const FVTermList&) const;
354  void passChangesToOverlappingWindow (FTermRegion*, const FTermRegion*) const noexcept;
355  void passChangesToOverlappingWindowLine (FTermRegion*, int, const FTermRegion*) const noexcept;
356  auto calculateStartCoordinate (int, int) const noexcept -> int;
357  auto calculateEndCoordinate (int, int, int, int) const noexcept -> int;
358  void updateVTerm() const;
359  void updateVTermDesktop() const;
360  void updateVTermWindow (FTermRegion*) const;
361  auto computeLayerGeometry (const FTermRegion*) const noexcept -> LayerGeometry;
362  auto isLayerOutsideVTerm (const LayerGeometry&) const noexcept -> bool;
363  void buildLineChangeBatch (const FTermRegion*, const LayerGeometry&) const noexcept;
364  void applyLineBatch (FTermRegion*, const LayerGeometry&) const noexcept;
365  void updateVTermChangesFromBatch (const LayerGeometry&) const noexcept;
366  void scrollTerminalForward() const;
367  void scrollTerminalReverse() const;
368  void callPreprocessingHandler (const FTermRegion*) const;
369  auto hasChildRegionChanges (const FTermRegion*) const -> bool;
370  void clearChildRegionChanges (const FTermRegion*) const;
371  static constexpr auto isInsideRegion (const FPoint&, const FTermRegion*) noexcept -> bool;
372  auto isInsideTerminal (const FPoint&) const noexcept -> bool;
373  static constexpr auto isFCharTransparent (const FChar&) noexcept -> bool;
374  auto isTransparentInvisible (const FChar&) const noexcept -> bool;
375  template <typename FOutputType>
376  void init();
377  void initFromGlobalInstance();
378  void initSettings();
379  void finish() const;
380  void saveCurrentVTerm() const noexcept;
381  void putRegionLine (const FChar&, FChar&, const int) const noexcept;
382  void applyColorOverlay (const FChar&, FChar&) const;
383  void inheritBackground (const FChar&, FChar&) const;
384  void putMultiLayerRegionLine (FChar_iterator, const int, const FPoint&) const noexcept;
385  void putRegionLineWithTransparency (FChar_const_iterator, FChar_iterator, const int, FPoint, bool) const;
386  void addRegionLineWithTransparency (FChar_const_iterator, FChar_iterator, const int) const;
387  void addTransparentRegionLine (const FChar_const_iterator&, const FChar_iterator&, const int) const;
388  void addTransparentRegionChar (const FChar&, FChar&) const;
389  auto clearFullRegion (FTermRegion*, FChar&) const -> bool;
390  void clearRegionWithShadow (FTermRegion*, const FChar&) const noexcept;
391  auto printWrap (FTermRegion*, FChar_iterator&) const -> bool;
392  auto interpretControlCodes (FTermRegion*, FChar_iterator&, const FChar&) const noexcept -> bool;
393  auto printCharacter (FTermRegion*, FChar_iterator&, const FChar&) const noexcept -> int;
394  auto printCharacterOnCoordinate ( FTermRegion*
395  , const FChar_iterator&
396  , const FChar&) const noexcept -> std::size_t;
397  void printPaddingCharacter (FTermRegion*, const FChar&) const;
398  void putNonTransparent (FChar_const_iterator, FChar_iterator&, int&) const;
399  void addTransparent (FChar_const_iterator, FChar_iterator&, int&) const;
400  void addVDesktopToListIfExists (FTermRegionList&) const;
401  void determineCoveredRegions (FTermRegion*) const;
402  void resetLineCoveredState (FTermRegion*) const;
403  void determineLineCoveredState (const FTermRegion* const, FTermRegion*) const noexcept;
404  auto canUpdateTerminalNow() const -> bool;
405  static auto hasPendingUpdates (const FTermRegion*) noexcept -> bool;
406 
407  // Data members
408  FTermRegion* print_region{nullptr}; // Print region for this object
409  FTermRegion* child_print_region{nullptr}; // Print region for children
410  FVTermBuffer vterm_buffer{}; // Print buffer
411  mutable FLineChangesBatch line_changes_batch{}; // All line changes to an region
412  mutable FOverlayLineBuffer overlay_line_buffer{}; // Overlay region line buffer
413  mutable FOverlaySearchBuffer overlay_search_buffer{}; // Overlay search state buffer
414  mutable FTermRegionList covered_regions_buffer{}; // Covered overlay regions buffer
415  mutable std::mutex line_changes_batch_mutex{}; // Protects line_changes_batch_mutex
416  mutable std::mutex buffer_mutex{}; // Protects the buffers
417  FChar nc{}; // Next character
418  std::unique_ptr<FTermRegion> vwin{}; // Virtual window
419  std::shared_ptr<FOutput> foutput{}; // Terminal output class
420  std::shared_ptr<FVTermList> vterm_window_list{}; // List of all window owner in z-order
421  std::shared_ptr<FTermRegion> vterm{}; // Virtual terminal
422  std::shared_ptr<FTermRegion> vterm_old{}; // Last virtual terminal
423  std::shared_ptr<FTermRegion> vdesktop{}; // Virtual desktop
424  static FTermRegion* active_region; // Active region
425  static int tabstop;
426  static bool draw_completed;
427  static bool skip_one_vterm_update;
428  static bool no_terminal_updates;
429  static bool force_terminal_update;
430 
431  // Friend function
432  friend void setPrintRegion (FWidget&, FTermRegion*);
433  friend auto getColumnWidth (const wchar_t wchar) -> std::size_t;
434 };
435 
436 
437 //----------------------------------------------------------------------
438 // struct FVTerm::FTermRegion
439 //----------------------------------------------------------------------
440 
441 struct FVTerm::FTermRegion // Define virtual terminal character properties
442 {
444  {
445  uInt xmin; // X-position with the first change
446  uInt xmax; // X-position with the last change
447  uInt trans_count; // Number of transparent characters
448  bool covered; // Line cover state
449  };
450 
451  struct FRowChanges
452  {
453  uInt ymin; // Y-position with the first change
454  uInt ymax; // Y-position with the last change
455  };
456 
457  // Using-declaration
458  using FDataAccessPtr = std::shared_ptr<FDataAccess>;
459  using FLineChangesVec = std::vector<FLineChanges>;
460  using FCharVec = std::vector<FChar>;
461  using FChar_reference = FCharVec::reference;
462  using FChar_const_reference = FCharVec::const_reference;
463  using FChar_iterator = FCharVec::iterator;
464  using FChar_const_iterator = FCharVec::const_iterator;
465 
466  // Constructor
467  FTermRegion() = default;
468 
469  // Disable copy constructor
470  FTermRegion (const FTermRegion&) = delete;
471 
472  // Destructor
473  ~FTermRegion() = default;
474 
475  // Disable copy assignment operator (=)
476  auto operator = (const FTermRegion&) -> FTermRegion& = delete;
477 
478  template <typename T>
479  inline auto getOwner() const -> clean_fdata_t<T>&
480  {
481  return static_cast<FData<clean_fdata_t<T>>&>(*owner).get();
482  }
483 
484  template <typename T>
485  inline void setOwner (T&& obj)
486  {
487  owner = makeFData(std::forward<T>(obj));
488  }
489 
490  inline auto hasOwner() const -> bool
491  {
492  return owner.get() != nullptr;
493  }
494 
495  constexpr auto contains (int, int) const noexcept -> bool;
496 
497  constexpr auto contains (const FPoint& pos) const noexcept -> bool
498  {
499  return contains(pos.getX(), pos.getY());
500  }
501 
502  constexpr auto isOverlapped (const FRect&) const noexcept -> bool;
503  constexpr auto isOverlapped (const FTermRegion*) const noexcept -> bool;
504  constexpr auto isPrintPositionInsideRegion() const noexcept -> bool;
505  auto reprint (const FRect&, const FSize&) noexcept -> bool;
506 
507  inline auto getFChar (int x, int y) const noexcept -> FChar_const_reference
508  {
509  return data[unsigned(y) * unsigned(size.width + shadow.width) + unsigned(x)];
510  }
511 
512  inline auto getFChar (int x, int y) noexcept -> FChar_reference
513  {
514  return data[unsigned(y) * unsigned(size.width + shadow.width) + unsigned(x)];
515  }
516 
517  inline auto getFChar (const FPoint& pos) const noexcept -> FChar_const_reference
518  {
519  return getFChar(pos.getX(), pos.getY());
520  }
521 
522  inline auto getFChar (const FPoint& pos) noexcept -> FChar_reference
523  {
524  return getFChar(pos.getX(), pos.getY());
525  }
526 
527  inline auto getFCharIterator (int x, int y) const noexcept -> FChar_const_iterator
528  {
529  return data.cbegin() + (unsigned(y) * unsigned(size.width + shadow.width) + unsigned(x));
530  }
531 
532  inline auto getFCharIterator (int x, int y) noexcept -> FChar_iterator
533  {
534  return data.begin() + (unsigned(y) * unsigned(size.width + shadow.width) + unsigned(x));
535  }
536 
537  constexpr void setCursorPos (int x, int y) noexcept
538  {
539  cursor.x = x;
540  cursor.y = y;
541  }
542 
543  constexpr void setInputCursorPos (int x, int y) noexcept
544  {
545  input_cursor.x = x;
546  input_cursor.y = y;
547  }
548 
549  template <typename T>
550  inline auto print (T&& term_data) -> int
551  {
552  if ( hasOwner() )
553  return getOwner<FVTerm*>()->print (this, std::forward<T>(term_data));
554 
555  return -1;
556  }
557 
558  void updateRegionChanges (uInt, uInt, uInt8) noexcept;
559 
560  // Data members
561  struct Coordinate
562  {
563  int x{};
564  int y{};
565  };
566 
567  struct Dimension
568  {
569  int width{};
570  int height{};
571  };
572 
573  Coordinate position{0, 0}; // Distance from left and top of terminal edge
574  Dimension size{-1, -1}; // Window width and height
575  Dimension shadow{0, 0}; // Right and bottom window shadow
576  Dimension min_size{-1, -1}; // Minimized window width and height
577  Coordinate cursor{0, 0}; // Position for the next write operation
578  Coordinate input_cursor{-1, -1}; // Position of visible input cursor
579  int layer{-1};
580  Encoding encoding{Encoding::Unknown};
581  bool input_cursor_visible{false};
582  bool has_changes{false};
583  bool visible{false};
584  bool minimized{false};
585  FDataAccessPtr owner{nullptr}; // Object that owns this FTermRegion
586  FPreprocVector preproc_list{};
587  FRowChanges changes_in_row{};
588  FLineChangesVec changes_in_line{};
589  FCharVec data{}; // FChar data of the drawing region
590 };
591 
592 //----------------------------------------------------------------------
593 constexpr auto FVTerm::FTermRegion::contains (int x, int y) const noexcept -> bool
594 {
595  // Is the terminal position (pos) located on my region?
596 
597  const int current_height = minimized ? min_size.height
598  : size.height + shadow.height;
599  const int x_min = position.x;
600  const int x_max = x_min + size.width + shadow.width;
601  const int y_min = position.y;
602  const int y_max = y_min + current_height;
603  return x >= x_min
604  && x < x_max
605  && y >= y_min
606  && y < y_max;
607 }
608 
609 //----------------------------------------------------------------------
610 constexpr auto FVTerm::FTermRegion::isOverlapped (const FRect& box) const noexcept -> bool
611 {
612  const int x1 = position.x;
613  const int x2 = x1 + size.width + shadow.width;
614 
615  if ( x2 < box.getX1() || x1 >= box.getX2() )
616  return false;
617 
618  const int y1 = position.y;
619  const int height = minimized ? min_size.height
620  : size.height + shadow.height;
621  const int y2 = y1 + height;
622  return ! ( y2 < box.getY1() || y1 >= box.getY2() );
623 }
624 
625 //----------------------------------------------------------------------
626 constexpr auto FVTerm::FTermRegion::isOverlapped (const FTermRegion* region) const noexcept -> bool
627 {
628  const int region_x1 = region->position.x;
629  const int region_x2 = region_x1 + region->size.width + region->shadow.width;
630  const int x1 = position.x;
631  const int x2 = x1 + size.width + shadow.width;
632 
633  if ( x2 <= region_x1 || x1 >= region_x2 )
634  return false;
635 
636  const int region_height = region->minimized ? region->min_size.height
637  : region->size.height + region->shadow.height;
638  const int region_y1 = region->position.y;
639  const int region_y2 = region_y1 + region_height;
640  const int height = minimized ? min_size.height
641  : size.height + shadow.height;
642  const int y1 = position.y;
643  const int y2 = y1 + height;
644  return ! ( y2 <= region_y1 || y1 >= region_y2 );
645 }
646 
647 //----------------------------------------------------------------------
648 constexpr auto FVTerm::FTermRegion::isPrintPositionInsideRegion() const noexcept -> bool
649 {
650  return cursor.x > 0
651  && cursor.y > 0
652  && cursor.x <= size.width + shadow.width
653  && cursor.y <= size.height + shadow.height;
654 }
655 
656 //----------------------------------------------------------------------
657 inline auto FVTerm::FTermRegion::reprint ( const FRect& box
658  , const FSize& term_size ) noexcept -> bool
659 {
660  if ( ! isOverlapped(box) )
661  return false;
662 
663  // Explicit type cast to avoid undefined behavior
664  const auto box_x1 = int(static_cast<unsigned int>(box.getX1()) - 1);
665  const auto box_y1 = int(static_cast<unsigned int>(box.getY1()) - 1);
666  const auto box_x2 = int(static_cast<unsigned int>(box.getX2()) - 1);
667  const auto box_y2 = int(static_cast<unsigned int>(box.getY2()) - 1);
668 
669  if ( box_x1 > box_x2 || box_y1 > box_y2 )
670  return false;
671 
672  has_changes = true;
673 
674  // Compute geometry
675  const int term_w = int(term_size.getWidth()) - 1;
676  const int term_h = int(term_size.getHeight()) - 1;
677  const int self_h = minimized ? min_size.height
678  : size.height + shadow.height;
679  const int self_w = size.width + shadow.width;
680  const int self_x1 = position.x;
681  const int self_y1 = position.y;
682  const int self_x2 = self_x1 + self_w - 1;
683  const int self_y2 = self_y1 + self_h - 1;
684 
685  // Vertical boundaries
686  const int y_start = std::max(std::max(0, box_y1), self_y1) - self_y1;
687  const int y_end = std::min(std::min(term_h, box_y2), self_y2) - self_y1;
688 
689  // Horizontal boundaries
690  const int x_start = std::max(std::max(0, box_x1), self_x1) - self_x1;
691  const int x_end = std::min(std::min(term_w, box_x2), self_x2) - self_x1;
692 
693  if ( y_end < y_start || x_end < x_start ) // Nothing visible
694  return false;
695 
696  auto first_row = unsigned(y_start);
697  auto last_row = unsigned(std::max(0, y_end));
698  auto line_changes = changes_in_line.begin() + first_row;
699  const auto line_changes_end = changes_in_line.cbegin() + last_row;
700 
701  while ( line_changes <= line_changes_end ) // Line loop
702  {
703  line_changes->xmin = std::min(line_changes->xmin, uInt(x_start));
704  line_changes->xmax = std::max(line_changes->xmax, uInt(x_end));
705  ++line_changes;
706  }
707 
708  changes_in_row.ymin = std::min(changes_in_row.ymin, first_row);
709  changes_in_row.ymax = std::max(changes_in_row.ymax, last_row);
710  return true;
711 }
712 
713 //----------------------------------------------------------------------
714 inline void FVTerm::FTermRegion::updateRegionChanges ( uInt x, uInt y
715  , uInt8 char_width ) noexcept
716 {
717  auto& line_changes = changes_in_line[y];
718  const uInt x_end = x + uInt( char_width >> 1 );
719 
720  line_changes.xmin = std::min(line_changes.xmin, x);
721  line_changes.xmax = std::max(line_changes.xmax, x_end);
722 
723  changes_in_row.ymin = std::min(changes_in_row.ymin, y);
724  changes_in_row.ymax = std::max(changes_in_row.ymax, y);
725 }
726 
727 
728 //----------------------------------------------------------------------
729 // struct FVTerm::FVTermPreprocessing
730 //----------------------------------------------------------------------
731 struct D
732 {
733  void operator () (const FVTerm*) const noexcept
734  {
735  // No deleting of pointer objects when exiting the std::unique_ptr
736  }
737 };
738 
740 {
741  // Constructor
742  FVTermPreprocessing (const FVTerm* i, FPreprocessingFunction&& f)
743  : instance(std::unique_ptr<const FVTerm, D>(i))
744  , function(std::move(f))
745  { }
746 
747  FVTermPreprocessing (const FVTermPreprocessing&) = delete;
748  FVTermPreprocessing (FVTermPreprocessing&&) noexcept = default;
749  auto operator = (const FVTermPreprocessing&) -> FVTermPreprocessing& = delete;
750  auto operator = (FVTermPreprocessing&&) noexcept -> FVTermPreprocessing& = default;
751 
752  // Data members
753  std::unique_ptr<const FVTerm, D> instance{};
754  FPreprocessingFunction function{};
755 };
756 
757 
758 // FVTerm inline functions
759 //----------------------------------------------------------------------
760 template <typename FOutputType>
761 FVTerm::FVTerm (outputClass<FOutputType>)
762 {
763  init<typename outputClass<FOutputType>::type>();
764 }
765 
766 //----------------------------------------------------------------------
767 template <typename NumT
768  , enable_if_arithmetic_without_char_t<NumT>>
769 inline auto FVTerm::operator << (const NumT& n) noexcept -> FVTerm&
770 {
771  print (FString(std::to_string(n)));
772  return *this;
773 }
774 
775 //----------------------------------------------------------------------
776 template <typename CharT
777  , enable_if_CString_t<CharT>>
778 inline auto FVTerm::operator << (const CharT& s) noexcept -> FVTerm&
779 {
780  print (FString(s));
781  return *this;
782 }
783 
784 //----------------------------------------------------------------------
785 inline auto FVTerm::operator << (char c) noexcept -> FVTerm&
786 {
787  print (wchar_t(uChar(c)));
788  return *this;
789 }
790 
791 //----------------------------------------------------------------------
792 inline auto FVTerm::operator << (wchar_t c) noexcept -> FVTerm&
793 {
794  print (c);
795  return *this;
796 }
797 
798 //----------------------------------------------------------------------
799 inline auto FVTerm::operator << (const wchar_t* wide_string) noexcept -> FVTerm&
800 {
801  print (wide_string);
802  return *this;
803 }
804 
805 //----------------------------------------------------------------------
806 inline auto FVTerm::operator << (const UniChar& c) noexcept -> FVTerm&
807 {
808  print (static_cast<wchar_t>(c)); // Required under Solaris
809  return *this;
810 }
811 
812 //----------------------------------------------------------------------
813 inline auto FVTerm::operator << (const std::string& string) noexcept -> FVTerm&
814 {
815  print (string);
816  return *this;
817 }
818 
819 //----------------------------------------------------------------------
820 inline auto FVTerm::operator << (const std::wstring& wide_string) noexcept -> FVTerm&
821 {
822  print (FString(wide_string));
823  return *this;
824 }
825 
826 //----------------------------------------------------------------------
827 inline auto FVTerm::operator << (const FString& fstring) noexcept -> FVTerm&
828 {
829  print (fstring);
830  return *this;
831 }
832 
833 //----------------------------------------------------------------------
834 inline auto FVTerm::operator << (const FChar& fchar) noexcept -> FVTerm&
835 {
836  print (fchar);
837  return *this;
838 }
839 
840 //----------------------------------------------------------------------
841 inline auto FVTerm::operator << (const FCharVector& term_string) noexcept -> FVTerm&
842 {
843  print (term_string);
844  return *this;
845 }
846 
847 //----------------------------------------------------------------------
848 inline auto FVTerm::operator << (const FPoint& pos) noexcept -> FVTerm&
849 {
850  print (pos);
851  return *this;
852 }
853 
854 //----------------------------------------------------------------------
855 inline auto FVTerm::operator << (const FStyle& t_style) noexcept -> FVTerm&
856 {
857  print (t_style);
858  return *this;
859 }
860 
861 //----------------------------------------------------------------------
862 inline auto FVTerm::operator << (const FColorPair& pair) noexcept -> FVTerm&
863 {
864  print (pair);
865  return *this;
866 }
867 
868 //----------------------------------------------------------------------
869 inline auto FVTerm::getClassName() const -> FString
870 { return "FVTerm"; }
871 
872 //----------------------------------------------------------------------
873 inline auto FVTerm::getVWin() noexcept -> FTermRegion*
874 { return vwin.get(); }
875 
876 //----------------------------------------------------------------------
877 inline auto FVTerm::getVWin() const noexcept -> const FTermRegion*
878 { return vwin.get(); }
879 
880 //----------------------------------------------------------------------
881 inline auto FVTerm::getWindowList() noexcept -> FVTermList*
882 {
883  static const auto& init_object = getGlobalFVTermInstance();
884  return ( isInitialized() && init_object->vterm_window_list )
885  ? init_object->vterm_window_list.get()
886  : nullptr;
887 }
888 
889 //----------------------------------------------------------------------
890 inline void FVTerm::setVWin (std::unique_ptr<FTermRegion>&& region) noexcept
891 { vwin = std::move(region); }
892 
893 //----------------------------------------------------------------------
894 inline void FVTerm::unsetNonBlockingRead()
895 { setNonBlockingRead(false); }
896 
897 //----------------------------------------------------------------------
898 inline auto FVTerm::isDrawingFinished() noexcept -> bool
899 { return draw_completed; }
900 
901 //----------------------------------------------------------------------
902 inline auto FVTerm::isTerminalUpdateForced() noexcept -> bool
903 { return force_terminal_update; }
904 
905 //----------------------------------------------------------------------
906 inline auto FVTerm::areTerminalUpdatesPaused() noexcept -> bool
907 { return no_terminal_updates; }
908 
909 //----------------------------------------------------------------------
910 inline auto FVTerm::hasPendingTerminalUpdates() noexcept -> bool
911 { return hasPendingUpdates(getGlobalFVTermInstance()->vterm.get()); }
912 
913 //----------------------------------------------------------------------
914 template <typename... Args>
915 auto FVTerm::printf (const FString& format, Args&&... args) -> int
916 {
917  FString str{};
918  str.sprintf (format, std::forward<Args>(args)...);
919  return print(str);
920 }
921 
922 //----------------------------------------------------------------------
923 inline auto FVTerm::print() noexcept -> FVTerm&
924 { return *this; }
925 
926 //----------------------------------------------------------------------
927 inline void FVTerm::print (const FPoint& p)
928 {
929  setCursor (p);
930 }
931 
932 //----------------------------------------------------------------------
933 inline auto FVTerm::getChildPrintRegion() const noexcept -> FTermRegion*
934 { return child_print_region; }
935 
936 //----------------------------------------------------------------------
937 inline auto FVTerm::getCurrentPrintRegion() const noexcept -> FTermRegion*
938 { return print_region; }
939 
940 //----------------------------------------------------------------------
941 inline auto FVTerm::getVirtualDesktop() const noexcept -> FTermRegion*
942 { return vdesktop.get(); }
943 
944 //----------------------------------------------------------------------
945 inline auto FVTerm::getVirtualTerminal() const noexcept -> FTermRegion*
946 { return vterm.get(); }
947 
948 //----------------------------------------------------------------------
949 inline void FVTerm::setPrintRegion (FTermRegion* region) noexcept
950 { print_region = region; }
951 
952 //----------------------------------------------------------------------
953 inline void FVTerm::setChildPrintRegion (FTermRegion* region) noexcept
954 { child_print_region = region; }
955 
956 //----------------------------------------------------------------------
957 inline void FVTerm::setActiveRegion (FTermRegion* region) const noexcept
958 { active_region = region; }
959 
960 //----------------------------------------------------------------------
961 inline auto FVTerm::isActive (const FTermRegion* region) const noexcept -> bool
962 { return region == active_region; }
963 
964 //----------------------------------------------------------------------
965 inline auto FVTerm::hasPrintRegion() const noexcept -> bool
966 { return print_region; }
967 
968 //----------------------------------------------------------------------
969 inline auto FVTerm::hasChildPrintRegion() const noexcept -> bool
970 { return child_print_region; }
971 
972 //----------------------------------------------------------------------
973 inline auto FVTerm::isVirtualWindow() const noexcept -> bool
974 { return vwin.get(); }
975 
976 //----------------------------------------------------------------------
977 inline void FVTerm::hideVTermCursor() const noexcept
978 { vterm->input_cursor_visible = false; }
979 
980 //----------------------------------------------------------------------
981 inline auto FVTerm::getLayer (FVTerm& obj) noexcept -> int
982 {
983  // returns the layer from the FVTerm object
984  return obj.FVTerm::getPrintRegion()->layer;
985 }
986 
987 //----------------------------------------------------------------------
988 template <typename FOutputType>
989 inline void FVTerm::init()
990 {
991  if ( isInitialized() )
992  {
993  initFromGlobalInstance();
994  }
995  else
996  {
997  setGlobalFVTermInstance(this);
998  foutput = std::make_shared<FOutputType>(*this);
999  vterm_window_list = std::make_shared<FVTermList>();
1000  initSettings();
1001  }
1002 }
1003 
1004 //----------------------------------------------------------------------
1005 inline void FVTerm::initFromGlobalInstance()
1006 {
1007  const auto& init_object = getGlobalFVTermInstance();
1008 
1009  if ( ! init_object )
1010  return;
1011 
1012  foutput = std::shared_ptr<FOutput>(init_object->foutput);
1013  vterm_window_list = std::shared_ptr<FVTermList>(init_object->vterm_window_list);
1014  vterm = std::shared_ptr<FTermRegion>(init_object->vterm);
1015  vterm_old = std::shared_ptr<FTermRegion>(init_object->vterm_old);
1016  vdesktop = std::shared_ptr<FTermRegion>(init_object->vdesktop);
1017 }
1018 
1019 } // namespace finalcut
1020 
1021 #endif // FVTERM_H
Definition: fvterm.h:441
Definition: frect.h:56
Definition: fvterm.h:97
Definition: fvtermbuffer.h:56
Definition: class_template.cpp:25
Definition: fpoint.h:50
Definition: fsize.h:55
Definition: ftypes.h:1081
Definition: fvterm.h:220
Definition: fstring.h:82
Definition: fstyle.h:49
Definition: fvterm.h:731
Definition: fdata.h:55
Definition: fwidget.h:129
Definition: fcolorpair.h:49
Definition: fvterm.h:88
Definition: fvtermattribute.h:86