$ git clone http://tcclient.ion.nu/tc_client.git
commit bb351cc37dbeb38f8d7626d21c99337eb4b3a37e
Author: Alicia <...>
Date:   Fri Feb 26 17:55:56 2016 +0100

    tc_client-gtk: added input history (up/down arrows)

diff --git a/ChangeLog b/ChangeLog
index 1b63df5..2087525 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,7 @@ tc_client-gtk: make timestamps gray and nicknames bold.
 tc_client-gtk: added option to change font size in the chat.
 tc_client-gtk: initialize audio samples of new cams to 0 (experimental audio support)
 tc_client-gtk: windows compat: do /mbs handling on a duplicated buffer to avoid cutting off the displayed message.
+tc_client-gtk: added input history (up/down arrows)
 modbot: use youtube-dl's 'ytsearch:' instead of '--default-search auto', fixes issues with search terms that include slashes.
 configure: check for multiple versions of ncurses.
 0.37:
diff --git a/Makefile b/Makefile
index 125d697..ea5a59c 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ IRCHACK_OBJ=utilities/irchack/irchack.o utilities/compat.o
 MODBOT_OBJ=utilities/modbot/modbot.o utilities/list.o utilities/modbot/queue.o
 CAMVIEWER_OBJ=utilities/camviewer/camviewer.o utilities/compat.o libcamera.a
 CURSEDCHAT_OBJ=utilities/cursedchat/cursedchat.o utilities/cursedchat/buffer.o utilities/compat.o utilities/list.o
-TC_CLIENT_GTK_OBJ=utilities/gtk/camviewer.o utilities/gtk/userlist.o utilities/gtk/media.o utilities/gtk/compat.o utilities/gtk/config.o utilities/gtk/gui.o utilities/stringutils.o utilities/gtk/logging.o utilities/compat.o libcamera.a
+TC_CLIENT_GTK_OBJ=utilities/gtk/camviewer.o utilities/gtk/userlist.o utilities/gtk/media.o utilities/gtk/compat.o utilities/gtk/config.o utilities/gtk/gui.o utilities/stringutils.o utilities/gtk/logging.o utilities/compat.o utilities/gtk/inputhistory.o libcamera.a
 LIBCAMERA_OBJ=utilities/libcamera/camera.o utilities/libcamera/camera_img.o
 UTILS=irchack modbot
 CONFINFO=|Will enable the IRC utility irchack|Will enable the bot utility modbot
@@ -144,7 +144,7 @@ SOURCES+=utilities/irchack/irchack.c
 SOURCES+=utilities/modbot/modbot.c utilities/modbot/queue.c utilities/modbot/queue.h utilities/modbot/commands.html
 SOURCES+=utilities/camviewer/camviewer.c
 SOURCES+=utilities/cursedchat/cursedchat.c utilities/cursedchat/buffer.c utilities/cursedchat/buffer.h
-SOURCES+=utilities/gtk/camviewer.c utilities/gtk/userlist.c utilities/gtk/media.c utilities/gtk/compat.c utilities/gtk/config.c utilities/gtk/gui.c utilities/gtk/logging.c utilities/gtk/userlist.h utilities/gtk/media.h utilities/gtk/compat.h utilities/gtk/config.h utilities/gtk/gui.h utilities/gtk/logging.h gtkgui.glade
+SOURCES+=utilities/gtk/camviewer.c utilities/gtk/userlist.c utilities/gtk/media.c utilities/gtk/compat.c utilities/gtk/config.c utilities/gtk/gui.c utilities/gtk/logging.c utilities/gtk/inputhistory.c utilities/gtk/userlist.h utilities/gtk/media.h utilities/gtk/compat.h utilities/gtk/config.h utilities/gtk/gui.h utilities/gtk/logging.h utilities/gtk/inputhistory.h gtkgui.glade
 SOURCES+=utilities/compat.c utilities/compat.h utilities/list.c utilities/list.h utilities/stringutils.c utilities/stringutils.h
 SOURCES+=utilities/libcamera/camera.c utilities/libcamera/camera.h utilities/libcamera/camera_v4l2.c utilities/libcamera/camera_v4l2.h utilities/libcamera/camera_img.c utilities/libcamera/camera_img.h utilities/libcamera/camera_escapi.cpp utilities/libcamera/camera_escapi.h
 tarball:
diff --git a/utilities/gtk/camviewer.c b/utilities/gtk/camviewer.c
index e709d7b..f89420f 100644
--- a/utilities/gtk/camviewer.c
+++ b/utilities/gtk/camviewer.c
@@ -54,6 +54,7 @@
 #include "logging.h"
 #include "../stringutils.h"
 #include "../compat.h"
+#include "inputhistory.h"
 
 struct viddata
 {
@@ -662,7 +663,11 @@ void handleresizepane(GObject* obj, GParamSpec* spec, struct viddata* data)
 
 gboolean inputkeys(GtkWidget* widget, GdkEventKey* event, void* data)
 {
-  if(event->keyval==GDK_KEY_Up || event->keyval==GDK_KEY_Down){return 1;}
+  if(event->keyval==GDK_KEY_Up || event->keyval==GDK_KEY_Down)
+  {
+    inputhistory(GTK_ENTRY(widget), event);
+    return 1;
+  }
   if(event->keyval==GDK_KEY_Tab)
   {
     // Tab completion
@@ -712,9 +717,10 @@ gboolean inputkeys(GtkWidget* widget, GdkEventKey* event, void* data)
   return 0;
 }
 
-void sendmessage(GtkEntry* entry, struct viddata* data)
+void sendmessage(GtkEntry* entry, void* data)
 {
   const char* msg=gtk_entry_get_text(entry);
+  inputhistory_add(msg);
   char* pm=0;
   if(!strncmp(msg, "/pm ", 4))
   {
diff --git a/utilities/gtk/inputhistory.c b/utilities/gtk/inputhistory.c
new file mode 100644
index 0000000..a9b9450
--- /dev/null
+++ b/utilities/gtk/inputhistory.c
@@ -0,0 +1,59 @@
+/*
+    tc_client-gtk, a graphical user interface for tc_client
+    Copyright (C) 2016  alicia@ion.nu
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, version 3 of the License.
+
+    This program 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+char** inputhistory_lines=0;
+unsigned int inputhistory_count=0;
+unsigned int inputhistory_current=0;
+
+void inputhistory(GtkEntry* entry, GdkEventKey* event)
+{
+  if(event->type!=GDK_KEY_PRESS){return;}
+  if(event->keyval==GDK_KEY_Up)
+  {
+    if(inputhistory_current>0)
+    {
+      --inputhistory_current;
+      gtk_entry_set_text(entry, inputhistory_lines[inputhistory_current]);
+      gtk_editable_set_position(GTK_EDITABLE(entry), strlen(inputhistory_lines[inputhistory_current]));
+    }
+  }
+  else if(event->keyval==GDK_KEY_Down)
+  {
+    if(inputhistory_current<inputhistory_count)
+    {
+      ++inputhistory_current;
+      if(inputhistory_current==inputhistory_count)
+      {
+        gtk_entry_set_text(entry, "");
+      }else{
+        gtk_entry_set_text(entry, inputhistory_lines[inputhistory_current]);
+        gtk_editable_set_position(GTK_EDITABLE(entry), strlen(inputhistory_lines[inputhistory_current]));
+      }
+    }
+  }
+}
+
+void inputhistory_add(const char* line)
+{
+  ++inputhistory_count;
+  inputhistory_lines=realloc(inputhistory_lines, sizeof(char*)*inputhistory_count);
+  inputhistory_lines[inputhistory_count-1]=strdup(line);
+  inputhistory_current=inputhistory_count;
+}
diff --git a/utilities/gtk/inputhistory.h b/utilities/gtk/inputhistory.h
new file mode 100644
index 0000000..419ecc0
--- /dev/null
+++ b/utilities/gtk/inputhistory.h
@@ -0,0 +1,18 @@
+/*
+    tc_client-gtk, a graphical user interface for tc_client
+    Copyright (C) 2016  alicia@ion.nu
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, version 3 of the License.
+
+    This program 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+extern void inputhistory(GtkEntry* entry, GdkEventKey* event);
+extern void inputhistory_add(const char* line);