Hello community,

here is the log from the commit of package libt3widget for openSUSE:Factory 
checked in at 2019-12-21 12:32:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libt3widget (Old)
 and      /work/SRC/openSUSE:Factory/.libt3widget.new.6675 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libt3widget"

Sat Dec 21 12:32:15 2019 rev:10 rq:758356 version:1.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/libt3widget/libt3widget.changes  2019-08-23 
11:09:42.354458664 +0200
+++ /work/SRC/openSUSE:Factory/.libt3widget.new.6675/libt3widget.changes        
2019-12-21 12:32:44.495402047 +0100
@@ -1,0 +2,14 @@
+Thu Dec 19 23:52:08 UTC 2019 - Jan Engelhardt <[email protected]>
+
+- Update to release 1.2.0
+  * This release provides several new features and bug fixes,
+    among which:
+  * Pressing ctrl+backspace will delete the previous word,
+  * Extra navigation keys (+/- and arrows) for expander widgets.
+  * Checkboxes can now have a third, indeterminate, state.
+  * Frame resizing correctly redraws the frame.
+  * This release changes the selection of binary attributes to
+    make the distinction between explicitly unset and fallback
+    from base attribute
+
+-------------------------------------------------------------------

Old:
----
  libt3widget-1.0.6.tar.bz2

New:
----
  libt3widget-1.2.0.tar.bz2
  libt3widget-1.2.0.tar.bz2.sig
  libt3widget.keyring

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libt3widget.spec ++++++
--- /var/tmp/diff_new_pack.k5O8zN/_old  2019-12-21 12:32:45.799402667 +0100
+++ /var/tmp/diff_new_pack.k5O8zN/_new  2019-12-21 12:32:45.803402668 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package libt3widget
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,25 +18,27 @@
 
 Name:           libt3widget
 %define lname  libt3widget2
-Version:        1.0.6
+Version:        1.2.0
 Release:        0
 Summary:        The Tilde terminal dialog toolkit
 License:        GPL-3.0-only
 Group:          Development/Libraries/C and C++
-Url:            https://os.ghalkes.nl/t3/libt3widget.html
+URL:            https://os.ghalkes.nl/t3/libt3widget.html
 
-#Git-Clone:    git://github.com/gphalkes/t3widget
+#Git-Clone:    https://github.com/gphalkes/t3widget
 Source:         https://os.ghalkes.nl/dist/%name-%version.tar.bz2
+Source2:        https://os.ghalkes.nl/dist/%name-%version.tar.bz2.sig
+Source3:        %name.keyring
 BuildRequires:  c++_compiler
 BuildRequires:  fdupes
 BuildRequires:  gettext-tools
 BuildRequires:  gpm-devel
 BuildRequires:  libtool
 BuildRequires:  libunistring-devel
-BuildRequires:  pkgconfig
+BuildRequires:  pkg-config
 BuildRequires:  pkgconfig(libpcre2-8)
 BuildRequires:  pkgconfig(libt3key) >= 0.2.0
-BuildRequires:  pkgconfig(libt3window) >= 0.3.1
+BuildRequires:  pkgconfig(libt3window) >= 0.4.0
 BuildRequires:  pkgconfig(libtranscript) >= 0.2.2
 BuildRequires:  pkgconfig(x11)
 BuildRequires:  pkgconfig(xcb)

++++++ libt3widget-1.0.6.tar.bz2 -> libt3widget-1.2.0.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/Changelog 
new/libt3widget-1.2.0/Changelog
--- old/libt3widget-1.0.6/Changelog     2019-05-05 10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/Changelog     2019-12-03 20:12:13.000000000 +0100
@@ -1,3 +1,35 @@
+Version 1.2.0:
+    New features:
+    - The attribute picker dialog distinguishes between explicitly unset and
+      indeterminate settings. The latter will always fall back to the base
+      attributes they are combined with. This requires libt3window version 
0.4.0
+      or later.
+
+Version 1.1.1:
+    Bug fixes:
+    - Display of the indeterminate state of checkbox_t did not work.
+    - Fix incorrect initialization of edit_window_t::behavior_parameters_t from
+      edit_window_t::view_parameters_t.
+
+Version 1.1.0:
+    New features:
+    - Ctrl+backspace erases the last word starting from the cursor.
+    - Expander widgets also expand/collapse on +/- and right/left arrow.
+    - Menus, including right-click menus, now close when clicking on the 
border.
+    - edit_window_t::view_parameters_t is deprecated and replaced by
+      edit_window_t::behavior_parameters_t. The reason for the replacement is 
to
+      make the parameters extensible without breaking ABI compatibility.
+    - checkbox_t can now operate in tri-state mode.
+
+    Bug fixes
+    - Handle errors in getcwd more gracefully (i.e. return "/" as current 
working
+      directory).
+    - Make force_redraw for frame_t call widget_t force_redraw as well, to 
ensure
+      that the frame_t is redrawn as well. This was very visible when resizing
+      the file dialogs.
+    - Calling set_size on edit_window_t now correctly handles nullopt values in
+      the parameters.
+
 Version 1.0.6:
     Bug fixes
     - Search & replace handles zero-width search results from regular 
expressions
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/config.pkg 
new/libt3widget-1.2.0/config.pkg
--- old/libt3widget-1.0.6/config.pkg    2019-05-05 10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/config.pkg    2019-12-03 20:12:13.000000000 +0100
@@ -146,7 +146,7 @@
        return 0;
 }
 EOF
-       pkgconfig libt3window/0.3.1 LIBT3WINDOW test_link_cxx 
PKGCONFIG_REQUIRES || \
+       pkgconfig libt3window/0.4.0 LIBT3WINDOW test_link_cxx 
PKGCONFIG_REQUIRES || \
                error "!! Can not find libt3window. libt3window is required to 
compile libt3widget."
 
        clean_cxx
@@ -405,7 +405,7 @@
        fi
 
        PKGCONFIG_DESC="Dialog toolkit library"
-       PKGCONFIG_VERSION="1.0.6"
+       PKGCONFIG_VERSION="1.2.0"
        PKGCONFIG_URL="http://os.ghalkes.nl/t3/libt3widget.html";
        PKGCONFIG_CFLAGS="-I\${includedir}/t3/widget"
        PKGCONFIG_LIBS="-lt3widget"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/colorscheme.cc 
new/libt3widget-1.2.0/src/colorscheme.cc
--- old/libt3widget-1.0.6/src/colorscheme.cc    2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/colorscheme.cc    2019-12-03 20:12:13.000000000 
+0100
@@ -184,6 +184,10 @@
      other attributes, while the full attributes define the complete rendering.
      In full attributes, the color should not be left unspecified, at least
      not in the default setting.
+
+     The attributes in this set don't use the T3_ATTR_*_SET bits to allow 
older software to keep
+     working without modification or recompilation. They are chosen such that 
all the highlight
+     attributes are strictly additive.
   */
   switch (attribute) {
     case attribute_t::NON_PRINT:
@@ -221,9 +225,8 @@
       return ensure_color(color_mode ? T3_ATTR_BG_BLACK : T3_ATTR_REVERSE);
     case attribute_t::META_TEXT:
       return color_mode ? T3_ATTR_FG_CYAN : T3_ATTR_UNDERLINE;
-    default:
-      return 0;
   }
+  return 0;
 }
 
 }  // namespace t3widget
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libt3widget-1.0.6/src/dialogs/attributepickerdialog.cc 
new/libt3widget-1.2.0/src/dialogs/attributepickerdialog.cc
--- old/libt3widget-1.0.6/src/dialogs/attributepickerdialog.cc  2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/dialogs/attributepickerdialog.cc  2019-12-03 
20:12:13.000000000 +0100
@@ -46,6 +46,20 @@
   implementation_t() : fg_picker(nullptr), bg_picker(nullptr), 
base_attributes(0) {}
 };
 
+namespace {
+
+checkbox_t::TriState attr_to_state(t3_attr_t attr, t3_attr_t bit) {
+  if (attr & bit) {
+    return checkbox_t::CHECKED;
+  }
+  if (attr & (bit << (T3_ATTR_COLOR_SHIFT + 17))) {
+    return checkbox_t::UNCHECKED;
+  }
+  return checkbox_t::INDERMINATE;
+}
+
+}  // namespace
+
 attribute_picker_dialog_t::attribute_picker_dialog_t(optional<std::string> 
_title,
                                                      bool with_default)
     : dialog_t(ATTRIBUTE_PICKER_DIALOG_HEIGHT + 2, 
ATTRIBUTE_PICKER_DIALOG_WIDTH, std::move(_title),
@@ -56,7 +70,7 @@
 
   t3_term_get_caps(&capabilities);
 
-  impl->underline_box = emplace_back<checkbox_t>(false);
+  impl->underline_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED);
   impl->underline_box->set_position(1, 2);
   smart_label_t *underline_label = emplace_back<smart_label_t>("_Underline");
   underline_label->set_anchor(impl->underline_box,
@@ -68,7 +82,7 @@
   impl->underline_box->connect_toggled([this] { attribute_changed(); });
   impl->underline_box->connect_activate([this] { ok_activate(); });
 
-  impl->bold_box = emplace_back<checkbox_t>(false);
+  impl->bold_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED);
   impl->bold_box->set_anchor(impl->underline_box,
                              T3_PARENT(T3_ANCHOR_TOPLEFT) | 
T3_CHILD(T3_ANCHOR_TOPLEFT));
   impl->bold_box->set_position(1, 0);
@@ -82,7 +96,7 @@
   impl->bold_box->connect_toggled([this] { attribute_changed(); });
   impl->bold_box->connect_activate([this] { ok_activate(); });
 
-  impl->dim_box = emplace_back<checkbox_t>(false);
+  impl->dim_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED);
   impl->dim_box->set_anchor(impl->bold_box,
                             T3_PARENT(T3_ANCHOR_TOPLEFT) | 
T3_CHILD(T3_ANCHOR_TOPLEFT));
   impl->dim_box->set_position(1, 0);
@@ -95,7 +109,7 @@
   impl->dim_box->connect_toggled([this] { attribute_changed(); });
   impl->dim_box->connect_activate([this] { ok_activate(); });
 
-  impl->reverse_box = emplace_back<checkbox_t>(false);
+  impl->reverse_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED);
   impl->reverse_box->set_anchor(impl->dim_box,
                                 T3_PARENT(T3_ANCHOR_TOPLEFT) | 
T3_CHILD(T3_ANCHOR_TOPLEFT));
   impl->reverse_box->set_position(1, 0);
@@ -109,7 +123,7 @@
   impl->reverse_box->connect_toggled([this] { attribute_changed(); });
   impl->reverse_box->connect_activate([this] { ok_activate(); });
 
-  impl->blink_box = emplace_back<checkbox_t>(false);
+  impl->blink_box = emplace_back<checkbox_t>(checkbox_t::UNCHECKED);
   impl->blink_box->set_anchor(impl->reverse_box,
                               T3_PARENT(T3_ANCHOR_TOPLEFT) | 
T3_CHILD(T3_ANCHOR_TOPLEFT));
   impl->blink_box->set_position(1, 0);
@@ -220,20 +234,55 @@
 
 t3_attr_t attribute_picker_dialog_t::get_attribute() const {
   t3_attr_t result = 0;
-  if (impl->underline_box->get_state()) {
-    result |= T3_ATTR_UNDERLINE;
+  switch (impl->underline_box->get_tristate()) {
+    case checkbox_t::UNCHECKED:
+      result |= T3_ATTR_UNDERLINE_SET;
+      break;
+    case checkbox_t::CHECKED:
+      result |= T3_ATTR_UNDERLINE | T3_ATTR_UNDERLINE_SET;
+      break;
+    default:
+      break;
   }
-  if (impl->bold_box->get_state()) {
-    result |= T3_ATTR_BOLD;
+  switch (impl->bold_box->get_tristate()) {
+    case checkbox_t::UNCHECKED:
+      result |= T3_ATTR_BOLD_SET;
+      break;
+    case checkbox_t::CHECKED:
+      result |= T3_ATTR_BOLD | T3_ATTR_BOLD_SET;
+      break;
+    default:
+      break;
   }
-  if (impl->dim_box->get_state()) {
-    result |= T3_ATTR_DIM;
+  switch (impl->dim_box->get_tristate()) {
+    case checkbox_t::UNCHECKED:
+      result |= T3_ATTR_DIM_SET;
+      break;
+    case checkbox_t::CHECKED:
+      result |= T3_ATTR_DIM | T3_ATTR_DIM_SET;
+      break;
+    default:
+      break;
   }
-  if (impl->blink_box->get_state()) {
-    result |= T3_ATTR_BLINK;
+  switch (impl->blink_box->get_tristate()) {
+    case checkbox_t::UNCHECKED:
+      result |= T3_ATTR_BLINK_SET;
+      break;
+    case checkbox_t::CHECKED:
+      result |= T3_ATTR_BLINK | T3_ATTR_BLINK_SET;
+      break;
+    default:
+      break;
   }
-  if (impl->reverse_box->get_state()) {
-    result |= T3_ATTR_REVERSE;
+  switch (impl->reverse_box->get_tristate()) {
+    case checkbox_t::UNCHECKED:
+      result |= T3_ATTR_REVERSE_SET;
+      break;
+    case checkbox_t::CHECKED:
+      result |= T3_ATTR_REVERSE | T3_ATTR_REVERSE_SET;
+      break;
+    default:
+      break;
   }
   if (impl->fg_picker != nullptr) {
     result |= impl->fg_picker->get_color();
@@ -245,11 +294,11 @@
 }
 
 void attribute_picker_dialog_t::set_attribute(t3_attr_t attr) {
-  impl->underline_box->set_state(attr & T3_ATTR_UNDERLINE);
-  impl->bold_box->set_state(attr & T3_ATTR_BOLD);
-  impl->dim_box->set_state(attr & T3_ATTR_DIM);
-  impl->blink_box->set_state(attr & T3_ATTR_BLINK);
-  impl->reverse_box->set_state(attr & T3_ATTR_REVERSE);
+  impl->underline_box->set_tristate(attr_to_state(attr, T3_ATTR_UNDERLINE));
+  impl->bold_box->set_tristate(attr_to_state(attr, T3_ATTR_BOLD));
+  impl->dim_box->set_tristate(attr_to_state(attr, T3_ATTR_DIM));
+  impl->blink_box->set_tristate(attr_to_state(attr, T3_ATTR_BLINK));
+  impl->reverse_box->set_tristate(attr_to_state(attr, T3_ATTR_REVERSE));
   if (impl->fg_picker != nullptr) {
     impl->fg_picker->set_color(attr);
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libt3widget-1.0.6/src/dialogs/attributepickerdialog.h 
new/libt3widget-1.2.0/src/dialogs/attributepickerdialog.h
--- old/libt3widget-1.0.6/src/dialogs/attributepickerdialog.h   2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/dialogs/attributepickerdialog.h   2019-12-03 
20:12:13.000000000 +0100
@@ -45,6 +45,7 @@
   ~attribute_picker_dialog_t() override;
   void show() override;
 
+  /** Set the value of the attributes to a specific value. */
   void set_attribute(t3_attr_t attr);
   /** Set the base attributes for the attribute picker.
       @param attr The base attributes to use
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/dialogs/dialog.cc 
new/libt3widget-1.2.0/src/dialogs/dialog.cc
--- old/libt3widget-1.0.6/src/dialogs/dialog.cc 2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/dialogs/dialog.cc 2019-12-03 20:12:13.000000000 
+0100
@@ -45,7 +45,8 @@
 
     This constructor should only be called by ::main_window_base_t.
 */
-dialog_t::dialog_t() : impl(new implementation_t(nullopt)) {}
+dialog_t::dialog_t()
+    : dialog_base_t(impl_alloc<implementation_t>(0)), 
impl(new_impl<implementation_t>(nullopt)) {}
 
 void dialog_t::activate_dialog() {
   if (!active_dialogs.empty()) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/dialogs/finddialog.cc 
new/libt3widget-1.2.0/src/dialogs/finddialog.cc
--- old/libt3widget-1.0.6/src/dialogs/finddialog.cc     2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/dialogs/finddialog.cc     2019-12-03 
20:12:13.000000000 +0100
@@ -50,7 +50,8 @@
 // FIXME: keep (limited) history
 
 find_dialog_t::find_dialog_t(int _state)
-    : dialog_t(FIND_DIALOG_HEIGHT, FIND_DIALOG_WIDTH, _("Find")), impl(new 
implementation_t()) {
+    : dialog_t(FIND_DIALOG_HEIGHT, FIND_DIALOG_WIDTH, _("Find"), 
impl_alloc<implementation_t>(0)),
+      impl(new_impl<implementation_t>()) {
   smart_label_t *find_label = emplace_back<smart_label_t>("Fi_nd", true);
   find_label->set_position(1, 2);
   impl->find_line = emplace_back<text_field_t>();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/dialogs/menupanel.cc 
new/libt3widget-1.2.0/src/dialogs/menupanel.cc
--- old/libt3widget-1.0.6/src/dialogs/menupanel.cc      2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/dialogs/menupanel.cc      2019-12-03 
20:12:13.000000000 +0100
@@ -125,6 +125,10 @@
   }
   if (event.x < 1 || event.x > window.get_width() - 2 || event.y < 1 ||
       event.y > window.get_height() - 2) {
+    if (event.type == EMOUSE_BUTTON_PRESS &&
+        (event.button_state & (EMOUSE_BUTTON_LEFT | EMOUSE_BUTTON_RIGHT | 
EMOUSE_BUTTON_MIDDLE))) {
+      close();
+    }
     return true;
   }
   focus_widget(event.y - 1);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/findcontext.cc 
new/libt3widget-1.2.0/src/findcontext.cc
--- old/libt3widget-1.0.6/src/findcontext.cc    2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/findcontext.cc    2019-12-03 20:12:13.000000000 
+0100
@@ -196,7 +196,6 @@
   }
 
   size_t c_size;
-  const char *c;
 
   text_pos_t start = std::max<text_pos_t>(0, result->start.pos);
   if (static_cast<size_t>(start) > haystack.size()) {
@@ -225,7 +224,6 @@
         char *c_data = reinterpret_cast<char *>(
             u8_casefold(reinterpret_cast<const uint8_t *>(substr.data()), 
substr.size(), nullptr,
                         nullptr, reinterpret_cast<uint8_t *>(folded_.get()), 
&c_size));
-        c = c_data;
         if (c_data != folded_.get()) {
           // Previous value of folded will be automatically deleted.
           folded_.reset(c_data);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/key.cc 
new/libt3widget-1.2.0/src/key.cc
--- old/libt3widget-1.0.6/src/key.cc    2019-05-05 10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/key.cc    2019-12-03 20:12:13.000000000 +0100
@@ -660,27 +660,27 @@
       }
 
     } else {
+      key_t key = separate_keypad ? iter->second : map_kp(iter->second);
+      for (size_t j = dash; j != std::string::npos && key_node->key[j] != 0; 
j++) {
+        switch (key_node->key[j]) {
+          case 'c':
+            key |= EKEY_CTRL;
+            break;
+          case 'm':
+            key |= EKEY_META;
+            break;
+          case 's':
+            key |= EKEY_SHIFT;
+            break;
+          default:
+            break;
+        }
+      }
       if (key_node->string[0] != 27) {
         if (strlen(key_node->string) == 1) {
-          map_single[static_cast<unsigned char>(key_node->string[0])] = 
iter->second;
+          map_single[static_cast<unsigned char>(key_node->string[0])] = key;
         }
       } else {
-        key_t key = separate_keypad ? iter->second : map_kp(iter->second);
-        for (size_t j = dash; j != std::string::npos && key_node->key[j] != 0; 
j++) {
-          switch (key_node->key[j]) {
-            case 'c':
-              key |= EKEY_CTRL;
-              break;
-            case 'm':
-              key |= EKEY_META;
-              break;
-            case 's':
-              key |= EKEY_SHIFT;
-              break;
-            default:
-              break;
-          }
-        }
         map[key_node->string] = key;
       }
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/main.h 
new/libt3widget-1.2.0/src/main.h
--- old/libt3widget-1.0.6/src/main.h    2019-05-05 10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/main.h    2019-12-03 20:12:13.000000000 +0100
@@ -34,7 +34,7 @@
     The value 0 is an invalid value which should be replaced by the script
     that builds the release package.
 */
-#define T3_WIDGET_VERSION 0x010006
+#define T3_WIDGET_VERSION 0x010200
 
 /** A class representing an error from one of the supporting libraries. */
 class T3_WIDGET_API complex_error_t {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/signals.h 
new/libt3widget-1.2.0/src/signals.h
--- old/libt3widget-1.0.6/src/signals.h 2019-05-05 10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/signals.h 2019-12-03 20:12:13.000000000 +0100
@@ -68,6 +68,12 @@
   connection_t() = default;
   connection_t(std::shared_ptr<internal::func_ptr_base_t> f) : func(f) {}
   connection_t(const connection_t &other) : func(other.func) {}
+
+  connection_t &operator=(const connection_t &other) {
+    func = other.func;
+    return *this;
+  }
+
   /// Disconnect the callback from the signal.
   void disconnect() {
     if (func) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/textbuffer.cc 
new/libt3widget-1.2.0/src/textbuffer.cc
--- old/libt3widget-1.0.6/src/textbuffer.cc     2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/textbuffer.cc     2019-12-03 20:12:13.000000000 
+0100
@@ -13,7 +13,6 @@
 */
 #include <algorithm>
 #include <cstring>
-#include <ext/alloc_traits.h>
 #include <limits>
 #include <memory>
 #include <string>
@@ -58,6 +57,8 @@
 
 bool text_buffer_t::backspace_char() { return impl->backspace_char(); }
 
+bool text_buffer_t::backspace_word() { return impl->backspace_word(); }
+
 bool text_buffer_t::is_modified() const { return 
!impl->undo_list.is_at_mark(); }
 
 bool text_buffer_t::merge(bool backspace) { return impl->merge(backspace); }
@@ -266,6 +267,25 @@
     return false;
   }
   cursor.pos = newpos;
+  cursor.pos = lines[cursor.line]->adjust_position(cursor.pos, 0);
+
+  rewrap_required(rewrap_type_t::REWRAP_LINE_LOCAL, cursor.line, cursor.pos);
+
+  last_undo_position = cursor;
+  return true;
+}
+
+bool text_buffer_t::implementation_t::backspace_word() {
+  text_pos_t newpos;
+  text_line_t *line = lines[cursor.line].get();
+  newpos = line->get_previous_word(cursor.pos);
+  if (newpos < 0) {
+    newpos = 0;
+  }
+  if (!line->backspace_word(cursor.pos, newpos, get_undo(UNDO_BACKSPACE))) {
+    return false;
+  }
+  cursor.pos = newpos;
   cursor.pos = lines[cursor.line]->adjust_position(cursor.pos, 0);
 
   rewrap_required(rewrap_type_t::REWRAP_LINE_LOCAL, cursor.line, cursor.pos);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/textbuffer.h 
new/libt3widget-1.2.0/src/textbuffer.h
--- old/libt3widget-1.0.6/src/textbuffer.h      2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/textbuffer.h      2019-12-03 20:12:13.000000000 
+0100
@@ -57,6 +57,7 @@
   bool overwrite_char(key_t c);
   bool delete_char();
   bool backspace_char();
+  bool backspace_word();
   bool merge(bool backspace);
   bool break_line(const std::string &indent = "");
   bool insert_block(const std::string &block);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/textbuffer_impl.h 
new/libt3widget-1.2.0/src/textbuffer_impl.h
--- old/libt3widget-1.0.6/src/textbuffer_impl.h 2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/textbuffer_impl.h 2019-12-03 20:12:13.000000000 
+0100
@@ -57,6 +57,7 @@
   bool overwrite_char(key_t c);
   bool delete_char();
   bool backspace_char();
+  bool backspace_word();
   bool merge_internal(text_pos_t line);
   bool insert_block_internal(text_coordinate_t insert_at, 
std::unique_ptr<text_line_t> block);
   void delete_block_internal(text_coordinate_t start, text_coordinate_t end, 
undo_t *undo);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/textline.cc 
new/libt3widget-1.2.0/src/textline.cc
--- old/libt3widget-1.0.6/src/textline.cc       2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/textline.cc       2019-12-03 20:12:13.000000000 
+0100
@@ -782,6 +782,35 @@
   return insert_char(impl->buffer.size(), c, undo);
 }
 
+/* Backspace word at 'pos' */
+bool text_line_t::backspace_word(text_pos_t pos, text_pos_t newpos, undo_t 
*undo) {
+  text_pos_t oldspace;
+
+  if (pos < 0 || static_cast<size_t>(pos) > impl->buffer.size()) {
+    return false;
+  }
+
+  if (newpos < 0 || static_cast<size_t>(newpos) > impl->buffer.size()) {
+    return false;
+  }
+
+  if (impl->starts_with_combining && newpos == 0) {
+    impl->starts_with_combining = false;
+  }
+
+  oldspace = pos - newpos;
+  if (undo != nullptr) {
+    tiny_string_t *undo_text = undo->get_text();
+    undo_text->reserve(oldspace);
+    ASSERT(undo->get_type() == UNDO_BACKSPACE);
+    undo_text->insert(0, string_view(impl->buffer.data() + newpos, oldspace));
+  }
+
+  impl->buffer.erase(newpos, oldspace);
+
+  return true;
+}
+
 /* Delete char at 'pos - 1' */
 bool text_line_t::backspace_char(text_pos_t pos, undo_t *undo) {
   if (pos == 0) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/textline.h 
new/libt3widget-1.2.0/src/textline.h
--- old/libt3widget-1.0.6/src/textline.h        2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/textline.h        2019-12-03 20:12:13.000000000 
+0100
@@ -132,6 +132,7 @@
   bool delete_char(text_pos_t pos, undo_t *undo);
   bool append_char(key_t c, undo_t *undo);
   bool backspace_char(text_pos_t pos, undo_t *undo);
+  bool backspace_word(text_pos_t pos, text_pos_t newpos, undo_t *undo);
 
   text_pos_t adjust_position(text_pos_t pos, int adjust) const;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/util.cc 
new/libt3widget-1.2.0/src/util.cc
--- old/libt3widget-1.0.6/src/util.cc   2019-05-05 10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/util.cc   2019-12-03 20:12:13.000000000 +0100
@@ -284,30 +284,31 @@
   size_t buffer_max = 511;
   char *buffer = nullptr, *result;
 
+  call_on_return_t free_buffer([&] { free(buffer); });
+
   do {
     result = reinterpret_cast<char *>(realloc(buffer, buffer_max));
     if (result == nullptr) {
-      free(buffer);
       throw ENOMEM;
     }
     buffer = result;
     if ((result = getcwd(buffer, buffer_max)) == nullptr) {
       if (errno != ERANGE) {
-        int error_save = errno;
-        free(buffer);
-        throw error_save;
+        lprintf("Could not get working directory (returning /): %s\n", 
strerror(errno));
+        return "/";
       }
 
       if ((static_cast<size_t>(-1)) / 2 < buffer_max) {
-        free(buffer);
         throw ENOMEM;
       }
     }
   } while (result == nullptr);
 
-  std::string retval(buffer);
-  free(buffer);
-  return retval;
+  if (buffer[0] == '/') {
+    return buffer;
+  } else {
+    return "/";
+  }
 }
 
 std::string get_directory(string_view directory) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/button.cc 
new/libt3widget-1.2.0/src/widgets/button.cc
--- old/libt3widget-1.0.6/src/widgets/button.cc 2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/widgets/button.cc 2019-12-03 20:12:13.000000000 
+0100
@@ -69,16 +69,16 @@
       break;
     case EKEY_LEFT:
       move_focus_left();
-      break;
+      return !impl->has_focus;
     case EKEY_RIGHT:
       move_focus_right();
-      break;
+      return !impl->has_focus;
     case EKEY_UP:
       move_focus_up();
-      break;
+      return !impl->has_focus;
     case EKEY_DOWN:
       move_focus_down();
-      break;
+      return !impl->has_focus;
     default:
       return false;
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/checkbox.cc 
new/libt3widget-1.2.0/src/widgets/checkbox.cc
--- old/libt3widget-1.0.6/src/widgets/checkbox.cc       2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/widgets/checkbox.cc       2019-12-03 
20:12:13.000000000 +0100
@@ -23,10 +23,15 @@
 #include "t3window/window.h"
 
 namespace t3widget {
+namespace {
+const char kStateToChar[] = " X:";
+}
 
 struct checkbox_t::implementation_t {
-  /** Current state (true if checked). */
-  bool state;
+  /** Whether tri-state mode is enabled. */
+  bool is_tristate;
+  /** Current state. */
+  TriState state;
   /** Boolean indicating whether this widget should be drawn as focuessed. */
   bool has_focus = false;
   /** Label associated with this checkbox_t. Used for determining the hotkey. 
*/
@@ -34,41 +39,71 @@
   signal_t<> activate;
   signal_t<> toggled;
 
-  implementation_t(bool _state) : state(_state) {}
+  implementation_t(bool _state)
+      : is_tristate(false), state(_state ? checkbox_t::CHECKED : 
checkbox_t::UNCHECKED) {}
+  implementation_t(TriState _state) : is_tristate(true), state(_state) {}
 };
 
-checkbox_t::checkbox_t(bool _state)
+checkbox_t::checkbox_t(bool state)
     : widget_t(1, 3, true,
                
impl_alloc<focus_widget_t::implementation_t>(impl_alloc<implementation_t>(0))),
       focus_widget_t(this),
-      impl(new_impl<implementation_t>(_state)) {}
+      impl(new_impl<implementation_t>(state)) {}
+
+checkbox_t::checkbox_t(TriState state)
+    : widget_t(1, 3, true,
+               
impl_alloc<focus_widget_t::implementation_t>(impl_alloc<implementation_t>(0))),
+      focus_widget_t(this),
+      impl(new_impl<implementation_t>(state)) {}
 
 checkbox_t::~checkbox_t() {}
 
+void checkbox_t::next_state() {
+  if (impl->is_tristate) {
+    switch (impl->state) {
+      case UNCHECKED:
+        impl->state = CHECKED;
+        break;
+      case CHECKED:
+        impl->state = INDERMINATE;
+        break;
+      default:
+        impl->state = UNCHECKED;
+        break;
+    }
+  } else {
+    if (impl->state == UNCHECKED) {
+      impl->state = CHECKED;
+    } else {
+      impl->state = UNCHECKED;
+    }
+  }
+  force_redraw();
+  impl->toggled();
+  update_contents();
+}
+
 bool checkbox_t::process_key(key_t key) {
   switch (key) {
     case ' ':
     case EKEY_HOTKEY:
-      impl->state ^= true;
-      force_redraw();
-      impl->toggled();
-      update_contents();
+      next_state();
       break;
     case EKEY_NL:
       impl->activate();
       break;
     case EKEY_LEFT:
       move_focus_left();
-      break;
+      return !impl->has_focus;
     case EKEY_RIGHT:
       move_focus_right();
-      break;
+      return !impl->has_focus;
     case EKEY_UP:
       move_focus_up();
-      break;
+      return !impl->has_focus;
     case EKEY_DOWN:
       move_focus_down();
-      break;
+      return !impl->has_focus;
     default:
       return false;
   }
@@ -88,8 +123,12 @@
   window.set_default_attrs(attributes.dialog);
   window.set_paint(0, 0);
   window.addch('[', 0);
-  window.addch(is_enabled() ? (impl->state ? 'X' : ' ') : '-',
-               impl->has_focus ? T3_ATTR_REVERSE : 0);
+  char c = '-';
+  if (is_enabled()) {
+    c = kStateToChar[std::min<int>(impl->state, 2)];
+  }
+
+  window.addch(c, impl->has_focus ? T3_ATTR_REVERSE : 0);
   window.addch(']', 0);
 }
 
@@ -101,10 +140,10 @@
   impl->has_focus = focus;
 }
 
-bool checkbox_t::get_state() { return impl->state; }
+bool checkbox_t::get_state() { return impl->state == CHECKED; }
 
 void checkbox_t::set_state(bool _state) {
-  impl->state = !!_state;
+  impl->state = _state ? CHECKED : UNCHECKED;
   force_redraw();
 }
 
@@ -127,14 +166,29 @@
 
 bool checkbox_t::process_mouse_event(mouse_event_t event) {
   if (event.button_state & EMOUSE_CLICKED_LEFT) {
-    impl->state ^= true;
-    force_redraw();
-    impl->toggled();
-    update_contents();
+    next_state();
   }
   return true;
 }
 
+void checkbox_t::set_tristate_mode(bool is_tristate) {
+  if (impl->is_tristate == is_tristate) {
+    return;
+  }
+  if (impl->is_tristate && impl->state == INDERMINATE) {
+    impl->state = UNCHECKED;
+    force_redraw();
+  }
+  impl->is_tristate = is_tristate;
+}
+
+checkbox_t::TriState checkbox_t::get_tristate() const { return impl->state; }
+
+void checkbox_t::set_tristate(TriState state) {
+  impl->state = state;
+  force_redraw();
+}
+
 _T3_WIDGET_IMPL_SIGNAL(checkbox_t, activate)
 _T3_WIDGET_IMPL_SIGNAL(checkbox_t, toggled)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/checkbox.h 
new/libt3widget-1.2.0/src/widgets/checkbox.h
--- old/libt3widget-1.0.6/src/widgets/checkbox.h        2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/widgets/checkbox.h        2019-12-03 
20:12:13.000000000 +0100
@@ -33,11 +33,16 @@
 
   single_alloc_pimpl_t<implementation_t> impl;
 
+  void next_state();
+
  public:
+  /** Enum indicating the different states the checkbox can be in. */
+  enum TriState { UNCHECKED, CHECKED, INDERMINATE };
   /** Create a new checkbox_t.
       @param _state The initial state of the checkbox_t.
   */
-  checkbox_t(bool _state = false);
+  checkbox_t(bool state = false);
+  checkbox_t(TriState tristate);
   ~checkbox_t() override;
   bool process_key(key_t key) override;
   /** Set the size of this checkbox_t (ignored).
@@ -52,13 +57,26 @@
       contents will be shown as a dash (-).
   */
   void set_enabled(bool enable) override;
-  /** Retrieve the current state of the checkbox_t. */
+  /** Retrieve the current state of the checkbox_t.
+
+      If the checkbox_t is in tri-state mode and the value is INDETERMINATE, 
false is returned. */
   bool get_state();
   /** Set the current state of the checkbox_t. */
   void set_state(bool _state);
   /** Associate this checkbox_t with a smart_label_t. */
   void set_label(smart_label_t *_label);
 
+  /** Sets whether the checkbox_t should be in tri-state mode.
+
+      When switching the checkbox_t to non-tri-state mode and the value is 
currently INDETERMINATE,
+      the value will be set to UNCHECKED.
+  */
+  void set_tristate_mode(bool is_tristate);
+  /** Retrieve the current state of the checkbox_t. */
+  TriState get_tristate() const;
+  /** Set the current state of the checkbox_t. */
+  void set_tristate(TriState state);
+
   /** @fn connection_t connect_activate(std::function<void()> func)
       Connect a callback to the #activate signal.
   */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/editwindow.cc 
new/libt3widget-1.2.0/src/widgets/editwindow.cc
--- old/libt3widget-1.0.6/src/widgets/editwindow.cc     2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/widgets/editwindow.cc     2019-12-03 
20:12:13.000000000 +0100
@@ -134,6 +134,18 @@
       repaint_max = std::numeric_limits<text_pos_t>::max(); /**< Last line to 
repaint. */
 };
 
+struct edit_window_t::behavior_parameters_t::implementation_t {
+  text_coordinate_t top_left{0, 0};
+  text_pos_t last_set_pos = 0;
+  int tabsize = 8;
+  int ins_mode = 0;
+  wrap_type_t wrap_type = wrap_type_t::NONE;
+  bool tab_spaces = false;
+  bool auto_indent = true;
+  bool indent_aware_home = true;
+  bool show_tabs = false;
+};
+
 void edit_window_t::init(bool _init) {
   if (_init) {
     /* Construct these from t3widget::init, such that the locale is set 
correctly and
@@ -153,11 +165,12 @@
     global_find_dialog = nullptr;
     delete replace_buttons;
     replace_buttons = nullptr;
+    delete right_click_menu;
+    right_click_menu = nullptr;
   }
 }
 
-edit_window_t::edit_window_t(text_buffer_t *_text, const view_parameters_t 
*params)
-    : impl(new implementation_t()), text(nullptr) {
+void edit_window_t::init_instance() {
   /* Register the unbacked window for mouse events, such that we can get focus
      if the bottom line is clicked. */
   init_unbacked_window(11, 11, true);
@@ -183,8 +196,6 @@
   
impl->scrollbar->connect_clicked(bind_front(&edit_window_t::scrollbar_clicked, 
this));
   
impl->scrollbar->connect_dragged(bind_front(&edit_window_t::scrollbar_dragged, 
this));
 
-  set_text(_text == nullptr ? new text_buffer_t() : _text, params);
-
   impl->screen_pos = 0;
   impl->focus = false;
 
@@ -192,12 +203,36 @@
   impl->autocomplete_panel->connect_activate([this] { 
autocomplete_activated(); });
 }
 
+edit_window_t::edit_window_t(text_buffer_t *_text, const view_parameters_t 
*params)
+    : widget_t(impl_alloc<implementation_t>(0)), 
impl(new_impl<implementation_t>()), text(nullptr) {
+  init_instance();
+  set_text(_text == nullptr ? new text_buffer_t() : _text, params);
+}
+
+edit_window_t::edit_window_t(text_buffer_t *_text, const behavior_parameters_t 
*params)
+    : widget_t(impl_alloc<implementation_t>(0)), 
impl(new_impl<implementation_t>()), text(nullptr) {
+  init_instance();
+  set_text(_text == nullptr ? new text_buffer_t() : _text, params);
+}
+
 edit_window_t::~edit_window_t() { delete impl->wrap_info; }
 
 void edit_window_t::set_text(text_buffer_t *_text, const view_parameters_t 
*params) {
   if (text == _text) {
     return;
   }
+  if (params != nullptr) {
+    behavior_parameters_t new_params(*params);
+    set_text(_text, &new_params);
+  } else {
+    set_text(_text, static_cast<behavior_parameters_t *>(nullptr));
+  }
+}
+
+void edit_window_t::set_text(text_buffer_t *_text, const behavior_parameters_t 
*params) {
+  if (text == _text) {
+    return;
+  }
 
   text = _text;
   if (params != nullptr) {
@@ -219,7 +254,12 @@
 
 bool edit_window_t::set_size(optint height, optint width) {
   bool result = true;
-  // FIXME: these int's are optional!!! Take that into account below!
+  if (!height.is_valid()) {
+    height = window.get_height();
+  }
+  if (!width.is_valid()) {
+    width = window.get_width();
+  }
 
   if (width.value() != window.get_width() || height.value() > 
window.get_height()) {
     update_repaint_lines(0, std::numeric_limits<text_pos_t>::max());
@@ -1012,6 +1052,29 @@
       impl->last_set_pos = impl->screen_pos;
       break;
     }
+    case EKEY_BS | EKEY_CTRL:
+      if (text->get_selection_mode() == selection_mode_t::NONE) {
+        const text_coordinate_t cursor = text->get_cursor();
+        if (cursor.pos <= text->get_line_size(cursor.line)) {
+          if (cursor.pos != 0) {
+            text->backspace_word();
+            update_repaint_lines(cursor.line);
+          } else if (cursor.line != 0) {
+            text->merge(true);
+            update_repaint_lines(cursor.line);
+          }
+        } else {
+          ASSERT(false);
+        }
+        ensure_cursor_on_screen();
+        impl->last_set_pos = impl->screen_pos;
+      } else {
+        delete_selection();
+      }
+      if (impl->autocomplete_panel->is_shown()) {
+        activate_autocomplete(false);
+      }
+      break;
     case EKEY_BS:
       if (text->get_selection_mode() == selection_mode_t::NONE) {
         const text_coordinate_t cursor = text->get_cursor();
@@ -1305,6 +1368,8 @@
     case ACTION_PASTE_SELECTION:
       paste(false);
       break;
+    default:
+      break;
   }
 }
 
@@ -1596,6 +1661,15 @@
   *params = view_parameters_t(this);
 }
 
+std::unique_ptr<edit_window_t::behavior_parameters_t> 
edit_window_t::save_behavior_parameters() {
+  // This can't use make_unique, as the constructor is private and only this 
class is a friend.
+  return wrap_unique(new behavior_parameters_t(*this));
+}
+
+void edit_window_t::save_behavior_parameters(behavior_parameters_t *params) {
+  *params = behavior_parameters_t(*this);
+}
+
 void edit_window_t::draw_info_window() {}
 
 void edit_window_t::set_autocompleter(autocompleter_t *_autocompleter) {
@@ -1897,6 +1971,102 @@
 }
 void edit_window_t::view_parameters_t::set_show_tabs(bool _show_tabs) { 
show_tabs = _show_tabs; }
 
+//====================== behavior_parameters_t ========================
+
+edit_window_t::behavior_parameters_t::behavior_parameters_t(const 
edit_window_t &view)
+    : impl(new implementation_t) {
+  impl->top_left = view.impl->top_left;
+  impl->wrap_type = view.impl->wrap_type;
+  if (impl->wrap_type != wrap_type_t::NONE) {
+    impl->top_left.pos =
+        view.impl->wrap_info->calculate_line_pos(impl->top_left.line, 0, 
impl->top_left.pos);
+  }
+  impl->tabsize = view.impl->tabsize;
+  impl->tab_spaces = view.impl->tab_spaces;
+  impl->ins_mode = view.impl->ins_mode;
+  impl->last_set_pos = view.impl->last_set_pos;
+  impl->auto_indent = view.impl->auto_indent;
+  impl->indent_aware_home = view.impl->indent_aware_home;
+  impl->show_tabs = view.impl->show_tabs;
+}
+
+edit_window_t::behavior_parameters_t::behavior_parameters_t() : impl(new 
implementation_t) {}
+
+edit_window_t::behavior_parameters_t::behavior_parameters_t(
+    const edit_window_t::view_parameters_t &params)
+    : impl(new implementation_t) {
+  impl->top_left = params.top_left;
+  impl->wrap_type = params.wrap_type;
+  impl->tabsize = params.tabsize;
+  impl->tab_spaces = params.tab_spaces;
+  impl->ins_mode = params.ins_mode;
+  impl->last_set_pos = params.last_set_pos;
+  impl->auto_indent = params.auto_indent;
+  impl->indent_aware_home = params.indent_aware_home;
+  impl->show_tabs = params.show_tabs;
+}
+
+/* Destructor must be defined in the .cc file, because in the .h file the size 
of implementation_t
+   is undefined. */
+edit_window_t::behavior_parameters_t::~behavior_parameters_t() {}
+
+edit_window_t::behavior_parameters_t 
&edit_window_t::behavior_parameters_t::operator=(
+    const behavior_parameters_t &other) {
+  *impl = *other.impl;
+  return *this;
+}
+
+void edit_window_t::behavior_parameters_t::apply_parameters(edit_window_t 
*view) const {
+  view->impl->top_left = impl->top_left;
+  view->impl->tabsize = impl->tabsize;
+  view->set_wrap(impl->wrap_type);
+  /* view->set_wrap will make sure that view->wrap_info is nullptr if
+     wrap_type != NONE. */
+  if (view->impl->wrap_info != nullptr) {
+    view->impl->wrap_info->set_text_buffer(view->text);
+    view->impl->top_left.pos = 
view->impl->wrap_info->find_line(impl->top_left);
+  }
+  // the calling function will call ensure_cursor_on_screen
+  view->impl->tab_spaces = impl->tab_spaces;
+  view->impl->ins_mode = impl->ins_mode;
+  view->impl->last_set_pos = impl->last_set_pos;
+  view->impl->auto_indent = impl->auto_indent;
+  view->impl->indent_aware_home = impl->indent_aware_home;
+  view->impl->show_tabs = impl->show_tabs;
+}
+
+void edit_window_t::behavior_parameters_t::set_tabsize(int _tabsize) { 
impl->tabsize = _tabsize; }
+void edit_window_t::behavior_parameters_t::set_wrap(wrap_type_t _wrap_type) {
+  impl->wrap_type = _wrap_type;
+}
+void edit_window_t::behavior_parameters_t::set_tab_spaces(bool _tab_spaces) {
+  impl->tab_spaces = _tab_spaces;
+}
+void edit_window_t::behavior_parameters_t::set_auto_indent(bool _auto_indent) {
+  impl->auto_indent = _auto_indent;
+}
+void edit_window_t::behavior_parameters_t::set_indent_aware_home(bool 
_indent_aware_home) {
+  impl->indent_aware_home = _indent_aware_home;
+}
+void edit_window_t::behavior_parameters_t::set_show_tabs(bool _show_tabs) {
+  impl->show_tabs = _show_tabs;
+}
+void edit_window_t::behavior_parameters_t::set_top_left(text_coordinate_t pos) 
{
+  impl->top_left = pos;
+}
+
+int edit_window_t::behavior_parameters_t::get_tabsize() const { return 
impl->tabsize; }
+wrap_type_t edit_window_t::behavior_parameters_t::get_wrap_type() const { 
return impl->wrap_type; }
+bool edit_window_t::behavior_parameters_t::get_tab_spaces() const { return 
impl->tab_spaces; }
+bool edit_window_t::behavior_parameters_t::get_auto_indent() const { return 
impl->auto_indent; }
+bool edit_window_t::behavior_parameters_t::get_indent_aware_home() const {
+  return impl->indent_aware_home;
+}
+bool edit_window_t::behavior_parameters_t::get_show_tabs() const { return 
impl->show_tabs; }
+text_coordinate_t edit_window_t::behavior_parameters_t::get_top_left() const {
+  return impl->top_left;
+}
+
 //====================== autocomplete_panel_t ========================
 
 edit_window_t::autocomplete_panel_t::autocomplete_panel_t(edit_window_t 
*parent)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/editwindow.h 
new/libt3widget-1.2.0/src/widgets/editwindow.h
--- old/libt3widget-1.0.6/src/widgets/editwindow.h      2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/widgets/editwindow.h      2019-12-03 
20:12:13.000000000 +0100
@@ -25,7 +25,6 @@
 
 #include <t3widget/autocompleter.h>
 #include <t3widget/dialogs/menupanel.h>
-#include <t3widget/dialogs/popup.h>
 #include <t3widget/interfaces.h>
 #include <t3widget/key.h>
 #include <t3widget/key_binding.h>
@@ -116,6 +115,12 @@
 
   void right_click_menu_activated(int action);
 
+  /** Internal function for initializing an instance.
+
+      Called from the constructors to do the part of the work that is the 
common between them.
+  */
+  void init_instance();
+
  protected:
   text_buffer_t *text;            /**< Buffer holding the text currently 
displayed. */
   t3window::window_t info_window; /**< Window for other information, such as 
buffer name. */
@@ -150,12 +155,20 @@
 
  public:
   class T3_WIDGET_API view_parameters_t;
+  class T3_WIDGET_API behavior_parameters_t;
+
+  /** Create a new edit_window_t.
+      @param _text The text to display in the edit_window_t.
+      @param params The view parameters to set.
 
+      @deprecated Use the constructor taking a 
::edit_window_t::behavior_parameters_t instead.
+  */
+  edit_window_t(text_buffer_t *_text, const view_parameters_t *params);
   /** Create a new edit_window_t.
       @param _text The text to display in the edit_window_t.
       @param params The view parameters to set.
   */
-  edit_window_t(text_buffer_t *_text = nullptr, const view_parameters_t 
*params = nullptr);
+  edit_window_t(text_buffer_t *_text = nullptr, const behavior_parameters_t 
*params = nullptr);
   ~edit_window_t() override;
   bool process_key(key_t key) override;
   bool set_size(optint height, optint width) override;
@@ -173,8 +186,17 @@
       get_text to retrieve the current text_buffer_t before calling this
       function to make sure you have a reference to the current buffer that
       you can use to delete the old text_buffer_t.
+
+      @deprecated Use the overload taking a 
::edit_window_t::behavior_parameters_t instead.
   */
-  void set_text(text_buffer_t *_text, const view_parameters_t *params = 
nullptr);
+  void set_text(text_buffer_t *_text, const view_parameters_t *params);
+  /** Set the text to display.
+      The previously displayed text will be replaced, without deleting. Use
+      get_text to retrieve the current text_buffer_t before calling this
+      function to make sure you have a reference to the current buffer that
+      you can use to delete the old text_buffer_t.
+  */
+  void set_text(text_buffer_t *_text, const behavior_parameters_t *params = 
nullptr);
   /** Get the text currently displayed. */
   text_buffer_t *get_text() const;
   /** Apply the undo action. */
@@ -253,11 +275,20 @@
   /** Get show tabs. */
   bool get_show_tabs() const;
 
-  /** Save the current view parameters, to allow them to be restored later. */
+  /** Save the current view parameters, to allow them to be restored later.
+      @deprecated Use ::edit_window_t::save_behavior_parameters instead.
+  */
   std::unique_ptr<edit_window_t::view_parameters_t> save_view_parameters();
-  /** Save the current view parameters, to allow them to be restored later. */
+  /** Save the current view parameters, to allow them to be restored later.
+      @deprecated Use ::edit_window_t::save_behavior_parameters instead.
+  */
   void save_view_parameters(view_parameters_t *params);
 
+  /** Save the current view parameters, to allow them to be restored later. */
+  std::unique_ptr<edit_window_t::behavior_parameters_t> 
save_behavior_parameters();
+  /** Save the current view parameters, to allow them to be restored later. */
+  void save_behavior_parameters(behavior_parameters_t *params);
+
   /** Set the autocompleter to use. */
   void set_autocompleter(autocompleter_t *_autocompleter);
   /** Perform autocompletion, or pop-up autocompletion choice menu. */
@@ -271,6 +302,10 @@
 #undef _T3_ACTION_FILE
 };
 
+/** A (deprecated) class to hold the parameters of an edit window.
+
+    @deprecated Use ::edit_window_t::behavior_parameters_t instead.
+*/
 class T3_WIDGET_API edit_window_t::view_parameters_t {
   friend class edit_window_t;
 
@@ -298,5 +333,38 @@
   void set_show_tabs(bool _show_tabs);
 };
 
+class T3_WIDGET_API edit_window_t::behavior_parameters_t {
+  friend class edit_window_t;
+
+ private:
+  struct T3_WIDGET_LOCAL implementation_t;
+  pimpl_t<implementation_t> impl;
+
+  behavior_parameters_t(const edit_window_t &view);
+  behavior_parameters_t(const edit_window_t::view_parameters_t &params);
+  void apply_parameters(edit_window_t *view) const;
+
+ public:
+  behavior_parameters_t();
+  ~behavior_parameters_t();
+  behavior_parameters_t &operator=(const behavior_parameters_t &other);
+
+  void set_tabsize(int _tabsize);
+  void set_wrap(wrap_type_t _wrap_type);
+  void set_tab_spaces(bool _tab_spaces);
+  void set_auto_indent(bool _auto_indent);
+  void set_indent_aware_home(bool _indent_aware_home);
+  void set_show_tabs(bool _show_tabs);
+  void set_top_left(text_coordinate_t pos);
+
+  int get_tabsize() const;
+  wrap_type_t get_wrap_type() const;
+  bool get_tab_spaces() const;
+  bool get_auto_indent() const;
+  bool get_indent_aware_home() const;
+  bool get_show_tabs() const;
+  text_coordinate_t get_top_left() const;
+};
+
 }  // namespace t3widget
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/expander.cc 
new/libt3widget-1.2.0/src/widgets/expander.cc
--- old/libt3widget-1.0.6/src/widgets/expander.cc       2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/widgets/expander.cc       2019-12-03 
20:12:13.000000000 +0100
@@ -66,9 +66,40 @@
   force_redraw();
 }
 
+void expander_t::expand() {
+  if (!impl->child) {
+    return;
+  }
+
+  impl->child->show();
+  impl->is_expanded = true;
+  window.resize(impl->full_height, window.get_width());
+  force_redraw();
+  if (impl->focus == FOCUS_SELF && impl->child != nullptr && 
impl->child->accepts_focus()) {
+    impl->focus = FOCUS_CHILD;
+    impl->child->set_focus(window_component_t::FOCUS_SET);
+  }
+  impl->expanded(true);
+}
+
+void expander_t::collapse() {
+  if (impl->child != nullptr) {
+    impl->child->hide();
+  }
+  if (impl->focus == FOCUS_CHILD) {
+    if (impl->child != nullptr) {
+      impl->child->set_focus(window_component_t::FOCUS_OUT);
+    }
+    impl->focus = FOCUS_SELF;
+  }
+  window.resize(1, window.get_width());
+  impl->is_expanded = false;
+  force_redraw();
+  impl->expanded(false);
+}
+
 void expander_t::set_child(std::unique_ptr<t3widget::widget_t> _child) {
   focus_widget_t *focus_child;
-  /* FIXME: connect to move_focus_XXX events. (requires dynamic_cast'ing to 
focus_widget_t) */
   if (impl->child != nullptr) {
     unset_widget_parent(impl->child.get());
     impl->move_up_connection.disconnect();
@@ -119,25 +150,11 @@
   force_redraw();
 }
 
-void expander_t::set_expanded(bool expand) {
-  if (!expand && impl->is_expanded) {
-    if (impl->focus == FOCUS_CHILD) {
-      impl->child->set_focus(window_component_t::FOCUS_OUT);
-      impl->focus = FOCUS_SELF;
-    }
-    if (impl->child != nullptr) {
-      impl->child->hide();
-    }
-    impl->is_expanded = false;
-    window.resize(1, window.get_width());
-    force_redraw();
-    impl->expanded(false);
-  } else if (expand && !impl->is_expanded && impl->child != nullptr) {
-    impl->child->show();
-    impl->is_expanded = true;
-    window.resize(impl->full_height, window.get_width());
-    force_redraw();
-    impl->expanded(true);
+void expander_t::set_expanded(bool expanded) {
+  if (!expanded && impl->is_expanded) {
+    collapse();
+  } else if (expanded && !impl->is_expanded) {
+    expand();
   }
 }
 
@@ -153,41 +170,52 @@
       return true;
     } else if (key == EKEY_DOWN && !impl->is_expanded) {
       move_focus_down();
+      return impl->focus == FOCUS_NONE;
     } else if (key == EKEY_UP) {
       move_focus_up();
+      return impl->focus == FOCUS_NONE;
     } else if (key == EKEY_RIGHT) {
       move_focus_right();
+      if (impl->focus == FOCUS_SELF) {
+        expand();
+      }
+      return impl->focus == FOCUS_NONE;
     } else if (key == EKEY_LEFT) {
       move_focus_left();
+      if (impl->focus == FOCUS_SELF) {
+        collapse();
+      }
+      return impl->focus == FOCUS_NONE;
     } else if (key == ' ' || key == EKEY_NL || key == EKEY_HOTKEY) {
-      if (!impl->is_expanded && impl->child != nullptr) {
-        window.resize(impl->full_height, window.get_width());
-        impl->is_expanded = true;
-        force_redraw();
-        impl->child->show();
-        if (impl->child->accepts_focus()) {
-          impl->focus = FOCUS_CHILD;
-          impl->child->set_focus(window_component_t::FOCUS_SET);
-        }
-        impl->expanded(true);
-      } else if (impl->is_expanded) {
-        if (impl->child != nullptr) {
-          impl->child->hide();
-        }
-        window.resize(1, window.get_width());
-        impl->is_expanded = false;
-        force_redraw();
-        impl->expanded(false);
+      if (impl->is_expanded) {
+        collapse();
+      } else {
+        expand();
       }
       return true;
+    } else if (key == '+' && !impl->is_expanded) {
+      expand();
+      return true;
+    } else if (key == '-' && impl->is_expanded) {
+      collapse();
+      return true;
     }
   } else if (impl->focus == FOCUS_CHILD) {
     bool result = impl->child->process_key(key);
-    if (!result && key == (EKEY_SHIFT | '\t')) {
-      impl->focus = FOCUS_SELF;
-      result = true;
-      impl->child->set_focus(window_component_t::FOCUS_OUT);
-      force_redraw();
+    if (!result) {
+      if (key == (EKEY_SHIFT | '\t')) {
+        impl->focus = FOCUS_SELF;
+        result = true;
+        impl->child->set_focus(window_component_t::FOCUS_OUT);
+        force_redraw();
+        return true;
+      } else if (key == '-') {
+        collapse();
+        return true;
+      } else if (impl->focus == FOCUS_CHILD && key == EKEY_LEFT) {
+        collapse();
+        return true;
+      }
     }
     return result;
   }
@@ -210,21 +238,20 @@
   impl->label.draw(&impl->symbol_window, 0, impl->focus == FOCUS_SELF);
 }
 
-void expander_t::set_focus(focus_t _focus) {
-  if (_focus == window_component_t::FOCUS_OUT) {
+void expander_t::set_focus(focus_t focus) {
+  if (focus == window_component_t::FOCUS_OUT) {
     if (impl->focus == FOCUS_CHILD && impl->child != nullptr) {
       impl->child->set_focus(window_component_t::FOCUS_OUT);
     }
     impl->last_focus = impl->focus;
     impl->focus = FOCUS_NONE;
-  } else if (_focus == window_component_t::FOCUS_SET ||
-             _focus == window_component_t::FOCUS_IN_FWD ||
-             (_focus == window_component_t::FOCUS_REVERT && impl->last_focus 
== FOCUS_SELF) ||
+  } else if (focus == window_component_t::FOCUS_SET || focus == 
window_component_t::FOCUS_IN_FWD ||
+             (focus == window_component_t::FOCUS_REVERT && impl->last_focus == 
FOCUS_SELF) ||
              impl->child == nullptr || !impl->is_expanded) {
     impl->focus = FOCUS_SELF;
   } else {
     impl->focus = FOCUS_CHILD;
-    impl->child->set_focus(_focus);
+    impl->child->set_focus(focus);
   }
   force_redraw();
 }
@@ -307,26 +334,12 @@
 
 bool expander_t::process_mouse_event(mouse_event_t event) {
   if (event.button_state & EMOUSE_CLICKED_LEFT) {
-    if (!impl->is_expanded && impl->child != nullptr) {
-      window.resize(impl->full_height, window.get_width());
-      impl->is_expanded = true;
-      force_redraw();
-      impl->child->show();
-      impl->expanded(true);
-      if (impl->focus == FOCUS_SELF) {
-        impl->focus = FOCUS_CHILD;
-        impl->child->set_focus(window_component_t::FOCUS_SET);
-      }
-    } else if (impl->is_expanded) {
+    if (impl->is_expanded) {
       /* No need to handle impl->focus, because we got a set_focus(SET) event
          before this call anyway. */
-      if (impl->child != nullptr) {
-        impl->child->hide();
-      }
-      window.resize(1, window.get_width());
-      impl->is_expanded = false;
-      force_redraw();
-      impl->expanded(false);
+      collapse();
+    } else {
+      expand();
     }
   }
   return true;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/expander.h 
new/libt3widget-1.2.0/src/widgets/expander.h
--- old/libt3widget-1.0.6/src/widgets/expander.h        2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/widgets/expander.h        2019-12-03 
20:12:13.000000000 +0100
@@ -42,6 +42,8 @@
   single_alloc_pimpl_t<implementation_t> impl;
 
   void focus_up_from_child();
+  void expand();
+  void collapse();
 
  public:
   /** Create a new expander_t.
@@ -70,7 +72,7 @@
 
   bool process_key(key_t key) override;
   void update_contents() override;
-  void set_focus(focus_t _focus) override;
+  void set_focus(focus_t focus) override;
   bool set_size(optint height, optint width) override;
   bool is_hotkey(key_t key) const override;
   void set_enabled(bool enable) override;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/frame.cc 
new/libt3widget-1.2.0/src/widgets/frame.cc
--- old/libt3widget-1.0.6/src/widgets/frame.cc  2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/widgets/frame.cc  2019-12-03 20:12:13.000000000 
+0100
@@ -120,6 +120,7 @@
   }
 }
 void frame_t::force_redraw() {
+  widget_t::force_redraw();
   if (impl->child != nullptr) {
     impl->child->force_redraw();
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/textfield.cc 
new/libt3widget-1.2.0/src/widgets/textfield.cc
--- old/libt3widget-1.0.6/src/widgets/textfield.cc      2019-05-05 
10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/widgets/textfield.cc      2019-12-03 
20:12:13.000000000 +0100
@@ -222,6 +222,22 @@
     case EKEY_UP:
       move_focus_up();
       break;
+    case EKEY_BS | EKEY_CTRL:
+      if (impl->selection_mode != selection_mode_t::NONE) {
+        delete_selection(false);
+      } else if (impl->pos > 0) {
+        text_pos_t newpos = impl->line->get_previous_word(impl->pos);
+        if(newpos < 0) {
+          newpos = 0;
+        }
+        if (impl->line->backspace_word(impl->pos, newpos, nullptr)) {
+          impl->pos = newpos;
+          ensure_cursor_on_screen();
+          force_redraw();
+          impl->edited = true;
+        }
+      }
+      break;
     case EKEY_BS:
       if (impl->selection_mode != selection_mode_t::NONE) {
         delete_selection(false);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/widgets/widget.h 
new/libt3widget-1.2.0/src/widgets/widget.h
--- old/libt3widget-1.0.6/src/widgets/widget.h  2019-05-05 10:23:54.000000000 
+0200
+++ new/libt3widget-1.2.0/src/widgets/widget.h  2019-12-03 20:12:13.000000000 
+0100
@@ -112,9 +112,16 @@
   /** Emit signal when the user pressed the down arrow key and focus should 
move. */
   void move_focus_down() const;
 
+  /** Get a function that will trigger the move_focus_left signal, for 
conneting to another signal.
+   */
   std::function<void()> get_move_focus_left_trigger() const;
+  /** Get a function that will trigger the move_focus_right signal, for 
conneting to another signal.
+   */
   std::function<void()> get_move_focus_right_trigger() const;
+  /** Get a function that will trigger the move_focus_up signal, for conneting 
to another signal. */
   std::function<void()> get_move_focus_up_trigger() const;
+  /** Get a function that will trigger the move_focus_down signal, for 
conneting to another signal.
+   */
   std::function<void()> get_move_focus_down_trigger() const;
 
   struct T3_WIDGET_LOCAL implementation_t;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libt3widget-1.0.6/src/x11.cc 
new/libt3widget-1.2.0/src/x11.cc
--- old/libt3widget-1.0.6/src/x11.cc    2019-05-05 10:23:54.000000000 +0200
+++ new/libt3widget-1.2.0/src/x11.cc    2019-12-03 20:12:13.000000000 +0100
@@ -108,7 +108,9 @@
   }
 
   void send_wakeup() {
-    char data;
+    /* The actual data is irrelevant here, but to prevent warnings about 
uninitialized data, this
+       is still initialized here. */
+    char data = 0;
     nosig_write(wakeup_pipe[1], &data, 1);
   }
 


Reply via email to