[Xfce4-commits] <mousepad:master> * 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.

Nick Schermer noreply at xfce.org
Sat May 5 21:30:58 CEST 2012


Updating branch refs/heads/master
         to f3a364cda15d48093802adbb4190a1d027e6a102 (commit)
       from 03cd4c266c5d539c85dbe22f505d1d54c1b011b4 (commit)

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)

 ChangeLog                       |   21 ++
 docs/manual/C/Mousepad.xml.in   |  355 +++++++++++++++++---
 mousepad/mousepad-document.c    |   75 +----
 mousepad/mousepad-document.h    |    4 -
 mousepad/mousepad-file.c        |    8 +-
 mousepad/mousepad-marshal.list  |    2 +-
 mousepad/mousepad-preferences.c |   31 +--
 mousepad/mousepad-preferences.h |    2 +
 mousepad/mousepad-print.c       |  701 +++++++++++++++++++++++++++++++++++----
 mousepad/mousepad-print.h       |   12 +-
 mousepad/mousepad-statusbar.c   |   20 +-
 mousepad/mousepad-statusbar.h   |    3 +-
 mousepad/mousepad-util.c        |  224 ++++++++++++-
 mousepad/mousepad-util.h        |   62 +++--
 mousepad/mousepad-view.c        |  446 +++++++++++++++----------
 mousepad/mousepad-view.h        |    2 +-
 mousepad/mousepad-window.c      |   68 ++---
 17 files changed, 1575 insertions(+), 461 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2d87175..72fca2a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2007-11-29	Nick Schermer <nick at xfce.org>
+	* 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.
+
+
 2007-10-26	Nick Schermer <nick at xfce.org>
 	* mousepad/mousepad-view.c: Implement transpose:
 	   - Selection on one line: Inverse selected text.
diff --git a/docs/manual/C/Mousepad.xml.in b/docs/manual/C/Mousepad.xml.in
index 48cf014..e31cef3 100644
--- a/docs/manual/C/Mousepad.xml.in
+++ b/docs/manual/C/Mousepad.xml.in
@@ -7,7 +7,6 @@
 ]>
 <article id="index" lang="en">
 
-  <!-- Header -->
   <articleinfo>
     <title>Mousepad Text Editor</title>
 
@@ -45,70 +44,334 @@
     </releaseinfo>
   </articleinfo>
 
-  <sect1 id="intro">
-    <title>Introduction to &application;</title>
+  <sect1 id="preface">
+    <title>Preface</title>
 
-    <para>
-      Mousepad 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 Mousepad starts quickly, but
-      also has features like editing multiple documents, vertical selection, type-ahead search, full tab
-      drag and drop and much more.
-    </para>
+    <sect2 id="introduction">
+      <title>Introduction</title>
 
-    <para>
-      Mousepad 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>
+      <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="mousepad">
+    <title>Working With &application;</title>
+
+    <sect2 id="window">
+      <title>Main Window</title>
+
+      <sect3 id="menu-bar">
+        <title>Menu Bar</title>
+      </sect3>
+
+      <sect3 id="statusbar">
+        <title>Statsbar</title>
+      </sect3>
+    </sect2>
+
+    <sect2 id="navigation">
+      <title>Navigation</title>
+
+      <sect3 id="go-to-line">
+        <title>Go To Line</title>
+      </sect3>
+    </sect2>
+
+    <sect2 id="ordering-documents">
+      <title>Ordering Documents</title>
+    </sect2>
+
+    <sect2 id="documents">
+      <title>Documents</title>
+
+      <sect3 id="new-documents">
+        <title>Creating New Documents</title>
+      </sect3>
+
+      <sect3 id="opening-documents">
+        <title>Opening Documents</title>
+      </sect3>
+
+      <sect3 id="recent-documents">
+        <title>Recent Documents</title>
+      </sect3>
+    </sect2>
   </sect1>
 
-  <sect1 id="mousepad-window">
-    <title>The Mousepad Window</title>
+  <sect1 id="text">
+    <title>Working With Text</title>
+
+    <sect2 id="keyboard-shortcuts">
+      <title>Keyboard Shortcuts</title>
+    </sect2>
+
+    <sect2 id="auto-indent">
+      <title>Auto Indent</title>
+    </sect2>
+
+    <sect2 id="selections">
+      <title>Selecting Text</title>
+
+      <sect3 id="multi-and-column-selections">
+        <title>Multi- And Column-Selections</title>
+      </sect3>
+
+      <sect3 id="indentation">
+        <title>Indentation</title>
+      </sect3>
+    </sect2>
+
+    <sect2 id="clipboard">
+      <title>Copy, Cut and Paste From The Clipboard</title>
+    </sect2>
+
+    <sect2 id="search-and-replace">
+      <title>Search And Replace</title>
+    </sect2>
+
+    <sect2 id="tabs">
+      <title>Tabs</title>
+
+      <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>
 
-    <sect2 id="editing-multiple-documents">
-      <title>Editing Multiple Documents</title>
+    <sect3 id="faq-hidden-settings">
+      <title>Does &application; has hidden settings?</title>
 
       <para>
-        By defaul the window hides the tab labels unless more then one document has been opened. If you have
-        more then one document opened, you can switch between then by clicking on the tab, use the
-        <guimenuitem>go</guimenuitem> menu or press the key combination <keycap>Alt</keycap> with the tab number.
+        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>
-        When you have multiple files opened in one window, you detach a document by choosing
-        <menuchoice><guimenu>File</guimenu><guimenuitem>Detach Tab</guimenuitem></menuchoice> or press
-        <keycombo><keycap>Ctrl</keycap><keycap>D</keycap></keycombo>. When Mousepad is compiled with Gtk+ 2.12,
-        it is also possible to drag a tab and drop it on another location on the screen.
+        &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>
-    </sect2>
-  </sect1>
+    </sect3>
 
-  <sect1 id="multi-selection">
-    <title>Multi Editing</title>
+    <sect3 id="faq-assign-keyboard-shortcuts">
+      <title>How do I assign different keyboard shortcuts?</title>
 
-    <para>
-      Mousepad supports multiple- and column-selections. You can start a column selection by pressing the <keycap>Ctrl</keycap>
-      key and starting a drag with your mouse. To add single words to the selection press <keycap>Ctrl</keycap> and double-click
-      a word with the mouse pointer. As long as you press <keycap>Ctrl</keycap> you can add content to the selection.
-    </para>
+      <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>
-      When you've created a multi-selection, it is possible to cut or copy this to the clipboard. When you start typing after a
-      multi-selection, the selected content will be removed and the typed characters will appear in each selected part.
-    </para>
+      <para>
+        To delete a keyboard assignment, press the <keycap>Backspace</keycap> key
+        while you are on the menu entry.
+      </para>
 
-    <para>
-      It is also possible to use this for multi typing. When you press <keycap>Ctrl</keycap> and drag at the end of a couple of lines
-      you will see blue retangles appear at the end of the lines. When you start typing the characters will be added to each selected
-      line. You can add as much of these insert points as you want as long you don't select a whole character.
+      <para>
+        If the shortcut doesn't change, then you need to enable the feature in
+        GTK+. This can be achieved in 3 ways:
+      </para>
 
-      Another useful key combination with multi typing is <keycombo><keycap>Ctrl</keycap><keycap>Backspace</keycap></keycombo>, this will
-      also remove character left or the insert point, while <keycap>Backspace</keycap> only removes characters inside the selection.
-    </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>
 <!--
diff --git a/mousepad/mousepad-document.c b/mousepad/mousepad-document.c
index 7a55dac..3a318e2 100644
--- a/mousepad/mousepad-document.c
+++ b/mousepad/mousepad-document.c
@@ -47,9 +47,6 @@
 static void      mousepad_document_class_init              (MousepadDocumentClass  *klass);
 static void      mousepad_document_init                    (MousepadDocument       *document);
 static void      mousepad_document_finalize                (GObject                *object);
-static void      mousepad_document_notify_has_selection    (GtkTextBuffer          *buffer,
-                                                            GParamSpec             *pspec,
-                                                            MousepadDocument       *document);
 static void      mousepad_document_notify_cursor_position  (GtkTextBuffer          *buffer,
                                                             GParamSpec             *pspec,
                                                             MousepadDocument       *document);
@@ -73,7 +70,6 @@ static void      mousepad_document_tab_button_clicked      (GtkWidget
 enum
 {
   CLOSE_TAB,
-  SELECTION_CHANGED,
   CURSOR_CHANGED,
   OVERWRITE_CHANGED,
   LAST_SIGNAL,
@@ -156,21 +152,13 @@ mousepad_document_class_init (MousepadDocumentClass *klass)
                   g_cclosure_marshal_VOID__VOID,
                   G_TYPE_NONE, 0);
 
-  document_signals[SELECTION_CHANGED] =
-    g_signal_new (I_("selection-changed"),
-                  G_TYPE_FROM_CLASS (gobject_class),
-                  G_SIGNAL_NO_HOOKS,
-                  0, NULL, NULL,
-                  g_cclosure_marshal_VOID__BOOLEAN,
-                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
   document_signals[CURSOR_CHANGED] =
     g_signal_new (I_("cursor-changed"),
                   G_TYPE_FROM_CLASS (gobject_class),
                   G_SIGNAL_NO_HOOKS,
                   0, NULL, NULL,
-                  _mousepad_marshal_VOID__UINT_UINT,
-                  G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+                  _mousepad_marshal_VOID__INT_INT_INT,
+                  G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
 
   document_signals[OVERWRITE_CHANGED] =
     g_signal_new (I_("overwrite-changed"),
@@ -257,7 +245,6 @@ mousepad_document_init (MousepadDocument *document)
   g_free (font_name);
 
   /* attach signals to the text view and buffer */
-  g_signal_connect (G_OBJECT (document->buffer), "notify::has-selection", G_CALLBACK (mousepad_document_notify_has_selection), document);
   g_signal_connect (G_OBJECT (document->buffer), "notify::cursor-position", G_CALLBACK (mousepad_document_notify_cursor_position), document);
   g_signal_connect (G_OBJECT (document->textview), "notify::overwrite", G_CALLBACK (mousepad_document_toggle_overwrite), document);
   g_signal_connect (G_OBJECT (document->textview), "drag-data-received", G_CALLBACK (mousepad_document_drag_data_received), document);
@@ -287,24 +274,6 @@ mousepad_document_finalize (GObject *object)
 }
 
 
-static void
-mousepad_document_notify_has_selection (GtkTextBuffer    *buffer,
-                                        GParamSpec       *pspec,
-                                        MousepadDocument *document)
-{
-  gboolean has_selection;
-
-  _mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
-  _mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
-
-  /* check if we have selected text or not */
-  has_selection = mousepad_view_get_has_selection (document->textview);
-
-  /* emit the signal */
-  g_signal_emit (G_OBJECT (document), document_signals[SELECTION_CHANGED], 0, has_selection);
-}
-
-
 
 static void
 mousepad_document_notify_cursor_position (GtkTextBuffer    *buffer,
@@ -312,7 +281,7 @@ mousepad_document_notify_cursor_position (GtkTextBuffer    *buffer,
                                           MousepadDocument *document)
 {
   GtkTextIter iter;
-  guint       line, column = 0;
+  guint       line, column, selection;
   gint        tab_size;
 
   _mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
@@ -330,8 +299,11 @@ mousepad_document_notify_cursor_position (GtkTextBuffer    *buffer,
   /* get the column */
   column = mousepad_util_get_real_line_offset (&iter, tab_size) + 1;
 
+  /* get length of the selection */
+  selection = mousepad_view_get_selection_length (document->textview);
+
   /* emit the signal */
-  g_signal_emit (G_OBJECT (document), document_signals[CURSOR_CHANGED], 0, line, column);
+  g_signal_emit (G_OBJECT (document), document_signals[CURSOR_CHANGED], 0, line, column, selection);
 }
 
 
@@ -612,36 +584,3 @@ mousepad_document_get_word_wrap (MousepadDocument *document)
 
   return document->priv->word_wrap;
 }
-
-
-
-void
-mousepad_document_get_font_information (MousepadDocument      *document,
-                                        PangoFontDescription **font_desc,
-                                        gint                  *font_height)
-{
-  PangoContext         *context;
-  PangoFontMetrics     *metrics;
-  PangoFontDescription *font;
-
-  /* get the textview context */
-  context = gtk_widget_get_pango_context (GTK_WIDGET (document->textview));
-
-  /* get the font description */
-  font = pango_context_get_font_description (context);
-
-  if (font_desc)
-    *font_desc = font;
-
-  if (G_LIKELY (font_height))
-    {
-      /* get metric information about the font */
-      metrics = pango_context_get_metrics (context, font, pango_context_get_language (context));
-
-      /* calculate the real font height */
-      *font_height = (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)) / PANGO_SCALE;
-
-      /* release the metrics */
-      pango_font_metrics_unref (metrics);
-    }
-}
diff --git a/mousepad/mousepad-document.h b/mousepad/mousepad-document.h
index 0906563..c07f4d5 100644
--- a/mousepad/mousepad-document.h
+++ b/mousepad/mousepad-document.h
@@ -93,10 +93,6 @@ const gchar      *mousepad_document_get_filename             (MousepadDocument
 
 gboolean          mousepad_document_get_word_wrap            (MousepadDocument      *document);
 
-void              mousepad_document_get_font_information     (MousepadDocument      *document,
-                                                              PangoFontDescription **font_desc,
-                                                              gint                  *font_height);
-
 G_END_DECLS
 
 #endif /* !__MOUSEPAD_DOCUMENT_H__ */
diff --git a/mousepad/mousepad-file.c b/mousepad/mousepad-file.c
index a02e28e..b0ed998 100644
--- a/mousepad/mousepad-file.c
+++ b/mousepad/mousepad-file.c
@@ -294,9 +294,13 @@ mousepad_file_open (MousepadFile  *file,
   _mousepad_return_val_if_fail (error == NULL || *error == NULL, FALSE);
   _mousepad_return_val_if_fail (file->filename != NULL, FALSE);
 
-  /* check if the file exists */
+  /* check if the file exists, if not, it's a filename from the command line */
   if (g_file_test (file->filename, G_FILE_TEST_EXISTS) == FALSE)
-    return TRUE;
+    {
+      file->readonly = FALSE;
+      
+      return TRUE;
+    }
 
   /* open the channel */
   channel = g_io_channel_new_file (file->filename, "r", error);
diff --git a/mousepad/mousepad-marshal.list b/mousepad/mousepad-marshal.list
index ba02bfc..4b5c216 100644
--- a/mousepad/mousepad-marshal.list
+++ b/mousepad/mousepad-marshal.list
@@ -1,3 +1,3 @@
-VOID:UINT,UINT
+VOID:INT,INT,INT
 INT:FLAGS,STRING,STRING
 VOID:OBJECT,INT,INT
diff --git a/mousepad/mousepad-preferences.c b/mousepad/mousepad-preferences.c
index 69ff461..86b6b3c 100644
--- a/mousepad/mousepad-preferences.c
+++ b/mousepad/mousepad-preferences.c
@@ -38,6 +38,7 @@
 #include <glib-object.h>
 
 #include <mousepad/mousepad-private.h>
+#include <mousepad/mousepad-util.h>
 #include <mousepad/mousepad-preferences.h>
 
 
@@ -442,11 +443,8 @@ mousepad_preferences_set_property (GObject      *object,
 static void
 mousepad_preferences_check_option_name (GParamSpec *pspec)
 {
-  const gchar *s;
   const gchar *name, *nick;
-  gboolean     upper = TRUE;
   gchar       *option;
-  gchar       *t;
 
   /* get property name and nick */
   name = g_param_spec_get_name (pspec);
@@ -458,27 +456,8 @@ mousepad_preferences_check_option_name (GParamSpec *pspec)
     }
   else
     {
-      /* allocate string for option name */
-      option = g_new (gchar, strlen (name) + 1);
-
-      /* convert name */
-      for (s = name, t = option; *s != '\0'; ++s)
-        {
-          if (*s == '-')
-            {
-              upper = TRUE;
-            }
-          else if (upper)
-            {
-              *t++ = g_ascii_toupper (*s);
-              upper = FALSE;
-            }
-          else
-            {
-              *t++ = *s;
-            }
-        }
-      *t = '\0';
+      /* get option name */
+      option = mousepad_util_config_name (name);
 
       /* compare the strings */
       if (G_UNLIKELY (!option || strcmp (option, nick) != 0))
@@ -505,7 +484,7 @@ mousepad_preferences_load (MousepadPreferences *preferences)
   guint         n;
 
   /* try to open the config file */
-  rc = xfce_rc_config_open (XFCE_RESOURCE_CONFIG, "Mousepad/mousepadrc", TRUE);
+  rc = xfce_rc_config_open (XFCE_RESOURCE_CONFIG, MOUSEPAD_PREFERENCES_REL_PATH, TRUE);
   if (G_UNLIKELY (rc == NULL))
     {
       g_warning (_("Failed to load the preferences."));
@@ -601,7 +580,7 @@ mousepad_preferences_store_idle (gpointer user_data)
   guint                n;
 
   /* open the config file */
-  rc = xfce_rc_config_open (XFCE_RESOURCE_CONFIG, "Mousepad/mousepadrc", FALSE);
+  rc = xfce_rc_config_open (XFCE_RESOURCE_CONFIG, MOUSEPAD_PREFERENCES_REL_PATH, FALSE);
   if (G_UNLIKELY (rc == NULL))
     {
       g_warning (_("Failed to store the preferences."));
diff --git a/mousepad/mousepad-preferences.h b/mousepad/mousepad-preferences.h
index d3161a0..c782432 100644
--- a/mousepad/mousepad-preferences.h
+++ b/mousepad/mousepad-preferences.h
@@ -27,6 +27,8 @@ G_BEGIN_DECLS
 #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))
 
+#define MOUSEPAD_PREFERENCES_REL_PATH         ("Mousepad" G_DIR_SEPARATOR_S "mousepadrc")
+
 typedef struct _MousepadPreferencesClass MousepadPreferencesClass;
 typedef struct _MousepadPreferences      MousepadPreferences;
 
diff --git a/mousepad/mousepad-print.c b/mousepad/mousepad-print.c
index 532103d..94bc85f 100644
--- a/mousepad/mousepad-print.c
+++ b/mousepad/mousepad-print.c
@@ -19,21 +19,44 @@
 #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>
 
-
-
-static void mousepad_print_class_init (MousepadPrintClass *klass);
-static void mousepad_print_init (MousepadPrint *print);
-static void mousepad_print_finalize (GObject *object);
-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_end_print (GtkPrintOperation *operation, GtkPrintContext *context);
-static GtkWidget *mousepad_print_create_custom_widget (GtkPrintOperation *operation);
-static void mousepad_print_status_changed (GtkPrintOperation *operation);
+#define DOCUMENT_SPACING (10)
+
+
+
+static void       mousepad_print_class_init            (MousepadPrintClass      *klass);
+static void       mousepad_print_init                  (MousepadPrint           *print);
+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_end_print             (GtkPrintOperation       *operation,
+                                                        GtkPrintContext         *context);
+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 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);
 
 
 
@@ -47,10 +70,31 @@ struct _MousepadPrint
   GtkPrintOperation __parent__;
 
   /* the document we're going to print */
-  MousepadDocument    *document;
+  MousepadDocument *document;
+
+  /* pango layout containing all text */
+  PangoLayout      *layout;
+
+  /* array with the lines drawn on each page */
+  GArray           *lines;
 
-  /* calculated lines per page */
-  gint                 lines_per_page;
+  /* drawing offsets */
+  gint              x_offset;
+  gint              y_offset;
+
+  /* page line number counter */
+  gint              line_number;
+
+  /* print dialog widgets */
+  GtkWidget        *widget_page_headers;
+  GtkWidget        *widget_line_numbers;
+  GtkWidget        *widget_text_wrapping;
+
+  /* settings */
+  guint             print_page_headers : 1;
+  guint             print_line_numbers : 1;
+  guint             text_wrapping : 1;
+  gchar            *font_name;
 };
 
 
@@ -97,6 +141,7 @@ mousepad_print_class_init (MousepadPrintClass *klass)
   gtkprintoperation_class->end_print = mousepad_print_end_print;
   gtkprintoperation_class->create_custom_widget = mousepad_print_create_custom_widget;
   gtkprintoperation_class->status_changed = mousepad_print_status_changed;
+  gtkprintoperation_class->done = mousepad_print_done;
 }
 
 
@@ -104,8 +149,17 @@ mousepad_print_class_init (MousepadPrintClass *klass)
 static void
 mousepad_print_init (MousepadPrint *print)
 {
+  /* init */
+  print->print_page_headers = FALSE;
+  print->print_line_numbers = FALSE;
+  print->text_wrapping = FALSE;
+  print->x_offset = 0;
+  print->y_offset = 0;
+  print->line_number = 0;
+  print->font_name = NULL;
+
   /* set a custom tab label */
-  //gtk_print_operation_set_custom_tab_label (GTK_PRINT_OPERATION (print), _("Document Settings"));
+  gtk_print_operation_set_custom_tab_label (GTK_PRINT_OPERATION (print), _("Document Settings"));
 }
 
 
@@ -113,103 +167,447 @@ mousepad_print_init (MousepadPrint *print)
 static void
 mousepad_print_finalize (GObject *object)
 {
+  MousepadPrint *print = MOUSEPAD_PRINT (object);
+
+  /* cleanup */
+  g_free (print->font_name);
+
   (*G_OBJECT_CLASS (mousepad_print_parent_class)->finalize) (object);
 }
 
 
 
 static void
-mousepad_print_begin_print (GtkPrintOperation *operation,
-                            GtkPrintContext   *context)
+mousepad_print_settings_load (GtkPrintOperation *operation)
 {
-  MousepadPrint *print = MOUSEPAD_PRINT (operation);
-  gint           n_lines, font_height;
-  gint           page_height, n_pages;
+  MousepadPrint         *print = MOUSEPAD_PRINT (operation);
+  XfceRc                *rc;
+  GtkPrintSettings      *settings = NULL;
+  gchar                **keys;
+  gint                   i;
+  gchar                 *key;
+  const gchar           *value;
+  GtkPageSetup          *page_setup;
+  GtkPaperSize          *paper_size;
+  PangoContext          *context;
+  PangoFontDescription  *font_desc;
 
-  _mousepad_return_if_fail (MOUSEPAD_IS_PRINT (print));
   _mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (print->document));
-  _mousepad_return_if_fail (GTK_IS_TEXT_BUFFER (print->document->buffer));
+  _mousepad_return_if_fail (GTK_IS_WIDGET (print->document->textview));
 
-  /* get the document font information */
-  mousepad_document_get_font_information (print->document, NULL, &font_height);
+  /* open the config file */
+  rc = xfce_rc_config_open (XFCE_RESOURCE_CONFIG, MOUSEPAD_PREFERENCES_REL_PATH, TRUE);
 
-  /* get the number of lines in the buffer */
-  n_lines = gtk_text_buffer_get_line_count (print->document->buffer);
+  if (G_LIKELY (rc != NULL))
+    {
+      /* get all the keys from the config file */
+      keys = xfce_rc_get_entries (rc, "Print Settings");
+
+      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 = xfce_rc_read_entry (rc, 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);
+                }
+            }
+
+          /* cleanup */
+          g_strfreev (keys);
+        }
+
+      /* close */
+      xfce_rc_close (rc);
+    }
 
-  /* get the page height */
-  page_height = gtk_print_context_get_height (context);
+  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 */
+      print->print_page_headers = gtk_print_settings_get_bool (settings, "print-page-headers");
+      print->print_line_numbers = gtk_print_settings_get_bool (settings, "print-line-numbers");
+      print->text_wrapping = gtk_print_settings_get_bool (settings, "text-wrapping");
+      print->font_name = g_strdup (gtk_print_settings_get (settings, "font-name"));
+
+      /* release reference */
+      g_object_unref (G_OBJECT (settings));
+    }
 
-  /* lines per page */
-  print->lines_per_page = page_height / font_height;
+  /* if no font name is set, get the one used in the widget */
+  if (G_UNLIKELY (print->font_name == 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);
+      print->font_name = pango_font_description_to_string (font_desc);
+    }
+}
 
-  /* calculate the number of pages */
-  n_pages = (n_lines / print->lines_per_page) + 1;
 
-  /* set the number of pages */
-  gtk_print_operation_set_n_pages (operation, n_pages);
+
+static void
+mousepad_print_settings_save_foreach (const gchar *key,
+                                      const gchar *value,
+                                      gpointer     user_data)
+{
+  XfceRc *rc = (XfceRc *) user_data;
+  gchar  *config;
+
+  /* save the setting */
+  if (G_LIKELY (key && value))
+    {
+      config = mousepad_util_config_name (key);
+      xfce_rc_write_entry (rc, config, value);
+      g_free (config);
+    }
 }
 
 
 
 static void
-mousepad_print_draw_page (GtkPrintOperation *operation,
-                          GtkPrintContext   *context,
-                          gint               page_nr)
+mousepad_print_settings_save (GtkPrintOperation *operation)
+{
+  MousepadPrint    *print = MOUSEPAD_PRINT (operation);
+  XfceRc           *rc;
+  GtkPrintSettings *settings;
+  GtkPageSetup     *page_setup;
+  GtkPaperSize     *paper_size;
+
+  /* open the config file */
+  rc = xfce_rc_config_open (XFCE_RESOURCE_CONFIG, MOUSEPAD_PREFERENCES_REL_PATH, FALSE);
+
+  if (G_LIKELY (rc != NULL))
+    {
+      /* set print settings group */
+      xfce_rc_set_group (rc, "Print Settings");
+
+      /* 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-page-headers", print->print_page_headers);
+          gtk_print_settings_set_bool (settings, "print-line-numbers", print->print_line_numbers);
+          gtk_print_settings_set_bool (settings, "text-wrapping", print->text_wrapping);
+          gtk_print_settings_set (settings, "font-name", print->font_name);
+
+          /* store all the print settings */
+          gtk_print_settings_foreach (settings, mousepad_print_settings_save_foreach, rc);
+        }
+
+      /* close */
+      xfce_rc_close (rc);
+    }
+}
+
+
+
+static void
+mousepad_print_begin_print (GtkPrintOperation *operation,
+                            GtkPrintContext   *context)
 {
   MousepadPrint        *print = MOUSEPAD_PRINT (operation);
-  PangoLayout          *layout;
+  MousepadDocument     *document = print->document;
+  GtkTextIter           start_iter, end_iter;
+  gint                  page_height;
+  gint                  page_width;
+  gint                  layout_height;
+  PangoRectangle        rect;
   PangoLayoutLine      *line;
   PangoFontDescription *font_desc;
-  gint                  start, end;
-  gint                  i, font_height;
-  GtkTextIter           start_iter, end_iter;
-  MousepadDocument     *document = print->document;
   gchar                *text;
-  cairo_t              *cr;
+  gint                  i;
+  gint                  size;
+  gint                  n_pages = 1;
 
-  _mousepad_return_if_fail (MOUSEPAD_IS_PRINT (print));
+  /* create the pango layout */
+  print->layout = gtk_print_context_create_pango_layout (context);
 
-  /* start and end line in the buffer */
-  start = print->lines_per_page * page_nr;
-  end = start + print->lines_per_page - 1;
+  /* set layout font */
+  font_desc = pango_font_description_from_string (print->font_name);
+  pango_layout_set_font_description (print->layout, font_desc);
+  pango_font_description_free (font_desc);
 
-  /* get the iters */
-  gtk_text_buffer_get_iter_at_line (document->buffer, &start_iter, start);
-  gtk_text_buffer_get_iter_at_line (document->buffer, &end_iter, end);
-  gtk_text_iter_forward_to_line_end (&end_iter);
+  /* calculate page header height */
+  if (print->print_page_headers)
+    {
+      /* set some pango layout text */
+      pango_layout_set_text (print->layout, "Page 1234", -1);
 
-  /* create the pango layout */
-  layout = gtk_print_context_create_pango_layout (context);
+      /* get the height */
+      pango_layout_get_pixel_size (print->layout, NULL, &size);
+
+      /* set the header offset */
+      print->y_offset = size + DOCUMENT_SPACING;
+    }
+
+  /* calculate the line number offset */
+  if (print->print_line_numbers)
+    {
+      /* insert the highest line number in the layout */
+      text = g_strdup_printf ("%d", MAX (99, gtk_text_buffer_get_line_count (document->buffer)));
+      pango_layout_set_text (print->layout, text, -1);
+      g_free (text);
+
+      /* get the width of the layout */
+      pango_layout_get_pixel_size (print->layout, &size, NULL);
 
-  /* get the document font information */
-  mousepad_document_get_font_information (document, &font_desc, &font_height);
+      /* set the text offset */
+      print->x_offset = size + DOCUMENT_SPACING;
+    }
 
-  /* set the layout font description */
-  pango_layout_set_font_description (layout, font_desc);
+  /* set the layout width */
+  page_width = gtk_print_context_get_width (context);
+  pango_layout_set_width (print->layout, PANGO_SCALE * (page_width - print->x_offset));
 
-  /* get the text slice */
+  /* wrapping mode for the layout */
+  pango_layout_set_wrap (print->layout, print->text_wrapping ? PANGO_WRAP_WORD_CHAR : PANGO_WRAP_CHAR);
+
+  /* get the text in the entire buffer */
+  gtk_text_buffer_get_bounds (document->buffer, &start_iter, &end_iter);
   text = gtk_text_buffer_get_slice (document->buffer, &start_iter, &end_iter, TRUE);
 
-  /* set the pango layout text */
-  pango_layout_set_text (layout, text, -1);
+  /* set the layout text */
+  pango_layout_set_text (print->layout, text, -1);
 
   /* cleanup */
   g_free (text);
 
+  /* get the page height in pango units */
+  page_height = gtk_print_context_get_height (context) - print->y_offset;
+
+  /* create and empty array to store the line numbers */
+  print->lines = g_array_new (FALSE, FALSE, sizeof (gint));
+
+  /* reset layout height */
+  layout_height = 0;
+
+  /* start with a zerro */
+  g_array_append_val (print->lines, layout_height);
+
+  for (i = 0; i < pango_layout_get_line_count (print->layout); i++)
+    {
+      /* get the line */
+      line = pango_layout_get_line_readonly (print->layout, i);
+
+      /* if we don't wrap lines, skip the lines that don't start a paragraph */
+      if (print->text_wrapping == FALSE && line->is_paragraph_start == FALSE)
+        continue;
+
+      /* get the line height */
+      pango_layout_line_get_pixel_extents (line, NULL, &rect);
+
+      /* append the height to the total page height */
+      layout_height += rect.height;
+
+      /* check if the layout still fits in the page */
+      if (layout_height > page_height)
+        {
+          /* reset the layout height */
+          layout_height = 0;
+
+          /* increase page counter */
+          n_pages++;
+
+          /* append the line number to the array */
+          g_array_append_val (print->lines, i);
+        }
+    }
+
+  /* append the last line to the array */
+  g_array_append_val (print->lines, i);
+
+  /* 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);
+  MousepadDocument *document = print->document;
+  PangoLayoutLine  *line;
+  cairo_t          *cr;
+  PangoRectangle    rect;
+  gint              i;
+  gint              x, y;
+  gint              width, height;
+  gint              start, end;
+  gchar            *text;
+  PangoLayout      *layout;
+
   /* get the cairo context */
   cr = gtk_print_context_get_cairo_context (context);
 
-  /* show all the lines at the correct position */
-  for (i = 0; i < pango_layout_get_line_count (layout); i++)
+  /* get the start and end line from the array */
+  start = g_array_index (print->lines, gint, page_nr);
+  end = g_array_index (print->lines, gint, page_nr + 1);
+
+  /* set line width */
+  cairo_set_line_width (cr, 1);
+
+  /* create an empty pango layout */
+  layout = gtk_print_context_create_pango_layout (context);
+  pango_layout_set_font_description (layout, pango_layout_get_font_description (print->layout));
+
+  /* print header */
+  if (print->print_page_headers)
+    {
+      /* create page number */
+      text = g_strdup_printf (_("Page %d of %d"), page_nr + 1, print->lines->len - 1);
+      pango_layout_set_text (layout, text, -1);
+      g_free (text);
+
+      /* get layout size */
+      pango_layout_get_pixel_size (layout, &width, &height);
+
+      /* position right of the document */
+      x = gtk_print_context_get_width (context) - width;
+
+      /* show the layout */
+      cairo_move_to (cr, x, 0);
+      pango_cairo_show_layout (cr, layout);
+
+      /* set the layout width of the filename */
+      pango_layout_set_width (layout, PANGO_SCALE * (x - DOCUMENT_SPACING * 2));
+
+      /* ellipsize the start of the filename */
+      pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_START);
+
+      /* set the document filename as text */
+      if (mousepad_document_get_filename (document))
+        pango_layout_set_text (layout, mousepad_document_get_filename (document), -1);
+      else
+        pango_layout_set_text (layout, mousepad_document_get_basename (document), -1);
+
+      /* show the layout */
+      cairo_move_to (cr, 0, 0);
+      pango_cairo_show_layout (cr, layout);
+
+      /* stroke a line under the header */
+      cairo_move_to (cr, 0, height + 1);
+      cairo_rel_line_to (cr, gtk_print_context_get_width (context), 0);
+      cairo_stroke (cr);
+
+      /* restore the layout for the line numbers */
+      pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
+      pango_layout_set_width (layout, -1);
+    }
+
+  /* position and render all lines */
+  for (i = start, y = print->y_offset; i < end; i++)
     {
       /* get the line */
-      line = pango_layout_get_line_readonly (layout, i);
+      line = pango_layout_get_line_readonly (print->layout, i);
 
-      /* move the cairo position */
-      cairo_move_to (cr, 0, font_height * (i + 1));
+      /* if we don't wrap lines, skip the lines that don't start a paragraph */
+      if (print->text_wrapping == FALSE && line->is_paragraph_start == FALSE)
+        continue;
+
+      /* get the line rectangle */
+      pango_layout_line_get_pixel_extents (line, NULL, &rect);
+
+      /* fix the start position */
+      if (G_UNLIKELY (i == start))
+        y -= rect.height / 3;
+
+      /* add the line hight to the top offset */
+      y += rect.height;
+
+      /* move the cursor to the start of the text */
+      cairo_move_to (cr, print->x_offset, y);
 
       /* show the line at the new position */
       pango_cairo_show_layout_line (cr, line);
+
+      /* print line number */
+      if (print->print_line_numbers && line->is_paragraph_start)
+        {
+          /* increase page number */
+          print->line_number++;
+
+          /* render a page number in the layout */
+          text = g_strdup_printf ("%d", print->line_number);
+          pango_layout_set_text (layout, text, -1);
+          g_free (text);
+
+          /* move the cursor to the start of the line */
+          cairo_move_to (cr, 0, y);
+
+          /* pick the first line and draw it on the cairo context */
+          line = pango_layout_get_line_readonly (layout, 0);
+          pango_cairo_show_layout_line (cr, line);
+        }
     }
 
   /* release the layout */
@@ -222,7 +620,73 @@ static void
 mousepad_print_end_print (GtkPrintOperation *operation,
                           GtkPrintContext   *context)
 {
+  MousepadPrint *print = MOUSEPAD_PRINT (operation);
 
+  /* release the layout */
+  g_object_unref (G_OBJECT (print->layout));
+
+  /* free array */
+  g_array_free (print->lines, TRUE);
+}
+
+
+
+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)
+    print->print_page_headers = active;
+  else if (button == print->widget_line_numbers)
+    print->print_line_numbers = active;
+  else if (button == print->widget_text_wrapping)
+    print->text_wrapping = active;
+}
+
+
+
+static void
+mousepad_print_button_font_set (GtkFontButton *button,
+                                MousepadPrint *print)
+{
+  /* remove old font name */
+  g_free (print->font_name);
+
+  /* set new font */
+  print->font_name = g_strdup (gtk_font_button_get_font_name (button));
 }
 
 
@@ -230,7 +694,94 @@ mousepad_print_end_print (GtkPrintOperation *operation,
 static GtkWidget *
 mousepad_print_create_custom_widget (GtkPrintOperation *operation)
 {
-  return NULL;
+  MousepadPrint *print = MOUSEPAD_PRINT (operation);
+  GtkWidget     *button;
+  GtkWidget     *vbox, *vbox2;
+  GtkWidget     *frame;
+  GtkWidget     *alignment;
+  GtkWidget     *label;
+
+  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 (_("<b>Page Setup</b>"));
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+  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 (_("<b>Appearance</b>"));
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+  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), print->print_page_headers);
+  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);
+
+  button = print->widget_text_wrapping = gtk_check_button_new_with_mnemonic (_("Enable text _wrapping"));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), print->text_wrapping);
+  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 (_("<b>Font</b>"));
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+  gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+  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 = gtk_font_button_new_with_font (print->font_name);
+  gtk_container_add (GTK_CONTAINER (alignment), button);
+  g_signal_connect (G_OBJECT (button), "font-set", G_CALLBACK (mousepad_print_button_font_set), print);
+  gtk_widget_show (button);
+
+  return vbox;
 }
 
 
@@ -238,7 +789,21 @@ mousepad_print_create_custom_widget (GtkPrintOperation *operation)
 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);
+    }
 }
 
 
@@ -268,6 +833,12 @@ mousepad_print_document_interactive (MousepadPrint     *print,
   /* set the document */
   print->document = document;
 
+  /* 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,
diff --git a/mousepad/mousepad-print.h b/mousepad/mousepad-print.h
index 45677b7..28011ae 100644
--- a/mousepad/mousepad-print.h
+++ b/mousepad/mousepad-print.h
@@ -30,14 +30,14 @@ typedef struct _MousepadPrint      MousepadPrint;
 #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;
+GType          mousepad_print_get_type             (void) G_GNUC_CONST;
 
-MousepadPrint *mousepad_print_new (void);
+MousepadPrint *mousepad_print_new                  (void);
 
-gboolean mousepad_print_document_interactive (MousepadPrint     *print,
-                                     MousepadDocument  *document,
-                                     GtkWindow         *parent,
-                                     GError           **error);
+gboolean       mousepad_print_document_interactive (MousepadPrint     *print,
+                                                    MousepadDocument  *document,
+                                                    GtkWindow         *parent,
+                                                    GError           **error);
 
 G_END_DECLS
 
diff --git a/mousepad/mousepad-statusbar.c b/mousepad/mousepad-statusbar.c
index 81e851d..613bc05 100644
--- a/mousepad/mousepad-statusbar.c
+++ b/mousepad/mousepad-statusbar.c
@@ -113,7 +113,7 @@ mousepad_statusbar_class_init (MousepadStatusbarClass *klass)
 static void
 mousepad_statusbar_init (MousepadStatusbar *statusbar)
 {
-  GtkWidget    *ebox, *box;
+  GtkWidget    *ebox, *box, *separator;
   GtkStatusbar *bar = GTK_STATUSBAR (statusbar);
 
   /* init statusbar */
@@ -130,11 +130,21 @@ mousepad_statusbar_init (MousepadStatusbar *statusbar)
   gtk_box_pack_start (GTK_BOX (box), bar->label, TRUE, TRUE, 0);
   g_object_unref (G_OBJECT (bar->label));
 
+  /* 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);
@@ -176,14 +186,18 @@ mousepad_statusbar_overwrite_clicked (GtkWidget         *widget,
 void
 mousepad_statusbar_set_cursor_position (MousepadStatusbar *statusbar,
                                         gint               line,
-                                        gint               column)
+                                        gint               column,
+                                        gint               selection)
 {
   gchar string[64];
 
   _mousepad_return_if_fail (MOUSEPAD_IS_STATUSBAR (statusbar));
 
   /* create printable string */
-  g_snprintf (string, sizeof (string), _("Line %d Col %d"), line, column);
+  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);
diff --git a/mousepad/mousepad-statusbar.h b/mousepad/mousepad-statusbar.h
index bd5b265..28c7c59 100644
--- a/mousepad/mousepad-statusbar.h
+++ b/mousepad/mousepad-statusbar.h
@@ -36,7 +36,8 @@ GtkWidget  *mousepad_statusbar_new                  (void);
 
 void        mousepad_statusbar_set_cursor_position  (MousepadStatusbar *statusbar,
                                                      gint               line,
-                                                     gint               column);
+                                                     gint               column,
+                                                     gint               selection);
 
 void        mousepad_statusbar_set_overwrite        (MousepadStatusbar *statusbar,
                                                      gboolean           overwrite);
diff --git a/mousepad/mousepad-util.c b/mousepad/mousepad-util.c
index 4e5a2f8..a0ef459 100644
--- a/mousepad/mousepad-util.c
+++ b/mousepad/mousepad-util.c
@@ -19,11 +19,231 @@
 #include <config.h>
 #endif
 
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
 #include <mousepad/mousepad-private.h>
 #include <mousepad/mousepad-util.h>
 
 
 
+static inline 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;
+}
+
+
+
 GtkWidget *
 mousepad_util_image_button (const gchar *stock_id,
                             const gchar *label)
@@ -291,7 +511,7 @@ mousepad_util_search_iter (const GtkTextIter   *start,
                   gtk_text_iter_forward_char (&iter);
 
                   /* check if we match a whole word */
-                  if (whole_word && !(gtk_text_iter_starts_word (&begin) && gtk_text_iter_ends_word (&iter)))
+                  if (whole_word && !(mousepad_util_iter_starts_word (&begin) && mousepad_util_iter_ends_word (&iter)))
                     goto reset_and_continue_searching;
                 }
               else
@@ -300,7 +520,7 @@ mousepad_util_search_iter (const GtkTextIter   *start,
                   gtk_text_iter_forward_char (&begin);
 
                   /* check if we match a whole word */
-                  if (whole_word && !(gtk_text_iter_starts_word (&iter) && gtk_text_iter_ends_word (&begin)))
+                  if (whole_word && !(mousepad_util_iter_starts_word (&iter) && mousepad_util_iter_ends_word (&begin)))
                     goto reset_and_continue_searching;
                 }
 
diff --git a/mousepad/mousepad-util.h b/mousepad/mousepad-util.h
index 7af6066..b25681a 100644
--- a/mousepad/mousepad-util.h
+++ b/mousepad/mousepad-util.h
@@ -56,39 +56,55 @@ enum _MousepadSearchFlags
   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);
 
-GtkWidget *mousepad_util_image_button           (const gchar         *stock_id,
-                                                 const gchar         *label);
+gboolean   mousepad_util_iter_inside_word         (const GtkTextIter   *iter);
 
-void       mousepad_util_entry_error            (GtkWidget           *widget,
-                                                 gboolean             error);
+gboolean   mousepad_util_iter_forward_word_end    (GtkTextIter         *iter);
 
-void       mousepad_util_dialog_header          (GtkDialog           *dialog,
-                                                 const gchar         *title,
-                                                 const gchar         *subtitle,
-                                                 const gchar         *icon);
+gboolean   mousepad_util_iter_backward_word_start (GtkTextIter         *iter);
 
-void       mousepad_util_set_tooltip            (GtkWidget           *widget,
-                                                 const gchar         *string);
+gboolean   mousepad_util_iter_forward_text_start  (GtkTextIter         *iter);
 
-gint       mousepad_util_get_real_line_offset   (const GtkTextIter   *iter,
-                                                 gint                 tab_size);
+gboolean   mousepad_util_iter_backward_text_start (GtkTextIter         *iter);
 
-gboolean   mousepad_util_forward_iter_to_text   (GtkTextIter         *iter,
-                                                 const GtkTextIter   *limit);
+gchar     *mousepad_util_config_name              (const gchar         *name);
 
-GType      mousepad_util_search_flags_get_type  (void) G_GNUC_CONST;
+gchar     *mousepad_util_key_name                 (const gchar         *name);
 
-gint       mousepad_util_highlight              (GtkTextBuffer       *buffer,
-                                                 GtkTextTag          *tag,
-                                                 const gchar         *string,
-                                                 MousepadSearchFlags  flags);
+GtkWidget *mousepad_util_image_button             (const gchar         *stock_id,
+                                                   const gchar         *label);
 
-gint       mousepad_util_search                 (GtkTextBuffer       *buffer,
-                                                 const gchar         *string,
-                                                 const gchar         *replace,
-                                                 MousepadSearchFlags  flags);
+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);
+
+void       mousepad_util_set_tooltip              (GtkWidget           *widget,
+                                                   const gchar         *string);
+
+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);
+
+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);
 
 G_END_DECLS
 
diff --git a/mousepad/mousepad-view.c b/mousepad/mousepad-view.c
index 2fed762..a91c643 100644
--- a/mousepad/mousepad-view.c
+++ b/mousepad/mousepad-view.c
@@ -31,8 +31,7 @@
 
 
 
-#define mousepad_view_get_buffer(view)      (GTK_TEXT_VIEW (view)->buffer)
-#define MOUSEPAD_VIEW_RECT_WIDTH            (3)
+#define mousepad_view_get_buffer(view) (GTK_TEXT_VIEW (view)->buffer)
 
 
 
@@ -49,21 +48,21 @@ static gboolean  mousepad_view_button_press_event            (GtkWidget
                                                               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,
                                                               GdkEventKey        *event,
                                                               guint               modifiers);
 static void      mousepad_view_selection_delete_content      (MousepadView       *view);
 static void      mousepad_view_selection_destroy             (MousepadView       *view);
-static void      mousepad_view_selection_add_word            (MousepadView       *view);
 static void      mousepad_view_selection_cleanup_equal_marks (MousepadView       *view);
 static void      mousepad_view_selection_add_marks           (MousepadView       *view,
                                                               GtkTextIter        *start_iter,
                                                               GtkTextIter        *end_iter);
 static void      mousepad_view_selection_draw                (MousepadView       *view,
-                                                              gboolean            draw_rectangles,
+                                                              gboolean            draw_cursors,
                                                               gboolean            add_marks);
-static void      mousepad_view_selection_emit_has_selection  (MousepadView       *view,
-                                                              gboolean            has_content);
 static gboolean  mousepad_view_selection_timeout             (gpointer            user_data);
 static void      mousepad_view_selection_timeout_destroy     (gpointer            user_data);
 static void      mousepad_view_indent_increase               (MousepadView       *view,
@@ -77,6 +76,8 @@ static gchar    *mousepad_view_indent_string                 (GtkTextBuffer
 static gint      mousepad_view_calculate_layout_width        (GtkWidget          *widget,
                                                               gsize               length,
                                                               gchar               fill_char);
+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);
@@ -124,6 +125,9 @@ struct _MousepadView
   gint                selection_end_x;
   gint                selection_end_y;
 
+  /* length of the selection */
+  gint                selection_length;
+
   /* settings */
   guint               auto_indent : 1;
   guint               line_numbers : 1;
@@ -193,6 +197,7 @@ mousepad_view_init (MousepadView *view)
   view->flags = 0;
   view->selection_tag = NULL;
   view->marks = NULL;
+  view->selection_length = 0;
 }
 
 
@@ -497,7 +502,7 @@ mousepad_view_key_press_event (GtkWidget   *widget,
               {
                 goto selection_key_press;
               }
-            else if (mousepad_view_get_has_selection (view))
+            else if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
               {
                 /* indent the selection */
                 mousepad_view_indent_selection (view, (modifiers & GDK_SHIFT_MASK));
@@ -551,40 +556,68 @@ static gboolean
 mousepad_view_button_press_event (GtkWidget      *widget,
                                   GdkEventButton *event)
 {
-  MousepadView *view = MOUSEPAD_VIEW (widget);
-  GtkTextView  *textview = GTK_TEXT_VIEW (widget);;
+  MousepadView  *view = MOUSEPAD_VIEW (widget);
+  GtkTextView   *textview = GTK_TEXT_VIEW (widget);
+  GtkTextIter    iter, start_iter, end_iter;
+  GtkTextBuffer *buffer;
 
   /* work with vertical selection while ctrl is pressed */
   if (event->state & GDK_CONTROL_MASK
       && event->x >= 0
       && event->y >= 0
-      && event->button == 1)
+      && event->button == 1
+      && event->type == GDK_BUTTON_PRESS)
     {
       /* set the vertical selection start position, inclusing textview offset */
       view->selection_start_x = event->x + textview->xoffset;
       view->selection_start_y = event->y + textview->yoffset;
 
-      if (event->type == GDK_BUTTON_PRESS)
-        {
-          /* whether this is going to be a multiple selection */
-          if (view->flags != 0)
-            MOUSEPAD_SET_FLAG (view->flags, MULTIPLE);
+      /* whether this is going to be a multiple selection */
+      if (view->flags != 0)
+        MOUSEPAD_SET_FLAG (view->flags, MULTIPLE);
 
-          /* enable dragging */
-          MOUSEPAD_SET_FLAG (view->flags, DRAGGING);
+      /* enable dragging */
+      MOUSEPAD_SET_FLAG (view->flags, DRAGGING);
 
-          /* 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);
-        }
-      else if (event->type == GDK_2BUTTON_PRESS)
+      /* 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) /* todo, button 1 en pos x coords */
+    {
+      /* 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))
         {
-          /* whether this is going to be a multiple selection */
-          if (view->flags != 0)
-            MOUSEPAD_SET_FLAG (view->flags, MULTIPLE);
+          /* get buffer */
+          buffer = mousepad_view_get_buffer (view);
+
+          /* add to normal selection or multiple selection */
+          if (event->state & GDK_CONTROL_MASK)
+            {
+              /* make it a multiple selection when there is already something selected */
+              if (view->flags != 0)
+                MOUSEPAD_SET_FLAG (view->flags, MULTIPLE);
 
-          /* add the word under the cursor to the selection */
-          mousepad_view_selection_add_word (view);
+              /* add to the list */
+              mousepad_view_selection_add_marks (view, &start_iter, &end_iter);
+
+              /* redraw */
+              mousepad_view_selection_draw (view, FALSE, FALSE);
+
+              /* set the cursor at the end of the word */
+              gtk_text_buffer_place_cursor (buffer, &end_iter);
+            }
+          else
+            {
+              /* select range */
+              gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
+            }
         }
 
       return TRUE;
@@ -631,6 +664,46 @@ mousepad_view_button_release_event (GtkWidget      *widget,
 /**
  * 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,
                                          GdkEventKey  *event,
@@ -711,11 +784,10 @@ mousepad_view_selection_key_press_event (MousepadView *view,
       li = li->next;
     }
 
+  /* TODO content */
+
   /* end user action */
   gtk_text_buffer_end_user_action (buffer);
-
-  /* update selection status */
-  mousepad_view_selection_emit_has_selection (view, has_content);
 }
 
 
@@ -753,11 +825,11 @@ mousepad_view_selection_delete_content (MousepadView *view)
       gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
     }
 
+  /* set the selection length to zerro */
+  view->selection_length = 0;
+
   /* end user action */
   gtk_text_buffer_end_user_action (buffer);
-
-  /* update selection status */
-  mousepad_view_selection_emit_has_selection (view, FALSE);
 }
 
 
@@ -796,46 +868,8 @@ mousepad_view_selection_destroy (MousepadView *view)
   /* reset status */
   view->flags = 0;
 
-  /* update selection status */
-  mousepad_view_selection_emit_has_selection (view, FALSE);
-}
-
-
-
-static void
-mousepad_view_selection_add_word (MousepadView *view)
-{
-  GtkTextBuffer *buffer;
-  GtkTextIter    start_iter, end_iter;
-
-  /* get buffer */
-  buffer = mousepad_view_get_buffer (view);
-
-  /* get the iter at the start coordinate */
-  gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &start_iter, view->selection_start_x, view->selection_start_y);
-
-  /* move the iter to the start of the word */
-  while (!gtk_text_iter_starts_word (&start_iter))
-    if (!gtk_text_iter_backward_char (&start_iter))
-      break;
-
-  /* set end iter */
-  end_iter = start_iter;
-
-  /* walk forward to end of the word */
-  while (!gtk_text_iter_ends_word (&end_iter))
-    if (!gtk_text_iter_forward_char (&end_iter))
-      break;
-
-  /* add the section when the iters are not equal */
-  if (!gtk_text_iter_equal (&start_iter, &end_iter))
-    {
-      /* add to the list */
-      mousepad_view_selection_add_marks (view, &start_iter, &end_iter);
-
-      /* redraw */
-      mousepad_view_selection_draw (view, FALSE, FALSE);
-    }
+  /* set selection length to zerro */
+  view->selection_length = 0;
 }
 
 
@@ -885,7 +919,7 @@ mousepad_view_selection_add_marks (MousepadView *view,
   GSList        *li, *lnext;
   gboolean       is_start = FALSE;
   gboolean       handled_start = FALSE;
-  gint           compare;
+  gint           compare, length;
 
   _mousepad_return_if_fail (view->marks == NULL || g_slist_length (view->marks) % 2 == 0);
 
@@ -895,6 +929,12 @@ mousepad_view_selection_add_marks (MousepadView *view,
   /* get buffer */
   buffer = mousepad_view_get_buffer (view);
 
+  /* calculate length of selection */
+  length = gtk_text_iter_get_line_offset (end_iter) - gtk_text_iter_get_line_offset (start_iter);
+
+  /* add to selection length */
+  view->selection_length += length;
+
   /* 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);
@@ -983,12 +1023,13 @@ mousepad_view_selection_add_marks (MousepadView *view,
 
 static void
 mousepad_view_selection_draw (MousepadView *view,
-                              gboolean      draw_rectangles,
+                              gboolean      draw_cursors,
                               gboolean      add_marks)
 {
   GtkTextBuffer *buffer;
   GtkTextView   *textview = GTK_TEXT_VIEW (view);
   GtkTextIter    start_iter, end_iter;
+  gint           line_x, line_y;
   gint           y, y_begin, y_height, y_end;
   gboolean       has_content = FALSE;
   GdkRectangle   rect;
@@ -1024,16 +1065,19 @@ mousepad_view_selection_draw (MousepadView *view,
       /* next element in the list */
       li = li->next;
 
-      if (draw_rectangles)
+      if (draw_cursors)
         {
           /* get the iter location and size */
           gtk_text_view_get_iter_location (textview, &start_iter, &rect);
 
-          /* draw a thin retangle in front of the iter */
-          gdk_draw_rectangle (GDK_DRAWABLE (window),
-                              GTK_WIDGET (view)->style->base_gc[GTK_STATE_SELECTED],
-                              TRUE, rect.x - textview->xoffset, rect.y - textview->yoffset,
-                              MOUSEPAD_VIEW_RECT_WIDTH, rect.height);
+          /* 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->text_gc[GTK_STATE_NORMAL],
+                         line_x, line_y, line_x, line_y + rect.height - 1);
         }
       else
         {
@@ -1076,16 +1120,19 @@ mousepad_view_selection_draw (MousepadView *view,
           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);
 
-          if (draw_rectangles)
+          if (draw_cursors)
             {
               /* get the iter location and size */
               gtk_text_view_get_iter_location (textview, &end_iter, &rect);
 
-              /* draw a thin retangle in front of the iter */
-              gdk_draw_rectangle (GDK_DRAWABLE (window),
-                                  GTK_WIDGET (view)->style->base_gc[GTK_STATE_SELECTED],
-                                  TRUE, rect.x - textview->xoffset, rect.y - textview->yoffset,
-                                  MOUSEPAD_VIEW_RECT_WIDTH, rect.height);
+              /* 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->text_gc[GTK_STATE_NORMAL],
+                             line_x, line_y, line_x, line_y + rect.height - 1);
             }
           else if (!gtk_text_iter_equal (&start_iter, &end_iter))
             {
@@ -1109,50 +1156,25 @@ mousepad_view_selection_draw (MousepadView *view,
               mousepad_view_selection_add_marks (view, &start_iter, &end_iter);
             }
         }
+
+      /* update selection status */
+      g_object_notify (G_OBJECT (buffer), "cursor-position");
     }
 
   /* update status when marks have been added */
   if (add_marks && has_content && MOUSEPAD_HAS_FLAG (view->flags, MULTIPLE))
     mousepad_view_selection_cleanup_equal_marks (view);
 
+  if (has_content)
+    MOUSEPAD_SET_FLAG (view->flags, HAS_CONTENT);
+  else
+    MOUSEPAD_UNSET_FLAG (view->flags, HAS_CONTENT);
+
   /* there is something in the list, prevent 0 flag */
   if (view->marks != NULL)
     MOUSEPAD_SET_FLAG (view->flags, HAS_SELECTION);
 
-  /* update selection status */
-  mousepad_view_selection_emit_has_selection (view, has_content);
-}
-
-
-
-static void
-mousepad_view_selection_emit_has_selection (MousepadView *view,
-                                            gboolean      has_content)
-{
-  GtkTextBuffer *buffer;
-
-  /* jump when there is not selection */
-  if (view->flags == 0)
-    goto emit_has_selection;
-
-  /* check if we need to emit */
-  if (has_content != MOUSEPAD_HAS_FLAG (view->flags, HAS_CONTENT))
-    {
-      /* update flag */
-      if (has_content)
-        MOUSEPAD_SET_FLAG (view->flags, HAS_CONTENT);
-      else
-        MOUSEPAD_UNSET_FLAG (view->flags, HAS_CONTENT);
-
-      /* label */
-      emit_has_selection:
-
-      /* get the buffer */
-      buffer = mousepad_view_get_buffer (view);
 
-      buffer->has_selection = has_content;
-      g_object_notify (G_OBJECT (buffer), "has-selection");
-    }
 }
 
 
@@ -1505,6 +1527,59 @@ mousepad_view_put_cursor_on_screen (MousepadView *view)
 
 
 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->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->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)
@@ -1601,68 +1676,78 @@ mousepad_view_transpose_lines (GtkTextBuffer *buffer,
   gtk_text_buffer_get_iter_at_line (buffer, start_iter, start_line);
 }
 
-
-
 static void
 mousepad_view_transpose_words (GtkTextBuffer *buffer,
                                GtkTextIter   *iter)
 {
-  GtkTextIter  start_one, end_one, end_two;
-  gchar       *word_left, *word_right, *word_space;
-
-  /* move the iter to the start of first word */
-  gtk_text_iter_backward_word_start (iter);
-  start_one = *iter;
-  if (!gtk_text_iter_starts_word (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;
 
-  /* move to end of first word */
-  gtk_text_iter_forward_word_end (iter);
-  end_one = *iter;
-  if (!gtk_text_iter_ends_word (iter))
+  /* left word start */
+  start_left = end_left;
+  if (!mousepad_util_iter_backward_word_start (&start_left))
     return;
 
-  /* move to end of second word */
-  gtk_text_iter_forward_word_end (iter);
-  end_two = *iter;
-  if (!gtk_text_iter_ends_word (iter))
+  /* right word start */
+  start_right = *iter;
+  if (!mousepad_util_iter_forward_text_start (&start_right))
     return;
 
-  /* move to start of second word */
-  gtk_text_iter_backward_word_start (iter);
-  if (!gtk_text_iter_starts_word (iter))
+  /* right word end */
+  end_right = start_right;
+  if (!mousepad_util_iter_forward_word_end (&end_right))
     return;
 
-  /* only do this on the same line */
-  if (gtk_text_iter_get_line (&start_one) != gtk_text_iter_get_line (&end_two))
-    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);
 
-  /* get the three parts */
-  word_left = gtk_text_buffer_get_slice (buffer, &start_one, &end_one, FALSE);
-  word_space = gtk_text_buffer_get_slice (buffer, &end_one, iter, FALSE);
-  word_right = gtk_text_buffer_get_slice (buffer, iter, &end_two, FALSE);
+      /* check if we need to restore the cursor afterwards */
+      restore_cursor = gtk_text_iter_equal (iter, &start_right);
 
-  /* build string */
-  gtk_text_buffer_delete (buffer, &start_one, &end_two);
-  *iter = end_two;
+      /* 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);
 
-  /* insert right word */
-  gtk_text_buffer_insert (buffer, iter, word_right, -1);
-  g_free (word_right);
+      /* 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);
 
-  /* insert space */
-  gtk_text_buffer_insert (buffer, iter, word_space, -1);
-  g_free (word_space);
+      /* 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);
 
-  /* insert left word */
-  gtk_text_buffer_insert (buffer, iter, word_left, -1);
-  g_free (word_left);
+      /* 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);
 
-  /* return valid iter */
-  gtk_text_iter_backward_word_start (iter);
+      /* 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);
+        }
 
-  /* place cursor */
-  gtk_text_buffer_place_cursor (buffer, iter);
+      /* cleanup the marks */
+      gtk_text_buffer_delete_mark (buffer, left_mark);
+      gtk_text_buffer_delete_mark (buffer, right_mark);
+    }
 }
 
 
@@ -1683,7 +1768,8 @@ mousepad_view_transpose (MousepadView *view)
 
   if (view->flags != 0)
     {
-
+      /* transpose a multi selection */
+      mousepad_view_transpose_multi_selection (buffer, view);
     }
   else if (gtk_text_buffer_get_selection_bounds (buffer, &sel_start, &sel_end))
     {
@@ -1722,7 +1808,7 @@ mousepad_view_transpose (MousepadView *view)
           if (gtk_text_iter_forward_line (&sel_end))
             mousepad_view_transpose_lines (buffer, &sel_start, &sel_end);
         }
-      else if (gtk_text_iter_inside_word (&sel_start) && !gtk_text_iter_starts_word (&sel_start))
+      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))
@@ -1748,7 +1834,7 @@ mousepad_view_clipboard_cut (MousepadView *view)
   GtkTextBuffer *buffer;
 
   _mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
-  _mousepad_return_if_fail (mousepad_view_get_has_selection (view));
+  _mousepad_return_if_fail (mousepad_view_get_selection_length (view) > 0);
 
   /* get the clipboard */
   clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view), GDK_SELECTION_CLIPBOARD);
@@ -1786,7 +1872,7 @@ mousepad_view_clipboard_copy (MousepadView *view)
   GtkTextBuffer *buffer;
 
   _mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
-  _mousepad_return_if_fail (mousepad_view_get_has_selection (view));
+  _mousepad_return_if_fail (mousepad_view_get_selection_length (view) > 0);
 
   /* get the clipboard */
   clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view), GDK_SELECTION_CLIPBOARD);
@@ -1909,7 +1995,7 @@ mousepad_view_delete_selection (MousepadView *view)
   GtkTextBuffer *buffer;
 
   _mousepad_return_if_fail (MOUSEPAD_IS_VIEW (view));
-  _mousepad_return_if_fail (mousepad_view_get_has_selection (view));
+  _mousepad_return_if_fail (mousepad_view_get_selection_length (view) > 0);
 
   if (view->flags != 0)
     {
@@ -2038,21 +2124,31 @@ mousepad_view_set_insert_spaces (MousepadView *view,
 
 
 gboolean
-mousepad_view_get_has_selection (MousepadView *view)
+mousepad_view_get_selection_length (MousepadView *view)
 {
   GtkTextBuffer *buffer;
+  GtkTextIter    sel_start, sel_end;
+  gint           sel_length = 0;
 
   _mousepad_return_val_if_fail (MOUSEPAD_IS_VIEW (view), FALSE);
 
-  /* we have a vertical selection */
-  if (view->flags != 0)
-    return TRUE;
-
   /* get the text buffer */
   buffer = mousepad_view_get_buffer (view);
 
-  /* normal selection */
-  return gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL);
+  /* we have a vertical selection */
+  if (view->flags != 0)
+    {
+      /* 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));
+    }
+
+  /* return length */
+  return sel_length;
 }
 
 
diff --git a/mousepad/mousepad-view.h b/mousepad/mousepad-view.h
index 8a1933f..7623fc3 100644
--- a/mousepad/mousepad-view.h
+++ b/mousepad/mousepad-view.h
@@ -60,7 +60,7 @@ void            mousepad_view_set_tab_size              (MousepadView      *view
 void            mousepad_view_set_insert_spaces         (MousepadView      *view,
                                                          gboolean           insert_spaces);
 
-gboolean        mousepad_view_get_has_selection         (MousepadView      *view);
+gint            mousepad_view_get_selection_length      (MousepadView      *view);
 
 gboolean        mousepad_view_get_line_numbers          (MousepadView      *view);
 
diff --git a/mousepad/mousepad-window.c b/mousepad/mousepad-window.c
index e68914c..504ce43 100644
--- a/mousepad/mousepad-window.c
+++ b/mousepad/mousepad-window.c
@@ -139,15 +139,13 @@ static GtkNotebook      *mousepad_window_notebook_create_window       (GtkNotebo
 /* document signals */
 static void              mousepad_window_modified_changed             (MousepadWindow         *window);
 static void              mousepad_window_cursor_changed               (MousepadDocument       *document,
-                                                                       guint                   line,
-                                                                       guint                   column,
+                                                                       gint                    line,
+                                                                       gint                    column,
+                                                                       gint                    selection,
                                                                        MousepadWindow         *window);
 static void              mousepad_window_overwrite_changed            (MousepadDocument       *document,
                                                                        gboolean                overwrite,
                                                                        MousepadWindow         *window);
-static void              mousepad_window_selection_changed            (MousepadDocument       *document,
-                                                                       gboolean                selected,
-                                                                       MousepadWindow         *window);
 static void              mousepad_window_can_undo                     (MousepadWindow         *window,
                                                                        gboolean                can_undo);
 static void              mousepad_window_can_redo                     (MousepadWindow         *window,
@@ -329,8 +327,8 @@ struct _MousepadWindow
 static const GtkActionEntry action_entries[] =
 {
   { "file-menu", NULL, N_("_File"), NULL, NULL, NULL, },
-    { "new-tab", "tab-new", N_("New Documen_t"), "<control>T", N_("Create a new document"), G_CALLBACK (mousepad_window_action_open_new_tab), },
-    { "new-window", "window-new", N_("_New Window"), "<control>N", N_("Create a new document in a new window"), G_CALLBACK (mousepad_window_action_open_new_window), },
+    { "new-tab", "tab-new", N_("New Documen_t"), "<control>N", N_("Create a new document"), G_CALLBACK (mousepad_window_action_open_new_tab), },
+    { "new-window", "window-new", N_("_New Window"), "<shift><control>N", N_("Create a new document in a new window"), G_CALLBACK (mousepad_window_action_open_new_window), },
     { "open-file", GTK_STOCK_OPEN, N_("_Open File"), NULL, N_("Open a file"), G_CALLBACK (mousepad_window_action_open_file), },
     { "recent-menu", NULL, N_("Open _Recent"), NULL, NULL, NULL, },
       { "no-recent-items", NULL, N_("No items found"), NULL, NULL, NULL, },
@@ -352,7 +350,7 @@ static const GtkActionEntry action_entries[] =
     { "paste-column", GTK_STOCK_PASTE, N_("Paste _Column"), "<control><shift>V", N_("Paste the clipboard text in a clumn"), G_CALLBACK (mousepad_window_action_paste_column), },
     { "delete", GTK_STOCK_DELETE, NULL, NULL, N_("Delete the selected text"), G_CALLBACK (mousepad_window_action_delete), },
     { "select-all", GTK_STOCK_SELECT_ALL, NULL, NULL, N_("Select the entire document"), G_CALLBACK (mousepad_window_action_select_all), },
-    { "transpose", NULL, N_("_Transpose"), NULL, N_("Reverse the order of something"), G_CALLBACK (mousepad_window_action_transpose), },
+    { "transpose", NULL, N_("_Transpose"), "<control>T", N_("Reverse the order of something"), G_CALLBACK (mousepad_window_action_transpose), },
 
   { "search-menu", NULL, N_("_Search"), NULL, NULL, NULL, },
     { "find", GTK_STOCK_FIND, NULL, NULL, N_("Search for text"), G_CALLBACK (mousepad_window_action_find), },
@@ -1227,7 +1225,6 @@ mousepad_window_notebook_added (GtkNotebook     *notebook,
 
   /* 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), "selection-changed", G_CALLBACK (mousepad_window_selection_changed), window);
   g_signal_connect (G_OBJECT (page), "cursor-changed", G_CALLBACK (mousepad_window_cursor_changed), window);
   g_signal_connect (G_OBJECT (page), "overwrite-changed", G_CALLBACK (mousepad_window_overwrite_changed), window);
   g_signal_connect (G_OBJECT (page), "drag-data-received", G_CALLBACK (mousepad_window_drag_data_received), window);
@@ -1273,7 +1270,6 @@ mousepad_window_notebook_removed (GtkNotebook     *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_selection_changed, 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_overwrite_changed, window);
   g_signal_handlers_disconnect_by_func (G_OBJECT (page), mousepad_window_drag_data_received, window);
@@ -1446,16 +1442,33 @@ mousepad_window_modified_changed (MousepadWindow   *window)
 
 static void
 mousepad_window_cursor_changed (MousepadDocument *document,
-                                guint             line,
-                                guint             column,
+                                gint              line,
+                                gint              column,
+                                gint              selection,
                                 MousepadWindow   *window)
 {
+  GtkAction *action;
+  gboolean   has_selection;
+
   _mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
   _mousepad_return_if_fail (MOUSEPAD_IS_DOCUMENT (document));
 
-  /* set the new statusbar position */
+  /* set the new statusbar cursor position and selection length */
   if (window->statusbar)
-    mousepad_statusbar_set_cursor_position (MOUSEPAD_STATUSBAR (window->statusbar), line, column);
+    mousepad_statusbar_set_cursor_position (MOUSEPAD_STATUSBAR (window->statusbar), line, column, selection);
+
+  /* whether we have a selection */
+  has_selection = (selection > 0);
+
+  /* update actions */
+  action = gtk_action_group_get_action (window->action_group, "cut");
+  gtk_action_set_sensitive (action, has_selection);
+
+  action = gtk_action_group_get_action (window->action_group, "copy");
+  gtk_action_set_sensitive (action, has_selection);
+
+  action = gtk_action_group_get_action (window->action_group, "delete");
+  gtk_action_set_sensitive (action, has_selection);
 }
 
 
@@ -1476,25 +1489,6 @@ mousepad_window_overwrite_changed (MousepadDocument *document,
 
 
 static void
-mousepad_window_selection_changed (MousepadDocument *document,
-                                   gboolean          selected,
-                                   MousepadWindow   *window)
-{
-  GtkAction *action;
-
-  action = gtk_action_group_get_action (window->action_group, "cut");
-  gtk_action_set_sensitive (action, selected);
-
-  action = gtk_action_group_get_action (window->action_group, "copy");
-  gtk_action_set_sensitive (action, selected);
-
-  action = gtk_action_group_get_action (window->action_group, "delete");
-  gtk_action_set_sensitive (action, selected);
-}
-
-
-
-static void
 mousepad_window_can_undo (MousepadWindow *window,
                           gboolean        can_undo)
 {
@@ -1708,7 +1702,6 @@ mousepad_window_update_actions (MousepadWindow *window)
   gboolean          cycle_tabs;
   gint              n_pages;
   gint              page_num;
-  gboolean          has_selection;
   gboolean          active;
 
   _mousepad_return_if_fail (MOUSEPAD_IS_WINDOW (window));
@@ -1769,10 +1762,6 @@ mousepad_window_update_actions (MousepadWindow *window)
       mousepad_window_can_undo (window, mousepad_undo_can_undo (document->undo));
       mousepad_window_can_redo (window, mousepad_undo_can_redo (document->undo));
 
-      /* set the sensitivity of the selection actions */
-      has_selection = mousepad_view_get_has_selection (document->textview);
-      mousepad_window_selection_changed (document, has_selection, window);
-
       /* active this tab in the go menu */
       action = g_object_get_data (G_OBJECT (document), I_("navigation-menu-action"));
       if (G_LIKELY (action != NULL))
@@ -2579,6 +2568,9 @@ mousepad_window_action_save_file (GtkAction      *action,
           /* save the document */
           succeed = mousepad_file_save (document->file, &error);
 
+          /* update the window title */
+          mousepad_window_set_title (window);
+
           if (G_UNLIKELY (succeed == FALSE))
             {
               /* show the warning */


More information about the Xfce4-commits mailing list