Include a stripped-down version of FLTK in tree and add a USE_INCLUDED_FLTK option to build against it.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4603 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/fltk/src/Fl_Input.cxx b/common/fltk/src/Fl_Input.cxx
new file mode 100644
index 0000000..d38d5cf
--- /dev/null
+++ b/common/fltk/src/Fl_Input.cxx
@@ -0,0 +1,822 @@
+//
+// "$Id: Fl_Input.cxx 8726 2011-05-23 18:32:47Z AlbrechtS $"
+//
+// Input widget for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2011 by Bill Spitzak and others.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems on the following page:
+//
+//     http://www.fltk.org/str.php
+//
+
+// This is the "user interface", it decodes user actions into what to
+// do to the text.  See also Fl_Input_.cxx, where the text is actually
+// manipulated (and some ui, in particular the mouse, is done...).
+// In theory you can replace this code with another subclass to change
+// the keybindings.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Input.H>
+#include <FL/fl_draw.H>
+#include <FL/fl_ask.H>
+#include "flstring.h"
+
+#if defined(FL_DLL)	// really needed for c'tors for MS VC++ only
+#include <FL/Fl_Float_Input.H>
+#include <FL/Fl_Int_Input.H>
+#include <FL/Fl_Multiline_Input.H>
+#include <FL/Fl_Output.H>
+#include <FL/Fl_Multiline_Output.H>
+#include <FL/Fl_Secret_Input.H>
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+
+void Fl_Input::draw() {
+  if (input_type() == FL_HIDDEN_INPUT) return;
+  Fl_Boxtype b = box();
+  if (damage() & FL_DAMAGE_ALL) draw_box(b, color());
+  Fl_Input_::drawtext(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
+		      w()-Fl::box_dw(b), h()-Fl::box_dh(b));
+}
+
+// kludge so shift causes selection to extend:
+int Fl_Input::shift_position(int p) {
+  return position(p, Fl::event_state(FL_SHIFT) ? mark() : p);
+}
+
+int Fl_Input::shift_up_down_position(int p) {
+  return up_down_position(p, Fl::event_state(FL_SHIFT));
+}
+
+// Old text from FLTK 1.1 for reference:
+// If you define NORMAL_INPUT_MOVE as zero you will get the peculiar fltk
+// behavior where moving off the end of an input field will move the
+// cursor into the next field:
+// define it as 1 to prevent cursor movement from going to next field:
+//
+// Note: this has been replaced by Fl::option(Fl::OPTION_ARROW_FOCUS)
+// in FLTK 1.3.  This option has "inverted" values:
+//   1 = Arrow keys move focus (previously 0)
+//   0 = Arrow keys don't move focus (previously 1)
+// Hence we define ...
+//
+#define NORMAL_INPUT_MOVE (Fl::option(Fl::OPTION_ARROW_FOCUS) ? 0 : 1)
+
+#define ctrl(x) ((x)^0x40)
+
+// List of characters that are legal in a floating point input field.
+// This text string is created at run-time to take the current locale
+// into account (for example, continental Europe uses a comma instead
+// of a decimal point). For back compatibility reasons, we always 
+// allow the decimal point.
+#ifdef HAVE_LOCALECONV
+static const char *standard_fp_chars = ".eE+-"; 
+static const char *legal_fp_chars = 0L;
+#else
+static const char *legal_fp_chars = ".eE+-"; 
+#endif
+
+// Move cursor up specified #lines
+//    If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
+//
+int Fl_Input::kf_lines_up(int repeat_num) {
+  int i = position();
+  if (!line_start(i)) {
+    //UNNEEDED if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1;
+    return NORMAL_INPUT_MOVE;
+  }
+  while(repeat_num--) {
+    i = line_start(i);
+    if (!i) break;
+    i--;
+  }
+  shift_up_down_position(line_start(i));
+  return 1;
+}
+
+// Move cursor down specified #lines
+//    If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
+//
+int Fl_Input::kf_lines_down(int repeat_num) {
+  int i = position();
+  if (line_end(i) >= size()) {
+    //UNNEEDED if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1;
+    return NORMAL_INPUT_MOVE;
+  }
+  while (repeat_num--) {  
+    i = line_end(i);
+    if (i >= size()) break;
+    i++;
+  }
+  shift_up_down_position(i);
+  return 1;
+}
+
+// Move up a page
+int Fl_Input::kf_page_up() {
+  return kf_lines_up(linesPerPage());
+}
+
+// Move down a page
+int Fl_Input::kf_page_down() {
+  return kf_lines_down(linesPerPage());
+}
+
+// Toggle insert mode
+int Fl_Input::kf_insert_toggle() {
+  if (readonly()) { fl_beep(); return 1; }
+  return 1;				// \todo: needs insert mode
+}
+
+// Delete word right
+int Fl_Input::kf_delete_word_right() {
+  if (readonly()) { fl_beep(); return 1; }
+  if (mark() != position()) return cut();
+  cut(position(), word_end(position()));
+  return 1;
+}
+
+// Delete word left
+int Fl_Input::kf_delete_word_left() {
+  if (readonly()) { fl_beep(); return 1; }
+  if (mark() != position()) return cut();
+  cut(word_start(position()), position());
+  return 1;
+}
+
+// Delete to start of line
+int Fl_Input::kf_delete_sol() {
+  if (readonly()) { fl_beep(); return 1; }
+  if (mark() != position()) return cut();
+  cut(line_start(position()), position());
+  return 1;
+}
+
+// Delete to end of line
+int Fl_Input::kf_delete_eol() {
+  if (readonly()) { fl_beep(); return 1; }
+  if (mark() != position()) return cut();
+  cut(position(), line_end(position()));
+  return 1;
+}
+
+int Fl_Input::kf_delete_char_right() {
+  if (readonly()) { fl_beep(); return 1; }
+  if (mark() != position()) return cut();
+  else return cut(1);
+}
+
+int Fl_Input::kf_delete_char_left() {
+  if (readonly()) { fl_beep(); return 1; }
+  if (mark() != position()) cut();
+  else cut(-1);
+  return 1;
+}
+
+// Move cursor to start of line
+int Fl_Input::kf_move_sol() {
+  return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
+}
+
+// Move cursor to end of line
+int Fl_Input::kf_move_eol() {
+  return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
+}
+
+// Clear to end of line
+int Fl_Input::kf_clear_eol() {
+  if (readonly()) { fl_beep(); return 1; }
+  if (position()>=size()) return 0;
+  int i = line_end(position());
+  if (i == position() && i < size()) i++;
+  cut(position(), i);
+  return copy_cuts();
+}
+
+// Move cursor one character to the left
+//    If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
+//
+int Fl_Input::kf_move_char_left() {
+  int i = shift_position(position()-1) + NORMAL_INPUT_MOVE;
+  return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1;
+}
+
+// Move cursor one character to the right
+//    If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
+//
+int Fl_Input::kf_move_char_right() {
+  int i = shift_position(position()+1) + NORMAL_INPUT_MOVE;
+  return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1;
+}
+
+// Move cursor word-left
+int Fl_Input::kf_move_word_left() {
+  shift_position(word_start(position()));
+  return 1; 
+}
+
+// Move cursor word-right
+int Fl_Input::kf_move_word_right() {
+  shift_position(word_end(position()));
+  return 1;
+}
+
+// Move cursor up one line and to the start of line (paragraph up)
+int Fl_Input::kf_move_up_and_sol() {
+  if (line_start(position())==position() && position()>0)
+    return shift_position(line_start(position()-1)) + NORMAL_INPUT_MOVE;
+  else
+    return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
+}
+
+// Move cursor down one line and to the end of line (paragraph down)
+int Fl_Input::kf_move_down_and_eol() {
+  if (line_end(position())==position() && position()<size())
+    return shift_position(line_end(position()+1)) + NORMAL_INPUT_MOVE;
+  else
+    return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
+}
+
+// Move to top of document
+int Fl_Input::kf_top() {
+  shift_position(0);
+  return 1;
+}
+
+// Move to bottom of document
+int Fl_Input::kf_bottom() {
+  shift_position(size());
+  return 1; 
+}
+
+// Select all text in the widget
+int Fl_Input::kf_select_all() {
+  position(0,size());
+  return 1;
+}
+
+// Undo.
+int Fl_Input::kf_undo() {
+  if (readonly()) { fl_beep(); return 1; }
+  return undo();
+}
+
+// Redo. (currently unimplemented.. toggles undo() instead)
+int Fl_Input::kf_redo() {
+  if (readonly()) { fl_beep(); return 1; }
+  return kf_undo();			// currently we don't support multilevel undo
+}
+
+// Do a copy operation
+int Fl_Input::kf_copy() {
+  return copy(1);
+}
+
+// Do a paste operation
+int Fl_Input::kf_paste() {
+  if (readonly()) { fl_beep(); return 1; }
+  Fl::paste(*this, 1);
+  return 1;
+}
+
+// Do a cut with copy
+int Fl_Input::kf_copy_cut() {
+  if (readonly()) { fl_beep(); return 1; }
+  copy(1);
+  return cut();
+}
+
+// Handle a keystroke.
+//     Returns 1 if handled by us, 0 if not.
+//
+int Fl_Input::handle_key() {
+  
+  char ascii = Fl::event_text()[0];
+  
+  int del;
+  if (Fl::compose(del)) {
+    
+    // Insert characters into numeric fields after checking for legality:
+    if (input_type() == FL_FLOAT_INPUT || input_type() == FL_INT_INPUT) {
+      Fl::compose_reset(); // ignore any foreign letters...
+      
+      // initialize the list of legal characters inside a floating point number
+#ifdef HAVE_LOCALECONV
+      if (!legal_fp_chars) {
+        int len = strlen(standard_fp_chars);
+        struct lconv *lc = localeconv();
+        if (lc) {
+          if (lc->decimal_point) len += strlen(lc->decimal_point);
+          if (lc->mon_decimal_point) len += strlen(lc->mon_decimal_point);
+          if (lc->positive_sign) len += strlen(lc->positive_sign);
+          if (lc->negative_sign) len += strlen(lc->negative_sign);
+        }
+        // the following line is not a true memory leak because the array is only
+        // allocated once if required, and automatically freed when the program quits
+        char *chars = (char*)malloc(len+1);
+	legal_fp_chars = chars;
+        strcpy(chars, standard_fp_chars);
+        if (lc) {
+          if (lc->decimal_point) strcat(chars, lc->decimal_point);
+          if (lc->mon_decimal_point) strcat(chars, lc->mon_decimal_point);
+          if (lc->positive_sign) strcat(chars, lc->positive_sign);
+          if (lc->negative_sign) strcat(chars, lc->negative_sign);
+        }
+      }
+#endif // HAVE_LOCALECONV
+      
+      // find the insert position
+      int ip = position()<mark() ? position() : mark();
+      // This is complex to allow "0xff12" hex to be typed:
+      if (   (!ip && (ascii == '+' || ascii == '-')) 
+          || (ascii >= '0' && ascii <= '9') 
+          || (ip==1 && index(0)=='0' && (ascii=='x' || ascii == 'X')) 
+          || (ip>1 && index(0)=='0' && (index(1)=='x'||index(1)=='X') 
+              && ((ascii>='A'&& ascii<='F') || (ascii>='a'&& ascii<='f'))) 
+          || (input_type()==FL_FLOAT_INPUT && ascii && strchr(legal_fp_chars, ascii))) 
+      {
+	if (readonly()) fl_beep();
+	else replace(position(), mark(), &ascii, 1);
+      }
+      return 1;
+    }
+    
+    if (del || Fl::event_length()) {
+      if (readonly()) fl_beep();
+      else replace(position(), del ? position()-del : mark(),
+	           Fl::event_text(), Fl::event_length());
+    }
+    return 1;
+  }
+  
+  unsigned int mods = Fl::event_state() & (FL_META|FL_CTRL|FL_ALT);
+  unsigned int shift = Fl::event_state() & FL_SHIFT;
+  unsigned int multiline = (input_type() == FL_MULTILINE_INPUT) ? 1 : 0;
+  //
+  // The following lists apps that support these keypresses.
+  // Prefixes: '!' indicates NOT supported, '?' indicates un-verified.
+  //
+  //    HIG=Human Interface Guide, 
+  //    TE=TextEdit.app, SA=Safari.app, WOX=MS Word/OSX -- OSX 10.4.x
+  //    NP=Notepad, WP=WordPad, WOW=MS Word/Windows     -- WinXP
+  //    GE=gedit, KE=kedit                              -- Ubuntu8.04
+  //    OF=old FLTK behavior (<=1.1.10)
+  //
+  // Example: (NP,WP,!WO) means supported in notepad + wordpad, but NOT word.
+  //
+  switch (Fl::event_key()) {
+
+    case FL_Insert:
+      // Note: Mac has no "Insert" key; it's the "Help" key.
+      //       This keypress is apparently not possible on macs.
+      //
+      if (mods==0 && shift) return kf_paste();			// Shift-Insert   (WP,NP,WOW,GE,KE,OF)
+      if (mods==0)          return kf_insert_toggle();		// Insert         (Standard)
+      if (mods==FL_CTRL)    return kf_copy();			// Ctrl-Insert    (WP,NP,WOW,GE,KE,OF)
+      return 0;							// ignore other combos, pass to parent
+
+    case FL_Delete: {
+#ifdef __APPLE__
+      if (mods==0)          return kf_delete_char_right();	// Delete         (OSX-HIG,TE,SA,WOX)
+      if (mods==FL_CTRL)    return kf_delete_char_right();	// Ctrl-Delete    (??? TE,!SA,!WOX)
+      if (mods==FL_ALT)     return kf_delete_word_right();	// Alt-Delete     (OSX-HIG,TE,SA)
+      return 0;							// ignore other combos, pass to parent
+#else
+      int selected = (position() != mark()) ? 1 : 0;
+      if (mods==0 && shift && selected)
+                            return kf_copy_cut();		// Shift-Delete with selection (WP,NP,WOW,GE,KE,OF)
+      if (mods==0 && shift && !selected)
+                            return kf_delete_char_right();	// Shift-Delete no selection (WP,NP,WOW,GE,KE,!OF)
+      if (mods==0)          return kf_delete_char_right();	// Delete         (Standard)
+      if (mods==FL_CTRL)    return kf_delete_word_right();	// Ctrl-Delete    (WP,!NP,WOW,GE,KE,!OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+    }
+
+    case FL_Left:
+#ifdef __APPLE__
+      if (mods==0)          return kf_move_char_left();		// Left           (OSX-HIG)
+      if (mods==FL_ALT)     return kf_move_word_left();		// Alt-Left       (OSX-HIG)
+      if (mods==FL_META)    return kf_move_sol();		// Meta-Left      (OSX-HIG)
+      if (mods==FL_CTRL)    return kf_move_sol();		// Ctrl-Left      (TE/SA)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_move_char_left();		// Left           (WP,NP,WOW,GE,KE,OF)
+      if (mods==FL_CTRL)    return kf_move_word_left();		// Ctrl-Left      (WP,NP,WOW,GE,KE,!OF)
+      if (mods==FL_META)    return kf_move_char_left();		// Meta-Left      (WP,NP,?WOW,GE,KE)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_Right:
+#ifdef __APPLE__
+      if (mods==0)          return kf_move_char_right();	// Right          (OSX-HIG)
+      if (mods==FL_ALT)     return kf_move_word_right();	// Alt-Right      (OSX-HIG)
+      if (mods==FL_META)    return kf_move_eol();		// Meta-Right     (OSX-HIG)
+      if (mods==FL_CTRL)    return kf_move_eol();		// Ctrl-Right     (TE/SA)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_move_char_right();	// Right          (WP,NP,WOW,GE,KE,OF)
+      if (mods==FL_CTRL)    return kf_move_word_right();	// Ctrl-Right     (WP,NP,WOW,GE,KE,!OF)
+      if (mods==FL_META)    return kf_move_char_right();	// Meta-Right     (WP,NP,?WOW,GE,KE,!OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_Up:
+#ifdef __APPLE__
+      if (mods==0)          return kf_lines_up(1);		// Up             (OSX-HIG)
+      if (mods==FL_CTRL)    return kf_page_up();		// Ctrl-Up        (TE !HIG)
+      if (mods==FL_ALT)     return kf_move_up_and_sol();	// Alt-Up         (OSX-HIG)
+      if (mods==FL_META)    return kf_top();			// Meta-Up        (OSX-HIG)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_lines_up(1);		// Up             (WP,NP,WOW,GE,KE,OF)
+      if (mods==FL_CTRL)    return kf_move_up_and_sol();	// Ctrl-Up        (WP,!NP,WOW,GE,!KE,OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_Down:
+#ifdef __APPLE__
+      if (mods==0)          return kf_lines_down(1);		// Dn             (OSX-HIG)
+      if (mods==FL_CTRL)    return kf_page_down();		// Ctrl-Dn        (TE !HIG)
+      if (mods==FL_ALT)     return kf_move_down_and_eol();	// Alt-Dn         (OSX-HIG)
+      if (mods==FL_META)    return kf_bottom();			// Meta-Dn        (OSX-HIG)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_lines_down(1);		// Dn             (WP,NP,WOW,GE,KE,OF)
+      if (mods==FL_CTRL)    return kf_move_down_and_eol();	// Ctrl-Down      (WP,!NP,WOW,GE,!KE,OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_Page_Up:
+      // Fl_Input has no scroll control, so instead we move the cursor by one page
+      // OSX-HIG recommends Alt increase one semantic unit, Meta next higher..
+#ifdef __APPLE__
+      if (mods==0)          return kf_page_up();		// PgUp           (OSX-HIG)
+      if (mods==FL_ALT)     return kf_page_up();		// Alt-PageUp     (OSX-HIG)
+      if (mods==FL_META)    return kf_top();			// Meta-PageUp    (OSX-HIG,!TE)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_page_up();		// PageUp         (WP,NP,WOW,GE,KE)
+      if (mods==FL_CTRL)    return kf_page_up();		// Ctrl-PageUp    (!WP,!NP,!WOW,!GE,KE,OF)
+      if (mods==FL_ALT)     return kf_page_up();		// Alt-PageUp     (!WP,!NP,!WOW,!GE,KE,OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_Page_Down:
+#ifdef __APPLE__
+      // Fl_Input has no scroll control, so instead we move the cursor by one page
+      // OSX-HIG recommends Alt increase one semantic unit, Meta next higher..
+      if (mods==0)          return kf_page_down();		// PgDn           (OSX-HIG)
+      if (mods==FL_ALT)     return kf_page_down();		// Alt-PageDn     (OSX-HIG)
+      if (mods==FL_META)    return kf_bottom();			// Meta-PageDn    (OSX-HIG,!TE)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_page_down();		// PageDn         (WP,NP,WOW,GE,KE)
+      if (mods==FL_CTRL)    return kf_page_down();		// Ctrl-PageDn    (!WP,!NP,!WOW,!GE,KE,OF)
+      if (mods==FL_ALT)     return kf_page_down();		// Alt-PageDn     (!WP,!NP,!WOW,!GE,KE,OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_Home:
+#ifdef __APPLE__
+      if (mods==0)          return kf_top();			// Home           (OSX-HIG)
+      if (mods==FL_ALT)     return kf_top();			// Alt-Home       (???)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_move_sol();		// Home           (WP,NP,WOW,GE,KE,OF)
+      if (mods==FL_CTRL)    return kf_top();			// Ctrl-Home      (WP,NP,WOW,GE,KE,OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_End:
+#ifdef __APPLE__
+      if (mods==0)          return kf_bottom();			// End            (OSX-HIG)
+      if (mods==FL_ALT)     return kf_bottom();			// Alt-End        (???)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_move_eol();		// End            (WP,NP,WOW,GE,KE,OF)
+      if (mods==FL_CTRL)    return kf_bottom();			// Ctrl-End       (WP,NP,WOW,GE,KE,OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_BackSpace:
+#ifdef __APPLE__
+      if (mods==0)          return kf_delete_char_left();	// Backspace      (OSX-HIG)
+      if (mods==FL_CTRL)    return kf_delete_char_left();	// Ctrl-Backspace (TE/SA)
+      if (mods==FL_ALT)     return kf_delete_word_left();	// Alt-Backspace  (OSX-HIG)
+      if (mods==FL_META)    return kf_delete_sol();		// Meta-Backspace (OSX-HIG,!TE)
+      return 0;							// ignore other combos, pass to parent
+#else
+      if (mods==0)          return kf_delete_char_left();	// Backspace      (WP,NP,WOW,GE,KE,OF)
+      if (mods==FL_CTRL)    return kf_delete_word_left();	// Ctrl-Backspace (WP,!NP,WOW,GE,KE,!OF)
+      return 0;							// ignore other combos, pass to parent
+#endif
+
+    case FL_Enter:
+    case FL_KP_Enter:
+      if (when() & FL_WHEN_ENTER_KEY) {
+        position(size(), 0);
+        maybe_do_callback();
+        return 1;
+      } else if (multiline && !readonly()) {
+        return replace(position(), mark(), "\n", 1);
+      } return 0;			// reserved for shortcuts
+
+    case FL_Tab:
+      // Handle special case for multiline input with 'old tab behavior';
+      // tab handled as a normal insertable character.
+      //
+      if (mods==0 && !shift 		// Tab?
+	   && !tab_nav()		// old tab behavior enabled?
+	   && multiline) {		// multiline input?
+        break;				// insert tab character
+      }
+      if (mods==0) return 0;					// Tab, Shift-Tab? nav focus      (Standard/OSX-HIG)
+      return 0;							// ignore other combos, pass to parent
+
+    case 'a':
+      if (mods==FL_COMMAND) return kf_select_all();		// Ctrl-A, Mac:Meta-A             (Standard/OSX-HIG)
+      break;							// handle other combos elsewhere
+    case 'c':
+      if (mods==FL_COMMAND) return kf_copy();			// Ctrl-C, Mac:Meta-C             (Standard/OSX-HIG)
+      break;							// handle other combos elsewhere
+    case 'v':
+      if (mods==FL_COMMAND) return kf_paste();			// Ctrl-V, Mac:Meta-V             (Standard/OSX-HIG)
+      break;							// handle other combos elsewhere
+    case 'x':
+      if (mods==FL_COMMAND) return kf_copy_cut();		// Ctrl-X, Mac:Meta-X             (Standard/OSX-HIG)
+      break;
+    case 'z':
+      if (mods==FL_COMMAND && !shift) return kf_undo();		// Ctrl-Z, Mac:Meta-Z             (Standard/OSX-HIG)
+      if (mods==FL_COMMAND && shift)  return kf_redo();		// Shift-Ctrl-Z, Mac:Shift-Meta-Z (Standard/OSX-HIG)
+      break;							// handle other combos elsewhere
+  }
+  
+  switch (ascii) {
+    case ctrl('H'):
+      return kf_delete_char_left();				// Ctrl-H                           (!WP,!NP,!WOW,!WOX,TE,SA,GE,KE,OF)
+    case ctrl('I'): 						// Ctrl-I (literal Tab)             (!WP,NP,!WOW,!GE,KE,OF)
+    case ctrl('J'):						// Ctrl-J (literal Line Feed/Enter) (Standard)
+    case ctrl('L'):						// Ctrl-L (literal Form Feed)       (Standard)
+    case ctrl('M'):						// Ctrl-M (literal Cr)              (Standard)
+      if (readonly()) { fl_beep(); return 1; }
+      // insert a few selected control characters literally:
+      if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT)
+        return replace(position(), mark(), &ascii, 1);
+      break;
+  }
+  
+  return 0;		// ignored
+}
+
+int Fl_Input::handle(int event) {
+  static int dnd_save_position, dnd_save_mark, drag_start = -1, newpos;
+  static Fl_Widget *dnd_save_focus;
+  switch (event) {
+    case FL_FOCUS:
+      switch (Fl::event_key()) {
+        case FL_Right:
+          position(0);
+          break;
+        case FL_Left:
+          position(size());
+          break;
+        case FL_Down:
+          up_down_position(0);
+          break;
+        case FL_Up:
+          up_down_position(line_start(size()));
+          break;
+        case FL_Tab:
+          position(size(),0);
+          break;
+        default:
+          position(position(),mark());// turns off the saved up/down arrow position
+          break;
+      }
+      break;
+      
+    case FL_KEYBOARD:
+      // Handle special case for multiline input with 'old tab behavior'
+      // where tab is entered as a character: make sure user attempt to 'tab over'
+      // widget doesn't destroy the field, replacing it with a tab character.
+      //
+      if (Fl::event_key() == FL_Tab 			// Tab key?
+          && !Fl::event_state(FL_SHIFT)			// no shift?
+          && !tab_nav()					// with tab navigation disabled?
+	  && input_type() == FL_MULTILINE_INPUT		// with a multiline input?
+          && (mark()==0 && position()==size())) {	// while entire field selected?
+        // Set cursor to the end of the selection...
+        if (mark() > position())
+          position(mark());
+        else
+          position(position());
+        return (1);
+      } else {
+        if (active_r() && window() && this == Fl::belowmouse()) 
+          window()->cursor(FL_CURSOR_NONE);
+        return handle_key();
+      }
+      //NOTREACHED
+      
+    case FL_PUSH:
+      if (Fl::dnd_text_ops()) {
+        int oldpos = position(), oldmark = mark();
+        Fl_Boxtype b = box();
+        Fl_Input_::handle_mouse(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
+                                w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
+        newpos = position(); 
+        position( oldpos, oldmark );
+        if (Fl::focus()==this && !Fl::event_state(FL_SHIFT) && input_type()!=FL_SECRET_INPUT &&
+           ( (newpos >= mark() && newpos < position()) || 
+             (newpos >= position() && newpos < mark()) ) ) {
+          // user clicked in the selection, may be trying to drag
+          drag_start = newpos;
+          return 1;
+        }
+        drag_start = -1;
+      }
+      
+      if (Fl::focus() != this) {
+        Fl::focus(this);
+        handle(FL_FOCUS);
+      }
+      break;
+      
+    case FL_DRAG:
+      if (Fl::dnd_text_ops()) {
+        if (drag_start >= 0) {
+          if (Fl::event_is_click()) return 1; // debounce the mouse
+                                              // save the position because sometimes we don't get DND_ENTER:
+          dnd_save_position = position();
+          dnd_save_mark = mark();
+          // drag the data:
+          copy(0); Fl::dnd();
+          return 1;
+        }
+      }
+      break;
+      
+    case FL_RELEASE:
+      if (Fl::event_button() == 2) {
+        Fl::event_is_click(0); // stop double click from picking a word
+        Fl::paste(*this, 0);
+      } else if (!Fl::event_is_click()) {
+        // copy drag-selected text to the clipboard.
+        copy(0);
+      } else if (Fl::event_is_click() && drag_start >= 0) {
+        // user clicked in the field and wants to reset the cursor position...
+        position(drag_start, drag_start);
+        drag_start = -1;
+      } else if (Fl::event_clicks()) {
+        // user double or triple clicked to select word or whole text
+        copy(0);
+      }
+      
+      // For output widgets, do the callback so the app knows the user
+      // did something with the mouse...
+      if (readonly()) do_callback();
+      
+      return 1;
+      
+    case FL_DND_ENTER:
+      Fl::belowmouse(this); // send the leave events first
+      dnd_save_position = position();
+      dnd_save_mark = mark();
+      dnd_save_focus = Fl::focus();
+      if (dnd_save_focus != this) {
+        Fl::focus(this);
+        handle(FL_FOCUS);
+      }
+      // fall through:
+    case FL_DND_DRAG: 
+      //int p = mouse_position(X, Y, W, H);
+#if DND_OUT_XXXX
+      if (Fl::focus()==this && (p>=dnd_save_position && p<=dnd_save_mark ||
+                                p>=dnd_save_mark && p<=dnd_save_position)) {
+        position(dnd_save_position, dnd_save_mark);
+        return 0;
+      }
+#endif
+      {
+        Fl_Boxtype b = box();
+        Fl_Input_::handle_mouse(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
+                                w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
+      }
+      return 1;
+      
+    case FL_DND_LEAVE:
+      position(dnd_save_position, dnd_save_mark);
+#if DND_OUT_XXXX
+      if (!focused())
+#endif
+        if (dnd_save_focus != this) {
+          Fl::focus(dnd_save_focus);
+          handle(FL_UNFOCUS);
+        }
+#if !(defined(__APPLE__) || defined(WIN32))
+      Fl::first_window()->cursor(FL_CURSOR_MOVE);
+#endif
+      return 1;
+      
+    case FL_DND_RELEASE:
+      take_focus();
+      return 1;
+      
+      /* TODO: this will scroll the area, but stop if the cursor would become invisible.
+       That clipping happens in drawtext(). Do we change the clipping or should 
+       we move the cursor (ouch)?
+       case FL_MOUSEWHEEL:
+       if (Fl::e_dy > 0) {
+       yscroll( yscroll() - Fl::e_dy*15 );
+       } else if (Fl::e_dy < 0) {
+       yscroll( yscroll() - Fl::e_dy*15 );
+       }
+       return 1;
+       */
+  }
+  Fl_Boxtype b = box();
+  return Fl_Input_::handletext(event,
+                               x()+Fl::box_dx(b), y()+Fl::box_dy(b),
+                               w()-Fl::box_dw(b), h()-Fl::box_dh(b));
+}
+
+/**
+ Creates a new Fl_Input widget using the given position, size,
+ and label string. The default boxtype is FL_DOWN_BOX.
+ */
+Fl_Input::Fl_Input(int X, int Y, int W, int H, const char *l)
+: Fl_Input_(X, Y, W, H, l) {
+}
+
+/*
+  The following constructors must not be in the header file(s) if we
+  build a shared object (DLL). Instead they are defined here to force
+  the constructor (and default destructor as well) to be defined in
+  the DLL and exported (STR #2632).
+  
+  Note: if you change any of them, do the same changes in the specific
+  header file as well.  This redundant definition was chosen to enable
+  inline constructors in the header files (for static linking) as well
+  as those here for dynamic linking (Windows DLL).
+*/
+#if defined(FL_DLL)
+
+Fl_Float_Input::Fl_Float_Input(int X,int Y,int W,int H,const char *l)
+    : Fl_Input(X,Y,W,H,l) {
+  type(FL_FLOAT_INPUT);
+}
+
+Fl_Int_Input::Fl_Int_Input(int X,int Y,int W,int H,const char *l)
+    : Fl_Input(X,Y,W,H,l) {
+  type(FL_INT_INPUT);
+}
+
+Fl_Multiline_Input::Fl_Multiline_Input(int X,int Y,int W,int H,const char *l)
+    : Fl_Input(X,Y,W,H,l) {
+  type(FL_MULTILINE_INPUT);
+}
+
+Fl_Output::Fl_Output(int X,int Y,int W,int H, const char *l)
+    : Fl_Input(X, Y, W, H, l) {
+  type(FL_NORMAL_OUTPUT);
+}
+
+Fl_Multiline_Output::Fl_Multiline_Output(int X,int Y,int W,int H,const char *l)
+    : Fl_Output(X,Y,W,H,l) {
+  type(FL_MULTILINE_OUTPUT);
+}
+
+Fl_Secret_Input::Fl_Secret_Input(int X,int Y,int W,int H,const char *l)
+    : Fl_Input(X,Y,W,H,l) {
+  type(FL_SECRET_INPUT);
+}
+
+#endif // FL_DLL
+
+//
+// End of "$Id: Fl_Input.cxx 8726 2011-05-23 18:32:47Z AlbrechtS $".
+//