Index: src/lib/ai.py
===================================================================
--- src/lib/ai.py	(revision 8388)
+++ src/lib/ai.py	(working copy)
@@ -359,6 +359,10 @@
         isSelf = player is self and self.moving
         self.moving = False
         self.connection.reportMove(move.canMove, isSelf)
+        
+    def onUndoMove(self):
+        """Called by game.ChessPlayer"""
+        self.connection.undoMove()
 
     def readyToMove(self):
         """Called by game.ChessPlayer"""
Index: src/lib/gtkui/chessview.py
===================================================================
--- src/lib/gtkui/chessview.py	(revision 8388)
+++ src/lib/gtkui/chessview.py	(working copy)
@@ -570,6 +570,13 @@
             
             self.ui._updateViewButtons()
 
+    def undoMove(self):
+        """Extends glchess.ui.ViewController"""
+        iter = self.moveModel.iter_nth_child(None, len(self.moveModel) - 1)
+        self.moveModel.remove(iter)
+        self.selectedMove = -1
+        self.ui._updateViewButtons()        
+
     def endGame(self, game):
         # Translators: Message displayed when a player wins. The %s is substituted with the winning player's name
         format = _('%s wins')
Index: src/lib/gtkui/gtkui.py
===================================================================
--- src/lib/gtkui/gtkui.py	(revision 8388)
+++ src/lib/gtkui/gtkui.py	(working copy)
@@ -836,6 +836,10 @@
         except KeyError:
             dialog = self.__saveGameDialogs[self.view] = dialogs.GtkSaveGameDialog(self, self.view, self.view.feedback.getFileName())
         dialog.window.present()
+        
+    def _on_undo_move_clicked(self, widget):
+        """Gtk+ callback"""
+        self.view.feedback.undo()
 
     def _on_resign_clicked(self, widget):
         """Gtk+ callback"""
Index: src/lib/player.py
===================================================================
--- src/lib/player.py	(revision 8388)
+++ src/lib/player.py	(working copy)
@@ -40,6 +40,9 @@
             p.endMove()
             
         self.__game.view.controller.addMove(move)
+        
+    def onUndoMove(self):
+        self.__game.view.controller.undoMove()
 
     def onGameEnded(self, game):
         """Called by chess.board.ChessPlayer"""
Index: src/lib/display.py
===================================================================
--- src/lib/display.py	(revision 8388)
+++ src/lib/display.py	(working copy)
@@ -39,7 +39,7 @@
 
     def onPlayerMoved(self, p, move):
         self.view._redrawHighlight()
-            
+        
     def onPlayerStartTurn(self, player):
         self.view._redrawHighlight()
 
@@ -312,6 +312,10 @@
 
     def selectSquare(self, coord):
         pass
+    
+    def undo(self):
+        """Called by ui.ViewFeedback"""
+        pass
 
     def resign(self):
         """Called by ui.ViewFeedback"""
@@ -553,6 +557,12 @@
         if self.game.inHistory:
             return None
         return self.game.fileName
+    
+    def undo(self):
+        """Called by ui.ViewFeedback"""
+        p = self.game.getHumanPlayer()
+        if p is not None:
+            p.undo()
         
     def resign(self):
         """Called by ui.ViewFeedback"""
Index: src/lib/game.py
===================================================================
--- src/lib/game.py	(revision 8388)
+++ src/lib/game.py	(working copy)
@@ -104,6 +104,9 @@
         """
         pass
     
+    def onUndoMove(self):
+        pass
+    
     def onPlayerStartTurn(self, player):
         pass
 
@@ -169,6 +172,10 @@
         """
         self.__game.move(self, move)
         
+    def undo(self):
+        """Undo moves until it is this players turn"""
+        self.__game.undo(self)
+        
     def endMove(self):
         """Complete this players turn"""
         self.__game.endMove(self)
@@ -495,7 +502,40 @@
             self._move(player, move)
 
         self.endLock()
+
+    def undo(self, player):
+        if self.__inCallback:
+            self.__queuedCalls.append((self.undo, (player,)))
+            return
         
+        self.startLock()
+        
+        self.__whitePlayer._setReadyToMove(False)
+        self.__blackPlayer._setReadyToMove(False)
+        
+        # Pretend the current player is the oponent so when endMove() is called
+        # this player will become the active player.
+        # Yes, this IS a big hack...
+        if player is self.__whitePlayer:
+            self.__currentPlayer = self.__blackPlayer
+        else:
+            self.__currentPlayer = self.__whitePlayer
+        
+        # If this player hasn't moved then undo oponents move before their one
+        if len(self.__moves) > 0 and self.__moves[-1].player is not player:
+            count = 2
+        else:
+            count = 1
+            
+        for i in xrange(count):
+            if len(self.__moves) != 0:
+                self.board.undo()
+                self.__moves = self.__moves[:-1]
+                for p in self.__players:
+                    p.onUndoMove()
+        
+        self.endLock()
+        
     def startLock(self):
         assert(self.__inCallback is False)
         self.__inCallback = True
Index: src/lib/cecp.py
===================================================================
--- src/lib/cecp.py	(revision 8388)
+++ src/lib/cecp.py	(working copy)
@@ -96,6 +96,10 @@
         """Stop the AI from automatically moving"""
         self.onOutgoingData('force\n')
         
+    def sendUndo(self):
+        """Undo the last move"""
+        self.onOutgoingData('undo\n')
+        
     def sendMovePrompt(self):
         """Get the AI to move for the current player"""
         self.onOutgoingData('go\n')
@@ -206,6 +210,11 @@
         # Prompt the AI to move
         self.sendMovePrompt()
         
+    def undoMove(self):
+        """Undo the last move made by this AI"""
+        self.sendWait()
+        self.sendUndo()
+
     def reportMove(self, move, isSelf):
         """Report the move the current player has made.
         
Index: src/lib/chess/board.py
===================================================================
--- src/lib/chess/board.py	(revision 8388)
+++ src/lib/chess/board.py	(working copy)
@@ -201,6 +201,9 @@
     
     # The move that got us to this state
     lastMove        = None
+    
+    # Pieces moved that got us to this state
+    moves           = None
 
     # If the last move was a pawn march the location where it can be taken by en-passant
     enPassantSquare = None
@@ -215,10 +218,11 @@
     
     # Flag to show if the previous move has caused a three fold repition
     threeFoldRepetition = False
-    
+
+    # Bitboards
     whiteBitBoard = 0
     blackBitBoard = 0
-    allBitBoard = 0
+    allBitBoard   = 0
 
     def __init__(self, lastState = None):
         """Constuctor for storing the state of a chess board.
@@ -243,6 +247,7 @@
             self.moveNumber = 0
             self.squares = {}
             self.casualties = []
+            self.moves = []
             self.whiteState = ChessPlayerState()
             self.blackState = ChessPlayerState()
             
@@ -251,6 +256,7 @@
             self.moveNumber = 0
             self.squares = {}
             self.casualties = []
+            self.moves = []            
             self.whiteBitBoard = 0
             self.blackBitBoard = 0
             self.allBitBoard = 0
@@ -275,6 +281,7 @@
             self.squares = lastState.squares.copy()
             self.casualties = lastState.casualties[:]
             self.lastMove = lastState.lastMove
+            self.moves = lastState.moves[:]
             self.enPassantSquare = lastState.enPassantSquare
             self.whiteState = ChessPlayerState(lastState.whiteState)
             self.blackState = ChessPlayerState(lastState.blackState)
@@ -352,8 +359,7 @@
 
             # See if this piece can take
             board = ChessBoardState(self)
-            move = board.movePiece(enemyPiece.getColour(), enemyCoord, location, testCheck = False, applyMove = False)
-            if move is not None:
+            if board.movePiece(enemyPiece.getColour(), enemyCoord, location, testCheck = False, applyMove = False):
                 return True
             
         return False
@@ -375,8 +381,7 @@
             for rank in 'abcdefgh':
                 for file in '12345678':
                     board = ChessBoardState(self)
-                    move = board.movePiece(colour, coord, rank + file, applyMove = False)
-                    if move is not None:
+                    if board.movePiece(colour, coord, rank + file, applyMove = False):
                         return True
 
         return False
@@ -693,6 +698,8 @@
             self.allBitBoard = allBitBoard
             
         else:
+            self.moves = result
+            
             # Remember the casualties
             if victim is not None:
                 self.casualties.append(victim)
@@ -867,12 +874,11 @@
         assert(self.__inCallback is False)
         
         state = ChessBoardState(self.__boardStates[moveNumber])
-        moves = state.movePiece(colour, start, end, promotionType = promotionType, allowSuicide = False)
-        if moves is None:
+        if not state.movePiece(colour, start, end, promotionType = promotionType, allowSuicide = False):
             return None
 
         victim = None
-        for (piece, start, end, delete) in moves:
+        for (piece, start, end, delete) in state.moves:
             # The victim is the enemy piece that has been deleted
             if delete and piece.getColour() != colour:
                 victim = piece
@@ -899,14 +905,23 @@
         if not test:
             self.__boardStates.append(state)
         move = Move()
-        move.moves = moves
+        move.moves = state.moves
         move.victim = victim
         move.opponentInCheck = state.inCheck(opponentColour)
         move.opponentCanMove = state.canMove(opponentColour)
         move.threeFoldRepetition = state.threeFoldRepetition
         move.fiftyMoveRule = state.fiftyMoveCount >= 50
         return move
+    
+    def undo(self):
+        """Undo the last move"""
+        undoState = self.__boardStates[-1]
+        self.__boardStates = self.__boardStates[:-1]
 
+        # Undo the moves
+        for (piece, start, end, delete) in undoState.moves:
+            self.__onPieceMoved(piece, end, start, False)
+
     def __str__(self):
         """Returns a representation of the current board state"""
         return str(self.__boardStates[-1])
Index: src/lib/uci.py
===================================================================
--- src/lib/uci.py	(revision 8388)
+++ src/lib/uci.py	(working copy)
@@ -116,6 +116,16 @@
             blackTime = 30000
             
         self.__sendCommand('go wtime %d btime %d' % (whiteTime, blackTime))
+        
+    def undoMove(self):
+        """
+        """
+        self.__sendCommand('stop');
+        (self.__positionCommand, _) = self.__positionCommand.rsplit(" ", 1)
+        if self.__positionCommand.endswith(' moves'):
+            self.__haveMoves = False
+            self.__positionCommand = 'position startpos'
+        self.__sendCommand(self.__positionCommand)        
 
     def reportMove(self, move, isSelf):
         """
@@ -125,7 +135,7 @@
         self.__haveMoves = True
         self.__positionCommand += ' ' + move
         self.__sendCommand(self.__positionCommand)
-        
+
     def parseLine(self, line):
         """
         """
Index: src/lib/main.py
===================================================================
--- src/lib/main.py	(revision 8388)
+++ src/lib/main.py	(working copy)
@@ -648,10 +648,6 @@
 
         return newGame
 
-    def addMove(self, view, move):
-        # TEMP
-        self.ui.controller.addMove(view, move)
-
     def start(self):
         """Run glChess.
         
Index: src/lib/ui/ui.py
===================================================================
--- src/lib/ui/ui.py	(revision 8388)
+++ src/lib/ui/ui.py	(working copy)
@@ -203,6 +203,10 @@
         'filename' is the file to save to (string or None to save to last filename).
         """
         assert(False)
+        
+    def undo(self):
+        """Indicates the human player wants to undo their last move"""
+        assert(False)
     
     def regsign(self):
         """Indicates the human player wants to resign"""
@@ -235,6 +239,10 @@
         'move' is the move made (string).
         """
         assert(False)
+        
+    def undoMove(self):
+        """Remove the last move from this view"""
+        assert(False)
     
     def render(self):
         """Request this view is redrawn"""
Index: glade/glchess.glade
===================================================================
--- glade/glchess.glade	(revision 8388)
+++ glade/glchess.glade	(working copy)
@@ -38,7 +38,7 @@
 	  <child>
 	    <widget class="GtkMenuItem" id="menuitem1">
 	      <property name="visible">True</property>
-	      <property name="label" translatable="yes" comments="The Game menu">_Game</property>
+	      <property name="label" translatable="yes">_Game</property>
 	      <property name="use_underline">True</property>
 
 	      <child>
@@ -90,13 +90,13 @@
 		  <child>
 		    <widget class="GtkImageMenuItem" id="menu_play_online_item">
 		      <property name="visible">True</property>
-		      <property name="label" translatable="yes" comments="The Game|Network Game menu">Network _Game</property>
+		      <property name="label" translatable="yes">Network _Game</property>
 		      <property name="use_underline">True</property>
 		      <signal name="activate" handler="_on_join_game_button_clicked" last_modification_time="Sun, 30 Jul 2006 14:16:15 GMT"/>
 		      <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image109">
+			<widget class="GtkImage" id="image121">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-network</property>
 			  <property name="icon_size">1</property>
@@ -116,14 +116,36 @@
 		  </child>
 
 		  <child>
+		    <widget class="GtkImageMenuItem" id="menu_undo_move">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_Undo Move</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="_on_undo_move_clicked" last_modification_time="Fri, 02 Jan 2009 04:57:07 GMT"/>
+		      <accelerator key="Z" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+		      <child internal-child="image">
+			<widget class="GtkImage" id="image122">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-undo</property>
+			  <property name="icon_size">1</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		  </child>
+
+		  <child>
 		    <widget class="GtkImageMenuItem" id="menu_resign">
 		      <property name="visible">True</property>
-		      <property name="label" translatable="yes" comments="The Game|Resign menu">_Resign</property>
+		      <property name="label" translatable="yes">_Resign</property>
 		      <property name="use_underline">True</property>
 		      <signal name="activate" handler="_on_resign_clicked" last_modification_time="Sun, 20 Jan 2008 19:45:39 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image110">
+			<widget class="GtkImage" id="image123">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-dialog-warning</property>
 			  <property name="icon_size">1</property>
@@ -139,12 +161,12 @@
 		  <child>
 		    <widget class="GtkImageMenuItem" id="menu_claim_draw">
 		      <property name="visible">True</property>
-		      <property name="label" translatable="yes" comments="The Game|Claim Draw menu">Claim _Draw</property>
+		      <property name="label" translatable="yes">Claim _Draw</property>
 		      <property name="use_underline">True</property>
 		      <signal name="activate" handler="_on_claim_draw_clicked" last_modification_time="Sun, 20 Jan 2008 19:45:39 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image111">
+			<widget class="GtkImage" id="image124">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-delete</property>
 			  <property name="icon_size">1</property>
@@ -179,7 +201,7 @@
 	  <child>
 	    <widget class="GtkMenuItem" id="menuitem3">
 	      <property name="visible">True</property>
-	      <property name="label" translatable="yes" comments="The View menu">_View</property>
+	      <property name="label" translatable="yes">_View</property>
 	      <property name="use_underline">True</property>
 
 	      <child>
@@ -188,13 +210,13 @@
 		  <child>
 		    <widget class="GtkImageMenuItem" id="menu_fullscreen">
 		      <property name="visible">True</property>
-		      <property name="label" translatable="yes" comments="The View|Fullscreen menu">_Fullscreen</property>
+		      <property name="label" translatable="yes">_Fullscreen</property>
 		      <property name="use_underline">True</property>
 		      <signal name="activate" handler="_on_view_fullscreen_clicked" last_modification_time="Mon, 30 Oct 2006 21:20:40 GMT"/>
 		      <accelerator key="F11" modifiers="0" signal="activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image112">
+			<widget class="GtkImage" id="image125">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-fullscreen</property>
 			  <property name="icon_size">1</property>
@@ -209,13 +231,13 @@
 
 		  <child>
 		    <widget class="GtkImageMenuItem" id="menu_leave_fullscreen">
-		      <property name="label" translatable="yes" comments="The View|Leave Fullscreen menu">Leave _Fullscreen</property>
+		      <property name="label" translatable="yes">Leave _Fullscreen</property>
 		      <property name="use_underline">True</property>
 		      <signal name="activate" handler="_on_view_unfullscreen_clicked" last_modification_time="Mon, 30 Oct 2006 21:43:10 GMT"/>
 		      <accelerator key="F11" modifiers="0" signal="activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image113">
+			<widget class="GtkImage" id="image126">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-leave-fullscreen</property>
 			  <property name="icon_size">1</property>
@@ -231,7 +253,7 @@
 		  <child>
 		    <widget class="GtkCheckMenuItem" id="menu_view_3d">
 		      <property name="visible">True</property>
-		      <property name="label" translatable="yes" comments="The View|3D Chess View menu">3_D Chess View</property>
+		      <property name="label" translatable="yes">3_D Chess View</property>
 		      <property name="use_underline">True</property>
 		      <property name="active">False</property>
 		      <signal name="activate" handler="_on_toggle_3d_clicked" last_modification_time="Thu, 14 Sep 2006 19:40:59 GMT"/>
@@ -241,7 +263,7 @@
 		  <child>
 		    <widget class="GtkCheckMenuItem" id="menu_view_logs">
 		      <property name="visible">True</property>
-		      <property name="label" translatable="yes" comments="The View|Show Logs menu">Show _Logs</property>
+		      <property name="label" translatable="yes">Show _Logs</property>
 		      <property name="use_underline">True</property>
 		      <property name="active">False</property>
 		      <signal name="activate" handler="_on_show_logs_clicked" last_modification_time="Sat, 01 Sep 2007 15:42:25 GMT"/>
@@ -255,7 +277,7 @@
 	  <child>
 	    <widget class="GtkMenuItem" id="settings">
 	      <property name="visible">True</property>
-	      <property name="label" translatable="yes" comments="The Settings menu">_Settings</property>
+	      <property name="label" translatable="yes">_Settings</property>
 	      <property name="use_underline">True</property>
 
 	      <child>
@@ -266,10 +288,7 @@
 		      <property name="visible">True</property>
 		      <property name="label">gtk-preferences</property>
 		      <property name="use_stock">True</property>
-		      <property name="use_underline">True</property>
 		      <signal name="activate" handler="_on_preferences_clicked" last_modification_time="Sun, 20 Jan 2008 17:28:02 GMT"/>
-
-		      
 		    </widget>
 		  </child>
 		</widget>
@@ -280,7 +299,7 @@
 	  <child>
 	    <widget class="GtkMenuItem" id="help2">
 	      <property name="visible">True</property>
-	      <property name="label" translatable="yes" comments="The Help menu">_Help</property>
+	      <property name="label" translatable="yes">_Help</property>
 	      <property name="use_underline">True</property>
 
 	      <child>
@@ -288,12 +307,12 @@
 
 		  <child>
 		    <widget class="GtkImageMenuItem" id="menu_help">
-		      <property name="label" translatable="yes" comments="The Help|Contents menu">_Contents</property>
+		      <property name="label" translatable="yes">_Contents</property>
 		      <property name="use_underline">True</property>
 		      <signal name="activate" handler="_on_help_clicked" last_modification_time="Fri, 11 Aug 2006 12:43:28 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image115">
+			<widget class="GtkImage" id="image127">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-help</property>
 			  <property name="icon_size">1</property>
@@ -404,6 +423,23 @@
 	  </child>
 
 	  <child>
+	    <widget class="GtkToolButton" id="undo_move_button">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes" comments="The tooltip for the Resign toolbar button">Undo Move</property>
+	      <property name="use_underline">True</property>
+	      <property name="stock_id">gtk-undo</property>
+	      <property name="visible_horizontal">True</property>
+	      <property name="visible_vertical">True</property>
+	      <property name="is_important">False</property>
+	      <signal name="clicked" handler="_on_undo_move_clicked" last_modification_time="Fri, 02 Jan 2009 04:58:33 GMT"/>
+	    </widget>
+	    <packing>
+	      <property name="expand">False</property>
+	      <property name="homogeneous">True</property>
+	    </packing>
+	  </child>
+
+	  <child>
 	    <widget class="GtkToolButton" id="resign_button">
 	      <property name="visible">True</property>
 	      <property name="label" translatable="yes" comments="The tooltip for the Resign toolbar button">Resign</property>
