diff --git a/FL/Fl_Input.H b/FL/Fl_Input.H index 93d1c2642..f53debd50 100644 --- a/FL/Fl_Input.H +++ b/FL/Fl_Input.H @@ -1,7 +1,7 @@ // // Input header file for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2021 by Bill Spitzak and others. +// Copyright 1998-2023 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this diff --git a/FL/Fl_Input_.H b/FL/Fl_Input_.H index d89a341bc..a7062f5a0 100644 --- a/FL/Fl_Input_.H +++ b/FL/Fl_Input_.H @@ -39,6 +39,7 @@ #define FL_MULTILINE_OUTPUT_WRAP (FL_MULTILINE_INPUT | FL_INPUT_READONLY | FL_INPUT_WRAP) class Fl_Input_Undo_Action; +class Fl_Input_Undo_Action_List; /** This class provides a low-overhead text input field. @@ -148,6 +149,8 @@ class FL_EXPORT Fl_Input_ : public Fl_Widget { /** \internal local undo event */ Fl_Input_Undo_Action* undo_; + Fl_Input_Undo_Action_List* undo_list_; + Fl_Input_Undo_Action_List* redo_list_; /** \internal Horizontal cursor position in pixels while moving up or down. */ static double up_down_pos; @@ -212,6 +215,9 @@ protected: /* Return the number of lines displayed on a single page. */ int linesPerPage(); + /* Apply the current undo/redo operation, called from undo() or redo() */ + int apply_undo(); + public: /* Change the size of the widget. */ @@ -378,6 +384,9 @@ public: /* Undo previous changes to the text buffer. */ int undo(); + /* Redo previous undo operations. */ + int redo(); + /* Copy the yank buffer to the clipboard. */ int copy_cuts(); diff --git a/FL/Fl_Text_Buffer.H b/FL/Fl_Text_Buffer.H index e3e131ef1..dabe5677a 100644 --- a/FL/Fl_Text_Buffer.H +++ b/FL/Fl_Text_Buffer.H @@ -1,7 +1,7 @@ // // Header file for Fl_Text_Buffer class. // -// Copyright 2001-2021 by Bill Spitzak and others. +// Copyright 2001-2023 by Bill Spitzak and others. // Original code Copyright Mark Edel. Permission to distribute under // the LGPL for the FLTK library granted by Mark Edel. // @@ -61,6 +61,7 @@ #include "Fl_Export.H" +class Fl_Text_Undo_Action_List; class Fl_Text_Undo_Action; /** @@ -326,6 +327,11 @@ public: */ int undo(int *cp=0); + /** + Redo previous undo action. + */ + int redo(int *cp=0); + /** Lets the undo system know if we can undo changes */ @@ -813,6 +819,11 @@ protected: */ void update_selections(int pos, int nDeleted, int nInserted); + /** + Apply the current undo/redo operation, called from undo() or redo(). + */ + int apply_undo(Fl_Text_Undo_Action* action, int* cursorPos); + Fl_Text_Selection mPrimary; /**< highlighted areas */ Fl_Text_Selection mSecondary; /**< highlighted areas */ Fl_Text_Selection mHighlight; /**< highlighted areas */ @@ -841,6 +852,8 @@ protected: bytes and should only be increased if frequent and large changes in buffer size are expected */ Fl_Text_Undo_Action* mUndo; /**< local undo event */ + Fl_Text_Undo_Action_List* mUndoList; /**< List of undo event */ + Fl_Text_Undo_Action_List* mRedoList; /**< List of redo event */ }; #endif diff --git a/FL/Fl_Text_Editor.H b/FL/Fl_Text_Editor.H index 5bf49781e..16af25451 100644 --- a/FL/Fl_Text_Editor.H +++ b/FL/Fl_Text_Editor.H @@ -1,7 +1,7 @@ // // Header file for Fl_Text_Editor class. // -// Copyright 2001-2010 by Bill Spitzak and others. +// Copyright 2001-2023 by Bill Spitzak and others. // Original code Copyright Mark Edel. Permission to distribute under // the LGPL for the FLTK library granted by Mark Edel. // @@ -110,6 +110,7 @@ class FL_EXPORT Fl_Text_Editor : public Fl_Text_Display { static int kf_paste(int c, Fl_Text_Editor* e); static int kf_select_all(int c, Fl_Text_Editor* e); static int kf_undo(int c, Fl_Text_Editor* e); + static int kf_redo(int c, Fl_Text_Editor* e); protected: int handle_key(); diff --git a/src/Fl_Input.cxx b/src/Fl_Input.cxx index c191bfc6e..6dd026b00 100644 --- a/src/Fl_Input.cxx +++ b/src/Fl_Input.cxx @@ -1,7 +1,7 @@ // // Input widget for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2021 by Bill Spitzak and others. +// Copyright 1998-2023 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -275,10 +275,10 @@ int Fl_Input::kf_undo() { return undo(); } -// Redo. (currently unimplemented.. toggles undo() instead) +// Redo. int Fl_Input::kf_redo() { if (readonly()) { fl_beep(); return 1; } - return kf_undo(); // currently we don't support multilevel undo + return redo(); } // Do a copy operation diff --git a/src/Fl_Input_.cxx b/src/Fl_Input_.cxx index a8f168b0e..cabbbd112 100644 --- a/src/Fl_Input_.cxx +++ b/src/Fl_Input_.cxx @@ -33,6 +33,7 @@ extern void fl_draw(const char*, int, float, float); //////////////////////////////////////////////////////////////// +// see: Fl_Text_Undo_Action class Fl_Input_Undo_Action { public: Fl_Input_Undo_Action() : @@ -71,6 +72,50 @@ public: } }; +// see: Fl_Text_Undo_Action_List +class Fl_Input_Undo_Action_List { + Fl_Input_Undo_Action** list_; + int list_size_; + int list_capacity_; +public: + Fl_Input_Undo_Action_List() : + list_(NULL), + list_size_(0), + list_capacity_(0) + { } + + ~Fl_Input_Undo_Action_List() { + clear(); + } + + void push(Fl_Input_Undo_Action* action) { + if (list_size_ == list_capacity_) { + list_capacity_ += 25; + list_ = (Fl_Input_Undo_Action**)realloc(list_, list_capacity_ * sizeof(Fl_Input_Undo_Action*)); + } + list_[list_size_++] = action; + } + + Fl_Input_Undo_Action* pop() { + if (list_size_ > 0) + return list_[--list_size_]; + else + return NULL; + } + + void clear() { + if (list_) { + for (int i=0; iundoat && (e-b)undoinsert) { undo_->undoinsert -= e-b; } else { + redo_list_->clear(); + undo_list_->push(undo_); + undo_ = new Fl_Input_Undo_Action(); undo_->undobuffersize(e-b); memcpy(undo_->undobuffer, value_+b, e-b); undo_->undocut = e-b; @@ -903,9 +951,12 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) { } if (ilen) { - if (b == undo_->undoat) + if (b == undo_->undoat) { undo_->undoinsert += ilen; - else { + } else { + redo_list_->clear(); + undo_list_->push(undo_); + undo_ = new Fl_Input_Undo_Action(); undo_->undocut = 0; undo_->undoinsert = ilen; } @@ -947,13 +998,13 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) { } /** - Undoes previous changes to the text buffer. + Apply the current undo/redo operation - This call undoes a number of previous calls to replace(). + It's up to undo() and redo() to push and pop actions to and from the lists. - \return non-zero if any change was made. -*/ -int Fl_Input_::undo() { + \return 1 if the current action changed any text. + \see undo(), redo() */ +int Fl_Input_::apply_undo() { was_up_down = 0; if (!undo_->undocut && !undo_->undoinsert) return 0; @@ -962,6 +1013,8 @@ int Fl_Input_::undo() { int b = undo_->undoat-xlen; int b1 = b; + minimal_update(position_); + put_in_buffer(size_+ilen); if (ilen) { @@ -989,10 +1042,52 @@ int Fl_Input_::undo() { while (b1 > 0 && index(b1)!='\n') b1--; minimal_update(b1); set_changed(); - if (when()&FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED); + return 1; } +/** + Undoes previous changes to the text buffer. + + This call undoes a number of previous calls to replace(). + + \return non-zero if any change was made. + */ +int Fl_Input_::undo() { + if (apply_undo() == 0) + return 0; + + redo_list_->push(undo_); + undo_ = undo_list_->pop(); + if (!undo_) undo_ = new Fl_Input_Undo_Action(); + + if (when()&FL_WHEN_CHANGED) do_callback(FL_REASON_CHANGED); + + return 1; +} + +/** + Redo previous undo operation. + + This call reapplies previously executed undo operations. + + \return non-zero if any change was made. + */ +int Fl_Input_::redo() { + Fl_Input_Undo_Action *redo_action = redo_list_->pop(); + if (!redo_action) + return 0; + + if (undo_->undocut || undo_->undoinsert) + undo_list_->push(undo_); + undo_ = redo_action; + + int ret = apply_undo(); + if (ret && (when()&FL_WHEN_CHANGED)) do_callback(FL_REASON_CHANGED); + + return ret; +} + /** Copies the \e yank buffer to the clipboard. @@ -1168,6 +1263,8 @@ Fl_Input_::Fl_Input_(int X, int Y, int W, int H, const char* l) xscroll_ = yscroll_ = 0; maximum_size_ = 32767; shortcut_ = 0; + undo_list_ = new Fl_Input_Undo_Action_List(); + redo_list_ = new Fl_Input_Undo_Action_List(); undo_ = new Fl_Input_Undo_Action(); set_flag(SHORTCUT_LABEL); set_flag(MAC_USE_ACCENTS_MENU); @@ -1236,6 +1333,8 @@ void Fl_Input_::put_in_buffer(int len) { int Fl_Input_::static_value(const char* str, int len) { clear_changed(); undo_->clear(); + undo_list_->clear(); + redo_list_->clear(); if (str == value_ && len == size_) return 0; if (len) { // non-empty new value: if (xscroll_ || yscroll_) { @@ -1336,6 +1435,8 @@ void Fl_Input_::resize(int X, int Y, int W, int H) { from the parent Fl_Group. */ Fl_Input_::~Fl_Input_() { + delete undo_list_; + delete redo_list_; delete undo_; if (bufsize) free((void*)buffer); } diff --git a/src/Fl_Text_Buffer.cxx b/src/Fl_Text_Buffer.cxx index 638a3d023..620b3d145 100644 --- a/src/Fl_Text_Buffer.cxx +++ b/src/Fl_Text_Buffer.cxx @@ -1,5 +1,5 @@ // -// Copyright 2001-2017 by Bill Spitzak and others. +// Copyright 2001-2023 by Bill Spitzak and others. // Original code Copyright Mark Edel. Permission to distribute under // the LGPL for the FLTK library granted by Mark Edel. // @@ -66,6 +66,23 @@ static int min(int i1, int i2) #endif +/* + Undo/Redo is handled with Fl_Text_Undo_Action. The names of the class members + relate to the original action. + + Deleting text will store the number of bytes deleted in `undocut`, and store + the deleted text in `undobuffer`. `undoat` is the insertion position. + + Inserting text will store the number of bytes inserted in `undoinsert` and + `undoat` will point after the inserted text. + + If text is deleted first and then text is inserted at the same position, it's + called a yankcut, and the number of bytes that were deleted is stored in + `undoyankcut`, again storing the deleted text in `undobuffer`. + + If an undo action is run, text is deleted and inserted via the normal + Fl_Text_Editor methods, generating the inverse undo action (redo) in mUndo. + */ class Fl_Text_Undo_Action { public: Fl_Text_Undo_Action() : @@ -102,6 +119,76 @@ public: void clear() { undocut = undoinsert = 0; } + + bool empty() { + return (!undocut && !undoinsert); + } +}; + +/* + Undo events are stored in a Last In - First Out stack. + + Any insertion or deletion of text will either add to the current undo event + in mUndo, or generate a new undo event if cursor positions are not consecutive. + The previously current undo event will then be pushed to the undo list and + the redo event list is purged. + + If the user calls undo(), the current undo event in mUndo will be run, + generating a matching redo event in mUndo. The redo event is then pushed into + the redo list, and the next undo event is popped from the undo list and made + current. + + A list can be locked to be protected from purging while running an undo event. + */ +class Fl_Text_Undo_Action_List { + Fl_Text_Undo_Action** list_; + int list_size_; + int list_capacity_; + bool locked_; +public: + Fl_Text_Undo_Action_List() : + list_(NULL), + list_size_(0), + list_capacity_(0), + locked_(false) + { } + + ~Fl_Text_Undo_Action_List() { + unlock(); + clear(); + } + + void push(Fl_Text_Undo_Action* action) { + if (list_size_ == list_capacity_) { + list_capacity_ += 25; + list_ = (Fl_Text_Undo_Action**)realloc(list_, list_capacity_ * sizeof(Fl_Text_Undo_Action*)); + } + list_[list_size_++] = action; + } + + Fl_Text_Undo_Action* pop() { + if (list_size_ > 0) { + Fl_Text_Undo_Action *action = list_[list_size_-1]; + return list_[--list_size_]; + } else + return NULL; + } + + void clear() { + if (locked_) return; + if (list_) { + for (int i=0; iclear(); + mUndoList->clear(); + mRedoList->clear(); + } } @@ -459,51 +553,97 @@ void Fl_Text_Buffer::copy(Fl_Text_Buffer * fromBuf, int fromStart, } -/* - Take the previous changes and undo them. Return the previous - cursor position in cursorPos. Returns 1 if the undo was applied. - CursorPos will be at a character boundary. +/** + Apply the current undo/redo operation, called from undo() or redo(). */ -int Fl_Text_Buffer::undo(int *cursorPos) +int Fl_Text_Buffer::apply_undo(Fl_Text_Undo_Action* action, int* cursorPos) { - if (!mCanUndo) + if (action->empty()) return 0; - if (!mUndo->undocut && !mUndo->undoinsert) - return 0; + mRedoList->lock(); - int ilen = mUndo->undocut; - int xlen = mUndo->undoinsert; - int b = mUndo->undoat - xlen; + int ilen = action->undocut; + int xlen = action->undoinsert; + int b = action->undoat - xlen; - if (xlen && mUndo->undoyankcut && !ilen) { - ilen = mUndo->undoyankcut; + if (xlen && action->undoyankcut && !ilen) { + ilen = action->undoyankcut; } if (xlen && ilen) { - mUndo->undobuffersize(ilen + 1); - mUndo->undobuffer[ilen] = 0; - char *tmp = fl_strdup(mUndo->undobuffer); - replace(b, mUndo->undoat, tmp); + action->undobuffersize(ilen + 1); + action->undobuffer[ilen] = 0; + char *tmp = fl_strdup(action->undobuffer); + replace(b, action->undoat, tmp); if (cursorPos) *cursorPos = mCursorPosHint; free(tmp); } else if (xlen) { - remove(b, mUndo->undoat); + remove(b, action->undoat); if (cursorPos) *cursorPos = mCursorPosHint; } else if (ilen) { - mUndo->undobuffersize(ilen + 1); - mUndo->undobuffer[ilen] = 0; - insert(mUndo->undoat, mUndo->undobuffer); + action->undobuffersize(ilen + 1); + action->undobuffer[ilen] = 0; + insert(action->undoat, action->undobuffer); if (cursorPos) *cursorPos = mCursorPosHint; - mUndo->undoyankcut = 0; + action->undoyankcut = 0; } + mRedoList->unlock(); return 1; } +/** + Take the previous changes and undo them. Return the previous + cursor position in cursorPos. Returns 1 if the undo was applied. + CursorPos will be at a character boundary. + */ +int Fl_Text_Buffer::undo(int *cursorPos) { + if (!mCanUndo || mUndo->empty()) + return 0; + + // save the current undo action and add an empty action to avoid generating yankcuts + Fl_Text_Undo_Action* action = mUndo; + mUndo = new Fl_Text_Undo_Action(); + + int ret = apply_undo(action, cursorPos); + delete action; + + if (ret) { + // push the generated undo action to the redo list + mRedoList->push(mUndo); + // drop the empty action we previously created + mUndo = mUndoList->pop(); + if (mUndo) { + delete mUndo; + // pop the undo action before that and make it the current undo action + mUndo = mUndoList->pop(); + if (!mUndo) mUndo = new Fl_Text_Undo_Action(); + } + } + + return ret; +} + +/** + Redo previous undo action. + */ +int Fl_Text_Buffer::redo(int *cursorPos) { + if (!mCanUndo) + return 0; + + Fl_Text_Undo_Action *redo_action = mRedoList->pop(); + if (!redo_action) + return 0; + + // running the redo action will also generate a new undo action + // Note: there is a slight chance that the current undo action and the + // generated action merge into one. + return apply_undo(redo_action, cursorPos); +} /* Set a flag if undo function will work. @@ -1218,10 +1358,20 @@ int Fl_Text_Buffer::insert_(int pos, const char *text) if (mCanUndo) { if (mUndo->undoat == pos && mUndo->undoinsert) { + // continue inserting text at the given cursor position mUndo->undoinsert += insertedLength; } else { + int yankcut = (mUndo->undoat == pos) ? mUndo->undocut : 0; + if (!yankcut) { + // insert text at a new position, so generate a new undo action + mRedoList->clear(); + mUndoList->push(mUndo); + mUndo = new Fl_Text_Undo_Action(); + } else { + // we deleted and inserted at the same position, making this a yankcut + } mUndo->undoinsert = insertedLength; - mUndo->undoyankcut = (mUndo->undoat == pos) ? mUndo->undocut : 0; + mUndo->undoyankcut = yankcut; } mUndo->undoat = pos + insertedLength; mUndo->undocut = 0; @@ -1241,10 +1391,15 @@ void Fl_Text_Buffer::remove_(int start, int end) if (mCanUndo) { if (mUndo->undoat == end && mUndo->undocut) { + // continue to remove text at the same cursor position mUndo->undobuffersize(mUndo->undocut + end - start + 1); memmove(mUndo->undobuffer + end - start, mUndo->undobuffer, mUndo->undocut); mUndo->undocut += end - start; } else { + // remove text at a new position, so generate a new undo action + mRedoList->clear(); + mUndoList->push(mUndo); + mUndo = new Fl_Text_Undo_Action(); mUndo->undocut = end - start; mUndo->undobuffersize(mUndo->undocut); } diff --git a/src/Fl_Text_Editor.cxx b/src/Fl_Text_Editor.cxx index 81dc2f441..c548ef6be 100644 --- a/src/Fl_Text_Editor.cxx +++ b/src/Fl_Text_Editor.cxx @@ -1,5 +1,5 @@ // -// Copyright 2001-2018 by Bill Spitzak and others. +// Copyright 2001-2023 by Bill Spitzak and others. // // Original code Copyright Mark Edel. Permission to distribute under // the LGPL for the FLTK library granted by Mark Edel. @@ -132,7 +132,9 @@ static struct { { FL_Page_Down, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, //{ FL_Clear, 0, Fl_Text_Editor::delete_to_eol }, { 'z', FL_CTRL, Fl_Text_Editor::kf_undo }, - { '/', FL_CTRL, Fl_Text_Editor::kf_undo }, + { 'z', FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_redo }, // MSWindows screen driver also defines Ctrl-Y + { '/', FL_CTRL, Fl_Text_Editor::kf_undo }, // Emacs + { '?', FL_CTRL, Fl_Text_Editor::kf_redo }, // Emacs { 'x', FL_CTRL, Fl_Text_Editor::kf_cut }, { FL_Delete, FL_SHIFT, Fl_Text_Editor::kf_cut }, { 'c', FL_CTRL, Fl_Text_Editor::kf_copy }, @@ -596,13 +598,13 @@ int Fl_Text_Editor::kf_select_all(int, Fl_Text_Editor* e) { } /** Undo last edit in the current buffer of editor \p 'e'. - Also deselects previous selection. - The key value \p 'c' is currently unused. -*/ + Also deselects previous selection. + The key value \p 'c' is currently unused. + */ int Fl_Text_Editor::kf_undo(int , Fl_Text_Editor* e) { e->buffer()->unselect(); Fl::copy("", 0, 0); - int crsr; + int crsr = e->insert_position(); int ret = e->buffer()->undo(&crsr); e->insert_position(crsr); e->show_insert_position(); @@ -611,6 +613,22 @@ int Fl_Text_Editor::kf_undo(int , Fl_Text_Editor* e) { return ret; } +/** Redo last undo action. + Also deselects previous selection. + The key value \p 'c' is currently unused. + */ +int Fl_Text_Editor::kf_redo(int , Fl_Text_Editor* e) { + e->buffer()->unselect(); + Fl::copy("", 0, 0); + int crsr = e->insert_position(); + int ret = e->buffer()->redo(&crsr); + e->insert_position(crsr); + e->show_insert_position(); + e->set_changed(); + if (e->when()&FL_WHEN_CHANGED) e->do_callback(); + return ret; +} + /** Handles a key press in the editor */ int Fl_Text_Editor::handle_key() { // Call FLTK's rules to try to turn this into a printing character. diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx index 76eee9e12..012261b2c 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx @@ -1,7 +1,7 @@ // // Definition of Apple Cocoa Screen interface. // -// Copyright 1998-2022 by Bill Spitzak and others. +// Copyright 1998-2023 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -79,6 +79,7 @@ Fl_Screen_Driver::Keyname darwin_key_table[] = { static Fl_Text_Editor::Key_Binding extra_bindings[] = { // Define CMD+key accelerators... { 'z', FL_COMMAND, Fl_Text_Editor::kf_undo ,0}, + { 'z', FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_redo ,0}, { 'x', FL_COMMAND, Fl_Text_Editor::kf_cut ,0}, { 'c', FL_COMMAND, Fl_Text_Editor::kf_copy ,0}, { 'v', FL_COMMAND, Fl_Text_Editor::kf_paste ,0}, diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H index 3bb5e11a6..3bbd51d59 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H @@ -41,9 +41,7 @@ protected: public: float dpi[MAX_SCREENS][2]; - Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() { - for (int i = 0; i < MAX_SCREENS; i++) scale_of_screen[i] = 1; - } + Fl_WinAPI_Screen_Driver(); // --- display management int visual(int flags) FL_OVERRIDE; // --- screen configuration diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 1f9ed3249..452815afb 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -38,6 +38,17 @@ extern const char *fl_bg2; # include #endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500 +static Fl_Text_Editor::Key_Binding extra_bindings[] = { + // Define MS Windows specific accelerators... + { 'y', FL_CTRL, Fl_Text_Editor::kf_redo ,0}, + { 0, 0, 0 ,0} +}; + + +Fl_WinAPI_Screen_Driver::Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() { + text_editor_extra_key_bindings = extra_bindings; + for (int i = 0; i < MAX_SCREENS; i++) scale_of_screen[i] = 1; +} int Fl_WinAPI_Screen_Driver::visual(int flags) {