[Xfce4-commits] <mousepad:master> Merge branch 'nick_0_3'

Matthew Brush noreply at xfce.org
Sat May 5 21:32:05 CEST 2012


Updating branch refs/heads/master
         to dafbfc876426ecc221a353fd586488a35e063a9f (commit)
       from 9de1554965033cc24b641be3aae84b8fbd1e5bab (commit)

commit dafbfc876426ecc221a353fd586488a35e063a9f
Merge: 9de1554 551173d
Author: Matthew Brush <matt at xfce.org>
Date:   Sat Mar 31 13:32:13 2012 -0700

    Merge branch 'nick_0_3'
    
    This branch contains a complete re-write.

commit 551173dcfac7ec4ae8c7e0a2baa4ea147c92253a
Author: Matthew Brush <matt at xfce.org>
Date:   Sat Mar 31 13:24:21 2012 -0700

    Add .gitignore file

commit 4783ee11ebd8b90e70923d83a7468351d6fedb80
Author: Matthew Brush <matt at xfce.org>
Date:   Fri Oct 7 05:58:04 2011 -0700

    Fix a couple minor issues from last couple commits.

commit 34cb31bbed2aef45bf0f85d34a87aea9d4eb0846
Author: Matthew Brush <matt at xfce.org>
Date:   Fri Oct 7 05:45:14 2011 -0700

    Add filetype selection popup menu to statusbar.

commit adf4ea822a98376362f812ae1ff6488148218380
Author: Matthew Brush <matt at xfce.org>
Date:   Fri Oct 7 03:24:38 2011 -0700

    Update a few documentation files.

commit ab93fe61fe7317e61ee6ec804e3d266bc1e50980
Author: Matthew Brush <matt at xfce.org>
Date:   Fri Oct 7 02:15:21 2011 -0700

    Make Filetype separate in the Document menu.

commit 4777a405afb12e26853328a9131c2c3f131014ec
Author: Matthew Brush <matt at xfce.org>
Date:   Fri Oct 7 01:05:09 2011 -0700

    Reorder action entry arrays (forgotten in last commit).

commit 143b6ba6c2a8e024057bfca7e96deeb6bc3e765f
Author: Matthew Brush <matt at xfce.org>
Date:   Fri Oct 7 00:52:59 2011 -0700

    Cleanup View and Document menus.
    
    * Move "Line Numbers" from Document to View menu and apply it to all
      of the currently open textviews.
    * Re-order View and Document menu items, mostly sorted alphabetically.
    * Remove extra separators between related items.
    * Re-arrange action handler functions to be in the same order as their
      items appear in the XML file.

commit 5c88d180a1e20cb51737990948bb041529a97357
Author: Matthew Brush <matt at xfce.org>
Date:   Thu Oct 6 22:37:00 2011 -0700

    Add extra settings to custom print dialog tab.
    
    * Add line number increment setting.
    * Add separate font settings for header, body and line numbers.

commit ba85e8dae9ae1c478242b3c678389191dd8e1e87
Author: Matthew Brush <matt at xfce.org>
Date:   Thu Oct 6 19:35:30 2011 -0700

    Use GtkSourcePrintCompositor property names in config file.

commit c45ed8da1ae2ed17fb291084cebae1275d33f7c8
Author: Matthew Brush <matt at xfce.org>
Date:   Thu Oct 6 19:23:13 2011 -0700

    Switch to GtkSourcePrintCompositor for printing.
    
    * Add printing option for syntax highlighting.
    * Some of the page footer code implemented in #if 0 blocks.
    * Remove mousepad_print_end_print() function.

commit 029bef60746206eaf08dc11c89afd59db186db8d
Merge: 05b3c46 52e5c6a
Author: Matthew Brush <matt at xfce.org>
Date:   Thu Oct 6 04:05:33 2011 -0700

    Merge branch 'nick_0_3' into gtksourceview

commit 52e5c6a0051cd456802d6b50b85b9190a33d62cf
Author: Matthew Brush <matt at xfce.org>
Date:   Thu Oct 6 03:56:42 2011 -0700

    Prevent segfault when opening more that 100 files.
    
    Reported by Mark_T on #xfce-dev IRC.

commit 05b3c46c8b9877fa62b07fd6a04b1b82fc5576ed
Author: Matthew Brush <matt at xfce.org>
Date:   Thu Oct 6 03:11:18 2011 -0700

    Select filetype radio menu item when detecting filetype.
    
    Fix setting filetype to None.

commit 66a2d472174195507aa00ae8287ff4c1b62c6604
Author: Matthew Brush <matt at xfce.org>
Date:   Thu Oct 6 01:35:14 2011 -0700

    Cleanup colour scheme util functions a bit.

commit 5d74b7018dd0f821f6f37a0293868466a9b836b3
Author: Matthew Brush <matt at xfce.org>
Date:   Wed Oct 5 20:50:06 2011 -0700

    Change mousepad_util_color_schemes_get_sorted to use GSList.
    
    Also add some comments and set default value on selected_color_scheme in
    mousepad_window_menu_color_schemes.

commit 81eb018689978502e6a128436ed4cb8ab5de77cf
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Wed Oct 5 15:59:11 2011 -0700

    Select the last saved colour scheme in the menu on application start.

commit 6ceb27df8efb7b23acc73c147511721cbea45b20
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Wed Oct 5 15:49:10 2011 -0700

    Cleanup and refactor some code from the last few commits.
    
    * Move colour scheme and language utility functions to mousepad-util.[ch].
    * Rename colour scheme and language utility functions with better names.
    * Put colour scheme action func/proto in the correct order of appearance.

commit 92b22bcb38d66f63b5ce69d9df7d3f14e60ac15a
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Wed Oct 5 15:05:43 2011 -0700

    Add menu to manually select filetype/language.
    
    This code needs to be reviewed and cleaned up more.
    Thanks to "cavalier" on #xfce-dev IRC for help getting this working.

commit c5ac3ceeff8979a20d60e40f62f0b04d0ea67b9f
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Tue Oct 4 01:28:34 2011 -0700

    Noise: remove extra whitespace added by editor.
    
    Apologies for the noise.

commit 7be1dde6dfe47b08cf49f6bfb3f4fe031d9fad8e
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Tue Oct 4 00:08:50 2011 -0700

    Use better string compare function for colour scheme names.

commit 349066029e579a6dc1014aff3759e0f78ec52eb7
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 23:47:52 2011 -0700

    Fix kludge from last commit (FIXME comment).
    
    Add a new signal 'language-changed' to MousepadDocument for the window
    to use to get notified of when to update the language/filetype in the
    statusbar.

commit ba38b4940b2998c30ba9bde6c707bf1c589cae0b
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 22:33:51 2011 -0700

    Update statusbar filetype when notebook pages are changed.
    
    Note the FIXME in the comments, this will probably need some refactoring.

commit 82b6e834ddeea4be8bf901307e6e093bde24631c
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 21:48:03 2011 -0700

    Add initial filetype/language support and guess on file open.
    
    Still need to add UI elements to let user select language to use.

commit cc401c48985b9f06c855cac39175ddcbe0efe091
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 20:06:24 2011 -0700

    Add colour scheme support.
    
    * Add new preference 'color-scheme' that stores the scheme's ID string.
    * Add new 'Color Schemes' menu and placeholder for items to UI XML file.
    * Add new actions for all colour schemes and merge into UI manager menu.
    * Handle actions by looping though all textview widgets and setting style.
    * Using 'g_str_hash' of scheme id for radio action value which might be bad.

commit 9a6ad0cb703ec1ef475458cec656cbeef9d865dc
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 08:10:59 2011 -0700

    Remove old tab size code and use GtkSourceView's tab-width.

commit 728cb754e087cf0bbc2efa7167a8008b2c66752a
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 06:54:20 2011 -0700

    Remove undo manager code and use GtkSourceView's undo manager.
    
    There was a call to mousepad_undo_lock() in mousepad-encoding-dialog.c
    that needs to be checked, since I wasn't sure what that call was for.

commit 6be5f6c5f9de3242f234f08506da31e55396d9b5
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 02:38:25 2011 -0700

    Remove old insert spaces code and use GtkSourceView's.
    
    Remove special tab handling since GtkSourceView handles it.

commit 898612c83495635ef657fea60f6b9048640b0f15
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 02:01:16 2011 -0700

    Remove old auto-indentation code and use GtkSourceView's auto-indent.

commit 801eadc860c894420a1807e5a9f496895bd031c8
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 01:52:27 2011 -0700

    Remove old line number code and use GtkSourceView's show-line-numbers.

commit d1970d6b3ec4e212f8fd2823b6f5dd00c17fe4cf
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 01:34:42 2011 -0700

    Make MousepadView a subclass of GtkSourceView instead of GtkTextView.
    
    Add include for gtksourceview.h in mousepad-private.h.
    
    Causes the line numbers to always be shown initially but this should be
    fixed once the line numbers code is ported to use GtkSourceView.

commit 4e5c46f563dc7e468041a62f82cab8e8bfc4a3dc
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 05:30:31 2011 -0700

    Add GtkSourceView dependency to build system.
    
    Still need to determine which version of GtkSourceView to depend on.

commit b401a34b8c6b88ebd26e26f03a70a13548cbc4c0
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 05:20:18 2011 -0700

    Prevent warnings when messing around with statusbar internal widgets.
    
    Remove statusbar frame border.

commit 6bdfbdf87e4ac5ffd528b6daafd9755acfe04415
Author: Matthew Brush <mbrush at codebrainz.ca>
Date:   Mon Oct 3 03:56:58 2011 -0700

    Revert "Drop usage of the GtkStatusbar."
    
    This reverts commit 185821ae262235222f7ef1d3a86dc0ea2b19bbd9.

commit ff0faf3c3250b4e56598aec891109d96f3aece7a
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Oct 15 16:24:59 2010 +0200

    Fix error in recent actions.

commit 185821ae262235222f7ef1d3a86dc0ea2b19bbd9
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Oct 15 16:19:40 2010 +0200

    Drop usage of the GtkStatusbar.
    
    Only shows a lot of errors. Because of this we loose the
    resize grip for now, but in gtk3 this will be possible again.

commit 385535209b957746bec3d29818bc1d4490df35e3
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Aug 26 21:11:41 2010 +0200

    Move MousepadHelp to $libdir/xfce4/mousepad.

commit a269c2d3c2f009925da47191f3eb7fec459072c1
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Apr 28 02:14:14 2010 +0200

    Rename configure.in.in to configure.ac.in.

commit acfa674ea1984c5a449cf8e23ae53e4409edda5a
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Apr 24 10:40:26 2010 +0200

    Drop old po files.

commit 3eea02f5adfabad3bbd9975eb6f69fea1c213a1b
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Apr 24 10:35:51 2010 +0200

    Make build GIT friendly.
    
    Also apply silent rules and use new XDT macros.

commit 1972a36499a3644bc32067bb748a79f0d4523257
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Apr 24 10:31:47 2010 +0200

    Don't disable deprecated Gtk functions.

commit c5c4bd8a3f8c8a0ce94e806e027d68dac540cec0
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Feb 10 12:59:50 2010 +0100

    Fix compilation with pango.

commit 375a246bf9f38733f368bfa05163734119b54168
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Aug 12 18:01:02 2009 +0200

    Move in all the changes from the old git branch.
    
    Because individual patches did not apply, this is one big
    commit the moving everything at once.

commit d7fce4e8e9890bee3cde1d8afa549b320ca0bb4c
Author: Mike Massonnet <mmassonnet at xfce.org>
Date:   Tue Apr 1 07:11:50 2008 +0000

    Revert French translation.  Add a note inside TRANSLATORS
    
    (Old svn revision: 26701)

commit 1a06210de348a7ef5e54262a43dd0410e4b91f62
Author: Mike Massonnet <mmassonnet at xfce.org>
Date:   Mon Mar 31 11:46:16 2008 +0000

    mousepad/nick: update french translation
    
    (Old svn revision: 26700)

commit 73c4f9cde2db6826c690d2b19eab715bd493c704
Author: Nick Schermer <nick at xfce.org>
Date:   Mon Mar 10 19:52:22 2008 +0000

    	* mousepad/mousepad-document.c: Swap the colors of readonly and
    	  modified tabs. Red is modified and green readonly.
    
    (Old svn revision: 26674)

commit e6deae974c002619ee11c3d68d92ec768b235ac5
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Mar 2 13:51:40 2008 +0000

    	* mousepad/mousepad-file.c: Don't set an error and return false on
    	  externally modified when the file does not exist. This fixes
    	  an error when saving a new file.
    	* mousepad/mousepad-file.c: Emit signal when the readonly status
    	  changes.
    	* mousepad/mousepad-document.c: Use the readonly signal to update
    	  the label color. This fixes a readonly-colored label when saving
    	  a new file.
    
    (Old svn revision: 26656)

commit 790cd28e036aec098aaee8cc03b101f0c436580d
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Feb 17 12:08:21 2008 +0000

    	* mousepad/mousepad-search-bar.c: Select the text in the search
    	  entry when focussing the search bar (Ctrl+F).
    	* mousepad/mousepad-window.c: Set default keybindings of Find Next
    	  and Find Previous to F3 and Shft+F3.
    
    (Old svn revision: 26621)

commit 59d55f4852cdfaf811f51c97927defdb1e197d5b
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Jan 15 18:23:21 2008 +0000

    * configure.in.in, mousepad/Makefile.am: Remove gmodule from the
      library list, is not used. Add glib to make sure it's linked.
    * mousepad/mousepad-window.c: Use the HOME environment variable
      to search for the templates path, fallback on g_get_homedir.
    * MousepadHelp.in: Improve script to find other browsers too,
      instead of only using exo-open.
    * mousepad/mousepad-preferences: Improve the performace of loading
      and saving a bit. Loading now directly writes to the internal
      value array. Could be a bit tricky, we'll see.
    * mousepad/mousepad-{preferences,print}.c: Use g_key_file_{get,
      set}_value instead of g_key_file_{get,set}_string, should be a
      bit faster.
    * mousepad/mousepad-window.c: Be more secure when loading tab sizes.
    * po/mousepad.pot: Update.
    
    
    (Old svn revision: 26574)

commit 9b4a2525a341187a8ea4bddfaeff3e07ef724773
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Jan 15 10:59:07 2008 +0000

    * mousepad/mousepad-window.c: Update menu actions after a document
      is closed, so the detach action becomes insensitive when there
      is only one document openened.
    
    
    (Old svn revision: 26573)

commit 35ea349ad0c4ee3557c3c28bb7b5c30cb9fdfe22
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Jan 15 10:34:47 2008 +0000

    * TODO: Update
    * mousepad/mousepad-{dialogs,window,file}.c: Check for external
      file modifications before saving.
    * ChangeLog: Update.
    * configure.in.in: Remove api version and add support for a nano
      version.
    
    
    (Old svn revision: 26572)

commit 2709fd15751d4197f8c260989b7069473dfae65f
Author: Nick Schermer <nick at xfce.org>
Date:   Mon Jan 14 16:49:57 2008 +0000

    * Drop libxfce4util as dependency
    * Switch to accessories-text-editor as icon name
    
    
    (Old svn revision: 26571)

commit a8924e11dad4f268f699ce42abd348ba4dcb2492
Author: Nick Schermer <nick at xfce.org>
Date:   Mon Jan 14 11:33:17 2008 +0000

    * Use G_DEFINE_TYPE.
    * Properly set the emission stage for all signals.
    * Remove some unused code.
    * Fix assert when dropping a file in the editor window.
    * Small typo in the menu tooltips.
    
    
    (Old svn revision: 26570)

commit b93f219eb75efb3769f5d1a150831a4a1f09291d
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Dec 12 09:29:50 2007 +0000

    	* mousepad/mousepad-window.c: Try to find the file encoding in the
    	  recent history, when opening a document that didn't pass the
    	  UTF-8 check.
    
    (Old svn revision: 26460)

commit ccf616594ecd39b49bb632372c7cd28557a776f1
Author: Nick Schermer <nick at xfce.org>
Date:   Mon Dec 10 19:47:45 2007 +0000

    * mousepad/mousepad-undo.c: Remove testing messages.
    
    
    (Old svn revision: 26455)

commit d1075d569a475bc2e16dfaab0209e1e4d0c8dec0
Author: Nick Schermer <nick at xfce.org>
Date:   Mon Dec 10 19:36:58 2007 +0000

    	* mousepad/mousepad-window.c: Use the switch-page signal instead
    	  of a notify on the page property.
    	* mousepad/mousepad-*: Remove deprecated tooltip api when compiled
    	  with Gtk+ >= 2.12.
    	* mousepad/mousepad-replace-dialog.c: Connect tab switch signal for
    	  updating the dialog status when switching tabs.
    	* mousepad/mousepad-undo.c: Fix issues with the undo manager. It
    	  now works with a points system (chars: 1pt, space/tab: 10pts,
    	  new line: 25pts). A step contains 30pts, whole words and spaces
    	  are merged. This way the undo steps feel more consistent.
    	  Properly keep the number of visible undo steps < 100.
    	  Store document save point in the undo manager, when you undo to
    	  this points the document will not be modified, but the history
    	  is not erased either when saving.
    	* mousepad/Makefile.am: Add DGTK_DISABLE_DEPRECATED and
    	  DGDK_DISABLE_DEPRECATED.
    
    (Old svn revision: 26454)

commit 1d7bef769029aae39ddcecb6c529177393363dcf
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Dec 8 10:46:08 2007 +0000

    	* mousepad/mousepad-{dialog,window}.c: Show save as button in
    	  question dialog for readonly documents. Also add the modified
    	  readonly documents to the save-as queue when running save all.
    
    (Old svn revision: 26451)

commit f67680befa81f562943b591a7143e25baea1fb17
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Dec 8 10:31:50 2007 +0000

    	* mousepad/mousepad-{search-bar,window}.c: Remove highlight when
    	  hiding the search bar. Search ahead when opening the search bar.
    
    (Old svn revision: 26450)

commit 72415680ea141554b03f505d5f9a96861957c5a0
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Dec 7 19:42:23 2007 +0000

    * mousepad/mousepad-search-bar.c: Fix red entry when toggling the
      highlight button.
    
    
    (Old svn revision: 26447)

commit 562a27b0824e528841b1a58b01d8c9978f4bd05e
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Dec 6 20:11:21 2007 +0000

    * mousepad/mousepad-document.c: Fix column number in statusbar.
      First column is 0 and not 1.
    * mousepad/mousepad-dialogs.c: Improve the go to dialog. You can now
      set the column number too.
    * mousepad/mousepad-window{.c,-ui.xml}: Improve the menu layout big
      time. Make mnemonics consistent right now. A couple of name,
      tooltip and keybindings changes. Internal names make more sense
      now.
    * mousepad/mousepad-{window,view}.c Add option to paste from
      history. The history holds the last 9 history cut/copied items
      from Mousepad.
    * mousepad/mousepad-window.c: New from template menu. Works the
      same as the implementation in Thunar. Menu is generated the first
      time the file menu is shown. Same for the recent menu.
    * mousepad/mousepad-{window,view}.c: Add option to toggle between
      column and normal selections. Put it in View -> Change to Column
      Selection. To make this work properly I've removed multi
      selection. Code got much easier and a couple of complex functions
      were dropped.
    * mousepad/mousepad-window{.c,-ui.xml}: Put search menu items in
      the edit menu, since you will most likely access them from
      keybindings most of the time.
    * mousepad/mousepad-window.c: Cleanuped up a lot of functions.
    * mousepad/mousepad-window.c: Check if files exists when generating
      the recent menu, remove it when it was not found. Also unref the
      action after adding it to the action group, fixes an ugly memory
      leak, since the recent info isn't released eighter.
    * mousepad/mousepad-util.c: Add faster function to escape
      underscores in the recent menu. Drop the previous function used
      for this.
    * mousepad/mousepad-private.h: Add macros around g_object_(get/set)
      _qdata and use them instead of the existing g_object_(get/set)
      _data functions.
    * mousepad/mousepad-view.c: Fix indent with (shift) tab.
    * mousepad/mousepad-view.c: Improve line number drawing. Only
      redraw the line numbers in the expose area and some other changes
      to reduce the amount of redraws and iter calls.
    * mousepad/mousepad-view.c: Use the IM to type in multi selections,
      the previous way was deprecated and this fixes a couple of weird
      issues.
    * mousepad/mousepad-view.c: Show realtime selection size in column
      selections.
    * mousepad/mousepad-{document,view,window}.c: Put selection change
      in a separate signal to avoid multiple update the the action
      group.
    * mousepad/mousepad-view.c: Avoid a lot of statusbar updates and
      column selection redraws during dragging by comparing the old and
      new cursor position. On the other hand, the 'only draw the visible
      area during drag' trick has been partly removed to properly
      display the selection length during a column draw that covers
      more then the window height.
    * mousepad/mousepad-{util,view}.c: Add functions to change the case
      of a selection.
    * mousepad/mousepad-view.c: Add function to replace tabs with spaces
      and vice versa. The replacements are inlined, so you don't see
      visual changes in the document. Actions are not usable during
      column selections.
    * mousepad/mousepad-window.c: Make the arrow buttons in the notebook
      work.
    * mousepad/mousepad-window.c: Close document on middle click on the
      tab, this is a stupid feature, but since everyone requests it on
      apps with tabs: add it to save a bugzilla report.
    * mousepad/mousepad-{window,view}.c: Add actions to increase or
      decrease the indentation of line(s) using the menu or keybindings.
    * mousepad/mousepad-{window,view}.c: Add an action to duplicate a
      line or selection. Only work for normal selections or no
      selection.
    * mousepad/mousepad-{window,view}.c: Add an action to move the
      selected lines up and down. Not implemented for column selections
      (yet). Menu actions are insensitive when there is no regual
      selection.
    * mousepad/mousepad-{window,view}.c: Add option to strip trailing
      spaces and tabs.
    * mousepad/mousepad-window.c: Add a file to the recent history
      after saving it under another name.
    * mousepad/mousepad-window{.c,-ui.xml}: Add line ending type in the
      document menu.
    * mousepad/mousepad-window.c: Avoid one menu update when adding or
      removing a new document to the window.
    * mousepad/mousepad-document.c: Change tab label color when the
      document is modified or readonly.
    * ChangeLog: Properly break lines.
    
    
    (Old svn revision: 26441)

commit 976c9707d60945030612eaf79db2e577135fe4ef
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Nov 29 19:20:44 2007 +0000

    	* mousepad/mousepad-document.c: Make tab close button a bit smaller.
    
    (Old svn revision: 26407)

commit d2cf9f1d53f4818ea92e162cf6b71b9963144ce8
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Nov 29 18:29:46 2007 +0000

    	* mousepad/mousepad-window.c: Use a box for packing the window elements.
    	  A table was not really needed, and boxes are a bit faster in calculating
    	  child sizes.
    	* mousepad/mousepad-window.c: Remove unused variable.
    
    (Old svn revision: 26406)

commit debc440d2c428b5aa91dcb567fd96a4f50a2804c
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Nov 29 18:00:22 2007 +0000

    	* mousepad/mousepad-print.c: Use bold attribute for labels, so there
    	  is no html in the strings.
    
    (Old svn revision: 26405)

commit f3a364cda15d48093802adbb4190a1d027e6a102
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Nov 29 16:38:43 2007 +0000

    	* mousepad/mousepad-utils.c: Add functions that extent the default
    	  Gtk word start/end function. Use them in the search functions,
    	  transpose and double click selection.
    	* mousepad/mousepad-view.c: Implement transpose for multi selections.
    	* mousepad/mousepad-view.c: Improve word swap function.
    	* docs/manual/C/Mousepad.xml.in: Other layout of the help file. Content
    	  will follow.
    	* mousepad/mousepad-{document,window,view}.c: Show the selection length
    	  in the statusbar. Also merged two signals and a couple of functions.
    	* mousepad/mousepad-window.c: Change default keybinding of new document
    	  (Ctrl+N) and new window (Shift+Ctrl+N). Assign Ctrl+T to transpose.
    	* mousepad/mousepad-window.c: Update the window title after saving a
    	  file with a new name.
    	* mousepad/mousepad-file.c: Set readonly to FALSE when starting with
    	  a non-existing filename in the argument.
    	* mousepad/mousepad-print.c: Improve the print backend. Settings are
    	  now saved. You can set the paper type, toggle options for line
    	  numbers, wrap and page heading and use a custom font.
    
    (Old svn revision: 26404)

commit 03cd4c266c5d539c85dbe22f505d1d54c1b011b4
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Oct 26 15:02:40 2007 +0000

    	* mousepad/mousepad-view.c: Implement transpose:
    	   - Selection on one line: Inverse selected text.
    	   - Multiple lines selected: Invert seleted lines.
    	   - Cursor is inside a word: Swap chars on each side of the cursor.
    	   - Cursor is outside a word: Swap word left and right of the cursor.
    	   - Cursor at the start of a line: Swap line with the line above.
    	   - Cursor at the end of a line: Swap line with the line below.
    	Will add support for multi- and column-selections later. Thanks to
    	Textmate for this great idea.
    
    (Old svn revision: 26200)

commit ec4cae752aa01e235b870df476b0c3008cb24f4d
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Oct 26 08:43:19 2007 +0000

    	* MousepadHelp.in, mousepad/mousepad-{dialogs,window}.{c,h}:
    	  Add support for the help file.
    	* Mousepad.spec.in: Add spec file.
    
    (Old svn revision: 26199)

commit 673f739167aa23710a7b570eb7e863871fd09e4d
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Oct 25 20:46:06 2007 +0000

    	* mousepad/mousepad-view.c: Redraw selection on theme change.
    
    (Old svn revision: 26197)

commit 24c163061c3e40620db488f98c51f1edd8d20f62
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Oct 25 17:51:07 2007 +0000

    	* mousepad/mousepad-view.c: Reimplemented multi-selection. It is also
    	  possible to do multi editing (typing in all the selections), select
    	  random words in the document (they will be copied to the clipboard as
    	  a list of words) and multi insert (create a drag without content or
    	  drag at the end of lines). Multiple selection will also be merged
    	  when possible. This proably has some rough edges, but it works pretty
    	  good. Keyboard multi drags will be added later.
    	* docs/manual/C/Mousepad.xml.in: Add a bit of info about multiple- and
    	  column-selections, but I'm not very good at this.
    	* mousepad/mousepad-{window.c,window-ui.xml}: Use our edit menu on right
    	  click, so copy/paste/delete works with multi selections. Also saves a
    	  bit of code since it integrates with the ui-manager.
    
    (Old svn revision: 26195)

commit 2d4c6469fc7680fe83c02af5ecfd4791f96de79f
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Oct 23 08:57:10 2007 +0000

    * configure.in.in, po/POTFILES.in: Fix dist-check. Thank to Brian
      for the hint.
    * mousepad/mousepad-{dialogs,window}.c: Implement tab size menu. You
      can set the default tab sizes in the rc file (MiscDefaultTabSizes).
    * mousepad/mousepad-window{-ui.xml,.c}: Reorder menus a bit. Go menu
      is now called 'Navigation' and the 'go to line' item is added to this
      menu. The document menu contains the tab size menu from now on.
    * Rename some functions and vars to more suitable names.
    
    
    (Old svn revision: 26178)

commit 0960eed1341ae9789caafcb61500fa2006a12a67
Author: Nick Schermer <nick at xfce.org>
Date:   Mon Oct 22 11:16:59 2007 +0000

    	* configure.in.in: Make sure __OPTIMIZE__ is enable in normal builds.
    	* mousepad/mousepad-private.h: Tune G_LIKELY macros for pure boolean.
    
    (Old svn revision: 26175)

commit 765cea4b137c29bbb1abebad9440a4a9534c93d7
Author: Nick Schermer <nick at xfce.org>
Date:   Mon Oct 22 09:18:55 2007 +0000

    	* mousepad/mousepad-window.c: Idea of the previous commit was good,
    	  but the implementation wasn't. Fix that.
    
    (Old svn revision: 26174)

commit 02326c575f8bc002d5a9680c1bb9b2d4b474125d
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Oct 21 19:08:51 2007 +0000

    	* mousepad/mousepad-window.c: Make the recent manager a singleton
    	  in the application, this is also done in gtk 2.12. We also
    	  initialize the recent manager when needed, since it's quite
    	  expensive to create one. This should improve the startup speed
    	  a bit.
    
    (Old svn revision: 26173)

commit c68eede22f8717c245154f83dab5b6569fc45d13
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Oct 21 15:17:17 2007 +0000

    	* docs/: Import basic manual files.
    	* configure.in.in, mousepad/Makefile.am: Don't search for startup-
    	  notification and gtk-unix-print. We don't use this in the code.
    
    (Old svn revision: 26172)

commit 1f30cae6c6774f25728d5c7254e772281762abd6
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Oct 18 09:47:52 2007 +0000

    * mousepad/mousepad-view.c: Respect input methods and don't insert
      text when the textview is not editable.
    * mousepad/mousepad-{file,document,window}.c: Properly handle
      read-only files. A file is now always readonly unless proven
      otherwise.
    
    
    (Old svn revision: 26145)

commit b01842db991e385a4a2373da1eaac1191197d9af
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Oct 18 09:04:31 2007 +0000

    * mousepad/mousepad-utils.{c,h}: Add iter function to move the iter
      in front of text. Code used from one of the indentation functions.
    * mousepad/mousepad-view.c: Add code for a smart home button: when
      the cursor starts a line and the home button is pressed, it will
      move to the start of the text.
    * mousepad/mousepad-view.c: Key bindings Ctrl + {Home,End} to jump
      to the start and end of a document.
    
    
    (Old svn revision: 26144)

commit a75d9920d838e508c10dfd17908233d45dc20e6c
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Oct 17 18:53:22 2007 +0000

    * mousepad/mousepad-window.c: Cleanup some code and get rid of the
      multiple action groups.
    
    
    (Old svn revision: 26142)

commit 2d17e63c32d75fb9fb7f98e8660b4980ec24af7d
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Oct 17 11:02:46 2007 +0000

    * mousepad/mousepad-window.c: Decrease the menu lock when a window
      is closed and disconnect the recent manager handler (this is a
      bug since 2.12 because the manager is a floating object).
    
    
    (Old svn revision: 26141)

commit 8a4f2f2e71d3fa064295bbbe0ca4697e562878f3
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Oct 17 09:48:30 2007 +0000

    * mousepad/mousepad-{window,util}.c: Fix compiler warnings.
    
    
    (Old svn revision: 26140)

commit 73fe06eded04e6c604a49caf443cf3cc7d22ddbf
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Oct 16 20:06:10 2007 +0000

    * Previous commit was a typo.
    
    
    (Old svn revision: 26136)

commit 0c494023ae1504211afbba57c9c469e4955426dc
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Oct 16 20:03:00 2007 +0000

    * Set Id property on files.
    
    
    (Old svn revision: 26135)

commit d1196e9f4486f9a5d4610fb88a1076a5e8d476a5
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Oct 16 20:01:37 2007 +0000

    * Diffstat:
      38 files changed, 5987 insertions(+), 3632 deletions(-)
    
    * mousepad/mousepad-dialogs.c: Set the correct default return
      in the jump dialog.
    * mousepad/mousepad-replace-{dialog,window,preferences}.{c,h}:
      Implement the new replace dialog.
    * Remove options from the type-ahead bar, it was too bloated
      and those options are now available in the replace dialog.
    * mousepad/mousepad-document.c: The MousepadDocument now holds
      utf-8 valid names, the MousepadFile the real filename.
    * mousepad/mousepad-window.c: Full tab dnd (detach) with
      Gtk+ 2.12.
    * mousepad/mousepad-encoding-dialog.{c,h}: Add a encoding dialog.
      This dialog should help users to find the right encoding for a
      document.
    * mousepad/mousepad-print.{c,h}: Initial version of a basic
      printing support. Needs some big improvement tho.
    * mousepad/mousepad-statusbar: Fix issues with some theme engines
      that paint a line above the statusbar (instead of a frame).
    * mousepad/mousepad-window.c: A window is now destoyed when it
      contains no tabs, previously this caused some segfaults with the
      tab dnd code, but this is all fixed now.
    * mousepad/mousepad-preferences.c: The option names are now stored
      in the nick name of the pspec. With debug build this name is
      compared with the option name from spec name to check for typos.
    * mousepad/mousepad-view.c: Options for 'insert tab as spaces' and
      settings the tab size. This also needed a rewrite of the
      indentation code, which ended up much cleaner.
    * mousepad/mousepad-view.c: Big speed improvements in the vertical
      selction code.
    * mousepad/mousepad-view.c: Cleanups in the clipboard code and move
      code from mousepad-document to mousepad-view.
    * mousepad/mousepad-{window,search-bar}.c: Handle clipboard actions
      properly when the search bar is focused.
    * A lot of code cleanups, bug fixes, polishing and stuff I can't
      remember after 5 months ;).
    
    
    (Old svn revision: 26134)

commit 772eeca118e48c94c5fe908c333197b3b6b8845e
Author: Nick Schermer <nick at xfce.org>
Date:   Tue May 22 19:50:01 2007 +0000

    	* *.*: Remove copyright lines.
    
    (Old svn revision: 25747)

commit c0bf115da5b4dd9ca9be101014e41565ffdeae1c
Author: Nick Schermer <nick at xfce.org>
Date:   Sun May 20 18:44:10 2007 +0000

    	* mousepad/mousepad-{preferences,search-bar,document}.c,
    	  mousepad/mousepad-types.h: Add match whole word option.
    
    (Old svn revision: 25736)

commit 0f9ccf029632a9bb61f393243c1153fb58dd5793
Author: Nick Schermer <nick at xfce.org>
Date:   Sun May 20 12:13:07 2007 +0000

    	* mousepad/Makefile.am: Use the new exo-csource
    	  --strip-comments and --strip-content arguments.
    
    (Old svn revision: 25729)

commit b408c7b5f735db6c91e3381953e6c5cfca967901
Author: Nick Schermer <nick at xfce.org>
Date:   Sun May 20 09:58:48 2007 +0000

    	* mousepad/mousepad-view.c: Initialize variables, so gcc is
    	  happy.
    	* README: Add some lines.
    	* mousepad/mousepad-window.c: Ctrl + Shift + v is the shortcut
    	  to paste in a column.
    
    (Old svn revision: 25726)

commit 924ec4cfdac8ef8ad541d643f9789836bb3bd86c
Author: Nick Schermer <nick at xfce.org>
Date:   Thu May 17 20:00:53 2007 +0000

    	* mousepad/mousepad-view.c: Cleanup the line number code.
    	  This version is a bit faster and removed a bunch of code.
    	* mousepad/mousepad-view.c: Cleanup the indentation code. You
    	  can also increase the (vertical) selected text with Shift +
    	  Space and decrease with Shift + Backspace. I though this
    	  might be useful for developers.
    	* mousepad/mousepad-view.c: Vertical selection using the mouse
    	  and Ctrl + Shift. Keyboard vertical selection is not possible
    	  because that adds too much code for (hardly) nothing. You can
    	  (un-)indent the block with Tab, Shift + Tab and the 2 new
    	  space (in/de)crease commands above.
    	* mousepad/mousepad-view.c: Draw a vertical line to separate
    	  the line numbers from the text, this looks beter with light
    	  themes (IMHO).
    	* mousepad/mousepad-window.c: Add 'paste column' option to
    	  paste the clipboard text in a column under the cursor.
    	* mousepad/mousepad-window.c: Set stock menu names to NULL so
    	  Gtk fills the default (translated) name,  makes your binary
    	  smaller and translators happy.
    	* mousepad/mousepad-{search-bar,document}.c: Fix segfault with
    	  empty string in the search bar and highlighting enabled.
    	* TODO: Add items.
    
    (Old svn revision: 25720)

commit 4abd78f00bd8306fd7a8028875cb9050b62df53e
Author: Nick Schermer <nick at xfce.org>
Date:   Sat May 12 16:38:47 2007 +0000

    	* mousepad/mousepad-window.c: Add extra tests if the file
    	  really exists, because Gtk file dialogs hang if the
    	  file does not exists.
    
    (Old svn revision: 25708)

commit d2c3c1f88384b617269bcd129f6cce6a86b5efa2
Author: Nick Schermer <nick at xfce.org>
Date:   Sat May 12 15:41:04 2007 +0000

    	* mousepad/mousepad-window.c: Jump to active file when
    	  opening a new document.
    
    (Old svn revision: 25707)

commit 23c7b01c285078e6346e1b65afcb611273ce3c2f
Author: Nick Schermer <nick at xfce.org>
Date:   Thu May 10 16:13:39 2007 +0000

    	* mousepad/mousepad-undo.c: Don't store a string (or even
    	  prepend it in a GString) when the user is inserting text.
    	  This saves a whole bunch of relocations (Bug #2737). We also
    	  flush the insert buffer after a redo and don't copy strings
    	  when inverting a delete step. This should bring the memory
    	  usage of the undo manager to a minimum.
    	* TODO: Add some undo manager reminders.
    	* mousepad/mousepad-window.c: Fix compiler warning when
    	  debugging is enabled.
    	* mousepad/mousepad-application.c: Change from append to
    	  prepend.
    
    (Old svn revision: 25700)

commit a4f297b08aa19d2aa06c969d821af3590a231a2a
Author: Nick Schermer <nick at xfce.org>
Date:   Tue May 8 17:17:37 2007 +0000

    	* mousepad/mousepad-window.c: Rename function so it matches
    	  the standard mousepad_window_* names.
    
    (Old svn revision: 25688)

commit 9fbd9fdc5d6123223d4ffe75a3407f44425c9548
Author: Nick Schermer <nick at xfce.org>
Date:   Tue May 8 17:14:34 2007 +0000

    	* mousepad/mousepad-window.c: Open a new tab when the notebook
    	  is double clicked. Also fix some indentation.
    
    (Old svn revision: 25687)

commit 932f662654e9f024422e8fd806a8b9b90cc6149a
Author: Nick Schermer <nick at xfce.org>
Date:   Tue May 1 21:16:15 2007 +0000

    	* configure.in.in: Don't break on a broken glibc.
    
    (Old svn revision: 25664)

commit 5cd70d2665de061f5c64d6a7a21b5f564eeec813
Author: Nick Schermer <nick at xfce.org>
Date:   Tue May 1 16:07:57 2007 +0000

    	* mousepad/mousepad-dbus-infos.xml, mousepad/mousepad-undo.c,
    	  mousepad/mousepad-view.c: Fix some typos and replace tabs.
    
    (Old svn revision: 25662)

commit 72d49ecc7196fe7c8d5479e978593718e3b17a39
Author: Nick Schermer <nick at xfce.org>
Date:   Tue May 1 15:59:28 2007 +0000

    	* mousepad/mousepad-{document,window}.c: Allow uri and tab
    	  drops inside the textview widget.
    	* mousepad/mousepad-window.c: Hide the searchbar when all the
    	  tabs are closed and make sure nothing segfaults when no
    	  active document is found.
    	* mousepad/mousepad-window.c: Make sure the textview is
    	  focused when a new document has been added.
    
    (Old svn revision: 25661)

commit 2beb0bf4ad103e2bc112b516f6253157e821e2a7
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Apr 28 18:59:18 2007 +0000

    * TODO: Removed the items I've fixed.
    * Changelog: Break after 70 characters.
    * mousepad/mousepad-{document,statusbar}.c: Hide the visible
      event box window.
    * mousepad/mousepad-statusbar: The statusbar is now on top of
      the Gtk statusbar.
    * mousepad/mousepad-window.c: Add support for dropping uris
      in the main window. Droping in the textview doesn't work
      yet.
    * mousepad/mousepad-window.c: Add tab dnd. This required some
      function reordering, but in the end it was quite easy and
      made the code more logical. I've also changed the window
      behaviour: when you close all the tabs in a window, an empty
      window is left. This is easier for tab dnd.
    * mousepad/mousepad-{application,window}.c: Beter handing of
      application windows. Also added detachable tabs.
    * mousepad/mousepad-{properties,window}.c: The last settings
      of line numbers and auto indent are now stored.
    * mousepad/mousepad-window.c: Beter locking of menu updates,
      this avoids some unneeded menu updates and also made the
      start time of Mousepad equal to Leafpad (and probably also
      Mosuepad 0.2.x), which is quite nice since it supports a
      whole bunch of extra features.
    * mousepad/mousepad-window.c: Removed the 'close all windows'
      option from the menu and the code. Not need for a text
      editor IMHO.
    
    
    (Old svn revision: 25654)

commit a20de9eada02c7cc07cda472ea4f197c3e3b97aa
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Apr 22 08:23:48 2007 +0000

    	* TODO: Fix some typos and add some new ideas and reminders.
    
    (Old svn revision: 25622)

commit 35f0b25ab3c544412ef32b71e4a8dd514142c281
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Apr 21 19:18:52 2007 +0000

    	* TODO: Add some stuff.
    
    (Old svn revision: 25621)

commit 666a0aebba2bca3fbeee5a650fe9ffa160455348
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Apr 20 10:55:16 2007 +0000

    	* TODO, NEWS: Update and expand both documents.
    	* mousepad/mousepad-search-bar.c, mousepad-window.c: Fix some
    	  compiler warnings.
    
    (Old svn revision: 25615)

commit a47b71f49c5221348b83135ffbcf2a05abdebeb4
Author: Erik Harrison <erikharrison at gmail.com>
Date:   Wed Apr 18 23:45:20 2007 +0000

    Little compiler fix
    
    
    (Old svn revision: 25600)

commit 44f28f94cfd8b18c76852726550c2fc476fb4801
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Apr 12 19:38:59 2007 +0000

    	* mousepad/mousepad-undo.c: Improve the behavior of the undo manager.
    	  It now merges multiple spaces, new lines are a separate undo action and
    	  when you redo some steps and then start editing again we append the redo-ed
    	  steps in reversed order with an inverted action, so you can undo every thing
    	  afterwards. This consumes a bit more memory compared to the old behavior
    	  (which simply removed every redo-ed step), but it's much more consistent.
    
    (Old svn revision: 25531)

commit 0210f46f4a9e604a52bda681c820e66d352303e5
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Apr 11 17:41:54 2007 +0000

    	* mousepad/mousepad-{window,view}.c: Fix some potential leaks, I'm not
    	  really sure, but it doesn't hurt...
    
    (Old svn revision: 25523)

commit d45ae8eaa022bd99c25c0db5e68594e12b25281d
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Apr 11 09:07:54 2007 +0000

    	* mousepad/mousepad-statusbar.c: Destroy the tool items together with the
    	  searchbar (memory leak from valgrind).
    
    (Old svn revision: 25516)

commit ec1234c58d36457576ea554ac2fd5885da962fd7
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Apr 11 08:22:46 2007 +0000

    	* mousepad/mousepad-{document,window,statusbar}: You can now click the OVR
    	  text in the statusbar to toggle the overwrite mode.
    	* mousepad/mousepad-{document,window,undo}: Initial version of an undo
    	  manager. This is not finished yet, but it's a start.
    	* mousepad/Makefile.am, mousepad/mousepad-csource.pl: Remove my perl script
    	  because it has some problems. Use exo-csource instead.
    	* Remove some empty object functions.
    
    (Old svn revision: 25514)

commit fe666120450ea8df11059d60c0bcdb806d3d5426
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Apr 6 19:06:59 2007 +0000

    	* mousepad/mousepad-document.c: Fix segfault from previous commit.
    	* mousepad/mousepad-document.c: Fix bug in searching backwards, we have to
    	  jump one iter backwards before searching, because we start with the
    	  character right from the first iter. Also removed the equal check because
    	  it's not needed and only causing problems with backwards searching on the
    	  first character in the buffer.
    
    (Old svn revision: 25405)

commit 7b33a930bf6efc2c879dbb304e6ee0fd4adb2b5a
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Apr 6 16:36:12 2007 +0000

    	* mousepad/mousepad-window.c: Fix opening recent files that do not exist.
    	* mousepad/mousepad-window.c, mousepad/mousepad-document.c: Update the window
    	  title correctly and remove the unused notify::title signals.
    
    (Old svn revision: 25404)

commit 46e78d17d7e5fc5ae16f9e9ee6ae8103e683af53
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Apr 6 13:57:06 2007 +0000

    	* mousepad/mousepad-document.c: Because we don't use invisible characters in
    	  the text buffer, I was able to write a custom iter search function that can
    	  search in both directions, can be case insensitive, no string duplications
    	  and above all: is over 10x faster then the gtk version. This gives a nice
    	  performance boost to the highlight function.
    	* mousepad/mousepad-search-bar.c: Connected the last signals and added a
    	  wrap around option to the search bar.
    
    (Old svn revision: 25402)

commit 4ccd1ba30c425214156b07cf6e58b001fa8970d9
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Apr 5 11:34:07 2007 +0000

    	* mousepad/mousepad-document.c: Remove unused properties.
    	* mousepad/mousepad-{exo,window,preoperties,search-bar}: Remove the
    	  exo bindings, mousepad only depends on Gtk and libxfce4util.
    	* mousepad/mousepad-csource.pl: Perl script to generate the menu code.
    	  This script also strips the code between the xml blocks, so a minimal
    	  amount of text is added to the binary (ie. it produces better code then
    	  exo-csource).
    
    (Old svn revision: 25385)

commit 2563fc285fb1b58ee9c7984b9a710b5668ef3c10
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Apr 4 18:42:18 2007 +0000

    	* po/: Update the POTFILES.in file and regenerate the pot file.
    	* mousepad/mousepad-document.c: Make the scroll offset smaller, so the
    	  textview doesn't jump around while searching.
    	* mousepad/mousepad-search-bar.c: Make sure the search signal is send
    	  when the search field is empty after a backspace, so no text is selected in
    	  the buffer.
    	* Remove some leftover tabs.
    	* mousepad/mousepad-{search-bar,document,window).*: Added function for
    	* Various performance improvements and code cleanups.
    
    (Old svn revision: 25382)

commit a0b89f341abe283462ad6f5c476b9d37ee644774
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Apr 4 15:50:00 2007 +0000

    	* configure.in.in: Mousepad does not depend on exo anymore. Only
    	  when you run in maintainer-mode, exo-csource is required.
    	* mousepad/mousepad-document.*: Renamed mousepad-screen to mousepad-document.
    	* mousepad/mousepad-{search-bar,document,window).*: Added function for
    	  searching, including the type-ahead search bar.
    	* mousepad/mousepad-statusbar.*: A custom statusbar suitable for displaying
    	  the tooltips, overwrite/insert and the line- and column-number.
    	* mousepad/mousepad-exo.*: The exo-bindings so we don't depend on exo anymore,
    	  although I want to get rid of all of them.
    	* mousepad/mousepad-marshal.list: Custom marshal for sending search signals.
    	* mousepad/mousepad-types.h: Search types (a mousepad-enum-types.{c,h} is
    	  generated during build).
    	* Various performance inprovements and code cleanups.
    
    
    (Old svn revision: 25379)

commit cab0d1a984369283d99376e364e216e7fff04bc3
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Mar 3 13:26:35 2007 +0000

    	* mousepad/mousepad-dialogs.{c,h}: Add response actions for Mousepad so it's
    	  easier to understand what happens.
    	* mousepad/mousepad-window.c, * mousepad/mousepad-screen.{c,h}: Basic
    	  support for document reloading.
    
    (Old svn revision: 25072)

commit 8a1670c4888db706b49b21c32d78786bf9ed2780
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Mar 3 12:11:20 2007 +0000

    	* configure.in.in, mousepad/Makefile.am: Remove the PCRE dependency.
    	  I should have removed this earier after some testing.
    
    (Old svn revision: 25070)

commit b5178ab96dc4dd424f9ce884529a67e95731e145
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Mar 3 12:07:46 2007 +0000

    	* mousepad/mousepad-dialogs.{c,h}: New file for the dialogs
    	  so the mousepad-window file becomes more readable.
    	* mousepad/mousepad-window.c: Split some function and reorder
    	  them a bit.
    	* mousepad/mousepad-window.c: The items in the go menu now have
    	  the filename as statusbar tooltip.
    	* mousepad/mousepad-window.c: Check if the file is externally modified
    	  before writing. If it is, ask the user what to do.
    	* mousepad/main.c, mousepad/mousepad-dbus.{c,h},
    	  mousepad/mousepad-dbus-infos.xml: Support for terminating a running
    	  mousepad instance (that is connected to dbus), using mousepad -q.
    	* mousepad/*: Add function destriptions for Erik (and others) :-).
    
    (Old svn revision: 25069)

commit 5263c479394dbb5a6bc0b892806f11a629bd81f4
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Feb 28 22:45:19 2007 +0000

    	* mousepad/mousepad-window.c: Improve the menu tooltips.
    
    (Old svn revision: 25045)

commit 64c5d0349576fb0c55f7f9df7e985437c0fe8aea
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Feb 28 19:16:13 2007 +0000

    	* mousepad/mousepad-window.c: Prevent multiple recent- and go-menu
    	  updates when multiple items are opened or the recent history is
    	  cleared.
    
    (Old svn revision: 25044)

commit f0dc6b97b9512e8121ad3b253562d13f5baca205
Author: Nick Schermer <nick at xfce.org>
Date:   Wed Feb 28 18:14:25 2007 +0000

    	* TODO, mousepad/mousepad-window.c: Add option to the recent menu
    	  to clear the history.
    	* mousepad/mousepad-window.c: The recent items are now in the Mousepad
    	  group so it's easier to filter them when removing. The list is also
    	  sorted by the most recently used item.
    	* mousepad/mousepad-window.c: Fix problem in checking if the
    	  file was already openened.
    	* mousepad/mousepad-window.c: You can now reorder tabs.
    	* mousepad/mousepad-window.c: A tab is now inserted right from the
    	  current active tab.
    	* mousepad/mousepad-screen.c: Untitled documents now have a number like
    	  "Untitled #". The number is increased as long as the application is running.
    	* mousepad/mousepad-window.c: Added first parts of code for a statusbar.
    
    (Old svn revision: 25043)

commit ff28ae1045a381c7dc815906b9a0816b87451e2b
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Feb 27 21:28:04 2007 +0000

    	* TODO: Remind myself to fix problems with UTF-8 filenames.
    	* mousepad/mousepad-window.c: Fix crash when opening files
    	  with the command line.
    	* Mousepad.desktop.in.in, Mousepad.desktop.in.in: Mousepad executable
    	  is now lowercase again.
    	* mousepad/mousepad-screen.c: Remove unused signals from the Class.
    
    (Old svn revision: 25040)

commit 62dbff28f0cd78e96933a78c979ef3109a5a43ba
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Feb 27 17:20:46 2007 +0000

    	* TODO, NEWS: Update the current status of the rewrite.
    	* Mousepad.desktop.in.in: Add MimeType and improve Categories.
    	* Initial import of my Mousepad rewrite.
    
    (Old svn revision: 25037)

commit 8a402ec2206b15649d4bc1a50621d3a52f11dd2b
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Feb 27 17:02:14 2007 +0000

    * Import my Mousepad rewrite
    
    
    (Old svn revision: 25036)

commit 1bd002d711d108435b12b0cf7aa694b908cd63ed
Author: Jean-François Wauthy <pollux at xfce.org>
Date:   Tue Feb 27 16:53:45 2007 +0000

    for nick
    
    (Old svn revision: 25035)

 .gitignore                                  |   37 +
 AUTHORS-pre-0.3.0 => AUTHORS                |    3 +-
 COPYING                                     |  340 ++
 INSTALL                                     |  231 ++
 Makefile.am                                 |   63 +
 Mousepad.desktop.in.in                      |   13 +
 Mousepad.spec.in                            |   49 +
 MousepadHelp.in                             |   95 +
 NEWS                                        |   42 +
 README                                      |   45 +
 TODO                                        |   43 +
 autogen.sh                                  |   15 +
 configure.ac.in                             |  156 +
 docs/Makefile.am                            |    4 +
 docs/manual/C/Makefile.am                   |   66 +
 docs/manual/C/Mousepad.xml.in               |  478 +++
 docs/manual/C/images/Makefile.am            |   15 +
 docs/manual/C/images/find-and-replace.png   |  Bin 0 -> 20777 bytes
 docs/manual/C/images/go-to.png              |  Bin 0 -> 9507 bytes
 docs/manual/C/images/main-window.png        |  Bin 0 -> 13955 bytes
 docs/manual/C/images/other-tab-size.png     |  Bin 0 -> 8168 bytes
 docs/manual/C/images/paste-from-history.png |  Bin 0 -> 9495 bytes
 docs/manual/C/images/tab-size-menu.png      |  Bin 0 -> 9130 bytes
 docs/manual/C/images/typeahead-search.png   |  Bin 0 -> 6724 bytes
 docs/manual/Makefile.am                     |   12 +
 docs/manual/mousepad.css                    |   99 +
 docs/manual/mousepad.xsl                    |  254 ++
 icons/16x16/Makefile.am                     |   13 +
 icons/16x16/Mousepad.png                    |  Bin 0 -> 574 bytes
 icons/24x24/Makefile.am                     |   13 +
 icons/24x24/Mousepad.png                    |  Bin 0 -> 972 bytes
 icons/Makefile.am                           |   19 +
 icons/scalable/Makefile.am                  |   13 +
 icons/scalable/Mousepad.svg                 |  552 +++
 mousepad/Makefile.am                        |  118 +
 mousepad/main.c                             |  202 ++
 mousepad/mousepad-application.c             |  299 ++
 mousepad/mousepad-application.h             |   48 +
 mousepad/mousepad-dbus-infos.xml            |   55 +
 mousepad/mousepad-dbus.c                    |  337 ++
 mousepad/mousepad-dbus.h                    |   40 +
 mousepad/mousepad-dialogs.c                 |  453 +++
 mousepad/mousepad-dialogs.h                 |   69 +
 mousepad/mousepad-document.c                |  649 ++++
 mousepad/mousepad-document.h                |   86 +
 mousepad/mousepad-encoding-dialog.c         |  517 +++
 mousepad/mousepad-encoding-dialog.h         |   45 +
 mousepad/mousepad-encoding.c                |  201 ++
 mousepad/mousepad-encoding.h                |  125 +
 mousepad/mousepad-file.c                    |  919 +++++
 mousepad/mousepad-file.h                    |   97 +
 mousepad/mousepad-marshal.list              |    3 +
 mousepad/mousepad-preferences.c             |  652 ++++
 mousepad/mousepad-preferences.h             |   38 +
 mousepad/mousepad-print.c                   |  805 +++++
 mousepad/mousepad-print.h                   |   43 +
 mousepad/mousepad-private.h                 |  126 +
 mousepad/mousepad-replace-dialog.c          |  653 ++++
 mousepad/mousepad-replace-dialog.h          |   42 +
 mousepad/mousepad-search-bar.c              |  536 +++
 mousepad/mousepad-search-bar.h              |   46 +
 mousepad/mousepad-statusbar.c               |  300 ++
 mousepad/mousepad-statusbar.h               |   49 +
 mousepad/mousepad-util.c                    | 1206 +++++++
 mousepad/mousepad-util.h                    |  138 +
 mousepad/mousepad-view.c                    | 2402 +++++++++++++
 mousepad/mousepad-view.h                    |  121 +
 mousepad/mousepad-window-ui.xml             |  159 +
 mousepad/mousepad-window.c                  | 5102 +++++++++++++++++++++++++++
 mousepad/mousepad-window.h                  |   59 +
 po/POTFILES.in                              |   27 +
 71 files changed, 19436 insertions(+), 1 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3e3e61d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+*.o
+Makefile
+Makefile.in
+Makefile.in.in
+Mousepad.desktop
+MousepadHelp
+aclocal.m4
+autom4te.cache/
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+configure.ac
+depcomp
+docs/manual/C/Mousepad.xml
+install-sh
+intltool-extract.in
+intltool-merge.in
+intltool-update.in
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+mousepad/.deps/
+mousepad/mousepad
+mousepad/mousepad-dbus-infos.h
+mousepad/mousepad-marshal.c
+mousepad/mousepad-marshal.h
+mousepad/mousepad-window-ui.h
+po/.intltool-merge-cache
+po/POTFILES
+po/stamp-it
+stamp-h1
diff --git a/AUTHORS-pre-0.3.0 b/AUTHORS
similarity index 54%
copy from AUTHORS-pre-0.3.0
copy to AUTHORS
index 1c0188e..fefc28d 100644
--- a/AUTHORS-pre-0.3.0
+++ b/AUTHORS
@@ -1,3 +1,4 @@
 Erik Harrison <erikharrison at xfce.org>
+Nick Schermer <nick at xfce.org>
 Benedikt Meurer <benny at xfce.org>
-Tarot Osuji <tarot at sdf.lonestar.org>
+Matthew Brush <matt at xfce.org>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..095b1eb
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,231 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PREFIX', the package will
+use PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..25a1d67
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,63 @@
+SUBDIRS =									\
+	icons									\
+	mousepad                                                        	\
+	po                                                                      \
+	docs
+
+distclean-local:
+	rm -rf *.spec *.cache *~
+
+rpm: dist
+	rpmbuild -ta $(PACKAGE)-$(VERSION).tar.gz
+	@rm -f $(PACKAGE)-$(VERSION).tar.gz
+
+mousepad_scriptsdir = $(libdir)/xfce4/mousepad
+mousepad_scripts_SCRIPTS =							\
+	MousepadHelp
+
+MousepadHelp: MousepadHelp.in Makefile
+	rm -f MousepadHelp.gen MousepadHelp
+	sed -e "s,\@datadir\@,$(datadir),g" 					\
+		< $(srcdir)/MousepadHelp.in					\
+		> MousepadHelp.gen
+	mv MousepadHelp.gen MousepadHelp
+
+desktopdir = $(datadir)/applications
+desktop_in_in_files = 								\
+	Mousepad.desktop.in.in
+desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in)
+%.desktop.in: %.desktop.in.in
+	sed -e "s,\@libexecdir\@,$(libexecdir),g" < $< > $@
+desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
+ at INTLTOOL_DESKTOP_RULE@
+
+.PHONY: ChangeLog
+
+ChangeLog: Makefile
+	(GIT_DIR=$(top_srcdir)/.git git log > .changelog.tmp			\
+	&& mv .changelog.tmp ChangeLog; rm -f .changelog.tmp)			\
+	|| (touch ChangeLog; echo 'Git directory not found: installing possibly empty changelog.' >&2)
+
+dist-hook: ChangeLog
+
+EXTRA_DIST =									\
+	MousepadHelp.in								\
+	Mousepad.spec.in							\
+	intltool-extract.in							\
+	intltool-merge.in							\
+	intltool-update.in							\
+	$(desktop_in_in_files)
+
+DISTCLEANFILES =								\
+	MousepadHelp								\
+	Mousepad.spec								\
+	intltool-extract							\
+	intltool-merge								\
+	intltool-update								\
+	$(desktop_in_files)							\
+	$(desktop_DATA)
+
+DISTCHECK_CONFIGURE_FLAGS =							\
+	--enable-xsltproc
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/Mousepad.desktop.in.in b/Mousepad.desktop.in.in
new file mode 100644
index 0000000..21fda29
--- /dev/null
+++ b/Mousepad.desktop.in.in
@@ -0,0 +1,13 @@
+
+[Desktop Entry]
+Encoding=UTF-8
+_Name=Mousepad
+_Comment=Simple Text Editor
+_GenericName=Text Editor
+Exec=mousepad %F
+Icon=accessories-text-editor
+Terminal=false
+StartupNotify=true
+Type=Application
+Categories=Application;Utility;TextEditor;GTK;
+MimeType=text/plain
diff --git a/Mousepad.spec.in b/Mousepad.spec.in
new file mode 100644
index 0000000..6261c2c
--- /dev/null
+++ b/Mousepad.spec.in
@@ -0,0 +1,49 @@
+Summary:	Mousepad Text Editor
+Name:		@PACKAGE_TARNAME@
+Version:	@PACKAGE_VERSION@
+Release:	1
+License:	GPL
+URL:		http://www.xfce.org/
+Source0:	%{name}-%{version}.tar.gz
+Group:		Applications/X11
+BuildRoot:	%{_tmppath}/%{name}-root
+Requires:	gtk2 >= @GTK_REQUIRED_VERSION@
+BuildRequires:	gtk2-devel >= @GTK_REQUIRED_VERSION@
+
+%description
+Mousepad is a simple text editor for the Xfce Desktop Environment.
+
+%prep
+%setup -q
+
+%build
+%configure --enable-dbus --enable-final --enable-xsltproc
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+update-desktop-database &> /dev/null ||:
+touch --no-create %{_datadir}/icons/hicolor || :
+if [ -x %{_bindir}/gtk-update-icon-cache ]; then
+   %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
+fi
+
+%postun
+update-desktop-database &> /dev/null ||:
+touch --no-create %{_datadir}/icons/hicolor || :
+if [ -x %{_bindir}/gtk-update-icon-cache ]; then
+   %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
+fi
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS ChangeLog COPYING INSTALL NEWS README THANKS TODO
+%{_bindir}/
+%{_datadir}/
+%{_libexecdir}/
diff --git a/MousepadHelp.in b/MousepadHelp.in
new file mode 100644
index 0000000..bde651f
--- /dev/null
+++ b/MousepadHelp.in
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# Copyright (c) 2004-2006 Benedikt Meurer <benny at xfce.org>
+# Copyright (c) 2007      Nick Schermer <nick at xfce.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+HELPDIR="@datadir@/doc/Mousepad/html"
+APPLICATIONS="exo-open firefox epiphany opera galeon mozilla konqueror dillo"
+
+# try to find a language
+if test -n "$LC_ALL"; then
+  LC=$LC_ALL
+elif test -n "$LANG"; then
+  LC=$LANG
+else
+  LC="C"
+fi
+
+# set the document or use index.html
+if test -n "$1"; then
+  HELPFILE="$1.html"
+else
+  HELPFILE="index.html"
+fi
+
+# test if the file exists, fallback on the C language or the C/index.html file
+if test -r "$HELPDIR/$LC/$HELPFILE"; then
+  URL="file://$HELPDIR/$LC/$HELPFILE"
+elif test -r "$HELPDIR/`echo $LC | sed 's/\(..\)_.*/\1/'`/$HELPFILE"; then
+  URL="file://$HELPDIR/`echo $LC | sed 's/\(..\)_.*/\1/'`/$HELPFILE"
+else
+  URL="file://$HELPDIR/C/index.html"
+fi
+
+# jump to a section if provided
+[ -n "$2" ] && URL="$URL#$2"
+
+# find a suitable browser to launch if no BROWSER variable is set
+if [ "x$BROWSER" = "x" ]; then
+  for i in $APPLICATIONS; do
+    # find the application in the path
+    testapp=$(which $i 2>/dev/null)
+    if test -f "$testapp"; then
+      # use the application and break
+      BROWSER=$i
+      break
+    fi
+  done
+fi
+
+# tell the use if no suitable browser was found
+if [ "x$BROWSER" = "x" ]; then
+  # print warning and leave
+  echo "MousepadHelp: Could not find a browser to use. Please set the BROWSER variable."
+  exit 1
+fi
+
+# run the browser
+case $BROWSER in
+  exo-open)
+    $BROWSER --launch WebBrowser $URL
+  ;;
+  opera*)
+    $BROWSER -remote openURL\($URL,new-window\) || $BROWSER $URL
+  ;;
+  firefox*)
+    $BROWSER -a firefox -remote openurl\($URL,new-window\) || $BROWSER $URL
+  ;;
+  communicator*|netscape|mozilla*|phoenix*|firebird*)
+    $BROWSER -remote openurl\($URL,new-window\) || $BROWSER $URL
+  ;;
+  *)
+    $BROWSER $URL;
+  ;;
+esac
+
+# leave
+exit 0
+
+# vim:set ts=2 sw=2 et ai:
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..b1dc310
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,42 @@
+0.3.0
+=====
+Highlights:
+    - A complete rewrite of Mousepad. The code is now written in GOjects
+      where possible so we have a solid base for further development.
+    - Run multiple windows in one instance. We also invoke a running
+      instance with DBus (optional), this is needed for tab DND between
+      windows.
+    - Drag and Drop support for text inside a document, between tabs and
+      between windows.  Also supports opening a file by dragging it into
+      the window.
+    - Support for multiple tabs in one window which are both reorderable
+      and detachable.
+    - Load multiple files at once from both the open dialog and the command
+      line.
+    - Type-ahead find and highlight feature like Firefox.
+    - Support for editable menu accelerators.
+    - Reimplemented recent file support. You can cleanup the Mousepad history
+      and a file is removed from the history when Mousepad was unable to open
+      it.
+    - Syntax highlighting of many filetypes (including printing).
+    - Various hidden settings.
+    - Statusbar with filetype, cursor location and whether overwrite is
+      actived.
+    - Mousepad depends on GTK+ 2.20.
+
+Bug fixes:
+    - Save button is now default response in the dialog (Bug #2941).
+    - No font is set as long the user has not defined any (Bug #2720).
+    - No compiler warnings (Bug #1697).
+    - Windows geometry is now properly saved (Bug #2945).
+    - Hidden option to show the full path in the window title (Bug #2896).
+    - Basic command line options (Bug #2397).
+    - The MousepadPreferences object uses XfceRc for saving the
+      settings (Bug #2786).
+    - No segfault when there is no rc file (Bug #2784).
+    - Support syntax highlighting using GtkSourceView (Bug #3228 & #5803).
+    - Proper Drag and Drop support (Bug #2055).
+    - Fix recent files support (Bug #5635, #3850 & #7890).
+    - Use GTK+ printing (Bug #4477).
+    - Settings saved in Find (and Replace) dialogs (Bug #7246).
+    - No deprecated dependencies (Bug #7259).
diff --git a/README b/README
new file mode 100644
index 0000000..0c53e33
--- /dev/null
+++ b/README
@@ -0,0 +1,45 @@
+What is it?
+===========
+
+Mousepad is a simple text editor for the Xfce  desktop environment.
+
+
+The Mousepad Mission
+====================
+
+Mousepad aims to be an easy-to-use and fast editor. Our target is an
+editor for quickly editing text files, not a development environment
+or an editor with a huge bunch of plugins.
+On the other hand we try to use the latest Gtk+ features available,
+which means that if Gtk adds something new in a major release that is
+useful for the editor, we will likely bump the Gtk dependency and
+integrate this new feature in Mousepad.
+
+
+Required packages
+=================
+
+Mousepad depends on the following packages:
+
+ - Gtk+ 2.20.0 or above
+ - Libxfce4util 4.4.0 or above
+ - GtkSourceView 2.2.2 or above
+
+The following packages are optional:
+
+ - D-BUS 0.34 or above (strongly suggested)
+
+
+Installation
+============
+
+The file 'INSTALL' contains generic installation
+instructions.
+
+
+How to report bugs?
+===================
+
+Bugs should be reported to the Xfce bug tracking system
+(http://bugzilla.xfce.org, product Mousepad). You will need to create
+an account for yourself.
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..e69de29
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..6976a23
--- /dev/null
+++ b/TODO
@@ -0,0 +1,43 @@
+All the items below, except those under the feature heading, must
+be fixed (or ignored when irrelevant) before the nick_0_3 branch
+can move to trunk. When the branch enters trunk, it's important
+we work towards a stable version, so we can release a 0.2.90.1
+(0.3 beta 1) version as soon as possible (if needed, independent
+from the Xfce release schedule).
+
+
+Interface
+=========
+- Test the application with a screen reader and add Atk objects
+  where needed.
+- Check the search and replace code for bugs.
+- Add option to disable the search feedback in the replace dialog
+  (highlight, count matches, type-ahead). This can slow down mousepad
+  with (multiple) large documents.
+- Transpose words works a bit odd sometimes.
+- Improve replace (all) in selection.
+
+
+Saving and loading
+==================
+- Cleanup and improve encoding support and order the encoding types.
+
+
+Other
+=====
+- We need a cool Mousepad logo.
+- Write documentation.
+- Session manager support (waiting for Gtk+ here).
+
+
+Testing and polishing
+=====================
+- Profiling loading large files (Gtk/Pango has a problem here). This
+  also locks some dialogs.
+- Checking for memory leaks.
+
+
+Feature
+=======
+- You'll never know. No promisses here...
+- GIO.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..fb9b80b
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+(type xdt-autogen) >/dev/null 2>&1 || {
+  cat >&2 <<EOF
+autogen.sh: You don't seem to have the Xfce development tools installed on
+            your system, which are required to build this software.
+            Please install the xfce4-dev-tools package first, it is available
+            from http://www.xfce.org/.
+EOF
+  exit 1
+}
+
+XDT_AUTOGEN_REQUIRED_VERSION="4.7.2" exec xdt-autogen $@
+
+# vi:set ts=2 sw=2 et ai:
diff --git a/configure.ac.in b/configure.ac.in
new file mode 100644
index 0000000..9c820c6
--- /dev/null
+++ b/configure.ac.in
@@ -0,0 +1,156 @@
+dnl ***************************
+dnl *** Version information ***
+dnl ***************************
+m4_define([mousepad_version_major], [0])
+m4_define([mousepad_version_minor], [3])
+m4_define([mousepad_version_micro], [0])
+m4_define([mousepad_version_nano], []) dnl leave this empty to have no nano version
+m4_define([mousepad_version_build], [@REVISION@])
+m4_define([mousepad_version_tag], [git])
+m4_define([mousepad_version], [mousepad_version_major().mousepad_version_minor().mousepad_version_micro()ifelse(mousepad_version_nano(), [], [], [.mousepad_version_nano()])ifelse(mousepad_version_tag(), [git], [mousepad_version_tag()-mousepad_version_build()], [mousepad_version_tag()])])
+
+dnl *******************************************
+dnl *** Debugging support for GIT snapshots ***
+dnl *******************************************
+m4_define([mousepad_debug_default], [ifelse(mousepad_version_tag(), [git], [yes], [minimum])])
+
+dnl ***************************
+dnl *** Initialize autoconf ***
+dnl ***************************
+AC_COPYRIGHT([Copyright (c) 2007-2010
+        The Xfce development team. All rights reserved.])
+AC_INIT([Mousepad], [mousepad_version], [http://bugzilla.xfce.org/], [mousepad])
+AC_PREREQ([2.50])
+AC_CANONICAL_TARGET()
+AC_REVISION([])
+
+dnl ***************************
+dnl *** Initialize automake ***
+dnl ***************************
+AM_INIT_AUTOMAKE([1.8 dist-bzip2 tar-ustar])
+AM_CONFIG_HEADER([config.h])
+AM_MAINTAINER_MODE()
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+dnl *******************************
+dnl *** Check for UNIX variants ***
+dnl *******************************
+AC_AIX()
+AC_ISC_POSIX()
+AC_MINIX()
+
+dnl ********************************
+dnl *** Check for basic programs ***
+dnl ********************************
+AC_PROG_CC()
+AM_PROG_CC_C_O()
+AC_PROG_LD()
+AC_PROG_INSTALL()
+AC_PROG_INTLTOOL()
+AC_CHECK_PROGS([PERL], [perl5 perl])
+
+dnl **************************
+dnl *** Initialize libtool ***
+dnl **************************
+AC_PROG_LIBTOOL()
+
+dnl **************************************
+dnl *** Substitute version information ***
+dnl **************************************
+MOUSEPAD_VERSION_MAJOR=mousepad_version_major()
+MOUSEPAD_VERSION_MINOR=mousepad_version_minor()
+MOUSEPAD_VERSION_MICRO=mousepad_version_micro()
+MOUSEPAD_VERSION_NANO=mousepad_version_nano()
+AC_SUBST([MOUSEPAD_VERSION_MAJOR])
+AC_SUBST([MOUSEPAD_VERSION_MINOR])
+AC_SUBST([MOUSEPAD_VERSION_MICRO])
+AC_SUBST([MOUSEPAD_VERSION_NANO])
+
+dnl **********************************
+dnl *** Check for standard headers ***
+dnl **********************************
+AC_CHECK_HEADERS([errno.h fcntl.h libintl.h memory.h math.h stdlib.h \
+                  string.h sys/types.h sys/stat.h time.h unistd.h])
+
+dnl ******************************
+dnl *** Check for i18n support ***
+dnl ******************************
+XDT_I18N([@LINGUAS@])
+
+dnl ***********************************
+dnl *** Check for required packages ***
+dnl ***********************************
+XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.12.0])
+XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.12.0])
+XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.10.0])
+XDT_CHECK_PACKAGE([GTKSOURCEVIEW], [gtksourceview-2.0])
+
+dnl **********************************
+dnl *** Optional support for D-BUS ***
+dnl **********************************
+XDT_CHECK_OPTIONAL_PACKAGE([DBUS], [dbus-glib-1],
+                           [0.34], [dbus], [D-BUS support])
+
+dnl **************************
+dnl *** Check for xsltproc ***
+dnl **************************
+AC_ARG_ENABLE([xsltproc], [AC_HELP_STRING([--enable-xsltproc], [Use xsltproc to build documentation @<:@default=no@:>@])],, [enable_xsltproc=no])
+if test x"$enable_xsltproc" = x"yes"; then
+  AC_PATH_PROG([XSLTPROC], [xsltproc], [no])
+  if test x"$XSLTPROC" = x"no"; then
+    enable_xsltproc=no
+  fi
+fi
+AM_CONDITIONAL([ENABLE_XSLTPROC], [test x"$enable_xsltproc" = x"yes"])
+
+dnl ***********************************
+dnl *** Check for debugging support ***
+dnl ***********************************
+XDT_FEATURE_DEBUG([mousepad_debug_default])
+
+dnl **************************************
+dnl *** Check for linker optimizations ***
+dnl **************************************
+XDT_FEATURE_LINKER_OPTS()
+
+dnl *********************************
+dnl *** Substitute platform flags ***
+dnl *********************************
+AC_MSG_CHECKING([PLATFORM_CPPFLAGS])
+AC_MSG_RESULT([$PLATFORM_CPPFLAGS])
+AC_SUBST([PLATFORM_CPPFLAGS])
+AC_MSG_CHECKING([PLATFORM_CFLAGS])
+AC_MSG_RESULT([$PLATFORM_CFLAGS])
+AC_SUBST([PLATFORM_CFLAGS])
+AC_MSG_CHECKING([PLATFORM_LDFLAGS])
+AC_MSG_RESULT([$PLATFORM_LDFLAGS])
+AC_SUBST([PLATFORM_LDFLAGS])
+
+AC_OUTPUT([
+Makefile
+docs/Makefile
+docs/manual/Makefile
+docs/manual/C/Makefile
+docs/manual/C/Mousepad.xml
+docs/manual/C/images/Makefile
+icons/Makefile
+icons/16x16/Makefile
+icons/24x24/Makefile
+icons/scalable/Makefile
+mousepad/Makefile
+po/Makefile.in
+])
+
+dnl ***************************
+dnl *** Print configuration ***
+dnl ***************************
+echo
+echo "Build Configuration:"
+echo
+if test x"$DBUS_FOUND" = x"yes"; then
+echo "* D-BUS support:             yes"
+else
+echo "* D-BUS support:             no"
+fi
+echo "* Debug Support:             $enable_debug"
+echo
diff --git a/docs/Makefile.am b/docs/Makefile.am
new file mode 100644
index 0000000..7511289
--- /dev/null
+++ b/docs/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = \
+	manual
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/docs/manual/C/Makefile.am b/docs/manual/C/Makefile.am
new file mode 100644
index 0000000..06db614
--- /dev/null
+++ b/docs/manual/C/Makefile.am
@@ -0,0 +1,66 @@
+SUBDIRS =								\
+	images
+
+TARGET_DIR = $(datadir)/doc/Mousepad/html/C
+STYLESHEET = ../mousepad.xsl
+DOCUMENT = Mousepad.xml
+
+# We set GPATH here; this gives us semantics for GNU make
+# which are more like other make's VPATH, when it comes to
+# whether a source that is a target of one rule is then
+# searched for in VPATH/GPATH.
+GPATH = $(srcdir)
+
+DOC_STAMPS = html-build.stamp
+
+EXTRA_DIST = $(DOCUMENT)
+CLEANFILES = $(DOC_STAMPS)
+
+if ENABLE_XSLTPROC
+all-local: html-build.stamp
+
+html-build.stamp: $(srcdir)/$(DOCUMENT) $(srcdir)/$(STYLESHEET)
+	@echo "*** Building HTML ***"
+	@-chmod -R u+w $(srcdir)
+	rm -rf $(srcdir)/html
+	mkdir $(srcdir)/html
+	$(XSLTPROC) --nonet -o $(srcdir)/html/ $(srcdir)/$(STYLESHEET) \
+		$(srcdir)/$(DOCUMENT)
+	touch html-build.stamp
+else
+all-local:
+endif
+
+maintainer-clean-local: clean
+	(cd $(srcdir) && rm -rf html)
+
+install-data-local:
+	installfiles=`echo $(srcdir)/html/*`;				\
+	if test "$$installfiles" = '$(srcdir)/html/*'; then		\
+		echo "--- Nothing to install";				\
+	else								\
+		$(mkinstalldirs) $(DESTDIR)$(TARGET_DIR);		\
+		for file in $$installfiles; do				\
+			echo "--- Installing "$$file;			\
+			$(INSTALL_DATA) $$file $(DESTDIR)$(TARGET_DIR);	\
+		done;							\
+	fi
+
+uninstall-local:
+	rm -rf $(DESTDIR)$(TARGET_DIR)/*
+
+if ENABLE_XSLTPROC
+dist-check-xsltproc: all
+else
+dist-check-xsltproc:
+	@echo "*** xsltproc must be installed and enabled in order to make dist"
+	@false
+endif
+
+dist-hook: dist-check-xsltproc dist-hook-local
+	mkdir $(distdir)/html
+	-cp $(srcdir)/html/* $(distdir)/html
+
+.PHONY: dist-hook-local
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/docs/manual/C/Mousepad.xml.in b/docs/manual/C/Mousepad.xml.in
new file mode 100644
index 0000000..fcd6ce3
--- /dev/null
+++ b/docs/manual/C/Mousepad.xml.in
@@ -0,0 +1,478 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+  <!ENTITY date "OCtober 2007">
+  <!ENTITY version "@PACKAGE_VERSION@">
+  <!ENTITY application "@PACKAGE_NAME@">
+]>
+<article id="index" lang="en">
+
+  <articleinfo>
+    <title>Mousepad Text Editor</title>
+
+    <pubdate>&date;</pubdate>
+
+    <copyright>
+      <year>2007</year>
+      <holder>Nick Schermer</holder>
+    </copyright>
+
+    <legalnotice id="legalnotice">
+      <para>
+        Permission is granted to copy, distribute and/or modify this document
+        under the terms of the GNU Free Documentation License, Version 1.1 or
+        any later version published by the Free Software Foundation; with no
+        Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+        Texts. The complete license text is available from the <ulink
+        type="http" url="http://www.gnu.org/">Free Software Foundation</ulink>.
+      </para>
+    </legalnotice>
+
+    <authorgroup>
+      <author>
+        <firstname>Nick</firstname>
+        <surname>Schermer</surname>
+        <affiliation>
+          <orgname>Xfce Development Team</orgname>
+          <address><email>nick at xfce.org</email></address>
+        </affiliation>
+      </author>
+    </authorgroup>
+
+    <releaseinfo>
+      This manual describes version &version; of &application;.
+    </releaseinfo>
+  </articleinfo>
+
+  <sect1 id="preface">
+    <title>Preface</title>
+
+    <sect2 id="introduction">
+      <title>Introduction</title>
+
+      <para>
+        &application; is the default text editor for the Xfce Desktop Environment. It has
+        been design to be a lightweight editor you would use for basic file editing.
+        Therefore &application; starts quickly, but also has features like editing
+        multiple documents, vertical selection, type-ahead search, full tab drag and drop
+        and much more.
+      </para>
+
+      <para>
+        &application; started as a fork of Leafpad to provide printing support using
+        Xfprint, but as of version 0.3 is has been completely rewritten to add support for
+        tabs and DBus. Although the rewrite added a lot of new features, it is still as
+        fast as the Leafpad based fork and therefore fits perfectly in the Xfce philosophy.
+      </para>
+    </sect2>
+
+    <sect2 id="terminology">
+      <title>Terminology</title>
+
+      <para>
+        There might be a couple of words in this manual that could be the source of
+        misunderstanding. The table below will clarify those words.
+      </para>
+
+      <table frame="all">
+        <title>Terminology</title>
+        <tgroup cols='2'>
+          <thead>
+            <row>
+              <entry>Term</entry>
+              <entry>Explanation</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry>Caret</entry>
+              <entry>The text insertion point.</entry>
+            </row>
+            <row>
+              <entry>Cursor</entry>
+              <entry>Mouse pointer.</entry>
+            </row>
+            <row>
+              <entry>Document</entry>
+              <entry>A file loaded in &application;.</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table>
+    </sect2>
+  </sect1>
+
+  <sect1 id="working-with-text">
+    <title>Working With Text</title>
+
+    <sect2 id="keyboard-shortcuts">
+      <title>Keyboard Shortcuts</title>
+    </sect2>
+
+    <sect2 id="undo-and-redo">
+      <title>Undo and Redo</title>
+
+      <para>
+
+      </para>
+    </sect2>
+
+    <sect2 id="copy-and-paste">
+      <title>Copy and Paste</title>
+
+      <para>
+        &application; supports both the selection and primary clipboard. To paste
+        something from the seletion clipboard you can click with the middle mouse
+        button in the &application; window.
+      </para>
+
+      <para>
+        The primary clipboard can be accessed by the <guimenuitem>Cut</guimenuitem>,
+        <guimenuitem>Copy</guimenuitem> and <guimenuitem>Paste</guimenuitem> menu
+        items in the <guimenu>Edit</guimenu> menu. The keyboard shortcuts mentioned
+        above also work.
+      </para>
+
+      <sect3 id="paste-from-history">
+        <title>Paste from History</title>
+
+        <screenshot>
+          <mediaobject>
+            <imageobject>
+              <imagedata fileref="images/paste-from-history.png" format="PNG"/>
+            </imageobject>
+
+            <textobject>
+              <phrase>Paste from History</phrase>
+            </textobject>
+
+            <caption>
+              <para>Screenshot of the history menu</para>
+            </caption>
+          </mediaobject>
+        </screenshot>
+
+        <para>
+          Each time you copy text in &application;, the text is pushed onto a stack.
+          When you choose <menuchoice><guimenu>Edit</guimenu><guimenuitem>Paste Special
+          </guimenuitem><guimenuitem>Paste from History</guimenuitem></menuchoice> a
+          menu will appear below the carret with the last 10 clipboard items.
+        </para>
+
+        <para>
+          You can choose an item from the list by clicking it, using the arrow keys
+          and press enter or by pressing the numeric keyboard accelerator.
+        </para>
+      </sect3>
+
+      <sect3 id="paste-as-column">
+        <title>Paste as Column</title>
+
+        <para>
+          When the content in the primary clipboard contains multiple lines, you can paste
+          the content in the same column. &application; will then try  to paste each line
+          in the clipboard at the same x-coordinate. You can access this option by
+          choosing <menuchoice><guimenu>Edit</guimenu><guimenuitem>Paste Special
+          </guimenuitem><guimenuitem>Paste as Column</guimenuitem></menuchoice>.
+        </para>
+      </sect3>
+    </sect2>
+
+    <sect2 id="auto-indent">
+      <title>Auto Indent</title>
+
+    </sect2>
+
+    <sect2 id="selections">
+      <title>Selecting Text</title>
+
+      <sect3 id="multi-and-column-selections">
+        <title>Column-Selections</title>
+      </sect3>
+
+      <sect3 id="indentation">
+        <title>Indentation</title>
+      </sect3>
+
+      <sect3 id="moving-selections">
+        <title>Moving Selections</title>
+      </sect3>
+    </sect2>
+
+    <sect2 id="search-and-replace">
+      <title>Search And Replace</title>
+
+      <sect3 id="typeahead-search">
+        <title>Typeahead Search</title>
+
+        <screenshot>
+          <mediaobject>
+            <imageobject>
+              <imagedata fileref="images/typeahead-search.png" format="PNG"/>
+            </imageobject>
+
+            <textobject>
+              <phrase>Typeahead search bar</phrase>
+            </textobject>
+
+            <caption>
+              <para>Screenshot of the typeahead search bar</para>
+            </caption>
+          </mediaobject>
+        </screenshot>
+      </sect3>
+
+      <sect3 id="replace-dialog">
+        <title>Search and Replace Dialog</title>
+
+        <screenshot>
+          <mediaobject>
+            <imageobject>
+              <imagedata fileref="images/find-and-replace.png" format="PNG"/>
+            </imageobject>
+
+            <textobject>
+              <phrase>Find and Replace Dialog</phrase>
+            </textobject>
+
+            <caption>
+              <para>Screenshot of the find and replace dialog</para>
+            </caption>
+          </mediaobject>
+        </screenshot>
+      </sect3>
+    </sect2>
+
+    <sect2 id="tabs">
+      <title>Tabs</title>
+
+        <screenshot>
+          <mediaobject>
+            <imageobject>
+              <imagedata fileref="images/tab-size-menu.png" format="PNG"/>
+            </imageobject>
+
+            <textobject>
+              <phrase>Tab Size menu</phrase>
+            </textobject>
+
+            <caption>
+              <para>Screenshot of the tabs size menu</para>
+            </caption>
+          </mediaobject>
+        </screenshot>
+
+        <screenshot>
+          <mediaobject>
+            <imageobject>
+              <imagedata fileref="images/other-tab-size.png" format="PNG"/>
+            </imageobject>
+
+            <textobject>
+              <phrase>Other tab size</phrase>
+            </textobject>
+
+            <caption>
+              <para>Screenshot of the other tab size dialog</para>
+            </caption>
+          </mediaobject>
+        </screenshot>
+
+      <sect3 id="insert-spaces">
+        <title>Insert Spaces</title>
+      </sect3>
+    </sect2>
+
+    <sect2 id="transpose">
+      <title>Transpose</title>
+    </sect2>
+
+    <sect2 id="printing">
+      <title>Printing</title>
+    </sect2>
+  </sect1>
+
+  <sect1 id="faq">
+    <title>Frequently Asked Questions</title>
+
+    <para>
+      The intent of this section is to collect the quite numerous frequently asked
+      questions that relate to working with &application;. If you know of a question that
+      is missing from this page, please <ulink type="http"
+      url="http://bugzilla.xfce.org/enter_bug.cgi?product=Mousepad&format=guided">
+      file a request</ulink>.
+    </para>
+
+    <sect3 id="faq-hidden-settings">
+      <title>Does &application; has hidden settings?</title>
+
+      <para>
+        Yes, some of the settings in the mousepadrc file are not configurable from
+        the interface and can only be modified by hand. To find the mousepadrc file
+        see <xref linkend="faq-mousepadrc" />. It is not recommended to change the
+        rc file using &application;, since it might be overwritten when you
+        close the window after editing. You must also restart &application; to
+        apply the settings. The hidden settings, starting with <varname>Misc</varname>,
+        are explained in the list below:
+      </para>
+
+      <variablelist>
+        <varlistentry>
+          <term><varname>MiscAlwaysShowTabs</varname></term>
+          <listitem>
+            <para>
+              If <literal>TRUE</literal> the tab headers will always be displayed even if only a single
+              document tab is open. This option is useful if you want to drag-and-drop the last tab to
+              another window. See <xref linkend="ordering-documents" />.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>MiscCycleTabs</varname></term>
+          <listitem>
+            <para>
+              This option controls whether you can circulate through document tabs. That is, whether
+              you are able to go from the last tab to the first tab using the <menuchoice>
+              <guimenu>Navigation</guimenu><guimenuitem>Forward</guimenuitem></menuchoice> entry
+              (or the associated keyboard shortcut), and from the first tab to the last tab using the
+              <menuchoice><guimenu>Navigation</guimenu><guimenuitem>Back</guimenuitem></menuchoice> entry.
+              The option can be either <literal>TRUE</literal> or <literal>FALSE</literal> (default).
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>MiscPathInTitle</varname></term>
+          <listitem>
+            <para>
+              This option controls whether the full document path is displayed in the window title.
+              By default, <literal>FALSE</literal>, only the filename is shown. The option can be either
+              <literal>TRUE</literal> or <literal>FALSE</literal>.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>MiscRecentMenuItems</varname></term>
+          <listitem>
+            <para>
+              This option controls the maximum number of items shown in the
+              <menuchoice><guimenu>File</guimenu><guimenuitem>Open Recent</guimenuitem>
+              </menuchoice> menu. When you set the value to <literal>0</literal>, so
+              entire menu will be hidden. The integer can be in a range of <literal>0</literal>
+              ..<literal>4096</literal>.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>MiscRememberGeometry</varname></term>
+          <listitem>
+            <para>
+              Whether &application; should remember the size of windows and apply that size to
+              new windows. If <literal>TRUE</literal> (default) the width and height are saved
+              to <varname>WindowWidth</varname> and <varname>WindowHeight</varname>. If
+              <literal>FALSE</literal> the user may specify the start size in
+              <varname>WindowWidth</varname> and <varname>WindowHeight</varname>.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>MiscDefaultTabSizes</varname></term>
+          <listitem>
+            <para>
+              This is the default list of tab sizes displayed in the <menuchoice>
+              <guimenu>Document</guimenu><guimenuitem>Tab Size</guimenuitem></menuchoice>
+              menu. Each size must be in a range of <literal>1</literal>..<literal>32</literal>.
+              By defaul the value is <literal>2,3,4,8</literal>.
+            </para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </sect3>
+
+    <sect3 id="faq-mousepadrc">
+      <title>Where does &application; store its preferences?</title>
+
+      <para>
+        &application; stores the user configurable preferences (and hidden settings) in
+        an <filename>.ini</filename> file, which is located at
+        <filename>$XDG_CONFIG_HOME/&application;/mousepadrc</filename>. If you make changes
+        to this file, make sure you restart &application;. It's also not recommended to
+        use &application; to edito this file, since it might overwrite it after you've
+        changed the file.
+      </para>
+    </sect3>
+
+    <sect3 id="faq-assign-keyboard-shortcuts">
+      <title>How do I assign different keyboard shortcuts?</title>
+
+      <para>
+        If you want to rebind a shortcut, &application; supports the standard GTK+ way
+        of changing shortcuts: simply hover over the menu option with the mouse
+        pointer and press the keyboard shortcut you want to rebind it to.
+      </para>
+
+      <para>
+        To delete a keyboard assignment, press the <keycap>Backspace</keycap> key
+        while you are on the menu entry.
+      </para>
+
+      <para>
+        If the shortcut doesn't change, then you need to enable the feature in
+        GTK+. This can be achieved in 3 ways:
+      </para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            If you are running Xfce 4.3 or above then you can enable <guilabel>Editable
+            menu accelerators</guilabel> in the <guilabel>User Interface Preferences</guilabel>
+            dialog.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            If you are running GNOME then you can enable <guilabel>Editable menu
+            accelerators</guilabel> in the <guilabel>Menu and Toolbars</guilabel> control
+            center dialog.
+          </para>
+        </listitem>
+
+        <listitem>
+          <para>
+            Otherwise put the following in your <filename>~/.gtkrc-2.0</filename> file
+            (create the file if it doesn't exist):<screen>gtk-can-change-accels=1</screen>
+          </para>
+        </listitem>
+      </itemizedlist>
+    </sect3>
+
+    <sect3 id="faq-store-keyboard-shortcuts">
+      <title>Where does &application; store the keyboard shortcuts?</title>
+
+      <para>
+        The custom keyboard shortcuts are stored in the standard GTK+ accel map format in a
+        file located at <filename>$XDG_CONFIG_HOME/&application;/accels.scm</filename>. Lines starting
+        with <literal>;</literal> are comments. See the GTK+ documentation for details about the
+        file format.
+      </para>
+
+      <para>
+        If you are a packager or a system administrator and want to provide a system wide default
+        for the keyboard shortcuts, that is different from the default shortcuts in &application;, you
+        can create a file <filename>&application;/accels.scm</filename> in one of the <envar>$XDG_CONFIG_DIRS</envar>.
+        For example, if <filename role="directory">/etc/xdg</filename> is part of <envar>$XDG_CONFIG_DIRS</envar>
+        (the default for most Linux distributions), you can install system wide defaults to
+        <filename>/etc/xdg/&application;/accels.scm</filename>. &application; will then load shortcuts from
+        this file on first startup.
+      </para>
+    </sect3>
+  </sect1>
+</article>
+<!--
+	vim:set ts=2 sw=2 et ai encoding=UTF-8:
+-->
diff --git a/docs/manual/C/images/Makefile.am b/docs/manual/C/images/Makefile.am
new file mode 100644
index 0000000..c329f2b
--- /dev/null
+++ b/docs/manual/C/images/Makefile.am
@@ -0,0 +1,15 @@
+imagesdir = $(datadir)/doc/Mousepad/html/C/images
+images_DATA =								\
+	find-and-replace.png						\
+	go-to.png							\
+	main-window.png							\
+	Makefile.am							\
+	other-tab-size.png						\
+	paste-from-history.png						\
+	tab-size-menu.png						\
+	typeahead-search.png
+
+EXTRA_DIST = 								\
+	$(images_DATA)
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/docs/manual/C/images/find-and-replace.png b/docs/manual/C/images/find-and-replace.png
new file mode 100644
index 0000000..9e8648a
Binary files /dev/null and b/docs/manual/C/images/find-and-replace.png differ
diff --git a/docs/manual/C/images/go-to.png b/docs/manual/C/images/go-to.png
new file mode 100644
index 0000000..4fe1d3c
Binary files /dev/null and b/docs/manual/C/images/go-to.png differ
diff --git a/docs/manual/C/images/main-window.png b/docs/manual/C/images/main-window.png
new file mode 100644
index 0000000..2ac0a27
Binary files /dev/null and b/docs/manual/C/images/main-window.png differ
diff --git a/docs/manual/C/images/other-tab-size.png b/docs/manual/C/images/other-tab-size.png
new file mode 100644
index 0000000..651d095
Binary files /dev/null and b/docs/manual/C/images/other-tab-size.png differ
diff --git a/docs/manual/C/images/paste-from-history.png b/docs/manual/C/images/paste-from-history.png
new file mode 100644
index 0000000..dd2d757
Binary files /dev/null and b/docs/manual/C/images/paste-from-history.png differ
diff --git a/docs/manual/C/images/tab-size-menu.png b/docs/manual/C/images/tab-size-menu.png
new file mode 100644
index 0000000..942063c
Binary files /dev/null and b/docs/manual/C/images/tab-size-menu.png differ
diff --git a/docs/manual/C/images/typeahead-search.png b/docs/manual/C/images/typeahead-search.png
new file mode 100644
index 0000000..2fc6664
Binary files /dev/null and b/docs/manual/C/images/typeahead-search.png differ
diff --git a/docs/manual/Makefile.am b/docs/manual/Makefile.am
new file mode 100644
index 0000000..817eaa6
--- /dev/null
+++ b/docs/manual/Makefile.am
@@ -0,0 +1,12 @@
+SUBDIRS =								\
+	C
+
+cssdir = $(datadir)/doc/Mousepad/html
+css_DATA =							        \
+	mousepad.css
+
+EXTRA_DIST = 						                \
+	$(css_DATA)						        \
+	mousepad.xsl
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/docs/manual/mousepad.css b/docs/manual/mousepad.css
new file mode 100644
index 0000000..de1ed89
--- /dev/null
+++ b/docs/manual/mousepad.css
@@ -0,0 +1,99 @@
+body address
+{
+  line-height: 1.3;
+  margin: .6em 0;
+}
+
+body blockquote
+{
+  margin-top: .75em;
+  line-height: 1.5;
+  margin-bottom: .75em;
+}
+
+html body
+{
+  margin: 1em 8% 1em 10%;
+  line-height: 1.2;
+  background-color: #ffffff;
+}
+
+body pre
+{
+  margin: .75em 0;
+  line-height: 1.3;
+  color: #4f3f3f;
+  font-weight: bold;
+}
+
+body div
+{
+  margin: 0;
+}
+
+dl
+{
+  margin: .8em 0;
+  line-height: 1.2;
+}
+
+.legalnotice
+{
+  font-size: small;
+  font-variant: small-caps;
+}
+
+h1,h2,h3,h4,h5,h6,
+div.example p b,
+.question,
+div.table p b,
+div.procedure p b
+{
+  color: #990000;
+}
+
+.option
+{
+  color: #0000ca;
+  font-weight: bold;
+}
+
+.parameter
+{
+  color: #007a00;
+  font-weight: bold;
+}
+
+a
+{
+  color: #000000;
+}
+
+a:hover
+{
+  color: #3c3c3c;
+  border-bottom: 1px dotted #dc0000;
+}
+
+hr
+{
+  background-color: #9c9c9c;
+  border-style: none;
+  height: 1px;
+}
+
+ul li
+{
+  list-style-type: square;
+}
+
+.programlisting, .screen
+{
+  background-color: #F8F9FD;
+  border-color: #907777;
+  border-width: 1px;
+  border-style: solid;
+  padding: 0.5em;
+}
+
+/* vim:set ts=2 sw=2 et ai: */
diff --git a/docs/manual/mousepad.xsl b/docs/manual/mousepad.xsl
new file mode 100644
index 0000000..229d192
--- /dev/null
+++ b/docs/manual/mousepad.xsl
@@ -0,0 +1,254 @@
+<?xml version='1.0'?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version='1.0'
+                xmlns="http://www.w3.org/TR/xhtml1/transitional"
+                exclude-result-prefixes="#default">
+
+<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/>
+
+<!-- Use stylesheet -->
+<xsl:param name="html.stylesheet" select="'../mousepad.css'"/>
+
+<!-- labels and numbering -->
+<xsl:param name="autotoc.label.separator" select="'. '"/>
+<xsl:param name="chapter.autolabel" select="1"/>
+
+<!-- Don't force the use of index.html as root filename -->
+<xsl:param name="root.filename" select="''"/>
+
+<!--  Use element id (if present) as file name  -->
+<xsl:variable name="use.id.as.filename">1</xsl:variable>
+
+<xsl:template match="releaseinfo" mode="titlepage.mode">
+  <span class="{name(.)}">
+    <br/>
+    <xsl:apply-templates mode="titlepage.mode"/>
+    <br/>
+  </span>
+</xsl:template>
+
+<!-- Use graphics in admonitions (note, warning, etc)  -->
+<xsl:variable name="admon.graphics">0</xsl:variable>
+
+<xsl:param name="admon.style">
+	<xsl:text>text-align: left;</xsl:text></xsl:param>
+
+<xsl:variable name="admon.graphics.path">stylesheet-images/</xsl:variable>
+
+<xsl:variable name="admon.graphics.extension">.gif</xsl:variable>
+
+<xsl:param name="table.border.thickness" select="'0.2pt'"/>
+
+<xsl:param name="graphic.default.extension" select="png"/>
+
+<!-- This requires an adapted template for tgroup (see end of stylesheet) -->
+<xsl:attribute-set name="table.style">
+	<xsl:attribute name="bgcolor">#fdf9f8</xsl:attribute>
+	<xsl:attribute name="cellspacing">0</xsl:attribute>
+	<xsl:attribute name="cellpadding">4</xsl:attribute>
+</xsl:attribute-set>
+
+
+<xsl:param name="generate.legalnotice.link" select="0"/>
+
+<!-- set font styles for various tags   -->
+<xsl:template match="guibutton">
+<xsl:call-template name="inline.boldseq"/>
+</xsl:template>
+
+<xsl:template match="guiicon">
+<xsl:call-template name="inline.boldseq"/>
+</xsl:template>
+
+<xsl:template match="guilabel">
+<xsl:call-template name="inline.boldseq"/>
+</xsl:template>
+
+<xsl:template match="guimenu">
+<xsl:call-template name="inline.boldseq"/>
+</xsl:template>
+
+<xsl:template match="guimenuitem">
+<xsl:call-template name="inline.boldseq"/>
+</xsl:template>
+
+<xsl:template match="guisubmenu">
+<xsl:call-template name="inline.boldseq"/>
+</xsl:template>
+
+<xsl:template match="application">
+<xsl:call-template name="inline.boldmonoseq"/>
+</xsl:template>
+
+<xsl:template match="caption">
+<xsl:call-template name="inline.boldseq"/>
+</xsl:template>
+
+<!-- Adapted template for tgroup. The only change is the addition of -->
+<!-- table.style attributes -->
+<xsl:template match="tgroup">
+  <table xsl:use-attribute-sets="table.style">
+    <xsl:choose>
+      <!-- If there's a <?dbhtml table-summary="foo"?> PI, use it for
+           the HTML table summary attribute -->
+      <xsl:when test="processing-instruction('dbhtml')">
+        <xsl:variable name="summary">
+          <xsl:call-template name="dbhtml-attribute">
+            <xsl:with-param name="pis"
+                            select="processing-instruction('dbhtml')[1]"/>
+            <xsl:with-param name="attribute" select="'table-summary'"/>
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:if test="$summary != ''">
+          <xsl:attribute name="summary">
+            <xsl:value-of select="$summary"/>
+          </xsl:attribute>
+        </xsl:if>
+      </xsl:when>
+      <!-- Otherwise, if there's a title, use that -->
+      <xsl:when test="../title">
+        <xsl:attribute name="summary">
+          <xsl:value-of select="string(../title)"/>
+        </xsl:attribute>
+      </xsl:when>
+      <!-- Otherwise, forget the whole idea -->
+      <xsl:otherwise><!-- nevermind --></xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:if test="../@pgwide=1">
+      <xsl:attribute name="width">100%</xsl:attribute>
+    </xsl:if>
+
+    <xsl:choose>
+      <xsl:when test="../@frame='none'">
+        <xsl:attribute name="border">0</xsl:attribute>
+      </xsl:when>
+      <xsl:when test="$table.borders.with.css != 0">
+        <xsl:attribute name="border">0</xsl:attribute>
+        <xsl:choose>
+          <xsl:when test="../@frame='topbot' or ../@frame='top'">
+            <xsl:attribute name="style">
+              <xsl:call-template name="border">
+                <xsl:with-param name="side" select="'top'"/>
+              </xsl:call-template>
+            </xsl:attribute>
+          </xsl:when>
+          <xsl:when test="../@frame='sides'">
+            <xsl:attribute name="style">
+              <xsl:call-template name="border">
+                <xsl:with-param name="side" select="'left'"/>
+              </xsl:call-template>
+              <xsl:call-template name="border">
+                <xsl:with-param name="side" select="'right'"/>
+              </xsl:call-template>
+            </xsl:attribute>
+          </xsl:when>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:attribute name="border">1</xsl:attribute>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:variable name="colgroup">
+      <colgroup>
+        <xsl:call-template name="generate.colgroup">
+          <xsl:with-param name="cols" select="@cols"/>
+        </xsl:call-template>
+      </colgroup>
+    </xsl:variable>
+
+    <xsl:variable name="explicit.table.width">
+      <xsl:call-template name="dbhtml-attribute">
+        <xsl:with-param name="pis"
+                        select="../processing-instruction('dbhtml')[1]"/>
+        <xsl:with-param name="attribute" select="'table-width'"/>
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:variable name="table.width">
+      <xsl:choose>
+        <xsl:when test="$explicit.table.width != ''">
+          <xsl:value-of select="$explicit.table.width"/>
+        </xsl:when>
+        <xsl:when test="$default.table.width = ''">
+          <xsl:text>100%</xsl:text>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="$default.table.width"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:if test="$default.table.width != ''
+                  or $explicit.table.width != ''">
+      <xsl:attribute name="width">
+        <xsl:choose>
+          <xsl:when test="contains($table.width, '%')">
+            <xsl:value-of select="$table.width"/>
+          </xsl:when>
+          <xsl:when test="$use.extensions != 0
+                          and $tablecolumns.extension != 0">
+            <xsl:choose>
+              <xsl:when test="function-available('stbl:convertLength')">
+                <xsl:value-of select="stbl:convertLength($table.width)"/>
+              </xsl:when>
+              <xsl:when test="function-available('xtbl:convertLength')">
+                <xsl:value-of select="xtbl:convertLength($table.width)"/>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:message terminate="yes">
+                  <xsl:text>No convertLength function available.</xsl:text>
+                </xsl:message>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="$table.width"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:attribute>
+    </xsl:if>
+
+    <xsl:choose>
+      <xsl:when test="$use.extensions != 0
+                      and $tablecolumns.extension != 0">
+        <xsl:choose>
+          <xsl:when test="function-available('stbl:adjustColumnWidths')">
+            <xsl:copy-of select="stbl:adjustColumnWidths($colgroup)"/>
+          </xsl:when>
+          <xsl:when test="function-available('xtbl:adjustColumnWidths')">
+            <xsl:copy-of select="xtbl:adjustColumnWidths($colgroup)"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:message terminate="yes">
+              <xsl:text>No adjustColumnWidths function available.</xsl:text>
+            </xsl:message>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:copy-of select="$colgroup"/>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:apply-templates select="thead"/>
+    <xsl:apply-templates select="tbody"/>
+    <xsl:apply-templates select="tfoot"/>
+
+    <xsl:if test=".//footnote">
+      <tbody class="footnotes">
+        <tr>
+          <td colspan="{@cols}">
+            <xsl:apply-templates select=".//footnote"
+                                 mode="table.footnote.mode"/>
+          </td>
+        </tr>
+      </tbody>
+    </xsl:if>
+  </table>
+</xsl:template>
+
+
+</xsl:stylesheet>
+
diff --git a/icons/16x16/Makefile.am b/icons/16x16/Makefile.am
new file mode 100644
index 0000000..a8e5cb7
--- /dev/null
+++ b/icons/16x16/Makefile.am
@@ -0,0 +1,13 @@
+iconsdir = $(datadir)/icons/hicolor/16x16/apps
+icons_DATA =								\
+	Mousepad.png
+
+# install symlink
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(iconsdir)
+	-( cd $(DESTDIR)$(iconsdir) ; ln -sf Mousepad.png accessories-text-editor.png )
+
+EXTRA_DIST =								\
+	$(icons_DATA)
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/icons/16x16/Mousepad.png b/icons/16x16/Mousepad.png
new file mode 100644
index 0000000..188e1c1
Binary files /dev/null and b/icons/16x16/Mousepad.png differ
diff --git a/icons/24x24/Makefile.am b/icons/24x24/Makefile.am
new file mode 100644
index 0000000..c22ae68
--- /dev/null
+++ b/icons/24x24/Makefile.am
@@ -0,0 +1,13 @@
+iconsdir = $(datadir)/icons/hicolor/24x24/apps
+icons_DATA =								\
+	Mousepad.png
+
+# install symlink
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(iconsdir)
+	-( cd $(DESTDIR)$(iconsdir) ; ln -sf Mousepad.png accessories-text-editor.png )
+
+EXTRA_DIST =								\
+	$(icons_DATA)
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/icons/24x24/Mousepad.png b/icons/24x24/Mousepad.png
new file mode 100644
index 0000000..bdbb88e
Binary files /dev/null and b/icons/24x24/Mousepad.png differ
diff --git a/icons/Makefile.am b/icons/Makefile.am
new file mode 100644
index 0000000..21932ab
--- /dev/null
+++ b/icons/Makefile.am
@@ -0,0 +1,19 @@
+SUBDIRS =								\
+	16x16								\
+	24x24								\
+	scalable
+
+gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
+
+install-data-hook:
+	@-if test -z "$(DESTDIR)"; then					\
+                echo "Updating Gtk icon cache.";			\
+                $(gtk_update_icon_cache);				\
+        else								\
+                echo "*** Icon cache not updated. Remember to run:";	\
+		echo "***";						\
+                echo "***   $(gtk_update_icon_cache)";			\
+		echo "***";						\
+        fi
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/icons/scalable/Makefile.am b/icons/scalable/Makefile.am
new file mode 100644
index 0000000..2beabc7
--- /dev/null
+++ b/icons/scalable/Makefile.am
@@ -0,0 +1,13 @@
+iconsdir = $(datadir)/icons/hicolor/scalable/apps
+icons_DATA =								\
+	Mousepad.svg
+
+# install symlink
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(iconsdir)
+	-( cd $(DESTDIR)$(iconsdir) ; ln -sf Mousepad.svg accessories-text-editor.svg )
+
+EXTRA_DIST =								\
+	$(icons_DATA)
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/icons/scalable/Mousepad.svg b/icons/scalable/Mousepad.svg
new file mode 100644
index 0000000..aa7188e
--- /dev/null
+++ b/icons/scalable/Mousepad.svg
@@ -0,0 +1,552 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   inkscape:export-ydpi="90.000000"
+   inkscape:export-xdpi="90.000000"
+   inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+   width="48px"
+   height="48px"
+   id="svg11300"
+   sodipodi:version="0.32"
+   inkscape:version="0.43+devel"
+   sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/apps"
+   sodipodi:docname="accessories-text-editor.svg">
+  <defs
+     id="defs3">
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient6719"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+       cx="605.71429"
+       cy="486.64789"
+       fx="605.71429"
+       fy="486.64789"
+       r="117.14286" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient5060">
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0"
+         id="stop5062" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop5064" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient6717"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+       cx="605.71429"
+       cy="486.64789"
+       fx="605.71429"
+       fy="486.64789"
+       r="117.14286" />
+    <linearGradient
+       id="linearGradient5048">
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="0"
+         id="stop5050" />
+      <stop
+         id="stop5056"
+         offset="0.5"
+         style="stop-color:black;stop-opacity:1;" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop5052" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5048"
+       id="linearGradient6715"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
+       x1="302.85715"
+       y1="366.64789"
+       x2="302.85715"
+       y2="609.50507" />
+    <linearGradient
+       id="linearGradient2994">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop2996" />
+      <stop
+         style="stop-color:#c9c9c9;stop-opacity:1;"
+         offset="1"
+         id="stop2998" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2984">
+      <stop
+         style="stop-color:#e7e2b8;stop-opacity:1;"
+         offset="0"
+         id="stop2986" />
+      <stop
+         style="stop-color:#e7e2b8;stop-opacity:0;"
+         offset="1"
+         id="stop2988" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2974">
+      <stop
+         style="stop-color:#c1c1c1;stop-opacity:1;"
+         offset="0"
+         id="stop2976" />
+      <stop
+         style="stop-color:#acacac;stop-opacity:1;"
+         offset="1"
+         id="stop2978" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2966">
+      <stop
+         style="stop-color:#ffd1d1;stop-opacity:1;"
+         offset="0"
+         id="stop2968" />
+      <stop
+         id="stop3006"
+         offset="0.5"
+         style="stop-color:#ff1d1d;stop-opacity:1;" />
+      <stop
+         style="stop-color:#6f0000;stop-opacity:1;"
+         offset="1"
+         id="stop2970" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2919">
+      <stop
+         style="stop-color:#a3a4a0;stop-opacity:1;"
+         offset="0"
+         id="stop2921" />
+      <stop
+         style="stop-color:#888a85;stop-opacity:1;"
+         offset="1"
+         id="stop2923" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2873">
+      <stop
+         style="stop-color:#939393;stop-opacity:1;"
+         offset="0"
+         id="stop2875" />
+      <stop
+         style="stop-color:#424242;stop-opacity:1;"
+         offset="1"
+         id="stop2877" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2865">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop2867" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop2869" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2855">
+      <stop
+         style="stop-color:#dfdfdf;stop-opacity:1;"
+         offset="0"
+         id="stop2857" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="1"
+         id="stop2859" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2855"
+       id="linearGradient2861"
+       x1="21.043484"
+       y1="42.83337"
+       x2="14.283642"
+       y2="6.8333683"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.137871,0.000000,0.000000,1.000000,-2.660884,0.000000)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2865"
+       id="radialGradient2871"
+       cx="23.5625"
+       cy="40.4375"
+       fx="23.5625"
+       fy="40.4375"
+       r="19.5625"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.348243,0.000000,26.35543)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2873"
+       id="linearGradient2879"
+       x1="26.612417"
+       y1="28.083368"
+       x2="26.228401"
+       y2="42.83337"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2919"
+       id="linearGradient2925"
+       x1="6"
+       y1="7.5624999"
+       x2="40.984375"
+       y2="7.5624999"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2966"
+       id="linearGradient2972"
+       x1="48.90625"
+       y1="17.376184"
+       x2="50.988335"
+       y2="22.250591"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.669292,0.000000)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2974"
+       id="linearGradient2980"
+       x1="46"
+       y1="19.8125"
+       x2="47.6875"
+       y2="22.625"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.669292,0.000000)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2984"
+       id="radialGradient2990"
+       cx="29.053354"
+       cy="27.640751"
+       fx="29.053354"
+       fy="27.640751"
+       r="3.2408544"
+       gradientTransform="matrix(2.923565,-3.911409e-24,2.471769e-23,2.029717,-61.55532,-27.88417)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2994"
+       id="linearGradient3000"
+       x1="25.71875"
+       y1="31.046875"
+       x2="25.514589"
+       y2="30.703125"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.825542,0.125000)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2865"
+       id="radialGradient3010"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.348243,1.439818e-16,26.35543)"
+       cx="23.5625"
+       cy="40.4375"
+       fx="23.5625"
+       fy="40.4375"
+       r="19.5625" />
+  </defs>
+  <sodipodi:namedview
+     stroke="#c4a000"
+     fill="#edd400"
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="0.25490196"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="14.928934"
+     inkscape:cy="7.6822472"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:showpageshadow="false"
+     inkscape:window-width="872"
+     inkscape:window-height="659"
+     inkscape:window-x="195"
+     inkscape:window-y="221" />
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+        <dc:title>Text Editor</dc:title>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Attribution" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <g
+       transform="matrix(2.417561e-2,0,0,2.086758e-2,45.12765,40.1536)"
+       id="g6707">
+      <rect
+         style="opacity:0.40206185;color:black;fill:url(#linearGradient6715);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect6709"
+         width="1339.6335"
+         height="478.35718"
+         x="-1559.2523"
+         y="-150.69685" />
+      <path
+         style="opacity:0.40206185;color:black;fill:url(#radialGradient6717);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z "
+         id="path6711"
+         sodipodi:nodetypes="cccc" />
+      <path
+         sodipodi:nodetypes="cccc"
+         id="path6713"
+         d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z "
+         style="opacity:0.40206185;color:black;fill:url(#radialGradient6719);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    </g>
+    <path
+       style="color:#000000;fill:url(#linearGradient2861);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2879);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 7.1638699,4.5063726 L 39.813122,4.5063726 C 40.575699,4.5063726 41.189615,5.0388241 41.189615,5.7002099 C 41.189615,5.7002099 43.590945,39.868907 43.590945,39.868907 C 43.590945,39.868907 43.603403,42.216529 43.603403,42.216529 C 43.603403,42.877915 42.989488,43.410366 42.226911,43.410366 L 4.750081,43.410366 C 3.9875042,43.410366 3.3735887,42.877915 3.3735887,42.216529 L 3.3624173,40.049613 L 5.7873775,5.7002099 C 5.7873775,5.0388241 6.4012931,4.5063726 7.1638699,4.5063726 z "
+       id="rect1975"
+       sodipodi:nodetypes="ccccccccccc" />
+    <path
+       transform="matrix(0.616613,0.000000,0.000000,0.440367,10.61425,13.94266)"
+       d="M 43.125 40.4375 A 19.5625 6.8125 0 1 1  4,40.4375 A 19.5625 6.8125 0 1 1  43.125 40.4375 z"
+       sodipodi:ry="6.8125"
+       sodipodi:rx="19.5625"
+       sodipodi:cy="40.4375"
+       sodipodi:cx="23.5625"
+       id="path3008"
+       style="opacity:0.31578944;color:#000000;fill:url(#radialGradient3010);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       sodipodi:type="arc" />
+    <rect
+       style="opacity:1;color:#000000;fill:#a4a4a4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       id="rect2851"
+       width="39.048077"
+       height="3.0714951"
+       x="3.9770372"
+       y="39.868271"
+       rx="0.67937863"
+       ry="0.67937863" />
+    <path
+       style="opacity:1;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 3.9267507,40.442796 C 3.9267507,40.442796 4.0776125,39.912466 4.6307727,39.868272 L 42.195375,39.868272 C 42.949684,39.868272 42.999971,40.619573 42.999971,40.619573 C 42.999971,40.619573 43.02357,39 41.7161,39 L 5.3042159,39 C 4.2984702,39.088388 3.9267507,39.779883 3.9267507,40.442796 z "
+       id="path2853"
+       sodipodi:nodetypes="ccccccc" />
+    <path
+       style="opacity:1;color:#000000;fill:url(#linearGradient2925);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 6.25,5.7343749 L 6,10.125 C 6,10.125 6.3125,8.9999999 7,8.9999999 L 40.125,8.9999999 C 40.828125,8.9843749 40.859375,9.3124999 40.984375,9.8281249 C 40.984375,9.8281249 40.734375,5.9531249 40.734375,5.9531249 C 40.703125,5.4062499 40.515625,4.9999999 39.953125,4.9999999 L 7.0625,4.9999999 C 6.609375,4.9999999 6.296875,5.3437499 6.25,5.7343749 z "
+       id="path2915"
+       sodipodi:nodetypes="ccccccccc" />
+    <path
+       sodipodi:nodetypes="ccccccccccc"
+       id="path2917"
+       d="M 7.8126474,5.5404503 L 38.944983,5.5404503 C 39.66702,5.5404503 40.2483,5.3883462 40.2483,6.014572 C 40.2483,6.014572 42.521973,39.023077 42.521973,39.023077 C 42.521973,39.023077 42.622156,41.732033 42.622156,41.732033 C 42.622156,42.358259 42.48282,42.376269 41.760782,42.376269 L 4.8620444,42.376269 C 4.4493662,42.376269 4.4426114,42.269871 4.4426114,41.864615 L 4.4320338,39.194177 L 6.7280807,6.045822 C 6.7280807,5.4195962 7.09061,5.5404503 7.8126474,5.5404503 z "
+       style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999946;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;opacity:0.43859649" />
+    <g
+       id="g2950">
+      <rect
+         ry="1"
+         rx="1"
+         y="2.5"
+         x="8.5"
+         height="5"
+         width="2"
+         id="rect2899"
+         style="opacity:1;color:#000000;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#886f00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <rect
+         style="opacity:1;color:#000000;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#886f00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect2901"
+         width="2"
+         height="5"
+         x="12.5"
+         y="2.5"
+         rx="1"
+         ry="1" />
+      <rect
+         ry="1"
+         rx="1"
+         y="2.5"
+         x="16.5"
+         height="5"
+         width="2"
+         id="rect2903"
+         style="opacity:1;color:#000000;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#886f00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <rect
+         style="opacity:1;color:#000000;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#886f00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect2905"
+         width="2"
+         height="5"
+         x="20.5"
+         y="2.5"
+         rx="1"
+         ry="1" />
+      <rect
+         ry="1"
+         rx="1"
+         y="2.5"
+         x="24.5"
+         height="5"
+         width="2"
+         id="rect2907"
+         style="opacity:1;color:#000000;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#886f00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <rect
+         style="opacity:1;color:#000000;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#886f00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect2909"
+         width="2"
+         height="5"
+         x="28.5"
+         y="2.5"
+         rx="1"
+         ry="1" />
+      <rect
+         ry="1"
+         rx="1"
+         y="2.5"
+         x="32.5"
+         height="5"
+         width="2"
+         id="rect2911"
+         style="opacity:1;color:#000000;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#886f00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <rect
+         style="opacity:1;color:#000000;fill:#fce94f;fill-opacity:1;fill-rule:evenodd;stroke:#886f00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect2913"
+         width="2"
+         height="5"
+         x="36.5"
+         y="2.5"
+         rx="1"
+         ry="1" />
+    </g>
+    <g
+       id="g2941">
+      <rect
+         y="12"
+         x="9"
+         height="1"
+         width="29"
+         id="rect2927"
+         style="opacity:0.28070175;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <rect
+         style="opacity:0.28070176;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect2929"
+         width="29"
+         height="1"
+         x="9"
+         y="14.981792" />
+      <rect
+         y="18.003939"
+         x="9"
+         height="1"
+         width="13"
+         id="rect2931"
+         style="opacity:0.28070176;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <rect
+         style="opacity:0.28070176;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect2933"
+         width="29"
+         height="1"
+         x="9"
+         y="22.985731" />
+      <rect
+         y="26.007877"
+         x="9"
+         height="1"
+         width="29"
+         id="rect2935"
+         style="opacity:0.28070176;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <rect
+         style="opacity:0.28070176;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         id="rect2937"
+         width="29"
+         height="1"
+         x="9"
+         y="29.030024" />
+      <rect
+         y="32.05217"
+         x="9"
+         height="1"
+         width="8"
+         id="rect2939"
+         style="opacity:0.28070176;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    </g>
+    <path
+       style="opacity:1;color:#000000;fill:#cb9022;fill-opacity:1;fill-rule:evenodd;stroke:#5c410c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 17.34116,32.5 L 22.96616,26.875 L 43.059909,17.125 C 46.309909,15.875 48.247409,20.5 45.372409,22.125 L 25.34116,31.5 L 17.34116,32.5 z "
+       id="path2960"
+       sodipodi:nodetypes="cccccc" />
+    <path
+       sodipodi:nodetypes="czcczcc"
+       id="path2964"
+       d="M 38.330708,20 C 38.330708,20 39.768208,20.09375 40.330708,21.34375 C 40.910201,22.631511 40.330708,24 40.330708,24 L 45.361958,21.53125 C 45.361958,21.53125 46.81399,20.649883 46.018208,18.6875 C 45.233296,16.751923 43.330708,17.53125 43.330708,17.53125 L 38.330708,20 z "
+       style="opacity:1;color:#000000;fill:url(#linearGradient2972);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+    <path
+       style="opacity:1;color:#000000;fill:url(#linearGradient2980);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 38.330708,20 C 38.330708,20 39.768208,20.09375 40.330708,21.34375 C 40.910201,22.631511 40.330708,24 40.330708,24 L 42.330708,23 C 42.330708,23 43.15774,21.681133 42.549458,20.3125 C 41.924458,18.90625 40.330708,19 40.330708,19 L 38.330708,20 z "
+       id="path2962"
+       sodipodi:nodetypes="czcczcc" />
+    <path
+       style="opacity:1;color:#000000;fill:url(#radialGradient2990);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 18.768208,31.78125 L 23.268208,27.28125 C 24.768208,28.09375 25.549458,29.4375 25.143208,31 L 18.768208,31.78125 z "
+       id="path2982"
+       sodipodi:nodetypes="cccc" />
+    <path
+       style="opacity:1;color:#000000;fill:url(#linearGradient3000);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 20.111958,30.375 L 18.486958,31.96875 L 20.830708,31.65625 C 21.049458,30.9375 20.643208,30.59375 20.111958,30.375 z "
+       id="path2992"
+       sodipodi:nodetypes="cccc" />
+    <path
+       style="opacity:1;color:#000000;fill:#ffffff;fill-opacity:0.36363639;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 23.268208,27.25 L 24.830708,28.5 L 40.218048,21.18133 C 39.773616,20.325286 38.976281,20.096733 38.314669,20.019068 L 23.268208,27.25 z "
+       id="path3002"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       style="opacity:1;color:#000000;fill:#000000;fill-opacity:0.36363639;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 25.143208,31.0625 L 25.330708,30.3125 L 40.561798,23.1829 C 40.561798,23.1829 40.451638,23.796527 40.345919,23.93225 L 25.143208,31.0625 z "
+       id="path3004"
+       sodipodi:nodetypes="ccccc" />
+  </g>
+</svg>
diff --git a/mousepad/Makefile.am b/mousepad/Makefile.am
new file mode 100644
index 0000000..3dfb8ac
--- /dev/null
+++ b/mousepad/Makefile.am
@@ -0,0 +1,118 @@
+INCLUDES = \
+	-I$(top_builddir) \
+	-I$(top_srcdir) \
+	-DBINDIR=\"$(bindir)\" \
+	-DDATADIR=\"$(datadir)\" \
+	-DLIBDIR=\"$(libdir)\" \
+	-DG_LOG_DOMAIN=\"Mousepad\" \
+	-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
+	-DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES \
+	-DGTK_DISABLE_SINGLE_INCLUDES \
+	$(PLATFORM_CPPFLAGS)
+
+bin_PROGRAMS = \
+	mousepad
+
+mousepad_built_sources = \
+	mousepad-marshal.c \
+	mousepad-marshal.h
+
+mousepad_SOURCES = \
+	$(mousepad_built_sources) \
+	$(mousepad_dbus_sources) \
+	main.c \
+	mousepad-application.c \
+	mousepad-application.h \
+	mousepad-dialogs.c \
+	mousepad-dialogs.h \
+	mousepad-document.c \
+	mousepad-document.h \
+	mousepad-encoding.c \
+	mousepad-encoding.h \
+	mousepad-encoding-dialog.c \
+	mousepad-encoding-dialog.h \
+	mousepad-file.c \
+	mousepad-file.h \
+	mousepad-preferences.c \
+	mousepad-preferences.h \
+	mousepad-print.c \
+	mousepad-print.h \
+	mousepad-private.h \
+	mousepad-replace-dialog.c \
+	mousepad-replace-dialog.h \
+	mousepad-search-bar.c \
+	mousepad-search-bar.h \
+	mousepad-statusbar.c \
+	mousepad-statusbar.h \
+	mousepad-view.c \
+	mousepad-view.h \
+	mousepad-util.c \
+	mousepad-util.h \
+	mousepad-window.c \
+	mousepad-window.h \
+	mousepad-window-ui.h
+
+mousepad_CFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(GTK_CFLAGS) \
+	$(GTHREAD_CFLAGS) \
+	$(GTKSOURCEVIEW_CFLAGS) \
+	$(PLATFORM_CFLAGS)
+
+mousepad_LDFLAGS = \
+	-no-undefined \
+	$(PLATFORM_LDFLAGS)
+
+mousepad_LDADD = \
+	$(GLIB_LIBS) \
+	$(GTK_LIBS)	\
+	$(GTHREAD_LIBS) \
+	$(GTKSOURCEVIEW_LIBS)
+
+if HAVE_DBUS
+mousepad_built_sources +=	\
+	mousepad-dbus-infos.h
+
+mousepad_dbus_sources = \
+	mousepad-dbus.c \
+	mousepad-dbus.h
+
+mousepad_CFLAGS += \
+	-DDBUS_API_SUBJECT_TO_CHANGE \
+	$(DBUS_CFLAGS)
+
+mousepad_LDADD +=	\
+	$(DBUS_LIBS)
+endif
+
+if MAINTAINER_MODE
+DISTCLEANFILES = \
+	$(mousepad_built_sources) \
+	mousepad-window-ui.h
+
+BUILT_SOURCES = \
+	$(mousepad_built_sources) \
+	mousepad-window-ui.h
+
+if HAVE_DBUS
+mousepad-dbus-infos.h: mousepad-dbus-infos.xml Makefile
+	$(AM_V_GEN) dbus-binding-tool --prefix=mousepad_dbus_service --mode=glib-server $< > $@
+endif
+
+mousepad-window-ui.h: mousepad-window-ui.xml Makefile
+	$(AM_V_GEN) exo-csource --strip-comments --strip-content --static --name=mousepad_window_ui $< > $@
+
+mousepad-marshal.h: mousepad-marshal.list Makefile
+	$(AM_V_GEN) glib-genmarshal --header --prefix=_mousepad_marshal $< > $@
+
+mousepad-marshal.c: mousepad-marshal.list Makefile
+	$(AM_V_GEN) echo "#include <mousepad/mousepad-marshal.h>" > $@ \
+	&& glib-genmarshal --body --prefix=_mousepad_marshal $< >> $@
+endif
+
+EXTRA_DIST = \
+	mousepad-dbus-infos.xml \
+	mousepad-marshal.list \
+	mousepad-window-ui.xml
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/mousepad/main.c b/mousepad/main.c
new file mode 100644
index 0000000..22e69eb
--- /dev/null
+++ b/mousepad/main.c
@@ -0,0 +1,202 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_LIBINTL_H
+#include <libintl.h>
+#endif
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-application.h>
+
+#ifdef HAVE_DBUS
+#include <mousepad/mousepad-dbus.h>
+#endif
+
+
+/* globals */
+static gchar    **filenames = NULL;
+static gboolean   opt_version = FALSE;
+#ifdef HAVE_DBUS
+static gboolean   opt_disable_server = FALSE;
+static gboolean   opt_quit = FALSE;
+#endif
+
+
+
+/* command line options */
+static const GOptionEntry option_entries[] =
+{
+#ifdef HAVE_DBUS
+  { "disable-server", '\0', 0, G_OPTION_ARG_NONE, &opt_disable_server, N_("Do not register with the D-BUS session message bus"), NULL },
+  { "quit", 'q', 0, G_OPTION_ARG_NONE, &opt_quit, N_("Quit a running Mousepad instance"), NULL },
+#endif
+  { "version", 'v', 0, G_OPTION_ARG_NONE, &opt_version, N_("Print version information and exit"), NULL },
+  { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, NULL },
+  { NULL }
+};
+
+
+
+gint
+main (gint argc, gchar **argv)
+{
+  MousepadApplication *application;
+  GError              *error = NULL;
+  gchar               *working_directory;
+#ifdef HAVE_DBUS
+  MousepadDBusService *dbus_service;
+#endif
+
+  /* bind the text domain to the locale directory */
+  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
+
+  /* set the package textdomain */
+  textdomain (GETTEXT_PACKAGE);
+
+  /* default application name */
+  g_set_application_name (_("Mousepad"));
+
+#ifdef G_ENABLE_DEBUG
+  /* crash when something went wrong */
+  g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
+#endif
+
+  /* initialize the gthread system */
+  if (G_LIKELY (!g_thread_supported ()))
+    g_thread_init (NULL);
+
+  /* initialize gtk+ */
+  if (!gtk_init_with_args (&argc, &argv, _("[FILES...]"), (GOptionEntry *) option_entries, (gchar *) GETTEXT_PACKAGE, &error))
+    {
+      /* check if we have an error message */
+      if (G_LIKELY (error == NULL))
+        {
+          /* no error message, the gui initialization failed */
+          g_error ("%s", _("Failed to open display."));
+        }
+      else
+        {
+          /* print the error message */
+          g_error ("%s", error->message);
+          g_error_free (error);
+        }
+
+      return EXIT_FAILURE;
+    }
+
+  /* check if we should print version information */
+  if (G_UNLIKELY (opt_version))
+    {
+      g_print ("%s %s\n\n", PACKAGE_NAME, PACKAGE_VERSION);
+      g_print ("%s\n", "Copyright (c) 2007");
+      g_print ("\t%s\n\n", _("The Xfce development team. All rights reserved."));
+      g_print (_("Please report bugs to <%s>."), PACKAGE_BUGREPORT);
+      g_print ("\n");
+
+      return EXIT_SUCCESS;
+    }
+
+#ifdef HAVE_DBUS
+  /* check if we need to terminate a running Mousepad instance */
+  if (G_UNLIKELY (opt_quit))
+    {
+      /* try to terminate whatever is running */
+      if (!mousepad_dbus_client_terminate (&error))
+        {
+          g_error ("Failed to terminate a running instance: %s\n", error->message);
+          g_error_free (error);
+          return EXIT_FAILURE;
+        }
+
+      return EXIT_SUCCESS;
+    }
+#endif /* !HAVE_DBUS */
+
+  /* get the current working directory */
+  working_directory = g_get_current_dir ();
+
+#ifdef HAVE_DBUS
+  if (G_LIKELY (!opt_disable_server))
+    {
+      /* check if we can reuse an existing instance */
+      if (mousepad_dbus_client_launch_files (filenames, working_directory, &error))
+        {
+          /* stop any running startup notification */
+          gdk_notify_startup_complete ();
+
+          /* cleanup */
+          g_free (working_directory);
+          g_strfreev (filenames);
+
+          /* print errors, if needed */
+          if (G_UNLIKELY (error))
+            {
+              g_error ("Mousepad: %s\n", error->message);
+              g_error_free (error);
+
+              return EXIT_FAILURE;
+            }
+
+          return EXIT_SUCCESS;
+        }
+    }
+#endif /* !HAVE_DBUS */
+
+  /* use the Mousepad icon as default for new windows */
+  gtk_window_set_default_icon_name ("Mousepad");
+
+  /* create a new mousepad application */
+  application = mousepad_application_get ();
+
+  /* open an empty window (with an empty document or the files) */
+  mousepad_application_new_window_with_files (application, NULL, working_directory, filenames);
+
+  /* cleanup */
+  g_free (working_directory);
+  g_strfreev (filenames);
+
+  /* do not enter the main loop, unless we have atleast one window */
+  if (G_LIKELY (mousepad_application_has_windows (application)))
+    {
+#ifdef HAVE_DBUS
+      /* register with dbus */
+      dbus_service = g_object_new (MOUSEPAD_TYPE_DBUS_SERVICE, NULL);
+#endif
+
+      /* enter the main loop */
+      gtk_main ();
+
+#ifdef HAVE_DBUS
+      /* release dbus service reference */
+      g_object_unref (G_OBJECT (dbus_service));
+#endif
+    }
+
+  /* release application reference */
+  g_object_unref (G_OBJECT (application));
+
+  return EXIT_SUCCESS;
+}
diff --git a/mousepad/mousepad-application.c b/mousepad/mousepad-application.c
new file mode 100644
index 0000000..cb7c778
--- /dev/null
+++ b/mousepad/mousepad-application.c
@@ -0,0 +1,299 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-application.h>
+#include <mousepad/mousepad-document.h>
+#include <mousepad/mousepad-replace-dialog.h>
+#include <mousepad/mousepad-window.h>
+
+
+
+static void        mousepad_application_finalize                  (GObject                   *object);
+static void        mousepad_application_window_destroyed          (GtkWidget                 *window,
+                                                                   MousepadApplication        *application);
+static GtkWidget  *mousepad_application_create_window             (MousepadApplication        *application);
+static void        mousepad_application_new_window_with_document  (MousepadWindow             *existing,
+                                                                   MousepadDocument           *document,
+                                                                   gint                        x,
+                                                                   gint                        y,
+                                                                   MousepadApplication        *application);
+static void        mousepad_application_new_window                (MousepadWindow             *existing,
+                                                                   MousepadApplication        *application);
+
+
+
+struct _MousepadApplicationClass
+{
+  GObjectClass __parent__;
+};
+
+struct _MousepadApplication
+{
+  GObject  __parent__;
+
+  /* internal list of all the opened windows */
+  GSList  *windows;
+};
+
+
+
+G_DEFINE_TYPE (MousepadApplication, mousepad_application, G_TYPE_OBJECT);
+
+
+
+static void
+mousepad_application_class_init (MousepadApplicationClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_application_finalize;
+}
+
+
+
+static void
+mousepad_application_init (MousepadApplication *application)
+{
+  gchar *filename;
+
+  /* check if we have a saved accel map */
+  filename = mousepad_util_get_save_location (MOUSEPAD_ACCELS_RELPATH, FALSE);
+  if (G_LIKELY (filename != NULL))
+    {
+      /* load the accel map */
+      gtk_accel_map_load (filename);
+
+      /* cleanup */
+      g_free (filename);
+    }
+}
+
+
+
+static void
+mousepad_application_finalize (GObject *object)
+{
+  MousepadApplication *application = MOUSEPAD_APPLICATION (object);
+  GSList              *li;
+  gchar               *filename;
+
+  /* flush the history items of the replace dialog
+   * this is a bit of an ugly place, but cleaning on a window close
+   * isn't a good option eighter */
+  mousepad_replace_dialog_history_clean ();
+
+  /* save the current accel map */
+  filename = mousepad_util_get_save_location (MOUSEPAD_ACCELS_RELPATH, TRUE);
+  if (G_LIKELY (filename != NULL))
+    {
+      /* save the accel map */
+      gtk_accel_map_save (filename);
+
+      /* cleanup */
+      g_free (filename);
+    }
+
+  /* destroy the windows if they are still opened */
+  for (li = application->windows; li != NULL; li = li->next)
+    {
+      g_signal_handlers_disconnect_by_func (G_OBJECT (li->data), G_CALLBACK (mousepad_application_window_destroyed), application);
+      gtk_widget_destroy (GTK_WIDGET (li->data));
+    }
+
+  /* cleanup the list of windows */
+  g_slist_free (application->windows);
+
+  (*G_OBJECT_CLASS (mousepad_application_parent_class)->finalize) (object);
+}
+
+
+
+MousepadApplication*
+mousepad_application_get (void)
+{
+  static MousepadApplication *application = NULL;
+
+  if (G_UNLIKELY (application == NULL))
+    {
+      application = g_object_new (MOUSEPAD_TYPE_APPLICATION, NULL);
+      g_object_add_weak_pointer (G_OBJECT (application), (gpointer) &application);
+    }
+  else
+    {
+      g_object_ref (G_OBJECT (application));
+    }
+
+  return application;
+}
+
+
+
+gboolean
+mousepad_application_has_windows (MousepadApplication *application)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_APPLICATION (application), FALSE);
+
+  return (application->windows != NULL);
+}
+
+
+
+static void
+mousepad_application_window_destroyed (GtkWidget           *window,
+                                       MousepadApplication *application)
+{
+  mousepad_return_if_fail (GTK_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_APPLICATION (application));
+  mousepad_return_if_fail (g_slist_find (application->windows, window) != NULL);
+
+  /* remove the window from the list */
+  application->windows = g_slist_remove (application->windows, window);
+
+  /* quit if there are no windows opened */
+  if (application->windows == NULL)
+    gtk_main_quit ();
+}
+
+
+
+void
+mousepad_application_take_window (MousepadApplication *application,
+                                  GtkWindow           *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_APPLICATION (application));
+  mousepad_return_if_fail (g_slist_find (application->windows, window) == NULL);
+
+  /* connect to the "destroy" signal */
+  g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (mousepad_application_window_destroyed), application);
+
+  /* add the window to our internal list */
+  application->windows = g_slist_prepend (application->windows, window);
+}
+
+
+
+static GtkWidget *
+mousepad_application_create_window (MousepadApplication *application)
+{
+  GtkWidget *window;
+
+  /* create a new window */
+  window = mousepad_window_new ();
+
+  /* hook up the new window */
+  mousepad_application_take_window (application, GTK_WINDOW (window));
+
+  /* connect signals */
+  g_signal_connect (G_OBJECT (window), "new-window-with-document", G_CALLBACK (mousepad_application_new_window_with_document), application);
+  g_signal_connect (G_OBJECT (window), "new-window", G_CALLBACK (mousepad_application_new_window), application);
+
+  return window;
+}
+
+
+
+static void
+mousepad_application_new_window_with_document (MousepadWindow      *existing,
+                                               MousepadDocument    *document,
+                                               gint                 x,
+                                               gint                 y,
+                                               MousepadApplication *application)
+{
+  GtkWidget *window;
+  GdkScreen *screen;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (existing));
+  mousepad_return_if_fail (document == NULL || MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (MOUSEPAD_IS_APPLICATION (application));
+
+  /* create a new window (signals added and already hooked up) */
+  window = mousepad_application_create_window (application);
+
+  /* place the new window on the same screen as the existing window */
+  screen = gtk_window_get_screen (GTK_WINDOW (existing));
+  if (G_LIKELY (screen != NULL))
+    gtk_window_set_screen (GTK_WINDOW (window), screen);
+
+  /* move the window on valid cooridinates */
+  if (x > -1 && y > -1)
+    gtk_window_move (GTK_WINDOW (window), x, y);
+
+  /* create an empty document if no document was send */
+  if (document == NULL)
+    document = mousepad_document_new ();
+
+  /* add the document to the new window */
+  mousepad_window_add (MOUSEPAD_WINDOW (window), document);
+
+  /* show the window */
+  gtk_widget_show (window);
+}
+
+
+
+static void
+mousepad_application_new_window (MousepadWindow      *existing,
+                                 MousepadApplication *application)
+{
+  /* trigger new document function */
+  mousepad_application_new_window_with_document (existing, NULL, -1, -1, application);
+}
+
+
+
+void
+mousepad_application_new_window_with_files (MousepadApplication  *application,
+                                            GdkScreen            *screen,
+                                            const gchar          *working_directory,
+                                            gchar               **filenames)
+{
+  GtkWidget        *window;
+  gboolean          succeed = FALSE;
+  MousepadDocument *document;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_APPLICATION (application));
+  mousepad_return_if_fail (screen == NULL || GDK_IS_SCREEN (screen));
+
+  /* create a new window (signals added and already hooked up) */
+  window = mousepad_application_create_window (application);
+
+  /* place the window on the right screen */
+  gtk_window_set_screen (GTK_WINDOW (window), screen ? screen : gdk_screen_get_default ());
+
+  /* try to open the files */
+  if (working_directory && filenames && g_strv_length (filenames))
+    succeed = mousepad_window_open_files (MOUSEPAD_WINDOW (window), working_directory, filenames);
+
+  /* open an empty document */
+  if (succeed == FALSE)
+    {
+      /* create a new document */
+      document = mousepad_document_new ();
+
+      /* add the document to the new window */
+      mousepad_window_add (MOUSEPAD_WINDOW (window), document);
+    }
+
+  /* show the window */
+  gtk_widget_show (window);
+}
diff --git a/mousepad/mousepad-application.h b/mousepad/mousepad-application.h
new file mode 100644
index 0000000..28e382c
--- /dev/null
+++ b/mousepad/mousepad-application.h
@@ -0,0 +1,48 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_APPLICATION_H__
+#define __MOUSEPAD_APPLICATION_H__
+
+G_BEGIN_DECLS
+
+typedef struct _MousepadApplicationClass MousepadApplicationClass;
+typedef struct _MousepadApplication      MousepadApplication;
+
+#define MOUSEPAD_TYPE_APPLICATION            (mousepad_application_get_type ())
+#define MOUSEPAD_APPLICATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_APPLICATION, MousepadApplication))
+#define MOUSEPAD_APPLICATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_APPLICATION, MousepadApplicationClass))
+#define MOUSEPAD_IS_APPLICATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_APPLICATION))
+#define MOUSEPAD_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOUSEPAD_TYPE_APPLICATION))
+#define MOUSEPAD_APPLICATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_APPLICATION, MousepadApplicationClass))
+
+GType                mousepad_application_get_type               (void) G_GNUC_CONST;
+
+MousepadApplication *mousepad_application_get                    (void);
+
+gboolean             mousepad_application_has_windows            (MousepadApplication  *application);
+
+void                 mousepad_application_take_window            (MousepadApplication  *application,
+                                                                  GtkWindow            *window);
+
+void                 mousepad_application_new_window_with_files  (MousepadApplication  *application,
+                                                                  GdkScreen            *screen,
+                                                                  const gchar          *working_directory,
+                                                                  gchar               **filenames);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_APPLICATION_H__ */
diff --git a/mousepad/mousepad-dbus-infos.xml b/mousepad/mousepad-dbus-infos.xml
new file mode 100644
index 0000000..3f0fab1
--- /dev/null
+++ b/mousepad/mousepad-dbus-infos.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the Free
+  Software Foundation; either version 2 of the License, or (at your option)
+  any later version.
+
+  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 General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+  Place, Suite 330, Boston, MA  02111-1307  USA
+-->
+
+<node name="/org/xfce/Mousepad">
+
+  <!--
+    org.xfce.Mousepad
+
+    The Mousepad specific interface, which provides Mousepad specific methods.
+
+    This inferface is internally used by Mousepad and should not be used externally.
+  -->
+  <interface name="org.xfce.Mousepad">
+    <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="mousepad_dbus_service" />
+
+    <!--
+      LaunchFiles (working-directory : STRING, filenames : ARRAY OF STRING : VOID
+
+      working-directory : the directory, relative to which filenames should
+                          be interpreted.
+      filenames         : an array of file names to launch. The file names may
+                          be either file:-URIs, absolute paths or paths relative
+                          to the working-directory.
+    -->
+    <method name="LaunchFiles">
+      <arg direction="in" name="working-directory" type="s" />
+      <arg direction="in" name="filenames" type="as" />
+    </method>
+
+    <!--
+      Terminate () : VOID
+
+      Tells a running Mousepad instance to terminate immediately.
+    -->
+    <method name="Terminate">
+    </method>
+
+  </interface>
+
+</node>
diff --git a/mousepad/mousepad-dbus.c b/mousepad/mousepad-dbus.c
new file mode 100644
index 0000000..8b7e769
--- /dev/null
+++ b/mousepad/mousepad-dbus.c
@@ -0,0 +1,337 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-dbus.h>
+#include <mousepad/mousepad-application.h>
+
+
+
+#define MOUSEPAD_DBUS_PATH      "/org/xfce/Mousepad"
+#define MOUSEPAD_DBUS_INTERFACE "org.xfce.Mousepad"
+
+
+
+static void      mousepad_dbus_service_finalize      (GObject              *object);
+static gboolean  mousepad_dbus_service_launch_files  (MousepadDBusService  *dbus_service,
+                                                      const gchar          *working_directory,
+                                                      gchar               **filenames,
+                                                      GError              **error);
+static gboolean  mousepad_dbus_service_terminate     (MousepadDBusService  *dbus_service,
+                                                      GError              **error);
+
+
+
+/* include the dbus glue generated by dbus-binding-tool */
+#include <mousepad/mousepad-dbus-infos.h>
+
+
+
+struct _MousepadDBusServiceClass
+{
+  GObjectClass __parent__;
+};
+
+struct _MousepadDBusService
+{
+  GObject __parent__;
+
+  DBusGConnection *connection;
+};
+
+
+
+G_DEFINE_TYPE (MousepadDBusService, mousepad_dbus_service, G_TYPE_OBJECT);
+
+
+
+static void
+mousepad_dbus_service_class_init (MousepadDBusServiceClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_dbus_service_finalize;
+
+  /* install the D-BUS info for our class */
+  dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), &dbus_glib_mousepad_dbus_service_object_info);
+}
+
+
+
+static void
+mousepad_dbus_service_init (MousepadDBusService *dbus_service)
+{
+  GError *error = NULL;
+
+  /* try to connect to the session bus */
+  dbus_service->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+
+  if (G_LIKELY (dbus_service->connection != NULL))
+    {
+      /* register the /org/xfce/TextEditor object for Mousepad */
+      dbus_g_connection_register_g_object (dbus_service->connection, MOUSEPAD_DBUS_PATH, G_OBJECT (dbus_service));
+
+      /* request the org.xfce.Mousepad name for Mousepad */
+      dbus_bus_request_name (dbus_g_connection_get_connection (dbus_service->connection),
+                             MOUSEPAD_DBUS_INTERFACE, DBUS_NAME_FLAG_REPLACE_EXISTING, NULL);
+    }
+  else
+    {
+#ifdef NDEBUG
+      /* hide this warning when the user is root and debug is disabled */
+      if (geteuid () != 0)
+#endif
+        {
+          /* notify the user that D-BUS service won't be available */
+          g_message ("Failed to connect to the D-BUS session bus: %s\n", error->message);
+        }
+
+      g_error_free (error);
+    }
+}
+
+
+
+static void
+mousepad_dbus_service_finalize (GObject *object)
+{
+  MousepadDBusService *dbus_service = MOUSEPAD_DBUS_SERVICE (object);
+
+  /* release the D-BUS connection object */
+  if (G_LIKELY (dbus_service->connection != NULL))
+    dbus_g_connection_unref (dbus_service->connection);
+
+  (*G_OBJECT_CLASS (mousepad_dbus_service_parent_class)->finalize) (object);
+}
+
+
+
+/**
+ * mousepad_dbus_service_launch_files:
+ * @dbus_service      : A #MousepadDBusService.
+ * @working_directory : The default working directory for this window.
+ * @filenames         : A list of filenames we try to open in tabs. The file names
+ *                      can either be absolute paths, supported URIs or relative file
+ *                      names to @working_directory or %NULL for an untitled document.
+ * @error             : Return location for errors, not used atm.
+ *
+ * This function is activated by DBus (service) and opens a new window in this instance of
+ * Mousepad.
+ *
+ * Return value: %TRUE on success, %FALSE if @error is set.
+ **/
+static gboolean
+mousepad_dbus_service_launch_files (MousepadDBusService  *dbus_service,
+                                    const gchar          *working_directory,
+                                    gchar               **filenames,
+                                    GError              **error)
+{
+  MousepadApplication *application;
+
+  mousepad_return_val_if_fail (g_path_is_absolute (working_directory), FALSE);
+  mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* open a mousepad window */
+  application = mousepad_application_get ();
+  mousepad_application_new_window_with_files (application, NULL, working_directory, filenames);
+  g_object_unref (G_OBJECT (application));
+
+  return TRUE;
+}
+
+
+
+/**
+ * mousepad_dbus_service_terminate:
+ * @dbus_service : A #MousepadDBusService.
+ * @error        : Return location for errors, not used atm.
+ *
+ * This function quits this instance of Mousepad.
+ *
+ * Return value: %TRUE on success.
+ **/
+static gboolean
+mousepad_dbus_service_terminate (MousepadDBusService  *dbus_service,
+                                 GError              **error)
+{
+  /* leave the Gtk main loop as soon as possible */
+  gtk_main_quit ();
+
+  /* we cannot fail */
+  return TRUE;
+}
+
+
+
+/**
+ * mousepad_dbus_client_send:
+ * @message : A #DBusMessage.
+ * @error   : Return location for errors or %NULL.
+ *
+ * This function sends the DBus message and should avoid
+ * code duplication in the functions below.
+ *
+ * Return value: %TRUE on succeed or %FALSE if @error is set.
+ **/
+static gboolean
+mousepad_dbus_client_send (DBusMessage  *message,
+                           GError      **error)
+{
+  DBusConnection *connection;
+  DBusMessage    *result;
+  DBusError       derror;
+
+  dbus_error_init (&derror);
+
+  /* try to connect to the session bus */
+  connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
+  if (G_UNLIKELY (connection == NULL))
+    {
+      dbus_set_g_error (error, &derror);
+      dbus_error_free (&derror);
+      return FALSE;
+    }
+
+  /* send the message */
+  result = dbus_connection_send_with_reply_and_block (connection, message, -1, &derror);
+
+  /* check if no reply was received */
+  if (result == NULL)
+    {
+      /* check if there was just no instance running */
+      if (!dbus_error_has_name (&derror, DBUS_ERROR_NAME_HAS_NO_OWNER))
+        dbus_set_g_error (error, &derror);
+
+      dbus_error_free (&derror);
+      return FALSE;
+    }
+
+  /* but maybe we received an error */
+  if (G_UNLIKELY (dbus_message_get_type (result) == DBUS_MESSAGE_TYPE_ERROR))
+    {
+      dbus_set_error_from_message (&derror, result);
+      dbus_set_g_error (error, &derror);
+      dbus_message_unref (result);
+      dbus_error_free (&derror);
+      return FALSE;
+    }
+
+  /* it seems everything worked */
+  dbus_message_unref (result);
+
+  return TRUE;
+}
+
+
+
+/**
+ * mousepad_dbus_client_terminate:
+ * @error : Return location for errors or %NULL.
+ *
+ * Function called from this instance of the application and tries to invoke
+ * with an already running instance and ties to quit it.
+ * The mousepad_dbus_service_terminate function is activated in the running instance.
+ *
+ * Return value: %TRUE on success.
+ **/
+gboolean
+mousepad_dbus_client_terminate (GError **error)
+{
+  DBusMessage *message;
+
+  mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* generate the message */
+  message = dbus_message_new_method_call (MOUSEPAD_DBUS_INTERFACE, MOUSEPAD_DBUS_PATH,
+                                          MOUSEPAD_DBUS_INTERFACE, "Terminate");
+  dbus_message_set_auto_start (message, FALSE);
+
+
+  /* send the message */
+  mousepad_dbus_client_send (message, error);
+
+  /* unref the message */
+  dbus_message_unref (message);
+
+  /* we return false if an error was set */
+  return (error != NULL);
+}
+
+
+
+/**
+ * mousepad_dbus_client_launch_files:
+ * @filenames         : A list of filenames we try to open in tabs. The file names
+ *                      can either be absolute paths, supported URIs or relative file
+ *                      names to @working_directory or %NULL for an untitled document.
+ * @working_directory : Working directory for the new Mousepad window.
+ * @error             : Return location for errors or %NULL.
+ *
+ * This function is called within this instance and tries to connect a running instance
+ * of Mousepad via DBus. The function mousepad_dbus_service_launch_files is activated in the
+ * running instance.
+ *
+ * Return value: %TRUE on success.
+ **/
+gboolean
+mousepad_dbus_client_launch_files (gchar       **filenames,
+                                   const gchar  *working_directory,
+                                   GError      **error)
+{
+  DBusMessage *message;
+  guint        length = 0;
+  gboolean     succeed;
+
+  mousepad_return_val_if_fail (g_path_is_absolute (working_directory), FALSE);
+  mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* get the length of the filesname string */
+  if (filenames)
+    length = g_strv_length (filenames);
+
+  /* generate the message */
+  message = dbus_message_new_method_call (MOUSEPAD_DBUS_INTERFACE, MOUSEPAD_DBUS_PATH,
+                                          MOUSEPAD_DBUS_INTERFACE, "LaunchFiles");
+  dbus_message_set_auto_start (message, FALSE);
+  dbus_message_append_args (message,
+                            DBUS_TYPE_STRING, &working_directory,
+                            DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &filenames, length,
+                            DBUS_TYPE_INVALID);
+
+  /* send the message */
+  succeed = mousepad_dbus_client_send (message, error);
+
+  /* unref the message */
+  dbus_message_unref (message);
+
+  return succeed;
+}
diff --git a/mousepad/mousepad-dbus.h b/mousepad/mousepad-dbus.h
new file mode 100644
index 0000000..e38ec44
--- /dev/null
+++ b/mousepad/mousepad-dbus.h
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_DBUS_H__
+#define __MOUSEPAD_DBUS_H__
+
+typedef struct _MousepadDBusServiceClass MousepadDBusServiceClass;
+typedef struct _MousepadDBusService      MousepadDBusService;
+
+#define MOUSEPAD_TYPE_DBUS_SERVICE            (mousepad_dbus_service_get_type ())
+#define MOUSEPAD_DBUS_SERVICE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_DBUS_SERVICE, MousepadDBusService))
+#define MOUSEPAD_DBUS_SERVICE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_DBUS_SERVICE, MousepadDBusServiceClass))
+#define MOUSEPAD_IS_DBUS_SERVICE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_DBUS_SERVICE))
+#define MOUSEPAD_IS_DBUS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOUSEPAD_TYPE_DBUS_BRIGDE))
+#define MOUSEPAD_DBUS_SERVICE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_DBUS_SERVICE, MousepadDBusServiceClass))
+
+GType     mousepad_dbus_service_get_type    (void) G_GNUC_CONST;
+
+gboolean  mousepad_dbus_client_terminate    (GError      **error);
+
+gboolean  mousepad_dbus_client_launch_files (gchar       **filenames,
+                                             const gchar  *working_directory,
+                                             GError      **error);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_DBUS_H__ */
diff --git a/mousepad/mousepad-dialogs.c b/mousepad/mousepad-dialogs.c
new file mode 100644
index 0000000..28271d2
--- /dev/null
+++ b/mousepad/mousepad-dialogs.c
@@ -0,0 +1,453 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-dialogs.h>
+#include <mousepad/mousepad-util.h>
+
+
+
+void
+mousepad_dialogs_show_about (GtkWindow *parent)
+{
+  static const gchar *authors[] =
+  {
+    "Nick Schermer <nick at xfce.org>",
+    "Erik Harrison <erikharrison at xfce.org>",
+    NULL
+  };
+
+  /* show the dialog */
+  gtk_show_about_dialog (parent,
+                         "authors", authors,
+                         "comments", _("Mousepad is a fast text editor for the Xfce Desktop Environment."),
+                         "destroy-with-parent", TRUE,
+                         "logo-icon-name", "accessories-text-editor",
+#if GTK_CHECK_VERSION (2,12,0)
+                         "program-name", PACKAGE_NAME,
+#else
+                         "name", PACKAGE_NAME,
+#endif
+                         "version", PACKAGE_VERSION,
+                         "translator-credits", _("translator-credits"),
+                         "website", "http://www.xfce.org/",
+                         NULL);
+}
+
+
+
+void
+mousepad_dialogs_show_error (GtkWindow    *parent,
+                             const GError *error,
+                             const gchar  *message)
+{
+  GtkWidget *dialog;
+
+  /* create the warning dialog */
+  dialog = gtk_message_dialog_new (parent,
+                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                   GTK_MESSAGE_ERROR,
+                                   GTK_BUTTONS_CLOSE,
+                                   "%s.", message);
+
+  /* set secondary text if an error is provided */
+  if (G_LIKELY (error != NULL))
+    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s.", error->message);
+
+  /* display the dialog */
+  gtk_dialog_run (GTK_DIALOG (dialog));
+
+  /* cleanup */
+  gtk_widget_destroy (dialog);
+}
+
+
+
+void
+mousepad_dialogs_show_help (GtkWindow   *parent,
+                            const gchar *page,
+                            const gchar *offset)
+{
+  GdkScreen *screen;
+  GError    *error = NULL;
+  gchar     *command;
+  gchar     *tmp;
+
+  /* get screen */
+  if (G_LIKELY (parent))
+    screen = gtk_widget_get_screen (GTK_WIDGET (parent));
+  else
+    screen = gdk_screen_get_default ();
+
+  /* generate the command for the documentation browser */
+  command = g_strdup (LIBDIR G_DIR_SEPARATOR_S "xfce4" G_DIR_SEPARATOR_S "mousepad" G_DIR_SEPARATOR_S "MousepadHelp");
+
+  /* check if a page is given */
+  if (G_UNLIKELY (page != NULL))
+    {
+      /* append page as second parameter */
+      tmp = g_strconcat (command, " ", page, NULL);
+      g_free (command);
+      command = tmp;
+
+      /* check if an offset is given */
+      if (G_UNLIKELY (offset != NULL))
+        {
+          /* append offset as third parameter */
+          tmp = g_strconcat (command, " ", offset, NULL);
+          g_free (command);
+          command = tmp;
+        }
+    }
+
+  /* try to run the documentation browser */
+  if (!gdk_spawn_command_line_on_screen (screen, command, &error))
+    {
+      /* display an error message to the user */
+      mousepad_dialogs_show_error (parent, error, _("Failed to open the documentation browser"));
+      g_error_free (error);
+    }
+
+  /* cleanup */
+  g_free (command);
+}
+
+
+
+gint
+mousepad_dialogs_other_tab_size (GtkWindow *parent,
+                                 gint      active_size)
+{
+  GtkWidget *dialog;
+  GtkWidget *scale;
+
+  /* build dialog */
+  dialog = gtk_dialog_new_with_buttons (_("Select Tab Size"),
+                                        parent,
+                                        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+                                        GTK_STOCK_CANCEL, MOUSEPAD_RESPONSE_CANCEL,
+                                        GTK_STOCK_OK, MOUSEPAD_RESPONSE_OK,
+                                        NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_OK);
+
+  /* create scale widget */
+  scale = gtk_hscale_new_with_range (1, 32, 1);
+  gtk_range_set_value (GTK_RANGE (scale), active_size);
+  gtk_scale_set_digits (GTK_SCALE (scale), 0);
+  gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
+  gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), scale, TRUE, TRUE, 0);
+  gtk_widget_show (scale);
+
+  /* run the dialog */
+  if (gtk_dialog_run (GTK_DIALOG (dialog)) == MOUSEPAD_RESPONSE_OK)
+    active_size = gtk_range_get_value (GTK_RANGE (scale));
+
+  /* destroy the dialog */
+  gtk_widget_destroy (dialog);
+
+  return active_size;
+}
+
+
+
+static void
+mousepad_dialogs_go_to_line_changed (GtkSpinButton *line_spin,
+                                     GtkSpinButton *col_spin)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    iter;
+
+  mousepad_return_if_fail (GTK_IS_SPIN_BUTTON (line_spin));
+  mousepad_return_if_fail (GTK_IS_SPIN_BUTTON (col_spin));
+
+  /* get the text buffer */
+  buffer = mousepad_object_get_data (G_OBJECT (col_spin), "buffer");
+
+  /* debug check */
+  mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  /* get iter at line */
+  gtk_text_buffer_get_iter_at_line (buffer, &iter, gtk_spin_button_get_value_as_int (line_spin) - 1);
+
+  /* move the iter to the end of the line if needed */
+  if (!gtk_text_iter_ends_line (&iter))
+    gtk_text_iter_forward_to_line_end (&iter);
+
+  /* update column spin button range */
+  gtk_spin_button_set_range (col_spin, 0, gtk_text_iter_get_line_offset (&iter));
+}
+
+
+
+gboolean
+mousepad_dialogs_go_to (GtkWindow     *parent,
+                        GtkTextBuffer *buffer)
+{
+  GtkWidget    *dialog;
+  GtkWidget    *vbox;
+  GtkWidget    *hbox;
+  GtkWidget    *label;
+  GtkWidget    *line_spin;
+  GtkWidget    *col_spin;
+  GtkSizeGroup *size_group;
+  GtkTextIter   iter;
+  gint          line, column, lines;
+  gint          response;
+
+  /* get cursor iter */
+  gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
+  line = gtk_text_iter_get_line (&iter) + 1;
+
+  /* get number of lines */
+  lines = gtk_text_buffer_get_line_count (buffer);
+
+  /* build the dialog */
+  dialog = gtk_dialog_new_with_buttons (_("Go To"),
+                                        parent,
+                                        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+                                        GTK_STOCK_CANCEL, MOUSEPAD_RESPONSE_CANCEL,
+                                        GTK_STOCK_JUMP_TO, MOUSEPAD_RESPONSE_JUMP_TO,
+                                        NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_JUMP_TO);
+  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+  gtk_widget_show (vbox);
+
+  /* create size group */
+  size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+  /* line number box */
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+  gtk_widget_show (hbox);
+
+  label = gtk_label_new_with_mnemonic (_("_Line number:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+  gtk_size_group_add_widget (size_group, label);
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_widget_show (label);
+
+  line_spin = gtk_spin_button_new_with_range (1, lines, 1);
+  gtk_entry_set_activates_default (GTK_ENTRY (line_spin), TRUE);
+  gtk_box_pack_start (GTK_BOX (hbox), line_spin, FALSE, FALSE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), line_spin);
+  gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (line_spin), TRUE);
+  gtk_entry_set_width_chars (GTK_ENTRY (line_spin), 8);
+  gtk_widget_show (line_spin);
+
+  /* column box */
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+  gtk_widget_show (hbox);
+
+  label = gtk_label_new_with_mnemonic (_("C_olumn number:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+  gtk_size_group_add_widget (size_group, label);
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_widget_show (label);
+
+  col_spin = gtk_spin_button_new_with_range (0, 0, 1);
+  gtk_entry_set_activates_default (GTK_ENTRY (col_spin), TRUE);
+  mousepad_object_set_data (G_OBJECT (col_spin), "buffer", buffer);
+  gtk_box_pack_start (GTK_BOX (hbox), col_spin, FALSE, FALSE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), col_spin);
+  gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (col_spin), TRUE);
+  gtk_entry_set_width_chars (GTK_ENTRY (col_spin), 8);
+  gtk_widget_show (col_spin);
+
+  /* signal to monitor column number */
+  g_signal_connect (G_OBJECT (line_spin), "value-changed", G_CALLBACK (mousepad_dialogs_go_to_line_changed), col_spin);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (line_spin), line);
+
+  /* run the dialog */
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+  if (response == MOUSEPAD_RESPONSE_JUMP_TO)
+    {
+      /* hide the dialog */
+      gtk_widget_hide (dialog);
+
+      /* get new position */
+      line = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (line_spin)) - 1;
+      column = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (col_spin));
+
+      /* get iter */
+      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, line, column);
+
+      /* get cursor position */
+      gtk_text_buffer_place_cursor (buffer, &iter);
+    }
+
+  /* release size group */
+  g_object_unref (G_OBJECT (size_group));
+
+  /* destroy the dialog */
+  gtk_widget_destroy (dialog);
+
+  return (response == MOUSEPAD_RESPONSE_JUMP_TO);
+}
+
+
+
+gboolean
+mousepad_dialogs_clear_recent (GtkWindow *parent)
+{
+  GtkWidget *dialog;
+  GtkWidget *image;
+  gboolean   succeed = FALSE;
+
+  /* create the question dialog */
+  dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                   GTK_MESSAGE_OTHER, GTK_BUTTONS_NONE,
+                                   _("Remove all entries from the documents history?"));
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                          GTK_STOCK_CANCEL, MOUSEPAD_RESPONSE_CANCEL,
+                          GTK_STOCK_CLEAR, MOUSEPAD_RESPONSE_CLEAR,
+                          NULL);
+  gtk_window_set_title (GTK_WINDOW (dialog), _("Clear Documents History"));
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_CANCEL);
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                            _("Clearing the documents history will permanently "
+                                              "remove all currently listed entries."));
+
+  /* the dialog icon */
+  image = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_DIALOG);
+  gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image);
+  gtk_widget_show (image);
+
+  /* popup the dialog */
+  if (gtk_dialog_run (GTK_DIALOG (dialog)) == MOUSEPAD_RESPONSE_CLEAR)
+    succeed = TRUE;
+
+  /* destroy the dialog */
+  gtk_widget_destroy (dialog);
+
+  return succeed;
+}
+
+
+
+gint
+mousepad_dialogs_save_changes (GtkWindow *parent,
+                               gboolean   readonly)
+{
+  GtkWidget *dialog;
+  GtkWidget *image;
+  gint       response;
+
+  /* create the question dialog */
+  dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                   GTK_MESSAGE_OTHER, GTK_BUTTONS_NONE,
+                                   _("Do you want to save the changes before closing?"));
+  gtk_window_set_title (GTK_WINDOW (dialog), _("Save Changes"));
+  gtk_dialog_add_action_widget (GTK_DIALOG (dialog), mousepad_util_image_button (GTK_STOCK_DELETE, _("_Don't Save")), MOUSEPAD_RESPONSE_DONT_SAVE);
+  gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, MOUSEPAD_RESPONSE_CANCEL);
+
+  /* we show the save as button instead of save for readonly document */
+  if (G_UNLIKELY (readonly))
+    {
+      image = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_DIALOG);
+      gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_SAVE_AS, MOUSEPAD_RESPONSE_SAVE_AS, NULL);
+      gtk_dialog_set_default_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_SAVE_AS);
+    }
+  else
+    {
+      image = gtk_image_new_from_stock (GTK_STOCK_SAVE, GTK_ICON_SIZE_DIALOG);
+      gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_SAVE, MOUSEPAD_RESPONSE_SAVE, NULL);
+      gtk_dialog_set_default_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_SAVE);
+    }
+
+  /* the dialog icon */
+  gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), image);
+  gtk_widget_show (image);
+
+  /* secondary text */
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("If you don't save the document, all the changes will be lost."));
+
+  /* run the dialog and wait for a response */
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  /* destroy the dialog */
+  gtk_widget_destroy (dialog);
+
+  return response;
+}
+
+
+
+gint
+mousepad_dialogs_externally_modified (GtkWindow *parent)
+{
+  GtkWidget *dialog;
+  gint       response;
+
+  /* create the question dialog */
+  dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                   GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
+                                   _("The document has been externally modified. Do you want to continue saving?"));
+  gtk_window_set_title (GTK_WINDOW (dialog), _("Externally Modified"));
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("If you don't save the document, all the external changes will be lost."));
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                          GTK_STOCK_CANCEL, MOUSEPAD_RESPONSE_CANCEL,
+                          GTK_STOCK_SAVE_AS, MOUSEPAD_RESPONSE_SAVE_AS,
+                          GTK_STOCK_SAVE, MOUSEPAD_RESPONSE_SAVE, NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_CANCEL);
+
+  /* run the dialog */
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  /* destroy the dialog */
+  gtk_widget_destroy (dialog);
+
+  return response;
+}
+
+
+
+gint
+mousepad_dialogs_revert (GtkWindow *parent)
+{
+  GtkWidget *dialog;
+  gint       response;
+
+  /* setup the question dialog */
+  dialog = gtk_message_dialog_new (parent,
+                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                   GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
+                                   _("Do you want to save your changes before reloading?"));
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                   _("If you revert the file, all unsaved changes will be lost."));
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                          GTK_STOCK_CANCEL, MOUSEPAD_RESPONSE_CANCEL,
+                          GTK_STOCK_SAVE_AS, MOUSEPAD_RESPONSE_SAVE_AS,
+                          GTK_STOCK_REVERT_TO_SAVED, MOUSEPAD_RESPONSE_REVERT,
+                          NULL);
+
+  /* run the dialog */
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  /* destroy the dialog */
+  gtk_widget_destroy (dialog);
+
+  return response;
+}
diff --git a/mousepad/mousepad-dialogs.h b/mousepad/mousepad-dialogs.h
new file mode 100644
index 0000000..cb01fd0
--- /dev/null
+++ b/mousepad/mousepad-dialogs.h
@@ -0,0 +1,69 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_DIALOGS_H__
+#define __MOUSEPAD_DIALOGS_H__
+
+G_BEGIN_DECLS
+
+/* dialog responses */
+enum {
+  MOUSEPAD_RESPONSE_CANCEL,
+  MOUSEPAD_RESPONSE_CLEAR,
+  MOUSEPAD_RESPONSE_CLOSE,
+  MOUSEPAD_RESPONSE_DONT_SAVE,
+  MOUSEPAD_RESPONSE_FIND,
+  MOUSEPAD_RESPONSE_JUMP_TO,
+  MOUSEPAD_RESPONSE_OK,
+  MOUSEPAD_RESPONSE_OVERWRITE,
+  MOUSEPAD_RESPONSE_REPLACE,
+  MOUSEPAD_RESPONSE_REVERT,
+  MOUSEPAD_RESPONSE_SAVE,
+  MOUSEPAD_RESPONSE_SAVE_AS,
+  MOUSEPAD_RESPONSE_CHECK_ENTRY
+};
+
+GtkWidget *mousepad_dialogs_image_button        (const gchar   *stock_id,
+                                                 const gchar   *label);
+
+void       mousepad_dialogs_show_about          (GtkWindow     *parent);
+
+void       mousepad_dialogs_show_error          (GtkWindow     *parent,
+                                                 const GError  *error,
+                                                 const gchar   *message);
+
+void       mousepad_dialogs_show_help           (GtkWindow     *parent,
+                                                 const gchar   *page,
+                                                 const gchar   *offset);
+
+gint       mousepad_dialogs_other_tab_size      (GtkWindow     *parent,
+                                                 gint           active_size);
+
+gboolean   mousepad_dialogs_go_to               (GtkWindow     *parent,
+                                                 GtkTextBuffer *buffer);
+
+gboolean   mousepad_dialogs_clear_recent        (GtkWindow     *parent);
+
+gint       mousepad_dialogs_save_changes        (GtkWindow     *parent,
+                                                 gboolean       readonly);
+
+gint       mousepad_dialogs_externally_modified (GtkWindow     *parent);
+
+gint       mousepad_dialogs_revert              (GtkWindow     *parent);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_DIALOGS_H__ */
diff --git a/mousepad/mousepad-document.c b/mousepad/mousepad-document.c
new file mode 100644
index 0000000..a3d9099
--- /dev/null
+++ b/mousepad/mousepad-document.c
@@ -0,0 +1,649 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-util.h>
+#include <mousepad/mousepad-document.h>
+#include <mousepad/mousepad-marshal.h>
+#include <mousepad/mousepad-view.h>
+#include <mousepad/mousepad-preferences.h>
+#include <mousepad/mousepad-window.h>
+
+
+
+#define MOUSEPAD_DOCUMENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MOUSEPAD_TYPE_DOCUMENT, MousepadDocumentPrivate))
+
+
+
+static void      mousepad_document_finalize                (GObject                *object);
+static void      mousepad_document_notify_cursor_position  (GtkTextBuffer          *buffer,
+                                                            GParamSpec             *pspec,
+                                                            MousepadDocument       *document);
+static void      mousepad_document_notify_has_selection    (GtkTextBuffer          *buffer,
+                                                            GParamSpec             *pspec,
+                                                            MousepadDocument       *document);
+static void      mousepad_document_notify_overwrite        (GtkTextView            *textview,
+                                                            GParamSpec             *pspec,
+                                                            MousepadDocument       *document);
+static void      mousepad_document_notify_language         (GtkSourceBuffer        *buffer,
+                                                            GParamSpec             *pspec,
+                                                            MousepadDocument       *document);
+static void      mousepad_document_drag_data_received      (GtkWidget              *widget,
+                                                            GdkDragContext         *context,
+                                                            gint                    x,
+                                                            gint                    y,
+                                                            GtkSelectionData       *selection_data,
+                                                            guint                   info,
+                                                            guint                   drag_time,
+                                                            MousepadDocument       *document);
+static void      mousepad_document_filename_changed        (MousepadDocument       *document,
+                                                            const gchar            *filename);
+static void      mousepad_document_label_color             (MousepadDocument       *document);
+static void      mousepad_document_tab_button_clicked      (GtkWidget              *widget,
+                                                            MousepadDocument       *document);
+
+
+enum
+{
+  CLOSE_TAB,
+  CURSOR_CHANGED,
+  SELECTION_CHANGED,
+  OVERWRITE_CHANGED,
+  LANGUAGE_CHANGED,
+  LAST_SIGNAL
+};
+
+struct _MousepadDocumentClass
+{
+  GtkScrolledWindowClass __parent__;
+};
+
+struct _MousepadDocumentPrivate
+{
+  GtkScrolledWindow __parent__;
+
+  /* the tab label and ebox */
+  GtkWidget           *ebox;
+  GtkWidget           *label;
+
+  /* utf-8 valid document names */
+  gchar               *utf8_filename;
+  gchar               *utf8_basename;
+
+  /* settings */
+  guint                word_wrap : 1;
+};
+
+
+
+static guint document_signals[LAST_SIGNAL];
+
+
+
+MousepadDocument *
+mousepad_document_new (void)
+{
+  return g_object_new (MOUSEPAD_TYPE_DOCUMENT, NULL);
+}
+
+
+
+G_DEFINE_TYPE (MousepadDocument, mousepad_document, GTK_TYPE_SCROLLED_WINDOW);
+
+
+
+static void
+mousepad_document_class_init (MousepadDocumentClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  g_type_class_add_private (klass, sizeof (MousepadDocumentPrivate));
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_document_finalize;
+
+  document_signals[CLOSE_TAB] =
+    g_signal_new (I_("close-tab"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  document_signals[CURSOR_CHANGED] =
+    g_signal_new (I_("cursor-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  _mousepad_marshal_VOID__INT_INT_INT,
+                  G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+
+  document_signals[SELECTION_CHANGED] =
+    g_signal_new (I_("selection-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__INT,
+                  G_TYPE_NONE, 1, G_TYPE_INT);
+
+  document_signals[OVERWRITE_CHANGED] =
+    g_signal_new (I_("overwrite-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__BOOLEAN,
+                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+  document_signals[LANGUAGE_CHANGED] =
+    g_signal_new (I_("language-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, GTK_TYPE_SOURCE_LANGUAGE);
+}
+
+
+
+static void
+mousepad_document_init (MousepadDocument *document)
+{
+  GtkTargetList        *target_list;
+  gboolean              word_wrap, auto_indent, line_numbers, insert_spaces;
+  gchar                *font_name, *color_scheme;
+  gint                  tab_size;
+  GtkSourceStyleScheme *scheme = NULL;
+  MousepadPreferences  *preferences;
+
+  /* private structure */
+  document->priv = MOUSEPAD_DOCUMENT_GET_PRIVATE (document);
+
+  /* initialize the variables */
+  document->priv->utf8_filename = NULL;
+  document->priv->utf8_basename = NULL;
+  document->priv->label = NULL;
+
+  /* setup the scolled window */
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (document), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (document), GTK_SHADOW_ETCHED_IN);
+  gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (document), NULL);
+  gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (document), NULL);
+
+  /* create a textbuffer */
+  document->buffer = GTK_TEXT_BUFFER (gtk_source_buffer_new (NULL));
+
+  /* initialize the file */
+  document->file = mousepad_file_new (document->buffer);
+
+  /* connect signals to the file */
+  g_signal_connect_swapped (G_OBJECT (document->file), "filename-changed", G_CALLBACK (mousepad_document_filename_changed), document);
+
+  /* create the highlight tag */
+  document->tag = gtk_text_buffer_create_tag (document->buffer, NULL, "background", "#ffff78", NULL);
+
+  /* setup the textview */
+  document->textview = g_object_new (MOUSEPAD_TYPE_VIEW, "buffer", document->buffer, NULL);
+  gtk_container_add (GTK_CONTAINER (document), GTK_WIDGET (document->textview));
+  gtk_widget_show (GTK_WIDGET (document->textview));
+
+  /* also allow dropping of uris and tabs in the textview */
+  target_list = gtk_drag_dest_get_target_list (GTK_WIDGET (document->textview));
+  gtk_target_list_add_table (target_list, drop_targets, G_N_ELEMENTS (drop_targets));
+
+  /* preferences */
+  preferences = mousepad_preferences_get ();
+
+  /* read all the default settings */
+  g_object_get (G_OBJECT (preferences),
+                "view-word-wrap", &word_wrap,
+                "view-line-numbers", &line_numbers,
+                "view-auto-indent", &auto_indent,
+                "view-font-name", &font_name,
+                "view-tab-size", &tab_size,
+                "view-insert-spaces", &insert_spaces,
+                "view-color-scheme", &color_scheme,
+                NULL);
+
+  /* release the preferences */
+  g_object_unref (G_OBJECT (preferences));
+
+  /* set all the settings */
+  mousepad_document_set_word_wrap (document, word_wrap);
+  mousepad_document_set_font (document, font_name);
+  mousepad_view_set_line_numbers (document->textview, line_numbers);
+  mousepad_view_set_auto_indent (document->textview, auto_indent);
+  mousepad_view_set_tab_size (document->textview, tab_size);
+  mousepad_view_set_insert_spaces (document->textview, insert_spaces);
+
+  if (g_strcmp0 (color_scheme, "none") != 0)
+    scheme =  gtk_source_style_scheme_manager_get_scheme (gtk_source_style_scheme_manager_get_default (), color_scheme);
+  gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (document->buffer), (scheme != NULL));
+  gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (document->buffer), scheme);
+
+  /* cleanup */
+  g_free (font_name);
+  g_free (color_scheme);
+
+  /* attach signals to the text view and buffer */
+  g_signal_connect (G_OBJECT (document->buffer), "notify::cursor-position", G_CALLBACK (mousepad_document_notify_cursor_position), document);
+  g_signal_connect (G_OBJECT (document->buffer), "notify::has-selection", G_CALLBACK (mousepad_document_notify_has_selection), document);
+  g_signal_connect_swapped (G_OBJECT (document->buffer), "modified-changed", G_CALLBACK (mousepad_document_label_color), document);
+  g_signal_connect_swapped (G_OBJECT (document->file), "readonly-changed", G_CALLBACK (mousepad_document_label_color), document);
+  g_signal_connect (G_OBJECT (document->textview), "notify::overwrite", G_CALLBACK (mousepad_document_notify_overwrite), document);
+  g_signal_connect (G_OBJECT (document->textview), "drag-data-received", G_CALLBACK (mousepad_document_drag_data_received), document);
+  g_signal_connect (G_OBJECT (document->buffer), "notify::language", G_CALLBACK (mousepad_document_notify_language), document);
+}
+
+
+
+static void
+mousepad_document_finalize (GObject *object)
+{
+  MousepadDocument *document = MOUSEPAD_DOCUMENT (object);
+
+  /* cleanup */
+  g_free (document->priv->utf8_filename);
+  g_free (document->priv->utf8_basename);
+
+  /* release the file */
+  g_object_unref (G_OBJECT (document->file));
+
+  /* release the buffer reference */
+  g_object_unref (G_OBJECT (document->buffer));
+
+  (*G_OBJECT_CLASS (mousepad_document_parent_class)->finalize) (object);
+}
+
+
+
+static void
+mousepad_document_notify_cursor_position (GtkTextBuffer    *buffer,
+                                          GParamSpec       *pspec,
+                                          MousepadDocument *document)
+{
+  GtkTextIter iter;
+  gint        line, column, selection;
+  gint        tab_size;
+
+  mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  /* get the current iter position */
+  gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
+
+  /* get the current line number */
+  line = gtk_text_iter_get_line (&iter) + 1;
+
+  /* get the tab size */
+  tab_size = mousepad_view_get_tab_size (document->textview);
+
+  /* get the column */
+  column = mousepad_util_get_real_line_offset (&iter, tab_size);
+
+  /* get length of the selection */
+  selection = mousepad_view_get_selection_length (document->textview, NULL);
+
+  /* emit the signal */
+  g_signal_emit (G_OBJECT (document), document_signals[CURSOR_CHANGED], 0, line, column, selection);
+}
+
+
+
+static void
+mousepad_document_notify_has_selection (GtkTextBuffer    *buffer,
+                                        GParamSpec       *pspec,
+                                        MousepadDocument *document)
+{
+  gint     selection;
+  gboolean is_column_selection;
+
+  mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  /* get length of the selection */
+  selection = mousepad_view_get_selection_length (document->textview, &is_column_selection);
+
+  /* don't send large numbers */
+  if (selection > 1)
+    selection = 1;
+
+  /* if it's a column selection with content */
+  if (selection == 1 && is_column_selection)
+    selection = 2;
+
+  /* emit the signal */
+  g_signal_emit (G_OBJECT (document), document_signals[SELECTION_CHANGED], 0, selection);
+}
+
+
+
+static void
+mousepad_document_notify_overwrite (GtkTextView      *textview,
+                                    GParamSpec       *pspec,
+                                    MousepadDocument *document)
+{
+  gboolean overwrite;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (GTK_IS_TEXT_VIEW (textview));
+
+  /* whether overwrite is enabled */
+  overwrite = gtk_text_view_get_overwrite (textview);
+
+  /* emit the signal */
+  g_signal_emit (G_OBJECT (document), document_signals[OVERWRITE_CHANGED], 0, overwrite);
+}
+
+
+
+static void
+mousepad_document_notify_language (GtkSourceBuffer  *buffer,
+                                   GParamSpec       *pspec,
+                                   MousepadDocument *document)
+{
+  GtkSourceLanguage *language;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (GTK_IS_SOURCE_BUFFER (buffer));
+
+  /* the new language */
+  language = gtk_source_buffer_get_language (buffer);
+
+  /* emit the signal */
+  g_signal_emit (G_OBJECT (document), document_signals[LANGUAGE_CHANGED], 0, language);
+}
+
+
+
+static void
+mousepad_document_drag_data_received (GtkWidget        *widget,
+                                      GdkDragContext   *context,
+                                      gint              x,
+                                      gint              y,
+                                      GtkSelectionData *selection_data,
+                                      guint             info,
+                                      guint             drag_time,
+                                      MousepadDocument *document)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  /* emit the drag-data-received signal from the document when a tab or uri has been dropped */
+  if (info == TARGET_TEXT_URI_LIST || info == TARGET_GTK_NOTEBOOK_TAB)
+    g_signal_emit_by_name (G_OBJECT (document), "drag-data-received", context, x, y, selection_data, info, drag_time);
+}
+
+
+
+static void
+mousepad_document_filename_changed (MousepadDocument *document,
+                                    const gchar      *filename)
+{
+  gchar *utf8_filename, *utf8_basename;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (filename != NULL);
+
+  /* convert the title into a utf-8 valid version for display */
+  utf8_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+
+  if (G_LIKELY (utf8_filename))
+    {
+      /* create the display name */
+      utf8_basename = g_filename_display_basename (utf8_filename);
+
+      /* remove the old names */
+      g_free (document->priv->utf8_filename);
+      g_free (document->priv->utf8_basename);
+
+      /* set the new names */
+      document->priv->utf8_filename = utf8_filename;
+      document->priv->utf8_basename = utf8_basename;
+
+      /* update the tab label and tooltip */
+      if (G_UNLIKELY (document->priv->label))
+        {
+          /* set the tab label */
+          gtk_label_set_text (GTK_LABEL (document->priv->label), utf8_basename);
+
+          /* set the tab tooltip */
+          mousepad_widget_set_tooltip_text (document->priv->ebox, utf8_filename);
+
+          /* update label color */
+          mousepad_document_label_color (document);
+        }
+    }
+}
+
+
+
+static void
+mousepad_document_label_color (MousepadDocument *document)
+{
+  GdkColor  green = {0, 0x0000, 0x9999, 0x0000};
+  GdkColor  red   = {0, 0xffff, 0x0000, 0x0000};
+  GdkColor *color;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (document->buffer));
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (document->file));
+
+  if (document->priv->label)
+    {
+      /* label color */
+      if (gtk_text_buffer_get_modified (document->buffer))
+        color = &red;
+      else if (mousepad_file_get_read_only (document->file))
+        color = &green;
+      else
+        color = NULL;
+
+      /* update colors */
+      gtk_widget_modify_fg (document->priv->label, GTK_STATE_NORMAL, color);
+      gtk_widget_modify_fg (document->priv->label, GTK_STATE_ACTIVE, color);
+    }
+}
+
+
+
+void
+mousepad_document_set_overwrite (MousepadDocument *document,
+                                 gboolean          overwrite)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  gtk_text_view_set_overwrite (GTK_TEXT_VIEW (document->textview), overwrite);
+}
+
+
+
+void
+mousepad_document_set_word_wrap (MousepadDocument *document,
+                                 gboolean          word_wrap)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  /* store the setting */
+  document->priv->word_wrap = word_wrap;
+
+  /* set the wrapping mode */
+  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (document->textview),
+                               word_wrap ? GTK_WRAP_WORD : GTK_WRAP_NONE);
+}
+
+
+
+void
+mousepad_document_set_font (MousepadDocument *document,
+                            const gchar      *font_name)
+{
+  PangoFontDescription *font_desc;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  if (G_LIKELY (font_name))
+    {
+      /* set the widget font */
+      font_desc = pango_font_description_from_string (font_name);
+      gtk_widget_modify_font (GTK_WIDGET (document->textview), font_desc);
+      pango_font_description_free (font_desc);
+    }
+}
+
+
+
+void
+mousepad_document_focus_textview (MousepadDocument *document)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  /* focus the textview */
+  gtk_widget_grab_focus (GTK_WIDGET (document->textview));
+}
+
+
+
+void
+mousepad_document_send_signals (MousepadDocument *document)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  /* re-send the cursor changed signal */
+  mousepad_document_notify_cursor_position (document->buffer, NULL, document);
+
+  /* re-send the overwrite signal */
+  mousepad_document_notify_overwrite (GTK_TEXT_VIEW (document->textview), NULL, document);
+
+  /* re-send the selection status */
+  mousepad_document_notify_has_selection (document->buffer, NULL, document);
+
+  /* re-send the language signal */
+  mousepad_document_notify_language (GTK_SOURCE_BUFFER (document->buffer), NULL, document);
+}
+
+
+
+GtkWidget *
+mousepad_document_get_tab_label (MousepadDocument *document)
+{
+  GtkWidget  *hbox;
+  GtkWidget  *button, *image;
+  GtkRcStyle *style;
+
+  /* create the box */
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_widget_show (hbox);
+
+  /* the ebox */
+  document->priv->ebox = g_object_new (GTK_TYPE_EVENT_BOX, "border-width", 2, "visible-window", FALSE, NULL);
+  gtk_box_pack_start (GTK_BOX (hbox), document->priv->ebox, TRUE, TRUE, 0);
+  mousepad_widget_set_tooltip_text (document->priv->ebox, document->priv->utf8_filename);
+  gtk_widget_show (document->priv->ebox);
+
+  /* create the label */
+  document->priv->label = gtk_label_new (mousepad_document_get_basename (document));
+  gtk_container_add (GTK_CONTAINER (document->priv->ebox), document->priv->label);
+  gtk_widget_show (document->priv->label);
+
+  /* set label color */
+  mousepad_document_label_color (document);
+
+  /* create the button */
+  button = gtk_button_new ();
+  gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
+  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+  GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_DEFAULT | GTK_CAN_FOCUS);
+
+  /* make button a bit smaller */
+  style = gtk_rc_style_new ();
+  style->xthickness = style->ythickness = 0;
+  gtk_widget_modify_style (button, style);
+  g_object_unref (G_OBJECT (style));
+
+  /* pack button, add signal and tooltip */
+  mousepad_widget_set_tooltip_text (button, _("Close this tab"));
+  gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mousepad_document_tab_button_clicked), document);
+  gtk_widget_show (button);
+
+  /* button image */
+  image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
+  gtk_container_add (GTK_CONTAINER (button), image);
+  gtk_widget_show (image);
+
+  return hbox;
+}
+
+
+
+static void
+mousepad_document_tab_button_clicked (GtkWidget        *widget,
+                                      MousepadDocument *document)
+{
+  g_signal_emit (G_OBJECT (document), document_signals[CLOSE_TAB], 0);
+}
+
+
+
+const gchar *
+mousepad_document_get_basename (MousepadDocument *document)
+{
+  static gint untitled_counter = 0;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (document), NULL);
+
+  /* check if there is a filename set */
+  if (document->priv->utf8_basename == NULL)
+    {
+      /* create an unique untitled document name */
+      document->priv->utf8_basename = g_strdup_printf ("%s %d", _("Untitled"), ++untitled_counter);
+    }
+
+  return document->priv->utf8_basename;
+}
+
+
+
+const gchar *
+mousepad_document_get_filename (MousepadDocument *document)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (document), NULL);
+
+  return document->priv->utf8_filename;
+}
+
+
+
+gboolean
+mousepad_document_get_word_wrap (MousepadDocument *document)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (document), FALSE);
+
+  return document->priv->word_wrap;
+}
diff --git a/mousepad/mousepad-document.h b/mousepad/mousepad-document.h
new file mode 100644
index 0000000..f2176c1
--- /dev/null
+++ b/mousepad/mousepad-document.h
@@ -0,0 +1,86 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_DOCUMENT_H__
+#define __MOUSEPAD_DOCUMENT_H__
+
+G_BEGIN_DECLS
+
+#include <mousepad/mousepad-util.h>
+#include <mousepad/mousepad-file.h>
+#include <mousepad/mousepad-view.h>
+
+typedef struct _MousepadDocumentPrivate MousepadDocumentPrivate;
+typedef struct _MousepadDocumentClass   MousepadDocumentClass;
+typedef struct _MousepadDocument        MousepadDocument;
+
+#define MOUSEPAD_SCROLL_MARGIN 0.02
+
+#define MOUSEPAD_TYPE_DOCUMENT            (mousepad_document_get_type ())
+#define MOUSEPAD_DOCUMENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_DOCUMENT, MousepadDocument))
+#define MOUSEPAD_DOCUMENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_DOCUMENT, MousepadDocumentClass))
+#define MOUSEPAD_IS_DOCUMENT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_DOCUMENT))
+#define MOUSEPAD_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOUSEPAD_TYPE_DOCUMENT))
+#define MOUSEPAD_DOCUMENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_DOCUMENT, MousepadDocumentClass))
+
+struct _MousepadDocument
+{
+  GtkScrolledWindow        __parent__;
+
+  /* private structure */
+  MousepadDocumentPrivate *priv;
+
+  /* file */
+  MousepadFile            *file;
+
+  /* text buffer */
+  GtkTextBuffer           *buffer;
+
+  /* text view */
+  MousepadView            *textview;
+
+  /* the highlight tag */
+  GtkTextTag              *tag;
+};
+
+GType             mousepad_document_get_type       (void) G_GNUC_CONST;
+
+MousepadDocument *mousepad_document_new            (void);
+
+void              mousepad_document_set_font       (MousepadDocument *document,
+                                                    const gchar      *font_name);
+
+void              mousepad_document_set_overwrite  (MousepadDocument *document,
+                                                    gboolean          overwrite);
+
+void              mousepad_document_set_word_wrap  (MousepadDocument *document,
+                                                    gboolean          word_wrap);
+
+void              mousepad_document_focus_textview (MousepadDocument *document);
+
+void              mousepad_document_send_signals   (MousepadDocument *document);
+
+GtkWidget        *mousepad_document_get_tab_label  (MousepadDocument *document);
+
+const gchar      *mousepad_document_get_basename   (MousepadDocument *document);
+
+const gchar      *mousepad_document_get_filename   (MousepadDocument *document);
+
+gboolean          mousepad_document_get_word_wrap  (MousepadDocument *document);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_DOCUMENT_H__ */
diff --git a/mousepad/mousepad-encoding-dialog.c b/mousepad/mousepad-encoding-dialog.c
new file mode 100644
index 0000000..7d4ce76
--- /dev/null
+++ b/mousepad/mousepad-encoding-dialog.c
@@ -0,0 +1,517 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-document.h>
+#include <mousepad/mousepad-encoding.h>
+#include <mousepad/mousepad-encoding-dialog.h>
+#include <mousepad/mousepad-preferences.h>
+#include <mousepad/mousepad-util.h>
+
+
+
+static void     mousepad_encoding_dialog_finalize               (GObject                     *object);
+static void     mousepad_encoding_dialog_response               (GtkDialog                   *dialog,
+                                                                 gint                         response_id);
+//~ static gboolean mousepad_encoding_dialog_test_encodings_idle    (gpointer                     user_data);
+//~ static void     mousepad_encoding_dialog_test_encodings_destroy (gpointer                     user_data);
+static void     mousepad_encoding_dialog_test_encodings         (MousepadEncodingDialog      *dialog);
+static void     mousepad_encoding_dialog_cancel_test_encodings  (GtkWidget                   *button,
+                                                                 MousepadEncodingDialog      *dialog);
+static void     mousepad_encoding_dialog_read_file              (MousepadEncodingDialog      *dialog,
+                                                                 MousepadEncoding encoding);
+static void     mousepad_encoding_dialog_button_toggled         (GtkWidget                   *button,
+                                                                 MousepadEncodingDialog      *dialog);
+static void     mousepad_encoding_dialog_combo_changed          (GtkComboBox                 *combo,
+                                                                 MousepadEncodingDialog      *dialog);
+
+
+
+enum
+{
+  COLUMN_LABEL,
+  COLUMN_ID,
+  N_COLUMNS
+};
+
+struct _MousepadEncodingDialogClass
+{
+  GtkDialogClass __parent__;
+};
+
+struct _MousepadEncodingDialog
+{
+  GtkDialog __parent__;
+
+  /* the file */
+  MousepadDocument *document;
+
+  /* encoding test idle id */
+  guint          timer_id;
+
+  /* boolean to cancel the testing loop */
+  guint          cancel_testing : 1;
+
+  /* dialog widget */
+  GtkWidget     *button_ok;
+  GtkWidget     *button_cancel;
+  GtkWidget     *error_box;
+  GtkWidget     *error_label;
+  GtkWidget     *progress_bar;
+
+  /* the three radio button */
+  GtkWidget     *radio_utf8;
+  GtkWidget     *radio_system;
+  GtkWidget     *radio_other;
+
+  /* other encodings combo box */
+  GtkListStore  *store;
+  GtkWidget     *combo;
+};
+
+
+
+G_DEFINE_TYPE (MousepadEncodingDialog, mousepad_encoding_dialog, GTK_TYPE_DIALOG);
+
+
+
+static void
+mousepad_encoding_dialog_class_init (MousepadEncodingDialogClass *klass)
+{
+  GObjectClass   *gobject_class;
+  GtkDialogClass *gtkdialog_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_encoding_dialog_finalize;
+
+  gtkdialog_class = GTK_DIALOG_CLASS (klass);
+  gtkdialog_class->response = mousepad_encoding_dialog_response;
+}
+
+
+
+static void
+mousepad_encoding_dialog_init (MousepadEncodingDialog *dialog)
+{
+  const gchar     *system_charset;
+  gchar           *system_label;
+  GtkWidget       *vbox, *hbox, *icon;
+  GtkCellRenderer *cell;
+
+  /* set some dialog properties */
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+  gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 350);
+
+  /* add buttons */
+  gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+  dialog->button_ok = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
+
+  /* create the header */
+  mousepad_util_dialog_header (GTK_DIALOG (dialog), _("The document was not UTF-8 valid"),
+                               _("Please select an encoding below."), GTK_STOCK_FILE);
+
+  /* dialog vbox */
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
+  gtk_widget_show (vbox);
+
+  hbox = gtk_hbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  /* encoding radio buttons */
+  dialog->radio_utf8 = gtk_radio_button_new_with_label (NULL, _("Default (UTF-8)"));
+  g_signal_connect (G_OBJECT (dialog->radio_utf8), "toggled", G_CALLBACK (mousepad_encoding_dialog_button_toggled), dialog);
+  gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_utf8, FALSE, FALSE, 0);
+  gtk_widget_show (dialog->radio_utf8);
+
+  g_get_charset (&system_charset);
+  system_label = g_strdup_printf ("%s (%s)", _("System"), system_charset);
+  dialog->radio_system = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (dialog->radio_utf8), system_label);
+  g_signal_connect (G_OBJECT (dialog->radio_system), "toggled", G_CALLBACK (mousepad_encoding_dialog_button_toggled), dialog);
+  gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_system, FALSE, FALSE, 0);
+  gtk_widget_show (dialog->radio_system);
+  g_free (system_label);
+
+  dialog->radio_other = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (dialog->radio_system), _("Other:"));
+  g_signal_connect (G_OBJECT (dialog->radio_other), "toggled", G_CALLBACK (mousepad_encoding_dialog_button_toggled), dialog);
+  gtk_box_pack_start (GTK_BOX (hbox), dialog->radio_other, FALSE, FALSE, 0);
+
+  /* create store */
+  dialog->store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
+
+  /* combobox with other charsets */
+  dialog->combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (dialog->store));
+  gtk_box_pack_start (GTK_BOX (hbox), dialog->combo, TRUE, TRUE, 0);
+  g_signal_connect (G_OBJECT (dialog->combo), "changed", G_CALLBACK (mousepad_encoding_dialog_combo_changed), dialog);
+
+  /* text renderer for 1st column */
+  cell = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combo), cell, TRUE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combo), cell, "text", COLUMN_LABEL, NULL);
+
+  /* progress bar */
+  dialog->progress_bar = gtk_progress_bar_new ();
+  gtk_box_pack_start (GTK_BOX (hbox), dialog->progress_bar, TRUE, TRUE, 0);
+  gtk_progress_bar_set_text (GTK_PROGRESS_BAR (dialog->progress_bar), _("Checking encodings..."));
+  gtk_widget_show (dialog->progress_bar);
+
+  /* cancel button */
+  dialog->button_cancel = gtk_button_new ();
+  gtk_box_pack_start (GTK_BOX (hbox), dialog->button_cancel, FALSE, FALSE, 0);
+  g_signal_connect (G_OBJECT (dialog->button_cancel), "clicked", G_CALLBACK (mousepad_encoding_dialog_cancel_test_encodings), dialog);
+  gtk_widget_show (dialog->button_cancel);
+
+  icon = gtk_image_new_from_stock (GTK_STOCK_CANCEL, GTK_ICON_SIZE_MENU);
+  gtk_container_add (GTK_CONTAINER (dialog->button_cancel), icon);
+  gtk_widget_show (icon);
+
+  /* error box */
+  dialog->error_box = gtk_hbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), dialog->error_box, FALSE, FALSE, 0);
+
+  /* error icon */
+  icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_BUTTON);
+  gtk_box_pack_start (GTK_BOX (dialog->error_box), icon, FALSE, FALSE, 0);
+  gtk_widget_show (icon);
+
+  /* error label */
+  dialog->error_label = gtk_label_new (NULL);
+  gtk_box_pack_start (GTK_BOX (dialog->error_box), dialog->error_label, FALSE, FALSE, 0);
+  gtk_label_set_use_markup (GTK_LABEL (dialog->error_label), TRUE);
+  gtk_widget_show (dialog->error_label);
+
+  /* create text view */
+  dialog->document = mousepad_document_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (dialog->document), TRUE, TRUE, 0);
+  gtk_text_view_set_editable (GTK_TEXT_VIEW (dialog->document->textview), FALSE);
+  gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (dialog->document->textview), FALSE);
+  mousepad_view_set_line_numbers (dialog->document->textview, FALSE);
+  mousepad_document_set_word_wrap (dialog->document, FALSE);
+  gtk_widget_show (GTK_WIDGET (dialog->document));
+}
+
+
+
+static void
+mousepad_encoding_dialog_finalize (GObject *object)
+{
+  MousepadEncodingDialog *dialog = MOUSEPAD_ENCODING_DIALOG (object);
+
+  /* stop running timeout */
+  if (G_UNLIKELY (dialog->timer_id))
+    g_source_remove (dialog->timer_id);
+
+  /* clear and release store */
+  gtk_list_store_clear (dialog->store);
+  g_object_unref (G_OBJECT (dialog->store));
+
+  (*G_OBJECT_CLASS (mousepad_encoding_dialog_parent_class)->finalize) (object);
+}
+
+
+
+static void
+mousepad_encoding_dialog_response (GtkDialog *dialog,
+                                   gint       response_id)
+{
+  /* make sure we cancel encoding testing asap */
+  MOUSEPAD_ENCODING_DIALOG (dialog)->cancel_testing = TRUE;
+}
+
+
+
+static gboolean
+mousepad_encoding_dialog_test_encodings_idle (gpointer user_data)
+{
+  MousepadEncodingDialog *dialog = MOUSEPAD_ENCODING_DIALOG (user_data);
+  const gchar            *filename;
+  GMappedFile            *mapped_file;
+  GError                 *error = NULL;
+  const gchar            *contents;
+  gsize                   length, written;
+  guint                   i, n;
+  gchar                  *encoded;
+
+  GDK_THREADS_ENTER ();
+
+  /* get the filename */
+  filename = mousepad_file_get_filename (dialog->document->file);
+
+  /* check if the file exists */
+  if (filename && g_file_test (filename, G_FILE_TEST_EXISTS))
+    {
+      /* try to open the file */
+      mapped_file = g_mapped_file_new (filename, FALSE, &error);
+
+      if (G_LIKELY (mapped_file))
+        {
+          /* get the mapped file contents and length */
+          contents = g_mapped_file_get_contents (mapped_file);
+          length = g_mapped_file_get_length (mapped_file);
+
+          if (G_LIKELY (contents && length > 0))
+            {
+              /* test all the encodings */
+              for (i = 0, n = 0; i < n_encoding_infos && !dialog->cancel_testing; i++)
+                {
+                  /* set progress bar fraction */
+                  gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (dialog->progress_bar), (i + 1.00) / n_encoding_infos);
+
+                  /* try to convert the content */
+                  encoded = g_convert (contents, length, "UTF-8", encoding_infos[i].charset, NULL, &written, NULL);
+
+                  if (G_LIKELY (encoded))
+                    {
+                      /* glib uses a faster validator when the string is nul-terminated */
+                      if (G_LIKELY (written > 0 && encoded[written] == '\0'))
+                        written = -1;
+
+                      /* validate the encoded content */
+                      if (G_LIKELY (g_utf8_validate (encoded, written, NULL)))
+                        {
+                          /* insert in the store */
+                          gtk_list_store_insert_with_values (dialog->store, NULL, n++,
+                                                             COLUMN_LABEL, encoding_infos[i].charset,
+                                                             COLUMN_ID, encoding_infos[i].encoding, -1);
+                        }
+
+                      /* cleanup */
+                      g_free (encoded);
+                    }
+
+                  /* iterate the main loop to update the gui */
+                  while (gtk_events_pending ())
+                    gtk_main_iteration ();
+                }
+            }
+
+          /* close the mapped file */
+#if GLIB_CHECK_VERSION (2, 21, 0)
+          g_mapped_file_unref (mapped_file);
+#else
+          g_mapped_file_free (mapped_file);
+#endif
+        }
+    }
+
+  /* hide progress bar and cancel button */
+  gtk_widget_hide (dialog->progress_bar);
+  gtk_widget_hide (dialog->button_cancel);
+
+  /* show the radio button and combo box */
+  gtk_widget_show (dialog->radio_other);
+  gtk_widget_show (dialog->combo);
+
+  /* select the first item */
+  gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combo), 0);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+
+
+static void
+mousepad_encoding_dialog_test_encodings_destroy (gpointer user_data)
+{
+  MOUSEPAD_ENCODING_DIALOG (user_data)->timer_id = 0;
+}
+
+
+
+static void
+mousepad_encoding_dialog_test_encodings (MousepadEncodingDialog *dialog)
+{
+  if (G_LIKELY (dialog->timer_id == 0))
+    {
+      /* reset boolean */
+      dialog->cancel_testing = FALSE;
+
+      /* start a new idle function */
+      dialog->timer_id = g_idle_add_full (G_PRIORITY_LOW, mousepad_encoding_dialog_test_encodings_idle,
+                                          dialog, mousepad_encoding_dialog_test_encodings_destroy);
+    }
+}
+
+
+
+static void
+mousepad_encoding_dialog_cancel_test_encodings (GtkWidget              *button,
+                                                MousepadEncodingDialog *dialog)
+{
+  /* cancel the testing loop */
+  dialog->cancel_testing = TRUE;
+}
+
+
+
+static void
+mousepad_encoding_dialog_read_file (MousepadEncodingDialog *dialog,
+                                    MousepadEncoding        encoding)
+{
+  GtkTextIter  start, end;
+  GError      *error = NULL;
+  gchar       *message;
+  gint         result;
+
+  /* clear buffer */
+  gtk_text_buffer_get_bounds (dialog->document->buffer, &start, &end);
+  gtk_text_buffer_delete (dialog->document->buffer, &start, &end);
+
+  /* set encoding */
+  mousepad_file_set_encoding (dialog->document->file, encoding);
+
+  /* try to open the file */
+  result = mousepad_file_open (dialog->document->file, NULL, &error);
+
+  /* set sensitivity of the ok button */
+  gtk_widget_set_sensitive (dialog->button_ok, result == 0);
+
+  if (result == 0)
+    {
+      /* no error, hide the box */
+      gtk_widget_hide (dialog->error_box);
+    }
+  else
+    {
+      /* format message */
+      message = g_strdup_printf ("<b>%s.</b>", error->message);
+
+      /* set the error label */
+      gtk_label_set_markup (GTK_LABEL (dialog->error_label), message);
+
+      /* cleanup */
+      g_free (message);
+
+      /* show the error box */
+      gtk_widget_show (dialog->error_box);
+
+      /* clear the error */
+      g_error_free (error);
+    }
+}
+
+
+
+static void
+mousepad_encoding_dialog_button_toggled (GtkWidget              *button,
+                                         MousepadEncodingDialog *dialog)
+{
+  /* ignore inactive buttons */
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
+    {
+      /* set sensitivity of the other combobox */
+      gtk_widget_set_sensitive (dialog->combo, (button == dialog->radio_other));
+
+      if (button == dialog->radio_utf8)
+        {
+          /* open the file */
+          mousepad_encoding_dialog_read_file (dialog, MOUSEPAD_ENCODING_UTF_8);
+        }
+      else if (button == dialog->radio_system)
+        {
+          /* open the file */
+          mousepad_encoding_dialog_read_file (dialog, mousepad_encoding_user ());
+        }
+      else
+        {
+          /* poke function */
+          mousepad_encoding_dialog_combo_changed (GTK_COMBO_BOX (dialog->combo), dialog);
+        }
+    }
+}
+
+
+
+static void
+mousepad_encoding_dialog_combo_changed (GtkComboBox            *combo,
+                                        MousepadEncodingDialog *dialog)
+{
+  GtkTreeIter iter;
+  gint        id;
+
+  /* get the selected item */
+  if (GTK_WIDGET_SENSITIVE (combo) && gtk_combo_box_get_active_iter (combo, &iter))
+    {
+      /* get the id */
+      gtk_tree_model_get (GTK_TREE_MODEL (dialog->store), &iter, COLUMN_ID, &id, -1);
+
+      /* open the file with other encoding */
+      mousepad_encoding_dialog_read_file (dialog, id);
+    }
+}
+
+
+
+GtkWidget *
+mousepad_encoding_dialog_new (GtkWindow    *parent,
+                              MousepadFile *file)
+{
+  MousepadEncodingDialog *dialog;
+
+  mousepad_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), NULL);
+
+  /* create the dialog */
+  dialog = g_object_new (MOUSEPAD_TYPE_ENCODING_DIALOG, NULL);
+
+  /* set parent window */
+  gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+
+  /* set the filename */
+  mousepad_file_set_filename (dialog->document->file, mousepad_file_get_filename (file));
+
+  /* start with the system encoding */
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->radio_system), TRUE);
+
+  /* queue idle function */
+  mousepad_encoding_dialog_test_encodings (dialog);
+
+  return GTK_WIDGET (dialog);
+}
+
+
+
+MousepadEncoding
+mousepad_encoding_dialog_get_encoding (MousepadEncodingDialog *dialog)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_ENCODING_DIALOG (dialog), MOUSEPAD_ENCODING_NONE);
+
+  return mousepad_file_get_encoding (dialog->document->file);
+}
+
+
+
+const gchar *
+mousepad_encoding_dialog_get_encoding_custom (MousepadEncodingDialog *dialog)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_ENCODING_DIALOG (dialog), NULL);
+
+  return NULL;
+}
diff --git a/mousepad/mousepad-encoding-dialog.h b/mousepad/mousepad-encoding-dialog.h
new file mode 100644
index 0000000..ca4ee7f
--- /dev/null
+++ b/mousepad/mousepad-encoding-dialog.h
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_ENCODING_DIALOG_H__
+#define __MOUSEPAD_ENCODING_DIALOG_H__
+
+G_BEGIN_DECLS
+
+#include <mousepad/mousepad-encoding.h>
+
+#define MOUSEPAD_TYPE_ENCODING_DIALOG            (mousepad_encoding_dialog_get_type ())
+#define MOUSEPAD_ENCODING_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_ENCODING_DIALOG, MousepadEncodingDialog))
+#define MOUSEPAD_ENCODING_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_ENCODING_DIALOG, MousepadEncodingDialogClass))
+#define MOUSEPAD_IS_ENCODING_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_ENCODING_DIALOG))
+#define MOUSEPAD_IS_ENCODING_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_ENCODING_DIALOG))
+#define MOUSEPAD_ENCODING_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_ENCODING_DIALOG, MousepadEncodingDialogClass))
+
+typedef struct _MousepadEncodingDialogClass MousepadEncodingDialogClass;
+typedef struct _MousepadEncodingDialog      MousepadEncodingDialog;
+
+GType             mousepad_encoding_dialog_get_type            (void) G_GNUC_CONST;
+
+GtkWidget        *mousepad_encoding_dialog_new                 (GtkWindow              *parent,
+                                                                MousepadFile           *file);
+
+MousepadEncoding  mousepad_encoding_dialog_get_encoding        (MousepadEncodingDialog *dialog);
+
+const gchar      *mousepad_encoding_dialog_get_encoding_custom (MousepadEncodingDialog *dialog);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_ENCODING_DIALOG_H__ */
diff --git a/mousepad/mousepad-encoding.c b/mousepad/mousepad-encoding.c
new file mode 100644
index 0000000..ac2f19a
--- /dev/null
+++ b/mousepad/mousepad-encoding.c
@@ -0,0 +1,201 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <glib.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-encoding.h>
+
+
+
+const MousepadEncodingInfo encoding_infos[] =
+{
+  /* west european */
+  { MOUSEPAD_ENCODING_ISO_8859_14,  "ISO-8859-14",      N_("Celtic") },
+  { MOUSEPAD_ENCODING_ISO_8859_7,   "ISO-8859-7",       N_("Greek") },
+  { MOUSEPAD_ENCODING_WINDOWS_1253, "WINDOWS-1253",     N_("Greek") },
+  { MOUSEPAD_ENCODING_ISO_8859_10,  "ISO-8859-10",      N_("Nordic") },
+  { MOUSEPAD_ENCODING_ISO_8859_3,   "ISO-8859-3",       N_("South European") },
+  { MOUSEPAD_ENCODING_IBM_850,      "IBM850",           N_("Western") },
+  { MOUSEPAD_ENCODING_ISO_8859_1,   "ISO-8859-1",       N_("Western") },
+  { MOUSEPAD_ENCODING_ISO_8859_15,  "ISO-8859-15",      N_("Western") },
+  { MOUSEPAD_ENCODING_WINDOWS_1252, "WINDOWS-1252",     N_("Western") },
+
+  /* east european */
+  { MOUSEPAD_ENCODING_ISO_8859_4,   "ISO-8859-4",       N_("Baltic") },
+  { MOUSEPAD_ENCODING_ISO_8859_13,  "ISO-8859-13",      N_("Baltic") },
+  { MOUSEPAD_ENCODING_WINDOWS_1257, "WINDOWS-1257",     N_("Baltic") },
+  { MOUSEPAD_ENCODING_IBM_852,      "IBM852",           N_("Central European") },
+  { MOUSEPAD_ENCODING_ISO_8859_2,   "ISO-8859-2",       N_("Central European") },
+  { MOUSEPAD_ENCODING_WINDOWS_1250, "WINDOWS-1250",     N_("Central European") },
+  { MOUSEPAD_ENCODING_IBM_855,      "IBM855",           N_("Cyrillic") },
+  { MOUSEPAD_ENCODING_ISO_8859_5,   "ISO-8859-5",       N_("Cyrillic") },
+  { MOUSEPAD_ENCODING_ISO_IR_111,   "ISO-IR-111",       N_("Cyrillic") },
+  { MOUSEPAD_ENCODING_KOI8_R,       "KOI8R",            N_("Cyrillic") },
+  { MOUSEPAD_ENCODING_WINDOWS_1251, "WINDOWS-1251",     N_("Cyrillic") },
+  { MOUSEPAD_ENCODING_CP_866,       "CP866",            N_("Cyrillic/Russian") },
+  { MOUSEPAD_ENCODING_KOI8_U,       "KOI8U",            N_("Cyrillic/Ukrainian") },
+  { MOUSEPAD_ENCODING_ISO_8859_16,  "ISO-8859-16",      N_("Romanian") },
+
+  /* middle eastern */
+  { MOUSEPAD_ENCODING_IBM_864,      "IBM864",           N_("Arabic") },
+  { MOUSEPAD_ENCODING_ISO_8859_6,   "ISO-8859-6",       N_("Arabic") },
+  { MOUSEPAD_ENCODING_WINDOWS_1256, "WINDOWS-1256",     N_("Arabic") },
+  { MOUSEPAD_ENCODING_IBM_862,      "IBM862",           N_("Hebrew") },
+  { MOUSEPAD_ENCODING_ISO_8859_8_I, "ISO-8859-8-I",     N_("Hebrew") },
+  { MOUSEPAD_ENCODING_WINDOWS_1255, "WINDOWS-1255",     N_("Hebrew") },
+  { MOUSEPAD_ENCODING_ISO_8859_8,   "ISO-8859-8",       N_("Hebrew Visual") },
+
+  /* asian */
+  { MOUSEPAD_ENCODING_ARMSCII_8,    "ARMSCII-8",        N_("Armenian") },
+  { MOUSEPAD_ENCODING_GEOSTD8,      "GEORGIAN-ACADEMY", N_("Georgian") },
+  { MOUSEPAD_ENCODING_TIS_620,      "TIS-620",          N_("Thai") },
+  { MOUSEPAD_ENCODING_IBM_857,      "IBM857",           N_("Turkish") },
+  { MOUSEPAD_ENCODING_WINDOWS_1254, "WINDOWS-1254",     N_("Turkish") },
+  { MOUSEPAD_ENCODING_ISO_8859_9,   "ISO-8859-9",       N_("Turkish") },
+  { MOUSEPAD_ENCODING_TCVN,         "TCVN",             N_("Vietnamese") },
+  { MOUSEPAD_ENCODING_VISCII,       "VISCII",           N_("Vietnamese") },
+  { MOUSEPAD_ENCODING_WINDOWS_1258, "WINDOWS-1258",     N_("Vietnamese") },
+
+  /* unicode */
+  { MOUSEPAD_ENCODING_UTF_7,        "UTF-7",            N_("Unicode") },
+  { MOUSEPAD_ENCODING_UTF_8,        "UTF-8",            N_("Unicode") },
+  { MOUSEPAD_ENCODING_UTF_16LE,     "UTF-16LE",         N_("Unicode") },
+  { MOUSEPAD_ENCODING_UTF_16BE,     "UTF-16BE",         N_("Unicode") },
+  { MOUSEPAD_ENCODING_UCS_2LE,      "UCS-2LE",          N_("Unicode") },
+  { MOUSEPAD_ENCODING_UCS_2BE,      "UCS-2BE",          N_("Unicode") },
+  { MOUSEPAD_ENCODING_UTF_32LE,     "UTF-32LE",         N_("Unicode") },
+  { MOUSEPAD_ENCODING_UTF_32BE,     "UTF-32BE",         N_("Unicode") },
+
+  /* east asian */
+  { MOUSEPAD_ENCODING_GB18030,      "GB18030",          N_("Chinese Simplified") },
+  { MOUSEPAD_ENCODING_GB2312,       "GB2312",           N_("Chinese Simplified") },
+  { MOUSEPAD_ENCODING_GBK,          "GBK",              N_("Chinese Simplified") },
+  { MOUSEPAD_ENCODING_HZ,           "HZ",               N_("Chinese Simplified") },
+  { MOUSEPAD_ENCODING_BIG5,         "BIG5",             N_("Chinese Traditional") },
+  { MOUSEPAD_ENCODING_BIG5_HKSCS,   "BIG5-HKSCS",       N_("Chinese Traditional") },
+  { MOUSEPAD_ENCODING_EUC_TW,       "EUC-TW",           N_("Chinese Traditional") },
+  { MOUSEPAD_ENCODING_EUC_JP,       "EUC-JP",           N_("Japanese") },
+  { MOUSEPAD_ENCODING_ISO_2022_JP,  "ISO-2022-JP",      N_("Japanese") },
+  { MOUSEPAD_ENCODING_SHIFT_JIS,    "SHIFT_JIS",        N_("Japanese") },
+  { MOUSEPAD_ENCODING_EUC_KR,       "EUC-KR",           N_("Korean") },
+  { MOUSEPAD_ENCODING_ISO_2022_KR,  "ISO-2022-KR",      N_("Korean") },
+  { MOUSEPAD_ENCODING_JOHAB,        "JOHAB",            N_("Korean") },
+  { MOUSEPAD_ENCODING_UHC,          "UHC",              N_("Korean") }
+};
+
+
+
+guint n_encoding_infos = G_N_ELEMENTS (encoding_infos);
+
+
+
+const gchar *
+mousepad_encoding_get_charset (MousepadEncoding encoding)
+{
+  guint i;
+
+  /* try to find and return the charset */
+  for (i = 0; i < G_N_ELEMENTS (encoding_infos); i++)
+    if (encoding_infos[i].encoding == encoding)
+      return encoding_infos[i].charset;
+
+  return NULL;
+}
+
+
+
+const gchar *
+mousepad_encoding_get_name (MousepadEncoding encoding)
+{
+  guint i;
+
+  /* try to find and return the translated name */
+  for (i = 0; i < G_N_ELEMENTS (encoding_infos); i++)
+    if (encoding_infos[i].encoding == encoding)
+      return _(encoding_infos[i].name);
+
+  return NULL;
+}
+
+
+
+MousepadEncoding
+mousepad_encoding_user (void)
+{
+  static MousepadEncoding  encoding = MOUSEPAD_ENCODING_NONE;
+  const gchar             *charset;
+
+  if (G_UNLIKELY (encoding == MOUSEPAD_ENCODING_NONE))
+    {
+      /* try to find the user charset */
+      if (g_get_charset (&charset) == FALSE)
+        encoding = mousepad_encoding_find (charset);
+
+      /* default to utf-8 */
+      if (G_LIKELY (encoding == MOUSEPAD_ENCODING_NONE))
+        encoding = MOUSEPAD_ENCODING_UTF_8;
+    }
+
+  return encoding;
+}
+
+
+
+MousepadEncoding
+mousepad_encoding_find (const gchar *charset)
+{
+  guint i;
+
+  /* check for invalid strings */
+  if (G_UNLIKELY (charset == NULL || *charset == '\0'))
+    return MOUSEPAD_ENCODING_NONE;
+
+  /* find the charset */
+  for (i = 0; i < G_N_ELEMENTS (encoding_infos); i++)
+    if (strcasecmp (encoding_infos[i].charset, charset) == 0)
+      return encoding_infos[i].encoding;
+
+  /* no encoding charset found */
+  return MOUSEPAD_ENCODING_NONE;
+}
+
+
+
+gboolean
+mousepad_encoding_is_unicode (MousepadEncoding encoding)
+{
+  const gchar *charset;
+
+  /* get the characterset name */
+  charset = mousepad_encoding_get_charset (encoding);
+
+  /* check for unicode charset */
+  if (charset != NULL && (strncmp (charset, "UTF", 3) == 0
+      || strncmp (charset, "UCS", 3) == 0))
+    return TRUE;
+
+  /* not an unicode charset */
+  return FALSE;
+}
diff --git a/mousepad/mousepad-encoding.h b/mousepad/mousepad-encoding.h
new file mode 100644
index 0000000..eee8528
--- /dev/null
+++ b/mousepad/mousepad-encoding.h
@@ -0,0 +1,125 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_ENCODINGS_H__
+#define __MOUSEPAD_ENCODINGS_H__
+
+G_BEGIN_DECLS
+
+typedef enum   _MousepadEncoding     MousepadEncoding;
+typedef struct _MousepadEncodingInfo MousepadEncodingInfo;
+
+enum _MousepadEncoding
+{
+  MOUSEPAD_ENCODING_NONE,
+  MOUSEPAD_ENCODING_CUSTOM,
+
+  MOUSEPAD_ENCODING_ISO_8859_1,
+  MOUSEPAD_ENCODING_ISO_8859_2,
+  MOUSEPAD_ENCODING_ISO_8859_3,
+  MOUSEPAD_ENCODING_ISO_8859_4,
+  MOUSEPAD_ENCODING_ISO_8859_5,
+  MOUSEPAD_ENCODING_ISO_8859_6,
+  MOUSEPAD_ENCODING_ISO_8859_7,
+  MOUSEPAD_ENCODING_ISO_8859_8,
+  MOUSEPAD_ENCODING_ISO_8859_8_I,
+  MOUSEPAD_ENCODING_ISO_8859_9,
+  MOUSEPAD_ENCODING_ISO_8859_10,
+  MOUSEPAD_ENCODING_ISO_8859_13,
+  MOUSEPAD_ENCODING_ISO_8859_14,
+  MOUSEPAD_ENCODING_ISO_8859_15,
+  MOUSEPAD_ENCODING_ISO_8859_16,
+
+  MOUSEPAD_ENCODING_UTF_7,
+  MOUSEPAD_ENCODING_UTF_8,
+  MOUSEPAD_ENCODING_UTF_16LE,
+  MOUSEPAD_ENCODING_UTF_16BE,
+  MOUSEPAD_ENCODING_UCS_2LE,
+  MOUSEPAD_ENCODING_UCS_2BE,
+  MOUSEPAD_ENCODING_UTF_32LE,
+  MOUSEPAD_ENCODING_UTF_32BE,
+
+  MOUSEPAD_ENCODING_ARMSCII_8,
+  MOUSEPAD_ENCODING_BIG5,
+  MOUSEPAD_ENCODING_BIG5_HKSCS,
+  MOUSEPAD_ENCODING_CP_866,
+
+  MOUSEPAD_ENCODING_EUC_JP,
+  MOUSEPAD_ENCODING_EUC_KR,
+  MOUSEPAD_ENCODING_EUC_TW,
+
+  MOUSEPAD_ENCODING_GB18030,
+  MOUSEPAD_ENCODING_GB2312,
+  MOUSEPAD_ENCODING_GBK,
+  MOUSEPAD_ENCODING_GEOSTD8,
+  MOUSEPAD_ENCODING_HZ,
+
+  MOUSEPAD_ENCODING_IBM_850,
+  MOUSEPAD_ENCODING_IBM_852,
+  MOUSEPAD_ENCODING_IBM_855,
+  MOUSEPAD_ENCODING_IBM_857,
+  MOUSEPAD_ENCODING_IBM_862,
+  MOUSEPAD_ENCODING_IBM_864,
+
+  MOUSEPAD_ENCODING_ISO_2022_JP,
+  MOUSEPAD_ENCODING_ISO_2022_KR,
+  MOUSEPAD_ENCODING_ISO_IR_111,
+  MOUSEPAD_ENCODING_JOHAB,
+  MOUSEPAD_ENCODING_KOI8_R,
+  MOUSEPAD_ENCODING_KOI8_U,
+
+  MOUSEPAD_ENCODING_SHIFT_JIS,
+  MOUSEPAD_ENCODING_TCVN,
+  MOUSEPAD_ENCODING_TIS_620,
+  MOUSEPAD_ENCODING_UHC,
+  MOUSEPAD_ENCODING_VISCII,
+
+  MOUSEPAD_ENCODING_WINDOWS_1250,
+  MOUSEPAD_ENCODING_WINDOWS_1251,
+  MOUSEPAD_ENCODING_WINDOWS_1252,
+  MOUSEPAD_ENCODING_WINDOWS_1253,
+  MOUSEPAD_ENCODING_WINDOWS_1254,
+  MOUSEPAD_ENCODING_WINDOWS_1255,
+  MOUSEPAD_ENCODING_WINDOWS_1256,
+  MOUSEPAD_ENCODING_WINDOWS_1257,
+  MOUSEPAD_ENCODING_WINDOWS_1258
+};
+
+struct _MousepadEncodingInfo
+{
+  MousepadEncoding  encoding;
+  const gchar      *charset;
+  const gchar      *name;
+};
+
+
+extern const MousepadEncodingInfo encoding_infos[];
+
+extern guint                      n_encoding_infos;
+
+const gchar      *mousepad_encoding_get_charset (MousepadEncoding  encoding);
+
+const gchar      *mousepad_encoding_get_name    (MousepadEncoding  encoding);
+
+MousepadEncoding  mousepad_encoding_user        (void);
+
+MousepadEncoding  mousepad_encoding_find        (const gchar      *charset);
+
+gboolean          mousepad_encoding_is_unicode  (MousepadEncoding  encoding);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_ENCODINGS_H__ */
diff --git a/mousepad/mousepad-file.c b/mousepad/mousepad-file.c
new file mode 100644
index 0000000..0148b69
--- /dev/null
+++ b/mousepad/mousepad-file.c
@@ -0,0 +1,919 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-file.h>
+
+
+
+enum
+{
+  /* EXTERNALLY_MODIFIED, */
+  FILENAME_CHANGED,
+  READONLY_CHANGED,
+  LAST_SIGNAL
+};
+
+struct _MousepadFileClass
+{
+  GObjectClass __parent__;
+};
+
+struct _MousepadFile
+{
+  GObject             __parent__;
+
+  /* the text buffer this file belongs to */
+  GtkTextBuffer      *buffer;
+
+  /* filename */
+  gchar              *filename;
+
+  /* encoding of the file */
+  MousepadEncoding    encoding;
+
+  /* line ending of the file */
+  MousepadLineEnding  line_ending;
+
+  /* our last modification time */
+  gint                mtime;
+
+  /* if file is read-only */
+  guint               readonly : 1;
+
+  /* whether we write the bom at the start of the file */
+  guint               write_bom : 1;
+};
+
+
+
+static void  mousepad_file_finalize         (GObject            *object);
+static void  mousepad_file_set_readonly     (MousepadFile       *file,
+                                             gboolean            readonly);
+
+
+
+static guint file_signals[LAST_SIGNAL];
+
+
+
+G_DEFINE_TYPE (MousepadFile, mousepad_file, G_TYPE_OBJECT);
+
+
+
+static void
+mousepad_file_class_init (MousepadFileClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_file_finalize;
+
+#if 0
+  /* TODO implement this signal */
+  file_signals[EXTERNALLY_MODIFIED] =
+    g_signal_new (I_("externally-modified"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__BOOLEAN,
+                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+#endif
+
+  file_signals[READONLY_CHANGED] =
+    g_signal_new (I_("readonly-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__BOOLEAN,
+                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+  file_signals[FILENAME_CHANGED] =
+    g_signal_new (I_("filename-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__STRING,
+                  G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+
+
+static void
+mousepad_file_init (MousepadFile *file)
+{
+  /* initialize */
+  file->filename    = NULL;
+  file->encoding    = MOUSEPAD_ENCODING_UTF_8;
+#ifdef G_OS_WIN32
+  file->line_ending = MOUSEPAD_EOL_DOS;
+#else
+  file->line_ending = MOUSEPAD_EOL_UNIX;
+#endif
+  file->readonly    = TRUE;
+  file->mtime       = 0;
+  file->write_bom   = FALSE;
+}
+
+
+
+static void
+mousepad_file_finalize (GObject *object)
+{
+  MousepadFile *file = MOUSEPAD_FILE (object);
+
+  /* cleanup */
+  g_free (file->filename);
+
+  /* release the reference from the buffer */
+  g_object_unref (G_OBJECT (file->buffer));
+
+  (*G_OBJECT_CLASS (mousepad_file_parent_class)->finalize) (object);
+}
+
+
+
+static void
+mousepad_file_set_readonly (MousepadFile *file,
+                            gboolean      readonly)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (file));
+
+  if (G_LIKELY (file->readonly != readonly))
+    {
+      /* store new value */
+      file->readonly = readonly;
+
+      /* emit signal */
+      g_signal_emit (G_OBJECT (file), file_signals[READONLY_CHANGED], 0, readonly);
+    }
+}
+
+
+
+static MousepadEncoding
+mousepad_file_encoding_read_bom (const gchar *contents,
+                                 gsize        length,
+                                 gsize       *bom_length)
+{
+  const guchar     *bom = (const guchar *) contents;
+  MousepadEncoding  encoding = MOUSEPAD_ENCODING_NONE;
+  gsize             bytes = 0;
+
+  mousepad_return_val_if_fail (contents != NULL && length > 0, MOUSEPAD_ENCODING_NONE);
+  mousepad_return_val_if_fail (contents != NULL && length > 0, MOUSEPAD_ENCODING_NONE);
+
+  switch (bom[0])
+    {
+      case 0xef:
+        if (length >= 3 && bom[1] == 0xbb && bom[2] == 0xbf)
+          {
+            bytes = 3;
+            encoding = MOUSEPAD_ENCODING_UTF_8;
+          }
+        break;
+
+      case 0x00:
+        if (length >= 4 && bom[1] == 0x00 && bom[2] == 0xfe && bom[3] == 0xff)
+          {
+            bytes = 4;
+            encoding = MOUSEPAD_ENCODING_UTF_32BE;
+          }
+        break;
+
+      case 0xff:
+        if (length >= 4 && bom[1] == 0xfe && bom[2] == 0x00 && bom[3] == 0x00)
+          {
+            bytes = 4;
+            encoding = MOUSEPAD_ENCODING_UTF_32LE;
+          }
+        else if (length >= 2 && bom[1] == 0xfe)
+          {
+            bytes = 2;
+            encoding = MOUSEPAD_ENCODING_UTF_16LE;
+          }
+        break;
+
+      case 0x2b:
+        if (length >= 4 && (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) &&
+            (bom[3] == 0x38 || bom[3] == 0x39 || bom[3] == 0x2b || bom[3] == 0x2f))
+          {
+            bytes = 4;
+            encoding = MOUSEPAD_ENCODING_UTF_7;
+          }
+        break;
+
+      case 0xfe:
+        if (length >= 2 && bom[1] == 0xff)
+          {
+            bytes = 2;
+            encoding = MOUSEPAD_ENCODING_UTF_16BE;
+          }
+        break;
+    }
+
+  if (bom_length)
+    *bom_length = bytes;
+
+  return encoding;
+}
+
+
+
+MousepadFile *
+mousepad_file_new (GtkTextBuffer *buffer)
+{
+  MousepadFile *file;
+
+  mousepad_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+  file = g_object_new (MOUSEPAD_TYPE_FILE, NULL);
+
+  /* set the buffer */
+  file->buffer = g_object_ref (G_OBJECT (buffer));
+
+  return file;
+}
+
+
+
+void
+mousepad_file_set_filename (MousepadFile *file,
+                            const gchar  *filename)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (file));
+
+  /* free the old filename */
+  g_free (file->filename);
+
+  /* set the filename */
+  file->filename = g_strdup (filename);
+
+  /* send a signal that the name has been changed */
+  g_signal_emit (G_OBJECT (file), file_signals[FILENAME_CHANGED], 0, file->filename);
+}
+
+
+
+const gchar *
+mousepad_file_get_filename (MousepadFile *file)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), NULL);
+
+  return file->filename;
+}
+
+
+
+gchar *
+mousepad_file_get_uri (MousepadFile *file)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), NULL);
+
+  return g_filename_to_uri (file->filename, NULL, NULL);
+}
+
+
+
+void
+mousepad_file_set_encoding (MousepadFile     *file,
+                            MousepadEncoding  encoding)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (file));
+
+  /* set new encoding */
+  file->encoding = encoding;
+}
+
+
+
+MousepadEncoding
+mousepad_file_get_encoding (MousepadFile *file)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), MOUSEPAD_ENCODING_NONE);
+
+  return file->encoding;
+}
+
+
+
+gboolean
+mousepad_file_get_read_only (MousepadFile *file)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), FALSE);
+
+  return file->filename ? file->readonly : FALSE;
+}
+
+
+
+void
+mousepad_file_set_write_bom (MousepadFile *file,
+                             gboolean      write_bom)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (file));
+  mousepad_return_if_fail (mousepad_encoding_is_unicode (file->encoding));
+
+  /* set new value */
+  file->write_bom = write_bom;
+}
+
+
+
+gboolean
+mousepad_file_get_write_bom (MousepadFile *file,
+                             gboolean     *sensitive)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), FALSE);
+
+  /* return if we can write a bom */
+  if (G_LIKELY (sensitive))
+    *sensitive = mousepad_encoding_is_unicode (file->encoding);
+
+  return file->write_bom;
+}
+
+
+
+void
+mousepad_file_set_line_ending (MousepadFile       *file,
+                               MousepadLineEnding  line_ending)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (file));
+
+  file->line_ending = line_ending;
+}
+
+
+
+MousepadLineEnding
+mousepad_file_get_line_ending (MousepadFile *file)
+{
+  return file->line_ending;
+}
+
+
+
+void
+mousepad_file_set_language (MousepadFile      *file,
+                            GtkSourceLanguage *language)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (file));
+  mousepad_return_if_fail (GTK_IS_SOURCE_BUFFER (file->buffer));
+
+  gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (file->buffer), language);
+}
+
+
+
+GtkSourceLanguage *
+mousepad_file_get_language (MousepadFile *file)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), NULL);
+  mousepad_return_val_if_fail (GTK_IS_SOURCE_BUFFER (file->buffer), NULL);
+
+  return gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (file->buffer));
+}
+
+
+
+void
+mousepad_file_set_language_id (MousepadFile *file,
+                               const gchar  *language_id)
+{
+  GtkSourceLanguage *lang;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (file));
+  mousepad_return_if_fail (GTK_IS_SOURCE_BUFFER (file->buffer));
+
+  if (G_UNLIKELY (language_id == NULL))
+    {
+      gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (file->buffer), NULL);
+      return;
+    }
+
+  lang = gtk_source_language_manager_get_language (gtk_source_language_manager_get_default (), language_id);
+  mousepad_file_set_language (file, lang);
+}
+
+
+
+const gchar *
+mousepad_file_get_language_id (MousepadFile *file)
+{
+  GtkSourceLanguage *lang;
+
+  lang = mousepad_file_get_language (file);
+  return (lang != NULL) ? gtk_source_language_get_id (lang) : NULL;
+}
+
+
+
+GtkSourceLanguage *
+mousepad_file_guess_language (MousepadFile *file)
+{
+  gchar             *content_type;
+  gboolean           result_uncertain;
+  GtkSourceLanguage *language = NULL;
+
+  content_type = g_content_type_guess (file->filename, NULL, 0, &result_uncertain);
+  if (result_uncertain)
+    {
+      g_free (content_type);
+      content_type = NULL;
+    }
+
+  language = gtk_source_language_manager_guess_language (gtk_source_language_manager_get_default (),
+                                                         file->filename,
+                                                         content_type);
+  g_free (content_type);
+
+  return language;
+}
+
+
+
+gint
+mousepad_file_open (MousepadFile  *file,
+                    const gchar   *template_filename,
+                    GError       **error)
+{
+  GMappedFile      *mapped_file;
+  const gchar      *filename;
+  gint              retval = ERROR_READING_FAILED;
+  gsize             length, written;
+  gsize             bom_length;
+  const gchar      *contents;
+  gchar            *encoded = NULL;
+  const gchar      *charset;
+  GtkTextIter       start_iter, end_iter;
+  struct stat       statb;
+  const gchar      *end, *n, *m;
+  MousepadEncoding  bom_encoding;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), FALSE);
+  mousepad_return_val_if_fail (GTK_IS_TEXT_BUFFER (file->buffer), FALSE);
+  mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  mousepad_return_val_if_fail (file->filename != NULL || template_filename != NULL, FALSE);
+
+  /* get the filename */
+  if (G_UNLIKELY (template_filename != NULL))
+    filename = template_filename;
+  else
+    filename = file->filename;
+
+  /* check if the file exists, if not, it's a filename from the command line */
+  if (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE)
+    {
+      /* update readonly status */
+      mousepad_file_set_readonly (file, FALSE);
+
+      return 0;
+    }
+
+  /* try to open the file */
+  mapped_file = g_mapped_file_new (filename, FALSE, error);
+
+  if (G_LIKELY (mapped_file))
+    {
+      /* get the mapped file contents and length */
+      contents = g_mapped_file_get_contents (mapped_file);
+      length = g_mapped_file_get_length (mapped_file);
+
+      if (G_LIKELY (contents != NULL && length > 0))
+        {
+          /* detect if there is a bom with the encoding type */
+          bom_encoding = mousepad_file_encoding_read_bom (contents, length, &bom_length);
+          if (G_UNLIKELY (bom_encoding != MOUSEPAD_ENCODING_NONE))
+            {
+              /* we've found a valid bom at the start of the contents */
+              file->write_bom = TRUE;
+
+              /* advance the contents offset and decrease length */
+              contents += bom_length;
+              length -= bom_length;
+
+              /* set the detected encoding */
+              file->encoding = bom_encoding;
+            }
+
+          /* handle encoding and check for utf-8 valid text */
+          if (G_LIKELY (file->encoding == MOUSEPAD_ENCODING_UTF_8))
+            {
+              validate:
+
+              /* glib uses a faster validator when the string is nul-terminated */
+              if (G_LIKELY (length > 0 && contents[length] == '\0'))
+                length = -1;
+
+              /* leave when the contents is not utf-8 valid */
+              if (g_utf8_validate (contents, length, &end) == FALSE)
+                {
+                  /* set return value */
+                  retval = ERROR_NOT_UTF8_VALID;
+
+                  /* set an error */
+                  g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+                               _("Invalid byte sequence in conversion input"));
+
+                  goto failed;
+                }
+            }
+          else
+            {
+              /* get the encoding charset */
+              charset = mousepad_encoding_get_charset (file->encoding);
+
+              /* convert the contents */
+              encoded = g_convert (contents, length, "UTF-8", charset, NULL, &written, error);
+
+              /* check if the string is utf-8 valid */
+              if (G_UNLIKELY (encoded == NULL))
+                {
+                  /* set return value */
+                  retval = ERROR_CONVERTING_FAILED;
+
+                  goto failed;
+                }
+
+              /* set new values */
+              contents = encoded;
+              length = written;
+
+              /* validate the converted content */
+              goto validate;
+            }
+
+          /* detect the line ending, based on the first eol we match */
+          for (n = contents; n < end; n = g_utf8_next_char (n))
+            {
+              if (G_LIKELY (*n == '\n'))
+                {
+                  /* set unix line ending */
+                  file->line_ending = MOUSEPAD_EOL_UNIX;
+
+                  break;
+                }
+              else if (*n == '\r')
+                {
+                  /* get next character */
+                  n = g_utf8_next_char (n);
+
+                  /* set dos or mac line ending */
+                  file->line_ending = (*n == '\n') ? MOUSEPAD_EOL_DOS : MOUSEPAD_EOL_MAC;
+
+                  break;
+                }
+            }
+
+          /* get the iter at the beginning of the document */
+          gtk_text_buffer_get_start_iter (file->buffer, &start_iter);
+
+          /* insert the file contents in the buffer (for documents with cr line ending) */
+          for (n = m = contents; n < end; n = g_utf8_next_char (n))
+            {
+              if (G_UNLIKELY (*n == '\r'))
+                {
+                  /* insert the text in the buffer */
+                  if (G_LIKELY (n - m > 0))
+                    gtk_text_buffer_insert (file->buffer, &start_iter, m, n - m);
+
+                  /* advance the offset */
+                  m = g_utf8_next_char (n);
+
+                  /* insert a new line when the document is not cr+lf */
+                  if (*m != '\n')
+                    gtk_text_buffer_insert (file->buffer, &start_iter, "\n", 1);
+                }
+            }
+
+          /* insert the remaining part, or everything for lf line ending */
+          if (G_LIKELY (n - m > 0))
+            gtk_text_buffer_insert (file->buffer, &start_iter, m, n - m);
+
+          /* get the start iter */
+          gtk_text_buffer_get_start_iter (file->buffer, &start_iter);
+
+          /* set the cursor to the beginning of the document */
+          gtk_text_buffer_place_cursor (file->buffer, &start_iter);
+        }
+
+      /* assume everything when file */
+      retval = 0;
+
+      /* store the file status */
+      if (G_LIKELY (filename != template_filename))
+        {
+          if (G_LIKELY (g_stat (file->filename, &statb) == 0))
+            {
+              /* whether the file is readonly (ie. not writable by the user) */
+              mousepad_file_set_readonly (file, !((statb.st_mode & S_IWUSR) != 0));
+
+              /* store the file modification time */
+              file->mtime = statb.st_mtime;
+            }
+          else
+            {
+              /* set return value */
+              retval = ERROR_FILE_STATUS_FAILED;
+            }
+        }
+      else
+        {
+          /* this is a new document with content from a template */
+          file->mtime = 0;
+          mousepad_file_set_readonly (file, FALSE);
+        }
+
+      failed:
+
+      /* make sure the buffer is empty if we did not succeed */
+      if (G_UNLIKELY (retval != 0))
+        {
+          gtk_text_buffer_get_bounds (file->buffer, &start_iter, &end_iter);
+          gtk_text_buffer_delete (file->buffer, &start_iter, &end_iter);
+        }
+
+      /* cleanup */
+      g_free (encoded);
+
+      /* close the mapped file */
+#if GLIB_CHECK_VERSION (2, 21, 0)
+      g_mapped_file_unref (mapped_file);
+#else
+      g_mapped_file_free (mapped_file);
+#endif
+
+      /* guess and set the file's filetype/language */
+      mousepad_file_set_language (file, mousepad_file_guess_language (file));
+
+      /* this does not count as a modified buffer */
+      gtk_text_buffer_set_modified (file->buffer, FALSE);
+    }
+
+  return retval;
+}
+
+
+
+gboolean
+mousepad_file_save (MousepadFile  *file,
+                    GError       **error)
+{
+  gint          fd;
+  gboolean      succeed = FALSE;
+  gchar        *contents, *p;
+  gchar        *encoded;
+  const gchar  *charset;
+  GtkTextIter   start_iter, end_iter;
+  gint          l, m, length;
+  gsize         written;
+  struct stat   statb;
+  gchar       **chunks;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), FALSE);
+  mousepad_return_val_if_fail (GTK_IS_TEXT_BUFFER (file->buffer), FALSE);
+  mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  mousepad_return_val_if_fail (file->filename != NULL, FALSE);
+
+  /* open the file */
+  fd = g_open (file->filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+  if (G_LIKELY (fd != -1))
+    {
+      /* get the buffer bounds */
+      gtk_text_buffer_get_bounds (file->buffer, &start_iter, &end_iter);
+
+      /* get the buffer contents */
+      contents = gtk_text_buffer_get_slice (file->buffer, &start_iter, &end_iter, TRUE);
+
+      if (G_LIKELY (contents))
+        {
+          /* get the content length */
+          length = strlen (contents);
+
+          /* handle line endings */
+          if (file->line_ending == MOUSEPAD_EOL_MAC)
+            {
+              /* replace the unix with a mac line ending */
+              for (p = contents; *p != '\0'; p++)
+                if (G_UNLIKELY (*p == '\n'))
+                  *p = '\r';
+            }
+          else if (file->line_ending == MOUSEPAD_EOL_DOS)
+            {
+              /* split the contents into chunks */
+              chunks = g_strsplit (contents, "\n", -1);
+
+              /* cleanup */
+              g_free (contents);
+
+              /* join the chunks with dos line endings in between */
+              contents = g_strjoinv ("\r\n", chunks);
+
+              /* cleanup */
+              g_strfreev (chunks);
+
+              /* new contents length */
+              length = strlen (contents);
+            }
+
+          /* add and utf-8 bom at the start of the contents if needed */
+          if (file->write_bom && mousepad_encoding_is_unicode (file->encoding))
+            {
+              /* realloc the contents string */
+              contents = g_realloc (contents, length + 4);
+
+              /* move the existing contents 3 bytes */
+              g_memmove (contents + 3, contents, length + 1);
+
+              /* write an utf-8 bom at the start of the contents */
+              contents[0] = (guchar) 0xef;
+              contents[1] = (guchar) 0xbb;
+              contents[2] = (guchar) 0xbf;
+
+              /* increase the length */
+              length += 3;
+            }
+
+          /* convert to the encoding if set */
+          if (G_UNLIKELY (file->encoding != MOUSEPAD_ENCODING_UTF_8))
+            {
+              /* get the charset */
+              charset = mousepad_encoding_get_charset (file->encoding);
+              if (G_UNLIKELY (charset == NULL))
+                goto failed;
+
+              /* convert the content to the user encoding */
+              encoded = g_convert (contents, length, charset, "UTF-8", NULL, &written, error);
+
+              /* return if nothing was encoded */
+              if (G_UNLIKELY (encoded == NULL))
+                goto failed;
+
+              /* cleanup */
+              g_free (contents);
+
+              /* set the new contents */
+              contents = encoded;
+              length = written;
+            }
+
+          /* write the buffer to the file */
+          for (m = 0; m < length;)
+            {
+              /* write */
+              l = write (fd, contents + m, length - m);
+
+              if (G_UNLIKELY (l < 0))
+                {
+                  /* just try again on EAGAIN/EINTR */
+                  if (G_LIKELY (errno != EAGAIN && errno != EINTR))
+                    {
+                      /* set an error */
+                      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s", g_strerror (errno));
+
+                      /* bail out */
+                      goto failed;
+                    }
+                }
+              else
+                {
+                  /* advance the offset */
+                  m += l;
+                }
+            }
+
+          /* set the new modification time */
+          if (G_LIKELY (fstat (fd, &statb) == 0))
+            file->mtime = statb.st_mtime;
+
+          /* everything has been saved */
+          gtk_text_buffer_set_modified (file->buffer, FALSE);
+
+          /* we saved succesfully */
+          mousepad_file_set_readonly (file, FALSE);
+
+          /* everything went file */
+          succeed = TRUE;
+
+          failed:
+
+          /* cleanup */
+          g_free (contents);
+
+          /* close the file */
+          close (fd);
+        }
+    }
+  else
+    {
+      /* set an error */
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), "%s", g_strerror (errno));
+    }
+
+  return succeed;
+}
+
+
+
+gboolean
+mousepad_file_reload (MousepadFile  *file,
+                      GError       **error)
+{
+  GtkTextIter start, end;
+  gboolean    succeed = FALSE;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), FALSE);
+  mousepad_return_val_if_fail (GTK_IS_TEXT_BUFFER (file->buffer), FALSE);
+  mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  mousepad_return_val_if_fail (file->filename != NULL, FALSE);
+
+  /* simple test if the file has not been removed */
+  if (G_UNLIKELY (g_file_test (file->filename, G_FILE_TEST_EXISTS) == FALSE))
+    {
+      /* set an error */
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
+                   _("The file \"%s\" you tried to reload does not exist anymore"), file->filename);
+
+      return FALSE;
+    }
+
+  /* clear the buffer */
+  gtk_text_buffer_get_bounds (file->buffer, &start, &end);
+  gtk_text_buffer_delete (file->buffer, &start, &end);
+
+  /* reload the file */
+  succeed = mousepad_file_open (file, NULL, error);
+
+  return succeed;
+}
+
+
+
+gboolean
+mousepad_file_get_externally_modified (MousepadFile  *file,
+                                       GError       **error)
+{
+  struct stat statb;
+  GFileError  error_code;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_FILE (file), TRUE);
+  mousepad_return_val_if_fail (file->filename != NULL, TRUE);
+  mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* check if our modification time differs from the current one */
+  if (G_LIKELY (g_stat (file->filename, &statb) == 0))
+    return (file->mtime > 0 && statb.st_mtime != file->mtime);
+
+  /* get the error code */
+  error_code = g_file_error_from_errno (errno);
+
+  /* file does not exists, nothing wrong with that */
+  if (G_LIKELY (error_code == G_FILE_ERROR_NOENT))
+    return FALSE;
+
+  /* set an error */
+  if (error != NULL)
+    g_set_error (error, G_FILE_ERROR, error_code, _("Failed to read the status of \"%s\""), file->filename);
+
+  return TRUE;
+}
diff --git a/mousepad/mousepad-file.h b/mousepad/mousepad-file.h
new file mode 100644
index 0000000..e9a8be3
--- /dev/null
+++ b/mousepad/mousepad-file.h
@@ -0,0 +1,97 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_FILE_H__
+#define __MOUSEPAD_FILE_H__
+
+G_BEGIN_DECLS
+
+#include <mousepad/mousepad-encoding.h>
+
+typedef struct _MousepadFileClass  MousepadFileClass;
+typedef struct _MousepadFile       MousepadFile;
+typedef enum   _MousepadLineEnding MousepadLineEnding;
+
+#define MOUSEPAD_TYPE_FILE            (mousepad_file_get_type ())
+#define MOUSEPAD_FILE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_FILE, MousepadFile))
+#define MOUSEPAD_FILE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_FILE, MousepadFileClass))
+#define MOUSEPAD_IS_FILE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_FILE))
+#define MOUSEPAD_IS_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOUSEPAD_TYPE_FILE))
+#define MOUSEPAD_FILE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_FILE, MousepadFileClass))
+
+enum _MousepadLineEnding
+{
+  MOUSEPAD_EOL_UNIX,
+  MOUSEPAD_EOL_MAC,
+  MOUSEPAD_EOL_DOS
+};
+
+GType               mousepad_file_get_type                 (void) G_GNUC_CONST;
+
+MousepadFile       *mousepad_file_new                      (GtkTextBuffer       *buffer);
+
+void                mousepad_file_set_filename             (MousepadFile        *file,
+                                                            const gchar         *filename);
+
+const gchar        *mousepad_file_get_filename             (MousepadFile        *file);
+
+gchar              *mousepad_file_get_uri                  (MousepadFile        *file);
+
+void                mousepad_file_set_encoding             (MousepadFile        *file,
+                                                            MousepadEncoding     encoding);
+
+MousepadEncoding    mousepad_file_get_encoding             (MousepadFile        *file);
+
+gboolean            mousepad_file_get_read_only            (MousepadFile        *file);
+
+void                mousepad_file_set_write_bom            (MousepadFile        *file,
+                                                            gboolean             write_bom);
+
+gboolean            mousepad_file_get_write_bom            (MousepadFile        *file,
+                                                            gboolean            *sensitive);
+
+void                mousepad_file_set_line_ending          (MousepadFile        *file,
+                                                            MousepadLineEnding   line_ending);
+
+MousepadLineEnding  mousepad_file_get_line_ending          (MousepadFile        *file);
+
+void                mousepad_file_set_language             (MousepadFile        *file,
+                                                            GtkSourceLanguage   *language);
+
+GtkSourceLanguage  *mousepad_file_get_language             (MousepadFile        *file);
+
+void                mousepad_file_set_language_id          (MousepadFile        *file,
+                                                            const gchar         *language_id);
+
+const gchar        *mousepad_file_get_language_id          (MousepadFile        *file);
+
+GtkSourceLanguage  *mousepad_file_guess_language           (MousepadFile        *file);
+
+gint                mousepad_file_open                     (MousepadFile        *file,
+                                                            const gchar         *template_filename,
+                                                            GError             **error);
+
+gboolean            mousepad_file_save                     (MousepadFile        *file,
+                                                            GError             **error);
+
+gboolean            mousepad_file_reload                   (MousepadFile        *file,
+                                                            GError             **error);
+
+gboolean            mousepad_file_get_externally_modified  (MousepadFile        *file,
+                                                            GError             **error);
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_FILE_H__ */
diff --git a/mousepad/mousepad-marshal.list b/mousepad/mousepad-marshal.list
new file mode 100644
index 0000000..4b5c216
--- /dev/null
+++ b/mousepad/mousepad-marshal.list
@@ -0,0 +1,3 @@
+VOID:INT,INT,INT
+INT:FLAGS,STRING,STRING
+VOID:OBJECT,INT,INT
diff --git a/mousepad/mousepad-preferences.c b/mousepad/mousepad-preferences.c
new file mode 100644
index 0000000..740b281
--- /dev/null
+++ b/mousepad/mousepad-preferences.c
@@ -0,0 +1,652 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <glib-object.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-util.h>
+#include <mousepad/mousepad-preferences.h>
+
+#define GROUP_NAME "Configuration"
+
+
+
+enum
+{
+  PROP_0,
+
+  /* search preferences */
+  PROP_SEARCH_DIRECTION,
+  PROP_SEARCH_MATCH_CASE,
+  PROP_SEARCH_MATCH_WHOLE_WORD,
+  PROP_SEARCH_REPLACE_ALL_LOCATION,
+
+  /* textview preferences */
+  PROP_VIEW_AUTO_INDENT,
+  PROP_VIEW_FONT_NAME,
+  PROP_VIEW_LINE_NUMBERS,
+  PROP_VIEW_TAB_WIDTH,
+  PROP_VIEW_TABS_AS_SPACES,
+  PROP_VIEW_WORD_WRAP,
+  PROP_VIEW_COLOR_SCHEME,
+
+  /* window preferences */
+  PROP_WINDOW_HEIGHT,
+  PROP_WINDOW_WIDTH,
+  PROP_WINDOW_STATUSBAR_VISIBLE,
+
+  /* hidden settings */
+  PROP_MISC_ALWAYS_SHOW_TABS,
+  PROP_MISC_CYCLE_TABS,
+  PROP_MISC_DEFAULT_TAB_SIZES,
+  PROP_MISC_PATH_IN_TITLE,
+  PROP_MISC_RECENT_MENU_ITEMS,
+  PROP_MISC_REMEMBER_GEOMETRY,
+  N_PROPERTIES
+};
+
+
+
+static void     mousepad_preferences_finalize           (GObject                  *object);
+static void     mousepad_preferences_get_property       (GObject                  *object,
+                                                         guint                     prop_id,
+                                                         GValue                   *value,
+                                                         GParamSpec               *pspec);
+static void     mousepad_preferences_set_property       (GObject                  *object,
+                                                         guint                     prop_id,
+                                                         const GValue             *value,
+                                                         GParamSpec               *pspec);
+#ifndef NDEBUG
+static void     mousepad_preferences_check_option_name  (GParamSpec               *pspec);
+#endif
+static void     mousepad_preferences_load               (MousepadPreferences      *preferences);
+static void     mousepad_preferences_store              (MousepadPreferences      *preferences);
+static gboolean mousepad_preferences_store_idle         (gpointer                  user_data);
+static void     mousepad_preferences_store_idle_destroy (gpointer                  user_data);
+
+struct _MousepadPreferencesClass
+{
+  GObjectClass __parent__;
+};
+
+struct _MousepadPreferences
+{
+  GObject  __parent__;
+
+  /* all the properties stored in the object */
+  GValue   values[N_PROPERTIES];
+
+  /* idle save timer id */
+  gint     store_idle_id;
+};
+
+
+
+G_DEFINE_TYPE (MousepadPreferences, mousepad_preferences, G_TYPE_OBJECT);
+
+
+
+static void
+mousepad_preferences_class_init (MousepadPreferencesClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_preferences_finalize;
+  gobject_class->get_property = mousepad_preferences_get_property;
+  gobject_class->set_property = mousepad_preferences_set_property;
+
+  /**
+   * Search Preferences
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_SEARCH_DIRECTION,
+                                   g_param_spec_int ("search-direction",
+                                                     "SearchDirection",
+                                                     NULL,
+                                                     0, 2, 1,
+                                                     MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_SEARCH_MATCH_CASE,
+                                   g_param_spec_boolean ("search-match-case",
+                                                         "SearchMatchCase",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_SEARCH_MATCH_WHOLE_WORD,
+                                   g_param_spec_boolean ("search-match-whole-word",
+                                                         "SearchMatchWholeWord",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_SEARCH_REPLACE_ALL_LOCATION,
+                                   g_param_spec_int ("search-replace-all-location",
+                                                     "SearchReplaceAllLocation",
+                                                     NULL,
+                                                     0, 2, 1,
+                                                     MOUSEPAD_PARAM_READWRITE));
+
+  /**
+   * Textview Preferences
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_VIEW_AUTO_INDENT,
+                                   g_param_spec_boolean ("view-auto-indent",
+                                                         "ViewAutoIndent",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_VIEW_FONT_NAME,
+                                   g_param_spec_string ("view-font-name",
+                                                        "ViewFontName",
+                                                        NULL,
+                                                        NULL,
+                                                        MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_VIEW_LINE_NUMBERS,
+                                   g_param_spec_boolean ("view-line-numbers",
+                                                         "ViewLineNumbers",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_VIEW_TAB_WIDTH,
+                                   g_param_spec_int ("view-tab-size",
+                                                     "ViewTabSize",
+                                                     NULL,
+                                                     1, 32, 8,
+                                                     MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_VIEW_TABS_AS_SPACES,
+                                   g_param_spec_boolean ("view-insert-spaces",
+                                                         "ViewInsertSpaces",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_VIEW_WORD_WRAP,
+                                   g_param_spec_boolean ("view-word-wrap",
+                                                         "ViewWordWrap",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_VIEW_COLOR_SCHEME,
+                                   g_param_spec_string ("view-color-scheme",
+                                                        "ViewColorScheme",
+                                                        NULL,
+                                                        "none",
+                                                        MOUSEPAD_PARAM_READWRITE));
+
+
+  /**
+   * Window Preferences
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_WINDOW_HEIGHT,
+                                   g_param_spec_int ("window-height",
+                                                     "WindowHeight",
+                                                     NULL,
+                                                     1, G_MAXINT, 480,
+                                                     MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_WINDOW_WIDTH,
+                                   g_param_spec_int ("window-width",
+                                                     "WindowWidth",
+                                                     NULL,
+                                                     1, G_MAXINT, 640,
+                                                     MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_WINDOW_STATUSBAR_VISIBLE,
+                                   g_param_spec_boolean ("window-statusbar-visible",
+                                                         "WindowStatusbarVisible",
+                                                         NULL,
+                                                         TRUE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+
+  /**
+   * Hidden Preferences
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_ALWAYS_SHOW_TABS,
+                                   g_param_spec_boolean ("misc-always-show-tabs",
+                                                         "MiscAlwaysShowTabs",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_CYCLE_TABS,
+                                   g_param_spec_boolean ("misc-cycle-tabs",
+                                                         "MiscCycleTabs",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_DEFAULT_TAB_SIZES,
+                                   g_param_spec_string ("misc-default-tab-sizes",
+                                                        "MiscDefaultTabSizes",
+                                                        NULL,
+                                                        "2,3,4,8",
+                                                        MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_PATH_IN_TITLE,
+                                   g_param_spec_boolean ("misc-path-in-title",
+                                                         "MiscPathInTitle",
+                                                         NULL,
+                                                         FALSE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_RECENT_MENU_ITEMS,
+                                   g_param_spec_int ("misc-recent-menu-items",
+                                                     "MiscRecentMenuItems",
+                                                     NULL,
+                                                     1, 100, 10,
+                                                     MOUSEPAD_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_REMEMBER_GEOMETRY,
+                                   g_param_spec_boolean ("misc-remember-geometry",
+                                                         "MiscRememberGeometry",
+                                                         NULL,
+                                                         TRUE,
+                                                         MOUSEPAD_PARAM_READWRITE));
+}
+
+
+
+static void
+mousepad_preferences_init (MousepadPreferences *preferences)
+{
+  /* load the settings */
+  mousepad_preferences_load (preferences);
+}
+
+
+
+static void
+mousepad_preferences_finalize (GObject *object)
+{
+  MousepadPreferences *preferences = MOUSEPAD_PREFERENCES (object);
+  guint                n;
+
+  /* flush preferences */
+  if (G_UNLIKELY (preferences->store_idle_id != 0))
+    {
+      g_source_remove (preferences->store_idle_id);
+      mousepad_preferences_store (preferences);
+    }
+  /* release the property values */
+  for (n = 1; n < N_PROPERTIES; ++n)
+    if (G_IS_VALUE (preferences->values + n))
+      g_value_unset (preferences->values + n);
+
+  (*G_OBJECT_CLASS (mousepad_preferences_parent_class)->finalize) (object);
+}
+
+
+
+static void
+mousepad_preferences_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  MousepadPreferences *preferences = MOUSEPAD_PREFERENCES (object);
+  GValue              *src = preferences->values + prop_id;
+
+  if (G_LIKELY (G_IS_VALUE (src)))
+    g_value_copy (src, value);
+  else
+    g_param_value_set_default (pspec, value);
+}
+
+
+
+static void
+mousepad_preferences_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  MousepadPreferences *preferences = MOUSEPAD_PREFERENCES (object);
+  GValue              *dst = preferences->values + prop_id;
+
+  /* initialize value if needed */
+  if (G_UNLIKELY (G_IS_VALUE (dst) == FALSE))
+    {
+      g_value_init (dst, pspec->value_type);
+      g_param_value_set_default (pspec, dst);
+    }
+
+  /* compare the values */
+  if (g_param_values_cmp (pspec, value, dst) != 0)
+    {
+      /* copy the new value */
+      g_value_copy (value, dst);
+
+      /* queue a store */
+      mousepad_preferences_store (preferences);
+    }
+}
+
+
+
+#ifndef NDEBUG
+static void
+mousepad_preferences_check_option_name (GParamSpec *pspec)
+{
+  const gchar *name, *nick;
+  gchar       *option;
+
+  /* get property name and nick */
+  name = g_param_spec_get_name (pspec);
+  nick = g_param_spec_get_nick (pspec);
+
+  if (G_UNLIKELY (nick == NULL))
+    {
+      g_warning ("The nick name of %s is NULL", name);
+    }
+  else
+    {
+      /* get option name */
+      option = mousepad_util_config_name (name);
+
+      /* compare the strings */
+      if (G_UNLIKELY (!option || strcmp (option, nick) != 0))
+        g_warning ("The option name (%s) and nick name (%s) of property %s do not match", option, nick, name);
+
+      /* cleanup */
+      g_free (option);
+    }
+}
+#endif
+
+
+
+static void
+mousepad_preferences_load (MousepadPreferences *preferences)
+{
+  gchar          *string;
+  GParamSpec    **pspecs;
+  GParamSpec     *pspec;
+  GParamSpecInt  *ispec;
+  GKeyFile       *keyfile;
+  gchar          *filename;
+  GValue         *dst;
+  guint           nspecs;
+  guint           n;
+  gint            integer;
+
+  /* get the save location, leave when there if no file found */
+  filename = mousepad_util_get_save_location (MOUSEPAD_RC_RELPATH, FALSE);
+  if (G_UNLIKELY (filename == NULL))
+    return;
+
+  /* create a new key file */
+  keyfile = g_key_file_new ();
+
+  /* open the config file */
+  if (G_LIKELY (g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL)))
+    {
+      /* freeze notification signals */
+      g_object_freeze_notify (G_OBJECT (preferences));
+
+      /* get all the properties in the class */
+      pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (preferences), &nspecs);
+
+      for (n = 0; n < nspecs; n++)
+        {
+          /* get the pspec */
+          pspec = pspecs[n];
+
+          /* get the pspec destination value and initialize it */
+          dst = preferences->values + (n + 1);
+          g_value_init (dst, pspec->value_type);
+
+#ifndef NDEBUG
+          /* check nick name with generated option name */
+          mousepad_preferences_check_option_name (pspec);
+#endif
+
+          /* read the propert value from the key file */
+          string = g_key_file_get_value (keyfile, GROUP_NAME, g_param_spec_get_nick (pspec), NULL);
+          if (G_UNLIKELY (string == NULL || *string == '\0'))
+            goto setdefault;
+
+          if (pspec->value_type == G_TYPE_STRING)
+            {
+              /* set string as the value */
+              g_value_take_string (dst, string);
+
+              /* don't free the string */
+              string = NULL;
+            }
+          else if (pspec->value_type == G_TYPE_INT)
+            {
+              /* get integer spec */
+              ispec = G_PARAM_SPEC_INT (pspec);
+
+              /* get the value and clamp it */
+              integer = CLAMP (atoi (string), ispec->minimum, ispec->maximum);
+
+              /* set the integer */
+              g_value_set_int (dst, integer);
+            }
+          else if (pspec->value_type == G_TYPE_BOOLEAN)
+            {
+              /* set the boolean */
+              g_value_set_boolean (dst, (strcmp (string, "false") != 0));
+            }
+          else
+            {
+              /* print warning */
+              g_warning ("Failed to load property \"%s\"", pspec->name);
+
+              setdefault:
+
+              /* set default */
+              g_param_value_set_default (pspec, dst);
+            }
+
+          /* cleanup */
+          g_free (string);
+        }
+
+      /* cleanup the specs */
+      g_free (pspecs);
+
+      /* allow notifications again */
+      g_object_thaw_notify (G_OBJECT (preferences));
+    }
+
+  /* free the key file */
+  g_key_file_free (keyfile);
+
+  /* cleanup filename */
+  g_free (filename);
+}
+
+
+
+static void
+mousepad_preferences_store (MousepadPreferences *preferences)
+{
+  if (preferences->store_idle_id == 0)
+    {
+      preferences->store_idle_id = g_idle_add_full (G_PRIORITY_LOW, mousepad_preferences_store_idle,
+                                                    preferences, mousepad_preferences_store_idle_destroy);
+    }
+}
+
+
+
+static gboolean
+mousepad_preferences_store_idle (gpointer user_data)
+{
+  MousepadPreferences  *preferences = MOUSEPAD_PREFERENCES (user_data);
+  GParamSpec          **pspecs;
+  GParamSpec           *pspec;
+  GKeyFile             *keyfile;
+  gchar                *filename;
+  GValue               *value;
+  guint                 nspecs;
+  guint                 n;
+  const gchar          *nick;
+
+  /* get the config filename */
+  filename = mousepad_util_get_save_location (MOUSEPAD_RC_RELPATH, TRUE);
+
+  /* leave when no filename is returned */
+  if (G_UNLIKELY (filename == NULL))
+    return FALSE;
+
+  /* create an empty key file */
+  keyfile = g_key_file_new ();
+
+  /* try to load the file contents, no worries if this fails */
+  g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL);
+
+  /* get the list of properties in the class */
+  pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (preferences), &nspecs);
+
+  for (n = 0; n < nspecs; n++)
+    {
+      /* get the pspec */
+      pspec = pspecs[n];
+
+      /* get the value */
+      value = preferences->values + (n + 1);
+
+      /* continue if the value is not initialized */
+      if (G_UNLIKELY (G_IS_VALUE (value) == FALSE))
+        continue;
+
+      /* get nick name */
+      nick = g_param_spec_get_nick (pspec);
+
+      if (pspec->value_type == G_TYPE_STRING)
+        {
+          /* store the string */
+          if (g_value_get_string (value) != NULL)
+            g_key_file_set_value (keyfile, GROUP_NAME, nick, g_value_get_string (value));
+        }
+      else if (pspec->value_type == G_TYPE_INT)
+        {
+          /* store the interger */
+          g_key_file_set_integer (keyfile, GROUP_NAME, nick, g_value_get_int (value));
+        }
+      else if (pspec->value_type == G_TYPE_BOOLEAN)
+        {
+          /* store the boolean */
+          g_key_file_set_boolean (keyfile, GROUP_NAME, nick, g_value_get_boolean (value));
+        }
+      else
+        {
+          g_warning ("Failed to save property \"%s\"", pspec->name);
+        }
+    }
+
+  /* cleanup the specs */
+  g_free (pspecs);
+
+  /* save the keyfile */
+  mousepad_util_save_key_file (keyfile, filename);
+
+  /* close the key file */
+  g_key_file_free (keyfile);
+
+  /* cleanup */
+  g_free (filename);
+
+  return FALSE;
+}
+
+
+
+static void
+mousepad_preferences_store_idle_destroy (gpointer user_data)
+{
+  MOUSEPAD_PREFERENCES (user_data)->store_idle_id = 0;
+}
+
+
+
+/**
+ * mousepad_preferences_get:
+ *
+ * Queries the global #MousepadPreferences instance, which is shared
+ * by all modules. The function automatically takes a reference
+ * for the caller, so you'll need to call g_object_unref() when
+ * you're done with it.
+ *
+ * Return value: the global #MousepadPreferences instance.
+ **/
+MousepadPreferences*
+mousepad_preferences_get (void)
+{
+  static MousepadPreferences *preferences = NULL;
+
+  if (G_UNLIKELY (preferences == NULL))
+    {
+      preferences = g_object_new (MOUSEPAD_TYPE_PREFERENCES, NULL);
+      g_object_add_weak_pointer (G_OBJECT (preferences), (gpointer) &preferences);
+    }
+  else
+    {
+      g_object_ref (G_OBJECT (preferences));
+    }
+
+  return preferences;
+}
diff --git a/mousepad/mousepad-preferences.h b/mousepad/mousepad-preferences.h
new file mode 100644
index 0000000..31302b7
--- /dev/null
+++ b/mousepad/mousepad-preferences.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_PREFERENCIES_H__
+#define __MOUSEPAD_PREFERENCIES_H__
+
+G_BEGIN_DECLS
+
+#define MOUSEPAD_TYPE_PREFERENCES             (mousepad_preferences_get_type ())
+#define MOUSEPAD_PREFERENCES(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_PREFERENCES, MousepadPreferences))
+#define MOUSEPAD_PREFERENCES_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_PREFERENCES, MousepadPreferencesClass))
+#define MOUSEPAD_IS_PREFERENCES(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_PREFERENCES))
+#define MOUSEPAD_IS_PREFERENCES_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), MOUSEPAD_TYPE_PREFERENCES))
+#define MOUSEPAD_PREFERENCES_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_PREFERENCES, MousepadPreferencesClass))
+
+typedef struct _MousepadPreferencesClass MousepadPreferencesClass;
+typedef struct _MousepadPreferences      MousepadPreferences;
+
+GType                mousepad_preferences_get_type (void) G_GNUC_CONST;
+
+MousepadPreferences *mousepad_preferences_get      (void);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_PREFERENCIES_H__ */
diff --git a/mousepad/mousepad-print.c b/mousepad/mousepad-print.c
new file mode 100644
index 0000000..e647ae1
--- /dev/null
+++ b/mousepad/mousepad-print.c
@@ -0,0 +1,805 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pango/pango.h>
+#include <cairo.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-preferences.h>
+#include <mousepad/mousepad-document.h>
+#include <mousepad/mousepad-util.h>
+#include <mousepad/mousepad-print.h>
+
+#define DOCUMENT_SPACING (10)
+
+
+
+static void           mousepad_print_finalize              (GObject                 *object);
+static void           mousepad_print_settings_load         (GtkPrintOperation       *operation);
+static void           mousepad_print_settings_save_foreach (const gchar             *key,
+                                                            const gchar             *value,
+                                                            gpointer                 user_data);
+static void           mousepad_print_settings_save         (GtkPrintOperation       *operation);
+static void           mousepad_print_begin_print           (GtkPrintOperation       *operation,
+                                                            GtkPrintContext         *context);
+static void           mousepad_print_draw_page             (GtkPrintOperation       *operation,
+                                                            GtkPrintContext         *context,
+                                                            gint                     page_nr);
+static void           mousepad_print_page_setup_dialog     (GtkWidget               *button,
+                                                            GtkPrintOperation       *operation);
+static void           mousepad_print_button_toggled        (GtkWidget               *button,
+                                                            MousepadPrint           *print);
+static void           mousepad_print_button_font_set       (GtkFontButton           *button,
+                                                            MousepadPrint           *print);
+static PangoAttrList *mousepad_print_attr_list_bold        (void);
+static GtkWidget     *mousepad_print_create_custom_widget  (GtkPrintOperation       *operation);
+static void           mousepad_print_status_changed        (GtkPrintOperation       *operation);
+static void           mousepad_print_done                  (GtkPrintOperation       *operation,
+                                                            GtkPrintOperationResult  result);
+
+
+
+struct _MousepadPrintClass
+{
+  GtkPrintOperationClass __parent__;
+};
+
+struct _MousepadPrint
+{
+  GtkPrintOperation __parent__;
+
+  /* the document we're going to print */
+  MousepadDocument        *document;
+
+  /* print dialog widgets */
+  GtkWidget                *widget_page_headers;
+  GtkWidget                *widget_page_footers;
+  GtkWidget                *widget_line_numbers;
+  GtkWidget                *widget_text_wrapping;
+  GtkWidget                *widget_syntax_highlighting;
+  GtkWidget                *widget_header_font;
+  GtkWidget                *widget_line_numbers_font;
+  GtkWidget                *widget_body_font;
+  GtkWidget                *widget_line_numbers_spin;
+  GtkWidget                *widget_line_numbers_hbox;
+
+  /* settings */
+  gboolean                  print_line_numbers;
+  gint                      line_number_increment;
+
+  /* source view print compositor */
+  GtkSourcePrintCompositor *compositor;
+};
+
+
+
+G_DEFINE_TYPE (MousepadPrint, mousepad_print, GTK_TYPE_PRINT_OPERATION);
+
+
+
+static void
+mousepad_print_class_init (MousepadPrintClass *klass)
+{
+  GObjectClass           *gobject_class;
+  GtkPrintOperationClass *gtkprintoperation_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_print_finalize;
+
+  gtkprintoperation_class = GTK_PRINT_OPERATION_CLASS (klass);
+  gtkprintoperation_class->begin_print = mousepad_print_begin_print;
+  gtkprintoperation_class->draw_page = mousepad_print_draw_page;
+  gtkprintoperation_class->create_custom_widget = mousepad_print_create_custom_widget;
+  gtkprintoperation_class->status_changed = mousepad_print_status_changed;
+  gtkprintoperation_class->done = mousepad_print_done;
+}
+
+
+
+static void
+mousepad_print_init (MousepadPrint *print)
+{
+  /* init */
+  print->print_line_numbers = FALSE;
+  print->line_number_increment = 1;
+  print->compositor = NULL;
+
+  /* set a custom tab label */
+  gtk_print_operation_set_custom_tab_label (GTK_PRINT_OPERATION (print), _("Document Settings"));
+}
+
+
+
+static void
+mousepad_print_finalize (GObject *object)
+{
+  MousepadPrint *print = MOUSEPAD_PRINT (object);
+
+  /* cleanup */
+  g_object_unref (print->compositor);
+
+  (*G_OBJECT_CLASS (mousepad_print_parent_class)->finalize) (object);
+}
+
+
+
+static void
+mousepad_print_settings_load (GtkPrintOperation *operation)
+{
+  MousepadPrint         *print = MOUSEPAD_PRINT (operation);
+  GKeyFile              *keyfile;
+  gchar                 *filename;
+  GtkPrintSettings      *settings = NULL;
+  gchar                **keys;
+  gint                   i;
+  gchar                 *key;
+  gchar                 *value;
+  gchar                 *body_font = NULL;
+  gchar                 *header_font = NULL;
+  gchar                 *line_numbers_font = NULL;
+  GtkPageSetup          *page_setup;
+  GtkPaperSize          *paper_size;
+  PangoContext          *context;
+  PangoFontDescription  *font_desc;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (print->document));
+  mousepad_return_if_fail (GTK_IS_WIDGET (print->document->textview));
+
+  /* get the config file filename */
+  filename = mousepad_util_get_save_location (MOUSEPAD_RC_RELPATH, FALSE);
+  if (G_UNLIKELY (filename == NULL))
+    return;
+
+  /* create a new keyfile */
+  keyfile = g_key_file_new ();
+
+  if (G_LIKELY (g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL)))
+    {
+      /* get all the keys from the config file */
+      keys = g_key_file_get_keys (keyfile, "Print Settings", NULL, NULL);
+
+      if (G_LIKELY (keys))
+        {
+          /* create new settings object */
+          settings = gtk_print_settings_new ();
+
+          /* set all the keys */
+          for (i = 0; keys[i] != NULL; i++)
+            {
+              /* read the value from the config file */
+              value = g_key_file_get_value (keyfile, "Print Settings", keys[i], NULL);
+
+              /* set the value */
+              if (G_LIKELY (value))
+                {
+                  key = mousepad_util_key_name (keys[i]);
+                  gtk_print_settings_set (settings, key, value);
+                  g_free (key);
+                  g_free (value);
+                }
+            }
+
+          /* cleanup */
+          g_strfreev (keys);
+        }
+    }
+
+  /* free the key file */
+  g_key_file_free (keyfile);
+
+  /* cleanup */
+  g_free (filename);
+
+  if (G_LIKELY (settings))
+    {
+      /* apply the settings */
+      gtk_print_operation_set_print_settings (operation, settings);
+
+      if (gtk_print_settings_get_bool (settings, "page-setup-saved") == TRUE)
+        {
+          /* create new page setup */
+          page_setup = gtk_page_setup_new ();
+
+          /* set orientation */
+          gtk_page_setup_set_orientation (page_setup, gtk_print_settings_get_orientation (settings));
+
+          /* restore margins */
+          gtk_page_setup_set_top_margin (page_setup, gtk_print_settings_get_double (settings, "top-margin"), GTK_UNIT_MM);
+          gtk_page_setup_set_bottom_margin (page_setup, gtk_print_settings_get_double (settings, "bottom-margin"), GTK_UNIT_MM);
+          gtk_page_setup_set_right_margin (page_setup, gtk_print_settings_get_double (settings, "right-margin"), GTK_UNIT_MM);
+          gtk_page_setup_set_left_margin (page_setup, gtk_print_settings_get_double (settings, "left-margin"), GTK_UNIT_MM);
+
+          /* set paper size */
+          paper_size = gtk_print_settings_get_paper_size (settings);
+          if (G_LIKELY (paper_size))
+            gtk_page_setup_set_paper_size (page_setup, paper_size);
+
+          /* set the default page setup */
+          gtk_print_operation_set_default_page_setup (operation, page_setup);
+
+          /* release reference */
+          g_object_unref (G_OBJECT (page_setup));
+        }
+
+      /* restore print settings */
+      g_object_set (print->compositor,
+                    "print-header",
+                    gtk_print_settings_get_bool (settings, "print-header"),
+                    "print-line-numbers",
+                    gtk_print_settings_get_int (settings, "line-numbers-increment"),
+                    "wrap-mode",
+                    gtk_print_settings_get_bool (settings, "text-wrapping") ? GTK_WRAP_WORD : GTK_WRAP_NONE,
+                    "highlight-syntax",
+                    gtk_print_settings_get_bool (settings, "highlight-syntax"),
+                    NULL);
+
+      print->print_line_numbers = gtk_print_settings_get_bool (settings, "print-line-numbers");
+      print->line_number_increment = gtk_print_settings_get_int (settings, "line-numbers-increment");
+
+      /* get the saved fonts, if set */
+      body_font = g_strdup (gtk_print_settings_get (settings, "body-font-name"));
+      header_font = g_strdup (gtk_print_settings_get (settings, "header-font-name"));
+      line_numbers_font = g_strdup (gtk_print_settings_get (settings, "line-numbers-font-name"));
+
+      /* release reference */
+      g_object_unref (G_OBJECT (settings));
+    }
+
+    /* if no font name is set, get the one used in the widget */
+    if (G_UNLIKELY (body_font == NULL))
+      {
+        /* get the font description from the context and convert it into a string */
+        context = gtk_widget_get_pango_context (GTK_WIDGET (print->document->textview));
+        font_desc = pango_context_get_font_description (context);
+        body_font = pango_font_description_to_string (font_desc);
+      }
+
+    /* set the restored body font or the one from the textview */
+    gtk_source_print_compositor_set_body_font_name (print->compositor, body_font);
+
+    /* if header font restored use it, otherwise use body font */
+    if (header_font)
+      gtk_source_print_compositor_set_header_font_name (print->compositor, header_font);
+    else
+      gtk_source_print_compositor_set_header_font_name (print->compositor, body_font);
+
+    /* if line numbers font restored use it, otherwise use body font */
+    if (line_numbers_font)
+      gtk_source_print_compositor_set_line_numbers_font_name (print->compositor, line_numbers_font);
+    else
+      gtk_source_print_compositor_set_line_numbers_font_name (print->compositor, body_font);
+
+    /* cleanup */
+    g_free (body_font);
+    g_free (header_font);
+    g_free (line_numbers_font);
+}
+
+
+
+static void
+mousepad_print_settings_save_foreach (const gchar *key,
+                                      const gchar *value,
+                                      gpointer     user_data)
+{
+  GKeyFile *keyfile = user_data;
+  gchar    *config;
+
+  /* save the setting */
+  if (G_LIKELY (key && value))
+    {
+      config = mousepad_util_config_name (key);
+      g_key_file_set_value (keyfile, "Print Settings", config, value);
+      g_free (config);
+    }
+}
+
+
+
+static void
+mousepad_print_settings_save (GtkPrintOperation *operation)
+{
+  MousepadPrint    *print = MOUSEPAD_PRINT (operation);
+  GKeyFile         *keyfile;
+  gchar            *filename;
+  GtkPrintSettings *settings;
+  GtkPageSetup     *page_setup;
+  GtkPaperSize     *paper_size;
+
+  /* get the save location */
+  filename = mousepad_util_get_save_location (MOUSEPAD_RC_RELPATH, TRUE);
+
+  /* create a new keyfile */
+  keyfile = g_key_file_new ();
+
+  /* load the existing settings */
+  if (G_LIKELY (g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL)))
+    {
+      /* get the print settings */
+      settings = gtk_print_operation_get_print_settings (operation);
+
+      if (G_LIKELY (settings != NULL))
+        {
+          /* get the page setup */
+          page_setup = gtk_print_operation_get_default_page_setup (operation);
+
+          /* restore the page setup */
+          if (G_LIKELY (page_setup != NULL))
+            {
+              /* the the settings page orienation */
+              gtk_print_settings_set_orientation (settings, gtk_page_setup_get_orientation (page_setup));
+
+              /* save margins */
+              gtk_print_settings_set_double (settings, "top-margin", gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM));
+              gtk_print_settings_set_double (settings, "bottom-margin", gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM));
+              gtk_print_settings_set_double (settings, "right-margin", gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM));
+              gtk_print_settings_set_double (settings, "left-margin", gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM));
+
+              /* get the paper size */
+              paper_size = gtk_page_setup_get_paper_size (page_setup);
+
+              /* set settings page size */
+              if (G_LIKELY (paper_size))
+                gtk_print_settings_set_paper_size (settings, paper_size);
+            }
+
+          /* a bool we use for loading */
+          gtk_print_settings_set_bool (settings, "page-setup-saved", page_setup != NULL);
+
+          /* set print settings */
+          gtk_print_settings_set_bool (settings,
+                                       "print-header",
+                                       gtk_source_print_compositor_get_print_header (print->compositor));
+
+          gtk_print_settings_set_bool (settings,
+                                       "print-line-numbers",
+                                       print->print_line_numbers);
+
+          gtk_print_settings_set_int (settings,
+                                      "line-numbers-increment",
+                                      print->line_number_increment);
+
+          gtk_print_settings_set_bool (settings,
+                                       "text-wrapping",
+                                       gtk_source_print_compositor_get_wrap_mode (print->compositor) == GTK_WRAP_NONE ? FALSE : TRUE);
+
+          gtk_print_settings_set_bool (settings,
+                                       "highlight-syntax",
+                                       gtk_source_print_compositor_get_highlight_syntax (print->compositor));
+
+          gtk_print_settings_set (settings,
+                                  "body-font-name",
+                                  gtk_source_print_compositor_get_body_font_name (print->compositor));
+
+          gtk_print_settings_set (settings,
+                                  "header-font-name",
+                                  gtk_source_print_compositor_get_header_font_name (print->compositor));
+
+          gtk_print_settings_set (settings,
+                                  "line-numbers-font-name",
+                                  gtk_source_print_compositor_get_line_numbers_font_name (print->compositor));
+
+          /* store all the print settings */
+          gtk_print_settings_foreach (settings, mousepad_print_settings_save_foreach, keyfile);
+
+          /* save the contents */
+          mousepad_util_save_key_file (keyfile, filename);
+        }
+    }
+
+  /* cleanup */
+  g_key_file_free (keyfile);
+  g_free (filename);
+}
+
+
+
+static void
+mousepad_print_begin_print (GtkPrintOperation *operation,
+                            GtkPrintContext   *context)
+{
+  MousepadPrint    *print = MOUSEPAD_PRINT (operation);
+  MousepadDocument *document = print->document;
+  gint              n_pages = 1;
+  const gchar      *file_name;
+
+  /* print header */
+  if (gtk_source_print_compositor_get_print_header (print->compositor))
+    {
+      if (mousepad_document_get_filename (document))
+        file_name = mousepad_document_get_filename (document);
+      else
+        file_name = mousepad_document_get_basename (document);
+
+      gtk_source_print_compositor_set_header_format (print->compositor,
+                                                     TRUE,
+                                                     file_name,
+                                                     NULL,
+                                                     "Page %N of %Q");
+    }
+
+  /* paginate all of the pages at once */
+  while (!gtk_source_print_compositor_paginate (print->compositor, context))
+    ;
+
+  n_pages = gtk_source_print_compositor_get_n_pages (print->compositor);
+
+  /* set the number of pages we're going to draw */
+  gtk_print_operation_set_n_pages (operation, n_pages);
+}
+
+
+
+static void
+mousepad_print_draw_page (GtkPrintOperation *operation,
+                          GtkPrintContext   *context,
+                          gint               page_nr)
+{
+  MousepadPrint *print = MOUSEPAD_PRINT (operation);
+
+  gtk_source_print_compositor_draw_page (print->compositor, context, page_nr);
+}
+
+
+
+static void
+mousepad_print_page_setup_dialog (GtkWidget         *button,
+                                  GtkPrintOperation *operation)
+{
+  GtkWidget        *toplevel;
+  GtkPrintSettings *settings;
+  GtkPageSetup     *page_setup;
+
+  /* get the toplevel of the button */
+  toplevel = gtk_widget_get_toplevel (button);
+  if (G_UNLIKELY (!GTK_WIDGET_TOPLEVEL (toplevel)))
+    toplevel = NULL;
+
+  /* get the print settings */
+  settings = gtk_print_operation_get_print_settings (operation);
+  if (G_UNLIKELY (settings == NULL))
+    settings = gtk_print_settings_new ();
+
+  /* get the page setup */
+  page_setup = gtk_print_operation_get_default_page_setup (operation);
+
+  /* run the dialog */
+  page_setup = gtk_print_run_page_setup_dialog (GTK_WINDOW (toplevel), page_setup, settings);
+
+  /* set the new page setup */
+  gtk_print_operation_set_default_page_setup (operation, page_setup);
+}
+
+
+
+static void
+mousepad_print_button_toggled (GtkWidget     *button,
+                               MousepadPrint *print)
+{
+  gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+  /* save the correct setting */
+  if (button == print->widget_page_headers)
+    gtk_source_print_compositor_set_print_header (print->compositor, active);
+  else if (button == print->widget_line_numbers)
+  {
+    print->print_line_numbers = active;
+    gtk_widget_set_sensitive (print->widget_line_numbers_hbox, active);
+  }
+  else if (button == print->widget_text_wrapping)
+    gtk_source_print_compositor_set_wrap_mode (print->compositor, active ? GTK_WRAP_WORD : GTK_WRAP_NONE);
+  else if (button == print->widget_syntax_highlighting)
+    gtk_source_print_compositor_set_highlight_syntax (print->compositor, active);
+}
+
+
+
+static void
+mousepad_print_button_font_set (GtkFontButton *button,
+                                MousepadPrint *print)
+{
+  const gchar *font;
+  GtkWidget   *widget = GTK_WIDGET (button);
+
+  font = gtk_font_button_get_font_name (button);
+
+  if (widget == print->widget_body_font)
+    gtk_source_print_compositor_set_body_font_name (print->compositor, font);
+  else if (widget == print->widget_header_font)
+    gtk_source_print_compositor_set_header_font_name (print->compositor, font);
+  else if (widget == print->widget_line_numbers_font)
+    gtk_source_print_compositor_set_line_numbers_font_name (print->compositor, font);
+}
+
+
+
+static void
+mousepad_print_spin_value_changed (GtkSpinButton *button,
+                                   MousepadPrint *print)
+{
+  print->line_number_increment = gtk_spin_button_get_value_as_int (button);
+
+  if (print->line_number_increment > 0 && print->print_line_numbers)
+    {
+      gtk_source_print_compositor_set_print_line_numbers (print->compositor,
+                                                          print->line_number_increment);
+    }
+  else
+    gtk_source_print_compositor_set_print_line_numbers (print->compositor, 0);
+}
+
+
+
+static PangoAttrList *
+mousepad_print_attr_list_bold (void)
+{
+  static PangoAttrList *attr_list = NULL;
+  PangoAttribute       *attr;
+
+  if (G_UNLIKELY (attr_list == NULL))
+    {
+      /* create new attributes list */
+      attr_list = pango_attr_list_new ();
+
+      /* create attribute */
+      attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
+      attr->start_index = 0;
+      attr->end_index = -1;
+
+      /* insert bold element */
+      pango_attr_list_insert (attr_list, attr);
+    }
+
+  return attr_list;
+}
+
+
+
+static GtkWidget *
+mousepad_print_create_custom_widget (GtkPrintOperation *operation)
+{
+  MousepadPrint *print = MOUSEPAD_PRINT (operation);
+  GtkWidget     *button;
+  GtkWidget     *vbox, *vbox2;
+  GtkWidget     *frame;
+  GtkWidget     *alignment;
+  GtkWidget     *label;
+  GtkWidget     *table;
+  GtkAdjustment *adjustment;
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
+
+  frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  gtk_widget_show (frame);
+
+  label = gtk_label_new (_("Page Setup"));
+  gtk_label_set_attributes (GTK_LABEL (label), mousepad_print_attr_list_bold ());
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+  gtk_widget_show (label);
+
+  alignment = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 12, 6);
+  gtk_container_add (GTK_CONTAINER (frame), alignment);
+  gtk_widget_show (alignment);
+
+  button = mousepad_util_image_button (GTK_STOCK_PROPERTIES, _("_Adjust page size and orientation"));
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (mousepad_print_page_setup_dialog), operation);
+  gtk_container_add (GTK_CONTAINER (alignment), button);
+  gtk_widget_show (button);
+
+  frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  gtk_widget_show (frame);
+
+  label = gtk_label_new (_("Appearance"));
+  gtk_label_set_attributes (GTK_LABEL (label), mousepad_print_attr_list_bold ());
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+  gtk_widget_show (label);
+
+  alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 12, 6);
+  gtk_container_add (GTK_CONTAINER (frame), alignment);
+  gtk_widget_show (alignment);
+
+  vbox2 = gtk_vbox_new (FALSE, 6);
+  gtk_container_add (GTK_CONTAINER (alignment), vbox2);
+  gtk_widget_show (vbox2);
+
+  button = print->widget_page_headers = gtk_check_button_new_with_mnemonic (_("Print page _headers"));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+                                gtk_source_print_compositor_get_print_header (print->compositor));
+  g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (mousepad_print_button_toggled), print);
+  gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+
+  button = print->widget_line_numbers = gtk_check_button_new_with_mnemonic (_("Print _line numbers"));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+                                print->print_line_numbers);
+  g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (mousepad_print_button_toggled), print);
+  gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+
+  alignment = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 24, 0);
+  gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0);
+  gtk_widget_show (alignment);
+
+  print->widget_line_numbers_hbox = gtk_hbox_new (FALSE, 6);
+  gtk_widget_set_sensitive (print->widget_line_numbers_hbox, print->print_line_numbers);
+  gtk_container_add (GTK_CONTAINER (alignment), print->widget_line_numbers_hbox);
+  gtk_widget_show (print->widget_line_numbers_hbox);
+
+  label = gtk_label_new (_("Number every"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_box_pack_start (GTK_BOX (print->widget_line_numbers_hbox), label, FALSE, TRUE, 0);
+  gtk_widget_show (label);
+
+  adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (1.0, 1.0, 100.0, 1.0, 0.0, 0.0));
+  print->widget_line_numbers_spin = gtk_spin_button_new (adjustment, 1.0, 0);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (print->widget_line_numbers_spin),
+                             (gdouble) print->line_number_increment);
+  g_signal_connect (G_OBJECT (print->widget_line_numbers_spin),
+                    "value-changed",
+                    G_CALLBACK (mousepad_print_spin_value_changed),
+                    print);
+  gtk_box_pack_start (GTK_BOX (print->widget_line_numbers_hbox), print->widget_line_numbers_spin, FALSE, TRUE, 0);
+  gtk_widget_show (print->widget_line_numbers_spin);
+
+  label = gtk_label_new (_("line(s)"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_box_pack_start (GTK_BOX (print->widget_line_numbers_hbox), label, FALSE, TRUE, 0);
+  gtk_widget_show (label);
+
+  button = print->widget_text_wrapping = gtk_check_button_new_with_mnemonic (_("Enable text _wrapping"));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+                                gtk_source_print_compositor_get_wrap_mode (print->compositor) == GTK_WRAP_NONE ? FALSE : TRUE);
+  g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (mousepad_print_button_toggled), print);
+  gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+
+  button = print->widget_syntax_highlighting = gtk_check_button_new_with_mnemonic (_("Enable _syntax highlighting"));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+                                gtk_source_print_compositor_get_highlight_syntax (print->compositor));
+  g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (mousepad_print_button_toggled), print);
+  gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+
+  frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  gtk_widget_show (frame);
+
+  label = gtk_label_new (_("Fonts"));
+  gtk_label_set_attributes (GTK_LABEL (label), mousepad_print_attr_list_bold ());
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+  gtk_widget_show (label);
+
+  alignment = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 12, 6);
+  gtk_container_add (GTK_CONTAINER (frame), alignment);
+  gtk_widget_show (alignment);
+
+  table = gtk_table_new (3, 2, FALSE);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_container_add (GTK_CONTAINER (alignment), table);
+  gtk_widget_show (table);
+
+  label = gtk_label_new (_("Header:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
+  gtk_widget_show (label);
+
+  print->widget_header_font = gtk_font_button_new_with_font (gtk_source_print_compositor_get_header_font_name (print->compositor));
+  gtk_table_attach_defaults (GTK_TABLE (table), print->widget_header_font, 1, 2, 0, 1);
+  g_signal_connect (G_OBJECT (print->widget_header_font), "font-set", G_CALLBACK (mousepad_print_button_font_set), print);
+  gtk_widget_show (print->widget_header_font);
+
+  label = gtk_label_new (_("Body:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
+  gtk_widget_show (label);
+
+  print->widget_body_font = gtk_font_button_new_with_font (gtk_source_print_compositor_get_body_font_name (print->compositor));
+  gtk_table_attach_defaults (GTK_TABLE (table), print->widget_body_font, 1, 2, 1, 2);
+  g_signal_connect (G_OBJECT (print->widget_body_font), "font-set", G_CALLBACK (mousepad_print_button_font_set), print);
+  gtk_widget_show (print->widget_body_font);
+
+  label = gtk_label_new (_("Line numbers:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2, 3);
+  gtk_widget_show (label);
+
+  print->widget_line_numbers_font = gtk_font_button_new_with_font (gtk_source_print_compositor_get_line_numbers_font_name (print->compositor));
+  gtk_table_attach_defaults (GTK_TABLE (table), print->widget_line_numbers_font, 1, 2, 2, 3);
+  g_signal_connect (G_OBJECT (print->widget_line_numbers_font), "font-set", G_CALLBACK (mousepad_print_button_font_set), print);
+  gtk_widget_show (print->widget_line_numbers_font);
+
+  return vbox;
+}
+
+
+
+static void
+mousepad_print_status_changed (GtkPrintOperation *operation)
+{
+  /* nothing usefull for now, we could set a statusbar text or something */
+}
+
+
+
+static void
+mousepad_print_done (GtkPrintOperation       *operation,
+                     GtkPrintOperationResult  result)
+{
+  /* check if the print succeeded */
+  if (result == GTK_PRINT_OPERATION_RESULT_APPLY)
+    {
+      /* save the settings */
+      mousepad_print_settings_save (operation);
+    }
+}
+
+
+
+MousepadPrint *
+mousepad_print_new (void)
+{
+  return g_object_new (MOUSEPAD_TYPE_PRINT, NULL);
+}
+
+
+
+gboolean
+mousepad_print_document_interactive (MousepadPrint     *print,
+                                     MousepadDocument  *document,
+                                     GtkWindow         *parent,
+                                     GError           **error)
+{
+  GtkPrintOperationResult result;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_PRINT (print), FALSE);
+  mousepad_return_val_if_fail (GTK_IS_PRINT_OPERATION (print), FALSE);
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (document), FALSE);
+  mousepad_return_val_if_fail (GTK_IS_SOURCE_BUFFER (document->buffer), FALSE);
+  mousepad_return_val_if_fail (GTK_IS_WINDOW (parent), FALSE);
+  mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* set the document */
+  print->document = document;
+  print->compositor = gtk_source_print_compositor_new (GTK_SOURCE_BUFFER (document->buffer));
+
+  /* load settings */
+  mousepad_print_settings_load (GTK_PRINT_OPERATION (print));
+
+  /* allow async printing is support by the platform */
+  gtk_print_operation_set_allow_async (GTK_PRINT_OPERATION (print), TRUE);
+
+  /* run the operation */
+  result = gtk_print_operation_run (GTK_PRINT_OPERATION (print),
+                                    GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+                                    parent, error);
+
+  return (result != GTK_PRINT_OPERATION_RESULT_ERROR);
+}
diff --git a/mousepad/mousepad-print.h b/mousepad/mousepad-print.h
new file mode 100644
index 0000000..3806d7b
--- /dev/null
+++ b/mousepad/mousepad-print.h
@@ -0,0 +1,43 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_PRINT_H__
+#define __MOUSEPAD_PRINT_H__
+
+G_BEGIN_DECLS
+
+typedef struct _MousepadPrintClass MousepadPrintClass;
+typedef struct _MousepadPrint      MousepadPrint;
+
+#define MOUSEPAD_TYPE_PRINT            (mousepad_print_get_type ())
+#define MOUSEPAD_PRINT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_PRINT, MousepadPrint))
+#define MOUSEPAD_PRINT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_PRINT, MousepadPrintClass))
+#define MOUSEPAD_IS_PRINT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_PRINT))
+#define MOUSEPAD_IS_PRINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOUSEPAD_TYPE_PRINT))
+#define MOUSEPAD_PRINT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_PRINT, MousepadPrintClass))
+
+GType          mousepad_print_get_type             (void) G_GNUC_CONST;
+
+MousepadPrint *mousepad_print_new                  (void);
+
+gboolean       mousepad_print_document_interactive (MousepadPrint     *print,
+                                                    MousepadDocument  *document,
+                                                    GtkWindow         *parent,
+                                                    GError           **error);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_PRINT_H__ */
diff --git a/mousepad/mousepad-private.h b/mousepad/mousepad-private.h
new file mode 100644
index 0000000..49ec851
--- /dev/null
+++ b/mousepad/mousepad-private.h
@@ -0,0 +1,126 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_PRIVATE_H__
+#define __MOUSEPAD_PRIVATE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gtksourceview/gtksourceview.h>
+#include <gtksourceview/gtksourcestylescheme.h>
+#include <gtksourceview/gtksourcestyleschememanager.h>
+#include <gtksourceview/gtksourcelanguage.h>
+#include <gtksourceview/gtksourcelanguagemanager.h>
+#include <gtksourceview/gtksourceprintcompositor.h>
+
+G_BEGIN_DECLS
+
+/* errors inside mousepad */
+enum
+{
+  ERROR_READING_FAILED     = -1,
+  ERROR_CONVERTING_FAILED  = -2,
+  ERROR_NOT_UTF8_VALID     = -3,
+  ERROR_FILE_STATUS_FAILED = -4
+};
+
+/* config file locations */
+#define MOUSEPAD_RC_RELPATH     ("Mousepad" G_DIR_SEPARATOR_S "mousepadrc")
+#define MOUSEPAD_ACCELS_RELPATH ("Mousepad" G_DIR_SEPARATOR_S "accels.scm")
+
+/* handling flags */
+#define MOUSEPAD_SET_FLAG(flags,flag)   G_STMT_START{ ((flags) |= (flag)); }G_STMT_END
+#define MOUSEPAD_UNSET_FLAG(flags,flag) G_STMT_START{ ((flags) &= ~(flag)); }G_STMT_END
+#define MOUSEPAD_HAS_FLAG(flags,flag)   (((flags) & (flag)) != 0)
+
+/* for personal testing */
+#define TIMER_START    GTimer *__FUNCTION__timer = g_timer_new();
+#define TIMER_SPLIT    g_print ("%s: %.2f ms\n", G_STRLOC, g_timer_elapsed (__FUNCTION__timer, NULL) * 1000);
+#define TIMER_STOP     TIMER_SPLIT g_timer_destroy (__FUNCTION__timer);
+#define PRINT_LOCATION g_print ("%s\n", G_STRLOC);
+
+/* optimize the properties */
+#define MOUSEPAD_PARAM_READWRITE (G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
+
+/* support for canonical strings and quarks */
+#define I_(string)  (g_intern_static_string (string))
+
+/* convienient function for setting object data */
+#define mousepad_object_set_data(object,key,data)              (g_object_set_qdata ((object), \
+                                                                g_quark_from_static_string (key), (data)))
+#define mousepad_object_set_data_full(object,key,data,destroy) (g_object_set_qdata_full ((object), \
+                                                                g_quark_from_static_string (key), (data), (GDestroyNotify) (destroy)))
+#define mousepad_object_get_data(object,key)                   (g_object_get_qdata ((object), g_quark_try_string (key)))
+
+/* support macros for debugging */
+#ifndef NDEBUG
+#define mousepad_assert(expr)                  g_assert (expr)
+#define mousepad_assert_not_reached()          g_assert_not_reached ()
+#define mousepad_return_if_fail(expr)          g_return_if_fail (expr)
+#define mousepad_return_val_if_fail(expr, val) g_return_val_if_fail (expr, (val))
+#else
+#define mousepad_assert(expr)                  G_STMT_START{ (void)0; }G_STMT_END
+#define mousepad_assert_not_reached()          G_STMT_START{ (void)0; }G_STMT_END
+#define mousepad_return_if_fail(expr)          G_STMT_START{ (void)0; }G_STMT_END
+#define mousepad_return_val_if_fail(expr, val) G_STMT_START{ (void)0; }G_STMT_END
+#endif
+
+/* avoid trivial g_value_get_*() function calls */
+#ifdef NDEBUG
+#define g_value_get_boolean(v)  (((const GValue *) (v))->data[0].v_int)
+#define g_value_get_char(v)     (((const GValue *) (v))->data[0].v_int)
+#define g_value_get_uchar(v)    (((const GValue *) (v))->data[0].v_uint)
+#define g_value_get_int(v)      (((const GValue *) (v))->data[0].v_int)
+#define g_value_get_uint(v)     (((const GValue *) (v))->data[0].v_uint)
+#define g_value_get_long(v)     (((const GValue *) (v))->data[0].v_long)
+#define g_value_get_ulong(v)    (((const GValue *) (v))->data[0].v_ulong)
+#define g_value_get_int64(v)    (((const GValue *) (v))->data[0].v_int64)
+#define g_value_get_uint64(v)   (((const GValue *) (v))->data[0].v_uint64)
+#define g_value_get_enum(v)     (((const GValue *) (v))->data[0].v_long)
+#define g_value_get_flags(v)    (((const GValue *) (v))->data[0].v_ulong)
+#define g_value_get_float(v)    (((const GValue *) (v))->data[0].v_float)
+#define g_value_get_double(v)   (((const GValue *) (v))->data[0].v_double)
+#define g_value_get_string(v)   (((const GValue *) (v))->data[0].v_pointer)
+#define g_value_get_param(v)    (((const GValue *) (v))->data[0].v_pointer)
+#define g_value_get_boxed(v)    (((const GValue *) (v))->data[0].v_pointer)
+#define g_value_get_pointer(v)  (((const GValue *) (v))->data[0].v_pointer)
+#define g_value_get_object(v)   (((const GValue *) (v))->data[0].v_pointer)
+#endif
+
+/* properly set guess branch probability for pure booleans */
+#undef G_LIKELY
+#undef G_UNLIKELY
+
+#if defined(NDEBUG) && defined(__GNUC__) && (__GNUC__ > 2)
+#define G_LIKELY(expr) (__builtin_expect (!!(expr), TRUE))
+#define G_UNLIKELY(expr) (__builtin_expect (!!(expr), FALSE))
+#else
+#define G_LIKELY(expr) (expr)
+#define G_UNLIKELY(expr) (expr)
+#endif
+
+/* tooltip api */
+#if GTK_CHECK_VERSION (2,12,0)
+#define mousepad_widget_set_tooltip_text(widget,text) (gtk_widget_set_tooltip_text (widget, text))
+#else
+#define mousepad_widget_set_tooltip_text(widget,text) (mousepad_util_set_tooltip (widget, text))
+#endif
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_PRIVATE_H__ */
diff --git a/mousepad/mousepad-replace-dialog.c b/mousepad/mousepad-replace-dialog.c
new file mode 100644
index 0000000..a3a171e
--- /dev/null
+++ b/mousepad/mousepad-replace-dialog.c
@@ -0,0 +1,653 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-document.h>
+#include <mousepad/mousepad-replace-dialog.h>
+#include <mousepad/mousepad-dialogs.h>
+#include <mousepad/mousepad-preferences.h>
+#include <mousepad/mousepad-util.h>
+#include <mousepad/mousepad-marshal.h>
+
+
+
+static void                 mousepad_replace_dialog_unrealize               (GtkWidget                  *widget);
+static void                 mousepad_replace_dialog_finalize                (GObject                    *object);
+static void                 mousepad_replace_dialog_response                (GtkWidget                  *widget,
+                                                                             gint                        response_id);
+static void                 mousepad_replace_dialog_changed                 (MousepadReplaceDialog      *dialog);
+static void                 mousepad_replace_dialog_case_sensitive_toggled  (GtkToggleButton            *button,
+                                                                             MousepadReplaceDialog      *dialog);
+static void                 mousepad_replace_dialog_whole_word_toggled      (GtkToggleButton            *button,
+                                                                             MousepadReplaceDialog      *dialog);
+static void                 mousepad_replace_dialog_replace_all_toggled     (GtkToggleButton            *button,
+                                                                             MousepadReplaceDialog      *dialog);
+static void                 mousepad_replace_dialog_search_location_changed (GtkComboBox                *combo,
+                                                                             MousepadReplaceDialog      *dialog);
+static void                 mousepad_replace_dialog_direction_changed       (GtkComboBox                *combo,
+                                                                             MousepadReplaceDialog      *dialog);
+static void                 mousepad_replace_dialog_history_combo_box       (GtkComboBox                *combo_box);
+static void                 mousepad_replace_dialog_history_insert_text     (const gchar                *text);
+
+
+
+struct _MousepadReplaceDialogClass
+{
+  GtkDialogClass __parent__;
+};
+
+struct _MousepadReplaceDialog
+{
+  GtkDialog __parent__;
+
+  /* mousepad preferences */
+  MousepadPreferences *preferences;
+
+  /* dialog widgets */
+  GtkWidget           *search_entry;
+  GtkWidget           *replace_entry;
+  GtkWidget           *find_button;
+  GtkWidget           *replace_button;
+  GtkWidget           *search_location_combo;
+  GtkWidget           *hits_label;
+
+  /* search flags */
+  guint                search_direction;
+  guint                match_case : 1;
+  guint                match_whole_word : 1;
+  guint                replace_all : 1;
+  guint                replace_all_location;
+};
+
+enum
+{
+  IN_SELECTION = 0,
+  IN_DOCUMENT,
+  IN_ALL_DOCUMENTS
+};
+
+enum
+{
+  DIRECTION_UP = 0,
+  DIRECTION_DOWN,
+  DIRECTION_BOTH
+};
+
+enum
+{
+  SEARCH,
+  LAST_SIGNAL
+};
+
+
+
+static GSList *history_list = NULL;
+static guint   dialog_signals[LAST_SIGNAL];
+
+
+
+G_DEFINE_TYPE (MousepadReplaceDialog, mousepad_replace_dialog, GTK_TYPE_DIALOG);
+
+
+static void
+mousepad_replace_dialog_class_init (MousepadReplaceDialogClass *klass)
+{
+  GObjectClass   *gobject_class;
+  GtkWidgetClass *gtkwidget_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_replace_dialog_finalize;
+
+  gtkwidget_class = GTK_WIDGET_CLASS (klass);
+  gtkwidget_class->unrealize = mousepad_replace_dialog_unrealize;
+
+  dialog_signals[SEARCH] =
+    g_signal_new (I_("search"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  _mousepad_marshal_INT__FLAGS_STRING_STRING,
+                  G_TYPE_INT, 3,
+                  MOUSEPAD_TYPE_SEARCH_FLAGS,
+                  G_TYPE_STRING, G_TYPE_STRING);
+}
+
+
+
+static void
+mousepad_replace_dialog_init (MousepadReplaceDialog *dialog)
+{
+  GtkWidget    *vbox, *hbox, *combo, *label, *check;
+  GtkSizeGroup *size_group;
+  gboolean      match_whole_word, match_case;
+  gint          search_direction, replace_all_location;
+
+  /* initialize some variables */
+  dialog->replace_all = FALSE;
+
+  /* get the mousepad preferences */
+  dialog->preferences = mousepad_preferences_get ();
+
+  /* read the preferences */
+  g_object_get (G_OBJECT (dialog->preferences),
+                "search-match-whole-word", &match_whole_word,
+                "search-match-case", &match_case,
+                "search-direction", &search_direction,
+                "search-replace-all-location", &replace_all_location,
+                NULL);
+
+  /* set some flags */
+  dialog->match_whole_word = match_whole_word;
+  dialog->match_case = match_case;
+  dialog->search_direction = search_direction;
+  dialog->replace_all_location = replace_all_location;
+
+  /* set dialog properties */
+  gtk_window_set_title (GTK_WINDOW (dialog), _("Replace"));
+  gtk_window_set_default_size (GTK_WINDOW (dialog), 400, -1);
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+  g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (mousepad_replace_dialog_response), NULL);
+
+  /* dialog buttons */
+  dialog->find_button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_FIND, MOUSEPAD_RESPONSE_FIND);
+  dialog->replace_button = mousepad_util_image_button (GTK_STOCK_FIND_AND_REPLACE, _("_Replace"));
+  gtk_dialog_add_action_widget (GTK_DIALOG (dialog), dialog->replace_button, MOUSEPAD_RESPONSE_REPLACE);
+  gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, MOUSEPAD_RESPONSE_CLOSE);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_FIND);
+
+  /* create main vertical box */
+  vbox = g_object_new (GTK_TYPE_VBOX, "border-width", 6, "spacing", 4, NULL);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
+  gtk_widget_show (vbox);
+
+  /* horizontal box for search string */
+  hbox = gtk_hbox_new (FALSE, 8);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+  gtk_widget_show (hbox);
+
+  /* create a size group */
+  size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+  label = gtk_label_new_with_mnemonic (_("_Search for:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  gtk_size_group_add_widget (size_group, label);
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_widget_show (label);
+
+  combo = gtk_combo_box_entry_new_text ();
+  mousepad_replace_dialog_history_combo_box (GTK_COMBO_BOX (combo));
+  gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL(label), combo);
+  gtk_widget_show (combo);
+
+  /* store as an entry widget */
+  dialog->search_entry = gtk_bin_get_child (GTK_BIN (combo));
+  g_signal_connect_swapped (G_OBJECT (dialog->search_entry), "changed", G_CALLBACK (mousepad_replace_dialog_changed), dialog);
+
+  /* horizontal box for replace string */
+  hbox = gtk_hbox_new (FALSE, 8);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+  gtk_widget_show (hbox);
+
+  label = gtk_label_new_with_mnemonic (_("Replace _with:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  gtk_size_group_add_widget (size_group, label);
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_widget_show (label);
+
+  combo = gtk_combo_box_entry_new_text ();
+  mousepad_replace_dialog_history_combo_box (GTK_COMBO_BOX (combo));
+  gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
+  gtk_widget_show (combo);
+
+  /* store as an entry widget */
+  dialog->replace_entry = gtk_bin_get_child (GTK_BIN (combo));
+
+  /* search direction */
+  hbox = gtk_hbox_new (FALSE, 8);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL(label), combo);
+  gtk_widget_show (hbox);
+
+  label = gtk_label_new_with_mnemonic (_("Search _direction:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  gtk_size_group_add_widget (size_group, label);
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_widget_show (label);
+
+  combo = gtk_combo_box_new_text ();
+  gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL(label), combo);
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Up"));
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Down"));
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Both"));
+  gtk_combo_box_set_active (GTK_COMBO_BOX (combo), search_direction);
+  g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (mousepad_replace_dialog_direction_changed), dialog);
+  gtk_widget_show (combo);
+
+  /* release size group */
+  g_object_unref (G_OBJECT (size_group));
+
+  /* case sensitive */
+  check = gtk_check_button_new_with_mnemonic (_("Case sensi_tive"));
+  gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), match_case);
+  g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (mousepad_replace_dialog_case_sensitive_toggled), dialog);
+  gtk_widget_show (check);
+
+  /* match whole word */
+  check = gtk_check_button_new_with_mnemonic (_("_Match whole word"));
+  gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), match_whole_word);
+  g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (mousepad_replace_dialog_whole_word_toggled), dialog);
+  gtk_widget_show (check);
+
+  /* horizontal box for the replace all options */
+  hbox = gtk_hbox_new (FALSE, 8);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  check = gtk_check_button_new_with_mnemonic (_("Replace _all in:"));
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
+  g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (mousepad_replace_dialog_replace_all_toggled), dialog);
+  gtk_widget_show (check);
+
+  combo = dialog->search_location_combo = gtk_combo_box_new_text ();
+  gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Selection"));
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Document"));
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("All Documents"));
+  gtk_combo_box_set_active (GTK_COMBO_BOX (combo), replace_all_location);
+  gtk_widget_set_sensitive (combo, FALSE);
+  g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (mousepad_replace_dialog_search_location_changed), dialog);
+  gtk_widget_show (combo);
+
+  label = dialog->hits_label = gtk_label_new (NULL);
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  gtk_widget_show (label);
+}
+
+
+
+static void
+mousepad_replace_dialog_unrealize (GtkWidget *widget)
+{
+  MousepadReplaceDialog *dialog = MOUSEPAD_REPLACE_DIALOG (widget);
+  const gchar           *text;
+
+  mousepad_return_if_fail (GTK_IS_ENTRY (dialog->replace_entry));
+  mousepad_return_if_fail (GTK_IS_ENTRY (dialog->search_entry));
+
+  text = gtk_entry_get_text (GTK_ENTRY (dialog->search_entry));
+  mousepad_replace_dialog_history_insert_text (text);
+
+  text = gtk_entry_get_text (GTK_ENTRY (dialog->replace_entry));
+  mousepad_replace_dialog_history_insert_text (text);
+
+  (*GTK_WIDGET_CLASS (mousepad_replace_dialog_parent_class)->unrealize) (widget);
+}
+
+
+
+static void
+mousepad_replace_dialog_finalize (GObject *object)
+{
+  MousepadReplaceDialog *dialog = MOUSEPAD_REPLACE_DIALOG (object);
+
+  /* release the preferences */
+  g_object_unref (G_OBJECT (dialog->preferences));
+
+  (*G_OBJECT_CLASS (mousepad_replace_dialog_parent_class)->finalize) (object);
+}
+
+
+
+static void
+mousepad_replace_dialog_response (GtkWidget *widget,
+                                  gint       response_id)
+{
+  MousepadSearchFlags    flags;
+  MousepadReplaceDialog *dialog = MOUSEPAD_REPLACE_DIALOG (widget);
+  gint                   matches;
+  const gchar           *search_str, *replace_str;
+  gchar                 *message;
+
+  /* close dialog */
+  if (response_id == MOUSEPAD_RESPONSE_CLOSE)
+    goto destroy_dialog;
+
+  /* search direction */
+  if (dialog->search_direction == DIRECTION_UP
+      && dialog->replace_all == FALSE)
+    flags = MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD;
+  else
+    flags = MOUSEPAD_SEARCH_FLAGS_DIR_FORWARD;
+
+  /* case sensitive searching */
+  if (dialog->match_case)
+    flags |= MOUSEPAD_SEARCH_FLAGS_MATCH_CASE;
+
+  /* only match whole words */
+  if (dialog->match_whole_word)
+    flags |= MOUSEPAD_SEARCH_FLAGS_WHOLE_WORD;
+
+  /* wrap around */
+  if (dialog->search_direction == DIRECTION_BOTH
+      && dialog->replace_all == FALSE)
+    flags |= MOUSEPAD_SEARCH_FLAGS_WRAP_AROUND;
+
+  /* search area */
+  if (dialog->replace_all
+      && dialog->replace_all_location == IN_SELECTION)
+    flags |= MOUSEPAD_SEARCH_FLAGS_AREA_SELECTION;
+  else
+    flags |= MOUSEPAD_SEARCH_FLAGS_AREA_DOCUMENT;
+
+  /* start position */
+  if (response_id == MOUSEPAD_RESPONSE_CHECK_ENTRY)
+    {
+      /* no visible actions */
+      flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_NONE;
+
+      if (dialog->replace_all)
+        goto replace_flags;
+      else
+        goto search_flags;
+    }
+  else if (response_id == MOUSEPAD_RESPONSE_FIND)
+    {
+      /* select the first match */
+      flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT;
+
+      search_flags:
+
+      /* start at the 'end' of the selection */
+      if (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD)
+        flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START;
+      else
+        flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_END;
+    }
+  else if (response_id == MOUSEPAD_RESPONSE_REPLACE)
+    {
+      /* replace matches */
+      flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_REPLACE;
+
+      if (dialog->replace_all)
+        {
+          replace_flags:
+
+          /* replace all from the beginning of the document */
+          flags |= MOUSEPAD_SEARCH_FLAGS_ITER_AREA_START
+                   | MOUSEPAD_SEARCH_FLAGS_ENTIRE_AREA;
+
+          /* search all opened documents (flag used in mousepad-window.c) */
+          if (dialog->replace_all_location == IN_ALL_DOCUMENTS)
+            flags |= MOUSEPAD_SEARCH_FLAGS_ALL_DOCUMENTS;
+        }
+      else
+        {
+          /* start at the 'beginning' of the selection */
+          if (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD)
+            flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_END;
+          else
+            flags |= MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START;
+        }
+    }
+  else
+    {
+      destroy_dialog:
+
+      /* destroy the window */
+      gtk_widget_destroy (widget);
+
+      /* leave */
+      return;
+    }
+
+  /* get strings */
+  search_str = gtk_entry_get_text (GTK_ENTRY (dialog->search_entry));
+  replace_str = gtk_entry_get_text (GTK_ENTRY (dialog->replace_entry));
+
+  /* emit the signal */
+  g_signal_emit (G_OBJECT (dialog), dialog_signals[SEARCH], 0, flags, search_str, replace_str, &matches);
+
+  /* reset counter */
+  if (response_id == MOUSEPAD_RESPONSE_REPLACE && dialog->replace_all)
+    matches = 0;
+
+  /* update entry color */
+  mousepad_util_entry_error (dialog->search_entry, matches == 0);
+
+  /* update counter */
+  if (dialog->replace_all)
+    {
+      message = g_strdup_printf (ngettext ("%d occurence", "%d occurences", matches), matches);
+      gtk_label_set_markup (GTK_LABEL (dialog->hits_label), message);
+      g_free (message);
+    }
+}
+
+
+static void
+mousepad_replace_dialog_changed (MousepadReplaceDialog *dialog)
+{
+  const gchar *text;
+  gboolean     sensitive;
+
+  /* get the search entry text */
+  text = gtk_entry_get_text (GTK_ENTRY (dialog->search_entry));
+
+  if (text != NULL && *text != '\0')
+    {
+      /* do an invisible search to give the user some visible feedback */
+      gtk_dialog_response (GTK_DIALOG (dialog), MOUSEPAD_RESPONSE_CHECK_ENTRY);
+
+      /* buttons are sensitive */
+      sensitive = TRUE;
+    }
+  else
+    {
+      /* not text, means no error */
+      mousepad_util_entry_error (dialog->search_entry, FALSE);
+
+      /* reset occurences label */
+      gtk_label_set_text (GTK_LABEL (dialog->hits_label), NULL);
+
+      /* buttons are not sensitive */
+      sensitive = FALSE;
+    }
+
+  /* set the sensitivity */
+  gtk_widget_set_sensitive (dialog->find_button, sensitive);
+  gtk_widget_set_sensitive (dialog->replace_button, sensitive);
+}
+
+
+
+static void
+mousepad_replace_dialog_case_sensitive_toggled (GtkToggleButton       *button,
+                                                MousepadReplaceDialog *dialog)
+{
+  /* get the toggle button state */
+  dialog->match_case = gtk_toggle_button_get_active (button);
+
+  /* save the setting */
+  g_object_set (G_OBJECT (dialog->preferences), "search-match-case", dialog->match_case, NULL);
+
+  /* update dialog */
+  mousepad_replace_dialog_changed (dialog);
+}
+
+
+
+static void
+mousepad_replace_dialog_whole_word_toggled (GtkToggleButton       *button,
+                                            MousepadReplaceDialog *dialog)
+{
+  /* get the toggle button state */
+  dialog->match_whole_word = gtk_toggle_button_get_active (button);
+
+  /* save the setting */
+  g_object_set (G_OBJECT (dialog->preferences), "search-match-whole-word", dialog->match_whole_word, NULL);
+
+  /* update dialog */
+  mousepad_replace_dialog_changed (dialog);
+}
+
+
+
+static void
+mousepad_replace_dialog_replace_all_toggled (GtkToggleButton       *button,
+                                             MousepadReplaceDialog *dialog)
+{
+  gboolean active;
+
+  /* get the toggle button state */
+  active = gtk_toggle_button_get_active (button);
+
+  /* save flags */
+  dialog->replace_all = active;
+
+  /* set the sensitivity of some dialog widgets */
+  gtk_widget_set_sensitive (dialog->search_location_combo, active);
+
+  /* reset occurences label */
+  gtk_label_set_text (GTK_LABEL (dialog->hits_label), NULL);
+
+  /* set new label of the replace button */
+  gtk_button_set_label (GTK_BUTTON (dialog->replace_button),
+                        active ? _("_Replace All") : _("_Replace"));
+
+  /* update dialog */
+  mousepad_replace_dialog_changed (dialog);
+}
+
+
+
+static void
+mousepad_replace_dialog_search_location_changed (GtkComboBox           *combo,
+                                                 MousepadReplaceDialog *dialog)
+{
+  /* get the selected action */
+  dialog->replace_all_location = gtk_combo_box_get_active (combo);
+
+  /* save setting */
+  g_object_set (G_OBJECT (dialog->preferences), "search-replace-all-location", dialog->replace_all_location, NULL);
+
+  /* update dialog */
+  mousepad_replace_dialog_changed (dialog);
+}
+
+
+
+static void
+mousepad_replace_dialog_direction_changed (GtkComboBox           *combo,
+                                           MousepadReplaceDialog *dialog)
+{
+  /* get the selected item */
+  dialog->search_direction = gtk_combo_box_get_active (combo);
+
+  /* save the last direction */
+  g_object_set (G_OBJECT (dialog->preferences), "search-direction", dialog->search_direction, NULL);
+
+  /* update dialog */
+  mousepad_replace_dialog_changed (dialog);
+}
+
+
+
+/**
+ * History functions
+ **/
+static void
+mousepad_replace_dialog_history_combo_box (GtkComboBox *combo_box)
+{
+  GSList *li;
+
+  mousepad_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
+
+  /* append the items from the history to the combobox */
+  for (li = history_list; li != NULL; li = li->next)
+    gtk_combo_box_append_text (combo_box, li->data);
+}
+
+
+
+static void
+mousepad_replace_dialog_history_insert_text (const gchar *text)
+{
+  GSList *li;
+
+  /* quit if the box is empty */
+  if (text == NULL || *text == '\0')
+    return;
+
+  /* check if the string is already in the history */
+  for (li = history_list; li != NULL; li = li->next)
+    if (strcmp (li->data, text) == 0)
+      return;
+
+  /* prepend the string */
+  history_list = g_slist_prepend (history_list, g_strdup (text));
+}
+
+
+
+GtkWidget *
+mousepad_replace_dialog_new (void)
+{
+  return g_object_new (MOUSEPAD_TYPE_REPLACE_DIALOG, NULL);
+}
+
+
+
+void
+mousepad_replace_dialog_history_clean (void)
+{
+  GSList *li;
+
+  if (history_list)
+    {
+      /* remove all the entries */
+      for (li = history_list; li != NULL; li = li->next)
+        {
+          /* cleanup the string */
+          g_free (li->data);
+
+          /* remove the item from the list */
+          history_list = g_slist_delete_link (history_list, li);
+        }
+
+      /* cleanup the list */
+      g_slist_free (history_list);
+    }
+}
+
+
+
+void
+mousepad_replace_dialog_page_switched (MousepadReplaceDialog *dialog)
+{
+  mousepad_replace_dialog_changed (dialog);
+}
diff --git a/mousepad/mousepad-replace-dialog.h b/mousepad/mousepad-replace-dialog.h
new file mode 100644
index 0000000..b3e7d2f
--- /dev/null
+++ b/mousepad/mousepad-replace-dialog.h
@@ -0,0 +1,42 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_REPLACE_DIALOG_H__
+#define __MOUSEPAD_REPLACE_DIALOG_H__
+
+G_BEGIN_DECLS
+
+#define MOUSEPAD_TYPE_REPLACE_DIALOG            (mousepad_replace_dialog_get_type ())
+#define MOUSEPAD_REPLACE_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_REPLACE_DIALOG, MousepadReplaceDialog))
+#define MOUSEPAD_REPLACE_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_REPLACE_DIALOG, MousepadReplaceDialogClass))
+#define MOUSEPAD_IS_REPLACE_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_REPLACE_DIALOG))
+#define MOUSEPAD_IS_REPLACE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPADL_TYPE_REPLACE_DIALOG))
+#define MOUSEPAD_REPLACE_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_REPLACE_DIALOG, MousepadReplaceDialogClass))
+
+typedef struct _MousepadReplaceDialogClass MousepadReplaceDialogClass;
+typedef struct _MousepadReplaceDialog      MousepadReplaceDialog;
+
+GType           mousepad_replace_dialog_get_type       (void) G_GNUC_CONST;
+
+GtkWidget      *mousepad_replace_dialog_new            (void);
+
+void            mousepad_replace_dialog_history_clean  (void);
+
+void            mousepad_replace_dialog_page_switched  (MousepadReplaceDialog *dialog);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_REPLACE_DIALOG_H__ */
diff --git a/mousepad/mousepad-search-bar.c b/mousepad/mousepad-search-bar.c
new file mode 100644
index 0000000..4158d02
--- /dev/null
+++ b/mousepad/mousepad-search-bar.c
@@ -0,0 +1,536 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-marshal.h>
+#include <mousepad/mousepad-document.h>
+#include <mousepad/mousepad-search-bar.h>
+#include <mousepad/mousepad-preferences.h>
+#include <mousepad/mousepad-util.h>
+#include <mousepad/mousepad-window.h>
+
+
+
+#define TOOL_BAR_ICON_SIZE  GTK_ICON_SIZE_MENU
+#define HIGHTLIGHT_TIMEOUT  225
+
+
+
+static void      mousepad_search_bar_finalize                   (GObject                 *object);
+static void      mousepad_search_bar_find_string                (MousepadSearchBar       *bar,
+                                                                 MousepadSearchFlags   flags);
+static void      mousepad_search_bar_hide_clicked               (MousepadSearchBar       *bar);
+static void      mousepad_search_bar_entry_changed              (GtkWidget               *entry,
+                                                                 MousepadSearchBar       *bar);
+static void      mousepad_search_bar_highlight_toggled          (GtkWidget               *button,
+                                                                 MousepadSearchBar       *bar);
+static void      mousepad_search_bar_match_case_toggled         (GtkWidget               *button,
+                                                                 MousepadSearchBar       *bar);
+static void      mousepad_search_bar_menuitem_toggled           (GtkCheckMenuItem        *item,
+                                                                 GtkToggleButton         *button);
+static void      mousepad_search_bar_highlight_schedule         (MousepadSearchBar       *bar);
+static gboolean  mousepad_search_bar_highlight_timeout          (gpointer                 user_data);
+static void      mousepad_search_bar_highlight_timeout_destroy  (gpointer                 user_data);
+
+
+
+enum
+{
+  HIDE_BAR,
+  SEARCH,
+  LAST_SIGNAL
+};
+
+struct _MousepadSearchBarClass
+{
+  GtkToolbarClass __parent__;
+};
+
+struct _MousepadSearchBar
+{
+  GtkToolbar           __parent__;
+
+  /* preferences */
+  MousepadPreferences *preferences;
+
+  /* text entry */
+  GtkWidget           *entry;
+
+  /* menu entries */
+  GtkWidget           *match_case_entry;
+
+  /* flags */
+  guint                highlight_all : 1;
+  guint                match_case : 1;
+
+  /* highlight id */
+  guint                highlight_id;
+};
+
+
+
+static guint search_bar_signals[LAST_SIGNAL];
+
+
+
+GtkWidget *
+mousepad_search_bar_new (void)
+{
+  return g_object_new (MOUSEPAD_TYPE_SEARCH_BAR,
+                       "toolbar-style", GTK_TOOLBAR_BOTH_HORIZ,
+                       "icon-size", TOOL_BAR_ICON_SIZE,
+                       NULL);
+}
+
+
+
+G_DEFINE_TYPE (MousepadSearchBar, mousepad_search_bar, GTK_TYPE_TOOLBAR);
+
+
+
+static void
+mousepad_search_bar_class_init (MousepadSearchBarClass *klass)
+{
+  GObjectClass  *gobject_class;
+  GtkBindingSet *binding_set;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_search_bar_finalize;
+
+  /* signals */
+  search_bar_signals[HIDE_BAR] =
+    g_signal_new (I_("hide-bar"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  search_bar_signals[SEARCH] =
+    g_signal_new (I_("search"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  _mousepad_marshal_INT__FLAGS_STRING_STRING,
+                  G_TYPE_INT, 3,
+                  MOUSEPAD_TYPE_SEARCH_FLAGS,
+                  G_TYPE_STRING, G_TYPE_STRING);
+
+  /* setup key bindings for the search bar */
+  binding_set = gtk_binding_set_by_class (klass);
+  gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "hide-bar", 0);
+
+  /* hide the shadow around the toolbar */
+  gtk_rc_parse_string ("style \"mousepad-search-bar-style\"\n"
+                         "{\n"
+                           "GtkToolbar::shadow-type = GTK_SHADOW_NONE\n"
+                         "}\n"
+                       "class \"MousepadSearchBar\" style \"mousepad-search-bar-style\"\n"
+
+                       /* add 2px space between the toolbar buttons */
+                       "style \"mousepad-button-style\"\n"
+                         "{\n"
+                           "GtkToolButton::icon-spacing = 2\n"
+                         "}\n"
+                       "widget \"MousepadWindow.*.Gtk*ToolButton\" style \"mousepad-button-style\"\n");
+}
+
+
+
+static void
+mousepad_search_bar_init (MousepadSearchBar *bar)
+{
+  GtkWidget   *label, *image, *check, *menuitem;
+  GtkToolItem *item;
+  gboolean     match_case;
+
+  /* preferences */
+  bar->preferences = mousepad_preferences_get ();
+
+  /* load some preferences */
+  g_object_get (G_OBJECT (bar->preferences), "search-match-case", &match_case, NULL);
+
+  /* init variables */
+  bar->highlight_id = 0;
+  bar->match_case = match_case;
+
+  /* the close button */
+  item = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE);
+  gtk_toolbar_insert (GTK_TOOLBAR (bar), item, -1);
+  g_signal_connect_swapped (G_OBJECT (item), "clicked", G_CALLBACK (mousepad_search_bar_hide_clicked), bar);
+  gtk_widget_show (GTK_WIDGET (item));
+
+  /* the find label */
+  item = gtk_tool_item_new ();
+  gtk_toolbar_insert (GTK_TOOLBAR (bar), item, -1);
+  gtk_widget_show (GTK_WIDGET (item));
+
+  label = gtk_label_new_with_mnemonic (_("Fi_nd:"));
+  gtk_container_add (GTK_CONTAINER (item), label);
+  gtk_misc_set_padding (GTK_MISC (label), 2, 0);
+  gtk_widget_show (label);
+
+  /* the entry field */
+  item = gtk_tool_item_new ();
+  gtk_toolbar_insert (GTK_TOOLBAR (bar), item, -1);
+  gtk_widget_show (GTK_WIDGET (item));
+
+  bar->entry = gtk_entry_new ();
+  gtk_container_add (GTK_CONTAINER (item), bar->entry);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), bar->entry);
+  g_signal_connect (G_OBJECT (bar->entry), "changed", G_CALLBACK (mousepad_search_bar_entry_changed), bar);
+  gtk_widget_show (bar->entry);
+
+  /* next button */
+  image = gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, TOOL_BAR_ICON_SIZE);
+  gtk_widget_show (image);
+
+  item = gtk_tool_button_new (image, _("_Next"));
+  gtk_tool_item_set_is_important (item, TRUE);
+  gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (item), TRUE);
+  gtk_toolbar_insert (GTK_TOOLBAR (bar), item, -1);
+  g_signal_connect_swapped (G_OBJECT (item), "clicked", G_CALLBACK (mousepad_search_bar_find_next), bar);
+  gtk_widget_show (GTK_WIDGET (item));
+
+  /* previous button */
+  image = gtk_image_new_from_stock (GTK_STOCK_GO_UP, TOOL_BAR_ICON_SIZE);
+  gtk_widget_show (image);
+
+  item = gtk_tool_button_new (image, _("_Previous"));
+  gtk_tool_item_set_is_important (item, TRUE);
+  gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (item), TRUE);
+  gtk_toolbar_insert (GTK_TOOLBAR (bar), item, -1);
+  g_signal_connect_swapped (G_OBJECT (item), "clicked", G_CALLBACK (mousepad_search_bar_find_previous), bar);
+  gtk_widget_show (GTK_WIDGET (item));
+
+  /* highlight all */
+  item = (GtkToolItem *) gtk_toggle_tool_button_new ();
+  g_signal_connect_object (G_OBJECT (bar), "destroy", G_CALLBACK (gtk_widget_destroy), item, G_CONNECT_SWAPPED);
+  gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), GTK_STOCK_SELECT_ALL);
+  gtk_tool_button_set_label (GTK_TOOL_BUTTON (item), _("Highlight _All"));
+  gtk_tool_item_set_is_important (item, TRUE);
+  gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (item), TRUE);
+  gtk_toolbar_insert (GTK_TOOLBAR (bar), item, -1);
+  g_signal_connect (G_OBJECT (item), "clicked", G_CALLBACK (mousepad_search_bar_highlight_toggled), bar);
+  gtk_widget_show (GTK_WIDGET (item));
+
+  /* check button for case sensitive, including the proxy menu item */
+  item = gtk_tool_item_new ();
+  g_signal_connect_object (G_OBJECT (bar), "destroy", G_CALLBACK (gtk_widget_destroy), item, G_CONNECT_SWAPPED);
+  gtk_toolbar_insert (GTK_TOOLBAR (bar), item, -1);
+  gtk_widget_show (GTK_WIDGET (item));
+
+  check = gtk_check_button_new_with_mnemonic (_("Mat_ch Case"));
+  g_signal_connect_object (G_OBJECT (bar), "destroy", G_CALLBACK (gtk_widget_destroy), item, G_CONNECT_SWAPPED);
+  gtk_container_add (GTK_CONTAINER (item), check);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), match_case);
+  g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (mousepad_search_bar_match_case_toggled), bar);
+  gtk_widget_show (check);
+
+  bar->match_case_entry = menuitem = gtk_check_menu_item_new_with_mnemonic (_("Mat_ch Case"));
+  g_signal_connect_object (G_OBJECT (bar), "destroy", G_CALLBACK (gtk_widget_destroy), item, G_CONNECT_SWAPPED);
+  gtk_tool_item_set_proxy_menu_item (item, "case-sensitive", menuitem);
+  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), match_case);
+  g_signal_connect (G_OBJECT (menuitem), "toggled", G_CALLBACK (mousepad_search_bar_menuitem_toggled), check);
+  gtk_widget_show (menuitem);
+}
+
+
+
+static void
+mousepad_search_bar_finalize (GObject *object)
+{
+  MousepadSearchBar *bar = MOUSEPAD_SEARCH_BAR (object);
+
+  /* release the preferences */
+  g_object_unref (G_OBJECT (bar->preferences));
+
+  /* stop a running highlight timeout */
+  if (bar->highlight_id != 0)
+    g_source_remove (bar->highlight_id);
+
+  (*G_OBJECT_CLASS (mousepad_search_bar_parent_class)->finalize) (object);
+}
+
+
+
+static void
+mousepad_search_bar_find_string (MousepadSearchBar   *bar,
+                                 MousepadSearchFlags  flags)
+{
+  const gchar *string;
+  gint         nmatches;
+
+  /* search the entire document */
+  flags |= MOUSEPAD_SEARCH_FLAGS_AREA_DOCUMENT;
+
+  /* if we don't hightlight, we select with wrapping */
+  if ((flags & MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT) == 0)
+    flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT
+             | MOUSEPAD_SEARCH_FLAGS_WRAP_AROUND;
+
+  /* append the insensitive flags when needed */
+  if (bar->match_case)
+    flags |= MOUSEPAD_SEARCH_FLAGS_MATCH_CASE;
+
+  /* get the entry string */
+  string = gtk_entry_get_text (GTK_ENTRY (bar->entry));
+
+  /* emit signal */
+  g_signal_emit (G_OBJECT (bar), search_bar_signals[SEARCH], 0, flags, string, NULL, &nmatches);
+
+  /* do nothing with the error entry when highlight when trigged with highlight */
+  if ((flags & MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT) == 0)
+    {
+      /* make sure the search entry is not red when no text was typed */
+      if (string == NULL || *string == '\0')
+        nmatches = 1;
+
+      /* change the entry style */
+      mousepad_util_entry_error (bar->entry, nmatches < 1);
+    }
+}
+
+
+
+static void
+mousepad_search_bar_hide_clicked (MousepadSearchBar *bar)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
+
+  /* emit the signal */
+  g_signal_emit (G_OBJECT (bar), search_bar_signals[HIDE_BAR], 0);
+}
+
+
+
+static void
+mousepad_search_bar_entry_changed (GtkWidget         *entry,
+                                   MousepadSearchBar *bar)
+{
+  MousepadSearchFlags flags;
+
+  /* set the search flags */
+  flags = MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START
+          | MOUSEPAD_SEARCH_FLAGS_DIR_FORWARD;
+
+  /* find */
+  mousepad_search_bar_find_string (bar, flags);
+
+  /* schedule a new highlight */
+  mousepad_search_bar_highlight_schedule (bar);
+}
+
+
+
+static void
+mousepad_search_bar_highlight_toggled (GtkWidget         *button,
+                                       MousepadSearchBar *bar)
+{
+  MousepadSearchFlags flags;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
+
+  /* set the new state */
+  bar->highlight_all = gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button));
+
+  if (bar->highlight_all)
+    {
+      /* reschedule the highlight */
+      mousepad_search_bar_highlight_schedule (bar);
+    }
+  else
+    {
+      /* stop timeout */
+      if (bar->highlight_id != 0)
+        g_source_remove (bar->highlight_id);
+
+      /* set search flags */
+      flags = MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT
+              | MOUSEPAD_SEARCH_FLAGS_ACTION_CLEANUP;
+
+      /* emit signal to cleanup the highlight */
+      mousepad_search_bar_find_string (bar, flags);
+    }
+}
+
+
+
+static void
+mousepad_search_bar_match_case_toggled (GtkWidget         *button,
+                                        MousepadSearchBar *bar)
+{
+  gboolean active;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
+
+  /* get the state of the toggle button */
+  active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+  /* set the state of the menu item */
+  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (bar->match_case_entry), active);
+
+  /* save the state */
+  bar->match_case = active;
+
+  /* save the setting */
+  g_object_set (G_OBJECT (bar->preferences), "search-match-case", active, NULL);
+
+  /* search ahead with this new flags */
+  mousepad_search_bar_entry_changed (NULL, bar);
+
+  /* schedule a new hightlight */
+  mousepad_search_bar_highlight_schedule (bar);
+}
+
+
+
+static void
+mousepad_search_bar_menuitem_toggled (GtkCheckMenuItem *item,
+                                      GtkToggleButton  *button)
+{
+  gboolean active;
+
+  mousepad_return_if_fail (GTK_IS_CHECK_MENU_ITEM (item));
+  mousepad_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
+
+  /* toggle the menubar item, he/she will send the signal */
+  active = gtk_check_menu_item_get_active (item);
+  gtk_toggle_button_set_active (button, active);
+}
+
+
+
+static void
+mousepad_search_bar_highlight_schedule (MousepadSearchBar *bar)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
+
+  /* stop a pending timeout */
+  if (bar->highlight_id != 0)
+    g_source_remove (bar->highlight_id);
+
+  /* schedule a new timeout */
+  if (bar->highlight_all)
+    {
+      bar->highlight_id = g_timeout_add_full (G_PRIORITY_LOW, HIGHTLIGHT_TIMEOUT, mousepad_search_bar_highlight_timeout,
+                                              bar, mousepad_search_bar_highlight_timeout_destroy);
+    }
+}
+
+
+
+static void
+mousepad_search_bar_highlight_timeout_destroy (gpointer user_data)
+{
+  MOUSEPAD_SEARCH_BAR (user_data)->highlight_id = 0;
+}
+
+
+
+static gboolean
+mousepad_search_bar_highlight_timeout (gpointer user_data)
+{
+  MousepadSearchBar   *bar = MOUSEPAD_SEARCH_BAR (user_data);
+  MousepadSearchFlags  flags;
+
+  GDK_THREADS_ENTER ();
+
+  /* set search flags */
+  flags = MOUSEPAD_SEARCH_FLAGS_DIR_FORWARD
+          | MOUSEPAD_SEARCH_FLAGS_ITER_AREA_START
+          | MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT;
+
+  /* emit signal */
+  mousepad_search_bar_find_string (bar, flags);
+
+  GDK_THREADS_LEAVE ();
+
+  /* stop the timeout */
+  return FALSE;
+}
+
+
+
+GtkEditable *
+mousepad_search_bar_entry (MousepadSearchBar *bar)
+{
+  if (bar && GTK_WIDGET_HAS_FOCUS (bar->entry))
+    return GTK_EDITABLE (bar->entry);
+  else
+    return NULL;
+}
+
+
+
+void
+mousepad_search_bar_focus (MousepadSearchBar *bar)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
+
+  /* focus the entry field */
+  gtk_widget_grab_focus (bar->entry);
+
+  /* trigger search function */
+  mousepad_search_bar_entry_changed (NULL, bar);
+
+  /* update the highlight */
+  mousepad_search_bar_highlight_schedule (bar);
+
+  /* select the entire entry */
+  gtk_editable_select_region (GTK_EDITABLE (bar->entry), 0, -1);
+}
+
+
+
+void
+mousepad_search_bar_find_next (MousepadSearchBar *bar)
+{
+  MousepadSearchFlags flags;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
+
+  /* set search flags */
+  flags = MOUSEPAD_SEARCH_FLAGS_ITER_SEL_END
+          | MOUSEPAD_SEARCH_FLAGS_DIR_FORWARD;
+
+  /* search */
+  mousepad_search_bar_find_string (bar, flags);
+}
+
+
+
+void
+mousepad_search_bar_find_previous (MousepadSearchBar *bar)
+{
+  MousepadSearchFlags flags;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (bar));
+
+  /* set search flags */
+  flags = MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START
+          | MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD;
+
+  /* search */
+  mousepad_search_bar_find_string (bar, flags);
+}
diff --git a/mousepad/mousepad-search-bar.h b/mousepad/mousepad-search-bar.h
new file mode 100644
index 0000000..4dbfe11
--- /dev/null
+++ b/mousepad/mousepad-search-bar.h
@@ -0,0 +1,46 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_SEARCH_BAR_H__
+#define __MOUSEPAD_SEARCH_BAR_H__
+
+G_BEGIN_DECLS
+
+#define MOUSEPAD_TYPE_SEARCH_BAR            (mousepad_search_bar_get_type ())
+#define MOUSEPAD_SEARCH_BAR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_SEARCH_BAR, MousepadSearchBar))
+#define MOUSEPAD_SEARCH_BAR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_SEARCH_BAR, MousepadSearchBarClass))
+#define MOUSEPAD_IS_SEARCH_BAR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_SEARCH_BAR))
+#define MOUSEPAD_IS_SEARCH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPADL_TYPE_SEARCH_BAR))
+#define MOUSEPAD_SEARCH_BAR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_SEARCH_BAR, MousepadSearchBarClass))
+
+typedef struct _MousepadSearchBarClass MousepadSearchBarClass;
+typedef struct _MousepadSearchBar      MousepadSearchBar;
+
+GType           mousepad_search_bar_get_type        (void) G_GNUC_CONST;
+
+GtkWidget      *mousepad_search_bar_new             (void);
+
+GtkEditable    *mousepad_search_bar_entry           (MousepadSearchBar *bar);
+
+void            mousepad_search_bar_focus           (MousepadSearchBar *bar);
+
+void            mousepad_search_bar_find_next       (MousepadSearchBar *bar);
+
+void            mousepad_search_bar_find_previous   (MousepadSearchBar *bar);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_SEARCH_BAR_H__ */
diff --git a/mousepad/mousepad-statusbar.c b/mousepad/mousepad-statusbar.c
new file mode 100644
index 0000000..e69a494
--- /dev/null
+++ b/mousepad/mousepad-statusbar.c
@@ -0,0 +1,300 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-statusbar.h>
+#include <mousepad/mousepad-window.h>
+#include <mousepad/mousepad-util.h>
+
+
+
+static gboolean mousepad_statusbar_overwrite_clicked (GtkWidget         *widget,
+                                                      GdkEventButton    *event,
+                                                      MousepadStatusbar *statusbar);
+
+static gboolean mousepad_statusbar_filetype_clicked  (GtkWidget         *widget,
+                                                      GdkEventButton    *event,
+                                                      MousepadStatusbar *statusbar);
+
+
+
+enum
+{
+  ENABLE_OVERWRITE,
+  POPULATE_FILETYPE_POPUP,
+  LAST_SIGNAL,
+};
+
+struct _MousepadStatusbarClass
+{
+  GtkStatusbarClass __parent__;
+};
+
+struct _MousepadStatusbar
+{
+  GtkStatusbar        __parent__;
+
+  /* whether overwrite is enabled */
+  guint               overwrite_enabled : 1;
+
+  /* extra labels in the statusbar */
+  GtkWidget          *language;
+  GtkWidget          *position;
+  GtkWidget          *overwrite;
+};
+
+
+
+static guint statusbar_signals[LAST_SIGNAL];
+
+
+
+G_DEFINE_TYPE (MousepadStatusbar, mousepad_statusbar, GTK_TYPE_STATUSBAR);
+
+
+
+GtkWidget *
+mousepad_statusbar_new (void)
+{
+  return g_object_new (MOUSEPAD_TYPE_STATUSBAR, NULL);
+}
+
+
+
+static void
+mousepad_statusbar_class_init (MousepadStatusbarClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+
+  statusbar_signals[ENABLE_OVERWRITE] =
+    g_signal_new (I_("enable-overwrite"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__BOOLEAN,
+                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+  statusbar_signals[POPULATE_FILETYPE_POPUP] =
+    g_signal_new (I_("populate-filetype-popup"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, GTK_TYPE_MENU);
+}
+
+
+
+static void
+mousepad_statusbar_init (MousepadStatusbar *statusbar)
+{
+  GtkWidget    *ebox, *box, *separator, *label;
+  GtkStatusbar *bar = GTK_STATUSBAR (statusbar);
+  GList *frame;
+
+  /* init statusbar */
+  gtk_statusbar_set_has_resize_grip (bar, TRUE);
+
+  /* create a new horizontal box */
+  box = gtk_hbox_new (FALSE, 8);
+  gtk_widget_show (box);
+
+  /* reorder the gtk statusbar */
+  frame = gtk_container_get_children (GTK_CONTAINER (bar));
+  gtk_frame_set_shadow_type (GTK_FRAME (frame->data), GTK_SHADOW_NONE);
+  label = gtk_bin_get_child (GTK_BIN (frame->data));
+  g_object_ref (label);
+  gtk_container_remove (GTK_CONTAINER (frame->data), label);
+  gtk_container_add (GTK_CONTAINER (frame->data), box);
+  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+  g_object_unref (label);
+  g_list_free (frame);
+
+  /* separator */
+  separator = gtk_vseparator_new ();
+  gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, 0);
+  gtk_widget_show (separator);
+
+  /* language/filetype event box */
+  ebox = gtk_event_box_new ();
+  gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, TRUE, 0);
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (ebox), FALSE);
+  mousepad_widget_set_tooltip_text (ebox, _("Choose a filetype"));
+  g_signal_connect (G_OBJECT (ebox), "button-press-event", G_CALLBACK (mousepad_statusbar_filetype_clicked), statusbar);
+  gtk_widget_show (ebox);
+
+  /* language/filetype */
+  statusbar->language = gtk_label_new (_("Filetype: None"));
+  gtk_container_add (GTK_CONTAINER (ebox), statusbar->language);
+  gtk_widget_show (statusbar->language);
+
+  /* separator */
+  separator = gtk_vseparator_new ();
+  gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, 0);
+  gtk_widget_show (separator);
+
+  /* line and column numbers */
+  statusbar->position = gtk_label_new (NULL);
+  gtk_box_pack_start (GTK_BOX (box), statusbar->position, FALSE, TRUE, 0);
+  gtk_widget_show (statusbar->position);
+
+  /* separator */
+  separator = gtk_vseparator_new ();
+  gtk_box_pack_start (GTK_BOX (box), separator, FALSE, FALSE, 0);
+  gtk_widget_show (separator);
+
+  /* overwrite event box */
+  ebox = gtk_event_box_new ();
+  gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, TRUE, 0);
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (ebox), FALSE);
+  mousepad_widget_set_tooltip_text (ebox, _("Toggle the overwrite mode"));
+  g_signal_connect (G_OBJECT (ebox), "button-press-event", G_CALLBACK (mousepad_statusbar_overwrite_clicked), statusbar);
+  gtk_widget_show (ebox);
+
+  /* overwrite label */
+  statusbar->overwrite = gtk_label_new (_("OVR"));
+  gtk_container_add (GTK_CONTAINER (ebox), statusbar->overwrite);
+  gtk_widget_show (statusbar->overwrite);
+}
+
+
+
+static gboolean
+mousepad_statusbar_overwrite_clicked (GtkWidget         *widget,
+                                      GdkEventButton    *event,
+                                      MousepadStatusbar *statusbar)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_STATUSBAR (statusbar), FALSE);
+
+  /* only respond on the left button click */
+  if (event->type != GDK_BUTTON_PRESS || event->button != 1)
+    return FALSE;
+
+  /* swap the overwrite mode */
+  statusbar->overwrite_enabled = !statusbar->overwrite_enabled;
+
+  /* send the signal */
+  g_signal_emit (G_OBJECT (statusbar), statusbar_signals[ENABLE_OVERWRITE], 0, statusbar->overwrite_enabled);
+
+  return TRUE;
+}
+
+
+
+static gboolean
+mousepad_statusbar_filetype_clicked (GtkWidget         *widget,
+                                     GdkEventButton    *event,
+                                     MousepadStatusbar *statusbar)
+{
+  GtkMenu *menu;
+  GList   *children;
+  gint     n_children = 0;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_STATUSBAR (statusbar), FALSE);
+
+  /* only respond on the left button click */
+  if (event->type != GDK_BUTTON_PRESS || event->button != 1)
+    return FALSE;
+
+  /* create the popup menu */
+  menu = GTK_MENU (gtk_menu_new ());
+
+  /* send the signal to fill the menu */
+  g_signal_emit (G_OBJECT (statusbar), statusbar_signals[POPULATE_FILETYPE_POPUP], 0, menu);
+
+  /* get the number of items in the menu */
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  n_children = g_list_length (children);
+  g_list_free (children);
+
+  /* make sure there's at least one item in the menu */
+  if (n_children)
+    {
+      /* cleanup the menu once a selection is made or the menu is cancelled */
+      g_signal_connect (menu, "selection-done", G_CALLBACK (gtk_widget_destroy), NULL);
+
+      /* show the menu */
+      gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time);
+    }
+  else
+    {
+      /* since the menu wasn't shown, just destroy it straight-away */
+      gtk_widget_destroy (GTK_WIDGET (menu));
+    }
+
+  return TRUE;
+}
+
+
+
+void
+mousepad_statusbar_set_language (MousepadStatusbar *statusbar,
+                                 GtkSourceLanguage *language)
+{
+  gchar *label;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_STATUSBAR (statusbar));
+
+  if (language == NULL)
+      gtk_label_set_text (GTK_LABEL (statusbar->language), _("Filetype: None"));
+  else
+    {
+      label = g_strdup_printf (_("Filetype: %s"), gtk_source_language_get_name (language));
+      gtk_label_set_text (GTK_LABEL (statusbar->language), label);
+      g_free (label);
+    }
+}
+
+
+
+void
+mousepad_statusbar_set_cursor_position (MousepadStatusbar *statusbar,
+                                        gint               line,
+                                        gint               column,
+                                        gint               selection)
+{
+  gchar string[64];
+
+  mousepad_return_if_fail (MOUSEPAD_IS_STATUSBAR (statusbar));
+
+  /* create printable string */
+  if (G_UNLIKELY (selection > 0))
+    g_snprintf (string, sizeof (string), _("Line: %d Column: %d Selection: %d"), line, column, selection);
+  else
+    g_snprintf (string, sizeof (string), _("Line: %d Column: %d"), line, column);
+
+  /* set label */
+  gtk_label_set_text (GTK_LABEL (statusbar->position), string);
+}
+
+
+
+void
+mousepad_statusbar_set_overwrite (MousepadStatusbar *statusbar,
+                                  gboolean           overwrite)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_STATUSBAR (statusbar));
+
+  gtk_widget_set_sensitive (statusbar->overwrite, overwrite);
+
+  statusbar->overwrite_enabled = overwrite;
+}
diff --git a/mousepad/mousepad-statusbar.h b/mousepad/mousepad-statusbar.h
new file mode 100644
index 0000000..8ebe7a6
--- /dev/null
+++ b/mousepad/mousepad-statusbar.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_STATUSBAR_H__
+#define __MOUSEPAD_STATUSBAR_H__
+
+G_BEGIN_DECLS
+
+#define MOUSEPAD_TYPE_STATUSBAR            (mousepad_statusbar_get_type ())
+#define MOUSEPAD_STATUSBAR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_STATUSBAR, MousepadStatusbar))
+#define MOUSEPAD_STATUSBAR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_STATUSBAR, MousepadStatusbarClass))
+#define MOUSEPAD_IS_STATUSBAR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_STATUSBAR))
+#define MOUSEPAD_IS_STATUSBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_STATUSBAR))
+#define MOUSEPAD_STATUSBAR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_STATUSBAR, MousepadStatusbarClass))
+
+typedef struct _MousepadStatusbarClass MousepadStatusbarClass;
+typedef struct _MousepadStatusbar      MousepadStatusbar;
+
+GType       mousepad_statusbar_get_type             (void) G_GNUC_CONST;
+
+GtkWidget  *mousepad_statusbar_new                  (void);
+
+void        mousepad_statusbar_set_cursor_position  (MousepadStatusbar *statusbar,
+                                                     gint               line,
+                                                     gint               column,
+                                                     gint               selection);
+
+void        mousepad_statusbar_set_overwrite        (MousepadStatusbar *statusbar,
+                                                     gboolean           overwrite);
+
+void        mousepad_statusbar_set_language         (MousepadStatusbar *statusbar,
+                                                     GtkSourceLanguage *language);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_STATUSBAR_H__ */
diff --git a/mousepad/mousepad-util.c b/mousepad/mousepad-util.c
new file mode 100644
index 0000000..05ed8af
--- /dev/null
+++ b/mousepad/mousepad-util.c
@@ -0,0 +1,1206 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-util.h>
+
+
+
+static gboolean
+mousepad_util_iter_word_characters (const GtkTextIter *iter)
+{
+  gunichar c;
+
+  /* get the characters */
+  c = gtk_text_iter_get_char (iter);
+
+  /* character we'd like to see in a word */
+  if (g_unichar_isalnum (c) || c == '_')
+    return TRUE;
+
+  return FALSE;
+}
+
+
+
+gboolean
+mousepad_util_iter_starts_word (const GtkTextIter *iter)
+{
+  GtkTextIter prev;
+
+  /* normal gtk word start */
+  if (!gtk_text_iter_starts_word (iter))
+    return FALSE;
+
+  /* init iter for previous char */
+  prev = *iter;
+
+  /* return true when we could not step backwards (start of buffer) */
+  if (!gtk_text_iter_backward_char (&prev))
+    return TRUE;
+
+  /* check if the previous char also belongs to the word */
+  if (mousepad_util_iter_word_characters (&prev))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+
+gboolean
+mousepad_util_iter_ends_word (const GtkTextIter *iter)
+{
+  if (!gtk_text_iter_ends_word (iter))
+    return FALSE;
+
+  /* check if it's a character we'd like to see in a word */
+  if (mousepad_util_iter_word_characters (iter))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+
+gboolean
+mousepad_util_iter_inside_word (const GtkTextIter *iter)
+{
+  GtkTextIter prev;
+
+  /* not inside a word when at beginning or end of a word */
+  if (mousepad_util_iter_starts_word (iter) || mousepad_util_iter_ends_word (iter))
+    return FALSE;
+
+  /* normal gtk function */
+  if (gtk_text_iter_inside_word (iter))
+    return TRUE;
+
+  /* check if the character is a word char */
+  if (!mousepad_util_iter_word_characters (iter))
+    return FALSE;
+
+  /* initialize previous iter */
+  prev = *iter;
+
+  /* get one character backwards */
+  if (!gtk_text_iter_backward_char (&prev))
+    return FALSE;
+
+  return mousepad_util_iter_word_characters (&prev);
+}
+
+
+
+gboolean
+mousepad_util_iter_forward_word_end (GtkTextIter *iter)
+{
+  if (mousepad_util_iter_ends_word (iter))
+    return TRUE;
+
+  while (gtk_text_iter_forward_char (iter))
+    if (mousepad_util_iter_ends_word (iter))
+      return TRUE;
+
+  return mousepad_util_iter_ends_word (iter);
+}
+
+
+
+gboolean
+mousepad_util_iter_backward_word_start (GtkTextIter *iter)
+{
+  /* return true if the iter already starts a word */
+  if (mousepad_util_iter_starts_word (iter))
+    return TRUE;
+
+  /* move backwards until we find a word start */
+  while (gtk_text_iter_backward_char (iter))
+    if (mousepad_util_iter_starts_word (iter))
+      return TRUE;
+
+  /* while stops when we hit the first char in the buffer */
+  return mousepad_util_iter_starts_word (iter);
+}
+
+
+
+gboolean
+mousepad_util_iter_forward_text_start (GtkTextIter *iter)
+{
+  mousepad_return_val_if_fail (!mousepad_util_iter_inside_word (iter), FALSE);
+
+  /* keep until we hit text or a line end */
+  while (g_unichar_isspace (gtk_text_iter_get_char (iter)))
+    if (gtk_text_iter_ends_line (iter) || !gtk_text_iter_forward_char (iter))
+      break;
+
+  return TRUE;
+}
+
+
+
+gboolean
+mousepad_util_iter_backward_text_start (GtkTextIter *iter)
+{
+  GtkTextIter prev = *iter;
+
+  mousepad_return_val_if_fail (!mousepad_util_iter_inside_word (iter), FALSE);
+
+  while (!gtk_text_iter_starts_line (&prev) && gtk_text_iter_backward_char (&prev))
+    {
+      if (g_unichar_isspace (gtk_text_iter_get_char (&prev)))
+        *iter = prev;
+      else
+        break;
+    }
+
+  return TRUE;
+}
+
+
+
+gchar *
+mousepad_util_config_name (const gchar *name)
+{
+  const gchar *s;
+  gchar       *config, *t;
+  gboolean     upper = TRUE;
+
+  /* allocate string */
+  config = g_new (gchar, strlen (name) + 1);
+
+  /* convert name */
+  for (s = name, t = config; *s != '\0'; ++s)
+    {
+      if (*s == '-')
+        {
+          upper = TRUE;
+        }
+      else if (upper)
+        {
+          *t++ = g_ascii_toupper (*s);
+          upper = FALSE;
+        }
+      else
+        {
+          *t++ = g_ascii_tolower (*s);
+        }
+    }
+
+  /* zerro terminate string */
+  *t = '\0';
+
+  return config;
+}
+
+
+
+gchar *
+mousepad_util_key_name (const gchar *name)
+{
+  const gchar *s;
+  gchar       *key, *t;
+
+  /* allocate string (max of 9 extra - chars) */
+  key = g_new (gchar, strlen (name) + 10);
+
+  /* convert name */
+  for (s = name, t = key; *s != '\0'; ++s)
+    {
+      if (g_ascii_isupper (*s) && s != name)
+        *t++ = '-';
+
+      *t++ = g_ascii_tolower (*s);
+    }
+
+  /* zerro terminate string */
+  *t = '\0';
+
+  return key;
+}
+
+
+
+gchar *
+mousepad_util_utf8_strcapital (const gchar *str)
+{
+  gunichar     c;
+  const gchar *p;
+  gchar       *buf;
+  GString     *result;
+  gboolean     upper = TRUE;
+
+  mousepad_return_val_if_fail (g_utf8_validate (str, -1, NULL), NULL);
+
+  /* create a new string */
+  result = g_string_sized_new (strlen (str));
+
+  /* walk though the string */
+  for (p = str; *p != '\0'; p = g_utf8_next_char (p))
+    {
+      /* get the unicode char */
+      c = g_utf8_get_char (p);
+
+      /* only change the case of alpha chars */
+      if (g_unichar_isalpha (c))
+        {
+          /* check case */
+          if (upper ? g_unichar_isupper (c) : g_unichar_islower (c))
+            {
+              /* currect case is already correct */
+              g_string_append_unichar (result, c);
+            }
+          else
+            {
+              /* convert the case of the char and append it */
+              buf = upper ? g_utf8_strup (p, 1) : g_utf8_strdown (p, 1);
+              g_string_append (result, buf);
+              g_free (buf);
+            }
+
+          /* next char must be lowercase */
+          upper = FALSE;
+        }
+      else
+        {
+          /* append the char */
+          g_string_append_unichar (result, c);
+
+          /* next alpha char uppercase after a space */
+          upper = g_unichar_isspace (c);
+        }
+    }
+
+  /* return the result */
+  return g_string_free (result, FALSE);
+}
+
+
+
+gchar *
+mousepad_util_utf8_stropposite (const gchar *str)
+{
+  gunichar     c;
+  const gchar *p;
+  gchar       *buf;
+  GString     *result;
+
+  mousepad_return_val_if_fail (g_utf8_validate (str, -1, NULL), NULL);
+
+  /* create a new string */
+  result = g_string_sized_new (strlen (str));
+
+  /* walk though the string */
+  for (p = str; *p != '\0'; p = g_utf8_next_char (p))
+    {
+      /* get the unicode char */
+      c = g_utf8_get_char (p);
+
+      /* only change the case of alpha chars */
+      if (g_unichar_isalpha (c))
+        {
+          /* get the opposite case of the char */
+          if (g_unichar_isupper (c))
+            buf = g_utf8_strdown (p, 1);
+          else
+            buf = g_utf8_strup (p, 1);
+
+          /* append to the buffer */
+          g_string_append (result, buf);
+          g_free (buf);
+        }
+      else
+        {
+          /* append the char */
+          g_string_append_unichar (result, c);
+        }
+    }
+
+  /* return the result */
+  return g_string_free (result, FALSE);
+}
+
+
+
+gchar *
+mousepad_util_escape_underscores (const gchar *str)
+{
+  GString     *result;
+  const gchar *s;
+
+  /* allocate a new string */
+  result = g_string_sized_new (strlen (str));
+
+  /* escape all underscores */
+  for (s = str; *s != '\0'; ++s)
+    {
+      if (G_UNLIKELY (*s == '_'))
+        g_string_append (result, "__");
+      else
+        g_string_append_c (result, *s);
+    }
+
+  return g_string_free (result, FALSE);
+}
+
+
+
+GtkWidget *
+mousepad_util_image_button (const gchar *stock_id,
+                            const gchar *label)
+{
+  GtkWidget *button, *image;
+
+  image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+  gtk_widget_show (image);
+
+  button = gtk_button_new_with_mnemonic (label);
+  gtk_button_set_image (GTK_BUTTON (button), image);
+  gtk_widget_show (button);
+
+  return button;
+}
+
+
+
+void
+mousepad_util_entry_error (GtkWidget *widget,
+                           gboolean   error)
+{
+  const GdkColor red   = {0, 0xffff, 0x6666, 0x6666};
+  const GdkColor white = {0, 0xffff, 0xffff, 0xffff};
+  gpointer       pointer;
+
+  mousepad_return_if_fail (GTK_IS_WIDGET (widget));
+
+  /* get the current error state */
+  pointer = mousepad_object_get_data (G_OBJECT (widget), "error-state");
+
+  /* only change the state when really needed to avoid multiple widget calls */
+  if (GPOINTER_TO_INT (pointer) != error)
+    {
+      /* set the widget style */
+      gtk_widget_modify_base (widget, GTK_STATE_NORMAL, error ? &red : NULL);
+      gtk_widget_modify_text (widget, GTK_STATE_NORMAL, error ? &white : NULL);
+
+      /* set the new state */
+      mousepad_object_set_data (G_OBJECT (widget), "error-state", GINT_TO_POINTER (error));
+    }
+}
+
+
+
+void
+mousepad_util_dialog_header (GtkDialog   *dialog,
+                             const gchar *title,
+                             const gchar *subtitle,
+                             const gchar *iconname)
+{
+  gchar     *full_title;
+  GtkWidget *vbox, *ebox, *hbox;
+  GtkWidget *icon, *label, *line;
+
+  /* remove the main vbox */
+  g_object_ref (G_OBJECT (dialog->vbox));
+  gtk_container_remove (GTK_CONTAINER (dialog), dialog->vbox);
+
+  /* add a new vbox to the main window */
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (dialog), vbox);
+  gtk_widget_show (vbox);
+
+  /* event box for the background color */
+  ebox = gtk_event_box_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), ebox, FALSE, FALSE, 0);
+  gtk_widget_modify_bg (ebox, GTK_STATE_NORMAL, &ebox->style->base[GTK_STATE_NORMAL]);
+  gtk_widget_show (ebox);
+
+  /* create a hbox */
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
+  gtk_container_add (GTK_CONTAINER (ebox), hbox);
+  gtk_widget_show (hbox);
+
+  /* title icon */
+  icon = gtk_image_new_from_icon_name (iconname, GTK_ICON_SIZE_DIALOG);
+  gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
+  gtk_widget_show (icon);
+
+  /* create the title */
+  full_title = g_strdup_printf ("<b><big>%s</big></b>\n%s", title, subtitle);
+
+  /* title label */
+  label = gtk_label_new (full_title);
+  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+  gtk_widget_show (label);
+
+  /* cleanup */
+  g_free (full_title);
+
+  /* add the separator between header and content */
+  line = gtk_hseparator_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), line, FALSE, FALSE, 0);
+  gtk_widget_show (line);
+
+  /* add the main dialog box to the new vbox */
+  gtk_box_pack_start (GTK_BOX (vbox), GTK_DIALOG (dialog)->vbox, TRUE, TRUE, 0);
+  g_object_unref (G_OBJECT (GTK_DIALOG (dialog)->vbox));
+}
+
+
+#if !GTK_CHECK_VERSION (2,12,0)
+void
+mousepad_util_set_tooltip (GtkWidget   *widget,
+                           const gchar *string)
+{
+  static GtkTooltips *tooltips = NULL;
+
+  mousepad_return_if_fail (GTK_IS_WIDGET (widget));
+  mousepad_return_if_fail (string ? g_utf8_validate (string, -1, NULL) : TRUE);
+
+  /* allocate the shared tooltips on-demand */
+  if (G_UNLIKELY (tooltips == NULL))
+    tooltips = gtk_tooltips_new ();
+
+  /* setup the tooltip for the widget */
+  gtk_tooltips_set_tip (tooltips, widget, string, NULL);
+}
+#endif
+
+
+gint
+mousepad_util_get_real_line_offset (const GtkTextIter *iter,
+                                    gint               tab_size)
+{
+  gint        offset = 0;
+  GtkTextIter needle = *iter;
+
+  /* move the needle to the start of the line */
+  gtk_text_iter_set_line_offset (&needle, 0);
+
+  /* forward the needle until we hit the iter */
+  while (!gtk_text_iter_equal (&needle, iter))
+    {
+      /* append the real tab offset or 1 */
+      if (gtk_text_iter_get_char (&needle) == '\t')
+        offset += (tab_size - (offset % tab_size));
+      else
+        offset++;
+
+      /* next char */
+      gtk_text_iter_forward_char (&needle);
+    }
+
+  return offset;
+}
+
+
+
+gboolean
+mousepad_util_forward_iter_to_text (GtkTextIter       *iter,
+                                    const GtkTextIter *limit)
+{
+  gunichar c;
+
+  do
+    {
+      /* get the iter character */
+      c = gtk_text_iter_get_char (iter);
+
+      /* break if the character is not a space */
+      if (!g_unichar_isspace (c) || c == '\n' || c == '\r')
+        break;
+
+      /* break when we reached the limit iter */
+      if (limit && gtk_text_iter_equal (iter, limit))
+        return FALSE;
+    }
+  while (gtk_text_iter_forward_char (iter));
+
+  return TRUE;
+}
+
+
+
+gchar *
+mousepad_util_get_save_location (const gchar *relpath,
+                                 gboolean     create_parents)
+{
+  gchar *filename, *dirname;
+
+  mousepad_return_val_if_fail (g_get_user_config_dir () != NULL, NULL);
+
+  /* create the full filename */
+  filename = g_build_filename (g_get_user_config_dir (), relpath, NULL);
+
+  /* test if the file exists */
+  if (G_UNLIKELY (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE))
+    {
+      if (create_parents)
+        {
+          /* get the directory name */
+          dirname = g_path_get_dirname (filename);
+
+          /* make the directory with parents */
+          if (g_mkdir_with_parents (dirname, 0700) == -1)
+            {
+              /* show warning to the user */
+              g_critical (_("Unable to create base directory \"%s\". "
+                            "Saving to file \"%s\" will be aborted."), dirname, filename);
+
+              /* don't return a filename, to avoid problems */
+              g_free (filename);
+              filename = NULL;
+            }
+
+          /* cleanup */
+          g_free (dirname);
+        }
+      else
+        {
+          /* cleanup */
+          g_free (filename);
+          filename = NULL;
+        }
+    }
+
+  return filename;
+}
+
+
+
+void
+mousepad_util_save_key_file (GKeyFile    *keyfile,
+                             const gchar *filename)
+{
+  gchar  *contents;
+  gsize   length;
+  GError *error = NULL;
+
+  /* get the contents of the key file */
+  contents = g_key_file_to_data (keyfile, &length, &error);
+
+  if (G_LIKELY (error == NULL))
+    {
+      /* write the contents to the file */
+      if (G_UNLIKELY (g_file_set_contents (filename, contents, length, &error) == FALSE))
+        goto print_error;
+    }
+  else
+    {
+      print_error:
+
+      /* print error */
+      g_critical (_("Failed to store the preferences to \"%s\": %s"), filename, error->message);
+
+      /* cleanup */
+      g_error_free (error);
+    }
+
+  /* cleanup */
+  g_free (contents);
+}
+
+
+
+GType
+mousepad_util_search_flags_get_type (void)
+{
+  static GType type = G_TYPE_NONE;
+
+  if (G_UNLIKELY (type == G_TYPE_NONE))
+    {
+      /* use empty values table */
+      static const GFlagsValue values[] =
+      {
+          { 0, NULL, NULL }
+      };
+
+      /* register the type */
+      type = g_flags_register_static (I_("MousepadSearchFlags"), values);
+      }
+
+  return type;
+}
+
+
+
+static gboolean
+mousepad_util_search_iter (const GtkTextIter   *start,
+                           const gchar         *string,
+                           MousepadSearchFlags  flags,
+                           GtkTextIter         *match_start,
+                           GtkTextIter         *match_end,
+                           const GtkTextIter   *limit)
+{
+  GtkTextIter  iter, begin;
+  gunichar     iter_char, str_char;
+  gboolean     succeed = FALSE;
+  const gchar *needle = string;
+  gboolean     match_case, search_backwards, whole_word;
+  guint        needle_offset = 0;
+
+  mousepad_return_val_if_fail (start != NULL, FALSE);
+  mousepad_return_val_if_fail (string != NULL, FALSE);
+  mousepad_return_val_if_fail (limit != NULL, FALSE);
+
+  /* search properties */
+  match_case       = (flags & MOUSEPAD_SEARCH_FLAGS_MATCH_CASE) != 0;
+  search_backwards = (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD) != 0;
+  whole_word       = (flags & MOUSEPAD_SEARCH_FLAGS_WHOLE_WORD) != 0;
+
+  /* set the start iter */
+  iter = *start;
+
+  /* walk from the start to the end iter */
+  for (;;)
+    {
+      /* break when we reach the limit iter */
+      if (G_UNLIKELY (gtk_text_iter_equal (&iter, limit)))
+        break;
+
+      /* get the unichar characters */
+      iter_char = gtk_text_iter_get_char (&iter);
+      str_char  = g_utf8_get_char (needle);
+
+      /* skip unknown characters */
+      if (G_UNLIKELY (iter_char == 0xFFFC))
+        goto continue_searching;
+
+      /* lower case searching */
+      if (!match_case)
+        {
+          /* convert the characters to lower case */
+          iter_char = g_unichar_tolower (iter_char);
+          str_char  = g_unichar_tolower (str_char);
+        }
+
+      /* compare the two characters */
+      if (iter_char == str_char)
+        {
+          /* first character matched, set the begin iter */
+          if (needle_offset == 0)
+            begin = iter;
+
+          /* get the next character and increase the offset counter */
+          needle = g_utf8_next_char (needle);
+          needle_offset++;
+
+          /* we hit the end of the search string, so we had a full match */
+          if (G_UNLIKELY (*needle == '\0'))
+            {
+              if (G_LIKELY (!search_backwards))
+                {
+                  /* set the end iter after the character (for selection) */
+                  gtk_text_iter_forward_char (&iter);
+
+                  /* check if we match a whole word */
+                  if (whole_word && !(mousepad_util_iter_starts_word (&begin) && mousepad_util_iter_ends_word (&iter)))
+                    goto reset_and_continue_searching;
+                }
+              else
+                {
+                  /* set the start iter after the character (for selection) */
+                  gtk_text_iter_forward_char (&begin);
+
+                  /* check if we match a whole word */
+                  if (whole_word && !(mousepad_util_iter_starts_word (&iter) && mousepad_util_iter_ends_word (&begin)))
+                    goto reset_and_continue_searching;
+                }
+
+              /* set the start and end iters */
+              *match_start = begin;
+              *match_end   = iter;
+
+              /* return true and stop searching */
+              succeed = TRUE;
+
+              break;
+            }
+        }
+      else if (needle_offset > 0)
+        {
+          /* label */
+          reset_and_continue_searching:
+
+          /* reset the needle */
+          needle = string;
+          needle_offset = 0;
+
+          /* reset the iter */
+          iter = begin;
+        }
+
+      /* label */
+      continue_searching:
+
+      /* jump to next iter in the buffer */
+      if ((!search_backwards && !gtk_text_iter_forward_char (&iter))
+          || (search_backwards && !gtk_text_iter_backward_char (&iter)))
+        break;
+    }
+
+  return succeed;
+}
+
+
+
+static void
+mousepad_util_search_get_iters (GtkTextBuffer       *buffer,
+                                MousepadSearchFlags  flags,
+                                GtkTextIter         *start,
+                                GtkTextIter         *end,
+                                GtkTextIter         *iter)
+{
+  GtkTextIter sel_start, sel_end, tmp;
+
+  /* get selection bounds */
+  gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end);
+
+  if (flags & MOUSEPAD_SEARCH_FLAGS_AREA_DOCUMENT)
+    {
+      /* get document bounds */
+      gtk_text_buffer_get_bounds (buffer, start, end);
+
+      /* set the start iter */
+      if (flags & MOUSEPAD_SEARCH_FLAGS_ITER_AREA_START)
+        *iter = *start;
+      else if (flags & MOUSEPAD_SEARCH_FLAGS_ITER_AREA_END)
+        *iter = *end;
+      else
+        goto set_selection_iter;
+    }
+  else if (flags & MOUSEPAD_SEARCH_FLAGS_AREA_SELECTION)
+    {
+      /* set area iters */
+      *start = sel_start;
+      *end = sel_end;
+
+      set_selection_iter:
+
+      /* set the start iter */
+      if (flags & (MOUSEPAD_SEARCH_FLAGS_ITER_AREA_START | MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START))
+        *iter = sel_start;
+      else if (flags & (MOUSEPAD_SEARCH_FLAGS_ITER_AREA_END | MOUSEPAD_SEARCH_FLAGS_ITER_SEL_END))
+        *iter = sel_end;
+      else
+        mousepad_assert_not_reached ();
+    }
+  else
+    {
+      /* this should never happen */
+      mousepad_assert_not_reached ();
+    }
+
+  /* invert the start and end iter on backwards searching */
+  if (flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD)
+    {
+      tmp = *start;
+      *start = *end;
+      *end = tmp;
+    }
+}
+
+
+
+gint
+mousepad_util_highlight (GtkTextBuffer       *buffer,
+                         GtkTextTag          *tag,
+                         const gchar         *string,
+                         MousepadSearchFlags  flags)
+{
+  GtkTextIter start, iter, end;
+  GtkTextIter match_start, match_end;
+  GtkTextIter cache_start, cache_end;
+  gboolean    found, cached = FALSE;
+  gint        counter = 0;
+
+  mousepad_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), -1);
+  mousepad_return_val_if_fail (GTK_IS_TEXT_TAG (tag), -1);
+  mousepad_return_val_if_fail (string == NULL || g_utf8_validate (string, -1, NULL), -1);
+  mousepad_return_val_if_fail ((flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD) == 0, -1);
+
+  /* get the buffer bounds */
+  gtk_text_buffer_get_bounds (buffer, &start, &end);
+
+  /* remove all the highlight tags */
+  gtk_text_buffer_remove_tag (buffer, tag, &start, &end);
+
+  /* quit if there is nothing to highlight */
+  if (string == NULL || *string == '\0' || flags & MOUSEPAD_SEARCH_FLAGS_ACTION_CLEANUP)
+    return 0;
+
+  /* get the search iters */
+  mousepad_util_search_get_iters (buffer, flags, &start, &end, &iter);
+
+  /* initialize cache iters */
+  cache_start = cache_end = iter;
+
+  /* highlight all the occurences of the strings */
+  do
+    {
+      /* search for the next occurence of the string */
+      found = mousepad_util_search_iter (&iter, string, flags, &match_start, &match_end, &end);
+
+      if (G_LIKELY (found))
+        {
+          /* try to extend the cache */
+          if (gtk_text_iter_equal (&cache_end, &match_start))
+            {
+              /* enable caching */
+              cached = TRUE;
+            }
+          else
+            {
+              if (cached)
+                {
+                  /* highlight the cached occurences */
+                  gtk_text_buffer_apply_tag (buffer, tag, &cache_start, &cache_end);
+
+                  /* cache is flushed */
+                  cached = FALSE;
+                }
+
+              /* highlight the matched occurence */
+              gtk_text_buffer_apply_tag (buffer, tag, &match_start, &match_end);
+
+              /* set the new cache start iter */
+              cache_start = match_start;
+            }
+
+          /* set the end iters */
+          iter = cache_end = match_end;
+
+          /* increase the counter */
+          counter++;
+        }
+      else if (G_UNLIKELY (cached))
+        {
+          /* flush the cached iters */
+          gtk_text_buffer_apply_tag (buffer, tag, &cache_start, &cache_end);
+        }
+    }
+  while (G_LIKELY (found));
+
+  return counter;
+}
+
+
+
+gint
+mousepad_util_search (GtkTextBuffer       *buffer,
+                      const gchar         *string,
+                      const gchar         *replace,
+                      MousepadSearchFlags  flags)
+{
+  gchar       *reversed = NULL;
+  gint         counter = 0;
+  gboolean     found, search_again = FALSE;
+  gboolean     search_backwards, wrap_around;
+  GtkTextIter  start, end, iter;
+  GtkTextIter  match_start, match_end;
+  GtkTextMark *mark_start, *mark_iter, *mark_end, *mark_replace;
+
+  mousepad_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), -1);
+  mousepad_return_val_if_fail (string && g_utf8_validate (string, -1, NULL), -1);
+  mousepad_return_val_if_fail (replace == NULL || g_utf8_validate (replace, -1, NULL), -1);
+  mousepad_return_val_if_fail ((flags & MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT) == 0, -1);
+
+  /* freeze buffer notifications */
+  g_object_freeze_notify (G_OBJECT (buffer));
+
+  /* get the search iters */
+  mousepad_util_search_get_iters (buffer, flags, &start, &end, &iter);
+
+  /* store the initial iters in marks */
+  mark_start = gtk_text_buffer_create_mark (buffer, NULL, &start, TRUE);
+  mark_iter  = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
+  mark_end   = gtk_text_buffer_create_mark (buffer, NULL, &end, TRUE);
+
+  /* some to make the code easier to read */
+  search_backwards = ((flags & MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD) != 0);
+  wrap_around = ((flags & MOUSEPAD_SEARCH_FLAGS_WRAP_AROUND) != 0 && !gtk_text_iter_equal (&start, &iter));
+
+  /* if we're not really searching anything, reset the cursor */
+  if (string == NULL || *string == '\0')
+    goto reset_cursor;
+
+  if (search_backwards)
+    {
+      /* reverse the search string */
+      reversed = g_utf8_strreverse (string, -1);
+
+      /* set the new search string */
+      string = reversed;
+    }
+
+  do
+    {
+      /* search the string */
+      found = mousepad_util_search_iter (&iter, string, flags, &match_start, &match_end, &end);
+
+      /* don't search again unless changed below */
+      search_again = FALSE;
+
+      if (found)
+        {
+          /* handle the action */
+          if (flags & MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT)
+            {
+              /* select the match */
+              gtk_text_buffer_select_range (buffer, &match_start, &match_end);
+            }
+          else if (flags & MOUSEPAD_SEARCH_FLAGS_ACTION_REPLACE)
+          {
+              /* create text mark */
+              mark_replace = gtk_text_buffer_create_mark (buffer, NULL, &match_start, search_backwards);
+
+              /* delete the match */
+              gtk_text_buffer_delete (buffer, &match_start, &match_end);
+
+              /* restore the iter */
+              gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark_replace);
+
+              /* insert the replacement */
+              if (G_LIKELY (replace))
+                gtk_text_buffer_insert (buffer, &iter, replace, -1);
+
+              /* remove the mark */
+              gtk_text_buffer_delete_mark (buffer, mark_replace);
+
+              /* restore the begin and end iters */
+              gtk_text_buffer_get_iter_at_mark (buffer, &start, mark_start);
+              gtk_text_buffer_get_iter_at_mark (buffer, &end, mark_end);
+
+              /* when we don't replace all matches, select the next one */
+              if ((flags & MOUSEPAD_SEARCH_FLAGS_ENTIRE_AREA) == 0)
+                flags |= MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT;
+
+              /* search again */
+              search_again = TRUE;
+          }
+        else if (flags & MOUSEPAD_SEARCH_FLAGS_ACTION_NONE)
+            {
+              /* keep searching when requested */
+              if (flags & MOUSEPAD_SEARCH_FLAGS_ENTIRE_AREA)
+                search_again = TRUE;
+
+              /* move iter */
+              iter = match_end;
+            }
+        else
+          {
+              /* no valid action was defined */
+              mousepad_assert_not_reached ();
+            }
+
+          /* increase the counter */
+          counter++;
+        }
+      else if (wrap_around)
+        {
+          /* get the start iter (note that the start and iter were already
+           * reversed for backwards searching) */
+          gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark_start);
+
+          /* get end iter */
+          gtk_text_buffer_get_iter_at_mark (buffer, &end, mark_iter);
+
+          /* we wrapped, don't try again */
+          wrap_around = FALSE;
+
+          /* search again */
+          search_again = TRUE;
+        }
+      else
+        {
+          reset_cursor:
+
+          /* get the initial start mark */
+          gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark_iter);
+
+          /* reset the cursor */
+          gtk_text_buffer_place_cursor (buffer, &iter);
+        }
+    }
+  while (search_again);
+
+  /* make sure the selection is restored */
+  if (flags & MOUSEPAD_SEARCH_FLAGS_AREA_SELECTION)
+    gtk_text_buffer_select_range (buffer, &start, &end);
+
+  /* cleanup */
+  g_free (reversed);
+
+  /* cleanup marks */
+  gtk_text_buffer_delete_mark (buffer, mark_start);
+  gtk_text_buffer_delete_mark (buffer, mark_iter);
+  gtk_text_buffer_delete_mark (buffer, mark_end);
+
+  /* thawn buffer notifications */
+  g_object_thaw_notify (G_OBJECT (buffer));
+
+  return counter;
+}
+
+
+
+/**
+ * Colour scheme functions
+ */
+gint
+mousepad_util_color_schemes_name_compare (gconstpointer a,
+                                          gconstpointer b)
+{
+  const gchar *name_a, *name_b;
+
+  if (G_UNLIKELY (!GTK_IS_SOURCE_STYLE_SCHEME (a)))
+    return -(a != b);
+  if (G_UNLIKELY (!GTK_IS_SOURCE_STYLE_SCHEME (b)))
+    return a != b;
+
+  name_a = gtk_source_style_scheme_get_name (GTK_SOURCE_STYLE_SCHEME (a));
+  name_b = gtk_source_style_scheme_get_name (GTK_SOURCE_STYLE_SCHEME (b));
+
+  return g_utf8_collate (name_a, name_b);
+}
+
+
+
+GSList *
+mousepad_util_color_schemes_get (void)
+{
+  GSList               *list = NULL;
+  const gchar * const  *schemes;
+  GtkSourceStyleScheme *scheme;
+
+  schemes = gtk_source_style_scheme_manager_get_scheme_ids (
+              gtk_source_style_scheme_manager_get_default ());
+
+  while (*schemes)
+    {
+      scheme = gtk_source_style_scheme_manager_get_scheme (
+                gtk_source_style_scheme_manager_get_default (), *schemes);
+      list = g_slist_prepend (list, scheme);
+      schemes++;
+    }
+
+  return list;
+}
+
+
+
+GSList *
+mousepad_util_color_schemes_get_sorted (void)
+{
+  return g_slist_sort (mousepad_util_color_schemes_get (),
+                       mousepad_util_color_schemes_name_compare);
+}
+
+
+
+/**
+ * Language/filetype functions
+ */
+gint
+mousepad_util_languages_name_compare (gconstpointer a,
+                                      gconstpointer b)
+{
+  const gchar *name_a, *name_b;
+
+  if (G_UNLIKELY (!GTK_IS_SOURCE_LANGUAGE (a)))
+    return -(a != b);
+  if (G_UNLIKELY (!GTK_IS_SOURCE_LANGUAGE (b)))
+    return a != b;
+
+  name_a = gtk_source_language_get_name (GTK_SOURCE_LANGUAGE (a));
+  name_b = gtk_source_language_get_name (GTK_SOURCE_LANGUAGE (b));
+
+  return g_utf8_collate (name_a, name_b);
+}
+
+
+
+GSList *
+mousepad_util_language_sections_get_sorted (void)
+{
+  GSList                   *list = NULL;
+  const gchar *const       *languages;
+  GtkSourceLanguage        *language;
+  GtkSourceLanguageManager *manager;
+
+  manager = gtk_source_language_manager_get_default ();
+  languages = gtk_source_language_manager_get_language_ids (manager);
+
+  while (*languages)
+    {
+      language = gtk_source_language_manager_get_language (manager, *languages);
+      if (G_LIKELY (GTK_IS_SOURCE_LANGUAGE (language)))
+        {
+          /* ensure no duplicates in list */
+          if (!g_slist_find_custom (list,
+                                    gtk_source_language_get_section (language),
+                                    (GCompareFunc)g_strcmp0))
+            {
+              list = g_slist_prepend (list, (gchar *)gtk_source_language_get_section (language));
+            }
+        }
+      languages++;
+    }
+
+  return g_slist_sort (list, (GCompareFunc)g_strcmp0);
+}
+
+
+
+GSList *
+mousepad_util_languages_get_sorted_for_section (const gchar *section)
+{
+  GSList                   *list = NULL;
+  const gchar *const       *languages;
+  GtkSourceLanguage        *language;
+  GtkSourceLanguageManager *manager;
+
+  mousepad_return_val_if_fail (section != NULL, NULL);
+
+  manager = gtk_source_language_manager_get_default ();
+  languages = gtk_source_language_manager_get_language_ids (manager);
+
+  while (*languages)
+    {
+      language = gtk_source_language_manager_get_language (manager, *languages);
+      if (G_LIKELY (GTK_IS_SOURCE_LANGUAGE (language)))
+        {
+          /* only get languages in the specified section */
+          if (g_strcmp0 (gtk_source_language_get_section (language), section) == 0)
+            list = g_slist_prepend (list, language);
+        }
+      languages++;
+    }
+
+  return g_slist_sort(list, (GCompareFunc)mousepad_util_languages_name_compare);
+}
diff --git a/mousepad/mousepad-util.h b/mousepad/mousepad-util.h
new file mode 100644
index 0000000..dbafd81
--- /dev/null
+++ b/mousepad/mousepad-util.h
@@ -0,0 +1,138 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_UTIL_H__
+#define __MOUSEPAD_UTIL_H__
+
+G_BEGIN_DECLS
+
+#define MOUSEPAD_TYPE_SEARCH_FLAGS (mousepad_util_search_flags_get_type ())
+
+typedef enum _MousepadSearchFlags MousepadSearchFlags;
+
+enum _MousepadSearchFlags
+{
+  /* search area */
+  MOUSEPAD_SEARCH_FLAGS_AREA_DOCUMENT     = 1 << 0,  /* search the entire document */
+  MOUSEPAD_SEARCH_FLAGS_AREA_SELECTION    = 1 << 1,  /* search inside selection */
+
+  /* iter start point */
+  MOUSEPAD_SEARCH_FLAGS_ITER_AREA_START   = 1 << 2,  /* search from the beginning of the area */
+  MOUSEPAD_SEARCH_FLAGS_ITER_AREA_END     = 1 << 3,  /* search from the end of the area */
+  MOUSEPAD_SEARCH_FLAGS_ITER_SEL_START    = 1 << 4,  /* start at from the beginning of the selection */
+  MOUSEPAD_SEARCH_FLAGS_ITER_SEL_END      = 1 << 5,  /* start at from the end of the selection */
+
+  /* direction */
+  MOUSEPAD_SEARCH_FLAGS_DIR_FORWARD       = 1 << 6,  /* search forward to end of area */
+  MOUSEPAD_SEARCH_FLAGS_DIR_BACKWARD      = 1 << 7,  /* search backwards to start of area */
+
+  /* search settings */
+  MOUSEPAD_SEARCH_FLAGS_MATCH_CASE        = 1 << 8,  /* match case */
+  MOUSEPAD_SEARCH_FLAGS_WHOLE_WORD        = 1 << 9,  /* only match whole words */
+  MOUSEPAD_SEARCH_FLAGS_WRAP_AROUND       = 1 << 10, /* wrap around */
+  MOUSEPAD_SEARCH_FLAGS_ENTIRE_AREA       = 1 << 11, /* keep searching until the end of the area is reached */
+  MOUSEPAD_SEARCH_FLAGS_ALL_DOCUMENTS     = 1 << 12, /* search all documents */
+
+
+  /* actions */
+  MOUSEPAD_SEARCH_FLAGS_ACTION_NONE       = 1 << 13, /* no visible actions */
+  MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT = 1 << 14, /* highlight all the occurences */
+  MOUSEPAD_SEARCH_FLAGS_ACTION_CLEANUP    = 1 << 15, /* cleanup the highlighted occurences */
+  MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT     = 1 << 16, /* select the match */
+  MOUSEPAD_SEARCH_FLAGS_ACTION_REPLACE    = 1 << 17, /* replace the match */
+};
+
+gboolean   mousepad_util_iter_starts_word                 (const GtkTextIter   *iter);
+
+gboolean   mousepad_util_iter_ends_word                   (const GtkTextIter   *iter);
+
+gboolean   mousepad_util_iter_inside_word                 (const GtkTextIter   *iter);
+
+gboolean   mousepad_util_iter_forward_word_end            (GtkTextIter         *iter);
+
+gboolean   mousepad_util_iter_backward_word_start         (GtkTextIter         *iter);
+
+gboolean   mousepad_util_iter_forward_text_start          (GtkTextIter         *iter);
+
+gboolean   mousepad_util_iter_backward_text_start         (GtkTextIter         *iter);
+
+gchar     *mousepad_util_config_name                      (const gchar         *name);
+
+gchar     *mousepad_util_key_name                         (const gchar         *name);
+
+gchar     *mousepad_util_utf8_strcapital                  (const gchar         *str);
+
+gchar     *mousepad_util_utf8_stropposite                 (const gchar         *str);
+
+gchar     *mousepad_util_escape_underscores               (const gchar         *str);
+
+GtkWidget *mousepad_util_image_button                     (const gchar         *stock_id,
+                                                           const gchar         *label);
+
+void       mousepad_util_entry_error                      (GtkWidget           *widget,
+                                                           gboolean             error);
+
+void       mousepad_util_dialog_header                    (GtkDialog           *dialog,
+                                                           const gchar         *title,
+                                                           const gchar         *subtitle,
+                                                           const gchar         *icon);
+
+#if !GTK_CHECK_VERSION (2,12,0)
+void       mousepad_util_set_tooltip                      (GtkWidget           *widget,
+                                                           const gchar         *string);
+#endif
+
+gint       mousepad_util_get_real_line_offset             (const GtkTextIter   *iter,
+                                                           gint                 tab_size);
+
+gboolean   mousepad_util_forward_iter_to_text             (GtkTextIter         *iter,
+                                                           const GtkTextIter   *limit);
+
+gchar     *mousepad_util_get_save_location                (const gchar         *relpath,
+                                                           gboolean             create_parents);
+
+void       mousepad_util_save_key_file                    (GKeyFile            *keyfile,
+                                                           const gchar         *filename);
+
+GType      mousepad_util_search_flags_get_type            (void) G_GNUC_CONST;
+
+gint       mousepad_util_highlight                        (GtkTextBuffer       *buffer,
+                                                           GtkTextTag          *tag,
+                                                           const gchar         *string,
+                                                           MousepadSearchFlags  flags);
+
+gint       mousepad_util_search                           (GtkTextBuffer       *buffer,
+                                                           const gchar         *string,
+                                                           const gchar         *replace,
+                                                           MousepadSearchFlags  flags);
+
+gint       mousepad_util_color_schemes_name_compare       (gconstpointer        a,
+                                                           gconstpointer        b);
+
+GSList    *mousepad_util_color_schemes_get                (void);
+
+GSList    *mousepad_util_color_schemes_get_sorted         (void);
+
+gint       mousepad_util_languages_name_compare           (gconstpointer        a,
+                                                           gconstpointer        b);
+
+GSList    *mousepad_util_language_sections_get_sorted     (void);
+
+GSList    *mousepad_util_languages_get_sorted_for_section (const gchar         *section);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_UTIL_H__ */
diff --git a/mousepad/mousepad-view.c b/mousepad/mousepad-view.c
new file mode 100644
index 0000000..9bb4ace
--- /dev/null
+++ b/mousepad/mousepad-view.c
@@ -0,0 +1,2402 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <gdk/gdkkeysyms.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-util.h>
+#include <mousepad/mousepad-view.h>
+
+
+
+#define mousepad_view_get_buffer(view) (GTK_TEXT_VIEW (view)->buffer)
+
+
+
+static void      mousepad_view_finalize                      (GObject            *object);
+static void      mousepad_view_style_set                     (GtkWidget          *widget,
+                                                              GtkStyle           *previous_style);
+static gint      mousepad_view_expose                        (GtkWidget          *widget,
+                                                              GdkEventExpose     *event);
+static gboolean  mousepad_view_key_press_event               (GtkWidget          *widget,
+                                                              GdkEventKey        *event);
+static gboolean  mousepad_view_button_press_event            (GtkWidget          *widget,
+                                                              GdkEventButton     *event);
+static gboolean  mousepad_view_button_release_event          (GtkWidget          *widget,
+                                                              GdkEventButton     *event);
+static gboolean  mousepad_view_selection_word_range          (const GtkTextIter  *iter,
+                                                              GtkTextIter        *range_start,
+                                                              GtkTextIter        *range_end);
+static void      mousepad_view_selection_key_press_event     (MousepadView       *view,
+                                                              const gchar        *text,
+                                                              guint               keyval,
+                                                              guint               modifiers);
+static void      mousepad_view_commit_handler                (GtkIMContext       *context,
+                                                              const gchar        *str,
+                                                              MousepadView       *view);
+static void      mousepad_view_selection_delete_content      (MousepadView       *view);
+static void      mousepad_view_selection_destroy             (MousepadView       *view);
+static void      mousepad_view_selection_draw                (MousepadView       *view,
+                                                              gboolean            append);
+static gboolean  mousepad_view_selection_timeout             (gpointer            user_data);
+static void      mousepad_view_selection_timeout_destroy     (gpointer            user_data);
+static gchar    *mousepad_view_selection_string              (MousepadView       *view);
+static void      mousepad_view_indent_increase               (MousepadView       *view,
+                                                              GtkTextIter        *iter);
+static void      mousepad_view_indent_decrease               (MousepadView       *view,
+                                                              GtkTextIter        *iter);
+static void      mousepad_view_indent_selection              (MousepadView       *view,
+                                                              gboolean            increase,
+                                                              gboolean            force);
+static void      mousepad_view_transpose_multi_selection     (GtkTextBuffer       *buffer,
+                                                              MousepadView        *view);
+static void      mousepad_view_transpose_range               (GtkTextBuffer       *buffer,
+                                                              GtkTextIter         *start_iter,
+                                                              GtkTextIter         *end_iter);
+static void      mousepad_view_transpose_lines               (GtkTextBuffer       *buffer,
+                                                              GtkTextIter         *start_iter,
+                                                              GtkTextIter         *end_iter);
+static void      mousepad_view_transpose_words               (GtkTextBuffer       *buffer,
+                                                              GtkTextIter         *iter);
+
+
+
+struct _MousepadViewClass
+{
+  GtkSourceViewClass __parent__;
+};
+
+struct _MousepadView
+{
+  GtkSourceView  __parent__;
+
+  /* the selection style tag */
+  GtkTextTag         *selection_tag;
+
+  /* list with all the selection marks */
+  GSList             *selection_marks;
+
+  /* selection timeout id */
+  guint               selection_timeout_id;
+
+  /* coordinates for the selection */
+  gint                selection_start_x;
+  gint                selection_start_y;
+  gint                selection_end_x;
+  gint                selection_end_y;
+
+  /* length of the selection (-1 = zerro width selection, 0 = no selection) */
+  gint                selection_length;
+
+  /* if the selection is in editing mode */
+  guint               selection_editing : 1;
+};
+
+
+
+G_DEFINE_TYPE (MousepadView, mousepad_view, GTK_TYPE_SOURCE_VIEW);
+
+
+
+static void
+mousepad_view_class_init (MousepadViewClass *klass)
+{
+  GObjectClass   *gobject_class;
+  GtkWidgetClass *widget_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = mousepad_view_finalize;
+
+  widget_class = GTK_WIDGET_CLASS (klass);
+  widget_class->expose_event         = mousepad_view_expose;
+  widget_class->style_set            = mousepad_view_style_set;
+  widget_class->key_press_event      = mousepad_view_key_press_event;
+  widget_class->button_press_event   = mousepad_view_button_press_event;
+  widget_class->button_release_event = mousepad_view_button_release_event;
+}
+
+
+
+static void
+mousepad_view_init (MousepadView *view)
+{
+  /* initialize selection variables */
+  view->selection_timeout_id = 0;
+  view->selection_tag = NULL;
+  view->selection_marks = NULL;
+  view->selection_length = 0;
+  view->selection_editing = FALSE;
+
+  /* reset drag coordinates */
+  view->selection_start_x = view->selection_end_x = -1;
+  view->selection_start_y = view->selection_end_y = -1;
+
+  g_signal_connect (GTK_TEXT_VIEW (view)->im_context, "commit",
+                    G_CALLBACK (mousepad_view_commit_handler), view);
+}
+
+
+
+static void
+mousepad_view_finalize (GObject *object)
+{
+  MousepadView *view = MOUSEPAD_VIEW (object);
+
+  /* stop a running selection timeout */
+  if (G_UNLIKELY (view->selection_timeout_id != 0))
+    g_source_remove (view->selection_timeout_id);
+
+  /* free the selection marks list (marks are owned by the buffer) */
+  if (G_UNLIKELY (view->selection_marks != NULL))
+    g_slist_free (view->selection_marks);
+
+  (*G_OBJECT_CLASS (mousepad_view_parent_class)->finalize) (object);
+}
+
+
+
+static gboolean
+mousepad_view_expose (GtkWidget      *widget,
+                      GdkEventExpose *event)
+{
+  GtkTextView  *textview = GTK_TEXT_VIEW (widget);
+  MousepadView *view = MOUSEPAD_VIEW (widget);
+
+  if (G_UNLIKELY (view->selection_length == -1
+      && (view->selection_marks != NULL || view->selection_end_x != -1)
+      && event->window == gtk_text_view_get_window (textview, GTK_TEXT_WINDOW_TEXT)))
+    {
+      /* redraw the cursor lines for the vertical selection */
+      mousepad_view_selection_draw (view, FALSE);
+    }
+
+  /* gtk can draw the text now */
+  return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->expose_event) (widget, event);
+}
+
+
+
+static void
+mousepad_view_style_set (GtkWidget *widget,
+                         GtkStyle  *previous_style)
+{
+  GtkStyle      *style;
+  GtkTextIter    start, end;
+  MousepadView  *view = MOUSEPAD_VIEW (widget);
+  GtkTextBuffer *buffer;
+
+  /* run widget handler */
+  (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->style_set) (widget, previous_style);
+
+  /* update the style after a real style change */
+  if (previous_style)
+    {
+      /* get the textview style */
+      style = gtk_widget_get_style (widget);
+
+      /* get the text buffer */
+      buffer = mousepad_view_get_buffer (view);
+
+      /* remove previous selection tag */
+      if (G_UNLIKELY (view->selection_tag))
+        {
+          gtk_text_buffer_get_bounds (buffer, &start, &end);
+          gtk_text_buffer_remove_tag (buffer, view->selection_tag, &start, &end);
+        }
+
+      /* create the new selection tag */
+      view->selection_tag = gtk_text_buffer_create_tag (buffer, NULL,
+                                                        "background-gdk", &style->base[GTK_STATE_SELECTED],
+                                                        "foreground-gdk", &style->text[GTK_STATE_SELECTED],
+                                                        NULL);
+
+      /* redraw selection */
+      if (view->selection_marks != NULL)
+        mousepad_view_selection_draw (view, FALSE);
+    }
+}
+
+
+
+static gboolean
+mousepad_view_key_press_event (GtkWidget   *widget,
+                               GdkEventKey *event)
+{
+  MousepadView  *view = MOUSEPAD_VIEW (widget);
+  GtkTextBuffer *buffer;
+  GtkTextIter    iter;
+  GtkTextMark   *cursor;
+  guint          modifiers;
+  gboolean       im_handled;
+  gboolean       is_editable;
+
+  /* get the modifiers state */
+  modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
+
+  /* get the textview buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* whether the textview is editable */
+  is_editable = GTK_TEXT_VIEW (view)->editable;
+
+  /* handle the key event */
+  switch (event->keyval)
+    {
+      case GDK_End:
+      case GDK_KP_End:
+        if (modifiers & GDK_CONTROL_MASK)
+          {
+            /* get the end iter */
+            gtk_text_buffer_get_end_iter (buffer, &iter);
+
+            /* get the cursor mark */
+            cursor = gtk_text_buffer_get_insert (buffer);
+
+            goto move_cursor;
+          }
+        break;
+
+      case GDK_Home:
+      case GDK_KP_Home:
+        /* get the cursor mark */
+        cursor = gtk_text_buffer_get_insert (buffer);
+
+        /* when control is pressed, we jump to the start of the document */
+        if (modifiers & GDK_CONTROL_MASK)
+          {
+            /* get the start iter */
+            gtk_text_buffer_get_start_iter (buffer, &iter);
+
+            goto move_cursor;
+          }
+
+        /* get the iter position of the cursor */
+        gtk_text_buffer_get_iter_at_mark (buffer, &iter, cursor);
+
+        /* if the cursor starts a line, try to move it in front of the text */
+        if (gtk_text_iter_starts_line (&iter)
+            && mousepad_util_forward_iter_to_text (&iter, NULL))
+          {
+             /* label for the ctrl home/end events */
+             move_cursor:
+
+             /* move (select) or set (jump) cursor */
+             if (modifiers & GDK_SHIFT_MASK)
+               gtk_text_buffer_move_mark (buffer, cursor, &iter);
+             else
+               gtk_text_buffer_place_cursor (buffer, &iter);
+
+             /* make sure the cursor is visible for the user */
+             mousepad_view_scroll_to_cursor (view);
+
+             return TRUE;
+          }
+        break;
+
+      case GDK_Delete:
+      case GDK_KP_Delete:
+        if (view->selection_marks != NULL && is_editable)
+          {
+            /* delete or destroy the selection */
+            if (view->selection_length > 0)
+              mousepad_view_delete_selection (view);
+            else
+              mousepad_view_selection_destroy (view);
+
+            return TRUE;
+          }
+        break;
+
+      case GDK_BackSpace:
+        if (view->selection_marks != NULL && is_editable)
+          {
+            /* backspace in the selection */
+            mousepad_view_selection_key_press_event (view, NULL, GDK_BackSpace, modifiers);
+
+            return TRUE;
+          }
+        break;
+
+      default:
+        if (G_UNLIKELY (view->selection_marks != NULL && is_editable))
+          {
+            /* block textview updates (from gtk) */
+            gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
+
+            /* handle the im context */
+            im_handled = gtk_im_context_filter_keypress (GTK_TEXT_VIEW (view)->im_context, event);
+
+            /* allow textview updates again */
+            gtk_text_view_set_editable (GTK_TEXT_VIEW (view), TRUE);
+
+            /* only leave when the im handle the event */
+            if (im_handled)
+              return TRUE;
+          }
+    }
+
+  /* remove the selection when no valid key combination has been pressed */
+  if (G_UNLIKELY (view->selection_marks != NULL && event->is_modifier == FALSE))
+    mousepad_view_selection_destroy (view);
+
+  return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->key_press_event) (widget, event);
+}
+
+
+
+static void
+mousepad_view_commit_handler (GtkIMContext *context,
+                              const gchar  *str,
+                              MousepadView *view)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+  mousepad_return_if_fail (GTK_IS_IM_CONTEXT (context));
+
+  /* if there is a selection, insert this string there too */
+  if (G_UNLIKELY (view->selection_marks != NULL))
+    {
+      /* debug check */
+      mousepad_return_if_fail (gtk_text_view_get_editable (GTK_TEXT_VIEW (view)) == FALSE);
+
+      /* handle the text input for the multi selection */
+      mousepad_view_selection_key_press_event (view, str, 0, 0);
+    }
+}
+
+
+
+static gboolean
+mousepad_view_button_press_event (GtkWidget      *widget,
+                                  GdkEventButton *event)
+{
+  MousepadView  *view = MOUSEPAD_VIEW (widget);
+  GtkTextView   *textview = GTK_TEXT_VIEW (widget);
+  GtkTextIter    iter, start_iter, end_iter;
+  GtkTextBuffer *buffer;
+
+  /* destroy old selection */
+  if (view->selection_marks != NULL && event->button != 3)
+    mousepad_view_selection_destroy (view);
+
+  /* work with vertical selection while ctrl is pressed */
+  if (event->state & GDK_CONTROL_MASK
+      && event->x >= 0
+      && event->y >= 0
+      && event->button == 1
+      && event->type == GDK_BUTTON_PRESS)
+    {
+      /* set the vertical selection start position, including textview offset */
+      view->selection_start_x = event->x + textview->xoffset;
+      view->selection_start_y = event->y + textview->yoffset;
+
+      /* hide cursor */
+      gtk_text_view_set_cursor_visible (textview, FALSE);
+
+      /* start a vertical selection timeout */
+      view->selection_timeout_id = g_timeout_add_full (G_PRIORITY_LOW, 50, mousepad_view_selection_timeout,
+                                                       view, mousepad_view_selection_timeout_destroy);
+
+      return TRUE;
+    }
+  else if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
+    {
+      /* get the iter under the cursor */
+      gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter,
+                                          event->x + textview->xoffset,
+                                          event->y + textview->yoffset);
+
+      /* try to select a whole word or space */
+      if (mousepad_view_selection_word_range (&iter, &start_iter, &end_iter))
+        {
+          /* get the buffer */
+          buffer = mousepad_view_get_buffer (view);
+
+          /* select range */
+          gtk_text_buffer_select_range (buffer, &end_iter, &start_iter);
+
+          return TRUE;
+        }
+    }
+
+  return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->button_press_event) (widget, event);
+}
+
+
+
+static gboolean
+mousepad_view_button_release_event (GtkWidget      *widget,
+                                    GdkEventButton *event)
+{
+  MousepadView  *view = MOUSEPAD_VIEW (widget);
+
+  /* end of a vertical selection */
+  if (G_UNLIKELY (view->selection_timeout_id != 0))
+    {
+      /* stop the timeout */
+      g_source_remove (view->selection_timeout_id);
+
+      /* append the selected marks */
+      mousepad_view_selection_draw (view, TRUE);
+
+      /* reset the drag coordinates */
+      view->selection_start_x = view->selection_end_x = -1;
+      view->selection_start_y = view->selection_end_y = -1;
+    }
+
+  return (*GTK_WIDGET_CLASS (mousepad_view_parent_class)->button_release_event) (widget, event);
+}
+
+
+
+/**
+ * Selection Functions
+ **/
+static gboolean
+mousepad_view_selection_word_range (const GtkTextIter *iter,
+                                    GtkTextIter       *range_start,
+                                    GtkTextIter       *range_end)
+{
+  /* init iters */
+  *range_start = *range_end = *iter;
+
+  /* get the iter character */
+  if (!mousepad_util_iter_inside_word (iter))
+    {
+      /* walk back and forward to select as much spaces as possible */
+      if (!mousepad_util_iter_forward_text_start (range_end))
+        return FALSE;
+
+      if (!mousepad_util_iter_backward_text_start (range_start))
+        return FALSE;
+    }
+  else
+    {
+      /* return false when we could not find a word start */
+      if (!mousepad_util_iter_backward_word_start (range_start))
+        return FALSE;
+
+      /* return false when we could not find a word end */
+      if (!mousepad_util_iter_forward_word_end (range_end))
+        return FALSE;
+    }
+
+  /* sort iters */
+  gtk_text_iter_order (range_start, range_end);
+
+  /* when the iters are not equal and the origional iter is in the range, we succeeded */
+  return (!gtk_text_iter_equal (range_start, range_end)
+          && gtk_text_iter_compare (iter, range_start) >= 0
+          && gtk_text_iter_compare (iter, range_end) <= 0);
+}
+
+
+
+static void
+mousepad_view_selection_key_press_event (MousepadView *view,
+                                         const gchar  *text,
+                                         guint         keyval,
+                                         guint         modifiers)
+{
+  GtkTextIter    start_iter, end_iter;
+  GSList        *li;
+  GtkTextBuffer *buffer;
+
+  mousepad_return_if_fail (view->selection_marks != NULL);
+  mousepad_return_if_fail (view->selection_start_x == -1);
+  mousepad_return_if_fail (view->selection_end_x == -1);
+  mousepad_return_if_fail ((keyval == 0 && text != NULL) || keyval != 0);
+  mousepad_return_if_fail (g_slist_length (view->selection_marks) % 2 == 0);
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* begin user action */
+  gtk_text_buffer_begin_user_action (buffer);
+
+  /* delete the content of the selection when we're not in editing mode yet */
+  if (view->selection_editing == FALSE && view->selection_length > 0)
+    mousepad_view_selection_delete_content (view);
+
+  /* enter editing mode */
+  view->selection_editing = TRUE;
+
+  for (li = view->selection_marks; li != NULL; li = li->next)
+    {
+      /* get end iter */
+      gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, li->next->data);
+
+      /* handle the event */
+      if (keyval == GDK_Tab)
+        {
+          /* insert a (soft) tab */
+          mousepad_view_indent_increase (view, &end_iter);
+        }
+      else if (keyval == GDK_BackSpace)
+        {
+          /* get start iter */
+          gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, li->data);
+
+          /* only backspace when there is text inside the selection or ctrl is pressed */
+          if (!gtk_text_iter_equal (&start_iter, &end_iter) || modifiers == GDK_CONTROL_MASK)
+            gtk_text_buffer_backspace (buffer, &end_iter, FALSE, TRUE);
+        }
+      else if (text != NULL)
+        {
+          /* insert the text */
+          gtk_text_buffer_insert (buffer, &end_iter, text, -1);
+        }
+
+      /* go to next element in the list */
+      li = li->next;
+    }
+
+  /* redraw the content */
+  mousepad_view_selection_draw (view, FALSE);
+
+  /* end user action */
+  gtk_text_buffer_end_user_action (buffer);
+}
+
+
+
+static void
+mousepad_view_selection_delete_content (MousepadView *view)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    start_iter, end_iter;
+  GSList        *li;
+
+  mousepad_return_if_fail (view->selection_marks != NULL);
+  mousepad_return_if_fail (view->selection_length > 0);
+  mousepad_return_if_fail (g_slist_length (view->selection_marks) % 2 == 0);
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* begin user action */
+  gtk_text_buffer_begin_user_action (buffer);
+
+  /* remove everything between the marks */
+  for (li = view->selection_marks; li != NULL; li = li->next)
+    {
+      /* get start iter */
+      gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, li->data);
+
+      /* next element */
+      li = li->next;
+
+      /* get end iter */
+      gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, li->data);
+
+      /* delete content between the iters */
+      gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
+    }
+
+  /* set the selection length to -1 */
+  view->selection_length = -1;
+
+  /* end user action */
+  gtk_text_buffer_end_user_action (buffer);
+}
+
+
+
+static void
+mousepad_view_selection_destroy (MousepadView *view)
+{
+  GtkTextBuffer *buffer;
+  GSList        *li;
+  GtkTextIter    start_iter, end_iter;
+
+  mousepad_return_if_fail (view->selection_marks != NULL);
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* freeze notifications */
+  g_object_freeze_notify (G_OBJECT (buffer));
+
+  /* remove the selection tags */
+  gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
+  gtk_text_buffer_remove_tag (buffer, view->selection_tag, &start_iter, &end_iter);
+
+  /* remove all the selection marks */
+  if (G_LIKELY (view->selection_marks))
+    {
+      /* delete marks from the buffer */
+      for (li = view->selection_marks; li != NULL; li = li->next)
+        gtk_text_buffer_delete_mark (buffer, li->data);
+
+      /* free the list */
+      g_slist_free (view->selection_marks);
+
+      /* null */
+      view->selection_marks = NULL;
+    }
+
+  /* set selection length to zerro */
+  view->selection_length = 0;
+
+  /* unset editing mode */
+  view->selection_editing = FALSE;
+
+  /* show cursor again */
+  gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), TRUE);
+
+  /* update buffer status */
+  g_object_notify (G_OBJECT (buffer), "has-selection");
+
+  /* allow notifications again */
+  g_object_thaw_notify (G_OBJECT (buffer));
+}
+
+
+
+static void
+mousepad_view_selection_draw (MousepadView *view,
+                              gboolean      append)
+{
+  GtkTextBuffer *buffer;
+  GtkTextView   *textview = GTK_TEXT_VIEW (view);
+  GtkTextIter    start_iter, end_iter;
+  GdkWindow     *window;
+  gint           y, y_begin, y_height, y_end;
+  gint           line_x, line_y;
+  GdkRectangle   rect;
+  gint           length = 0;
+  gint           visible_start_y = 0;
+  GtkTextMark   *start_mark, *end_mark;
+  GSList        *li;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+  mousepad_return_if_fail (view->selection_marks == NULL || g_slist_length (view->selection_marks) % 2 == 0);
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* freeze buffer notifications */
+  g_object_freeze_notify (G_OBJECT (buffer));
+
+  /* get the drawable window */
+  window = gtk_text_view_get_window (textview, GTK_TEXT_WINDOW_TEXT);
+
+  /* cleanup the old selection */
+  if (view->selection_length > 0)
+    {
+      /* remove the old tags */
+      gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
+      gtk_text_buffer_remove_tag (buffer, view->selection_tag, &start_iter, &end_iter);
+    }
+  else if (view->selection_length == -1)
+    {
+      /* invalidate the window so no retangles are left */
+      gtk_widget_queue_draw (GTK_WIDGET (view));
+    }
+
+  /* draw the dragging selection or the marks in the list */
+  if (view->selection_start_y != -1 && view->selection_end_y != -1)
+    {
+      /* get the start and end iter */
+      gtk_text_view_get_iter_at_location (textview, &start_iter, 0, view->selection_start_y);
+      gtk_text_view_get_iter_at_location (textview, &end_iter, 0, view->selection_end_y);
+
+      /* make sure the start iter is before the end iter */
+      gtk_text_iter_order (&start_iter, &end_iter);
+
+      /* get the y coordinates we're going to walk */
+      gtk_text_view_get_line_yrange (textview, &start_iter, &y_begin, &y_height);
+      gtk_text_view_get_line_yrange (textview, &end_iter, &y_end, NULL);
+
+      /* make sure atleast one line is selected */
+      y_end += y_height;
+
+      /* get the visible area */
+      if (G_LIKELY (append == FALSE))
+        {
+          visible_start_y = MIN (y_begin, y_end);
+          visible_start_y = MAX (visible_start_y, textview->yoffset);
+        }
+
+      /* walk the lines inside the selection area */
+      for (y = y_begin; y < y_end; y += y_height)
+        {
+          /* get the start and end iter in the line */
+          gtk_text_view_get_iter_at_location (textview, &start_iter, view->selection_start_x, y);
+          gtk_text_view_get_iter_at_location (textview, &end_iter, view->selection_end_x, y);
+
+          /* make sure the iters are correctly sorted */
+          gtk_text_iter_order (&start_iter, &end_iter);
+
+          /* calculate length of selection */
+          length += gtk_text_iter_get_line_offset (&end_iter) - gtk_text_iter_get_line_offset (&start_iter);
+
+          /* continue if this iter is outside the visible area */
+          if (y < visible_start_y)
+            continue;
+
+          if (length == 0)
+            {
+              /* get the iter location and size */
+              gtk_text_view_get_iter_location (textview, &end_iter, &rect);
+
+              /* calculate line cooridinates */
+              line_x = rect.x - textview->xoffset;
+              line_y = rect.y - textview->yoffset;
+
+              /* draw a line in front of the iter */
+              gdk_draw_line (GDK_DRAWABLE (window),
+                             GTK_WIDGET (view)->style->base_gc[GTK_STATE_SELECTED],
+                             line_x, line_y, line_x, line_y + rect.height - 1);
+            }
+          else if (!gtk_text_iter_equal (&start_iter, &end_iter))
+            {
+              /* apply tag */
+              gtk_text_buffer_apply_tag (buffer, view->selection_tag, &start_iter, &end_iter);
+            }
+          else
+            {
+              /* when both of the conditions above were not met, we'll
+               * never added them to the marks list and there is nothing to draw
+               * eighter */
+              continue;
+            }
+
+          if (append)
+            {
+              /* create marks */
+              start_mark = gtk_text_buffer_create_mark (buffer, NULL, &start_iter, TRUE);
+              end_mark = gtk_text_buffer_create_mark (buffer, NULL, &end_iter, FALSE);
+
+              /* append to the list */
+              view->selection_marks = g_slist_append (view->selection_marks, start_mark);
+              view->selection_marks = g_slist_append (view->selection_marks, end_mark);
+            }
+        }
+    }
+  else
+    {
+      for (li = view->selection_marks; li != NULL; li = li->next)
+        {
+          /* get the start iter */
+          gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, li->data);
+
+          /* next element in the list */
+          li = li->next;
+
+          /* get the end iter */
+          gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, li->data);
+
+          /* calculate length of selection */
+          length += gtk_text_iter_get_line_offset (&end_iter) - gtk_text_iter_get_line_offset (&start_iter);
+
+          if (length == 0)
+            {
+              /* get the iter location and size */
+              gtk_text_view_get_iter_location (textview, &start_iter, &rect);
+
+              /* calculate line coordinates */
+              line_x = rect.x - textview->xoffset;
+              line_y = rect.y - textview->yoffset;
+
+              /* draw a line in front of the iter */
+              gdk_draw_line (GDK_DRAWABLE (window),
+                             GTK_WIDGET (view)->style->base_gc[GTK_STATE_SELECTED],
+                             line_x, line_y, line_x, line_y + rect.height - 1);
+            }
+          else
+            {
+              /* apply tag */
+              gtk_text_buffer_apply_tag (buffer, view->selection_tag, &start_iter, &end_iter);
+            }
+        }
+    }
+
+  /* emit signal for selection (type) change */
+  if ((length == 0 && view->selection_length != -1)
+      || (length > 0 && view->selection_length <= 0))
+    g_object_notify (G_OBJECT (buffer), "has-selection");
+
+  /* update the selection length */
+  view->selection_length = length > 0 ? length : -1;
+
+  /* allow sending notifications again */
+  g_object_thaw_notify (G_OBJECT (buffer));
+}
+
+
+
+static gboolean
+mousepad_view_selection_timeout (gpointer user_data)
+{
+  MousepadView  *view = MOUSEPAD_VIEW (user_data);
+  GtkTextView   *textview = GTK_TEXT_VIEW (view);
+  gint           pointer_x, pointer_y;
+  gint           selection_start_x, selection_start_y;
+  GtkTextBuffer *buffer;
+  GtkTextIter    iter, cursor;
+
+  GDK_THREADS_ENTER ();
+
+  /* get the cursor coordinate */
+  gdk_window_get_pointer (gtk_text_view_get_window (textview, GTK_TEXT_WINDOW_TEXT),
+                          &pointer_x, &pointer_y, NULL);
+
+  /* convert to positive values and add buffer offset */
+  pointer_x = MAX (pointer_x, 0) + textview->xoffset;
+  pointer_y = MAX (pointer_y, 0) + textview->yoffset;
+
+  /* only update the selection when the cursor moved */
+  if (view->selection_end_x != pointer_x || view->selection_end_y != pointer_y)
+    {
+      /* update the end coordinates */
+      view->selection_end_x = pointer_x;
+      view->selection_end_y = pointer_y;
+
+      /* backup start coordinates */
+      selection_start_x = view->selection_start_x;
+      selection_start_y = view->selection_start_y;
+
+      /* get the text buffer */
+      buffer = mousepad_view_get_buffer (view);
+
+      /* get the iter position of the cursor based on the coordinates */
+      gtk_text_view_get_iter_at_location (textview, &iter, pointer_x, pointer_y);
+
+      /* get the real cursor position */
+      gtk_text_buffer_get_iter_at_mark (buffer, &cursor, gtk_text_buffer_get_insert (buffer));
+
+      /* redraw the selection when the cursor position changed */
+      if (!gtk_text_iter_equal (&iter, &cursor))
+        {
+          /* show the selection */
+          mousepad_view_selection_draw (view, FALSE);
+
+          /* update the cursor position */
+          gtk_text_buffer_place_cursor (buffer, &iter);
+
+          /* put cursor on screen */
+          mousepad_view_scroll_to_cursor (view);
+        }
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  /* keep the timeout running */
+  return TRUE;
+}
+
+
+
+static void
+mousepad_view_selection_timeout_destroy (gpointer user_data)
+{
+  MOUSEPAD_VIEW (user_data)->selection_timeout_id = 0;
+}
+
+
+
+static gchar *
+mousepad_view_selection_string (MousepadView *view)
+{
+  GString       *string;
+  GtkTextBuffer *buffer;
+  gint           line, previous_line = -1;
+  gchar         *slice;
+  GtkTextIter    start_iter, end_iter;
+  GSList        *li;
+
+  mousepad_return_val_if_fail (view->selection_marks == NULL || g_slist_length (view->selection_marks) % 2 == 0, NULL);
+
+  /* create new string */
+  string = g_string_new (NULL);
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  for (li = view->selection_marks; li != NULL; li = li->next)
+    {
+      /* get the iters */
+      gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, li->data);
+      li = li->next;
+      gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, li->data);
+
+      /* get the line number */
+      line = gtk_text_iter_get_line (&start_iter);
+
+      /* fix the number of new lines between the parts */
+      if (previous_line == -1)
+        previous_line = line;
+      else
+        for (; previous_line < line; previous_line++)
+          string = g_string_append_c (string, '\n');
+
+      /* get the text slice */
+      slice = gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, TRUE);
+
+      /* append the slice to the string */
+      string = g_string_append (string, slice);
+
+      /* cleanup */
+      g_free (slice);
+    }
+
+  /* return the string */
+  return g_string_free (string, FALSE);
+}
+
+
+
+/**
+ * Indentation Functions
+ **/
+static void
+mousepad_view_indent_increase (MousepadView *view,
+                               GtkTextIter  *iter)
+{
+  gchar         *string;
+  gint           offset, length, inline_len, tab_size;
+  GtkTextBuffer *buffer;
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+  tab_size = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (view));
+
+  if (gtk_source_view_get_insert_spaces_instead_of_tabs (GTK_SOURCE_VIEW (view)))
+    {
+      /* get the offset */
+      offset = mousepad_util_get_real_line_offset (iter, tab_size);
+
+      /* calculate the length to inline with a tab */
+      inline_len = offset % tab_size;
+
+      if (inline_len == 0)
+        length = tab_size;
+      else
+        length = tab_size - inline_len;
+
+      /* create spaces string */
+      string = g_strnfill (length, ' ');
+
+      /* insert string */
+      gtk_text_buffer_insert (buffer, iter, string, length);
+
+      /* cleanup */
+      g_free (string);
+    }
+  else
+    {
+      /* insert a tab or a space */
+      gtk_text_buffer_insert (buffer, iter, "\t", -1);
+    }
+}
+
+
+
+static void
+mousepad_view_indent_decrease (MousepadView *view,
+                               GtkTextIter  *iter)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    start, end;
+  gint           columns, tab_size;
+  gunichar       c;
+
+  /* set iters */
+  start = end = *iter;
+
+  tab_size = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (view));
+  columns = tab_size;
+
+  /* walk until we've removed enough columns */
+  while (columns > 0)
+    {
+      /* get the character */
+      c = gtk_text_iter_get_char (&end);
+
+      if (c == '\t')
+        columns -= tab_size;
+      else if (c == ' ')
+        columns--;
+      else
+        break;
+
+      /* go to the next character */
+      gtk_text_iter_forward_char (&end);
+    }
+
+  /* unindent the selection when the iters are not equal */
+  if (!gtk_text_iter_equal (&start, &end))
+    {
+      /* get the buffer */
+      buffer = mousepad_view_get_buffer (view);
+
+      /* remove the columns */
+      gtk_text_buffer_delete (buffer, &start, &end);
+    }
+}
+
+
+
+static void
+mousepad_view_indent_selection (MousepadView *view,
+                                gboolean      increase,
+                                gboolean      force)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    start_iter, end_iter;
+  gint           start_line, end_line;
+  gint           i;
+
+  /* get the textview buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  if (gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter) || force)
+    {
+      /* begin a user action */
+      gtk_text_buffer_begin_user_action (buffer);
+
+      /* get start and end line */
+      start_line = gtk_text_iter_get_line (&start_iter);
+      end_line = gtk_text_iter_get_line (&end_iter);
+
+      /* only change indentation when an entire line is selected or multiple lines */
+      if (start_line != end_line
+          || ((gtk_text_iter_starts_line (&start_iter) && gtk_text_iter_ends_line (&end_iter)) || force))
+        {
+          /* change indentation of each line */
+          for (i = start_line; i <= end_line && i < G_MAXINT; i++)
+            {
+              /* get the iter of the line we're going to indent */
+              gtk_text_buffer_get_iter_at_line (buffer, &start_iter, i);
+
+              /* don't change indentation of empty lines */
+              if (gtk_text_iter_ends_line (&start_iter))
+                continue;
+
+              /* increase or decrease the indentation */
+              if (increase)
+                mousepad_view_indent_increase (view, &start_iter);
+              else
+                mousepad_view_indent_decrease (view, &start_iter);
+            }
+        }
+
+      /* end user action */
+      gtk_text_buffer_end_user_action (buffer);
+
+      /* put cursor on screen */
+      mousepad_view_scroll_to_cursor (view);
+    }
+}
+
+
+void
+mousepad_view_scroll_to_cursor (MousepadView *view)
+{
+  GtkTextBuffer *buffer;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* scroll to visible area */
+  gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
+                                gtk_text_buffer_get_insert (buffer),
+                                0.02, FALSE, 0.0, 0.0);
+}
+
+
+
+static void
+mousepad_view_transpose_multi_selection (GtkTextBuffer *buffer,
+                                         MousepadView  *view)
+{
+  GSList      *li, *ls;
+  GSList      *strings = NULL;
+  GtkTextIter  start_iter, end_iter;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* get the strings and delete the existing strings */
+  for (li = view->selection_marks; li != NULL; li = li->next)
+    {
+      /* get the iters */
+      gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, li->data);
+      li = li->next;
+      gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, li->data);
+
+      /* prepend the text between the iters to an internal list */
+      strings = g_slist_prepend (strings, gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, FALSE));
+
+      /* delete the content */
+      gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
+    }
+
+  /* insert the strings in reversed order */
+  for (li = view->selection_marks, ls = strings; li != NULL && ls != NULL; li = li->next, ls = ls->next)
+    {
+      /* get the end iter */
+      gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, li->next->data);
+
+      /* insert the string */
+      gtk_text_buffer_insert (buffer, &end_iter, ls->data, -1);
+
+      /* get the start iter */
+      gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, li->data);
+
+      /* apply tag */
+      gtk_text_buffer_apply_tag (buffer, view->selection_tag, &start_iter, &end_iter);
+
+      /* free string */
+      g_free (ls->data);
+
+      /* next iter */
+      li = li->next;
+    }
+
+  /* free list */
+  g_slist_free (strings);
+}
+
+
+
+static void
+mousepad_view_transpose_range (GtkTextBuffer *buffer,
+                               GtkTextIter   *start_iter,
+                               GtkTextIter   *end_iter)
+{
+  gchar *string, *reversed;
+  gint   offset;
+
+  /* store start iter line offset */
+  offset = gtk_text_iter_get_offset (start_iter);
+
+  /* get selected text */
+  string = gtk_text_buffer_get_slice (buffer, start_iter, end_iter, FALSE);
+  if (G_LIKELY (string))
+    {
+      /* reverse the string */
+      reversed = g_utf8_strreverse (string, -1);
+
+      /* only change the buffer then the string changed */
+      if (G_LIKELY (reversed && strcmp (reversed, string) != 0))
+        {
+          /* delete the text between the iters */
+          gtk_text_buffer_delete (buffer, start_iter, end_iter);
+
+          /* insert the reversed string */
+          gtk_text_buffer_insert (buffer, end_iter, reversed, -1);
+
+          /* restore start iter */
+          gtk_text_buffer_get_iter_at_offset (buffer, start_iter, offset);
+        }
+
+      /* cleanup */
+      g_free (string);
+      g_free (reversed);
+    }
+}
+
+
+
+static void
+mousepad_view_transpose_lines (GtkTextBuffer *buffer,
+                               GtkTextIter   *start_iter,
+                               GtkTextIter   *end_iter)
+{
+  GString *string;
+  gint     start_line, end_line;
+  gint     i;
+  gchar   *slice;
+
+  /* make sure the order is ok */
+  gtk_text_iter_order (start_iter, end_iter);
+
+  /* get the line numbers */
+  start_line = gtk_text_iter_get_line (start_iter);
+  end_line = gtk_text_iter_get_line (end_iter);
+
+  /* new string */
+  string = g_string_new (NULL);
+
+  /* add the lines in reversed order to the string */
+  for (i = start_line; i <= end_line && i < G_MAXINT; i++)
+    {
+      /* get start iter */
+      gtk_text_buffer_get_iter_at_line (buffer, start_iter, i);
+
+      /* set end iter */
+      *end_iter = *start_iter;
+
+      /* only prepend when the iters won't be equal */
+      if (!gtk_text_iter_ends_line (end_iter))
+        {
+          /* move the iter to the end of this line */
+          gtk_text_iter_forward_to_line_end (end_iter);
+
+          /* prepend line */
+          slice = gtk_text_buffer_get_slice (buffer, start_iter, end_iter, FALSE);
+          string = g_string_prepend (string, slice);
+          g_free (slice);
+        }
+
+      /* prepend new line */
+      if (i < end_line)
+        string = g_string_prepend_c (string, '\n');
+    }
+
+  /* get start iter again */
+  gtk_text_buffer_get_iter_at_line (buffer, start_iter, start_line);
+
+  /* delete selection */
+  gtk_text_buffer_delete (buffer, start_iter, end_iter);
+
+  /* insert reversed lines */
+  gtk_text_buffer_insert (buffer, end_iter, string->str, string->len);
+
+  /* cleanup */
+  g_string_free (string, TRUE);
+
+  /* restore start iter */
+  gtk_text_buffer_get_iter_at_line (buffer, start_iter, start_line);
+}
+
+static void
+mousepad_view_transpose_words (GtkTextBuffer *buffer,
+                               GtkTextIter   *iter)
+{
+  GtkTextMark *left_mark, *right_mark;
+  GtkTextIter  start_left, end_left, start_right, end_right;
+  gchar       *word_left, *word_right;
+  gboolean     restore_cursor;
+
+  /* left word end */
+  end_left = *iter;
+  if (!mousepad_util_iter_backward_text_start (&end_left))
+    return;
+
+  /* left word start */
+  start_left = end_left;
+  if (!mousepad_util_iter_backward_word_start (&start_left))
+    return;
+
+  /* right word start */
+  start_right = *iter;
+  if (!mousepad_util_iter_forward_text_start (&start_right))
+    return;
+
+  /* right word end */
+  end_right = start_right;
+  if (!mousepad_util_iter_forward_word_end (&end_right))
+    return;
+
+  /* check if we selected something usefull */
+  if (gtk_text_iter_get_line (&start_left) == gtk_text_iter_get_line (&end_right)
+      && !gtk_text_iter_equal (&start_left, &end_left)
+      && !gtk_text_iter_equal (&start_right, &end_right)
+      && !gtk_text_iter_equal (&end_left, &start_right))
+    {
+      /* get the words */
+      word_left = gtk_text_buffer_get_slice (buffer, &start_left, &end_left, FALSE);
+      word_right = gtk_text_buffer_get_slice (buffer, &start_right, &end_right, FALSE);
+
+      /* check if we need to restore the cursor afterwards */
+      restore_cursor = gtk_text_iter_equal (iter, &start_right);
+
+      /* insert marks at the start and end of the right word */
+      left_mark = gtk_text_buffer_create_mark (buffer, NULL, &start_right, TRUE);
+      right_mark = gtk_text_buffer_create_mark (buffer, NULL, &end_right, FALSE);
+
+      /* delete the left word and insert the right word there */
+      gtk_text_buffer_delete (buffer, &start_left, &end_left);
+      gtk_text_buffer_insert (buffer, &start_left, word_right, -1);
+      g_free (word_right);
+
+      /* restore the right word iters */
+      gtk_text_buffer_get_iter_at_mark (buffer, &start_right, left_mark);
+      gtk_text_buffer_get_iter_at_mark (buffer, &end_right, right_mark);
+
+      /* delete the right words and insert the left word there */
+      gtk_text_buffer_delete (buffer, &start_right, &end_right);
+      gtk_text_buffer_insert (buffer, &end_right, word_left, -1);
+      g_free (word_left);
+
+      /* restore the cursor if needed */
+      if (restore_cursor)
+        {
+          /* restore the iter from the left mark (left gravity) */
+          gtk_text_buffer_get_iter_at_mark (buffer, &start_right, left_mark);
+          gtk_text_buffer_place_cursor (buffer, &start_right);
+        }
+
+      /* cleanup the marks */
+      gtk_text_buffer_delete_mark (buffer, left_mark);
+      gtk_text_buffer_delete_mark (buffer, right_mark);
+    }
+}
+
+
+
+void
+mousepad_view_transpose (MousepadView *view)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    sel_start, sel_end;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* begin user action */
+  gtk_text_buffer_begin_user_action (buffer);
+
+  if (view->selection_marks != NULL)
+    {
+      /* transpose a multi selection */
+      mousepad_view_transpose_multi_selection (buffer, view);
+    }
+  else if (gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end))
+    {
+      /* if the selection is not on the same line, include the whole lines */
+      if (gtk_text_iter_get_line (&sel_start) == gtk_text_iter_get_line (&sel_end))
+        {
+          /* reverse selection */
+          mousepad_view_transpose_range (buffer, &sel_start, &sel_end);
+        }
+      else
+        {
+          /* reverse lines */
+          mousepad_view_transpose_lines (buffer, &sel_start, &sel_end);
+        }
+
+      /* restore selection */
+      gtk_text_buffer_select_range (buffer, &sel_end, &sel_start);
+    }
+  else
+    {
+      /* get cursor iter */
+      gtk_text_buffer_get_iter_at_mark (buffer, &sel_start, gtk_text_buffer_get_insert (buffer));
+
+      /* set end iter */
+      sel_end = sel_start;
+
+      if (gtk_text_iter_starts_line (&sel_start))
+        {
+          /* swap this line with the line above */
+          if (gtk_text_iter_backward_line (&sel_end))
+            mousepad_view_transpose_lines (buffer, &sel_start, &sel_end);
+        }
+      else if (gtk_text_iter_ends_line (&sel_start))
+        {
+          /* swap this line with the line below */
+          if (gtk_text_iter_forward_line (&sel_end))
+            mousepad_view_transpose_lines (buffer, &sel_start, &sel_end);
+        }
+      else if (mousepad_util_iter_inside_word (&sel_start))
+        {
+          /* reverse the characters before and after the cursor */
+          if (gtk_text_iter_backward_char (&sel_start) && gtk_text_iter_forward_char (&sel_end))
+            mousepad_view_transpose_range (buffer, &sel_start, &sel_end);
+        }
+      else
+        {
+          /* swap the words left and right of the cursor */
+          mousepad_view_transpose_words (buffer, &sel_start);
+        }
+    }
+
+  /* end user action */
+  gtk_text_buffer_end_user_action (buffer);
+}
+
+
+
+void
+mousepad_view_clipboard_cut (MousepadView *view)
+{
+  GtkClipboard  *clipboard;
+  GtkTextBuffer *buffer;
+  gchar         *string;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+  mousepad_return_if_fail (mousepad_view_get_selection_length (view, NULL) > 0);
+
+  /* get the clipboard */
+  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view), GDK_SELECTION_CLIPBOARD);
+
+  if (view->selection_marks != NULL)
+    {
+      /* get the selection string */
+      string = mousepad_view_selection_string (view);
+
+      /* set the clipboard text */
+      gtk_clipboard_set_text (clipboard, string, -1);
+
+      /* cleanup */
+      g_free (string);
+
+      /* cleanup the vertical selection */
+      mousepad_view_selection_delete_content (view);
+
+      /* destroy selection */
+      mousepad_view_selection_destroy (view);
+    }
+  else
+    {
+      /* get the buffer */
+      buffer = mousepad_view_get_buffer (view);
+
+      /* cut from buffer */
+      gtk_text_buffer_cut_clipboard (buffer, clipboard, gtk_text_view_get_editable (GTK_TEXT_VIEW (view)));
+    }
+
+  /* put cursor on screen */
+  mousepad_view_scroll_to_cursor (view);
+}
+
+
+
+void
+mousepad_view_clipboard_copy (MousepadView *view)
+{
+  GtkClipboard  *clipboard;
+  GtkTextBuffer *buffer;
+  gchar         *string;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+  mousepad_return_if_fail (mousepad_view_get_selection_length (view, NULL) > 0);
+
+  /* get the clipboard */
+  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view), GDK_SELECTION_CLIPBOARD);
+
+  if (view->selection_marks != NULL)
+    {
+      /* get the selection string */
+      string = mousepad_view_selection_string (view);
+
+      /* set the clipboard text */
+      gtk_clipboard_set_text (clipboard, string, -1);
+
+      /* cleanup */
+      g_free (string);
+    }
+  else
+    {
+      /* get the buffer */
+      buffer = mousepad_view_get_buffer (view);
+
+      /* copy from buffer */
+      gtk_text_buffer_copy_clipboard (buffer, clipboard);
+    }
+
+  /* put cursor on screen */
+  mousepad_view_scroll_to_cursor (view);
+}
+
+
+
+void
+mousepad_view_clipboard_paste (MousepadView *view,
+                               const gchar  *string,
+                               gboolean      paste_as_column)
+{
+  GtkClipboard   *clipboard;
+  GtkTextBuffer  *buffer;
+  GtkTextView    *textview = GTK_TEXT_VIEW (view);
+  gchar          *text = NULL;
+  GtkTextMark    *mark;
+  GtkTextIter     iter;
+  GtkTextIter     start_iter, end_iter;
+  GdkRectangle    rect;
+  gchar         **pieces;
+  gint            i, y;
+
+  if (string == NULL)
+    {
+      /* get the clipboard */
+      clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view), GDK_SELECTION_CLIPBOARD);
+
+      /* get the clipboard text */
+      text = gtk_clipboard_wait_for_text (clipboard);
+
+      /* leave when the text is null */
+      if (G_UNLIKELY (text == NULL))
+        return;
+
+      /* set the string */
+      string = text;
+    }
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* begin user action */
+  gtk_text_buffer_begin_user_action (buffer);
+
+  if (paste_as_column)
+    {
+      /* chop the string into pieces */
+      pieces = g_strsplit (string, "\n", -1);
+
+      /* get iter at cursor position */
+      mark = gtk_text_buffer_get_insert (buffer);
+      gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+
+      /* get the iter location */
+      gtk_text_view_get_iter_location (textview, &iter, &rect);
+
+      /* insert the pieces in the buffer */
+      for (i = 0; pieces[i] != NULL; i++)
+        {
+          /* insert the text in the buffer */
+          gtk_text_buffer_insert (buffer, &iter, pieces[i], -1);
+
+          /* break if the next piece is null */
+          if (G_UNLIKELY (pieces[i+1] == NULL))
+            break;
+
+          /* move the iter to the next line */
+          if (!gtk_text_iter_forward_line (&iter))
+            {
+              /* no new line, insert a new line */
+              gtk_text_buffer_insert (buffer, &iter, "\n", 1);
+            }
+          else
+            {
+              /* get the y coordinate for this line */
+              gtk_text_view_get_line_yrange (textview, &iter, &y, NULL);
+
+              /* get the iter at the correct coordinate */
+              gtk_text_view_get_iter_at_location (textview, &iter, rect.x, y);
+            }
+        }
+
+      /* cleanup */
+      g_strfreev (pieces);
+
+      /* set the cursor to the last iter position */
+      gtk_text_buffer_place_cursor (buffer, &iter);
+    }
+  else
+    {
+      /* get selection bounds */
+      gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter);
+
+      /* remove the existing selection if the iters are not equal */
+      if (!gtk_text_iter_equal (&start_iter, &end_iter))
+        gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
+
+      /* insert string */
+      gtk_text_buffer_insert (buffer, &start_iter, string, -1);
+    }
+
+  /* cleanup */
+  g_free (text);
+
+  /* end user action */
+  gtk_text_buffer_end_user_action (buffer);
+
+  /* put cursor on screen */
+  mousepad_view_scroll_to_cursor (view);
+}
+
+
+
+void
+mousepad_view_delete_selection (MousepadView *view)
+{
+  GtkTextBuffer *buffer;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+  mousepad_return_if_fail (mousepad_view_get_selection_length (view, NULL) > 0);
+
+  if (view->selection_marks != NULL)
+    {
+      /* remove the text in our selection */
+      mousepad_view_selection_delete_content (view);
+
+      /* cleanup the vertical selection */
+      mousepad_view_selection_destroy (view);
+    }
+  else
+    {
+      /* get the buffer */
+      buffer = mousepad_view_get_buffer (view);
+
+      /* delete the selection */
+      gtk_text_buffer_delete_selection (buffer, TRUE, gtk_text_view_get_editable (GTK_TEXT_VIEW (view)));
+    }
+
+  /* put cursor on screen */
+  mousepad_view_scroll_to_cursor (view);
+}
+
+
+
+void
+mousepad_view_select_all (MousepadView *view)
+{
+  GtkTextIter    start, end;
+  GtkTextBuffer *buffer;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* cleanup our selection */
+  if (view->selection_marks != NULL)
+    mousepad_view_selection_destroy (view);
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* get the start and end iter */
+  gtk_text_buffer_get_bounds (buffer, &start, &end);
+
+  /* select everything between those iters */
+  gtk_text_buffer_select_range (buffer, &end, &start);
+}
+
+
+
+void
+mousepad_view_change_selection (MousepadView *view)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    start_iter, end_iter;
+  GdkRectangle   rect;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+  mousepad_return_if_fail (mousepad_view_get_selection_length (view, NULL) != 0);
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* freeze notifications */
+  g_object_freeze_notify (G_OBJECT (buffer));
+
+  if (view->selection_marks != NULL)
+    {
+      /* get the first and last iter from the selection */
+      gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, view->selection_marks->data);
+      gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, g_slist_last (view->selection_marks)->data);
+
+      /* sort the iters */
+      gtk_text_iter_order (&start_iter, &end_iter);
+
+      /* destroy the selection */
+      mousepad_view_selection_destroy (view);
+
+      /* select the range */
+      gtk_text_buffer_select_range (buffer, &end_iter, &start_iter);
+    }
+  else if (gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter))
+    {
+      /* set the start coordinates */
+      gtk_text_view_get_iter_location (GTK_TEXT_VIEW (view), &start_iter, &rect);
+      view->selection_start_x = rect.x;
+      view->selection_start_y = rect.y;
+
+      /* set the end coordinates */
+      gtk_text_view_get_iter_location (GTK_TEXT_VIEW (view), &end_iter, &rect);
+      view->selection_end_x = rect.x;
+      view->selection_end_y = rect.y;
+
+      /* drop the normal selection and hide cursor */
+      gtk_text_buffer_place_cursor (buffer, &end_iter);
+      gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
+
+      /* poke selection function to add the marks */
+      mousepad_view_selection_draw (view, TRUE);
+
+      /* reset the coordinates */
+      view->selection_start_x = view->selection_start_y = -1;
+      view->selection_end_x = view->selection_end_y = -1;
+    }
+
+  /* allow notifications again */
+  g_object_thaw_notify (G_OBJECT (buffer));
+}
+
+
+
+void
+mousepad_view_convert_selection_case (MousepadView *view,
+                                      gint          type)
+{
+  gchar         *text;
+  gchar         *converted;
+  GtkTextBuffer *buffer;
+  GtkTextIter    start_iter, end_iter;
+  gint           offset = -1;
+  GSList        *li = NULL;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+  mousepad_return_if_fail (mousepad_view_get_selection_length (view, NULL) > 0);
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* begin a user action */
+  gtk_text_buffer_begin_user_action (buffer);
+
+  if (view->selection_marks == NULL)
+    {
+      /* get selection bounds */
+      gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter);
+
+      /* get string offset */
+      offset = gtk_text_iter_get_offset (&start_iter);
+
+      /* enter the loop without hassle */
+      goto selection_enter;
+    }
+
+  /* replace all selected items */
+  for (li = view->selection_marks; li != NULL; li = li->next)
+    {
+      /* get iters from column selection */
+      gtk_text_buffer_get_iter_at_mark (buffer, &start_iter, li->data);
+      li = li->next;
+      gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, li->data);
+
+      /* label for normal selections */
+      selection_enter:
+
+      /* get the selected string */
+      text = gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, FALSE);
+      if (G_LIKELY (text != NULL))
+        {
+          switch (type)
+            {
+              case LOWERCASE:
+                converted = g_utf8_strdown (text, -1);
+                break;
+
+              case UPPERCASE:
+                converted = g_utf8_strup (text, -1);
+                break;
+
+              case TITLECASE:
+                converted = mousepad_util_utf8_strcapital (text);
+                break;
+
+              case OPPOSITE_CASE:
+                converted = mousepad_util_utf8_stropposite (text);
+                break;
+
+              default:
+                mousepad_assert_not_reached ();
+                break;
+            }
+
+          /* only update the buffer if the string changed */
+          if (G_LIKELY (converted && strcmp (text, converted) != 0))
+            {
+              /* debug check */
+              mousepad_return_if_fail (g_utf8_validate (converted, -1, NULL));
+
+              /* delete old string */
+              gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
+
+              /* insert string */
+              gtk_text_buffer_insert (buffer, &end_iter, converted, -1);
+            }
+
+          /* cleanup */
+          g_free (converted);
+          g_free (text);
+        }
+
+      /* leave for normal selections */
+      if (offset != -1)
+        break;
+    }
+
+  /* restore selection if needed */
+  if (offset != -1)
+    {
+      /* restore start iter */
+      gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, offset);
+
+      /* select range */
+      gtk_text_buffer_select_range (buffer, &end_iter, &start_iter);
+    }
+  else
+    {
+      /* redraw column selection */
+      mousepad_view_selection_draw (view, FALSE);
+    }
+
+  /* end user action */
+  gtk_text_buffer_end_user_action (buffer);
+}
+
+
+
+void
+mousepad_view_convert_spaces_and_tabs (MousepadView *view,
+                                       gint          type)
+{
+  GtkTextBuffer *buffer;
+  GtkTextMark   *mark;
+  GtkTextIter    start_iter, end_iter;
+  GtkTextIter    iter;
+  gint           tab_size;
+  gboolean       in_range = FALSE;
+  gboolean       no_forward;
+  gunichar       c;
+  gint           offset;
+  gint           n_spaces = 0;
+  gint           start_offset = -1;
+  gchar         *string;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* get the tab size */
+  tab_size = gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (view));
+
+  /* get the start and end iter */
+  if (gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter))
+    {
+      /* move to the start of the line when replacing spaces */
+      if (type == SPACES_TO_TABS && !gtk_text_iter_starts_line (&start_iter))
+        gtk_text_iter_set_line_offset (&start_iter, 0);
+
+      /* offset for restoring the selection afterwards */
+      start_offset = gtk_text_iter_get_offset (&start_iter);
+    }
+  else
+    {
+      /* get the document bounds */
+      gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
+    }
+
+  /* leave when the iters are equal (empty docs) */
+  if (gtk_text_iter_equal (&start_iter, &end_iter))
+    return;
+
+  /* begin a user action and free notifications */
+  g_object_freeze_notify (G_OBJECT (buffer));
+  gtk_text_buffer_begin_user_action (buffer);
+
+  /* create a mark to restore the end iter after modifieing the buffer */
+  mark = gtk_text_buffer_create_mark (buffer, NULL, &end_iter, FALSE);
+
+  /* walk the text between the iters */
+  for (;;)
+    {
+      /* get the character */
+      c = gtk_text_iter_get_char (&start_iter);
+
+      /* reset */
+      no_forward = FALSE;
+
+      if (type == SPACES_TO_TABS)
+        {
+          if (c == ' ' || in_range)
+            {
+              if (in_range == FALSE)
+                {
+                  /* set the start iter */
+                  iter = start_iter;
+
+                  /* get the real offset of the start iter */
+                  offset = mousepad_util_get_real_line_offset (&iter, tab_size);
+
+                  /* the number of spaces to inline with the tabs */
+                  n_spaces = tab_size - offset % tab_size;
+                }
+
+              /* check if we can already insert a tab */
+              if (n_spaces == 0)
+                {
+                  /* delete the selected spaces */
+                  gtk_text_buffer_delete (buffer, &iter, &start_iter);
+                  gtk_text_buffer_insert (buffer, &start_iter, "\t", 1);
+
+                  /* restore the end iter */
+                  gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, mark);
+
+                  /* stop being inside a range */
+                  in_range = FALSE;
+
+                  /* no need to forward (iter moved after the insert */
+                  no_forward = TRUE;
+                }
+              else
+                {
+                  /* check whether we're still in a range */
+                  in_range = (c == ' ');
+                }
+
+              /* decrease counter */
+              n_spaces--;
+            }
+
+          /* go to next line if we reached text */
+          if (!g_unichar_isspace (c))
+            {
+              /* continue to the next line if we hit non spaces */
+              gtk_text_iter_forward_line (&start_iter);
+
+              /* make sure there is no valid range anymore */
+              in_range = FALSE;
+
+              /* no need to forward */
+              no_forward = TRUE;
+            }
+        }
+      else if (type == TABS_TO_SPACES && c == '\t')
+        {
+          /* get the real offset of the iter */
+          offset = mousepad_util_get_real_line_offset (&start_iter, tab_size);
+
+          /* the number of spaces to inline with the tabs */
+          n_spaces = tab_size - offset % tab_size;
+
+          /* move one character forwards */
+          iter = start_iter;
+          gtk_text_iter_forward_char (&start_iter);
+
+          /* delete the tab */
+          gtk_text_buffer_delete (buffer, &iter, &start_iter);
+
+          /* create a string with the number of spaces */
+          string = g_strnfill (n_spaces, ' ');
+
+          /* insert the spaces */
+          gtk_text_buffer_insert (buffer, &start_iter, string, n_spaces);
+
+          /* cleanup */
+          g_free (string);
+
+          /* restore the end iter */
+          gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, mark);
+
+          /* iter already moved by the insert */
+          no_forward = TRUE;
+        }
+
+      /* break when the iters are equal (or start is bigger) */
+      if (gtk_text_iter_compare (&start_iter, &end_iter) >= 0)
+        break;
+
+      /* forward the iter */
+      if (G_LIKELY (no_forward == FALSE))
+        gtk_text_iter_forward_char (&start_iter);
+    }
+
+  /* delete our mark */
+  gtk_text_buffer_delete_mark (buffer, mark);
+
+  /* restore the selection if needed */
+  if (start_offset > -1)
+    {
+      /* restore iter and select range */
+      gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset);
+      gtk_text_buffer_select_range (buffer, &end_iter, &start_iter);
+    }
+
+  /* end the user action */
+  gtk_text_buffer_end_user_action (buffer);
+  g_object_thaw_notify (G_OBJECT (buffer));
+}
+
+
+
+void
+mousepad_view_strip_trailing_spaces (MousepadView *view)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    start_iter, end_iter, needle;
+  gint           start, end, i;
+  gunichar       c;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* get range in line numbers */
+  if (gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter))
+    {
+      start = gtk_text_iter_get_line (&start_iter);
+      end = gtk_text_iter_get_line (&end_iter) + 1;
+    }
+  else
+    {
+      start = 0;
+      end = gtk_text_buffer_get_line_count (buffer);
+    }
+
+  /* begin a user action and free notifications */
+  g_object_freeze_notify (G_OBJECT (buffer));
+  gtk_text_buffer_begin_user_action (buffer);
+
+  /* walk all the selected lines */
+  for (i = start; i < end; i++)
+    {
+      /* get the iter at the line */
+      gtk_text_buffer_get_iter_at_line (buffer, &end_iter, i);
+
+      /* continue if the line is empty */
+      if (gtk_text_iter_ends_line (&end_iter))
+        continue;
+
+      /* move the iter to the end of the line */
+      gtk_text_iter_forward_to_line_end (&end_iter);
+
+      /* initialize the iters */
+      needle = start_iter = end_iter;
+
+      /* walk backwards until we hit something else then a space or tab */
+      while (gtk_text_iter_backward_char (&needle))
+        {
+          /* get the character */
+          c = gtk_text_iter_get_char (&needle);
+
+          /* set the start iter of the spaces range or stop searching */
+          if (c == ' ' || c == '\t')
+            start_iter = needle;
+          else
+            break;
+        }
+
+      /* remove the spaces/tabs if the iters are not equal */
+      if (!gtk_text_iter_equal (&start_iter, &end_iter))
+        gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
+    }
+
+  /* end the user action */
+  gtk_text_buffer_end_user_action (buffer);
+  g_object_thaw_notify (G_OBJECT (buffer));
+}
+
+
+
+void
+mousepad_view_move_selection (MousepadView *view,
+                              gint          type)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    start_iter, end_iter, iter;
+  GtkTextMark   *mark;
+  gchar         *text;
+  gboolean       insert_eol;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* begin a user action */
+  gtk_text_buffer_begin_user_action (buffer);
+
+  if (gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter))
+    {
+      if (type == MOVE_LINE_UP)
+        {
+          /* useless action if we're already at the start of the buffer */
+          if (gtk_text_iter_get_line (&start_iter) == 0)
+            goto leave;
+
+          /* set insert point to end of selected line */
+          iter = end_iter;
+          if (!gtk_text_iter_ends_line (&iter))
+            gtk_text_iter_forward_to_line_end (&iter);
+
+          /* make start iter to previous line (can not fail) */
+          gtk_text_iter_backward_line (&start_iter);
+
+          /* move end iter to end of line */
+          end_iter = start_iter;
+          if (!gtk_text_iter_ends_line (&end_iter))
+            gtk_text_iter_forward_to_line_end (&end_iter);
+
+          /* move start iter one line back */
+          insert_eol = !gtk_text_iter_backward_char (&start_iter);
+        }
+      else /* MOVE_LINE_DOWN */
+        {
+          /* useless action if we're already at the end of the buffer */
+          if (gtk_text_iter_get_line (&end_iter) == gtk_text_buffer_get_line_count (buffer) - 1)
+            goto leave;
+
+          /* move insert iter to start of the line */
+          iter = start_iter;
+          if (!gtk_text_iter_starts_line (&iter))
+            gtk_text_iter_set_line_offset (&iter, 0);
+
+          /* move start iter to the start of the line below the selection */
+          start_iter = end_iter;
+          gtk_text_iter_forward_line (&start_iter);
+
+          /* set the end iter */
+          end_iter = start_iter;
+          insert_eol = !gtk_text_iter_forward_line (&end_iter);
+        }
+
+      /* create mark at insert point */
+      mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
+
+      /* copy the line above the selection  */
+      text = gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, FALSE);
+
+      /* delete the new line that we're going to insert later on */
+      if (insert_eol && type == MOVE_LINE_UP)
+        gtk_text_iter_forward_char (&end_iter);
+      else if (insert_eol && type == MOVE_LINE_DOWN)
+        gtk_text_iter_backward_char (&start_iter);
+
+      /* delete */
+      gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
+
+      /* restore mark */
+      gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+
+      /* insert new line if needed */
+      if (insert_eol && type == MOVE_LINE_UP)
+        gtk_text_buffer_insert (buffer, &iter, "\n", 1);
+
+      /* insert text */
+      gtk_text_buffer_insert (buffer, &iter, text, -1);
+
+      /* insert new line if needed */
+      if (insert_eol && type == MOVE_LINE_DOWN)
+        gtk_text_buffer_insert (buffer, &iter, "\n", 1);
+
+      /* cleanup */
+      g_free (text);
+
+      /* sometimes we need to restore the selection (left gravity of the selection marks) */
+      if (type == MOVE_LINE_UP)
+        {
+          /* get selection bounds */
+          gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter);
+
+          /* check if we need to restore the selected range */
+          if (gtk_text_iter_equal (&iter, &end_iter))
+            {
+              /* restore end iter from mark and select the range again */
+              gtk_text_buffer_get_iter_at_mark (buffer, &end_iter, mark);
+              gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
+            }
+        }
+
+      /* delete mark */
+      gtk_text_buffer_delete_mark (buffer, mark);
+    }
+
+  /* labeltje */
+  leave:
+
+  /* end the action */
+  gtk_text_buffer_end_user_action (buffer);
+
+  /* show */
+  mousepad_view_scroll_to_cursor (view);
+}
+
+
+
+void
+mousepad_view_duplicate (MousepadView *view)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    start_iter, end_iter;
+  gboolean       has_selection;
+  gboolean       insert_eol = FALSE;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* get the buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* begin a user action */
+  gtk_text_buffer_begin_user_action (buffer);
+
+  /* get iters */
+  has_selection = gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter);
+
+  /* select entire line */
+  if (has_selection == FALSE)
+    {
+      /* set to the start of the line */
+      if (!gtk_text_iter_starts_line (&start_iter))
+        gtk_text_iter_set_line_offset (&start_iter, 0);
+
+      /* move the other iter to the start of the next line */
+      insert_eol = !gtk_text_iter_forward_line (&end_iter);
+    }
+
+  /* insert a dupplicate of the text before the iter */
+  gtk_text_buffer_insert_range (buffer, &start_iter, &start_iter, &end_iter);
+
+  /* insert a new line if needed */
+  if (insert_eol)
+    gtk_text_buffer_insert (buffer, &start_iter, "\n", 1);
+
+  /* end the action */
+  gtk_text_buffer_end_user_action (buffer);
+}
+
+
+
+void
+mousepad_view_indent (MousepadView *view,
+                      gint          type)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  /* run a forced indent of the line(s) */
+  mousepad_view_indent_selection (view, type == INCREASE_INDENT, TRUE);
+}
+
+
+
+void
+mousepad_view_set_line_numbers (MousepadView *view,
+                                gboolean      line_numbers)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  gtk_source_view_set_show_line_numbers (GTK_SOURCE_VIEW (view), line_numbers);
+}
+
+
+
+void
+mousepad_view_set_auto_indent (MousepadView *view,
+                               gboolean      auto_indent)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  gtk_source_view_set_auto_indent (GTK_SOURCE_VIEW (view), auto_indent);
+}
+
+
+
+void
+mousepad_view_set_tab_size (MousepadView *view,
+                             gint          tab_size)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+  mousepad_return_if_fail (GTK_IS_TEXT_VIEW (view));
+
+  gtk_source_view_set_tab_width (GTK_SOURCE_VIEW (view), tab_size);
+}
+
+
+
+void
+mousepad_view_set_insert_spaces (MousepadView *view,
+                                 gboolean      insert_spaces)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
+
+  gtk_source_view_set_insert_spaces_instead_of_tabs (GTK_SOURCE_VIEW (view), insert_spaces);
+}
+
+
+
+gboolean
+mousepad_view_get_selection_length (MousepadView *view,
+                                    gboolean     *is_column_selection)
+{
+  GtkTextBuffer *buffer;
+  GtkTextIter    sel_start, sel_end;
+  gint           sel_length = 0;
+  gboolean       column_selection;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_VIEW (view), FALSE);
+
+  /* get the text buffer */
+  buffer = mousepad_view_get_buffer (view);
+
+  /* whether this is a column selection */
+  column_selection = view->selection_marks != NULL || view->selection_start_x != -1;
+
+  /* we have a vertical selection */
+  if (column_selection)
+    {
+      /* get the selection count from the selection draw function */
+      sel_length = view->selection_length;
+    }
+  else if (gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end))
+    {
+      /* calculate the selection length from the iter offset (absolute) */
+      sel_length = ABS (gtk_text_iter_get_offset (&sel_end) - gtk_text_iter_get_offset (&sel_start));
+    }
+
+  /* whether this is a column selection */
+  if (is_column_selection)
+    *is_column_selection = column_selection;
+
+  /* return length */
+  return sel_length;
+}
+
+
+
+gboolean
+mousepad_view_get_line_numbers (MousepadView *view)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_VIEW (view), FALSE);
+
+  return gtk_source_view_get_show_line_numbers (GTK_SOURCE_VIEW (view));
+}
+
+
+
+gboolean
+mousepad_view_get_auto_indent (MousepadView *view)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_VIEW (view), FALSE);
+
+  return gtk_source_view_get_auto_indent (GTK_SOURCE_VIEW (view));
+}
+
+
+
+gint
+mousepad_view_get_tab_size (MousepadView *view)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_VIEW (view), -1);
+
+  return gtk_source_view_get_tab_width (GTK_SOURCE_VIEW (view));
+}
+
+
+
+gboolean
+mousepad_view_get_insert_spaces (MousepadView *view)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_VIEW (view), FALSE);
+
+  return gtk_source_view_get_insert_spaces_instead_of_tabs (GTK_SOURCE_VIEW (view));
+}
diff --git a/mousepad/mousepad-view.h b/mousepad/mousepad-view.h
new file mode 100644
index 0000000..109f7f0
--- /dev/null
+++ b/mousepad/mousepad-view.h
@@ -0,0 +1,121 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_VIEW_H__
+#define __MOUSEPAD_VIEW_H__
+
+G_BEGIN_DECLS
+
+#define MOUSEPAD_TYPE_VIEW            (mousepad_view_get_type ())
+#define MOUSEPAD_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_VIEW, MousepadView))
+#define MOUSEPAD_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_VIEW, MousepadViewClass))
+#define MOUSEPAD_IS_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_VIEW))
+#define MOUSEPAD_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPADL_TYPE_VIEW))
+#define MOUSEPAD_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_VIEW, MousepadViewClass))
+
+typedef struct _MousepadViewClass MousepadViewClass;
+typedef struct _MousepadView      MousepadView;
+typedef enum   _MousepadViewFlags MousepadViewFlags;
+
+enum
+{
+  LOWERCASE,
+  UPPERCASE,
+  TITLECASE,
+  OPPOSITE_CASE
+};
+
+enum
+{
+  SPACES_TO_TABS,
+  TABS_TO_SPACES
+};
+
+enum
+{
+  MOVE_LINE_UP,
+  MOVE_LINE_DOWN
+};
+
+enum
+{
+  INCREASE_INDENT,
+  DECREASE_INDENT
+};
+
+GType           mousepad_view_get_type                  (void) G_GNUC_CONST;
+
+void            mousepad_view_scroll_to_cursor          (MousepadView      *view);
+
+void            mousepad_view_transpose                 (MousepadView      *view);
+
+void            mousepad_view_clipboard_cut             (MousepadView      *view);
+
+void            mousepad_view_clipboard_copy            (MousepadView      *view);
+
+void            mousepad_view_clipboard_paste           (MousepadView      *view,
+                                                         const gchar       *string,
+                                                         gboolean           paste_as_column);
+
+void            mousepad_view_delete_selection          (MousepadView      *view);
+
+void            mousepad_view_select_all                (MousepadView      *view);
+
+void            mousepad_view_change_selection          (MousepadView      *view);
+
+void            mousepad_view_convert_selection_case    (MousepadView      *view,
+                                                         gint               type);
+
+void            mousepad_view_convert_spaces_and_tabs   (MousepadView      *view,
+                                                         gint               type);
+
+void            mousepad_view_strip_trailing_spaces     (MousepadView      *view);
+
+void            mousepad_view_move_selection            (MousepadView      *view,
+                                                         gint               type);
+
+void            mousepad_view_duplicate                 (MousepadView      *view);
+
+void            mousepad_view_indent                    (MousepadView      *view,
+                                                         gint               type);
+
+void            mousepad_view_set_line_numbers          (MousepadView      *view,
+                                                         gboolean           line_numbers);
+
+void            mousepad_view_set_auto_indent           (MousepadView      *view,
+                                                         gboolean           auto_indent);
+
+void            mousepad_view_set_tab_size              (MousepadView      *view,
+                                                         gint               tab_size);
+
+void            mousepad_view_set_insert_spaces         (MousepadView      *view,
+                                                         gboolean           insert_spaces);
+
+gint            mousepad_view_get_selection_length      (MousepadView      *view,
+                                                         gboolean          *is_column_selection);
+
+gboolean        mousepad_view_get_line_numbers          (MousepadView      *view);
+
+gboolean        mousepad_view_get_auto_indent           (MousepadView      *view);
+
+gint            mousepad_view_get_tab_size              (MousepadView      *view);
+
+gboolean        mousepad_view_get_insert_spaces         (MousepadView      *view);
+
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_VIEW_H__ */
diff --git a/mousepad/mousepad-window-ui.xml b/mousepad/mousepad-window-ui.xml
new file mode 100644
index 0000000..f960bc6
--- /dev/null
+++ b/mousepad/mousepad-window-ui.xml
@@ -0,0 +1,159 @@
+<ui>
+  <!--
+    This program is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the Free
+    Software Foundation; either version 2 of the License, or (at your option)
+    any later version.
+
+    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 General Public License for
+    more details.
+
+    You should have received a copy of the GNU General Public License along with
+    this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+    Place, Suite 330, Boston, MA  02111-1307  USA
+  -->
+
+  <menubar name="main-menu">
+    <menu action="file-menu">
+      <menuitem action="new" />
+      <menuitem action="new-window" />
+      <menuitem action="template-menu" />
+      <separator />
+      <menuitem action="open" />
+      <menu action="recent-menu">
+        <menuitem action="no-recent-items" />
+        <placeholder name="placeholder-recent-items" />
+        <separator />
+        <menuitem action="clear-recent" />
+      </menu>
+      <separator />
+      <menuitem action="save" />
+      <menuitem action="save-as" />
+      <menuitem action="save-all" />
+      <menuitem action="revert" />
+      <separator />
+      <menuitem action="print" />
+      <separator />
+      <menuitem action="detach" />
+      <separator />
+      <menuitem action="close" />
+      <menuitem action="close-window" />
+    </menu>
+
+    <menu action="edit-menu">
+      <menuitem action="undo" />
+      <menuitem action="redo" />
+      <separator />
+      <menuitem action="cut" />
+      <menuitem action="copy" />
+      <menuitem action="paste" />
+      <menu action="paste-menu">
+        <menuitem action="paste-history" />
+        <menuitem action="paste-column" />
+      </menu>
+      <menuitem action="delete" />
+      <separator />
+      <menuitem action="select-all" />
+      <menuitem action="change-selection" />
+      <separator />
+      <menuitem action="find" />
+      <menuitem action="find-next" />
+      <menuitem action="find-previous" />
+      <menuitem action="replace" />
+    </menu>
+
+    <menu action="view-menu">
+      <menuitem action="font" />
+      <separator />
+      <menu action="color-scheme-menu">
+        <placeholder name="placeholder-color-scheme-items" />
+      </menu>
+      <menuitem action="line-numbers" />
+      <separator />
+      <menuitem action="statusbar" />
+    </menu>
+
+    <menu action="text-menu">
+      <menu action="convert-menu">
+        <menuitem action="lowercase" />
+        <menuitem action="uppercase" />
+        <menuitem action="titlecase" />
+        <menuitem action="opposite-case" />
+        <separator />
+        <menuitem action="tabs-to-spaces" />
+        <menuitem action="spaces-to-tabs" />
+        <separator />
+        <menuitem action="strip-trailing" />
+        <separator />
+        <menuitem action="transpose" />
+      </menu>
+      <menu action="move-menu">
+        <menuitem action="line-up" />
+        <menuitem action="line-down" />
+      </menu>
+      <separator />
+      <menuitem action="duplicate" />
+      <separator />
+      <menuitem action="increase-indent" />
+      <menuitem action="decrease-indent" />
+    </menu>
+
+    <menu action="document-menu">
+      <menuitem action="auto-indent" />
+      <menu action="eol-menu">
+        <menuitem action="unix" />
+        <menuitem action="mac" />
+        <menuitem action="dos" />
+      </menu>
+      <menu action="tab-size-menu">
+        <placeholder name="placeholder-tab-items" />
+        <separator />
+        <menuitem action="insert-spaces" />
+      </menu>
+      <menuitem action="word-wrap" />
+      <separator />
+      <menuitem action="write-bom" />
+      <separator />
+      <menu action="language-menu">
+        <placeholder name="placeholder-language-section-items" />
+      </menu>
+    </menu>
+
+    <menu action="navigation-menu">
+      <menuitem action="back" />
+      <menuitem action="forward" />
+      <separator />
+      <placeholder name="placeholder-file-items" />
+      <separator />
+      <menuitem action="go-to" />
+    </menu>
+
+    <menu action="help-menu">
+      <menuitem action="contents" />
+      <menuitem action="about" />
+    </menu>
+  </menubar>
+
+  <popup action="tab-menu">
+    <menuitem action="save" />
+    <menuitem action="save-as" />
+    <separator />
+    <menuitem action="revert" />
+    <separator />
+    <menuitem action="detach" />
+    <menuitem action="close" />
+  </popup>
+
+  <popup action="textview-menu">
+    <menuitem action="undo" />
+    <menuitem action="redo" />
+    <separator />
+    <menuitem action="cut" />
+    <menuitem action="copy" />
+    <menuitem action="paste" />
+    <separator />
+    <menuitem action="select-all" />
+  </popup>
+</ui>
diff --git a/mousepad/mousepad-window.c b/mousepad/mousepad-window.c
new file mode 100644
index 0000000..3067788
--- /dev/null
+++ b/mousepad/mousepad-window.c
@@ -0,0 +1,5102 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <glib/gstdio.h>
+
+#include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-application.h>
+#include <mousepad/mousepad-marshal.h>
+#include <mousepad/mousepad-document.h>
+#include <mousepad/mousepad-dialogs.h>
+#include <mousepad/mousepad-preferences.h>
+#include <mousepad/mousepad-replace-dialog.h>
+#include <mousepad/mousepad-encoding-dialog.h>
+#include <mousepad/mousepad-search-bar.h>
+#include <mousepad/mousepad-statusbar.h>
+#include <mousepad/mousepad-print.h>
+#include <mousepad/mousepad-window.h>
+#include <mousepad/mousepad-window-ui.h>
+
+
+
+#define PADDING                   (2)
+#define PASTE_HISTORY_MENU_LENGTH (30)
+
+#if GTK_CHECK_VERSION (2,12,0)
+static gconstpointer NOTEBOOK_GROUP = "Mousepad";
+#endif
+
+
+
+enum
+{
+  NEW_WINDOW,
+  NEW_WINDOW_WITH_DOCUMENT,
+  LAST_SIGNAL
+};
+
+
+
+static void              mousepad_window_dispose                      (GObject                *object);
+static void              mousepad_window_finalize                     (GObject                *object);
+static gboolean          mousepad_window_configure_event              (GtkWidget              *widget,
+                                                                       GdkEventConfigure      *event);
+
+/* statusbar tooltips */
+static void              mousepad_window_connect_proxy                (GtkUIManager           *manager,
+                                                                       GtkAction              *action,
+                                                                       GtkWidget              *proxy,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_disconnect_proxy             (GtkUIManager           *manager,
+                                                                       GtkAction              *action,
+                                                                       GtkWidget              *proxy,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_menu_item_selected           (GtkWidget              *menu_item,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_menu_item_deselected         (GtkWidget              *menu_item,
+                                                                       MousepadWindow         *window);
+
+/* save windows geometry */
+static gboolean          mousepad_window_save_geometry_timer          (gpointer                user_data);
+static void              mousepad_window_save_geometry_timer_destroy  (gpointer                user_data);
+
+/* window functions */
+static gboolean          mousepad_window_open_file                    (MousepadWindow         *window,
+                                                                       const gchar            *filename,
+                                                                       MousepadEncoding        encoding);
+static gboolean          mousepad_window_close_document               (MousepadWindow         *window,
+                                                                       MousepadDocument       *document);
+static void              mousepad_window_set_title                    (MousepadWindow         *window);
+static void              mousepad_window_populate_statusbar_popup     (MousepadWindow         *window,
+                                                                       GtkMenu                *menu,
+                                                                       MousepadStatusbar      *statusbar);
+static void              mousepad_window_statusbar_filetype_toggled   (GtkCheckMenuItem       *item,
+                                                                       MousepadWindow         *window);
+
+/* notebook signals */
+static void              mousepad_window_notebook_switch_page         (GtkNotebook            *notebook,
+                                                                       GtkNotebookPage        *page,
+                                                                       guint                   page_num,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_notebook_reordered           (GtkNotebook            *notebook,
+                                                                       GtkWidget              *page,
+                                                                       guint                   page_num,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_notebook_added               (GtkNotebook            *notebook,
+                                                                       GtkWidget              *page,
+                                                                       guint                   page_num,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_notebook_removed             (GtkNotebook            *notebook,
+                                                                       GtkWidget              *page,
+                                                                       guint                   page_num,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_notebook_menu_position       (GtkMenu                *menu,
+                                                                       gint                   *x,
+                                                                       gint                   *y,
+                                                                       gboolean               *push_in,
+                                                                       gpointer                user_data);
+static gboolean          mousepad_window_notebook_button_release_event (GtkNotebook           *notebook,
+                                                                        GdkEventButton        *event,
+                                                                        MousepadWindow        *window);
+static gboolean          mousepad_window_notebook_button_press_event  (GtkNotebook            *notebook,
+                                                                       GdkEventButton         *event,
+                                                                       MousepadWindow         *window);
+#if GTK_CHECK_VERSION (2,12,0)
+static GtkNotebook      *mousepad_window_notebook_create_window       (GtkNotebook            *notebook,
+                                                                       GtkWidget              *page,
+                                                                       gint                    x,
+                                                                       gint                    y,
+                                                                       MousepadWindow         *window);
+#endif
+
+/* document signals */
+static void              mousepad_window_modified_changed             (MousepadWindow         *window);
+static void              mousepad_window_cursor_changed               (MousepadDocument       *document,
+                                                                       gint                    line,
+                                                                       gint                    column,
+                                                                       gint                    selection,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_selection_changed            (MousepadDocument       *document,
+                                                                       gint                    selection,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_overwrite_changed            (MousepadDocument       *document,
+                                                                       gboolean                overwrite,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_language_changed             (MousepadDocument       *document,
+                                                                       GtkSourceLanguage      *language,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_can_undo                     (MousepadWindow         *window,
+                                                                       GParamSpec             *unused,
+                                                                       GObject                *buffer);
+static void              mousepad_window_can_redo                     (MousepadWindow         *window,
+                                                                       GParamSpec             *unused,
+                                                                       GObject                *buffer);
+
+/* menu functions */
+static void              mousepad_window_menu_templates_fill          (MousepadWindow         *window,
+                                                                       GtkWidget              *menu,
+                                                                       const gchar            *path);
+static void              mousepad_window_menu_templates               (GtkWidget              *item,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_menu_tab_sizes               (MousepadWindow         *window);
+static void              mousepad_window_menu_tab_sizes_update        (MousepadWindow         *window);
+static void              mousepad_window_menu_textview_deactivate     (GtkWidget              *menu,
+                                                                       GtkTextView            *textview);
+static void              mousepad_window_menu_textview_popup          (GtkTextView            *textview,
+                                                                       GtkMenu                *old_menu,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_update_actions               (MousepadWindow         *window);
+static gboolean          mousepad_window_update_gomenu_idle           (gpointer                user_data);
+static void              mousepad_window_update_gomenu_idle_destroy   (gpointer                user_data);
+static void              mousepad_window_update_gomenu                (MousepadWindow         *window);
+static void              mousepad_window_menu_color_schemes           (MousepadWindow         *window);
+static void              mousepad_window_menu_languages               (MousepadWindow         *window);
+
+/* recent functions */
+static void              mousepad_window_recent_add                   (MousepadWindow         *window,
+                                                                       MousepadFile           *file);
+static gint              mousepad_window_recent_sort                  (GtkRecentInfo          *a,
+                                                                       GtkRecentInfo          *b);
+static void              mousepad_window_recent_manager_init          (MousepadWindow         *window);
+static gboolean          mousepad_window_recent_menu_idle             (gpointer                user_data);
+static void              mousepad_window_recent_menu_idle_destroy     (gpointer                user_data);
+static void              mousepad_window_recent_menu                  (MousepadWindow         *window);
+static const gchar      *mousepad_window_recent_get_charset           (GtkRecentInfo          *info);
+static void              mousepad_window_recent_clear                 (MousepadWindow         *window);
+
+/* dnd */
+static void              mousepad_window_drag_data_received           (GtkWidget              *widget,
+                                                                       GdkDragContext         *context,
+                                                                       gint                    x,
+                                                                       gint                    y,
+                                                                       GtkSelectionData       *selection_data,
+                                                                       guint                   info,
+                                                                       guint                   drag_time,
+                                                                       MousepadWindow         *window);
+
+/* search bar */
+static void              mousepad_window_hide_search_bar              (MousepadWindow         *window);
+
+/* history clipboard functions */
+static void              mousepad_window_paste_history_add            (MousepadWindow         *window);
+static void              mousepad_window_paste_history_menu_position  (GtkMenu                *menu,
+                                                                       gint                   *x,
+                                                                       gint                   *y,
+                                                                       gboolean               *push_in,
+                                                                       gpointer                user_data);
+static void              mousepad_window_paste_history_activate       (GtkMenuItem            *item,
+                                                                       MousepadWindow         *window);
+static GtkWidget        *mousepad_window_paste_history_menu_item      (const gchar            *text,
+                                                                       const gchar            *mnemonic);
+static GtkWidget        *mousepad_window_paste_history_menu           (MousepadWindow         *window);
+
+/* miscellaneous actions */
+static void              mousepad_window_button_close_tab             (MousepadDocument       *document,
+                                                                       MousepadWindow         *window);
+static gboolean          mousepad_window_delete_event                 (MousepadWindow         *window,
+                                                                       GdkEvent               *event);
+
+/* actions */
+static void              mousepad_window_action_new                   (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_new_window            (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_new_from_template     (GtkMenuItem            *item,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_open                  (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_open_recent           (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_clear_recent          (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static gboolean          mousepad_window_action_save                  (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static gboolean          mousepad_window_action_save_as               (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_save_all              (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_revert                (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_print                 (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_detach                (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_close                 (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_close_window          (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_undo                  (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_redo                  (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_cut                   (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_copy                  (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_paste                 (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_paste_history         (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_paste_column          (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_delete                (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_select_all            (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_change_selection      (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_find                  (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_find_next             (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_find_previous         (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_replace_destroy       (MousepadWindow         *window);
+static void              mousepad_window_action_replace               (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_select_font           (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_color_scheme          (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_line_numbers          (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_statusbar_overwrite   (MousepadWindow         *window,
+                                                                       gboolean                overwrite);
+static void              mousepad_window_action_statusbar             (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_lowercase             (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_uppercase             (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_titlecase             (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_opposite_case         (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_tabs_to_spaces        (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_spaces_to_tabs        (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_strip_trailing_spaces (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_transpose             (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_move_line_up          (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_move_line_down        (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_duplicate             (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_increase_indent       (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_decrease_indent       (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_auto_indent           (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_line_ending           (GtkRadioAction         *action,
+                                                                       GtkRadioAction         *current,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_tab_size              (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_word_wrap             (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_write_bom             (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_language              (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_insert_spaces         (GtkToggleAction        *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_prev_tab              (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_next_tab              (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_go_to_tab             (GtkRadioAction         *action,
+                                                                       GtkNotebook            *notebook);
+static void              mousepad_window_action_go_to_position        (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_contents              (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+static void              mousepad_window_action_about                 (GtkAction              *action,
+                                                                       MousepadWindow         *window);
+
+
+
+struct _MousepadWindowClass
+{
+  GtkWindowClass __parent__;
+};
+
+struct _MousepadWindow
+{
+  GtkWindow __parent__;
+
+  /* mousepad preferences */
+  MousepadPreferences *preferences;
+
+  /* the current active document */
+  MousepadDocument    *active;
+
+  /* closures for the menu callbacks */
+  GClosure            *menu_item_selected_closure;
+  GClosure            *menu_item_deselected_closure;
+
+  /* action group */
+  GtkActionGroup      *action_group;
+
+  /* recent manager */
+  GtkRecentManager    *recent_manager;
+
+  /* UI manager */
+  GtkUIManager        *ui_manager;
+  guint                gomenu_merge_id;
+  guint                recent_merge_id;
+
+  /* main window widgets */
+  GtkWidget           *box;
+  GtkWidget           *notebook;
+  GtkWidget           *search_bar;
+  GtkWidget           *statusbar;
+  GtkWidget           *replace_dialog;
+
+  /* support to remember window geometry */
+  guint                save_geometry_timer_id;
+
+  /* idle update functions for the recent and go menu */
+  guint                update_recent_menu_id;
+  guint                update_go_menu_id;
+};
+
+
+
+static const GtkActionEntry action_entries[] =
+{
+  { "file-menu", NULL, N_("_File"), NULL, NULL, NULL, },
+    { "new", GTK_STOCK_NEW, N_("_New"), "<control>N", N_("Create a new document"), G_CALLBACK (mousepad_window_action_new), },
+    { "new-window", NULL, N_("New _Window"), "<shift><control>N", N_("Create a new document in a new window"), G_CALLBACK (mousepad_window_action_new_window), },
+    { "template-menu", NULL, N_("New From Te_mplate"), NULL, NULL, NULL, },
+    { "open", GTK_STOCK_OPEN, N_("_Open..."), NULL, N_("Open a file"), G_CALLBACK (mousepad_window_action_open), },
+    { "recent-menu", NULL, N_("Op_en Recent"), NULL, NULL, NULL, },
+      { "no-recent-items", NULL, N_("No items found"), NULL, NULL, NULL, },
+      { "clear-recent", GTK_STOCK_CLEAR, N_("Clear _History"), NULL, N_("Clear the recently used files history"), G_CALLBACK (mousepad_window_action_clear_recent), },
+    { "save", GTK_STOCK_SAVE, NULL, "<control>S", N_("Save the current document"), G_CALLBACK (mousepad_window_action_save), },
+    { "save-as", GTK_STOCK_SAVE_AS, N_("Save _As..."), "<shift><control>S", N_("Save current document as another file"), G_CALLBACK (mousepad_window_action_save_as), },
+    { "save-all", NULL, N_("Save A_ll"), NULL, N_("Save all document in this window"), G_CALLBACK (mousepad_window_action_save_all), },
+    { "revert", GTK_STOCK_REVERT_TO_SAVED, N_("Re_vert"), NULL, N_("Revert to the saved version of the file"), G_CALLBACK (mousepad_window_action_revert), },
+    { "print", GTK_STOCK_PRINT, N_("_Print..."), "<control>P", N_("Print the current document"), G_CALLBACK (mousepad_window_action_print), },
+    { "detach", NULL, N_("_Detach Tab"), "<control>D", N_("Move the current document to a new window"), G_CALLBACK (mousepad_window_action_detach), },
+    { "close", GTK_STOCK_CLOSE, N_("Close _Tab"), "<control>W", N_("Close the current document"), G_CALLBACK (mousepad_window_action_close), },
+    { "close-window", GTK_STOCK_QUIT, N_("_Close Window"), "<control>Q", N_("Close this window"), G_CALLBACK (mousepad_window_action_close_window), },
+
+  { "edit-menu", NULL, N_("_Edit"), NULL, NULL, NULL, },
+    { "undo", GTK_STOCK_UNDO, NULL, "<control>Z", N_("Undo the last action"), G_CALLBACK (mousepad_window_action_undo), },
+    { "redo", GTK_STOCK_REDO, NULL, "<control>Y", N_("Redo the last undone action"), G_CALLBACK (mousepad_window_action_redo), },
+    { "cut", GTK_STOCK_CUT, NULL, NULL, N_("Cut the selection"), G_CALLBACK (mousepad_window_action_cut), },
+    { "copy", GTK_STOCK_COPY, NULL, NULL, N_("Copy the selection"), G_CALLBACK (mousepad_window_action_copy), },
+    { "paste", GTK_STOCK_PASTE, NULL, NULL, N_("Paste the clipboard"), G_CALLBACK (mousepad_window_action_paste), },
+    { "paste-menu", NULL, N_("Paste _Special"), NULL, NULL, NULL, },
+      { "paste-history", NULL, N_("Paste from _History"), NULL, N_("Paste from the clipboard history"), G_CALLBACK (mousepad_window_action_paste_history), },
+      { "paste-column", NULL, N_("Paste as _Column"), NULL, N_("Paste the clipboard text into a column"), G_CALLBACK (mousepad_window_action_paste_column), },
+    { "delete", GTK_STOCK_DELETE, NULL, NULL, N_("Delete the current selection"), G_CALLBACK (mousepad_window_action_delete), },
+    { "select-all", GTK_STOCK_SELECT_ALL, NULL, NULL, N_("Select the text in the entire document"), G_CALLBACK (mousepad_window_action_select_all), },
+    { "change-selection", NULL, N_("Change the selection"), NULL, N_("Change a normal selection into a column selection and vice versa"), G_CALLBACK (mousepad_window_action_change_selection), },
+    { "find", GTK_STOCK_FIND, NULL, NULL, N_("Search for text"), G_CALLBACK (mousepad_window_action_find), },
+    { "find-next", NULL, N_("Find _Next"), "F3", N_("Search forwards for the same text"), G_CALLBACK (mousepad_window_action_find_next), },
+    { "find-previous", NULL, N_("Find _Previous"), "<shift>F3", N_("Search backwards for the same text"), G_CALLBACK (mousepad_window_action_find_previous), },
+    { "replace", GTK_STOCK_FIND_AND_REPLACE, N_("Find and Rep_lace..."), NULL, N_("Search for and replace text"), G_CALLBACK (mousepad_window_action_replace), },
+
+  { "view-menu", NULL, N_("_View"), NULL, NULL, NULL, },
+    { "font", GTK_STOCK_SELECT_FONT, N_("Select F_ont..."), NULL, N_("Change the editor font"), G_CALLBACK (mousepad_window_action_select_font), },
+    { "color-scheme-menu", NULL, N_("_Color Scheme"), NULL, NULL, NULL, },
+
+  { "text-menu", NULL, N_("_Text"), NULL, NULL, NULL, },
+    { "convert-menu", NULL, N_("_Convert"), NULL, NULL, NULL, },
+      { "uppercase", NULL, N_("to _Uppercase"), NULL, N_("Change the case of the selection to uppercase"), G_CALLBACK (mousepad_window_action_uppercase), },
+      { "lowercase", NULL, N_("to _Lowercase"), NULL, N_("Change the case of the selection to lowercase"), G_CALLBACK (mousepad_window_action_lowercase), },
+      { "titlecase", NULL, N_("to _Title Case"), NULL, N_("Change the case of the selection to title case"), G_CALLBACK (mousepad_window_action_titlecase), },
+      { "opposite-case", NULL, N_("to _Opposite Case"), NULL, N_("Change the case of the selection opposite case"), G_CALLBACK (mousepad_window_action_opposite_case), },
+      { "tabs-to-spaces", NULL, N_("_Tabs to Spaces"), NULL, N_("Convert all tabs to spaces in the selection or document"), G_CALLBACK (mousepad_window_action_tabs_to_spaces), },
+      { "spaces-to-tabs", NULL, N_("_Spaces to Tabs"), NULL, N_("Convert all the leading spaces to tabs in the selected line(s) or document"), G_CALLBACK (mousepad_window_action_spaces_to_tabs), },
+      { "strip-trailing", NULL, N_("St_rip Trailing Spaces"), NULL, N_("Remove all the trailing spaces from the selected line(s) or document"), G_CALLBACK (mousepad_window_action_strip_trailing_spaces), },
+      { "transpose", NULL, N_("_Transpose"), "<control>T", N_("Reverse the order of something"), G_CALLBACK (mousepad_window_action_transpose), },
+    { "move-menu", NULL, N_("_Move Selection"), NULL, NULL, NULL, },
+      { "line-up", NULL, N_("Line _Up"), NULL, N_("Move the selection one line up"), G_CALLBACK (mousepad_window_action_move_line_up), },
+      { "line-down", NULL, N_("Line _Down"), NULL, N_("Move the selection one line down"), G_CALLBACK (mousepad_window_action_move_line_down), },
+    { "duplicate", NULL, N_("D_uplicate Line / Selection"), NULL, N_("Duplicate the current line or selection"), G_CALLBACK (mousepad_window_action_duplicate), },
+    { "increase-indent", GTK_STOCK_INDENT, N_("_Increase Indent"), NULL, N_("Increase the indentation of the selection or current line"), G_CALLBACK (mousepad_window_action_increase_indent), },
+    { "decrease-indent", GTK_STOCK_UNINDENT, N_("_Decrease Indent"), NULL, N_("Decrease the indentation of the selection or current line"), G_CALLBACK (mousepad_window_action_decrease_indent), },
+
+  { "document-menu", NULL, N_("_Document"), NULL, NULL, NULL, },
+    { "eol-menu", NULL, N_("Line E_nding"), NULL, NULL, NULL, },
+    { "tab-size-menu", NULL, N_("Tab _Size"), NULL, NULL, NULL, },
+    { "language-menu", NULL, N_("_Filetype"), NULL, NULL, NULL, },
+
+  { "navigation-menu", NULL, N_("_Navigation"), NULL, },
+    { "back", GTK_STOCK_GO_BACK, N_("_Previous Tab"), "<control>Page_Up", N_("Select the previous tab"), G_CALLBACK (mousepad_window_action_prev_tab), },
+    { "forward", GTK_STOCK_GO_FORWARD, N_("_Next Tab"), "<control>Page_Down", N_("Select the next tab"), G_CALLBACK (mousepad_window_action_next_tab), },
+    { "go-to", GTK_STOCK_JUMP_TO, N_("_Go to..."), "<control>G", N_("Go to a specific location in the document"), G_CALLBACK (mousepad_window_action_go_to_position), },
+
+  { "help-menu", NULL, N_("_Help"), NULL, },
+    { "contents", GTK_STOCK_HELP, N_ ("_Contents"), "F1", N_("Display the Mousepad user manual"), G_CALLBACK (mousepad_window_action_contents), },
+    { "about", GTK_STOCK_ABOUT, NULL, NULL, N_("About this application"), G_CALLBACK (mousepad_window_action_about), }
+};
+
+static const GtkToggleActionEntry toggle_action_entries[] =
+{
+  { "line-numbers", NULL, N_("Line N_umbers"), NULL, N_("Show line numbers"), G_CALLBACK (mousepad_window_action_line_numbers), FALSE, },
+  { "statusbar", NULL, N_("St_atusbar"), NULL, N_("Change the visibility of the statusbar"), G_CALLBACK (mousepad_window_action_statusbar), FALSE, },
+  { "auto-indent", NULL, N_("_Auto Indent"), NULL, N_("Auto indent a new line"), G_CALLBACK (mousepad_window_action_auto_indent), FALSE, },
+  { "insert-spaces", NULL, N_("Insert _Spaces"), NULL, N_("Insert spaces when the tab button is pressed"), G_CALLBACK (mousepad_window_action_insert_spaces), FALSE, },
+  { "word-wrap", NULL, N_("_Word Wrap"), NULL, N_("Toggle breaking lines in between words"), G_CALLBACK (mousepad_window_action_word_wrap), FALSE, },
+  { "write-bom", NULL, N_("Write Unicode _BOM"), NULL, N_("Store the byte-order mark in the file"), G_CALLBACK (mousepad_window_action_write_bom), FALSE, }
+};
+
+static const GtkRadioActionEntry radio_action_entries[] =
+{
+  { "unix", NULL, N_("Unix (_LF)"), NULL, N_("Set the line ending of the document to Unix (LF)"), MOUSEPAD_EOL_UNIX, },
+  { "mac", NULL, N_("Mac (_CR)"), NULL, N_("Set the line ending of the document to Mac (CR)"), MOUSEPAD_EOL_MAC, },
+  { "dos", NULL, N_("DOS / Windows (C_R LF)"), NULL, N_("Set the line ending of the document to DOS / Windows (CR LF)"), MOUSEPAD_EOL_DOS, }
+};
+
+
+
+/* global variables */
+static guint   window_signals[LAST_SIGNAL];
+static gint    lock_menu_updates = 0;
+static GSList *clipboard_history = NULL;
+static guint   clipboard_history_ref_count = 0;
+
+
+
+G_DEFINE_TYPE (MousepadWindow, mousepad_window, GTK_TYPE_WINDOW);
+
+
+
+GtkWidget *
+mousepad_window_new (void)
+{
+  return g_object_new (MOUSEPAD_TYPE_WINDOW, NULL);
+}
+
+
+
+static void
+mousepad_window_class_init (MousepadWindowClass *klass)
+{
+  GObjectClass   *gobject_class;
+  GtkWidgetClass *gtkwidget_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->dispose = mousepad_window_dispose;
+  gobject_class->finalize = mousepad_window_finalize;
+
+  gtkwidget_class = GTK_WIDGET_CLASS (klass);
+  gtkwidget_class->configure_event = mousepad_window_configure_event;
+
+  window_signals[NEW_WINDOW] =
+    g_signal_new (I_("new-window"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  window_signals[NEW_WINDOW_WITH_DOCUMENT] =
+    g_signal_new (I_("new-window-with-document"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  _mousepad_marshal_VOID__OBJECT_INT_INT,
+                  G_TYPE_NONE, 3,
+                  G_TYPE_OBJECT,
+                  G_TYPE_INT, G_TYPE_INT);
+}
+
+
+
+static void
+mousepad_window_init (MousepadWindow *window)
+{
+  GtkAccelGroup *accel_group;
+  GtkWidget     *menubar;
+  GtkWidget     *label;
+  GtkWidget     *separator;
+  GtkWidget     *ebox;
+  GtkWidget     *item;
+  GtkAction     *action;
+  gint           width, height;
+  gboolean       statusbar_visible;
+
+  /* initialize stuff */
+  window->save_geometry_timer_id = 0;
+  window->update_recent_menu_id = 0;
+  window->update_go_menu_id = 0;
+  window->gomenu_merge_id = 0;
+  window->recent_merge_id = 0;
+  window->search_bar = NULL;
+  window->statusbar = NULL;
+  window->replace_dialog = NULL;
+  window->active = NULL;
+  window->recent_manager = NULL;
+
+  /* setup window */
+  gtk_window_set_icon_name (GTK_WINDOW (window), "accessories-text-editor");
+
+  /* increase clipboard history ref count */
+  clipboard_history_ref_count++;
+
+  /* add the preferences to the window */
+  window->preferences = mousepad_preferences_get ();
+
+  /* signal for handling the window delete event */
+  g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (mousepad_window_delete_event), NULL);
+
+  /* allocate a closure for the menu_item_selected() callback */
+  window->menu_item_selected_closure = g_cclosure_new_object (G_CALLBACK (mousepad_window_menu_item_selected), G_OBJECT (window));
+  g_closure_ref (window->menu_item_selected_closure);
+  g_closure_sink (window->menu_item_selected_closure);
+
+  /* allocate a closure for the menu_item_deselected() callback */
+  window->menu_item_deselected_closure = g_cclosure_new_object (G_CALLBACK (mousepad_window_menu_item_deselected), G_OBJECT (window));
+  g_closure_ref (window->menu_item_deselected_closure);
+  g_closure_sink (window->menu_item_deselected_closure);
+
+  /* read settings from the preferences */
+  g_object_get (G_OBJECT (window->preferences),
+                "window-width", &width,
+                "window-height", &height,
+                "window-statusbar-visible", &statusbar_visible,
+                NULL);
+
+  /* set the default window size */
+  gtk_window_set_default_size (GTK_WINDOW (window), width, height);
+
+  /* the action group for this window */
+  window->action_group = gtk_action_group_new ("MousepadWindow");
+  gtk_action_group_set_translation_domain (window->action_group, GETTEXT_PACKAGE);
+  gtk_action_group_add_actions (window->action_group, action_entries, G_N_ELEMENTS (action_entries), GTK_WIDGET (window));
+  gtk_action_group_add_toggle_actions (window->action_group, toggle_action_entries, G_N_ELEMENTS (toggle_action_entries), GTK_WIDGET (window));
+  gtk_action_group_add_radio_actions (window->action_group, radio_action_entries, G_N_ELEMENTS (radio_action_entries), -1, G_CALLBACK (mousepad_window_action_line_ending), GTK_WIDGET (window));
+
+  /* create the ui manager and connect proxy signals for the statusbar */
+  window->ui_manager = gtk_ui_manager_new ();
+  g_signal_connect (G_OBJECT (window->ui_manager), "connect-proxy", G_CALLBACK (mousepad_window_connect_proxy), window);
+  g_signal_connect (G_OBJECT (window->ui_manager), "disconnect-proxy", G_CALLBACK (mousepad_window_disconnect_proxy), window);
+  gtk_ui_manager_insert_action_group (window->ui_manager, window->action_group, 0);
+  gtk_ui_manager_add_ui_from_string (window->ui_manager, mousepad_window_ui, mousepad_window_ui_length, NULL);
+
+  /* build the templates menu when the item is shown for the first time */
+  /* from here we also trigger the idle build of the recent menu */
+  item = gtk_ui_manager_get_widget (window->ui_manager, "/main-menu/file-menu/template-menu");
+  g_signal_connect (G_OBJECT (item), "map", G_CALLBACK (mousepad_window_menu_templates), window);
+
+  /* add tab size menu */
+  mousepad_window_menu_tab_sizes (window);
+
+  /* add color schemes menu */
+  mousepad_window_menu_color_schemes (window);
+
+  /* add languages/filetypes menu */
+  mousepad_window_menu_languages (window);
+
+  /* set accel group for the window */
+  accel_group = gtk_ui_manager_get_accel_group (window->ui_manager);
+  gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+
+  /* create the main table */
+  window->box = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), window->box);
+  gtk_widget_show (window->box);
+
+  menubar = gtk_ui_manager_get_widget (window->ui_manager, "/main-menu");
+  gtk_box_pack_start (GTK_BOX (window->box), menubar, FALSE, FALSE, 0);
+  gtk_widget_show (menubar);
+
+  /* check if we need to add the root warning */
+  if (G_UNLIKELY (geteuid () == 0))
+    {
+      /* install default settings for the root warning text box */
+      gtk_rc_parse_string ("style\"mousepad-window-root-style\"\n"
+                             "{\n"
+                               "bg[NORMAL]=\"#b4254b\"\n"
+                               "fg[NORMAL]=\"#fefefe\"\n"
+                             "}\n"
+                           "widget\"MousepadWindow.*.root-warning\"style\"mousepad-window-root-style\"\n"
+                           "widget\"MousepadWindow.*.root-warning.GtkLabel\"style\"mousepad-window-root-style\"\n");
+
+      /* add the box for the root warning */
+      ebox = gtk_event_box_new ();
+      gtk_widget_set_name (ebox, "root-warning");
+      gtk_box_pack_start (GTK_BOX (window->box), ebox, FALSE, FALSE, 0);
+      gtk_widget_show (ebox);
+
+      /* add the label with the root warning */
+      label = gtk_label_new (_("Warning, you are using the root account, you may harm your system."));
+      gtk_misc_set_padding (GTK_MISC (label), 6, 3);
+      gtk_container_add (GTK_CONTAINER (ebox), label);
+      gtk_widget_show (label);
+
+      separator = gtk_hseparator_new ();
+      gtk_box_pack_start (GTK_BOX (window->box), separator, FALSE, FALSE, 0);
+      gtk_widget_show (separator);
+    }
+
+  /* create the notebook */
+  window->notebook = g_object_new (GTK_TYPE_NOTEBOOK,
+                                   "homogeneous", FALSE,
+                                   "scrollable", TRUE,
+                                   "show-border", FALSE,
+                                   "show-tabs", FALSE,
+                                   "tab-hborder", 0,
+                                   "tab-vborder", 0,
+                                   NULL);
+
+  /* set the group id */
+#if GTK_CHECK_VERSION (2,12,0)
+  gtk_notebook_set_group (GTK_NOTEBOOK (window->notebook), (gpointer) NOTEBOOK_GROUP);
+#else
+  gtk_notebook_set_group_id (GTK_NOTEBOOK (window->notebook), 1337);
+#endif
+
+  /* connect signals to the notebooks */
+  g_signal_connect (G_OBJECT (window->notebook), "switch-page", G_CALLBACK (mousepad_window_notebook_switch_page), window);
+  g_signal_connect (G_OBJECT (window->notebook), "page-reordered", G_CALLBACK (mousepad_window_notebook_reordered), window);
+  g_signal_connect (G_OBJECT (window->notebook), "page-added", G_CALLBACK (mousepad_window_notebook_added), window);
+  g_signal_connect (G_OBJECT (window->notebook), "page-removed", G_CALLBACK (mousepad_window_notebook_removed), window);
+  g_signal_connect (G_OBJECT (window->notebook), "button-press-event", G_CALLBACK (mousepad_window_notebook_button_press_event), window);
+  g_signal_connect (G_OBJECT (window->notebook), "button-release-event", G_CALLBACK (mousepad_window_notebook_button_release_event), window);
+#if GTK_CHECK_VERSION (2,12,0)
+  g_signal_connect (G_OBJECT (window->notebook), "create-window", G_CALLBACK (mousepad_window_notebook_create_window), window);
+#endif
+
+  /* append and show the notebook */
+  gtk_box_pack_start (GTK_BOX (window->box), window->notebook, TRUE, TRUE, PADDING);
+  gtk_widget_show (window->notebook);
+
+  /* check if we should display the statusbar by default */
+  action = gtk_action_group_get_action (window->action_group, "statusbar");
+  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), statusbar_visible);
+
+  /* allow drops in the window */
+  gtk_drag_dest_set (GTK_WIDGET (window), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, drop_targets, G_N_ELEMENTS (drop_targets), GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  g_signal_connect (G_OBJECT (window), "drag-data-received", G_CALLBACK (mousepad_window_drag_data_received), window);
+
+}
+
+
+
+static void
+mousepad_window_dispose (GObject *object)
+{
+  MousepadWindow *window = MOUSEPAD_WINDOW (object);
+
+  /* disconnect recent manager signal */
+  if (G_LIKELY (window->recent_manager))
+    g_signal_handlers_disconnect_by_func (G_OBJECT (window->recent_manager), mousepad_window_recent_menu, window);
+
+  /* destroy the save geometry timer source */
+  if (G_UNLIKELY (window->save_geometry_timer_id != 0))
+    g_source_remove (window->save_geometry_timer_id);
+
+  (*G_OBJECT_CLASS (mousepad_window_parent_class)->dispose) (object);
+}
+
+
+
+static void
+mousepad_window_finalize (GObject *object)
+{
+  MousepadWindow *window = MOUSEPAD_WINDOW (object);
+
+  /* decrease history clipboard ref count */
+  clipboard_history_ref_count--;
+
+  /* cancel a scheduled recent menu update */
+  if (G_UNLIKELY (window->update_recent_menu_id != 0))
+    g_source_remove (window->update_recent_menu_id);
+
+  /* cancel a scheduled go menu update */
+  if (G_UNLIKELY (window->update_go_menu_id != 0))
+    g_source_remove (window->update_go_menu_id);
+
+  /* drop our references on the menu_item_selected()/menu_item_deselected() closures */
+  g_closure_unref (window->menu_item_deselected_closure);
+  g_closure_unref (window->menu_item_selected_closure);
+
+  /* release the ui manager */
+  g_signal_handlers_disconnect_matched (G_OBJECT (window->ui_manager), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
+  g_object_unref (G_OBJECT (window->ui_manager));
+
+  /* release the action group */
+  g_object_unref (G_OBJECT (window->action_group));
+
+  /* release the preferences reference */
+  g_object_unref (G_OBJECT (window->preferences));
+
+  /* free clipboard history if needed */
+  if (clipboard_history_ref_count == 0 && clipboard_history != NULL)
+    {
+      g_slist_foreach (clipboard_history, (GFunc) g_free, NULL);
+      g_slist_free (clipboard_history);
+    }
+
+  (*G_OBJECT_CLASS (mousepad_window_parent_class)->finalize) (object);
+}
+
+
+
+static gboolean
+mousepad_window_configure_event (GtkWidget         *widget,
+                                 GdkEventConfigure *event)
+{
+  MousepadWindow *window = MOUSEPAD_WINDOW (widget);
+
+  /* check if we have a new dimension here */
+  if (widget->allocation.width != event->width || widget->allocation.height != event->height)
+    {
+      /* drop any previous timer source */
+      if (window->save_geometry_timer_id > 0)
+        g_source_remove (window->save_geometry_timer_id);
+
+      /* check if we should schedule another save timer */
+      if (GTK_WIDGET_VISIBLE (widget))
+        {
+          /* save the geometry one second after the last configure event */
+          window->save_geometry_timer_id = g_timeout_add_full (G_PRIORITY_LOW, 1000, mousepad_window_save_geometry_timer,
+                                                               window, mousepad_window_save_geometry_timer_destroy);
+        }
+    }
+
+  /* let gtk+ handle the configure event */
+  return (*GTK_WIDGET_CLASS (mousepad_window_parent_class)->configure_event) (widget, event);
+}
+
+
+
+/**
+ * Statusbar Tooltip Functions
+ **/
+static void
+mousepad_window_connect_proxy (GtkUIManager   *manager,
+                               GtkAction      *action,
+                               GtkWidget      *proxy,
+                               MousepadWindow *window)
+{
+  mousepad_return_if_fail (GTK_IS_ACTION (action));
+  mousepad_return_if_fail (GTK_IS_MENU_ITEM (proxy));
+  mousepad_return_if_fail (GTK_IS_UI_MANAGER (manager));
+
+  /* we want to get informed when the user hovers a menu item */
+  g_signal_connect_closure (G_OBJECT (proxy), "select", window->menu_item_selected_closure, FALSE);
+  g_signal_connect_closure (G_OBJECT (proxy), "deselect", window->menu_item_deselected_closure, FALSE);
+}
+
+
+
+static void
+mousepad_window_disconnect_proxy (GtkUIManager   *manager,
+                                  GtkAction      *action,
+                                  GtkWidget      *proxy,
+                                  MousepadWindow *window)
+{
+  mousepad_return_if_fail (GTK_IS_ACTION (action));
+  mousepad_return_if_fail (GTK_IS_MENU_ITEM (proxy));
+  mousepad_return_if_fail (GTK_IS_UI_MANAGER (manager));
+
+  /* disconnect the signal from mousepad_window_connect_proxy() */
+  g_signal_handlers_disconnect_matched (G_OBJECT (proxy), G_SIGNAL_MATCH_CLOSURE, 0, 0, window->menu_item_selected_closure, NULL, NULL);
+  g_signal_handlers_disconnect_matched (G_OBJECT (proxy), G_SIGNAL_MATCH_CLOSURE, 0, 0, window->menu_item_deselected_closure, NULL, NULL);
+}
+
+
+
+static void
+mousepad_window_menu_item_selected (GtkWidget      *menu_item,
+                                    MousepadWindow *window)
+{
+  GtkAction *action;
+  gchar     *tooltip;
+  gint       id;
+
+  /* we can only display tooltips if we have a statusbar */
+  if (G_LIKELY (window->statusbar != NULL))
+    {
+      /* get the action from the menu item */
+#if GTK_CHECK_VERSION (2, 16, 0)
+      action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (menu_item));
+#else
+      action = gtk_widget_get_action (menu_item);
+#endif
+      if (G_LIKELY (action))
+        {
+          /* read the tooltip from the action, if there is one */
+          g_object_get (G_OBJECT (action), "tooltip", &tooltip, NULL);
+
+          if (G_LIKELY (tooltip != NULL))
+            {
+              /* show the tooltip */
+              id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "tooltip");
+              gtk_statusbar_push (GTK_STATUSBAR (window->statusbar), id, tooltip);
+
+              /* cleanup */
+              g_free (tooltip);
+            }
+        }
+    }
+}
+
+
+
+static void
+mousepad_window_menu_item_deselected (GtkWidget      *menu_item,
+                                      MousepadWindow *window)
+{
+  gint id;
+
+  /* we can only undisplay tooltips if we have a statusbar */
+  if (G_LIKELY (window->statusbar != NULL))
+    {
+      /* drop the last tooltip from the statusbar */
+      id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "tooltip");
+      gtk_statusbar_pop (GTK_STATUSBAR (window->statusbar), id);
+    }
+}
+
+
+
+/**
+ * Save Geometry Functions
+ **/
+static gboolean
+mousepad_window_save_geometry_timer (gpointer user_data)
+{
+  GdkWindowState   state;
+  MousepadWindow  *window = MOUSEPAD_WINDOW (user_data);
+  gboolean         remember_geometry;
+  gint             width;
+  gint             height;
+
+  GDK_THREADS_ENTER ();
+
+  /* check if we should remember the window geometry */
+  g_object_get (G_OBJECT (window->preferences), "misc-remember-geometry", &remember_geometry, NULL);
+  if (G_LIKELY (remember_geometry))
+    {
+      /* check if the window is still visible */
+      if (GTK_WIDGET_VISIBLE (window))
+        {
+          /* determine the current state of the window */
+          state = gdk_window_get_state (GTK_WIDGET (window)->window);
+
+          /* don't save geometry for maximized or fullscreen windows */
+          if ((state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) == 0)
+            {
+              /* determine the current width/height of the window... */
+              gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+
+              /* ...and remember them as default for new windows */
+              g_object_set (G_OBJECT (window->preferences),
+                            "window-width", width,
+                            "window-height", height, NULL);
+            }
+        }
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+
+
+static void
+mousepad_window_save_geometry_timer_destroy (gpointer user_data)
+{
+  MOUSEPAD_WINDOW (user_data)->save_geometry_timer_id = 0;
+}
+
+
+
+/**
+ * Mousepad Window Functions
+ **/
+static gboolean
+mousepad_window_open_file (MousepadWindow   *window,
+                           const gchar      *filename,
+                           MousepadEncoding  encoding)
+{
+  MousepadDocument *document;
+  GError           *error = NULL;
+  gint              result;
+  gint              npages = 0, i;
+  gint              response;
+  const gchar      *charset;
+  const gchar      *opened_filename;
+  GtkWidget        *dialog;
+  gboolean          encoding_from_recent = FALSE;
+  gchar            *uri;
+  GtkRecentInfo    *info;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), FALSE);
+  mousepad_return_val_if_fail (filename != NULL && *filename != '\0', FALSE);
+
+  /* check if the file is already openend */
+  npages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
+  for (i = 0; i < npages; i++)
+    {
+      document = MOUSEPAD_DOCUMENT (gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), i));
+
+      /* debug check */
+      mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (document), FALSE);
+
+      if (G_LIKELY (document))
+        {
+          /* get the filename */
+          opened_filename = mousepad_file_get_filename (MOUSEPAD_DOCUMENT (document)->file);
+
+          /* see if the file is already opened */
+          if (opened_filename && strcmp (filename, opened_filename) == 0)
+            {
+              /* switch to the tab */
+              gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), i);
+
+              /* and we're done */
+              return TRUE;
+            }
+        }
+    }
+
+  /* new document */
+  document = mousepad_document_new ();
+
+  /* make sure it's not a floating object */
+  g_object_ref_sink (G_OBJECT (document));
+
+  /* set the filename */
+  mousepad_file_set_filename (document->file, filename);
+
+  /* set the passed encoding */
+  mousepad_file_set_encoding (document->file, encoding);
+
+  retry:
+
+  /* lock the undo manager */
+  gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (document->buffer));
+
+  /* read the content into the buffer */
+  result = mousepad_file_open (document->file, NULL, &error);
+
+  /* release the lock */
+  gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (document->buffer));
+
+  switch (result)
+    {
+      case 0:
+        /* add the document to the window */
+        mousepad_window_add (window, document);
+
+        /* insert in the recent history */
+        mousepad_window_recent_add (window, document->file);
+        break;
+
+      case ERROR_CONVERTING_FAILED:
+      case ERROR_NOT_UTF8_VALID:
+        /* clear the error */
+        g_clear_error (&error);
+
+        /* try to lookup the encoding from the recent history */
+        if (encoding_from_recent == FALSE)
+          {
+            /* we only try this once */
+            encoding_from_recent = TRUE;
+
+            /* build uri */
+            uri = g_filename_to_uri (filename, NULL, NULL);
+            if (G_LIKELY (uri))
+              {
+                /* try to lookup the recent item */
+                info = gtk_recent_manager_lookup_item (window->recent_manager, uri, NULL);
+
+                /* cleanup */
+                g_free (uri);
+
+                if (info)
+                  {
+                    /* try to find the encoding */
+                    charset = mousepad_window_recent_get_charset (info);
+
+                    encoding = mousepad_encoding_find (charset);
+
+                    /* set the new encoding */
+                    mousepad_file_set_encoding (document->file, encoding);
+
+                    /* release */
+                    gtk_recent_info_unref (info);
+
+                    /* try to open again with the last used encoding */
+                    if (G_LIKELY (encoding))
+                      goto retry;
+                  }
+              }
+          }
+
+        /* run the encoding dialog */
+        dialog = mousepad_encoding_dialog_new (GTK_WINDOW (window), document->file);
+
+        /* run the dialog */
+        response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+        if (response == GTK_RESPONSE_OK)
+          {
+            /* set the new encoding */
+            encoding = mousepad_encoding_dialog_get_encoding (MOUSEPAD_ENCODING_DIALOG (dialog));
+
+            /* set encoding */
+            mousepad_file_set_encoding (document->file, encoding);
+          }
+
+        /* destroy the dialog */
+        gtk_widget_destroy (dialog);
+
+        /* handle */
+        if (response == GTK_RESPONSE_OK)
+          goto retry;
+
+      default:
+        /* something went wrong, release the document */
+        g_object_unref (G_OBJECT (document));
+
+        if (G_LIKELY (error))
+          {
+            /* show the warning */
+            mousepad_dialogs_show_error (GTK_WINDOW (window), error, _("Failed to open the document"));
+
+            /* cleanup */
+            g_error_free (error);
+          }
+
+        break;
+    }
+
+  return (result == 0);
+}
+
+
+
+gboolean
+mousepad_window_open_files (MousepadWindow  *window,
+                            const gchar     *working_directory,
+                            gchar          **filenames)
+{
+  guint  n;
+  gchar *filename;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), FALSE);
+  mousepad_return_val_if_fail (working_directory != NULL, FALSE);
+  mousepad_return_val_if_fail (filenames != NULL, FALSE);
+  mousepad_return_val_if_fail (*filenames != NULL, FALSE);
+
+  /* block menu updates */
+  lock_menu_updates++;
+
+  /* walk through all the filenames */
+  for (n = 0; filenames[n] != NULL; ++n)
+    {
+      /* check if the filename looks like an uri */
+      if (strncmp (filenames[n], "file:", 5) == 0)
+        {
+          /* convert the uri to an absolute filename */
+          filename = g_filename_from_uri (filenames[n], NULL, NULL);
+        }
+      else if (g_path_is_absolute (filenames[n]) == FALSE)
+        {
+          /* create an absolute file */
+          filename = g_build_filename (working_directory, filenames[n], NULL);
+        }
+      else
+        {
+          /* looks like a valid filename */
+          filename = NULL;
+        }
+
+      /* open a new tab with the file */
+      mousepad_window_open_file (window, filename ? filename : filenames[n], MOUSEPAD_ENCODING_UTF_8);
+
+      /* cleanup */
+      g_free (filename);
+    }
+
+  /* allow menu updates again */
+  lock_menu_updates--;
+
+  /* check if the window contains tabs */
+  if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) == 0)
+    return FALSE;
+
+  /* update the menus */
+  mousepad_window_recent_menu (window);
+  mousepad_window_update_gomenu (window);
+
+  return TRUE;
+}
+
+
+
+void
+mousepad_window_add (MousepadWindow   *window,
+                     MousepadDocument *document)
+{
+  GtkWidget        *label;
+  gint              page;
+  MousepadDocument *prev_active = window->active;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (GTK_IS_NOTEBOOK (window->notebook));
+
+  /* create the tab label */
+  label = mousepad_document_get_tab_label (document);
+
+  /* get active page */
+  page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
+
+  /* insert the page right of the active tab */
+  page = gtk_notebook_insert_page (GTK_NOTEBOOK (window->notebook), GTK_WIDGET (document), label, page + 1);
+
+  /* allow tab reordering and detaching */
+  gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (window->notebook), GTK_WIDGET (document), TRUE);
+  gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (window->notebook), GTK_WIDGET (document), TRUE);
+
+  /* show the document */
+  gtk_widget_show (GTK_WIDGET (document));
+
+  /* don't bother about this when there was no previous active page (startup) */
+  if (G_LIKELY (prev_active != NULL))
+    {
+      /* switch to the new tab */
+      gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page);
+
+      /* destroy the previous tab if it was not modified, untitled and the new tab is not untitled */
+      if (gtk_text_buffer_get_modified (prev_active->buffer) == FALSE
+          && mousepad_file_get_filename (prev_active->file) == NULL
+          && mousepad_file_get_filename (document->file) != NULL)
+        gtk_widget_destroy (GTK_WIDGET (prev_active));
+    }
+
+  /* make sure the textview is focused in the new document */
+  mousepad_document_focus_textview (document);
+}
+
+
+
+static gboolean
+mousepad_window_close_document (MousepadWindow   *window,
+                                MousepadDocument *document)
+{
+  gboolean succeed = FALSE;
+  gint     response;
+  gboolean readonly;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), FALSE);
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (document), FALSE);
+
+  /* check if the document has been modified */
+  if (gtk_text_buffer_get_modified (document->buffer))
+    {
+      /* whether the file is readonly */
+      readonly = mousepad_file_get_read_only (document->file);
+
+      /* run save changes dialog */
+      response = mousepad_dialogs_save_changes (GTK_WINDOW (window), readonly);
+
+      switch (response)
+        {
+          case MOUSEPAD_RESPONSE_DONT_SAVE:
+            /* don't save, only destroy the document */
+            succeed = TRUE;
+            break;
+
+          case MOUSEPAD_RESPONSE_CANCEL:
+            /* do nothing */
+            break;
+
+          case MOUSEPAD_RESPONSE_SAVE:
+            succeed = mousepad_window_action_save (NULL, window);
+            break;
+
+          case MOUSEPAD_RESPONSE_SAVE_AS:
+            succeed = mousepad_window_action_save_as (NULL, window);
+            break;
+        }
+    }
+  else
+    {
+      /* no changes in the document, safe to destroy it */
+      succeed = TRUE;
+    }
+
+  /* destroy the document */
+  if (succeed)
+    gtk_widget_destroy (GTK_WIDGET (document));
+
+  return succeed;
+}
+
+
+
+static void
+mousepad_window_set_title (MousepadWindow *window)
+{
+  gchar            *string;
+  const gchar      *title;
+  gboolean          show_full_path;
+  MousepadDocument *document = window->active;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* whether to show the full path */
+  g_object_get (G_OBJECT (window->preferences), "misc-path-in-title", &show_full_path, NULL);
+
+  /* name we display in the title */
+  if (G_UNLIKELY (show_full_path && mousepad_document_get_filename (document)))
+    title = mousepad_document_get_filename (document);
+  else
+    title = mousepad_document_get_basename (document);
+
+  /* build the title */
+  if (G_UNLIKELY (mousepad_file_get_read_only (document->file)))
+    string = g_strdup_printf ("%s [%s] - %s", title, _("Read Only"), PACKAGE_NAME);
+  else
+    string = g_strdup_printf ("%s%s - %s", gtk_text_buffer_get_modified (document->buffer) ? "*" : "", title, PACKAGE_NAME);
+
+  /* set the window title */
+  gtk_window_set_title (GTK_WINDOW (window), string);
+
+  /* cleanup */
+  g_free (string);
+}
+
+
+
+static void
+mousepad_window_statusbar_filetype_toggled (GtkCheckMenuItem *item,
+                                            MousepadWindow   *window)
+{
+  const gchar              *language_id;
+  GtkSourceLanguage        *language;
+  GtkSourceLanguageManager *manager;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  manager = gtk_source_language_manager_get_default ();
+  language_id = g_object_get_data (G_OBJECT (item), "language_id");
+
+  /* check if None was selected */
+  if (!language_id || g_strcmp0 (language_id, "none") == 0)
+    {
+      gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (window->active->buffer), NULL);
+      gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (window->active->buffer), FALSE);
+      return;
+    }
+
+  /* set to a non-None language */
+  language = gtk_source_language_manager_get_language (manager, language_id);
+  gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (window->active->buffer), TRUE);
+  gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (window->active->buffer), language);
+}
+
+
+
+static void
+mousepad_window_populate_statusbar_popup (MousepadWindow    *window,
+                                          GtkMenu           *menu,
+                                          MousepadStatusbar *statusbar)
+{
+  GSList            *group = NULL;
+  GSList            *sections, *s_iter;
+  GSList            *languages, *l_iter;
+  GtkWidget         *item;
+  GtkWidget         *submenu;
+  GtkSourceLanguage *active;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  active = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (window->active->buffer));
+
+  item = gtk_radio_menu_item_new_with_label (group, _("None"));
+  group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+  g_object_set_data (G_OBJECT (item), "language_id", "none");
+  g_signal_connect (item, "toggled", G_CALLBACK (mousepad_window_statusbar_filetype_toggled), window);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show (item);
+
+  if (!active)
+    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+
+  item = gtk_separator_menu_item_new ();
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show (item);
+
+  sections = mousepad_util_language_sections_get_sorted ();
+
+  for (s_iter = sections ; s_iter != NULL; s_iter = g_slist_next (s_iter))
+    {
+      item = gtk_menu_item_new_with_label (s_iter->data);
+      gtk_widget_show (item);
+      submenu = gtk_menu_new ();
+      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+      gtk_widget_show (submenu);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+      languages = mousepad_util_languages_get_sorted_for_section (s_iter->data);
+      for (l_iter = languages; l_iter != NULL; l_iter = g_slist_next (l_iter))
+        {
+          item = gtk_radio_menu_item_new_with_label (group, gtk_source_language_get_name (l_iter->data));
+          group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+          g_object_set_data (G_OBJECT (item), "language_id", (gpointer) gtk_source_language_get_id (l_iter->data));
+          g_signal_connect (item, "toggled", G_CALLBACK (mousepad_window_statusbar_filetype_toggled), window);
+          gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+          gtk_widget_show (item);
+
+          if (active == l_iter->data)
+            gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+        }
+    }
+}
+
+
+
+/**
+ * Notebook Signal Functions
+ **/
+static void
+mousepad_window_notebook_switch_page (GtkNotebook     *notebook,
+                                      GtkNotebookPage *page,
+                                      guint            page_num,
+                                      MousepadWindow  *window)
+{
+  MousepadDocument  *document;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+
+  /* get the new active document */
+  document = MOUSEPAD_DOCUMENT (gtk_notebook_get_nth_page (notebook, page_num));
+
+  /* only update when really changed */
+  if (G_LIKELY (window->active != document))
+    {
+      /* set new active document */
+      window->active = document;
+
+      /* set the window title */
+      mousepad_window_set_title (window);
+
+      /* update the menu actions */
+      mousepad_window_update_actions (window);
+
+      /* update the statusbar */
+      mousepad_document_send_signals (window->active);
+    }
+}
+
+
+
+static void
+mousepad_window_notebook_reordered (GtkNotebook     *notebook,
+                                    GtkWidget       *page,
+                                    guint            page_num,
+                                    MousepadWindow  *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (page));
+
+  /* update the go menu */
+  mousepad_window_update_gomenu (window);
+}
+
+
+
+static void
+mousepad_window_notebook_added (GtkNotebook     *notebook,
+                                GtkWidget       *page,
+                                guint            page_num,
+                                MousepadWindow  *window)
+{
+  MousepadDocument *document = MOUSEPAD_DOCUMENT (page);
+  gboolean          always_show_tabs;
+  gint              npages;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  /* connect signals to the document for this window */
+  g_signal_connect (G_OBJECT (page), "close-tab", G_CALLBACK (mousepad_window_button_close_tab), window);
+  g_signal_connect (G_OBJECT (page), "cursor-changed", G_CALLBACK (mousepad_window_cursor_changed), window);
+  g_signal_connect (G_OBJECT (page), "selection-changed", G_CALLBACK (mousepad_window_selection_changed), window);
+  g_signal_connect (G_OBJECT (page), "overwrite-changed", G_CALLBACK (mousepad_window_overwrite_changed), window);
+  g_signal_connect (G_OBJECT (page), "language-changed", G_CALLBACK (mousepad_window_language_changed), window);
+  g_signal_connect (G_OBJECT (page), "drag-data-received", G_CALLBACK (mousepad_window_drag_data_received), window);
+  g_signal_connect_swapped (G_OBJECT (document->buffer), "notify::can-undo", G_CALLBACK (mousepad_window_can_undo), window);
+  g_signal_connect_swapped (G_OBJECT (document->buffer), "notify::can-redo", G_CALLBACK (mousepad_window_can_redo), window);
+  g_signal_connect_swapped (G_OBJECT (document->buffer), "modified-changed", G_CALLBACK (mousepad_window_modified_changed), window);
+  g_signal_connect (G_OBJECT (document->textview), "populate-popup", G_CALLBACK (mousepad_window_menu_textview_popup), window);
+
+  /* get the number of pages */
+  npages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
+
+  /* check tabs should always be visible */
+  g_object_get (G_OBJECT (window->preferences), "misc-always-show-tabs", &always_show_tabs, NULL);
+
+  /* change the visibility of the tabs accordingly */
+  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook), always_show_tabs || (npages > 1));
+
+  /* update the go menu */
+  mousepad_window_update_gomenu (window);
+}
+
+
+
+static void
+mousepad_window_notebook_removed (GtkNotebook     *notebook,
+                                  GtkWidget       *page,
+                                  guint            page_num,
+                                  MousepadWindow  *window)
+{
+  gboolean          always_show_tabs;
+  gint              npages;
+  MousepadDocument *document = MOUSEPAD_DOCUMENT (page);
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+
+  /* disconnect the old document signals */
+  g_signal_handlers_disconnect_by_func (G_OBJECT (page), mousepad_window_button_close_tab, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (page), mousepad_window_cursor_changed, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (page), mousepad_window_selection_changed, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (page), mousepad_window_overwrite_changed, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (page), mousepad_window_language_changed, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (page), mousepad_window_drag_data_received, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (document->buffer), mousepad_window_can_undo, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (document->buffer), mousepad_window_can_redo, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (document->buffer), mousepad_window_modified_changed, window);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (document->textview), mousepad_window_menu_textview_popup, window);
+
+  /* unset the go menu item (part of the old window) */
+  mousepad_object_set_data (G_OBJECT (page), "navigation-menu-action", NULL);
+
+  /* get the number of pages in this notebook */
+  npages = gtk_notebook_get_n_pages (notebook);
+
+  /* update the window */
+  if (npages == 0)
+    {
+      /* window contains no tabs, destroy it */
+      gtk_widget_destroy (GTK_WIDGET (window));
+    }
+  else
+    {
+      /* check tabs should always be visible */
+      g_object_get (G_OBJECT (window->preferences), "misc-always-show-tabs", &always_show_tabs, NULL);
+
+      /* change the visibility of the tabs accordingly */
+      gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook), always_show_tabs || (npages > 1));
+
+      /* update the go menu */
+      mousepad_window_update_gomenu (window);
+
+      /* update action entries */
+      mousepad_window_update_actions (window);
+    }
+}
+
+
+
+static void
+mousepad_window_notebook_menu_position (GtkMenu  *menu,
+                                        gint     *x,
+                                        gint     *y,
+                                        gboolean *push_in,
+                                        gpointer  user_data)
+{
+  GtkWidget *widget = GTK_WIDGET (user_data);
+
+  gdk_window_get_origin (widget->window, x, y);
+
+  *x += widget->allocation.x;
+  *y += widget->allocation.y + widget->allocation.height;
+
+  *push_in = TRUE;
+}
+
+
+
+static gboolean
+mousepad_window_notebook_button_press_event (GtkNotebook    *notebook,
+                                             GdkEventButton *event,
+                                             MousepadWindow *window)
+{
+  GtkWidget *page, *label;
+  GtkWidget *menu;
+  guint      page_num = 0;
+  gint       x_root;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), FALSE);
+
+  if (event->type == GDK_BUTTON_PRESS && (event->button == 3 || event->button == 2))
+    {
+      /* walk through the tabs and look for the tab under the cursor */
+      while ((page = gtk_notebook_get_nth_page (notebook, page_num)) != NULL)
+        {
+          label = gtk_notebook_get_tab_label (notebook, page);
+
+          /* get the origin of the label */
+          gdk_window_get_origin (label->window, &x_root, NULL);
+          x_root = x_root + label->allocation.x;
+
+          /* check if the cursor is inside this label */
+          if (event->x_root >= x_root && event->x_root <= (x_root + label->allocation.width))
+            {
+              /* switch to this tab */
+              gtk_notebook_set_current_page (notebook, page_num);
+
+              /* handle the button action */
+              if (event->button == 3)
+                {
+                  /* get the menu */
+                  menu = gtk_ui_manager_get_widget (window->ui_manager, "/tab-menu");
+
+                  /* show it */
+                  gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+                                  mousepad_window_notebook_menu_position, label,
+                                  event->button, event->time);
+                }
+              else if (event->button == 2)
+                {
+                  /* close the document */
+                  mousepad_window_action_close (NULL, window);
+                }
+
+              /* we succeed */
+              return TRUE;
+            }
+
+          /* try the next tab */
+          ++page_num;
+        }
+    }
+  else if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
+    {
+      /* check if the event window is the notebook event window (not a tab) */
+      if (event->window == notebook->event_window)
+        {
+          /* create new document */
+          mousepad_window_action_new (NULL, window);
+
+          /* we succeed */
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+mousepad_window_notebook_button_release_event (GtkNotebook    *notebook,
+                                               GdkEventButton *event,
+                                               MousepadWindow *window)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), FALSE);
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (window->active), FALSE);
+
+  /* focus the active textview */
+  mousepad_document_focus_textview (window->active);
+
+  return FALSE;
+}
+
+
+
+#if GTK_CHECK_VERSION (2,12,0)
+static GtkNotebook *
+mousepad_window_notebook_create_window (GtkNotebook    *notebook,
+                                        GtkWidget      *page,
+                                        gint            x,
+                                        gint            y,
+                                        MousepadWindow *window)
+{
+  MousepadDocument *document;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), NULL);
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (page), NULL);
+
+  /* only create new window when there are more then 2 tabs */
+  if (gtk_notebook_get_n_pages (notebook) >= 2)
+    {
+      /* get the document */
+      document = MOUSEPAD_DOCUMENT (page);
+
+      /* take a reference */
+      g_object_ref (G_OBJECT (document));
+
+      /* remove the document from the active window */
+      gtk_container_remove (GTK_CONTAINER (window->notebook), page);
+
+      /* emit the new window with document signal */
+      g_signal_emit (G_OBJECT (window), window_signals[NEW_WINDOW_WITH_DOCUMENT], 0, document, x, y);
+
+      /* release our reference */
+      g_object_unref (G_OBJECT (document));
+    }
+
+  return NULL;
+}
+#endif
+
+
+
+/**
+ * Document Signals Functions
+ **/
+static void
+mousepad_window_modified_changed (MousepadWindow   *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  mousepad_window_set_title (window);
+}
+
+
+
+static void
+mousepad_window_cursor_changed (MousepadDocument *document,
+                                gint              line,
+                                gint              column,
+                                gint              selection,
+                                MousepadWindow   *window)
+{
+
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  if (window->statusbar)
+    {
+      /* set the new statusbar cursor position and selection length */
+      mousepad_statusbar_set_cursor_position (MOUSEPAD_STATUSBAR (window->statusbar), line, column, selection);
+    }
+}
+
+
+
+static void
+mousepad_window_selection_changed (MousepadDocument *document,
+                                   gint              selection,
+                                   MousepadWindow   *window)
+{
+  GtkAction   *action;
+  guint        i;
+  const gchar *action_names1[] = { "tabs-to-spaces", "spaces-to-tabs", "duplicate", "strip-trailing" };
+  const gchar *action_names2[] = { "line-up", "line-down" };
+  const gchar *action_names3[] = { "cut", "copy", "delete", "lowercase", "uppercase", "titlecase", "opposite-case" };
+
+  /* sensitivity of the change selection action */
+  action = gtk_action_group_get_action (window->action_group, "change-selection");
+  gtk_action_set_sensitive (action, selection != 0);
+
+  /* actions that are unsensitive during a column selection */
+  for (i = 0; i < G_N_ELEMENTS (action_names1); i++)
+    {
+      action = gtk_action_group_get_action (window->action_group, action_names1[i]);
+      gtk_action_set_sensitive (action, selection == 0 || selection == 1);
+    }
+
+  /* action that are only sensitive for normal selections */
+  for (i = 0; i < G_N_ELEMENTS (action_names2); i++)
+    {
+      action = gtk_action_group_get_action (window->action_group, action_names2[i]);
+      gtk_action_set_sensitive (action, selection == 1);
+    }
+
+  /* actions that are sensitive for all selections with content */
+  for (i = 0; i < G_N_ELEMENTS (action_names3); i++)
+    {
+      action = gtk_action_group_get_action (window->action_group, action_names3[i]);
+      gtk_action_set_sensitive (action, selection > 0);
+    }
+}
+
+
+
+static void
+mousepad_window_overwrite_changed (MousepadDocument *document,
+                                   gboolean          overwrite,
+                                   MousepadWindow   *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+  /* set the new overwrite mode in the statusbar */
+  if (window->statusbar)
+    mousepad_statusbar_set_overwrite (MOUSEPAD_STATUSBAR (window->statusbar), overwrite);
+}
+
+
+
+static void
+mousepad_window_language_changed (MousepadDocument  *document,
+                                  GtkSourceLanguage *language,
+                                  MousepadWindow    *window)
+{
+  gchar     *path;
+  GtkWidget *item;
+
+  if (!GTK_IS_SOURCE_LANGUAGE (language))
+    goto set_none;
+
+  path = g_strdup_printf ("/main-menu/document-menu/language-menu/"
+                          "placeholder-language-section-items/"
+                          "language-section-%s/language-%s",
+                          gtk_source_language_get_section (language),
+                          gtk_source_language_get_id (language));
+  item = gtk_ui_manager_get_widget (window->ui_manager, path);
+  g_free (path);
+
+  /* activate the appropriate menu item for the new language */
+  if (GTK_IS_CHECK_MENU_ITEM (item))
+    {
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+      goto set_statusbar;
+    }
+
+set_none:
+  item = gtk_ui_manager_get_widget (window->ui_manager,
+                                        "/main-menu/document-menu/language-menu/language-none");
+  if (GTK_IS_CHECK_MENU_ITEM (item))
+    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+
+set_statusbar:
+  /* set the filetype in the statusbar */
+  if (window->statusbar)
+    mousepad_statusbar_set_language (MOUSEPAD_STATUSBAR (window->statusbar), language);
+}
+
+
+
+static void
+mousepad_window_can_undo (MousepadWindow *window,
+                          GParamSpec     *unused,
+                          GObject        *buffer)
+{
+  GtkAction *action;
+  gboolean   can_undo;
+
+  can_undo = gtk_source_buffer_can_undo (GTK_SOURCE_BUFFER (buffer));
+
+  action = gtk_action_group_get_action (window->action_group, "undo");
+  gtk_action_set_sensitive (action, can_undo);
+}
+
+
+
+static void
+mousepad_window_can_redo (MousepadWindow *window,
+                          GParamSpec     *unused,
+                          GObject        *buffer)
+{
+  GtkAction *action;
+  gboolean   can_redo;
+
+  can_redo = gtk_source_buffer_can_redo (GTK_SOURCE_BUFFER (buffer));
+
+  action = gtk_action_group_get_action (window->action_group, "redo");
+  gtk_action_set_sensitive (action, can_redo);
+}
+
+
+
+/**
+ * Menu Functions
+ **/
+static void
+mousepad_window_menu_templates_fill (MousepadWindow *window,
+                                     GtkWidget      *menu,
+                                     const gchar    *path)
+{
+  GDir        *dir;
+  GSList      *files_list = NULL;
+  GSList      *dirs_list = NULL;
+  GSList      *li;
+  gchar       *absolute_path;
+  gchar       *label, *dot;
+  const gchar *name;
+  GtkWidget   *item, *image, *submenu;
+
+  /* open the directory */
+  dir = g_dir_open (path, 0, NULL);
+
+  /* read the directory */
+  if (G_LIKELY (dir))
+    {
+      /* walk the directory */
+      for (;;)
+        {
+          /* read the filename of the next file */
+          name = g_dir_read_name (dir);
+
+          /* break when we reached the last file */
+          if (G_UNLIKELY (name == NULL))
+            break;
+
+          /* skip hidden files */
+          if (name[0] == '.')
+            continue;
+
+          /* build absolute path */
+          absolute_path = g_build_path (G_DIR_SEPARATOR_S, path, name, NULL);
+
+          /* check if the file is a regular file or directory */
+          if (g_file_test (absolute_path, G_FILE_TEST_IS_DIR))
+            dirs_list = g_slist_insert_sorted (dirs_list, absolute_path, (GCompareFunc) strcmp);
+          else if (g_file_test (absolute_path, G_FILE_TEST_IS_REGULAR))
+            files_list = g_slist_insert_sorted (files_list, absolute_path, (GCompareFunc) strcmp);
+          else
+            g_free (absolute_path);
+        }
+
+      /* close the directory */
+      g_dir_close (dir);
+    }
+
+  /* append the directories */
+  for (li = dirs_list; li != NULL; li = li->next)
+    {
+      /* create a newsub menu for the directory */
+      submenu = gtk_menu_new ();
+      g_object_ref_sink (G_OBJECT (submenu));
+      gtk_menu_set_screen (GTK_MENU (submenu), gtk_widget_get_screen (menu));
+
+      /* fill the menu */
+      mousepad_window_menu_templates_fill (window, submenu, li->data);
+
+      /* check if the sub menu contains items */
+      if (G_LIKELY (GTK_MENU_SHELL (submenu)->children != NULL))
+        {
+          /* create directory label */
+          label = g_filename_display_basename (li->data);
+
+          /* append the menu */
+          item = gtk_image_menu_item_new_with_label (label);
+          gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+          gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+          gtk_widget_show (item);
+
+          /* cleanup */
+          g_free (label);
+
+          /* set menu image */
+          image = gtk_image_new_from_icon_name (GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU);
+          gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+          gtk_widget_show (image);
+        }
+
+      /* cleanup */
+      g_free (li->data);
+      g_object_unref (G_OBJECT (submenu));
+    }
+
+  /* append the files */
+  for (li = files_list; li != NULL; li = li->next)
+    {
+      /* create directory label */
+      label = g_filename_display_basename (li->data);
+
+      /* strip the extension from the label */
+      dot = g_utf8_strrchr (label, -1, '.');
+      if (dot != NULL)
+        *dot = '\0';
+
+      /* create menu item */
+      item = gtk_image_menu_item_new_with_label (label);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      mousepad_object_set_data_full (G_OBJECT (item), "filename", li->data, g_free);
+      g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (mousepad_window_action_new_from_template), window);
+      gtk_widget_show (item);
+
+      /* set menu image */
+      image = gtk_image_new_from_icon_name (GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
+      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+      gtk_widget_show (image);
+
+      /* cleanup */
+      g_free (label);
+    }
+
+  /* cleanup */
+  g_slist_free (dirs_list);
+  g_slist_free (files_list);
+}
+
+
+
+static void
+mousepad_window_menu_templates (GtkWidget      *item,
+                                MousepadWindow *window)
+{
+  GtkWidget   *submenu;
+  const gchar *homedir;
+  gchar       *templates_path;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (GTK_IS_MENU_ITEM (item));
+  mousepad_return_if_fail (gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)) == NULL);
+
+  /* schedule the idle build of the recent menu */
+  mousepad_window_recent_menu (window);
+
+  /* get the home directory */
+  homedir = g_getenv ("HOME");
+  if (G_UNLIKELY (homedir == NULL))
+    homedir = g_get_home_dir ();
+
+  /* get the templates path */
+  templates_path = g_build_filename (homedir, "Templates", NULL);
+
+  /* check if the directory exists */
+  if (g_file_test (templates_path, G_FILE_TEST_IS_DIR))
+    {
+      /* create submenu */
+      submenu = gtk_menu_new ();
+      g_object_ref_sink (G_OBJECT (submenu));
+      gtk_menu_set_screen (GTK_MENU (submenu), gtk_widget_get_screen (item));
+
+      /* fill the menu */
+      mousepad_window_menu_templates_fill (window, submenu, templates_path);
+
+      /* set the submenu if it contains items, else hide the item */
+      if (G_LIKELY (GTK_MENU_SHELL (submenu)->children != NULL))
+        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+      else
+        gtk_widget_hide (item);
+
+      /* release */
+      g_object_unref (G_OBJECT (submenu));
+    }
+  else
+    {
+      /* hide the templates menu item */
+      gtk_widget_hide (item);
+    }
+
+  /* cleanup */
+  g_free (templates_path);
+}
+
+
+
+static void
+mousepad_window_menu_tab_sizes (MousepadWindow *window)
+{
+  GtkRadioAction   *action;
+  GSList           *group = NULL;
+  gint              i, size, merge_id;
+  gchar            *name, *tmp;
+  gchar           **tab_sizes;
+
+  /* lock menu updates */
+  lock_menu_updates++;
+
+  /* get the default tab sizes and active tab size */
+  g_object_get (G_OBJECT (window->preferences), "misc-default-tab-sizes", &tmp, NULL);
+
+  /* get sizes array and free the temp string */
+  tab_sizes = g_strsplit (tmp, ",", -1);
+  g_free (tmp);
+
+  /* create merge id */
+  merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
+
+  /* add the default sizes to the menu */
+  for (i = 0; tab_sizes[i] != NULL; i++)
+    {
+      /* convert the string to a number */
+      size = CLAMP (atoi (tab_sizes[i]), 1, 32);
+
+      /* create action name */
+      name = g_strdup_printf ("tab-size_%d", size);
+
+      action = gtk_radio_action_new (name, name + 8, NULL, NULL, size);
+      gtk_radio_action_set_group (action, group);
+      group = gtk_radio_action_get_group (action);
+      g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (mousepad_window_action_tab_size), window);
+      gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (action), "");
+
+      /* release the action */
+      g_object_unref (G_OBJECT (action));
+
+      /* add the action to the go menu */
+      gtk_ui_manager_add_ui (window->ui_manager, merge_id,
+                             "/main-menu/document-menu/tab-size-menu/placeholder-tab-items",
+                             name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
+
+      /* cleanup */
+      g_free (name);
+    }
+
+  /* cleanup the array */
+  g_strfreev (tab_sizes);
+
+  /* create other action */
+  action = gtk_radio_action_new ("tab-size-other", "", _("Set custom tab size"), NULL, 0);
+  gtk_radio_action_set_group (action, group);
+  g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (mousepad_window_action_tab_size), window);
+  gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (action), "");
+
+  /* release the action */
+  g_object_unref (G_OBJECT (action));
+
+  /* add the action to the go menu */
+  gtk_ui_manager_add_ui (window->ui_manager, merge_id,
+                         "/main-menu/document-menu/tab-size-menu/placeholder-tab-items",
+                         "tab-size-other", "tab-size-other", GTK_UI_MANAGER_MENUITEM, FALSE);
+
+  /* unlock */
+  lock_menu_updates--;
+}
+
+
+
+static void
+mousepad_window_menu_tab_sizes_update (MousepadWindow *window)
+{
+  gint       tab_size;
+  gchar     *name, *label = NULL;
+  GtkAction *action;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* avoid menu actions */
+  lock_menu_updates++;
+
+  /* get tab size of active document */
+  tab_size = mousepad_view_get_tab_size (window->active->textview);
+
+  /* check if there is a default item with this number */
+  name = g_strdup_printf ("tab-size_%d", tab_size);
+  action = gtk_action_group_get_action (window->action_group, name);
+  g_free (name);
+
+  if (action)
+    {
+      /* toggle the default action */
+      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+    }
+  else
+    {
+      /* create suitable label for the other menu */
+      label = g_strdup_printf (_("Ot_her (%d)..."), tab_size);
+    }
+
+  /* get other action */
+  action = gtk_action_group_get_action (window->action_group, "tab-size-other");
+
+  /* toggle other action if needed */
+  if (label)
+    gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+
+  /* set action label */
+  g_object_set (G_OBJECT (action), "label", label ? label : _("Ot_her..."), NULL);
+
+  /* cleanup */
+  g_free (label);
+
+  /* allow menu actions again */
+  lock_menu_updates--;
+}
+
+
+
+static void
+mousepad_window_menu_textview_deactivate (GtkWidget   *menu,
+                                          GtkTextView *textview)
+{
+  mousepad_return_if_fail (GTK_IS_TEXT_VIEW (textview));
+  mousepad_return_if_fail (textview->popup_menu == menu);
+
+  /* disconnect this signal */
+  g_signal_handlers_disconnect_by_func (G_OBJECT (menu), mousepad_window_menu_textview_deactivate, textview);
+
+  /* unset the popup menu since your menu is owned by the ui manager */
+  GTK_TEXT_VIEW (textview)->popup_menu = NULL;
+}
+
+
+
+static void
+mousepad_window_menu_textview_popup (GtkTextView    *textview,
+                                     GtkMenu        *old_menu,
+                                     MousepadWindow *window)
+{
+  GtkWidget *menu;
+
+  mousepad_return_if_fail (GTK_WIDGET (old_menu) == textview->popup_menu);
+  mousepad_return_if_fail (GTK_IS_TEXT_VIEW (textview));
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+  mousepad_return_if_fail (GTK_IS_MENU (textview->popup_menu));
+
+  /* destroy origional menu */
+  gtk_widget_destroy (textview->popup_menu);
+
+  /* get the textview menu */
+  menu = gtk_ui_manager_get_widget (window->ui_manager, "/textview-menu");
+
+  /* connect signal */
+  g_signal_connect (G_OBJECT (menu), "deactivate", G_CALLBACK (mousepad_window_menu_textview_deactivate), textview);
+
+  /* set screen */
+  gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (GTK_WIDGET (textview)));
+
+  /* set ours */
+  textview->popup_menu = menu;
+}
+
+
+
+static void
+mousepad_window_update_actions (MousepadWindow *window)
+{
+  GtkAction          *action;
+  GtkNotebook        *notebook = GTK_NOTEBOOK (window->notebook);
+  MousepadDocument   *document = window->active;
+  gboolean            cycle_tabs;
+  gint                n_pages;
+  gint                page_num;
+  gboolean            active, sensitive;
+  MousepadLineEnding  line_ending;
+  const gchar        *action_name;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* update the actions for the active document */
+  if (G_LIKELY (document))
+    {
+      /* avoid menu actions */
+      lock_menu_updates++;
+
+      /* determine the number of pages and the current page number */
+      n_pages = gtk_notebook_get_n_pages (notebook);
+      page_num = gtk_notebook_page_num (notebook, GTK_WIDGET (document));
+
+      /* whether we cycle tabs */
+      g_object_get (G_OBJECT (window->preferences), "misc-cycle-tabs", &cycle_tabs, NULL);
+
+      /* set the sensitivity of the back and forward buttons in the go menu */
+      action = gtk_action_group_get_action (window->action_group, "back");
+      gtk_action_set_sensitive (action, (cycle_tabs && n_pages > 1) || (page_num > 0));
+
+      action = gtk_action_group_get_action (window->action_group, "forward");
+      gtk_action_set_sensitive (action, (cycle_tabs && n_pages > 1 ) || (page_num < n_pages - 1));
+
+      /* set the reload, detach and save sensitivity */
+      action = gtk_action_group_get_action (window->action_group, "save");
+      gtk_action_set_sensitive (action, !mousepad_file_get_read_only (document->file));
+
+      action = gtk_action_group_get_action (window->action_group, "detach");
+      gtk_action_set_sensitive (action, (n_pages > 1));
+
+      action = gtk_action_group_get_action (window->action_group, "revert");
+      gtk_action_set_sensitive (action, mousepad_file_get_filename (document->file) != NULL);
+
+      /* line ending type */
+      line_ending = mousepad_file_get_line_ending (document->file);
+      if (G_UNLIKELY (line_ending == MOUSEPAD_EOL_MAC))
+        action_name = "mac";
+      else if (G_UNLIKELY (line_ending == MOUSEPAD_EOL_DOS))
+        action_name = "dos";
+      else
+        action_name = "unix";
+
+      /* set the corrent line ending type */
+      action = gtk_action_group_get_action (window->action_group, action_name);
+      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+
+      /* write bom */
+      action = gtk_action_group_get_action (window->action_group, "write-bom");
+      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), mousepad_file_get_write_bom (document->file, &sensitive));
+      gtk_action_set_sensitive (action, sensitive);
+
+      /* toggle the document settings */
+      active = mousepad_document_get_word_wrap (document);
+      action = gtk_action_group_get_action (window->action_group, "word-wrap");
+      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active);
+
+      active = mousepad_view_get_line_numbers (document->textview);
+      action = gtk_action_group_get_action (window->action_group, "line-numbers");
+      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active);
+
+      active = mousepad_view_get_auto_indent (document->textview);
+      action = gtk_action_group_get_action (window->action_group, "auto-indent");
+      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active);
+
+      /* update the tabs size menu */
+      mousepad_window_menu_tab_sizes_update (window);
+
+      active = mousepad_view_get_insert_spaces (document->textview);
+      action = gtk_action_group_get_action (window->action_group, "insert-spaces");
+      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active);
+
+      /* set the sensitivity of the undo and redo actions */
+      mousepad_window_can_undo (window, NULL, G_OBJECT (document->buffer));
+      mousepad_window_can_redo (window, NULL, G_OBJECT (document->buffer));
+
+      /* active this tab in the go menu */
+      action = mousepad_object_get_data (G_OBJECT (document), "navigation-menu-action");
+      if (G_LIKELY (action != NULL))
+        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+
+      /* allow menu actions again */
+      lock_menu_updates--;
+    }
+}
+
+
+
+static gboolean
+mousepad_window_update_gomenu_idle (gpointer user_data)
+{
+  MousepadDocument *document;
+  MousepadWindow   *window;
+  gint              npages;
+  gint              n;
+  gchar             name[32];
+  const gchar      *title;
+  const gchar      *tooltip;
+  gchar             accelerator[7];
+  GtkRadioAction   *radio_action;
+  GSList           *group = NULL;
+  GList            *actions, *iter;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (user_data), FALSE);
+
+  GDK_THREADS_ENTER ();
+
+  /* get the window */
+  window = MOUSEPAD_WINDOW (user_data);
+
+  /* prevent menu updates */
+  lock_menu_updates++;
+
+  /* remove the old merge */
+  if (window->gomenu_merge_id != 0)
+    {
+      gtk_ui_manager_remove_ui (window->ui_manager, window->gomenu_merge_id);
+
+      /* drop all the old recent items from the menu */
+      actions = gtk_action_group_list_actions (window->action_group);
+      for (iter = actions; iter != NULL; iter = g_list_next (iter))
+        {
+          /* match only actions starting with "mousepad-tab-" */
+          if (g_str_has_prefix (gtk_action_get_name (iter->data), "mousepad-tab-"))
+            gtk_action_group_remove_action (window->action_group, iter->data);
+        }
+      g_list_free (actions);
+    }
+
+  /* create a new merge id */
+  window->gomenu_merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
+
+  /* walk through the notebook pages */
+  npages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
+
+  for (n = 0; n < npages; ++n)
+    {
+      document = MOUSEPAD_DOCUMENT (gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), n));
+
+      /* create a new action name */
+      g_snprintf (name, sizeof (name), "mousepad-tab-%d", n);
+
+      /* get the name and file name */
+      title = mousepad_document_get_basename (document);
+      tooltip = mousepad_document_get_filename (document);
+
+      /* create the radio action */
+      radio_action = gtk_radio_action_new (name, title, tooltip, NULL, n);
+      gtk_radio_action_set_group (radio_action, group);
+      group = gtk_radio_action_get_group (radio_action);
+      g_signal_connect (G_OBJECT (radio_action), "activate", G_CALLBACK (mousepad_window_action_go_to_tab), window->notebook);
+
+      /* connect the action to the document to we can easily active it when the user switched from tab */
+      mousepad_object_set_data (G_OBJECT (document), "navigation-menu-action", radio_action);
+
+      if (G_LIKELY (n < 9))
+        {
+          /* create an accelerator and add it to the menu */
+          g_snprintf (accelerator, sizeof (accelerator), "<Alt>%d", n + 1);
+          gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), accelerator);
+        }
+      else
+        /* add a menu item without accelerator */
+        gtk_action_group_add_action (window->action_group, GTK_ACTION (radio_action));
+
+      /* select the active entry */
+      if (gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook)) == n)
+        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (radio_action), TRUE);
+
+      /* release the action */
+      g_object_unref (G_OBJECT (radio_action));
+
+      /* add the action to the go menu */
+      gtk_ui_manager_add_ui (window->ui_manager, window->gomenu_merge_id,
+                             "/main-menu/navigation-menu/placeholder-file-items",
+                             name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
+    }
+
+  /* release our lock */
+  lock_menu_updates--;
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+
+
+static void
+mousepad_window_update_gomenu_idle_destroy (gpointer user_data)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (user_data));
+
+  MOUSEPAD_WINDOW (user_data)->update_go_menu_id = 0;
+}
+
+
+
+static void
+mousepad_window_update_gomenu (MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* leave when we're updating multiple files or there is this an idle function pending */
+  if (lock_menu_updates && window->update_go_menu_id != 0)
+    return;
+
+  /* schedule a go menu update */
+  window->update_go_menu_id = g_idle_add_full (G_PRIORITY_LOW, mousepad_window_update_gomenu_idle,
+                                               window, mousepad_window_update_gomenu_idle_destroy);
+}
+
+
+
+/**
+ * Funtions for managing the recent files
+ **/
+static void
+mousepad_window_recent_add (MousepadWindow *window,
+                            MousepadFile   *file)
+{
+  GtkRecentData  info;
+  gchar         *uri;
+  gchar         *description;
+  const gchar   *charset;
+  static gchar  *groups[] = { (gchar *) PACKAGE_NAME, NULL };
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (file));
+
+  /* get the charset */
+  charset = mousepad_encoding_get_charset (mousepad_file_get_encoding (file));
+
+  /* build description */
+  description = g_strdup_printf ("%s: %s", _("Charset"), charset);
+
+  /* create the recent data */
+  info.display_name = NULL;
+  info.description  = (gchar *) description;
+  info.mime_type    = (gchar *) "text/plain";
+  info.app_name     = (gchar *) PACKAGE_NAME;
+  info.app_exec     = (gchar *) PACKAGE " %u";
+  info.groups       = groups;
+  info.is_private   = FALSE;
+
+  /* create an uri from the filename */
+  uri = mousepad_file_get_uri (file);
+
+  if (G_LIKELY (uri != NULL))
+    {
+      /* make sure the recent manager is initialized */
+      mousepad_window_recent_manager_init (window);
+
+      /* add the new recent info to the recent manager */
+      gtk_recent_manager_add_full (window->recent_manager, uri, &info);
+
+      /* cleanup */
+      g_free (uri);
+    }
+
+  /* cleanup */
+  g_free (description);
+}
+
+
+
+static gint
+mousepad_window_recent_sort (GtkRecentInfo *a,
+                             GtkRecentInfo *b)
+{
+  return (gtk_recent_info_get_modified (a) < gtk_recent_info_get_modified (b));
+}
+
+
+
+static void
+mousepad_window_recent_manager_init (MousepadWindow *window)
+{
+  /* set recent manager if not already done */
+  if (G_UNLIKELY (window->recent_manager == NULL))
+    {
+      /* get the default manager */
+      window->recent_manager = gtk_recent_manager_get_default ();
+
+      /* connect changed signal */
+      g_signal_connect_swapped (G_OBJECT (window->recent_manager), "changed", G_CALLBACK (mousepad_window_recent_menu), window);
+    }
+}
+
+
+
+static gboolean
+mousepad_window_recent_menu_idle (gpointer user_data)
+{
+  MousepadWindow *window = MOUSEPAD_WINDOW (user_data);
+  GList          *items, *li;
+  GList          *filtered = NULL;
+  GtkRecentInfo  *info;
+  const gchar    *uri;
+  const gchar    *display_name;
+  gchar          *tooltip, *label;
+  gchar          *filename, *filename_utf8;
+  GtkAction      *action;
+  gchar           name[32];
+  gint            n, i;
+
+  GDK_THREADS_ENTER ();
+
+  if (window->recent_merge_id != 0)
+    {
+      /* unmerge the ui controls from the previous update */
+      gtk_ui_manager_remove_ui (window->ui_manager, window->recent_merge_id);
+
+      /* drop all the old recent items from the menu */
+      for (i = 1; i < 100 /* arbitrary */; i++)
+        {
+          g_snprintf (name, sizeof (name), "recent-info-%d", i);
+          action = gtk_action_group_get_action (window->action_group, name);
+          if (G_UNLIKELY (action == NULL))
+            break;
+          gtk_action_group_remove_action (window->action_group, action);
+        }
+    }
+
+  /* create a new merge id */
+  window->recent_merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
+
+  /* make sure the recent manager is initialized */
+  mousepad_window_recent_manager_init (window);
+
+  /* get all the items in the manager */
+  items = gtk_recent_manager_get_items (window->recent_manager);
+
+  /* walk through the items in the manager and pick the ones that or in the mousepad group */
+  for (li = items; li != NULL; li = li->next)
+    {
+      /* check if the item is in the Mousepad group */
+      if (!gtk_recent_info_has_group (li->data, PACKAGE_NAME))
+        continue;
+
+      /* insert the the list, sorted by date */
+      filtered = g_list_insert_sorted (filtered, li->data, (GCompareFunc) mousepad_window_recent_sort);
+    }
+
+  /* get the recent menu limit number */
+  g_object_get (G_OBJECT (window->preferences), "misc-recent-menu-items", &n, NULL);
+
+  /* append the items to the menu */
+  for (li = filtered, i = 1; n > 0 && li != NULL; li = li->next)
+    {
+      info = li->data;
+
+      /* get the filename */
+      uri = gtk_recent_info_get_uri (info);
+      filename = g_filename_from_uri (uri, NULL, NULL);
+
+      /* append to the menu if the file exists, else remove it from the history */
+      if (filename && g_file_test (filename, G_FILE_TEST_EXISTS))
+        {
+          /* create the action name */
+          g_snprintf (name, sizeof (name), "recent-info-%d", i);
+
+          /* get the name of the item and escape the underscores */
+          display_name = gtk_recent_info_get_display_name (info);
+          label = mousepad_util_escape_underscores (display_name);
+
+          /* create and utf-8 valid version of the filename */
+          filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+          tooltip = g_strdup_printf (_("Open '%s'"), filename_utf8);
+          g_free (filename_utf8);
+
+          /* create the action */
+          action = gtk_action_new (name, label, tooltip, NULL);
+
+          /* cleanup */
+          g_free (tooltip);
+          g_free (label);
+
+          /* add the info data and connect a menu signal */
+          mousepad_object_set_data_full (G_OBJECT (action), "gtk-recent-info", gtk_recent_info_ref (info), gtk_recent_info_unref);
+          g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (mousepad_window_action_open_recent), window);
+
+          /* add the action to the recent actions group */
+          gtk_action_group_add_action (window->action_group, action);
+
+          /* release the action */
+          g_object_unref (G_OBJECT (action));
+
+          /* add the action to the menu */
+          gtk_ui_manager_add_ui (window->ui_manager, window->recent_merge_id,
+                                 "/main-menu/file-menu/recent-menu/placeholder-recent-items",
+                                 name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
+
+          /* update couters */
+          n--;
+          i++;
+        }
+      else
+        {
+          /* remove the item. don't both the user if this fails */
+          gtk_recent_manager_remove_item (window->recent_manager, uri, NULL);
+        }
+
+      /* cleanup */
+      g_free (filename);
+    }
+
+  /* set the visibility of the 'no items found' action */
+  action = gtk_action_group_get_action (window->action_group, "no-recent-items");
+  gtk_action_set_visible (action, (filtered == NULL));
+  gtk_action_set_sensitive (action, FALSE);
+
+  /* set the sensitivity of the clear button */
+  action = gtk_action_group_get_action (window->action_group, "clear-recent");
+  gtk_action_set_sensitive (action, (filtered != NULL));
+
+  /* cleanup */
+  g_list_foreach (items, (GFunc) gtk_recent_info_unref, NULL);
+  g_list_free (items);
+  g_list_free (filtered);
+
+  GDK_THREADS_LEAVE ();
+
+  /* stop the idle function */
+  return FALSE;
+}
+
+
+
+static void
+mousepad_window_recent_menu_idle_destroy (gpointer user_data)
+{
+  MOUSEPAD_WINDOW (user_data)->update_recent_menu_id = 0;
+}
+
+
+
+static void
+mousepad_window_recent_menu (MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* leave when we're updating multiple files or there is this an idle function pending */
+  if (lock_menu_updates > 0 || window->update_recent_menu_id != 0)
+    return;
+
+  /* schedule a recent menu update */
+  window->update_recent_menu_id = g_idle_add_full (G_PRIORITY_LOW, mousepad_window_recent_menu_idle,
+                                                   window, mousepad_window_recent_menu_idle_destroy);
+}
+
+
+
+static const gchar *
+mousepad_window_recent_get_charset (GtkRecentInfo *info)
+{
+  const gchar *description;
+  const gchar *charset = NULL;
+  guint        offset;
+
+  /* get the description */
+  description = gtk_recent_info_get_description (info);
+  if (G_LIKELY (description))
+    {
+      /* get the offset length: 'Encoding: ' */
+      offset = strlen (_("Charset")) + 2;
+
+      /* check if the encoding string looks valid, if so, set it */
+      if (G_LIKELY (strlen (description) > offset))
+        charset = description + offset;
+    }
+
+  return charset;
+}
+
+
+
+static void
+mousepad_window_recent_clear (MousepadWindow *window)
+{
+  GList         *items, *li;
+  const gchar   *uri;
+  GError        *error = NULL;
+  GtkRecentInfo *info;
+
+  /* make sure the recent manager is initialized */
+  mousepad_window_recent_manager_init (window);
+
+  /* get all the items in the manager */
+  items = gtk_recent_manager_get_items (window->recent_manager);
+
+  /* walk through the items */
+  for (li = items; li != NULL; li = li->next)
+    {
+      info = li->data;
+
+      /* check if the item is in the Mousepad group */
+      if (!gtk_recent_info_has_group (info, PACKAGE_NAME))
+        continue;
+
+      /* get the uri of the recent item */
+      uri = gtk_recent_info_get_uri (info);
+
+      /* try to remove it, if it fails, break the loop to avoid multiple errors */
+      if (G_UNLIKELY (gtk_recent_manager_remove_item (window->recent_manager, uri, &error) == FALSE))
+        break;
+     }
+
+  /* cleanup */
+  g_list_foreach (items, (GFunc) gtk_recent_info_unref, NULL);
+  g_list_free (items);
+
+  /* print a warning is there is one */
+  if (G_UNLIKELY (error != NULL))
+    {
+      mousepad_dialogs_show_error (GTK_WINDOW (window), error, _("Failed to clear the recent history"));
+      g_error_free (error);
+    }
+}
+
+
+
+/**
+ * Drag and drop functions
+ **/
+static void
+mousepad_window_drag_data_received (GtkWidget        *widget,
+                                    GdkDragContext   *context,
+                                    gint              x,
+                                    gint              y,
+                                    GtkSelectionData *selection_data,
+                                    guint             info,
+                                    guint             drag_time,
+                                    MousepadWindow   *window)
+{
+  gchar     **uris;
+  gchar      *working_directory;
+  GtkWidget  *notebook, **document;
+  GtkWidget  *child, *label;
+  gint        i, n_pages;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+
+  /* we only accept text/uri-list drops with format 8 and atleast one byte of data */
+  if (info == TARGET_TEXT_URI_LIST && selection_data->format == 8 && selection_data->length > 0)
+    {
+      /* extract the uris from the data */
+      uris = g_uri_list_extract_uris ((const gchar *)selection_data->data);
+
+      /* get working directory */
+      working_directory = g_get_current_dir ();
+
+      /* open the files */
+      mousepad_window_open_files (window, working_directory, uris);
+
+      /* cleanup */
+      g_free (working_directory);
+      g_strfreev (uris);
+
+      /* finish the drag (copy) */
+      gtk_drag_finish (context, TRUE, FALSE, drag_time);
+    }
+  else if (info == TARGET_GTK_NOTEBOOK_TAB)
+    {
+      /* get the source notebook */
+      notebook = gtk_drag_get_source_widget (context);
+
+      /* get the document that has been dragged */
+      document = (GtkWidget **) selection_data->data;
+
+      /* check */
+      mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (*document));
+
+      /* take a reference on the document before we remove it */
+      g_object_ref (G_OBJECT (*document));
+
+      /* remove the document from the source window */
+      gtk_container_remove (GTK_CONTAINER (notebook), *document);
+
+      /* get the number of pages in the notebook */
+      n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
+
+      /* figure out where to insert the tab in the notebook */
+      for (i = 0; i < n_pages; i++)
+        {
+          /* get the child label */
+          child = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), i);
+          label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (window->notebook), child);
+
+          /* break if we have a matching drop position */
+          if (x < (label->allocation.x + label->allocation.width / 2))
+            break;
+        }
+
+      /* add the document to the new window */
+      mousepad_window_add (window, MOUSEPAD_DOCUMENT (*document));
+
+      /* move the tab to the correct position */
+      gtk_notebook_reorder_child (GTK_NOTEBOOK (window->notebook), *document, i);
+
+      /* release our reference on the document */
+      g_object_unref (G_OBJECT (*document));
+
+      /* finish the drag (move) */
+      gtk_drag_finish (context, TRUE, TRUE, drag_time);
+    }
+}
+
+
+
+/**
+ * Find and replace
+ **/
+static gint
+mousepad_window_search (MousepadWindow      *window,
+                        MousepadSearchFlags  flags,
+                        const gchar         *string,
+                        const gchar         *replacement)
+{
+  gint       nmatches = 0;
+  gint       npages, i;
+  GtkWidget *document;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), -1);
+
+  if (flags & MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT)
+    {
+      /* highlight all the matches */
+      nmatches = mousepad_util_highlight (window->active->buffer, window->active->tag, string, flags);
+    }
+  else if (flags & MOUSEPAD_SEARCH_FLAGS_ALL_DOCUMENTS)
+    {
+      /* get the number of documents in this window */
+      npages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
+
+      /* walk the pages */
+      for (i = 0; i < npages; i++)
+        {
+          /* get the document */
+          document = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), i);
+
+          /* replace the matches in the document */
+          nmatches += mousepad_util_search (MOUSEPAD_DOCUMENT (document)->buffer, string, replacement, flags);
+        }
+    }
+  else if (window->active != NULL)
+    {
+      /* search or replace in the active document */
+      nmatches = mousepad_util_search (window->active->buffer, string, replacement, flags);
+
+      /* make sure the selection is visible */
+      if (flags & (MOUSEPAD_SEARCH_FLAGS_ACTION_SELECT | MOUSEPAD_SEARCH_FLAGS_ACTION_REPLACE) && nmatches > 0)
+        mousepad_view_scroll_to_cursor (window->active->textview);
+    }
+  else
+    {
+      /* should never be reaches */
+      mousepad_assert_not_reached ();
+    }
+
+  return nmatches;
+}
+
+
+
+/**
+ * Search Bar
+ **/
+static void
+mousepad_window_hide_search_bar (MousepadWindow *window)
+{
+  MousepadSearchFlags flags;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+  mousepad_return_if_fail (MOUSEPAD_IS_SEARCH_BAR (window->search_bar));
+
+  /* setup flags */
+  flags = MOUSEPAD_SEARCH_FLAGS_ACTION_HIGHTLIGHT
+          | MOUSEPAD_SEARCH_FLAGS_ACTION_CLEANUP;
+
+  /* remove the highlight */
+  mousepad_window_search (window, flags, NULL, NULL);
+
+  /* hide the search bar */
+  gtk_widget_hide (window->search_bar);
+
+  /* focus the active document's text view */
+  mousepad_document_focus_textview (window->active);
+}
+
+
+
+/**
+ * Paste from History
+ **/
+static void
+mousepad_window_paste_history_add (MousepadWindow *window)
+{
+  GtkClipboard *clipboard;
+  gchar        *text;
+  GSList       *li;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* get the current clipboard text */
+  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
+  text = gtk_clipboard_wait_for_text (clipboard);
+
+  /* leave when there is no text */
+  if (G_UNLIKELY (text == NULL))
+    return;
+
+  /* check if the item is already in the history */
+  for (li = clipboard_history; li != NULL; li = li->next)
+    if (strcmp (li->data, text) == 0)
+      break;
+
+  /* append the item or remove it */
+  if (G_LIKELY (li == NULL))
+    {
+      /* add to the list */
+      clipboard_history = g_slist_prepend (clipboard_history, text);
+
+      /* get the 10th item from the list and remove it if it exists */
+      li = g_slist_nth (clipboard_history, 10);
+      if (li != NULL)
+        {
+          /* cleanup */
+          g_free (li->data);
+          clipboard_history = g_slist_delete_link (clipboard_history, li);
+        }
+    }
+  else
+    {
+      /* already in the history, remove it */
+      g_free (text);
+    }
+}
+
+
+
+static void
+mousepad_window_paste_history_menu_position (GtkMenu  *menu,
+                                             gint     *x,
+                                             gint     *y,
+                                             gboolean *push_in,
+                                             gpointer  user_data)
+{
+  MousepadWindow   *window = MOUSEPAD_WINDOW (user_data);
+  MousepadDocument *document = window->active;
+  GtkTextIter       iter;
+  GtkTextMark      *mark;
+  GdkRectangle      location;
+  gint              iter_x, iter_y;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (GTK_IS_TEXT_VIEW (document->textview));
+  mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (document->buffer));
+
+  /* get the root coordinates of the texview widget */
+  gdk_window_get_origin (gtk_text_view_get_window (GTK_TEXT_VIEW (document->textview), GTK_TEXT_WINDOW_TEXT), x, y);
+
+  /* get the cursor iter */
+  mark = gtk_text_buffer_get_insert (document->buffer);
+  gtk_text_buffer_get_iter_at_mark (document->buffer, &iter, mark);
+
+  /* get iter location */
+  gtk_text_view_get_iter_location (GTK_TEXT_VIEW (document->textview), &iter, &location);
+
+  /* convert to textview coordinates */
+  gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (document->textview), GTK_TEXT_WINDOW_TEXT,
+                                         location.x, location.y, &iter_x, &iter_y);
+
+  /* add the iter coordinates to the menu popup position */
+  *x += iter_x;
+  *y += iter_y + location.height;
+}
+
+
+
+static void
+mousepad_window_paste_history_activate (GtkMenuItem    *item,
+                                        MousepadWindow *window)
+{
+  const gchar *text;
+
+  mousepad_return_if_fail (GTK_IS_MENU_ITEM (item));
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+  mousepad_return_if_fail (MOUSEPAD_IS_VIEW (window->active->textview));
+
+  /* get the menu item text */
+  text = mousepad_object_get_data (G_OBJECT (item), "history-pointer");
+
+  /* paste the text */
+  if (G_LIKELY (text))
+    mousepad_view_clipboard_paste (window->active->textview, text, FALSE);
+}
+
+
+
+static GtkWidget *
+mousepad_window_paste_history_menu_item (const gchar *text,
+                                         const gchar *mnemonic)
+{
+  GtkWidget   *item;
+  GtkWidget   *label;
+  GtkWidget   *hbox;
+  const gchar *s;
+  gchar       *label_str;
+  GString     *string;
+
+  /* create new label string */
+  string = g_string_sized_new (PASTE_HISTORY_MENU_LENGTH);
+
+  /* get the first 30 chars of the clipboard text */
+  if (g_utf8_strlen (text, -1) > PASTE_HISTORY_MENU_LENGTH)
+    {
+      /* append the first 30 chars */
+      s = g_utf8_offset_to_pointer (text, PASTE_HISTORY_MENU_LENGTH);
+      string = g_string_append_len (string, text, s - text);
+
+      /* make it look like a ellipsized string */
+      string = g_string_append (string, "...");
+    }
+  else
+    {
+      /* append the entire string */
+      string = g_string_append (string, text);
+    }
+
+  /* get the string */
+  label_str = g_string_free (string, FALSE);
+
+  /* replace tab and new lines with spaces */
+  label_str = g_strdelimit (label_str, "\n\t\r", ' ');
+
+  /* create a new item */
+  item = gtk_menu_item_new ();
+
+  /* create a hbox */
+  hbox = gtk_hbox_new (FALSE, 14);
+  gtk_container_add (GTK_CONTAINER (item), hbox);
+  gtk_widget_show (hbox);
+
+  /* create the clipboard label */
+  label = gtk_label_new (label_str);
+  gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+
+  /* create the mnemonic label */
+  label = gtk_label_new_with_mnemonic (mnemonic);
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), item);
+  gtk_widget_show (label);
+
+  /* cleanup */
+  g_free (label_str);
+
+  return item;
+}
+
+
+
+static GtkWidget *
+mousepad_window_paste_history_menu (MousepadWindow *window)
+{
+  GSList       *li;
+  gchar        *text;
+  gpointer      list_data = NULL;
+  GtkWidget    *item;
+  GtkWidget    *menu;
+  GtkClipboard *clipboard;
+  gchar         mnemonic[4];
+  gint          n;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), NULL);
+
+  /* create new menu and set the screen */
+  menu = gtk_menu_new ();
+  g_object_ref_sink (G_OBJECT (menu));
+  g_signal_connect (G_OBJECT (menu), "deactivate", G_CALLBACK (g_object_unref), NULL);
+  gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (GTK_WIDGET (window)));
+
+  /* get the current clipboard text */
+  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
+  text = gtk_clipboard_wait_for_text (clipboard);
+
+  /* append the history items */
+  for (li = clipboard_history, n = 1; li != NULL; li = li->next)
+    {
+      /* skip the active clipboard item */
+      if (G_UNLIKELY (list_data == NULL && text && strcmp (li->data, text) == 0))
+        {
+          /* store the pointer so we can attach it at the end of the menu */
+          list_data = li->data;
+        }
+      else
+        {
+          /* create mnemonic string */
+          g_snprintf (mnemonic, sizeof (mnemonic), "_%d", n++);
+
+          /* create menu item */
+          item = mousepad_window_paste_history_menu_item (li->data, mnemonic);
+          mousepad_object_set_data (G_OBJECT (item), "history-pointer", li->data);
+          gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+          g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (mousepad_window_paste_history_activate), window);
+          gtk_widget_show (item);
+        }
+    }
+
+  /* cleanup */
+  g_free (text);
+
+  if (list_data != NULL)
+    {
+      /* add separator between history and active menu items */
+      if (GTK_MENU_SHELL (menu)->children != NULL)
+        {
+          item = gtk_separator_menu_item_new ();
+          gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+          gtk_widget_show (item);
+        }
+
+      /* create menu item for current clipboard text */
+      item = mousepad_window_paste_history_menu_item (list_data, "_0");
+      mousepad_object_set_data (G_OBJECT (item), "history-pointer", list_data);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (mousepad_window_paste_history_activate), window);
+      gtk_widget_show (item);
+    }
+  else if (GTK_MENU_SHELL (menu)->children == NULL)
+    {
+      /* create an item to inform the user */
+      item = gtk_menu_item_new_with_label (_("No clipboard data"));
+      gtk_widget_set_sensitive (item, FALSE);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+    }
+
+  return menu;
+}
+
+
+
+/**
+ * Miscellaneous Actions
+ **/
+static void
+mousepad_window_button_close_tab (MousepadDocument *document,
+                                  MousepadWindow   *window)
+{
+  gint page_num;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* switch to the tab we're going to close */
+  page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook), GTK_WIDGET (document));
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page_num);
+
+  /* close the document */
+  mousepad_window_close_document (window, document);
+}
+
+
+
+static gboolean
+mousepad_window_delete_event (MousepadWindow *window,
+                              GdkEvent       *event)
+{
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), FALSE);
+
+  /* try to close the window */
+  mousepad_window_action_close_window (NULL, window);
+
+  /* we will close the window when all the tabs are closed */
+  return TRUE;
+}
+
+
+
+static void
+mousepad_window_menu_color_schemes (MousepadWindow *window)
+{
+  GtkRadioAction       *action;
+  GSList               *group = NULL, *schemes, *iter;
+  gint                  merge_id;
+  gchar                *name, *selected_color_scheme = NULL;
+
+  /* lock menu updates */
+  lock_menu_updates++;
+
+  /* get the previously saved colour scheme name */
+  g_object_get (window->preferences, "view-color-scheme", &selected_color_scheme, NULL);
+
+  /* get list of schemes */
+  schemes = mousepad_util_color_schemes_get_sorted ();
+
+  /* create merge id */
+  merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
+
+  /* create a "none" action */
+  action = gtk_radio_action_new ("color-scheme-none",
+                                 _("None"),
+                                 _("Turn off color schemes"),
+                                 NULL,
+                                 g_str_hash ("none"));
+  gtk_radio_action_set_group (action, group);
+  group = gtk_radio_action_get_group (action);
+  g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (mousepad_window_action_color_scheme), window);
+  gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (action), "");
+
+  /* release the action */
+  g_object_unref (G_OBJECT (action));
+
+  /* add the action to the go menu */
+  gtk_ui_manager_add_ui (window->ui_manager, merge_id,
+                         "/main-menu/view-menu/color-scheme-menu/placeholder-color-scheme-items",
+                         "color-scheme-none", "color-scheme-none", GTK_UI_MANAGER_MENUITEM, FALSE);
+
+  /* add a separator */
+  gtk_ui_manager_add_ui (window->ui_manager, merge_id,
+                         "/main-menu/view-menu/color-scheme-menu/placeholder-color-scheme-items",
+                         "color-scheme-separator", NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
+
+  /* add the color schemes to the menu */
+  for (iter = schemes; iter != NULL; iter = g_slist_next (iter))
+    {
+      /* create action name */
+      name = g_strdup_printf ("color-scheme_%s", gtk_source_style_scheme_get_id (iter->data));
+
+      /* create action for colour scheme */
+      action = gtk_radio_action_new (name,
+                                     gtk_source_style_scheme_get_name (iter->data),
+                                     gtk_source_style_scheme_get_description (iter->data),
+                                     NULL,
+                                     g_str_hash (gtk_source_style_scheme_get_id (iter->data)));
+      gtk_radio_action_set_group (action, group);
+      group = gtk_radio_action_get_group (action);
+      g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (mousepad_window_action_color_scheme), window);
+      gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (action), "");
+
+      /* activate the radio button if it was the last saved colour scheme */
+      if (g_strcmp0 (gtk_source_style_scheme_get_id (iter->data), selected_color_scheme) == 0)
+          gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+
+      /* release the action */
+      g_object_unref (G_OBJECT (action));
+
+      /* add the action to the go menu */
+      gtk_ui_manager_add_ui (window->ui_manager, merge_id,
+                             "/main-menu/view-menu/color-scheme-menu/placeholder-color-scheme-items",
+                             name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
+
+      /* cleanup */
+      g_free (name);
+    }
+
+  /* cleanup the list */
+  g_slist_free (schemes);
+
+  /* unlock */
+  lock_menu_updates--;
+}
+
+
+
+static void
+mousepad_window_menu_languages (MousepadWindow *window)
+{
+  gint                  merge_id;
+  gchar                *name, *section_path;
+  gchar                 section_name[64];
+  GtkAction            *action;
+  GtkRadioAction       *radio_action;
+  GSList               *group = NULL;
+  GSList               *sections, *sect_iter, *languages, *lang_iter;
+
+  lock_menu_updates++;
+
+  merge_id = gtk_ui_manager_new_merge_id (window->ui_manager);
+
+  /* add the none language directly under the filetype */
+  radio_action = gtk_radio_action_new ("language-none",
+                                 _("None"),
+                                 _("No filetype"),
+                                 NULL,
+                                 g_str_hash ("none"));
+  gtk_radio_action_set_group (radio_action, group);
+  group = gtk_radio_action_get_group (radio_action);
+  g_signal_connect (G_OBJECT (radio_action), "activate", G_CALLBACK (mousepad_window_action_language), window);
+  gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), "");
+
+  /* release the action */
+  g_object_unref (G_OBJECT (radio_action));
+
+  /* add the action to the go menu */
+  gtk_ui_manager_add_ui (window->ui_manager,
+                         merge_id,
+                         "/main-menu/document-menu/language-menu/placeholder-language-section-items",
+                         "language-none",
+                         "language-none",
+                         GTK_UI_MANAGER_MENUITEM,
+                         FALSE);
+
+  /* add a separator */
+  gtk_ui_manager_add_ui (window->ui_manager,
+                         merge_id,
+                         "/main-menu/document-menu/language-menu/placeholder-language-section-items",
+                         "language-separator",
+                         NULL,
+                         GTK_UI_MANAGER_SEPARATOR,
+                         FALSE);
+
+  sections = mousepad_util_language_sections_get_sorted ();
+
+  for (sect_iter = sections; sect_iter != NULL; sect_iter = g_slist_next (sect_iter))
+    {
+      languages = mousepad_util_languages_get_sorted_for_section (sect_iter->data);
+
+      /* make sure there are langs in the section, otherwise skip it */
+      if (!languages)
+        continue;
+      else if (!g_slist_length (languages))
+        {
+          g_slist_free (languages);
+          continue;
+        }
+
+      g_snprintf (section_name, 64, "language-section-%s", (gchar *)sect_iter->data);
+
+      /* add the section directly under the gtkuimanager dynamic menu filetype */
+      action = gtk_action_new (section_name,
+                               sect_iter->data,
+                               NULL,
+                               NULL);
+      gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (action), "");
+
+      /* release the action */
+      g_object_unref (G_OBJECT (action));
+
+      /* add a menu for each section */
+      gtk_ui_manager_add_ui (window->ui_manager,
+                             merge_id,
+                             "/main-menu/document-menu/language-menu/placeholder-language-section-items",
+                             section_name,
+                             section_name,
+                             GTK_UI_MANAGER_MENU,
+                             FALSE);
+
+      section_path = g_strdup_printf ("/main-menu/document-menu/language-menu/"
+                                      "placeholder-language-section-items/%s",
+                                      section_name);
+
+      for (lang_iter = languages; lang_iter != NULL; lang_iter = g_slist_next (lang_iter))
+        {
+          if (g_strcmp0 (sect_iter->data, gtk_source_language_get_section (lang_iter->data)) == 0)
+          {
+            /* create action name */
+            name = g_strdup_printf ("language-%s", gtk_source_language_get_id (lang_iter->data));
+
+            radio_action = gtk_radio_action_new (name,
+                                                 gtk_source_language_get_name (lang_iter->data),
+                                                 NULL,
+                                                 NULL,
+                                                 g_str_hash (gtk_source_language_get_id (lang_iter->data)));
+            gtk_radio_action_set_group (radio_action, group);
+            group = gtk_radio_action_get_group (radio_action);
+            g_signal_connect (G_OBJECT (radio_action),
+                              "activate",
+                              G_CALLBACK (mousepad_window_action_language),
+                              window);
+            gtk_action_group_add_action_with_accel (window->action_group, GTK_ACTION (radio_action), "");
+
+            /* release the action */
+            g_object_unref (G_OBJECT (radio_action));
+
+            /* add the action to the section menu */
+            gtk_ui_manager_add_ui (window->ui_manager,
+                                   merge_id,
+                                   section_path,
+                                   name,
+                                   name,
+                                   GTK_UI_MANAGER_MENUITEM,
+                                   FALSE);
+
+            /* cleanup before next language */
+            g_free (name);
+          }
+        }
+
+        /* cleanup before next section */
+        g_free (section_path);
+        g_slist_free (languages);
+    }
+
+  g_slist_free (sections);
+
+  /* unlock */
+  lock_menu_updates--;
+}
+
+
+
+/**
+ * Menu Actions
+ *
+ * All those function should be sorted by the menu structure so it's
+ * easy to find a function. The function can always use window->active, since
+ * we can assume there is always an active document inside a window.
+ **/
+static void
+mousepad_window_action_new (GtkAction      *action,
+                            MousepadWindow *window)
+{
+  MousepadDocument *document;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* create new document */
+  document = mousepad_document_new ();
+
+  /* add the document to the window */
+  mousepad_window_add (window, document);
+}
+
+
+
+static void
+mousepad_window_action_new_window (GtkAction      *action,
+                                   MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* emit the new window signal */
+  g_signal_emit (G_OBJECT (window), window_signals[NEW_WINDOW], 0);
+}
+
+
+
+static void
+mousepad_window_action_new_from_template (GtkMenuItem    *item,
+                                          MousepadWindow *window)
+{
+  const gchar      *filename;
+  GError           *error = NULL;
+  gint              result;
+  MousepadDocument *document;
+  const gchar      *message;
+
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (GTK_IS_MENU_ITEM (item));
+
+  /* get the filename from the menu item */
+  filename = mousepad_object_get_data (G_OBJECT (item), "filename");
+
+  /* test if the file exists */
+  if (G_LIKELY (filename))
+    {
+      /* create new document */
+      document = mousepad_document_new ();
+
+      /* sink floating object */
+      g_object_ref_sink (G_OBJECT (document));
+
+      /* lock the undo manager */
+      gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (document->buffer));
+
+      /* try to load the template into the buffer */
+      result = mousepad_file_open (document->file, filename, &error);
+
+      /* release the lock */
+      gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (document->buffer));
+
+      /* handle the result */
+      if (G_LIKELY (result == 0))
+        {
+          /* no errors, insert the document */
+          mousepad_window_add (window, document);
+        }
+      else
+        {
+          /* release the document */
+          g_object_unref (G_OBJECT (document));
+
+          /* handle the error */
+          switch (result)
+            {
+              case ERROR_NOT_UTF8_VALID:
+              case ERROR_CONVERTING_FAILED:
+                /* set error message */
+                message = _("Templates should be UTF-8 valid");
+                break;
+
+              case ERROR_READING_FAILED:
+                /* destroy the menu item */
+                gtk_widget_destroy (GTK_WIDGET (item));
+
+                /* set error message */
+                message = _("Reading the template failed, the menu item has been removed");
+                break;
+
+              default:
+                /* set error message */
+                message = _("Loading the template failed");
+                break;
+            }
+
+          /* show the error */
+          mousepad_dialogs_show_error (GTK_WINDOW (window), error, message);
+        }
+    }
+}
+
+
+
+static void
+mousepad_window_action_open (GtkAction      *action,
+                             MousepadWindow *window)
+{
+  GtkWidget   *chooser;
+  GtkWidget    *hbox, *label, *combobox;
+  const gchar *filename;
+  GSList      *filenames, *li;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* create new file chooser dialog */
+  chooser = gtk_file_chooser_dialog_new (_("Open File"),
+                                         GTK_WINDOW (window),
+                                         GTK_FILE_CHOOSER_ACTION_OPEN,
+                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                         NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT);
+  gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
+  gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), TRUE);
+
+  /* encoding selector */
+  hbox = gtk_hbox_new (FALSE, 6);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+  gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (chooser), hbox);
+  gtk_widget_show (hbox);
+
+  label = gtk_label_new_with_mnemonic ("_Encoding:");
+  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+  gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+  gtk_widget_show (label);
+
+  combobox = gtk_combo_box_new ();
+  gtk_box_pack_start (GTK_BOX (hbox), combobox, FALSE, FALSE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), combobox);
+  gtk_widget_show (combobox);
+
+  /* select the active document in the file chooser */
+  filename = mousepad_file_get_filename (window->active->file);
+  if (filename && g_file_test (filename, G_FILE_TEST_EXISTS))
+    gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), filename);
+
+  /* run the dialog */
+  if (G_LIKELY (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT))
+    {
+      /* hide the dialog */
+      gtk_widget_hide (chooser);
+
+      /* get a list of selected filenames */
+      filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (chooser));
+
+      /* lock menu updates */
+      lock_menu_updates++;
+
+      /* open all the selected filenames in a new tab */
+      for (li = filenames; li != NULL; li = li->next)
+        {
+          /* open the file */
+          mousepad_window_open_file (window, li->data, MOUSEPAD_ENCODING_UTF_8);
+
+          /* cleanup */
+          g_free (li->data);
+        }
+
+      /* cleanup */
+      g_slist_free (filenames);
+
+      /* allow menu updates again */
+      lock_menu_updates--;
+
+      /* update the menus */
+      mousepad_window_recent_menu (window);
+      mousepad_window_update_gomenu (window);
+    }
+
+  /* destroy dialog */
+  gtk_widget_destroy (chooser);
+}
+
+
+
+static void
+mousepad_window_action_open_recent (GtkAction      *action,
+                                    MousepadWindow *window)
+{
+  const gchar      *uri, *charset;
+  MousepadEncoding  encoding;
+  GError           *error = NULL;
+  gchar            *filename;
+  gboolean          succeed = FALSE;
+  GtkRecentInfo    *info;
+
+  mousepad_return_if_fail (GTK_IS_ACTION (action));
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* get the info */
+  info = mousepad_object_get_data (G_OBJECT (action), "gtk-recent-info");
+
+  if (G_LIKELY (info != NULL))
+    {
+      /* get the file uri */
+      uri = gtk_recent_info_get_uri (info);
+
+      /* build a filename from the uri */
+      filename = g_filename_from_uri (uri, NULL, NULL);
+
+      if (G_LIKELY (filename != NULL))
+        {
+          /* open the file in a new tab if it exists */
+          if (g_file_test (filename, G_FILE_TEST_EXISTS))
+            {
+              /* try to get the charset from the description */
+              charset = mousepad_window_recent_get_charset (info);
+
+              /* lookup the encoding */
+              encoding = mousepad_encoding_find (charset);
+
+              /* try to open the file */
+              succeed = mousepad_window_open_file (window, filename, encoding);
+            }
+          else
+            {
+              /* create an error */
+              g_set_error (&error,  G_FILE_ERROR, G_FILE_ERROR_IO,
+                           _("Failed to open \"%s\" for reading. It will be "
+                             "removed from the document history"), filename);
+
+              /* show the warning and cleanup */
+              mousepad_dialogs_show_error (GTK_WINDOW (window), error, _("Failed to open file"));
+              g_error_free (error);
+            }
+
+          /* cleanup */
+          g_free (filename);
+
+          /* update the document history */
+          if (G_LIKELY (succeed))
+            gtk_recent_manager_add_item (window->recent_manager, uri);
+          else
+            gtk_recent_manager_remove_item (window->recent_manager, uri, NULL);
+        }
+    }
+}
+
+
+
+static void
+mousepad_window_action_clear_recent (GtkAction      *action,
+                                     MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* ask the user if he or she really want to clear the history */
+  if (mousepad_dialogs_clear_recent (GTK_WINDOW (window)))
+    {
+      /* avoid updating the menu */
+      lock_menu_updates++;
+
+      /* clear the document history */
+      mousepad_window_recent_clear (window);
+
+      /* allow menu updates again */
+      lock_menu_updates--;
+
+      /* update the recent menu */
+      mousepad_window_recent_menu (window);
+    }
+}
+
+
+
+static gboolean
+mousepad_window_action_save (GtkAction      *action,
+                             MousepadWindow *window)
+{
+  MousepadDocument *document = window->active;
+  GError           *error = NULL;
+  gboolean          succeed = FALSE;
+  gboolean          modified;
+  gint              response;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), FALSE);
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (window->active), FALSE);
+
+  if (mousepad_file_get_filename (document->file) == NULL)
+    {
+      /* file has no filename yet, open the save as dialog */
+      succeed = mousepad_window_action_save_as (NULL, window);
+    }
+  else
+    {
+      /* check whether the file is externally modified */
+      modified = mousepad_file_get_externally_modified (document->file, &error);
+      if (G_UNLIKELY (error != NULL))
+        goto showerror;
+
+      if (modified)
+        {
+          /* ask the user what to do */
+          response = mousepad_dialogs_externally_modified (GTK_WINDOW (window));
+        }
+      else
+        {
+          /* save */
+          response = MOUSEPAD_RESPONSE_SAVE;
+        }
+
+      switch (response)
+        {
+          case MOUSEPAD_RESPONSE_CANCEL:
+            /* do nothing */
+            return FALSE;
+
+          case MOUSEPAD_RESPONSE_SAVE_AS:
+            /* run save as dialog */
+            succeed = mousepad_window_action_save_as (NULL, window);
+            break;
+
+          case MOUSEPAD_RESPONSE_SAVE:
+            /* save the document */
+            succeed = mousepad_file_save (document->file, &error);
+            break;
+        }
+
+      if (G_LIKELY (succeed))
+        {
+          /* update the window title */
+          mousepad_window_set_title (window);
+        }
+      else if (error != NULL)
+        {
+          showerror:
+
+          /* show the error */
+          mousepad_dialogs_show_error (GTK_WINDOW (window), error, _("Failed to save the document"));
+          g_error_free (error);
+        }
+    }
+
+  return succeed;
+}
+
+
+
+static gboolean
+mousepad_window_action_save_as (GtkAction      *action,
+                                MousepadWindow *window)
+{
+  MousepadDocument *document = window->active;
+  gchar            *filename;
+  const gchar      *current_filename;
+  GtkWidget        *dialog;
+  gboolean          succeed = FALSE;
+
+  mousepad_return_val_if_fail (MOUSEPAD_IS_WINDOW (window), FALSE);
+  mousepad_return_val_if_fail (MOUSEPAD_IS_DOCUMENT (window->active), FALSE);
+
+  /* create the dialog */
+  dialog = gtk_file_chooser_dialog_new (_("Save As"),
+                                        GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_SAVE,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
+  gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE);
+  gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+  /* set the current filename if there is one */
+  current_filename = mousepad_file_get_filename (document->file);
+  if (current_filename)
+    gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), current_filename);
+
+  /* run the dialog */
+  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
+    {
+      /* get the new filename */
+      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+      if (G_LIKELY (filename))
+        {
+          /* set the new filename */
+          mousepad_file_set_filename (document->file, filename);
+
+          /* cleanup */
+          g_free (filename);
+
+          /* save the file with the function above */
+          succeed = mousepad_window_action_save (NULL, window);
+
+          /* add to the recent history is saving succeeded */
+          if (G_LIKELY (succeed))
+            mousepad_window_recent_add (window, document->file);
+        }
+    }
+
+  /* destroy the dialog */
+  gtk_widget_destroy (dialog);
+
+  return succeed;
+}
+
+
+
+static void
+mousepad_window_action_save_all (GtkAction      *action,
+                                 MousepadWindow *window)
+{
+  gint              i, current;
+  gint              page_num;
+  MousepadDocument *document;
+  GSList           *li, *documents = NULL;
+  gboolean          succeed = TRUE;
+  GError           *error = NULL;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* get the current active tab */
+  current = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
+
+  /* walk though all the document in the window */
+  for (i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)); i++)
+    {
+      /* get the document */
+      document = MOUSEPAD_DOCUMENT (gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), i));
+
+      /* debug check */
+      mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+      /* continue if the document is not modified */
+      if (!gtk_text_buffer_get_modified (document->buffer))
+        continue;
+
+      /* we try to quickly save files, without bothering the user */
+      if (mousepad_file_get_filename (document->file) != NULL
+          && mousepad_file_get_read_only (document->file) == FALSE
+          && mousepad_file_get_externally_modified (document->file, NULL) == FALSE)
+        {
+          /* try to quickly save the file */
+          succeed = mousepad_file_save (document->file, &error);
+
+          /* break on problems */
+          if (G_UNLIKELY (!succeed))
+            break;
+        }
+      else
+        {
+          /* add the document to a queue to bother the user later */
+          documents = g_slist_prepend (documents, document);
+        }
+    }
+
+  if (G_UNLIKELY (succeed == FALSE))
+    {
+      /* focus the tab that triggered the problem */
+      gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), i);
+
+      /* show the error */
+      mousepad_dialogs_show_error (GTK_WINDOW (window), error, _("Failed to save the document"));
+
+      /* free error */
+      if (error != NULL)
+        g_error_free (error);
+    }
+  else
+    {
+      /* open a save as dialog for all the unnamed files */
+      for (li = documents; li != NULL; li = li->next)
+        {
+          document = MOUSEPAD_DOCUMENT (li->data);
+
+          /* get the documents page number */
+          page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook), GTK_WIDGET (li->data));
+
+          if (G_LIKELY (page_num > -1))
+            {
+              /* focus the tab we're going to save */
+              gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page_num);
+
+              if (mousepad_file_get_filename (document->file) == NULL
+                  || mousepad_file_get_read_only (document->file))
+                {
+                  /* trigger the save as function */
+                  mousepad_window_action_save_as (NULL, window);
+                }
+              else
+                {
+                  /* trigger the save function (externally modified document) */
+                  mousepad_window_action_save (NULL, window);
+                }
+            }
+        }
+
+      /* focus the origional doc if everything went fine */
+      if (G_LIKELY (li == NULL))
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), current);
+    }
+
+  /* cleanup */
+  g_slist_free (documents);
+}
+
+
+
+static void
+mousepad_window_action_revert (GtkAction      *action,
+                               MousepadWindow *window)
+{
+  MousepadDocument *document = window->active;
+  GError           *error = NULL;
+  gint              response;
+  gboolean          succeed;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* ask the user if he really wants to do this when the file is modified */
+  if (gtk_text_buffer_get_modified (document->buffer))
+    {
+      /* ask the user if he really wants to revert */
+      response = mousepad_dialogs_revert (GTK_WINDOW (window));
+
+      if (response == MOUSEPAD_RESPONSE_SAVE_AS)
+        {
+          /* open the save as dialog, leave when use user did not save (or it failed) */
+          if (!mousepad_window_action_save_as (NULL, window))
+            return;
+        }
+      else if (response == MOUSEPAD_RESPONSE_CANCEL)
+        {
+          /* meh, first click revert and then cancel... pussy... */
+          return;
+        }
+
+      /* small check for debug builds */
+      mousepad_return_if_fail (response == MOUSEPAD_RESPONSE_REVERT);
+    }
+
+  /* lock the undo manager */
+  gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (document->buffer));
+
+  /* reload the file */
+  succeed = mousepad_file_reload (document->file, &error);
+
+  /* release the lock */
+  gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (document->buffer));
+
+  if (G_UNLIKELY (succeed == FALSE))
+    {
+      /* show the error */
+      mousepad_dialogs_show_error (GTK_WINDOW (window), error, _("Failed to reload the document"));
+      g_error_free (error);
+    }
+}
+
+
+
+static void
+mousepad_window_action_print (GtkAction      *action,
+                              MousepadWindow *window)
+{
+  MousepadPrint    *print;
+  GError           *error = NULL;
+  gboolean          succeed;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* create new print operation */
+  print = mousepad_print_new ();
+
+  /* print the current document */
+  succeed = mousepad_print_document_interactive (print, window->active, GTK_WINDOW (window), &error);
+
+  if (G_UNLIKELY (succeed == FALSE))
+    {
+      /* show the error */
+      mousepad_dialogs_show_error (GTK_WINDOW (window), error, _("Failed to print the document"));
+      g_error_free (error);
+    }
+
+  /* release the object */
+  g_object_unref (G_OBJECT (print));
+}
+
+
+
+static void
+mousepad_window_action_detach (GtkAction      *action,
+                               MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+#if GTK_CHECK_VERSION (2,12,0)
+  /* invoke function without cooridinates */
+  mousepad_window_notebook_create_window (GTK_NOTEBOOK (window->notebook),
+                                          GTK_WIDGET (window->active),
+                                          -1, -1, window);
+#else
+  /* only detach when there are more then 2 tabs */
+  if (G_LIKELY (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) >= 2))
+    {
+      /* take a reference */
+      g_object_ref (G_OBJECT (window->active));
+
+      /* remove the document from the active window */
+      gtk_container_remove (GTK_CONTAINER (window->notebook), GTK_WIDGET (window->active));
+
+      /* emit the new window with document signal */
+      g_signal_emit (G_OBJECT (window), window_signals[NEW_WINDOW_WITH_DOCUMENT], 0, window->active, -1, -1);
+
+      /* release our reference */
+      g_object_unref (G_OBJECT (window->active));
+    }
+#endif
+}
+
+
+
+static void
+mousepad_window_action_close (GtkAction      *action,
+                              MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* close active document */
+  mousepad_window_close_document (window, window->active);
+}
+
+
+
+static void
+mousepad_window_action_close_window (GtkAction      *action,
+                                     MousepadWindow *window)
+{
+  gint       npages, i;
+  GtkWidget *document;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* get the number of page in the notebook */
+  npages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) - 1;
+
+  /* prevent menu updates */
+  lock_menu_updates++;
+
+  /* ask what to do with the modified document in this window */
+  for (i = npages; i >= 0; --i)
+    {
+      /* get the document */
+      document = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), i);
+
+      /* check for debug builds */
+      mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+      /* focus the tab we're going to close */
+      gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), i);
+
+      /* close each document */
+      if (!mousepad_window_close_document (window, MOUSEPAD_DOCUMENT (document)))
+        {
+          /* closing cancelled, release menu lock */
+          lock_menu_updates--;
+
+          /* rebuild go menu */
+          mousepad_window_update_gomenu (window);
+
+          /* leave function */
+          return;
+        }
+    }
+
+  /* release lock */
+  lock_menu_updates--;
+}
+
+
+
+static void
+mousepad_window_action_undo (GtkAction      *action,
+                             MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* undo */
+  gtk_source_buffer_undo (GTK_SOURCE_BUFFER (window->active->buffer));
+
+  /* scroll to visible area */
+  mousepad_view_scroll_to_cursor (window->active->textview);
+}
+
+
+
+static void
+mousepad_window_action_redo (GtkAction      *action,
+                             MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* redo */
+  gtk_source_buffer_redo (GTK_SOURCE_BUFFER (window->active->buffer));
+
+  /* scroll to visible area */
+  mousepad_view_scroll_to_cursor (window->active->textview);
+}
+
+
+
+static void
+mousepad_window_action_cut (GtkAction      *action,
+                            MousepadWindow *window)
+{
+  GtkEditable *entry;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* get searchbar entry */
+  entry = mousepad_search_bar_entry (MOUSEPAD_SEARCH_BAR (window->search_bar));
+
+  /* cut from search bar entry or textview */
+  if (G_UNLIKELY (entry))
+    gtk_editable_cut_clipboard (entry);
+  else
+    mousepad_view_clipboard_cut (window->active->textview);
+
+  /* update the history */
+  mousepad_window_paste_history_add (window);
+}
+
+
+
+static void
+mousepad_window_action_copy (GtkAction      *action,
+                             MousepadWindow *window)
+{
+  GtkEditable *entry;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* get searchbar entry */
+  entry = mousepad_search_bar_entry (MOUSEPAD_SEARCH_BAR (window->search_bar));
+
+  /* copy from search bar entry or textview */
+  if (G_UNLIKELY (entry))
+    gtk_editable_copy_clipboard (entry);
+  else
+    mousepad_view_clipboard_copy (window->active->textview);
+
+  /* update the history */
+  mousepad_window_paste_history_add (window);
+}
+
+
+
+static void
+mousepad_window_action_paste (GtkAction      *action,
+                              MousepadWindow *window)
+{
+  GtkEditable *entry;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* get searchbar entry */
+  entry = mousepad_search_bar_entry (MOUSEPAD_SEARCH_BAR (window->search_bar));
+
+  /* paste in search bar entry or textview */
+  if (G_UNLIKELY (entry))
+    gtk_editable_paste_clipboard (entry);
+  else
+    mousepad_view_clipboard_paste (window->active->textview, NULL, FALSE);
+}
+
+
+
+static void
+mousepad_window_action_paste_history (GtkAction      *action,
+                                      MousepadWindow *window)
+{
+  GtkWidget *menu;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* get the history menu */
+  menu = mousepad_window_paste_history_menu (window);
+
+  /* select the first item in the menu */
+  gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), TRUE);
+
+  /* popup the menu */
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+                  mousepad_window_paste_history_menu_position,
+                  window, 0, gtk_get_current_event_time ());
+}
+
+
+
+static void
+mousepad_window_action_paste_column (GtkAction      *action,
+                                     MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* paste the clipboard into a column */
+  mousepad_view_clipboard_paste (window->active->textview, NULL, TRUE);
+}
+
+
+
+static void
+mousepad_window_action_delete (GtkAction      *action,
+                               MousepadWindow *window)
+{
+  GtkEditable *entry;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* get searchbar entry */
+  entry = mousepad_search_bar_entry (MOUSEPAD_SEARCH_BAR (window->search_bar));
+
+  /* delete selection in search bar entry or textview */
+  if (G_UNLIKELY (entry))
+    gtk_editable_delete_selection (entry);
+  else
+    mousepad_view_delete_selection (window->active->textview);
+}
+
+
+
+static void
+mousepad_window_action_select_all (GtkAction      *action,
+                                   MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* select everything in the document */
+  mousepad_view_select_all (window->active->textview);
+}
+
+
+
+static void
+mousepad_window_action_change_selection (GtkAction      *action,
+                                         MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* change the selection */
+  mousepad_view_change_selection (window->active->textview);
+}
+
+
+
+static void
+mousepad_window_action_find (GtkAction      *action,
+                             MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* create a new search bar is needed */
+  if (window->search_bar == NULL)
+    {
+      /* create a new toolbar and pack it into the box */
+      window->search_bar = mousepad_search_bar_new ();
+      gtk_box_pack_start (GTK_BOX (window->box), window->search_bar, FALSE, FALSE, PADDING);
+
+      /* connect signals */
+      g_signal_connect_swapped (G_OBJECT (window->search_bar), "hide-bar", G_CALLBACK (mousepad_window_hide_search_bar), window);
+      g_signal_connect_swapped (G_OBJECT (window->search_bar), "search", G_CALLBACK (mousepad_window_search), window);
+    }
+
+  /* show the search bar */
+  gtk_widget_show (window->search_bar);
+
+  /* focus the search entry */
+  mousepad_search_bar_focus (MOUSEPAD_SEARCH_BAR (window->search_bar));
+}
+
+
+
+static void
+mousepad_window_action_find_next (GtkAction      *action,
+                                  MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* find the next occurence */
+  if (G_LIKELY (window->search_bar != NULL))
+    mousepad_search_bar_find_next (MOUSEPAD_SEARCH_BAR (window->search_bar));
+}
+
+
+
+static void
+mousepad_window_action_find_previous (GtkAction      *action,
+                                      MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* find the previous occurence */
+  if (G_LIKELY (window->search_bar != NULL))
+    mousepad_search_bar_find_previous (MOUSEPAD_SEARCH_BAR (window->search_bar));
+}
+
+
+static void
+mousepad_window_action_replace_switch_page (MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_REPLACE_DIALOG (window->replace_dialog));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* page switched */
+  mousepad_replace_dialog_page_switched (MOUSEPAD_REPLACE_DIALOG (window->replace_dialog));
+}
+
+
+static void
+mousepad_window_action_replace_destroy (MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* disconnect tab switch signal */
+  g_signal_handlers_disconnect_by_func (G_OBJECT (window->notebook), mousepad_window_action_replace_switch_page, window);
+
+  /* reset the dialog variable */
+  window->replace_dialog = NULL;
+}
+
+
+static void
+mousepad_window_action_replace (GtkAction      *action,
+                                MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  if (window->replace_dialog == NULL)
+    {
+      /* create a new dialog */
+      window->replace_dialog = mousepad_replace_dialog_new ();
+
+      /* popup the dialog */
+      gtk_window_set_destroy_with_parent (GTK_WINDOW (window->replace_dialog), TRUE);
+      gtk_window_set_transient_for (GTK_WINDOW (window->replace_dialog), GTK_WINDOW (window));
+      gtk_widget_show (window->replace_dialog);
+
+      /* connect signals */
+      g_signal_connect_swapped (G_OBJECT (window->replace_dialog), "destroy", G_CALLBACK (mousepad_window_action_replace_destroy), window);
+      g_signal_connect_swapped (G_OBJECT (window->replace_dialog), "search", G_CALLBACK (mousepad_window_search), window);
+      g_signal_connect_swapped (G_OBJECT (window->notebook), "switch-page", G_CALLBACK (mousepad_window_action_replace_switch_page), window);
+    }
+  else
+    {
+      /* focus the existing dialog */
+      gtk_window_present (GTK_WINDOW (window->replace_dialog));
+    }
+}
+
+
+
+static void
+mousepad_window_action_select_font (GtkAction      *action,
+                                    MousepadWindow *window)
+{
+  GtkWidget        *dialog;
+  MousepadDocument *document;
+  gchar            *font_name;
+  gint              i;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  dialog = gtk_font_selection_dialog_new (_("Choose Mousepad Font"));
+  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
+
+  /* set the current font name */
+  g_object_get (G_OBJECT (window->preferences), "view-font-name", &font_name, NULL);
+  if (G_LIKELY (font_name))
+    {
+      gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (dialog), font_name);
+      g_free (font_name);
+    }
+
+  /* run the dialog */
+  if (G_LIKELY (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK))
+    {
+      /* get the selected font from the dialog */
+      font_name = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (dialog));
+
+      /* store the font in the preferences */
+      g_object_set (G_OBJECT (window->preferences), "view-font-name", font_name, NULL);
+
+      /* apply the font in all documents in this window */
+      for (i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)); i++)
+        {
+          /* get the document */
+          document = MOUSEPAD_DOCUMENT (gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), i));
+
+          /* debug check */
+          mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
+
+          /* set the font */
+          mousepad_document_set_font (document, font_name);
+
+          /* update the tab array */
+          mousepad_view_set_tab_size (document->textview, mousepad_view_get_tab_size (document->textview));
+        }
+
+      /* cleanup */
+      g_free (font_name);
+    }
+
+  /* destroy dialog */
+  gtk_widget_destroy (dialog);
+}
+
+
+
+static void
+mousepad_window_action_color_scheme (GtkToggleAction *action,
+                                     MousepadWindow  *window)
+{
+  gint                  page_num = 0;
+  guint                 scheme_id_hash;
+  GtkWidget            *page;
+  GtkTextBuffer        *buffer;
+  GtkSourceStyleScheme *scheme = NULL;
+  MousepadDocument     *document;
+  GSList               *schemes, *iter;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* leave when menu updates are locked */
+  if (lock_menu_updates == 0 && gtk_toggle_action_get_active (action))
+    {
+      mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+      /* get the color scheme id hashed */
+      scheme_id_hash = (guint) gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+
+      if (scheme_id_hash != g_str_hash ("none"))
+        {
+          /* lookup the scheme from the id hash */
+          schemes = mousepad_util_color_schemes_get ();
+          for (iter = schemes; iter != NULL; iter = g_slist_next (iter))
+            {
+              if (scheme_id_hash == g_str_hash (gtk_source_style_scheme_get_id (iter->data)))
+                {
+                  scheme = iter->data;
+                  break;
+                }
+            }
+          g_slist_free (schemes);
+        }
+
+      /* store as last used value */
+      g_object_set (G_OBJECT (window->preferences),
+                    "view-color-scheme",
+                    (scheme != NULL) ? gtk_source_style_scheme_get_id (scheme) : "none",
+                    NULL);
+
+      /* apply colour scheme to all open textviews */
+      while ((page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), page_num)))
+        {
+          if (G_LIKELY (MOUSEPAD_IS_DOCUMENT (page)))
+            {
+              document = MOUSEPAD_DOCUMENT (page);
+              buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (document->textview));
+              gtk_source_buffer_set_highlight_syntax (GTK_SOURCE_BUFFER (buffer), (scheme != NULL));
+              gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (buffer), scheme);
+            }
+            page_num++;
+        }
+    }
+}
+
+
+
+static void
+mousepad_window_action_line_numbers (GtkToggleAction *action,
+                                     MousepadWindow  *window)
+{
+  gint              page_num = 0;
+  gboolean          active;
+  GtkWidget        *page;
+  MousepadDocument *document;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* leave when menu updates are locked */
+  if (lock_menu_updates == 0)
+    {
+      /* get the current state */
+      active = gtk_toggle_action_get_active (action);
+
+      /* save as the last used line number setting */
+      g_object_set (G_OBJECT (window->preferences), "view-line-numbers", active, NULL);
+
+      /* apply line numbers setting to all open textviews */
+      while ((page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), page_num)))
+        {
+          if (G_LIKELY (MOUSEPAD_IS_DOCUMENT (page)))
+            {
+              document = MOUSEPAD_DOCUMENT (page);
+              mousepad_view_set_line_numbers (document->textview, active);
+            }
+          page_num++;
+        }
+    }
+}
+
+
+
+static void
+mousepad_window_action_statusbar_overwrite (MousepadWindow *window,
+                                            gboolean        overwrite)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* set the new overwrite mode */
+  mousepad_document_set_overwrite (window->active, overwrite);
+}
+
+
+
+static void
+mousepad_window_action_statusbar (GtkToggleAction *action,
+                                  MousepadWindow  *window)
+{
+  gboolean show_statusbar;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* whether we show the statusbar */
+  show_statusbar = gtk_toggle_action_get_active (action);
+
+  /* check if we should drop the statusbar */
+  if (!show_statusbar && window->statusbar != NULL)
+    {
+      /* destroy the statusbar */
+      gtk_widget_destroy (window->statusbar);
+      window->statusbar = NULL;
+    }
+  else if (show_statusbar && window->statusbar == NULL)
+    {
+      /* setup a new statusbar */
+      window->statusbar = mousepad_statusbar_new ();
+      gtk_box_pack_end (GTK_BOX (window->box), window->statusbar, FALSE, FALSE, 0);
+      gtk_widget_show (window->statusbar);
+
+      /* overwrite toggle signal */
+      g_signal_connect_swapped (G_OBJECT (window->statusbar), "enable-overwrite",
+                                G_CALLBACK (mousepad_window_action_statusbar_overwrite), window);
+
+      /* populate filetype popup menu signal */
+      g_signal_connect_swapped (G_OBJECT (window->statusbar), "populate-filetype-popup",
+                                G_CALLBACK (mousepad_window_populate_statusbar_popup), window);
+
+      /* update the statusbar items */
+      if (window->active)
+        {
+          /* debug check */
+          mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+          /* ask document to resend the cursor status signals */
+          mousepad_document_send_signals (window->active);
+        }
+    }
+
+  /* remember the setting */
+  g_object_set (G_OBJECT (window->preferences), "window-statusbar-visible", show_statusbar, NULL);
+}
+
+
+
+static void
+mousepad_window_action_lowercase (GtkAction      *action,
+                                  MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* convert selection to lowercase */
+  mousepad_view_convert_selection_case (window->active->textview, LOWERCASE);
+}
+
+
+
+static void
+mousepad_window_action_uppercase (GtkAction      *action,
+                                  MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* convert selection to uppercase */
+  mousepad_view_convert_selection_case (window->active->textview, UPPERCASE);
+}
+
+
+
+static void
+mousepad_window_action_titlecase (GtkAction      *action,
+                                  MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* convert selection to titlecase */
+  mousepad_view_convert_selection_case (window->active->textview, TITLECASE);
+}
+
+
+
+static void
+mousepad_window_action_opposite_case (GtkAction      *action,
+                                      MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* convert selection to opposite case */
+  mousepad_view_convert_selection_case (window->active->textview, OPPOSITE_CASE);
+}
+
+
+
+static void
+mousepad_window_action_tabs_to_spaces (GtkAction      *action,
+                                       MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* convert tabs to spaces */
+  mousepad_view_convert_spaces_and_tabs (window->active->textview, TABS_TO_SPACES);
+}
+
+
+
+static void
+mousepad_window_action_spaces_to_tabs (GtkAction      *action,
+                                       MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* convert spaces to tabs */
+  mousepad_view_convert_spaces_and_tabs (window->active->textview, SPACES_TO_TABS);
+}
+
+
+
+static void
+mousepad_window_action_strip_trailing_spaces (GtkAction      *action,
+                                              MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* convert spaces to tabs */
+  mousepad_view_strip_trailing_spaces (window->active->textview);
+}
+
+
+
+static void
+mousepad_window_action_transpose (GtkAction      *action,
+                                  MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* transpose */
+  mousepad_view_transpose (window->active->textview);
+}
+
+
+
+static void
+mousepad_window_action_move_line_up (GtkAction      *action,
+                                     MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* move the selection on line up */
+  mousepad_view_move_selection (window->active->textview, MOVE_LINE_UP);
+}
+
+
+
+static void
+mousepad_window_action_move_line_down (GtkAction      *action,
+                                       MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* move the selection on line down */
+  mousepad_view_move_selection (window->active->textview, MOVE_LINE_DOWN);
+}
+
+
+
+static void
+mousepad_window_action_duplicate (GtkAction      *action,
+                                  MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* dupplicate */
+  mousepad_view_duplicate (window->active->textview);
+}
+
+
+
+static void
+mousepad_window_action_increase_indent (GtkAction      *action,
+                                        MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* increase the indent */
+  mousepad_view_indent (window->active->textview, INCREASE_INDENT);
+}
+
+
+
+static void
+mousepad_window_action_decrease_indent (GtkAction      *action,
+                                        MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* decrease the indent */
+  mousepad_view_indent (window->active->textview, DECREASE_INDENT);
+}
+
+
+
+static void
+mousepad_window_action_auto_indent (GtkToggleAction *action,
+                                    MousepadWindow  *window)
+{
+  gboolean active;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* leave when menu updates are locked */
+  if (lock_menu_updates == 0)
+    {
+      /* get the current state */
+      active = gtk_toggle_action_get_active (action);
+
+      /* save as the last auto indent mode */
+      g_object_set (G_OBJECT (window->preferences), "view-auto-indent", active, NULL);
+
+      /* update the active document */
+      mousepad_view_set_auto_indent (window->active->textview, active);
+    }
+}
+
+
+
+static void
+mousepad_window_action_line_ending (GtkRadioAction *action,
+                                    GtkRadioAction *current,
+                                    MousepadWindow *window)
+{
+  MousepadLineEnding eol;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+  mousepad_return_if_fail (MOUSEPAD_IS_FILE (window->active->file));
+  mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (window->active->buffer));
+
+  /* leave when menu updates are locked */
+  if (lock_menu_updates == 0)
+    {
+      /* get selected line ending */
+      eol = gtk_radio_action_get_current_value (current);
+
+      /* set the new line ending on the file */
+      mousepad_file_set_line_ending (window->active->file, eol);
+
+      /* make buffer as modified to show the user the change is not saved */
+      gtk_text_buffer_set_modified (window->active->buffer, TRUE);
+    }
+}
+
+
+
+static void
+mousepad_window_action_tab_size (GtkToggleAction *action,
+                                 MousepadWindow  *window)
+{
+  gboolean tab_size;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* leave when menu updates are locked */
+  if (lock_menu_updates == 0 && gtk_toggle_action_get_active (action))
+    {
+      mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+      /* get the tab size */
+      tab_size = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+
+      /* whether the other item was clicked */
+      if (tab_size == 0)
+        {
+          /* get tab size from document */
+          tab_size = mousepad_view_get_tab_size (window->active->textview);
+
+          /* select other size in dialog */
+          tab_size = mousepad_dialogs_other_tab_size (GTK_WINDOW (window), tab_size);
+        }
+
+      /* store as last used value */
+      g_object_set (G_OBJECT (window->preferences), "view-tab-size", tab_size, NULL);
+
+      /* set the value */
+      mousepad_view_set_tab_size (window->active->textview, tab_size);
+
+      /* update menu */
+      mousepad_window_menu_tab_sizes_update (window);
+    }
+}
+
+
+
+static void
+mousepad_window_action_word_wrap (GtkToggleAction *action,
+                                  MousepadWindow  *window)
+{
+  gboolean active;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* leave when menu updates are locked */
+  if (lock_menu_updates == 0)
+    {
+      /* get the current state */
+      active = gtk_toggle_action_get_active (action);
+
+      /* store this as the last used wrap mode */
+      g_object_set (G_OBJECT (window->preferences), "view-word-wrap", active, NULL);
+
+      /* set the wrapping mode of the current document */
+      mousepad_document_set_word_wrap (window->active, active);
+    }
+}
+
+
+
+static void
+mousepad_window_action_write_bom (GtkToggleAction *action,
+                                  MousepadWindow  *window)
+{
+  gboolean active;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* leave when menu updates are locked */
+  if (lock_menu_updates == 0)
+    {
+      /* get the current state */
+      active = gtk_toggle_action_get_active (action);
+
+      /* set new value */
+      mousepad_file_set_write_bom (window->active->file, active);
+
+      /* make buffer as modified to show the user the change is not saved */
+      gtk_text_buffer_set_modified (window->active->buffer, TRUE);
+    }
+}
+
+
+
+static void
+mousepad_window_action_language (GtkToggleAction *action,
+                                 MousepadWindow  *window)
+{
+  guint                     lang_hash;
+  const gchar *const       *lang_id;
+  GtkSourceLanguage        *language;
+  GtkSourceLanguageManager *manager;
+  GtkSourceBuffer          *buffer;
+
+  lang_hash = (guint) gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+  buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->active->textview)));
+
+  if (lang_hash == g_str_hash ("none"))
+    {
+      gtk_source_buffer_set_language (buffer, NULL);
+      return;
+    }
+
+  manager = gtk_source_language_manager_get_default ();
+  lang_id = gtk_source_language_manager_get_language_ids (manager);
+
+  while (*lang_id)
+    {
+      if (g_str_hash (*lang_id) == lang_hash)
+        {
+          language = gtk_source_language_manager_get_language (manager, *lang_id);
+          gtk_source_buffer_set_language (buffer, language);
+          break;
+        }
+      lang_id++;
+    }
+}
+
+
+
+static void
+mousepad_window_action_insert_spaces (GtkToggleAction *action,
+                                      MousepadWindow  *window)
+{
+  gboolean insert_spaces;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+
+  /* leave when menu updates are locked */
+  if (lock_menu_updates == 0)
+    {
+      /* get the current state */
+      insert_spaces = gtk_toggle_action_get_active (action);
+
+      /* save as the last auto indent mode */
+      g_object_set (G_OBJECT (window->preferences), "view-insert-spaces", insert_spaces, NULL);
+
+      /* update the active document */
+      mousepad_view_set_insert_spaces (window->active->textview, insert_spaces);
+    }
+}
+
+
+
+
+static void
+mousepad_window_action_prev_tab (GtkAction      *action,
+                                 MousepadWindow *window)
+{
+  gint page_num;
+  gint n_pages;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* get notebook info */
+  page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
+  n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
+
+  /* switch to the previous tab or cycle to the last tab */
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), (page_num - 1) % n_pages);
+}
+
+
+
+static void
+mousepad_window_action_next_tab (GtkAction      *action,
+                                 MousepadWindow *window)
+{
+  gint page_num;
+  gint n_pages;
+
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* get notebook info */
+  page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
+  n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
+
+  /* switch to the next tab or cycle to the first tab */
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), (page_num + 1) % n_pages);
+}
+
+
+
+static void
+mousepad_window_action_go_to_tab (GtkRadioAction *action,
+                                  GtkNotebook    *notebook)
+{
+  gint page;
+
+  mousepad_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+  mousepad_return_if_fail (GTK_IS_RADIO_ACTION (action));
+  mousepad_return_if_fail (GTK_IS_TOGGLE_ACTION (action));
+
+  /* leave when the menu is locked or this is not the active radio button */
+  if (lock_menu_updates == 0
+      && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
+    {
+      /* get the page number from the action value */
+      page = gtk_radio_action_get_current_value (action);
+
+      /* set the page */
+      gtk_notebook_set_current_page (notebook, page);
+    }
+}
+
+
+
+static void
+mousepad_window_action_go_to_position (GtkAction      *action,
+                                       MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+  mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (window->active));
+  mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (window->active->buffer));
+
+  /* run jump dialog */
+  if (mousepad_dialogs_go_to (GTK_WINDOW (window), window->active->buffer))
+    {
+      /* put the cursor on screen */
+      mousepad_view_scroll_to_cursor (window->active->textview);
+    }
+}
+
+
+
+static void
+mousepad_window_action_contents (GtkAction      *action,
+                                 MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* show help */
+  mousepad_dialogs_show_help (GTK_WINDOW (window), NULL, NULL);
+}
+
+
+
+static void
+mousepad_window_action_about (GtkAction      *action,
+                              MousepadWindow *window)
+{
+  mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
+
+  /* show about dialog */
+  mousepad_dialogs_show_about (GTK_WINDOW (window));
+}
diff --git a/mousepad/mousepad-window.h b/mousepad/mousepad-window.h
new file mode 100644
index 0000000..cf68bc4
--- /dev/null
+++ b/mousepad/mousepad-window.h
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MOUSEPAD_WINDOW_H__
+#define __MOUSEPAD_WINDOW_H__
+
+G_BEGIN_DECLS
+
+#include <mousepad/mousepad-document.h>
+
+#define MOUSEPAD_TYPE_WINDOW            (mousepad_window_get_type ())
+#define MOUSEPAD_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOUSEPAD_TYPE_WINDOW, MousepadWindow))
+#define MOUSEPAD_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPAD_TYPE_WINDOW, MousepadWindowClass))
+#define MOUSEPAD_IS_WINDOW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOUSEPAD_TYPE_WINDOW))
+#define MOUSEPAD_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOUSEPADL_TYPE_WINDOW))
+#define MOUSEPAD_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MOUSEPAD_TYPE_WINDOW, MousepadWindowClass))
+
+enum
+{
+  TARGET_TEXT_URI_LIST,
+  TARGET_GTK_NOTEBOOK_TAB
+};
+
+static const GtkTargetEntry drop_targets[] =
+{
+  { (gchar *) "text/uri-list", 0, TARGET_TEXT_URI_LIST },
+  { (gchar *) "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, TARGET_GTK_NOTEBOOK_TAB }
+};
+
+typedef struct _MousepadWindowClass MousepadWindowClass;
+typedef struct _MousepadWindow      MousepadWindow;
+
+GType           mousepad_window_get_type         (void) G_GNUC_CONST;
+
+GtkWidget      *mousepad_window_new              (void);
+
+void            mousepad_window_add              (MousepadWindow   *window,
+                                                  MousepadDocument *document);
+
+gboolean        mousepad_window_open_files       (MousepadWindow  *window,
+                                                  const gchar     *working_directory,
+                                                  gchar          **filenames);
+
+G_END_DECLS
+
+#endif /* !__MOUSEPAD_WINDOW_H__ */
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..a62d797
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,27 @@
+#
+# Sources
+#
+mousepad/main.c
+mousepad/mousepad-application.c
+mousepad/mousepad-dbus.c
+mousepad/mousepad-dialogs.c
+mousepad/mousepad-document.c
+mousepad/mousepad-encoding-dialog.c
+mousepad/mousepad-encoding.c
+mousepad/mousepad-file.c
+mousepad/mousepad-preferences.c
+mousepad/mousepad-print.c
+mousepad/mousepad-replace-dialog.c
+mousepad/mousepad-search-bar.c
+mousepad/mousepad-statusbar.c
+mousepad/mousepad-undo.c
+mousepad/mousepad-util.c
+mousepad/mousepad-view.c
+mousepad/mousepad-window.c
+
+
+
+#
+# Desktop Files
+#
+Mousepad.desktop.in.in


More information about the Xfce4-commits mailing list