diff --git gtk/gtktextdisplay.c gtk/gtktextdisplay.c
index 42928f1..3c23657 100644
--- gtk/gtktextdisplay.c
+++ gtk/gtktextdisplay.c
@@ -81,6 +81,7 @@
 #include "gtkstylecontextprivate.h"
 #include "gtkintl.h"
 
+#include <math.h>
 /* DO NOT go putting private headers in here. This file should only
  * use the semi-public headers, as with gtktextview.c.
  */
@@ -572,6 +573,8 @@ render_para (GtkTextRenderer    *text_renderer,
   GdkRGBA selection;
   gboolean first = TRUE;
 
+  gboolean write_vertical = FALSE;
+
   iter = pango_layout_get_iter (layout);
 
   pango_layout_iter_get_layout_extents (iter, NULL, &layout_logical);
@@ -585,6 +588,7 @@ render_para (GtkTextRenderer    *text_renderer,
 
   context = gtk_widget_get_style_context (text_renderer->widget);
   state = gtk_widget_get_state_flags (text_renderer->widget);
+  write_vertical = gtk_text_view_get_write_vertical (GTK_TEXT_VIEW(text_renderer->widget));
 
   state |= GTK_STATE_FLAG_SELECTED;
 
@@ -634,17 +638,27 @@ render_para (GtkTextRenderer    *text_renderer,
 
           cairo_save (cr);
           gdk_cairo_set_source_rgba (cr, &selection);
-          cairo_rectangle (cr, 
+
+          if(write_vertical)
+            cairo_rotate(cr, M_PI/2);
+
+          cairo_rectangle (cr,
                            line_display->left_margin, selection_y,
                            screen_width, selection_height);
           cairo_fill (cr);
           cairo_restore(cr);
 
-	  text_renderer_set_state (text_renderer, SELECTED);
-	  pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
-					   line, 
-					   line_rect.x,
-					   baseline);
+          text_renderer_set_state (text_renderer, SELECTED);
+          cairo_save(text_renderer->cr);
+
+          if(write_vertical)
+            cairo_rotate(text_renderer->cr, M_PI/2);
+
+          pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
+                                           line,
+                                           line_rect.x,
+                                           baseline);
+          cairo_restore(text_renderer->cr);
         }
       else
         {
@@ -654,7 +668,7 @@ render_para (GtkTextRenderer    *text_renderer,
 
               cairo_save (cr);
  
-	      gdk_cairo_set_source_rgba (text_renderer->cr, line_display->pg_bg_rgba);
+              gdk_cairo_set_source_rgba (text_renderer->cr, line_display->pg_bg_rgba);
               cairo_rectangle (cr, 
                                line_display->left_margin, selection_y,
                                screen_width, selection_height);
@@ -663,26 +677,34 @@ render_para (GtkTextRenderer    *text_renderer,
               cairo_restore (cr);
             }
         
-	  text_renderer_set_state (text_renderer, NORMAL);
-	  pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
-					   line, 
-					   line_rect.x,
-					   baseline);
-
-	  /* Check if some part of the line is selected; the newline
-	   * that is after line->length for the last line of the
-	   * paragraph counts as part of the line for this
-	   */
+          text_renderer_set_state (text_renderer, NORMAL);
+
+          cairo_save(text_renderer->cr);
+
+          if(write_vertical)
+            cairo_rotate(text_renderer->cr, M_PI/2);
+
+          pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
+                                           line,
+                                           line_rect.x,
+                                           baseline);
+
+          cairo_restore(text_renderer->cr);
+
+          /* Check if some part of the line is selected; the newline
+           * that is after line->length for the last line of the
+           * paragraph counts as part of the line for this
+           */
           if ((selection_start_index < byte_offset + line->length ||
-	       (selection_start_index == byte_offset + line->length && pango_layout_iter_at_last_line (iter))) &&
-	      selection_end_index > byte_offset)
+               (selection_start_index == byte_offset + line->length && pango_layout_iter_at_last_line (iter))) &&
+              selection_end_index > byte_offset)
             {
               cairo_t *cr = text_renderer->cr;
               cairo_region_t *clip_region = get_selected_clip (text_renderer, layout, line,
-                                                          line_display->x_offset,
-                                                          selection_y,
-                                                          selection_height,
-                                                          selection_start_index, selection_end_index);
+                                                               line_display->x_offset,
+                                                               selection_y,
+                                                               selection_height,
+                                                               selection_start_index, selection_end_index);
 
               cairo_save (cr);
               gdk_cairo_region (cr, clip_region);
@@ -690,6 +712,10 @@ render_para (GtkTextRenderer    *text_renderer,
               cairo_region_destroy (clip_region);
 
               gdk_cairo_set_source_rgba (cr, &selection);
+
+              if(write_vertical )
+                cairo_rotate(cr, M_PI/2);
+
               cairo_rectangle (cr,
                                PANGO_PIXELS (line_rect.x),
                                selection_y,
@@ -697,11 +723,15 @@ render_para (GtkTextRenderer    *text_renderer,
                                selection_height);
               cairo_fill (cr);
 
-	      text_renderer_set_state (text_renderer, SELECTED);
-	      pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
-					       line, 
-					       line_rect.x,
-					       baseline);
+              text_renderer_set_state (text_renderer, SELECTED);
+
+              if(write_vertical)
+                cairo_rotate(text_renderer->cr, M_PI/2);
+
+              pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
+                                               line,
+                                               line_rect.x,
+                                               baseline);
 
               cairo_restore (cr);
 
@@ -713,6 +743,10 @@ render_para (GtkTextRenderer    *text_renderer,
                   cairo_save (cr);
 
                   gdk_cairo_set_source_rgba (cr, &selection);
+
+                  if(write_vertical)
+                    cairo_rotate(cr, M_PI/2);
+
                   cairo_rectangle (cr,
                                    line_display->left_margin,
                                    selection_y,
@@ -737,6 +771,10 @@ render_para (GtkTextRenderer    *text_renderer,
                   cairo_save (cr);
 
                   gdk_cairo_set_source_rgba (cr, &selection);
+
+                  if(write_vertical)
+                    cairo_rotate(cr, M_PI/2);
+
                   cairo_rectangle (cr,
                                    PANGO_PIXELS (line_rect.x) + PANGO_PIXELS (line_rect.width),
                                    selection_y,
@@ -747,13 +785,13 @@ render_para (GtkTextRenderer    *text_renderer,
                   cairo_restore (cr);
                 }
             }
-	  else if (line_display->has_block_cursor &&
-		   gtk_widget_has_focus (text_renderer->widget) &&
-		   byte_offset <= line_display->insert_index &&
-		   (line_display->insert_index < byte_offset + line->length ||
-		    (at_last_line && line_display->insert_index == byte_offset + line->length)))
-	    {
-	      GdkRectangle cursor_rect;
+          else if (line_display->has_block_cursor &&
+                   gtk_widget_has_focus (text_renderer->widget) &&
+                   byte_offset <= line_display->insert_index &&
+                   (line_display->insert_index < byte_offset + line->length ||
+                    (at_last_line && line_display->insert_index == byte_offset + line->length)))
+            {
+              GdkRectangle cursor_rect;
               GdkRGBA cursor_color;
               cairo_t *cr = text_renderer->cr;
 
@@ -761,13 +799,16 @@ render_para (GtkTextRenderer    *text_renderer,
                * (normally white on black) */
               _gtk_style_context_get_cursor_color (context, &cursor_color, NULL);
 
-	      cursor_rect.x = line_display->x_offset + line_display->block_cursor.x;
-	      cursor_rect.y = line_display->block_cursor.y + line_display->top_margin;
-	      cursor_rect.width = line_display->block_cursor.width;
-	      cursor_rect.height = line_display->block_cursor.height;
+              cursor_rect.x = line_display->x_offset + line_display->block_cursor.x;
+              cursor_rect.y = line_display->block_cursor.y + line_display->top_margin;
+              cursor_rect.width = line_display->block_cursor.width;
+              cursor_rect.height = line_display->block_cursor.height;
 
               cairo_save (cr);
 
+              if(write_vertical)
+                cairo_rotate(cr, M_PI/2);
+
               gdk_cairo_rectangle (cr, &cursor_rect);
               cairo_clip (cr);
 
@@ -784,16 +825,16 @@ render_para (GtkTextRenderer    *text_renderer,
 
                   gdk_cairo_set_source_rgba (cr, &color);
 
-		  text_renderer_set_state (text_renderer, CURSOR);
+                  text_renderer_set_state (text_renderer, CURSOR);
 
-		  pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
-						   line,
-						   line_rect.x,
-						   baseline);
+                  pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
+                                                   line,
+                                                   line_rect.x,
+                                                   baseline);
                 }
 
               cairo_restore (cr);
-	    }
+            }
         }
 
       byte_offset += line->length;
@@ -829,6 +870,8 @@ gtk_text_layout_draw (GtkTextLayout *layout,
   GSList *tmp_list;
   GList *tmp_widgets;
   GdkRectangle clip;
+  gboolean write_vertical;
+  gboolean first = TRUE;
 
   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
   g_return_if_fail (layout->default_style != NULL);
@@ -838,6 +881,7 @@ gtk_text_layout_draw (GtkTextLayout *layout,
   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
     return;
 
+  write_vertical = gtk_text_view_get_write_vertical(GTK_TEXT_VIEW(widget));
   context = gtk_widget_get_style_context (widget);
 
   line_list = gtk_text_layout_get_lines (layout, clip.y, clip.y + clip.height, &offset_y);
@@ -849,6 +893,7 @@ gtk_text_layout_draw (GtkTextLayout *layout,
   text_renderer_begin (text_renderer, widget, cr);
 
   /* text_renderer_begin/end does cairo_save/restore */
+
   cairo_translate (cr, 0, offset_y);
 
   gtk_text_layout_wrap_loop_start (layout);
@@ -881,8 +926,8 @@ gtk_text_layout_draw (GtkTextLayout *layout,
                                                 &line_start,
                                                 line, 0);
               line_end = line_start;
-	      if (!gtk_text_iter_ends_line (&line_end))
-		gtk_text_iter_forward_to_line_end (&line_end);
+              if (!gtk_text_iter_ends_line (&line_end))
+                gtk_text_iter_forward_to_line_end (&line_end);
               byte_count = gtk_text_iter_get_visible_line_index (&line_end);     
 
               if (gtk_text_iter_compare (&selection_start, &line_end) <= 0 &&
@@ -900,6 +945,12 @@ gtk_text_layout_draw (GtkTextLayout *layout,
                 }
             }
 
+          if (first && write_vertical)
+            {
+              cairo_translate(cr, line_display->height, offset_y);
+              first = FALSE;
+            }
+
           render_para (text_renderer, line_display,
                        selection_start_index, selection_end_index);
 
@@ -917,16 +968,28 @@ gtk_text_layout_draw (GtkTextLayout *layout,
 
                   index = g_array_index(line_display->cursors, int, i);
                   dir = (line_display->direction == GTK_TEXT_DIR_RTL) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
-                  gtk_render_insertion_cursor (context, cr,
-                                               line_display->x_offset, line_display->top_margin,
-                                               line_display->layout, index, dir);
+                  if (!write_vertical)
+                    {
+                      gtk_render_insertion_cursor (context, cr,
+                                                   line_display->x_offset, line_display->top_margin,
+                                                   line_display->layout, index, dir);
+                    }
+                  else
+                    {
+                      cairo_save(cr);
+                      cairo_rotate(cr, M_PI/2);
+                      gtk_render_insertion_cursor (context, cr,
+                                                   line_display->x_offset, line_display->top_margin,
+                                                   line_display->layout, index, dir);
+                      cairo_restore(cr);
+                    }
                 }
             }
         } /* line_display->height > 0 */
+      write_vertical ? cairo_translate (cr, line_display->height, 0) : cairo_translate (cr, 0, line_display->height);
 
-      cairo_translate (cr, 0, line_display->height);
       gtk_text_layout_free_line_display (layout, line_display);
-      
+
       tmp_list = g_slist_next (tmp_list);
     }
 
diff --git gtk/gtktextlayout.c gtk/gtktextlayout.c
index 8916aef..61d31f9 100644
--- gtk/gtktextlayout.c
+++ gtk/gtktextlayout.c
@@ -824,18 +824,18 @@ gtk_text_layout_invalidate_cache (GtkTextLayout *layout,
       GtkTextLineDisplay *display = layout->one_display_cache;
 
       if (cursors_only)
-	{
+        {
           if (display->cursors)
             g_array_free (display->cursors, TRUE);
-	  display->cursors = NULL;
-	  display->cursors_invalid = TRUE;
-	  display->has_block_cursor = FALSE;
-	}
+          display->cursors = NULL;
+          display->cursors_invalid = TRUE;
+          display->has_block_cursor = FALSE;
+        }
       else
-	{
-	  layout->one_display_cache = NULL;
-	  gtk_text_layout_free_line_display (layout, display);
-	}
+        {
+          layout->one_display_cache = NULL;
+          gtk_text_layout_free_line_display (layout, display);
+        }
     }
 }
 
diff --git gtk/gtktextview.c gtk/gtktextview.c
index 61961ec..7adc534 100644
--- gtk/gtktextview.c
+++ gtk/gtktextview.c
@@ -52,6 +52,7 @@
 #include "gtkwindow.h"
 #include "gtkscrollable.h"
 #include "gtktypebuiltins.h"
+#include <math.h>
 
 #include "a11y/gtktextviewaccessible.h"
 
@@ -231,6 +232,9 @@ struct _GtkTextViewPrivate
    * driving the scrollable adjustment values */
   guint hscroll_policy : 1;
   guint vscroll_policy : 1;
+
+  /* vertical writing */
+  guint write_vertical : 1;
 };
 
 struct _GtkTextPendingScroll
@@ -283,7 +287,8 @@ enum
   PROP_HADJUSTMENT,
   PROP_VADJUSTMENT,
   PROP_HSCROLL_POLICY,
-  PROP_VSCROLL_POLICY
+  PROP_VSCROLL_POLICY,
+  PROP_WRITE_VERTICAL
 };
 
 static void gtk_text_view_finalize             (GObject          *object);
@@ -811,6 +816,14 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
 							       P_("Color with which to draw error-indication underlines"),
 							       GDK_TYPE_COLOR,
 							       GTK_PARAM_READABLE));
+  /* Write vertical */
+  g_object_class_install_property (gobject_class,
+                                   PROP_WRITE_VERTICAL,
+                                   g_param_spec_boolean ("write-vertical",
+							 P_("Write vertical"),
+							 P_("Writes in top to bottom direction"),
+							 TRUE,
+							 GTK_PARAM_READWRITE));
   
   /*
    * Signals
@@ -1418,6 +1431,9 @@ gtk_text_view_init (GtkTextView *text_view)
 
   priv->pending_place_cursor_button = 0;
 
+  /* default, no vertical write */
+  priv->write_vertical = FALSE;
+
   /* We handle all our own redrawing */
   gtk_widget_set_redraw_on_allocate (widget, FALSE);
 }
@@ -1665,10 +1681,13 @@ gtk_text_view_get_cursor_locations (GtkTextView       *text_view,
                                     GdkRectangle      *weak)
 {
   GtkTextIter insert;
+  gboolean write_vertical = FALSE;
+  int tmp;
 
   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
   g_return_if_fail (iter == NULL ||
                     gtk_text_iter_get_buffer (iter) == get_buffer (text_view));
+  write_vertical = gtk_text_view_get_write_vertical (text_view);
 
   gtk_text_view_ensure_layout (text_view);
 
@@ -1680,6 +1699,22 @@ gtk_text_view_get_cursor_locations (GtkTextView       *text_view,
 
   gtk_text_layout_get_cursor_locations (text_view->priv->layout, &insert,
                                         strong, weak);
+  if (write_vertical)
+    {
+      if (strong )
+        {
+          tmp = strong->x;
+          strong->x = strong->y;
+          strong->y = tmp;
+        }
+      if ( weak )
+        {
+          tmp = weak->x;
+          weak->x = weak->y;
+          weak->y = tmp;
+        }
+    }
+
 }
 
 /**
@@ -1877,6 +1912,8 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
   gint screen_xoffset, screen_yoffset;
   gint current_x_scroll, current_y_scroll;
 
+  gboolean write_vertical = FALSE;
+
   /* FIXME why don't we do the validate-at-scroll-destination thing
    * from flush_scroll in this function? I think it wasn't done before
    * because changed_handler was screwed up, but I could be wrong.
@@ -1890,6 +1927,8 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
   
   widget = GTK_WIDGET (text_view);
 
+  write_vertical = gtk_text_view_get_write_vertical(text_view);
+
   DV(g_print(G_STRLOC"\n"));
   
   gtk_text_layout_get_iter_location (text_view->priv->layout,
@@ -1897,7 +1936,7 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
                                      &rect);
 
   DV (g_print (" target rect %d,%d  %d x %d\n", rect.x, rect.y, rect.width, rect.height));
-  
+
   current_x_scroll = text_view->priv->xoffset;
   current_y_scroll = text_view->priv->yoffset;
 
@@ -1923,8 +1962,17 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
   /* The -1 here ensures that we leave enough space to draw the cursor
    * when this function is used for horizontal scrolling. 
    */
-  screen_right = screen.x + screen.width - 1;
-  screen_bottom = screen.y + screen.height;
+  if (!write_vertical)
+    {
+      screen_right = screen.x + screen.width - 1;
+      screen_bottom = screen.y + screen.height;
+    }
+  else
+    {
+      screen_right = screen.x + screen.width;
+      screen_bottom = screen.y + screen.height -1;
+    }
+
   
   /* The alignment affects the point in the target character that we
    * choose to align. If we're doing right/bottom alignment, we align
@@ -1939,30 +1987,59 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
   scroll_inc = 0;
   scroll_dest = current_y_scroll;
   
-  if (use_align)
-    {      
-      scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
-      
-      /* if scroll_dest < screen.y, we move a negative increment (up),
-       * else a positive increment (down)
-       */
-      scroll_inc = scroll_dest - screen.y + screen_yoffset;
+  if (write_vertical)
+    {
+      if (use_align)
+        {
+          scroll_dest = rect.x + (rect.width * xalign) - (screen.height * xalign);
+
+          /* if scroll_dest < screen.y, we move a negative increment (left),
+           * else a positive increment (right)
+           */
+          scroll_inc = scroll_dest - screen.y + screen_yoffset;
+        }
+      else
+        {
+          /* move minimum to get onscreen */
+          if (rect.x < screen.y)
+            {
+              scroll_dest = rect.x;
+              scroll_inc = scroll_dest - screen.y - screen_yoffset;
+            }
+          else if ((rect.x + rect.width) > screen_bottom)
+            {
+              scroll_dest = rect.x + rect.width;
+              scroll_inc = scroll_dest - screen_bottom + screen_yoffset;
+            }
+        }
     }
   else
     {
-      /* move minimum to get onscreen */
-      if (rect.y < screen.y)
+      if (use_align)
         {
-          scroll_dest = rect.y;
-          scroll_inc = scroll_dest - screen.y - screen_yoffset;
+          scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
+
+          /* if scroll_dest < screen.y, we move a negative increment (up),
+           * else a positive increment (down)
+           */
+          scroll_inc = scroll_dest - screen.y + screen_yoffset;
         }
-      else if ((rect.y + rect.height) > screen_bottom)
+      else
         {
-          scroll_dest = rect.y + rect.height;
-          scroll_inc = scroll_dest - screen_bottom + screen_yoffset;
+          /* move minimum to get onscreen */
+          if (rect.y < screen.y)
+            {
+              scroll_dest = rect.y;
+              scroll_inc = scroll_dest - screen.y - screen_yoffset;
+            }
+          else if ((rect.y + rect.height) > screen_bottom)
+            {
+              scroll_dest = rect.y + rect.height;
+              scroll_inc = scroll_dest - screen_bottom + screen_yoffset;
+            }
         }
-    }  
-  
+    }
+
   if (scroll_inc != 0)
     {
       gtk_adjustment_set_value (text_view->priv->vadjustment,
@@ -1972,31 +2049,60 @@ gtk_text_view_scroll_to_iter (GtkTextView   *text_view,
     }
 
   /* Horizontal scroll */
-  
+
   scroll_inc = 0;
   scroll_dest = current_x_scroll;
-  
-  if (use_align)
-    {      
-      scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
 
-      /* if scroll_dest < screen.y, we move a negative increment (left),
-       * else a positive increment (right)
-       */
-      scroll_inc = scroll_dest - screen.x + screen_xoffset;
+  if (write_vertical)
+    {
+      if (use_align)
+        {
+          scroll_dest = rect.y + (rect.height * yalign) - (screen.width * yalign);
+
+          /* if scroll_dest < screen.y, we move a negative increment (up),
+           * else a positive increment (down)
+           */
+          scroll_inc = scroll_dest - screen.y + screen_yoffset;
+        }
+      else
+        {
+          /* move minimum to get onscreen */
+          if (rect.y < screen.y)
+            {
+              scroll_dest = rect.y;
+              scroll_inc = scroll_dest - screen.x - screen_xoffset;
+            }
+          else if ((rect.y + rect.height) > screen_right)
+            {
+              scroll_dest = rect.y + rect.height;
+              scroll_inc = scroll_dest - screen_right + screen_xoffset;
+            }
+        }
     }
   else
     {
-      /* move minimum to get onscreen */
-      if (rect.x < screen.x)
+      if (use_align)
         {
-          scroll_dest = rect.x;
-          scroll_inc = scroll_dest - screen.x - screen_xoffset;
+          scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
+
+          /* if scroll_dest < screen.y, we move a negative increment (left),
+           * else a positive increment (right)
+           */
+          scroll_inc = scroll_dest - screen.x + screen_xoffset;
         }
-      else if ((rect.x + rect.width) > screen_right)
+      else
         {
-          scroll_dest = rect.x + rect.width;
-          scroll_inc = scroll_dest - screen_right + screen_xoffset;
+          /* move minimum to get onscreen */
+          if (rect.x < screen.x)
+            {
+              scroll_dest = rect.x;
+              scroll_inc = scroll_dest - screen.x - screen_xoffset;
+            }
+          else if ((rect.x + rect.width) > screen_right)
+            {
+              scroll_dest = rect.x + rect.width;
+              scroll_inc = scroll_dest - screen_right + screen_xoffset;
+            }
         }
     }
   
@@ -2086,6 +2192,8 @@ gtk_text_view_flush_scroll (GtkTextView *text_view)
   gboolean retval;
   GtkWidget *widget;
 
+  gboolean write_vertical = gtk_text_view_get_write_vertical(text_view);
+
   widget = GTK_WIDGET (text_view);
   
   DV(g_print(G_STRLOC"\n"));
@@ -2112,9 +2220,18 @@ gtk_text_view_flush_scroll (GtkTextView *text_view)
    */
   DV(g_print (">Validating scroll destination ("G_STRLOC")\n"));
   gtk_widget_get_allocation (widget, &allocation);
+
   gtk_text_layout_validate_yrange (text_view->priv->layout, &iter,
-                                   -(allocation.height * 2),
-                                   allocation.height * 2);
+                                       -(allocation.height * 2),
+                                       allocation.height * 2)
+
+  /* (!write_vertical) */
+  /*   ? gtk_text_layout_validate_yrange (text_view->priv->layout, &iter, */
+  /*                                      -(allocation.height * 2), */
+  /*                                      allocation.height * 2) */
+  /*   : gtk_text_layout_validate_yrange (text_view->priv->layout, &iter, */
+  /*                                      -(allocation.width * 2), */
+  /*                                      allocation.width * 2); */
 
   DV(g_print (">Done validating scroll destination ("G_STRLOC")\n"));
 
@@ -2139,6 +2256,8 @@ gtk_text_view_update_adjustments (GtkTextView *text_view)
   GtkTextViewPrivate *priv;
   gint width = 0, height = 0;
 
+  gboolean write_vertical = gtk_text_view_get_write_vertical(text_view);
+
   DV(g_print(">Updating adjustments ("G_STRLOC")\n"));
 
   priv = text_view->priv;
@@ -3172,6 +3291,10 @@ gtk_text_view_set_property (GObject         *object,
       gtk_widget_queue_resize (GTK_WIDGET (text_view));
       break;
 
+    case PROP_WRITE_VERTICAL:
+      gtk_text_view_set_write_vertical(text_view, g_value_get_boolean(value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3695,7 +3818,7 @@ gtk_text_view_validate_onscreen (GtkTextView *text_view)
 
   widget = GTK_WIDGET (text_view);
   priv = text_view->priv;
-  
+
   DV(g_print(">Validating onscreen ("G_STRLOC")\n"));
   
   if (SCREEN_HEIGHT (widget) > 0)
@@ -3864,9 +3987,13 @@ changed_handler (GtkTextLayout     *layout,
   GtkWidget *widget;
   GdkRectangle visible_rect;
   GdkRectangle redraw_rect;
-  
+  gboolean write_vertical;
+
   text_view = GTK_TEXT_VIEW (data);
   priv = text_view->priv;
+
+  write_vertical = priv->write_vertical;
+
   widget = GTK_WIDGET (data);
   
   DV(g_print(">Lines Validated ("G_STRLOC")\n"));
@@ -3875,16 +4002,32 @@ changed_handler (GtkTextLayout     *layout,
     {      
       gtk_text_view_get_visible_rect (text_view, &visible_rect);
 
-      redraw_rect.x = visible_rect.x;
-      redraw_rect.width = visible_rect.width;
-      redraw_rect.y = start_y;
-
-      if (old_height == new_height)
-        redraw_rect.height = old_height;
-      else if (start_y + old_height > visible_rect.y)
-        redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
+      if (!write_vertical)
+        {
+          redraw_rect.x = visible_rect.x;
+          redraw_rect.width = visible_rect.width;
+          redraw_rect.y = start_y;
+
+          if (old_height == new_height)
+            redraw_rect.height = old_height;
+          else if (start_y + old_height > visible_rect.y)
+            redraw_rect.height = MAX (0, visible_rect.y + visible_rect.height - start_y);
+          else
+            redraw_rect.height = 0;
+        }
       else
-        redraw_rect.height = 0;
+        {
+          redraw_rect.x = start_y;
+          redraw_rect.height = visible_rect.height;
+          redraw_rect.y = visible_rect.y;
+
+          if (old_height == new_height)
+            redraw_rect.width = old_height;
+          else if (start_y + old_height > visible_rect.x)
+            redraw_rect.width = MAX (0, visible_rect.x + visible_rect.width - start_y);
+          else
+            redraw_rect.width = 0;
+        }
 	
       if (gdk_rectangle_intersect (&redraw_rect, &visible_rect, &redraw_rect))
         {
@@ -4563,10 +4706,15 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
           GtkTextIter iter;
           GtkTextIter start, end;
 
-          gtk_text_layout_get_iter_at_pixel (priv->layout,
-                                             &iter,
-                                             event->x + priv->xoffset,
-                                             event->y + priv->yoffset);
+          priv->write_vertical ?
+            gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                               &iter,
+                                               event->y + priv->yoffset,
+                                               event->x + priv->xoffset)
+            : gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                                 &iter,
+                                                 event->x + priv->xoffset,
+                                                 event->y + priv->yoffset);
 
           if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
                                                     &start, &end) &&
@@ -4594,7 +4742,12 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
              with the middle button */
           priv->scroll_after_paste = FALSE;
 
-          gtk_text_layout_get_iter_at_pixel (priv->layout,
+          priv->write_vertical ?
+            gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                               &iter,
+                                               event->y + priv->yoffset,
+                                               event->x + priv->xoffset)
+            : gtk_text_layout_get_iter_at_pixel (priv->layout,
                                              &iter,
                                              event->x + priv->xoffset,
                                              event->y + priv->yoffset);
@@ -4614,10 +4767,15 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
 
       gtk_text_view_end_selection_drag (text_view);
 
-      gtk_text_layout_get_iter_at_pixel (priv->layout,
-					 &iter,
-					 event->x + priv->xoffset,
-					 event->y + priv->yoffset);
+      priv->write_vertical ?
+            gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                               &iter,
+                                               event->y + priv->yoffset,
+                                               event->x + priv->xoffset)
+            : gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                             &iter,
+                                             event->x + priv->xoffset,
+                                             event->y + priv->yoffset);
       
       gtk_text_view_start_selection_drag (text_view, &iter, event);
       return TRUE;
@@ -4631,10 +4789,11 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
 {
   GtkTextView *text_view;
   GtkTextViewPrivate *priv;
-
+  gboolean write_vertical = FALSE;
   text_view = GTK_TEXT_VIEW (widget);
   priv = text_view->priv;
 
+  write_vertical = priv->write_vertical;
   if (event->window != priv->text_window->bin_window)
     return FALSE;
 
@@ -4656,10 +4815,15 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event)
            * didn't move by the drag threshold, so just clear selection
            * and place cursor.
            */
-	  gtk_text_layout_get_iter_at_pixel (priv->layout,
-					     &iter,
-					     event->x + priv->xoffset,
-					     event->y + priv->yoffset);
+          write_vertical
+            ? gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                                 &iter,
+                                                 event->y + priv->yoffset,
+                                                 event->x + priv->xoffset)
+            : gtk_text_layout_get_iter_at_pixel (priv->layout,
+                                                 &iter,
+                                                 event->x + priv->xoffset,
+                                                 event->y + priv->yoffset);
 
 	  gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
 	  gtk_text_view_check_cursor_blink (text_view);
@@ -4823,7 +4987,7 @@ gtk_text_view_paint (GtkWidget      *widget,
       g_warning (G_STRLOC ": somehow some text lines were modified or scrolling occurred since the last validation of lines on the screen - may be a text widget bug.");
       g_assert_not_reached ();
     }
-  
+
 #if 0
   printf ("painting %d,%d  %d x %d\n",
           area->x, area->y,
@@ -5528,6 +5692,20 @@ gtk_text_view_move_cursor (GtkTextView     *text_view,
                            gint             count,
                            gboolean         extend_selection)
 {
+  gboolean write_vertical = gtk_text_view_get_write_vertical(text_view);
+
+  if (write_vertical)
+    {
+      switch (step)
+        {
+        case GTK_MOVEMENT_VISUAL_POSITIONS:
+          step = GTK_MOVEMENT_DISPLAY_LINES;
+          break;
+        case GTK_MOVEMENT_DISPLAY_LINES:
+          step = GTK_MOVEMENT_VISUAL_POSITIONS;
+        }
+    }
+
   gtk_text_view_move_cursor_internal (text_view, step, count, extend_selection);
 }
 
@@ -6143,6 +6321,35 @@ gtk_text_view_set_accepts_tab (GtkTextView *text_view,
 }
 
 /**
+ *
+ * Write in top to bottom direction
+ *
+ **/
+void
+gtk_text_view_set_write_vertical (GtkTextView *text_view,
+                                  gboolean wv)
+{
+  GdkRectangle visible_rect;
+  g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+  wv = wv != FALSE;
+  if (text_view->priv->write_vertical != wv)
+    {
+      text_view->priv->write_vertical = wv;
+
+      gtk_text_view_get_visible_rect (text_view, &visible_rect);
+      text_window_invalidate_rect (text_view->priv->text_window,
+                                       &visible_rect);
+      queue_update_im_spot_location (text_view);
+      gtk_text_view_invalidate(text_view);
+    }
+}
+gboolean
+gtk_text_view_get_write_vertical(GtkTextView *text_view)
+{
+  g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
+  return text_view->priv->write_vertical;
+}
+/**
  * gtk_text_view_get_accepts_tab:
  * @text_view: A #GtkTextView
  * 
@@ -7440,25 +7647,48 @@ gtk_text_view_set_hadjustment_values (GtkTextView *text_view)
 {
   GtkTextViewPrivate *priv;
   gint screen_width;
+  gint screen_height;
   gdouble old_value;
   gdouble new_value;
   gdouble new_upper;
 
+  GtkTextIter first_para;
+  gint y;
+  gboolean write_vertical = gtk_text_view_get_write_vertical(text_view);
+
   priv = text_view->priv;
 
   screen_width = SCREEN_WIDTH (text_view);
+  screen_height = SCREEN_HEIGHT (text_view);
   old_value = gtk_adjustment_get_value (priv->hadjustment);
-  new_upper = MAX (screen_width, priv->width);
+
+  new_upper = write_vertical ? MAX (screen_width, priv->height) : MAX (screen_width, priv->width);
 
   g_object_set (priv->hadjustment,
-                "lower", 0.0,
-                "upper", new_upper,
-                "page-size", (gdouble)screen_width,
-                "step-increment", screen_width * 0.1,
-                "page-increment", screen_width * 0.9,
-                NULL);
+                    "lower", 0.0,
+                    "upper", new_upper,
+                    "page-size", (gdouble)screen_width,
+                    "step-increment", screen_width * 0.1,
+                    "page-increment", screen_width * 0.9,
+                    NULL);
+
+  if (!write_vertical)
+    {
+      new_value = CLAMP (old_value, 0, new_upper - screen_width);
+    }
+  else
+    {
+      /* Now adjust the value of the adjustment to keep the cursor at the
+       * same place in the buffer */
+      gtk_text_view_ensure_layout (text_view);
+      gtk_text_view_get_first_para_iter (text_view, &first_para);
+      gtk_text_layout_get_line_yrange (priv->layout, &first_para, &y, NULL);
+
+      y += priv->first_para_pixels;
+
+      new_value = CLAMP (y, 0, new_upper - screen_width);
+    }
 
-  new_value = CLAMP (old_value, 0, new_upper - screen_width);
   if (new_value != old_value)
     gtk_adjustment_set_value (priv->hadjustment, new_value);
 }
@@ -7469,16 +7699,20 @@ gtk_text_view_set_vadjustment_values (GtkTextView *text_view)
   GtkTextViewPrivate *priv;
   GtkTextIter first_para;
   gint screen_height;
+  gint screen_width;
   gint y;
   gdouble old_value;
   gdouble new_value;
   gdouble new_upper;
 
+  gboolean write_vertical = gtk_text_view_get_write_vertical(text_view);
+
   priv = text_view->priv;
 
   screen_height = SCREEN_HEIGHT (text_view);
+  screen_width = SCREEN_WIDTH (text_view);
   old_value = gtk_adjustment_get_value (priv->vadjustment);
-  new_upper = MAX (screen_height, priv->height);
+  new_upper = (write_vertical) ? MAX (screen_height, priv->width) : MAX (screen_height, priv->height);
 
   g_object_set (priv->vadjustment,
                 "lower", 0.0,
@@ -7488,17 +7722,27 @@ gtk_text_view_set_vadjustment_values (GtkTextView *text_view)
                 "page-increment", screen_height * 0.9,
                 NULL);
 
-  /* Now adjust the value of the adjustment to keep the cursor at the
-   * same place in the buffer */
-  gtk_text_view_ensure_layout (text_view);
-  gtk_text_view_get_first_para_iter (text_view, &first_para);
-  gtk_text_layout_get_line_yrange (priv->layout, &first_para, &y, NULL);
+  if (!write_vertical)
+    {
+      /* Now adjust the value of the adjustment to keep the cursor at the
+       * same place in the buffer */
+      gtk_text_view_ensure_layout (text_view);
+      gtk_text_view_get_first_para_iter (text_view, &first_para);
+      gtk_text_layout_get_line_yrange (priv->layout, &first_para, &y, NULL);
+
+      y += priv->first_para_pixels;
 
-  y += priv->first_para_pixels;
+      new_value = CLAMP (y, 0, new_upper - screen_height);
+
+    }
+  else
+    {
+      new_value = CLAMP (old_value, 0, new_upper - screen_height);
+    }
 
-  new_value = CLAMP (y, 0, new_upper - screen_height);
   if (new_value != old_value)
     gtk_adjustment_set_value (priv->vadjustment, new_value);
+
  }
 
 
@@ -7589,7 +7833,10 @@ gtk_text_view_value_changed (GtkAdjustment *adjustment,
   gint dx = 0;
   gint dy = 0;
 
+  gboolean write_vertical;
   priv = text_view->priv;
+  write_vertical = priv->write_vertical;
+
 
   /* Note that we oddly call this function with adjustment == NULL
    * sometimes
@@ -7603,34 +7850,73 @@ gtk_text_view_value_changed (GtkAdjustment *adjustment,
   
   if (adjustment == priv->hadjustment)
     {
-      dx = priv->xoffset - (gint)gtk_adjustment_get_value (adjustment);
-      priv->xoffset = gtk_adjustment_get_value (adjustment);
+      if (!write_vertical)
+        {
+          dx = priv->xoffset - (gint)gtk_adjustment_get_value (adjustment);
+          priv->xoffset = gtk_adjustment_get_value (adjustment);
 
-      /* If the change is due to a size change we need 
-       * to invalidate the entire text window because there might be
-       * right-aligned or centered text 
-       */
-      if (priv->width_changed)
-	{
-	  if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
-	    gdk_window_invalidate_rect (priv->text_window->bin_window, NULL, FALSE);
+          /* If the change is due to a size change we need
+           * to invalidate the entire text window because there might be
+           * right-aligned or centered text
+           */
+          if (priv->width_changed)
+            {
+              if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
+                gdk_window_invalidate_rect (priv->text_window->bin_window, NULL, FALSE);
 	  
-	  priv->width_changed = FALSE;
-	}
+              priv->width_changed = FALSE;
+            }
+        }
+      else
+        {
+          dx = priv->yoffset - (gint)gtk_adjustment_get_value (adjustment);
+          priv->yoffset = gtk_adjustment_get_value (adjustment);
+
+          if (priv->layout)
+            {
+              gtk_text_layout_get_line_at_y (priv->layout, &iter, gtk_adjustment_get_value (adjustment), &line_top);
+
+              gtk_text_buffer_move_mark (get_buffer (text_view), priv->first_para_mark, &iter);
+
+              priv->first_para_pixels = gtk_adjustment_get_value (adjustment) - line_top;
+            }
+
+        }
     }
   else if (adjustment == priv->vadjustment)
     {
-      dy = priv->yoffset - (gint)gtk_adjustment_get_value (adjustment);
-      priv->yoffset = gtk_adjustment_get_value (adjustment);
+      if (!write_vertical)
+        {
+          dy = priv->yoffset - (gint)gtk_adjustment_get_value (adjustment);
+          priv->yoffset = gtk_adjustment_get_value (adjustment);
 
-      if (priv->layout)
+          if (priv->layout)
+            {
+              gtk_text_layout_get_line_at_y (priv->layout, &iter, gtk_adjustment_get_value (adjustment), &line_top);
+
+              gtk_text_buffer_move_mark (get_buffer (text_view), priv->first_para_mark, &iter);
+
+              priv->first_para_pixels = gtk_adjustment_get_value (adjustment) - line_top;
+            }
+        }
+      else
         {
-          gtk_text_layout_get_line_at_y (priv->layout, &iter, gtk_adjustment_get_value (adjustment), &line_top);
+          dy = priv->yoffset - (gint)gtk_adjustment_get_value (adjustment);
+          priv->yoffset = gtk_adjustment_get_value (adjustment);
 
-          gtk_text_buffer_move_mark (get_buffer (text_view), priv->first_para_mark, &iter);
+          /* If the change is due to a size change we need
+           * to invalidate the entire text window because there might be
+           * right-aligned or centered text
+           */
+          if (priv->width_changed)
+            {
+              if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
+                gdk_window_invalidate_rect (priv->text_window->bin_window, NULL, FALSE);
 
-          priv->first_para_pixels = gtk_adjustment_get_value (adjustment) - line_top;
+              priv->width_changed = FALSE;
+            }
         }
+
     }
   
   if (dx != 0 || dy != 0)
@@ -8002,8 +8288,16 @@ gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
   if (x == -1 || y == -1)
     gtk_text_view_get_cursor_locations (text_view, NULL, &pos, NULL);
 
-  text_view->priv->virtual_cursor_x = (x == -1) ? pos.x : x;
-  text_view->priv->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
+  if (!text_view->priv->write_vertical)
+    {
+      text_view->priv->virtual_cursor_x = (x == -1) ? pos.x : x;
+      text_view->priv->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
+    }
+  else
+    {
+      text_view->priv->virtual_cursor_x = (x == -1) ? pos.x + 1 : x;
+      text_view->priv->virtual_cursor_y = (y == -1) ? pos.y : y;
+    }
 }
 
 /* Quick hack of a popup menu
@@ -8588,6 +8882,12 @@ text_window_invalidate_rect (GtkTextWindow *win,
           
   gdk_window_invalidate_rect (win->bin_window, &window_rect, FALSE);
 
+  cairo_t *cr = gdk_cairo_create (win->bin_window);
+  gdk_cairo_rectangle (cr, &window_rect);
+  cairo_set_source_rgb  (cr, 1.0, 0.0, 0.0);	/* red */
+  cairo_fill (cr);
+  cairo_destroy (cr);
+
 #if 0
   {
     cairo_t *cr = gdk_cairo_create (win->bin_window);
@@ -8611,15 +8911,27 @@ text_window_invalidate_cursors (GtkTextWindow *win)
   gfloat       cursor_aspect_ratio;
   gint         stem_width;
   gint         arrow_width;
-
+  gboolean write_vertical = FALSE;
+  gint tmp;
   text_view = GTK_TEXT_VIEW (win->widget);
   priv = text_view->priv;
 
+  write_vertical = priv->write_vertical;
+
   gtk_text_buffer_get_iter_at_mark (priv->buffer, &iter,
                                     gtk_text_buffer_get_insert (priv->buffer));
 
   if (_gtk_text_layout_get_block_cursor (priv->layout, &strong))
     {
+      /* if(write_vertical) */
+      /*   { */
+      /*     tmp = strong.x; */
+      /*     strong.x = strong.y; */
+      /*     strong.y = tmp; */
+      /*     tmp = strong.height; */
+      /*     strong.height = strong.width; */
+      /*     strong.width = tmp; */
+      /*   } */
       text_window_invalidate_rect (win, &strong);
       return;
     }
@@ -8655,6 +8967,16 @@ text_window_invalidate_cursors (GtkTextWindow *win)
       strong.width += arrow_width * 2;
     }
 
+  if(write_vertical)
+    {
+      tmp = strong.x;
+      strong.x = strong.y;
+      strong.y = tmp;
+      tmp = strong.height;
+      strong.height = strong.width;
+      strong.width = tmp;
+    }
+
   text_window_invalidate_rect (win, &strong);
 
   if (draw_arrow) /* == have weak */
@@ -8674,6 +8996,15 @@ text_window_invalidate_cursors (GtkTextWindow *win)
       weak.x     -= arrow_width;
       weak.width += arrow_width * 2;
 
+      if(write_vertical)
+        {
+          tmp = weak.x;
+          weak.x = weak.y;
+          weak.y = tmp;
+          tmp = weak.height;
+          weak.height = weak.width;
+          weak.width = tmp;
+        }
       text_window_invalidate_rect (win, &weak);
     }
 }
@@ -8806,17 +9137,34 @@ buffer_to_widget (GtkTextView      *text_view,
                   gint             *window_y)
 {
   GtkTextViewPrivate *priv = text_view->priv;
-
-  if (window_x)
+  gboolean write_vertical = gtk_text_view_get_write_vertical (text_view);
+  if (!write_vertical)
     {
-      *window_x = buffer_x - priv->xoffset;
-      *window_x += priv->text_window->allocation.x;
-    }
+      if (window_x)
+        {
+          *window_x = buffer_x - priv->xoffset;
+          *window_x += priv->text_window->allocation.x;
+        }
 
-  if (window_y)
+      if (window_y)
+        {
+          *window_y = buffer_y - priv->yoffset;
+          *window_y += priv->text_window->allocation.y;
+        }
+    }
+  else
     {
-      *window_y = buffer_y - priv->yoffset;
-      *window_y += priv->text_window->allocation.y;
+      if (window_x)
+        {
+          *window_x = buffer_y - priv->yoffset;
+          *window_x += priv->text_window->allocation.y;
+        }
+
+      if (window_y)
+        {
+          *window_y = buffer_x - priv->xoffset;
+          *window_y += priv->text_window->allocation.x;
+        }
     }
 }
 
@@ -8884,6 +9232,7 @@ gtk_text_view_buffer_to_window_coords (GtkTextView      *text_view,
                                        gint             *window_y)
 {
   GtkTextViewPrivate *priv = text_view->priv;
+  gboolean write_vertical = gtk_text_view_get_write_vertical (text_view);
 
   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
 
diff --git gtk/gtktextview.h gtk/gtktextview.h
index 62bd8d1..4bb82e3 100644
--- gtk/gtktextview.h
+++ gtk/gtktextview.h
@@ -253,6 +253,11 @@ void             gtk_text_view_set_overwrite          (GtkTextView      *text_vi
 gboolean         gtk_text_view_get_overwrite          (GtkTextView      *text_view);
 void		 gtk_text_view_set_accepts_tab        (GtkTextView	*text_view,
 						       gboolean		 accepts_tab);
+/* write vertical */
+void             gtk_text_view_set_write_vertical     (GtkTextView	    *text_view,
+						       gboolean		 wv);
+gboolean         gtk_text_view_get_write_vertical     (GtkTextView      *text_view);
+
 gboolean	 gtk_text_view_get_accepts_tab        (GtkTextView	*text_view);
 void             gtk_text_view_set_pixels_above_lines (GtkTextView      *text_view,
                                                        gint              pixels_above_lines);
