Logo Search packages:      
Sourcecode: papaya version File versions  Download package

GTKTwoVT.cpp

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gdk/gdkkeysyms.h>

#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#endif

#include "mudclient.h"
#include "callbacks.h"
#include "Prefs.h"
#include "Message.h"
#include "SystemColour.h"
#include "PluginHandler.h"
#include "ColouredLabel.h"
#include "GTKTwoVT.h"
#include "BaseWindow.h"

#include "CommandInterpreter.h"

#include "TeloptFilter.h"

extern PluginHandler * phandler;
extern CommandInterpreter * commandInterpreter;
extern BaseWindow * mainWindow;

#define ESCAPE '\033'
#define PAGE_UP 65365
#define PAGE_DOWN 65366
#define TAB 65289
#define BACKSPACE 65288

gboolean prompt_expose(GtkWidget *, GdkEventExpose *, gpointer);


gint textview_configure (GtkWidget * widget, GdkEventConfigure event, gpointer data) {
  printf ("Received a textview configure.\n");
  GTKTwoVT * vt = (GTKTwoVT *) data;
  vt->use();
  return 0;
}

/*
  Then, you just need to know that the Editable widgets don't even to
  try to paste when not editable. So you need to connect to
  "button_press_event", and do a gtk_selection_convert() yourself.
  Then, you need to connect to "selection_received" to get the data when
  it arrives. Your "selection_received" handler then needs to
  do a gtk_signal_emit_stop_by_name(), so that the GtkEditable
  default selection_received handler doesn't get called.
*/

void papaya_selection_received(GtkWidget * widget, GtkSelectionData * selection_data, gpointer data) {

  GtkWidget * input = mainWindow->getCurrentConnection()->getVT()->getInput();

  if (selection_data->length < 0)
    return;

  char buf[16384];
  buf[0] = '\0';
  
  if (gtk_entry_get_text(GTK_ENTRY(input)))
    strcat(buf, gtk_entry_get_text(GTK_ENTRY(input))); 

  if (selection_data->type == gdk_atom_intern("STRING", FALSE)) {
    selection_data->data[selection_data->length] = 0;
    strcat(buf, (char *)selection_data->data);
  } else {
    if (selection_data->type == gdk_atom_intern("COMPOUND_TEXT", FALSE)
      || selection_data->type == gdk_atom_intern("TEXT", FALSE)) {
      gchar **list;
      gint count;
      gint i;
      
      count = gdk_text_property_to_text_list (selection_data->type,
                                    selection_data->format, 
                                    selection_data->data,
                                    selection_data->length,
                                    &list);
      for (i = 0; i < count; i++)
      if (list[i])
        strcat(buf, list[i]);
    }
  }
 
  gtk_entry_set_text(GTK_ENTRY(input), buf);
  
}

void output_size_changed(GtkWidget * widget, GdkEvent * event, gpointer data) {

  Connection * c = (Connection *)data;
  GTKTwoVT * vt = (GTKTwoVT *)c->getVT();

  int prev_width = vt->getStoredWidth();
  int prev_height = vt->getStoredHeight();
  int width, height;
  vt->getScreenSize(&width, &height);

  if (width != prev_width || height != prev_height) {
    // Tell this connection to redo NAWS.
    TeloptFilter * filter = static_cast<TeloptFilter*>(c->getSocket()->inputFilters.findFilter("TelnetOptions"));
    if (filter)
      filter->do_naws();
  }

  //  VT * vt = c->getVT();
  //  vt->scroll();

}

gboolean output_button_pressed(GtkWidget * widget, GdkEventButton * event, gpointer data) {

  GdkAtom ctext_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE);

  switch (event->type) {
  case GDK_BUTTON_PRESS:
    switch (event->button) {
    case 2:
      
      gtk_selection_convert(widget, GDK_SELECTION_PRIMARY, ctext_atom, GDK_CURRENT_TIME);
      
      return true;
    }
    return false;

  case GDK_2BUTTON_PRESS:
    switch (event->button) {
    case 1:

      
      return false;
    }

  /* k0n pointed out that some combinations of GDK/C++ spew warnings if
   * the default option is not here.  (switch (enumeration) requires
   * a case statement for each item in the enumeration.)
   */
  default:
    return false;
  }

}


/// Start conversion here.




GTKTwoVT::GTKTwoVT(Connection * c) : VT(c) {

  scrolled_window = (GtkWidget *)NULL;
  text_view = (GtkWidget *)NULL;
  buffer = (GtkTextBuffer *)NULL;
  marker = NULL;
  stored_width = 0;
  stored_height = 0;
  custom_tag_list = NULL;

  /*
  filtered_scrolled_window = (GtkWidget *)NULL;
  filtered_text_view = (GtkWidget *)NULL;
  filtered_buffer = (GtkTextBuffer *)NULL;
  filtered_marker = NULL;
  */

  input = (GtkWidget *)NULL;

  //  appended_to_filtered = false;
  appended_to_output = false;
  //  filtered_lines = 0;
  output_lines = 0;

  // Initialise the colour state variables.

  background_color_default = true;
  foreground_color_default = true;
  
  bold = false;
  faint = false;
  italicised = false;
  
  concealed = false;
  flashing = false;
  rapid_flashing = false;
  
  singly_underlined = false;
  negative_image = false;
  crossed_out = false;
  
  fg = 0;
  bg = 7;

  papaya_colour = false;

  // Initialise the SystemColour class which contains the colour data.
  systemColour = new SystemColour(conn->queryPreferences());
  colour_enabled = conn->queryPreferences()->getPreferenceBoolean("EnableColour");
  prompt_on_input_line = conn->queryPreferences()->getPreferenceBoolean("PromptOnInputLine");
  double_prompt = conn->queryPreferences()->getPreferenceBoolean("DoublePrompt");
  sound_beep = conn->queryPreferences()->getPreferenceBoolean("Beep");
  character_set = conn->queryPreferences()->getPreference("charset");

  atBottom = true;

}

void GTKTwoVT::initialise() {
  initTextArea();
}

GTKTwoVT::~GTKTwoVT() {
  delete prompt;
  delete systemColour;
}

/*
void GTKTwoVT::destroyFilteredWidget() {
  gtk_container_remove(GTK_CONTAINER(output_vbox), filtered_text_view);
  gtk_widget_destroy(filtered_text_view);
  filtered_text_view = (GtkWidget *)NULL;
  filtered_buffer = (GtkTextBuffer *)NULL;
}

void GTKTwoVT::createFilteredWidget() {

  filtered_scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  gtk_widget_show(filtered_scrolled_window);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(filtered_scrolled_window),
                         GTK_POLICY_ALWAYS,
                         GTK_POLICY_ALWAYS);


  // Create the text view and assign the buffer pointer
  filtered_buffer = gtk_text_buffer_new(NULL);
  filtered_text_view = gtk_text_view_new_with_buffer(filtered_buffer);
  gtk_widget_show(filtered_text_view);

  gtk_container_add(GTK_CONTAINER(filtered_scrolled_window),
                filtered_text_view);


  // Set the default font.
  PangoFontDescription *font_desc;
  font_desc = pango_font_description_from_string (conn->queryPreferences()->getPreference("OutputFont"));

  gtk_widget_modify_font (filtered_text_view, font_desc);
  pango_font_description_free (font_desc);
  
  gtk_text_view_set_editable(GTK_TEXT_VIEW(filtered_text_view), false);
  gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(filtered_text_view), GTK_WRAP_WORD);
  gtk_box_pack_start(GTK_BOX(output_vbox), filtered_scrolled_window, false, false, 0);

  g_signal_connect_data(GTK_OBJECT(filtered_text_view), "button_press_event",
                 GTK_SIGNAL_FUNC(output_button_pressed),
                 input, NULL, (GConnectFlags)0);
}
*/

void GTKTwoVT::initTextArea() {

  vbox = gtk_vbox_new(false, 2);

  // Create the text view and assign the buffer pointer
  buffer = gtk_text_buffer_new(NULL);

  scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  gtk_widget_show(scrolled_window);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
                         GTK_POLICY_ALWAYS,
                         GTK_POLICY_ALWAYS);
  //  g_object_set_data_full(G_OBJECT(vbox), "scrolled_window", scrolled_window,
  //                     (GDestroyNotify) gtk_widget_unref);

  text_view = gtk_text_view_new_with_buffer(buffer);
  gtk_widget_show(text_view);

  //  g_object_set_data_full(G_OBJECT(vbox), "text_view", text_view,
  //               (GDestroyNotify) gtk_widget_unref );

  createTagTable();

  gtk_container_add(GTK_CONTAINER(scrolled_window), text_view);

  // Set the default font.
  PangoFontDescription *font_desc;
  font_desc = pango_font_description_from_string (conn->queryPreferences()->getPreference("OutputFont"));

  gtk_widget_modify_font (text_view, font_desc);
  pango_font_description_free (font_desc);

  gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), false);
  gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_WORD);
  
  output_vbox = gtk_vbox_new(false, 2);
  gtk_widget_show(output_vbox);

  gtk_box_pack_start(GTK_BOX(output_vbox), scrolled_window, TRUE, TRUE, 0);

  prompt = new ColouredLabel(conn, "");
  prompt->createWidget();
  gtk_widget_show(prompt->getWidget());
  
  input = gtk_entry_new();
  gtk_widget_show (input);

  font_desc = pango_font_description_from_string(conn->queryPreferences()->getPreference("InputFont"));
  gtk_widget_modify_font(input, font_desc);
  pango_font_description_free(font_desc);
  
  g_signal_connect_data (input, "activate",
                   GTK_SIGNAL_FUNC (papaya_input_entry_activate),
                   this, NULL, (GConnectFlags)0);
  
  g_signal_connect_data (input,
                   "key_press_event",
                   GTK_SIGNAL_FUNC(papaya_keypress),
                   NULL,
                   NULL,
                   G_CONNECT_AFTER);
                     
  g_signal_connect_data (text_view,
                   "key_press_event",
                   GTK_SIGNAL_FUNC(papaya_keypress),
                   (gpointer)NULL, /*optional gpointer for sig func*/
                   NULL,
                   (GConnectFlags) 0);

  g_signal_connect_data (text_view,
                   "client_event",
                   GTK_SIGNAL_FUNC(textview_configure),
                   (gpointer) this,
                   NULL,
                   (GConnectFlags) 0);

  g_signal_connect_data(text_view, "selection_received", GTK_SIGNAL_FUNC(papaya_selection_received), NULL, NULL, (GConnectFlags)0);


  GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET(text_view), GTK_CAN_FOCUS );

  gtk_box_pack_start(GTK_BOX(vbox), output_vbox, TRUE, TRUE, 0);

  input_vbox = gtk_vbox_new(false, 2);
  gtk_widget_show(input_vbox);

  if (prompt_on_input_line) {
    GtkWidget * pbox = gtk_hbox_new(false, 2);
    gtk_box_pack_start(GTK_BOX(pbox), prompt->getWidget(), false, false, 0);
    gtk_box_pack_start(GTK_BOX(pbox), input, TRUE, TRUE, 0);
    gtk_widget_show(pbox);
    
    gtk_box_pack_start(GTK_BOX(input_vbox), pbox, false, false, 0);
  } else {
    gtk_box_pack_start(GTK_BOX(input_vbox), prompt->getWidget(), false, false, 0);
    gtk_box_pack_start(GTK_BOX(input_vbox), input, false, false, 0);
  }

  gtk_box_pack_start(GTK_BOX(vbox), input_vbox, false, false, 0);

  // Why does this center the widget in the box?

  //  gtk_widget_show(hbox);

  gtk_container_add(GTK_CONTAINER(box), vbox);
  gtk_widget_show(vbox);

  g_signal_connect_data(GTK_OBJECT(text_view), "button_press_event",
                  GTK_SIGNAL_FUNC(output_button_pressed),
                  input, NULL, (GConnectFlags)0);

  // Need to connect up a signal for when the size of this window is changed.
  g_signal_connect_data(GTK_OBJECT(text_view), "size_allocate",
                  GTK_SIGNAL_FUNC(output_size_changed), conn,
                  NULL, (GConnectFlags)0);
}

void GTKTwoVT::hideInput() {
  gtk_widget_hide(input_vbox);
}

void GTKTwoVT::showInput() {
  gtk_widget_show(input_vbox);
}

char * GTKTwoVT::zapChars(char * text) {

  char * pc;

  if (*text == '\r')
    text++;

  pc = text;

  while (*pc != '\0') {
    if (*pc == '\r') { // || (unsigned char)*pc > 127) {
      memmove(pc, pc + 1, strlen(pc + 1) + 1);
      // Don't increment pc, as we just moved the next char to there
      continue;
    }

    if (*pc == MAGIC_PROMPT) {
      memmove(pc, pc + 1, strlen(pc + 1) + 1);
      continue;
    }

    pc++;
  }

  return text;
}

/**
 * Any text to be considered for the display will be sent to this method.
 * This includes prompts, which the VT must remove if it wishes to display
 * them in a separate area.
 */

void GTKTwoVT::append(char * text) {
  char * pc;
  char * last_marker;
  
  snarfPrompt(text); // note: modifies text in place & sets prompt

  pc = zapChars(text);
  last_marker = pc;

  if (pc[0] != '\0') // strlen(pc) > 0
    mainWindow->nextText(conn);

  while (*pc != 0) {

    switch (*pc) {
    case ESCAPE:
      // NUL terminate the last_marker string.
      *pc = '\0';
      // Write all stuff between last_marker and pc to the VT.
      printVT(last_marker);
      pc = parseVTCode(pc);
      last_marker = pc;
      continue;

    case 0x08:
    // Look for character 8, backspace.
      *pc = '\0';
      printVT(last_marker);
      deleteOneChar();
      pc++;
      last_marker = pc;
      continue;

    case '<':
      if (conn->getSocket()->getTelnetOption(Telnet::MXP)) {
      // MXP MUDs send this through as a tag.
      *pc = '\0';
      printVT(last_marker);
      pc++;
      last_marker = pc;
      continue;
      }
      // NON-MXP MUDs treat this as a normal character.
      break;

    case '>':
      if (conn->getSocket()->getTelnetOption(Telnet::MXP)) {
      // MXP MUDs send this through as a tag.
      *pc = '\0';
      printVTMarkup(last_marker);
      pc++;
      last_marker = pc;
      continue;
      }
      // NON-MXP MUDs treat this as a normal character.
      break;
    }
    pc++;
  }

  printVT(last_marker);

  //  if (appended_to_filtered)
  //    filtered_lines++;
  if (appended_to_output)
    output_lines++;

  //  appended_to_filtered = false;
  appended_to_output = false;
}

char * GTKTwoVT::getColourCodes(char * s) {

  char * pc;
  static char buf[16384];
  int count = 0;

  while ((pc = strchr(s, ESCAPE))) {

    buf[count++] = *pc++; // ESCAPE
    buf[count++] = *pc++; // [
    while (*pc && !isalpha(*pc))
      buf[count++] = *pc++;

    if (*pc)
      buf[count++] = *pc++; // alpha terminating character

    s = pc;
  }

  buf[count] = '\0';

  return buf;
}

void GTKTwoVT::snarfPrompt(char * s)
{
    // Find last prompt-end marker
    char *marker = strrchr(s, MAGIC_PROMPT);
    if (!marker) // no eol to be seen, no changes needed.
      return;

    // Find last line-end before marker
    char *pc;
    for (pc = marker - 1; pc >= s; --pc)
      if (*pc == '\n')
          break;

    ++pc; // point to start of line (or buffer if no line-end found)

    // Take a copy of the prompt.
    int prompt_len = marker - pc;
    char *prompt = new char[prompt_len + 1];
    memcpy(prompt, pc, prompt_len);
    prompt[prompt_len] = 0;

    setPrompt(prompt);

    // Now meddle with the output buffer.
    if (double_prompt) {
      delete[] prompt;
      return; // no changes needed.
    }

    // Replace prompt with only the color codes from it.
    strcpy(pc, getColourCodes(prompt)); // guaranteed to be smaller
    strcpy(pc+strlen(pc), marker+1);
    delete[] prompt;
}

/**
 * Sets the prompt to 'text', without stripping colour codes as
 * prompt understands these now.
 */

void GTKTwoVT::setPrompt(char * text) {
  
  phandler->processPromptFilters(conn, text);
  if (strlen(text) == 0)
    return;

  char * pr = strdup(text); // Assume it isn't safe to edit text directly.
  prompt->setText(pr);
  free(pr);
}

/**
 * 'code' is a pointer to the ESCAPE char at the start of a VT100 code.
 * The returned pointer points at the first character after the complete
 * VT100 code.
 */

char * GTKTwoVT::parseVTCode(char * code) {

  char *pc = code+1;

  switch (*pc) {
  case '[':
    pc = parseBracketVTCode(pc);
    break;

  case ']':
    pc = parseXTermCode(pc);
    break;

  default:
    pc = parsePlainVTCode(pc);
    break;
  }

  pc++;
  return pc;
}

char * GTKTwoVT::parseXTermCode(char * pc) {

  // Valid codes:
  // \033]0;<title>\a
  // \033]1;<icon>\a

  pc++; // Skip the bracket
  char * start = pc;

  while (isdigit(*pc))
    pc++;

  // 1 = icon title, 2 = main title, 0 = both

  // Skip over the ;
  pc++;

  char * title_start = pc;

  while (1) {
    // Hit EOS while parsing.
    if (*pc == '\0') {
      break;
    }

    // BEL marks the end of the sequence.
    if (*pc == '\007') {
      *pc = '\0';
      switch (*start) {
      case '0':
      setTitleBar(title_start);
      setIcon(title_start);
      break;

      case '1':
      setIcon(title_start);
      break;

      case '2':
      setTitleBar(title_start);
      break;

      default: // Do nothing.
      break;
      }

      break;
    }

    pc++;
  }

  // Return current position.
  return pc;
}

char * GTKTwoVT::parseBracketVTCode(char * pc) {

  char * orig = pc;

  while (!isalpha(*pc))
    pc++;

  switch (*pc) {

  case 'm': // Colour code
    setColour(orig);
    break;

  case 'p': // Internal Papaya colour code.
    setPapayaColour(orig);
    break;

  case 'q': // Reset Papaya colour.
    resetPapayaColour();

    // Cursor Control

  case 'H': // Set cursor to x;y
  case 'f': // Set cursor to x;y
    setPosition(orig);
    break;

  case 'A': // Move the cursor up x rows
    break;

  case 'B': // Move cursor down x rows
    break;

  case 'C': // Move cursor forward x columns
    break;

  case 's': // Save current current position
  case '7':
    break;

  case 'u': // Restore cursor position to last saved.
  case '8':
    break;

    // Device Status

  case 'c': // Requests a "Report Device Code" response
    break;

  case 'n': // Various device response stuff.
    break;

    // Terminal Setup
   
  case 'h': // Line wrap enabled (7h)
    break;

  case 'l': // Line wrap disabled (7l)
    break;

    // Scrolling

  case 'r': // Enable scrolling "x,y" = rows x to y.  No args = whole display
    break;

    // Tab Control

  case 'g': // Clears tab at the current position (3g = all tabs)
    break;

    // Erasing Text

  case 'K': // Various line based erases
    break;

  case 'J': // Various row based erases
    break;

    // Printing

  case 'i': // Printing related commands
    break;

  }

  // Now at the character that marks the start of normal text or the ESCAPE
  // for a new code.
  return pc;
}

char * GTKTwoVT::parsePlainVTCode(char * pc) {

  while (!isalpha(*pc))
    pc++;

  switch (*pc) {

    // Scrolling
    
  case 'D': // Scroll down one line
    break;
    
  case 'M': // Scroll up one line
    break;

    // Tab Control
    
  case 'H': // Sets a tab at the current position
    break;
    
    // Terminal Setup

  case 'c': // Reset all terminal settings to default
    break;

    // Fonts

  case ')': // Set default font
    break;

  case '(': // Use alternate font
    break;

  }


  pc++;
  return pc;
}

void GTKTwoVT::setPapayaColour(char * buf) {

  int red;
  int green;
  int blue;

  // allocate color

  char * pc;

  pc = strchr(buf, 'p');
  if (!pc)
    return;

  if (pc - buf != 12) { // [rrr;ggg;bbb
    printf(_("Invalid Papaya Colour code."));
    printf(CRLF);
    return;
  }

  *pc = '\0';
  if (sscanf(buf, "[%d;%d;%d", &red, &green, &blue) != 3) {
    printf(_("PapayaColour: unable to sscanf."));
    printf(CRLF);
    return;
  }

  papaya_colour = true;

  papaya_colour_red = red;
  papaya_colour_green = green;
  papaya_colour_blue = blue;

  // When text of this colour is inserted, it should use an anonymous tag.

}

void GTKTwoVT::resetPapayaColour() {
  papaya_colour = false;
}

void GTKTwoVT::setColour(char * buf) {
  char * pc = buf;
  char buf2[10];
  int pos = 0;

  buf2[0] = '\0';
  
  papaya_colour = false;

  while (1) {

    // Leave the loop if we hit end of string
    if (*pc == '\0')
      break;

    // If we haven't got a [ or ; indicating more codes, leave the loop.
    if (!(*pc == ';' || *pc == '['))
      break;

    // Rip out the bit until the next non-alphanumeric character.
    pos = 0;

    buf2[pos] = *pc++;

    while (1) {
      // Check for NUL character in case colour code split over two packets
      if (isalpha(*pc) || *pc == ';' || *pc == '\0')
        break;

      buf2[pos++] = *pc++;
    }
    
    buf2[pos] = '\0';
    setActualColour(buf2);
  }
}

void GTKTwoVT::setActualColour(char * buf) {

  if (!colour_enabled)
    return;

  if (buf[1] == '\0') { // strlen(buf) == 1
    int tmp = 0;

    switch (*buf) {
    case '0':
      background_color_default = true;
      foreground_color_default = true;

      bold = false;
      faint = false;
      italicised = false;

      concealed = false;
      flashing = false;
      rapid_flashing = false;

      singly_underlined = false;

      negative_image = false;

      crossed_out = false;

      return;

    case '1':
      bold = true;
      return;

    case '2':
      faint = true;
      return;

    case '3':
      italicised = true;
      return;

    case '4':
      singly_underlined = true;
      return;

    case '5':
      flashing = true;
      return;

    case '6':
      rapid_flashing = true;
      return;

    case '7':
      negative_image = true;
      return;

    case '8':
      concealed = true;
      return;

    case '9':
      crossed_out = true;
      return;

    default:
      printf (_("Unsupported colour code: %s\n"), buf);
      return;
    }
  } // End single code

  if (buf[2] == '\0') { // Two digit colour code


    int i = 0; // used in for-loop later, vc++ doesn't like initialisation being skipped
    int tmp = 0;
    switch (buf[0]) {

    case '2':

      switch (buf[1]) {

      case '1':
      //    doubly_underlined = true;
      return;

      case '2':
      bold = false;
      faint = false;
      return;

      case '3':
      italicised = false;
      return;

      case '4':
      singly_underlined = false;
      return;

      case '5':
      flashing = false;
      rapid_flashing = false;
      return;

      case '7':
      negative_image = false;
      return;

      case '8':
      concealed = false;
      return;

      case '9':
      crossed_out = false;
      return;

      default:
      printf (_("Unsupported colour code: %s.\n"), buf);
      return;

      } // Unset attributes

    case '3':
    case '4':

      if (buf[1] == '9') {
      if (buf[0] == '3')
        foreground_color_default = true;
      else
        background_color_default = true;
      return;
      }

      for (i = 0; i < 8; i++) {
      struct colour_table * table = systemColour->getColourTable();
      if (table[i].colour_character == buf[1]) {
        if (buf[0] == '3') {
          foreground_color_default = false;
          fg = i;
          return;
        }
        
        if (buf[0] == '4') {
          background_color_default = false;
          bg = i;
          return;
        }
        
        return;
      }
      }

      return;

    default:

      printf (_("Unsupported colour code: %s.\n"), buf);

    }
  }

  if (buf[0] == '\0') { // ESC[m is an alias for ESC[0m
    background_color_default = true;
    foreground_color_default = true;
    
    bold = false;
    faint = false;
    italicised = false;
    
    concealed = false;
    flashing = false;
    rapid_flashing = false;
    
    singly_underlined = false;
    //    doubly_underlined = false;
    negative_image = false;
    crossed_out = false;
    return;
  }

  // Length > 2.
  printf (_("Invalid colour code: %s.\n"), buf);
}

void GTKTwoVT::beep(char * buf) {
  char * b;
  while ((b = strchr(buf, '\007'))) {
    gdk_beep();
    buf = b + 1;
  }
}

void GTKTwoVT::deleteOneChar() {

  GtkTextIter end;
  GtkTextIter start;

  gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(buffer), &start);
  gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(buffer), &end);

  if (gtk_text_iter_backward_char(&start))
    gtk_text_buffer_delete(GTK_TEXT_BUFFER(buffer), &start, &end);


}

struct tag_info {
  char * name;
  char * arguments;
};

void GTKTwoVT::printVTMarkup(char * text) {

  // work out what extra tags we need to give to this text.

  if (!strncasecmp(text, "/tag", 4)) {

    // Closing tag, pop the top item off the stack.
    struct tag_info * tag_data;
    tag_data = (struct tag_info *)g_list_last(custom_tag_list);
    custom_tag_list = g_list_remove(custom_tag_list, tag_data);

    free(tag_data->name);
    free(tag_data->arguments);
    free(tag_data);

    return;
  }

  if (!strncasecmp(text, "tag", 3)) {
    struct tag_info * tag_data = (struct tag_info *)malloc(sizeof(struct tag_info));
    
    tag_data->name = strdup("foo");
    tag_data->arguments = strdup("arguments");

    custom_tag_list = g_list_append(custom_tag_list, tag_data);
    return;
  }


  printf ("Received %s to printVTMarkup, which is invalid.\n");
  printVT(text);
  return;

  // Is there some nice simple code that parses HTML style tags and
  // returns a nice list of elements and values?
}

void GTKTwoVT::printVT(char * text) {
  char * start = text;

  if (sound_beep)
    beep(start);

  if (flashing && (start[0] == '\n' || start[0] == '\r')) {
    start++;
    flashing = false;
  }

  insertText(start);
}

void GTKTwoVT::insertText(char * text) {

  // Figure out which buffer we're writing to.
  GtkTextBuffer * target_buffer;
  gboolean free_it = false;

  gchar * output = NULL;
  gsize read, written;
  GError * error = NULL;

  if (!character_set)
    character_set = "ISO-8859-1";

  if (character_set[0] != '\0') // Allow path with no conversion at all with charset blank.
    output = g_convert(text, strlen(text), "UTF-8", character_set,
                   &read, &written, &error);

  if (output) {
#ifndef WIN32
    free_it = true;
#endif
    text = output;
  }

  target_buffer = buffer;
  appended_to_output = true;

  GtkTextIter start, end;

  // Retrieve the current end of buffer.
  gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(buffer),
                         &end);

  // Create a marker for use later.
  marker = gtk_text_buffer_create_mark(buffer, "", &end, false);

  // Retrieve the offset of the current end marker, which will be the start of our range later.
  gint start_offset = gtk_text_iter_get_offset(&end);

  // Insert the text
  gtk_text_buffer_insert(GTK_TEXT_BUFFER(target_buffer),
                   &end,
                   text,
                   -1);

  // Retrieve the saved start position.
  gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(target_buffer),
                             &start, start_offset);
  // &end is automatically updated by insert.

  if (singly_underlined)
    gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              "underline", &start, &end);
  else
    gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              "underline-cancel", &start, &end);

  // If foreground colour set to default
  if (foreground_color_default) {
    if (negative_image)
      gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              "foreground_reverse_default", &start, &end);
    else
      gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              "foreground_default", &start, &end);
  }

  // If  background colour set to default
  if (background_color_default) {
    if (negative_image)
      gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              "background_reverse_default", &start, &end);
    else
      gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              "background_default", &start, &end);
  }

  // Set the font.
  char * font_tag;
  if (bold && italicised) {
    font_tag = "italic_font";
    // @@    font_tag = "bold_italic_font";
  }
  else if (bold) {
    font_tag = "bold_font";
  }
  else if (italicised) {
    font_tag = "italic_font";
  } else {
    font_tag = "default_font";
  }
  gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                            font_tag, &start, &end);

  char fg_tag[1024];
  char bg_tag[1024];  
  if (!foreground_color_default) {
    if (negative_image)
      snprintf(fg_tag, 1024, "bg_colour:%d", bold ? fg + 8 : fg);
    else
      snprintf(fg_tag, 1024, "fg_colour:%d", bold ? fg + 8 : fg);

    gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              fg_tag, &start, &end);
  }

  if (!background_color_default) {
    if (negative_image)
      snprintf(bg_tag, 1024, "fg_colour:%d", bold ? bg + 8 : bg);
    else
      snprintf(bg_tag, 1024, "bg_colour:%d", bold ? bg + 8 : bg);
    gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              bg_tag, &start, &end);
  }

  if (papaya_colour) {
    // Determine the appropriate colour tags.
    
    snprintf(fg_tag, 1024, "papaya_colour:%d:%d:%d",
           papaya_colour_red,
           papaya_colour_green,
           papaya_colour_blue);
    
    // Does a tag already exist by this name?
    if (!gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(GTK_TEXT_BUFFER(target_buffer)), fg_tag)) {
      
      // Create a tag for this colour.
      GdkColor color;
      color.red = papaya_colour_red * 0xffff / 255;
      color.green = papaya_colour_green * 0xffff / 255;
      color.blue = papaya_colour_blue * 0xffff / 255;
      gdk_color_alloc(gdk_colormap_get_system(), &color);
      
      gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(target_buffer),
                         fg_tag,
                         "foreground-gdk",
                         &color,
                         NULL);
    }

    gtk_text_buffer_apply_tag_by_name(GTK_TEXT_BUFFER(target_buffer),
                              fg_tag, &start, &end);


  } // end papaya_colour

  if (free_it)
    free(text);
}

void GTKTwoVT::scroll() {

  // @@ Implement restricted scrollback.

#if 0

  // Trim the amount of text to the maximum number of characters.
  if (conn->queryPreferences()->getPreferenceBoolean("UseMaxLines")
      && conn->queryPreferences()->getPreferenceInteger("MaxLines") > 0) {


    int lines = gtk_text_buffer_get_line_count(GTK_TEXT_BUFFER(buffer));
    int remove_output = lines - conn->queryPreferences()->getPreferenceInteger("MaxLines");

    // @@ Remove the first remove_output lines from the text buffer.


    // Are there any lines to remove.
    if (remove_output > 0) {
      gtk_text_freeze(GTK_TEXT(output));
      
      while (remove_output > 0) {
      // Remove the first line from the box.
      char * text = gtk_editable_get_chars(GTK_EDITABLE(output), 0, -1);
      // gtk_editable_get_chars does a strdup ...
      if (text) {
        char * pc = strchr(text, '\n');
        gtk_text_set_point(GTK_TEXT(output), 0);
        gtk_text_forward_delete(GTK_TEXT(output), pc - text + 1);
        output_lines--;
        remove_output--;
        free(text);
      }
      }
      gtk_text_set_point(GTK_TEXT(output), gtk_text_get_length(GTK_TEXT(output)));
      gtk_text_thaw(GTK_TEXT(output));
    }
    /*
    if (filtered_output) {
      int remove_filtered = filtered_lines - conn->queryPreferences()->getPreferenceInteger("MaxLines");
      // Are there any lines to remove.
      if (remove_filtered > 0) {
      gtk_text_freeze(GTK_TEXT(filtered_output));
      
      while (remove_filtered > 0) {
        
        // Remove the first line from the box.
        char * text = gtk_editable_get_chars(GTK_EDITABLE(output), 0, -1);
        if (text) {
          char * pc = strchr(text, '\n');
          gtk_text_set_point(GTK_TEXT(filtered_output), 0);
          gtk_text_forward_delete(GTK_TEXT(filtered_output), pc - text + 1);
          filtered_lines--;
          remove_filtered--;
        }
      }
      gtk_text_set_point(GTK_TEXT(filtered_output), gtk_text_get_length(GTK_TEXT(filtered_output)));
      gtk_text_thaw(GTK_TEXT(filtered_output));
      }
    }
    */
  }

#endif


  if (!doScroll())
      return;

  if (text_view && marker) {
        gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(text_view), marker, 0.0, true, 0.0, 1.0);
      gtk_text_buffer_delete_mark(buffer, marker);
      marker = NULL;
  }

}

bool GTKTwoVT::doScroll() {
  
  // If scrollbars are at the bottom always return true.
  if (atBottom == true)
        return true;

  // If scrollbars are not at the bottom only return true if scroll on input set.
  return conn->queryPreferences()->getPreferenceBoolean("ScrollOnInput");
}

/**
 * This function is called before text is inserted to determine
 * whether or not we should scroll to bottom after insertion.
 */

void GTKTwoVT::preInsert() {

      // This twisted bit of code gets the position of the last character in the
      // text buffer, and works out if it's on screen.  If it's on screen then we're
      // scrolled to the bottom of the text buffer.

      GtkTextIter iter;
      GdkRectangle rectangle;
    int window_x, window_y;
      gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(buffer), &iter);
      gtk_text_view_get_iter_location(GTK_TEXT_VIEW(text_view), &iter, &rectangle);
    gtk_text_view_buffer_to_window_coords(GTK_TEXT_VIEW(text_view), GTK_TEXT_WINDOW_WIDGET, rectangle.x, rectangle.y, &window_x, &window_y);

    if (window_y <= text_view->allocation.height)
            atBottom = true;
      else
            atBottom = false;
}

// @@ Perhaps an expose event should trigger this.

void StringToRGB(char *, gushort *, gushort *, gushort *);
void GTKTwoVT::use() {

  GdkColor background_colour;
  gushort red, green, blue;

  StringToRGB(conn->queryPreferences()->getPreference("Background_RGB"), &red, &green, &blue);

  background_colour.red = red;
  background_colour.green = green;
  background_colour.blue = blue;

  gdk_color_alloc(gdk_colormap_get_system(), &background_colour);

  GdkWindow * window = gtk_text_view_get_window(GTK_TEXT_VIEW(text_view),
                                    GTK_TEXT_WINDOW_TEXT);
  gdk_window_set_background(window, &background_colour);

}

GtkWidget * GTKTwoVT::getInput() {
  return input;
}

GtkWidget * GTKTwoVT::getOutput() {
  return text_view;
}

GtkWidget * GTKTwoVT::getBox() {
  return vbox;
}

GtkWidget * GTKTwoVT::getPrompt() {
  return prompt->getWidget();
}

int GTKTwoVT::getStoredWidth() {
  return stored_width;
}

int GTKTwoVT::getStoredHeight() {
  return stored_height;
}

int GTKTwoVT::width() {
  int width, height;
  getScreenSize(&width, &height);
  return width;
}

int GTKTwoVT::height() {
  int width, height;
  getScreenSize(&width, &height);
  return height;
}

void GTKTwoVT::getScreenSize(int * width, int * height) {
  int h, w;
  int ww, wh;

  PangoFontDescription * font = pango_font_description_from_string(conn->queryPreferences()->getPreference("OutputFont"));
  
  PangoContext *pc;
  PangoFontMetrics *metrics;
  PangoLanguage *lang;
  
  pc = gtk_widget_get_pango_context(text_view);
  lang = pango_context_get_language(pc);
  metrics = pango_context_get_metrics(pc, font, lang);
  w = pango_font_metrics_get_approximate_char_width(metrics);
  pango_font_metrics_unref(metrics);
  
  h = pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics);


  // @@ Rewrite this to use Pango
#if 0
  h = conn->queryPreferences()->getOutput()->ascent + conn->queryPreferences()->getOutput()->descent;
  w = gdk_char_width(conn->queryPreferences()->getOutput(), 'W');
#endif

  ww = text_view->allocation.width;
  wh = text_view->allocation.height;

  *width = ww/PANGO_PIXELS(w);
  *height = wh/PANGO_PIXELS(h);

  stored_width = *width;
  stored_height = *height;
}

void GTKTwoVT::setPosition(char * text) {
  
  // Returning immediately since this support is nowhere near complete.
  return;

  int row, column;
  char first[10];
  char second[10];
  int fc = 0, sc = 0;

  // Get past the [
  text++;

  while (isdigit(*text)) {
    first[fc++] = *text++;
  }
  first[fc] = '\0';

  // Get past the ;
  text++;

  while (isdigit(*text)) {
    second[sc++] = *text++;
  }
  second[sc] = '\0';

  row = atoi(first);
  column = atoi(second);

  setPosition(row, column);
}

void GTKTwoVT::setPosition(int r, int c) {
#if 0
  int rows, columns;
  getScreenSize(&columns, &rows);

  if (r > rows || c > columns) {
    return;
  }

  // Retrieve the text from the text box.
  char * text = gtk_editable_get_chars(GTK_EDITABLE(output), 0, -1);

  char * ptr = text + strlen(text);

  // Need to figure out which line is the right one.
  for (int i = rows; i >= 0; i--) {

    // Move to the char after '\n';
    ptr = findStartOfLine(ptr, text);

    if (rows - i == r) {

      char * eol = ptr;
      while (*eol != '\n')
      eol++;
      eol--; // Back off the \n

      while (1) {
      if (c <= eol - ptr) {
        gtk_text_set_point(GTK_TEXT(output), (ptr - text) + c);
        return;
      }

      gtk_text_set_point(GTK_TEXT(output), (int)(eol - text));
      insertText(" ");
      eol++;
      }
      
      // We might be off by one at this point.
      return;
    }
  }
#endif
}

char * GTKTwoVT::findStartOfLine(char * ptr, char * limit) {

  ptr--;
  ptr--;

  while (*ptr != '\n' && ptr >= limit)
    ptr--;

  ptr++; // Go past the \n

  if (ptr < limit)
    ptr = limit;

  return ptr;
}

void GTKTwoVT::moveLeft() {
}

void GTKTwoVT::moveRight() {
}

void GTKTwoVT::setInput(char * s) {
  gtk_entry_set_text(GTK_ENTRY(input), s);
  gtk_editable_set_position(GTK_EDITABLE(input), -1);
}

/**
 * The preferences have been updated, so let's check the settings.
 */

void GTKTwoVT::prefsUpdated() {

  // Update the colour table stored in SystemColour.
  Prefs * prefs = conn->queryPreferences();
  systemColour->update(prefs);

  colour_enabled = conn->queryPreferences()->getPreferenceBoolean("EnableColour");
  prompt_on_input_line = conn->queryPreferences()->getPreferenceBoolean("PromptOnInputLine");
  double_prompt = conn->queryPreferences()->getPreferenceBoolean("DoublePrompt");
  sound_beep = conn->queryPreferences()->getPreferenceBoolean("Beep");
  character_set = conn->queryPreferences()->getPreference("charset");



  // Update the colour and font tags.
  createTagTable();

  // Change the font on the font input

  PangoFontDescription * font = pango_font_description_from_string(conn->queryPreferences()->getPreference("InputFont"));
  gtk_widget_modify_font(getInput(), font);
  pango_font_description_free(font);

  use();

  // Change where flashing text goes.
  /*
  if (conn->queryPreferences()->getPreference("FilteredOutput") && !filtered_text_view) {
    createFilteredWidget();
    scroll();
    return;
  }

  if (!conn->queryPreferences()->getPreference("FilteredOutput") && filtered_text_view) {
    destroyFilteredWidget();
    scroll();
    return;
  }
  */

  // This causes NAWS to be resent.
  output_size_changed(NULL, NULL, conn);
}

void GTKTwoVT::keypressEvent(GtkWidget * widget, GdkEventKey * event) {
  papaya_keypress(widget, event);

  // We need to detect which widget currently has focus.  If it's not the
  // input, then we need to switch focus and append the character.

  if (GTK_WIDGET_HAS_FOCUS(widget))
    return;

  focus();

  // append the character.
  gchar * current_input = (gchar *)gtk_entry_get_text(GTK_ENTRY(getInput()));
  gchar * new_input = (gchar *)g_malloc(strlen(current_input) + 2);
  snprintf(new_input, strlen(current_input) + 2, "%s%c", current_input, event->keyval);
  setInput(new_input);
  g_free(new_input);

}

int papaya_keypress(GtkWidget * widget, GdkEventKey * event) {

  Connection * c = mainWindow->getCurrentConnection();
  if (!c)
    return 0;

  /* If this is line mode, check for command history. */
  if (c->getVT()->getMode() == VTLineMode) {
    switch(event->keyval) {

    case P:
      if (!(event->state & GDK_CONTROL_MASK))
      break;
    case UP_ARROW:
      c->getVT()->setInput(c->getHistory()->getPrev());
      return 1;

    case N:
      if (!(event->state & GDK_CONTROL_MASK))
      break;
    case DOWN_ARROW:
      c->getVT()->setInput(c->getHistory()->getNext());
      return 1;

    /* Check for scroll up/down. */
  case PAGE_UP:
    c->getVT()->scrollUp();
    break;
  case PAGE_DOWN:
    c->getVT()->scrollDown();
    }

    return 1;
  }

  if (event->keyval == ENTER || event->keyval == KP_ENTER) {
    c->getSocket()->write("\r\0", 2);
    return 1;
  }

  if (event->keyval == TAB) {
    printf ("Sending horizontal tab.\n");
    c->getSocket()->write("\011", 1);
    return 1;
  }

  if (event->keyval == BACKSPACE) {
    c->getSocket()->write("\x7f", 1);
    return 1;
  }

  if (event->string && event->string[0] != '\0') {
    c->getSocket()->write(event->string, strlen(event->string));
    return 1;
  }

  return 0;
}

int papaya_input_entry_activate(GtkEditable * editable, gpointer data) {

  Connection * conn = mainWindow->getCurrentConnection();
  if (!conn)
    return 0;

  if (conn->getVT()->getMode() == VTCharacterMode) {
    conn->getVT()->setInput("");
    return 1;
  }

  GTKTwoVT * pvt = (GTKTwoVT *)conn->getVT();

  gchar * text = (gchar *)gtk_entry_get_text(GTK_ENTRY(pvt->getInput()));
  if (!commandInterpreter)
    commandInterpreter = new CommandInterpreter();

  // Convert this text from UTF-8 to the MUD character set if requested in
  // preferences.

  gchar * output;
  gsize read, written;
  GError * error = NULL;

  gchar * out_charset = conn->queryPreferences()->getPreference("charset");
  if (!out_charset)
    out_charset = "ISO-8859-1";

  if (out_charset[0] != '\0') {
    output = g_convert(text, strlen(text), out_charset, "UTF-8",
                   &read, &written, &error);
    commandInterpreter->interpret(conn, output);
#ifndef WIN32
    free(output);
#endif
  } else {
    commandInterpreter->interpret(conn, text);
  }

  return 1;
}

void GTKTwoVT::setMode(VTMode m) {

  VT::setMode(m);

  if (getMode() == VTCharacterMode)
    hideInput();
  
  if (getMode() == VTLineMode)
    showInput();

  focus();
}

void GTKTwoVT::focus() {
  switch (getMode()) {
  case VTCharacterMode:
    GTK_WIDGET_SET_FLAGS( GTK_WIDGET(text_view), GTK_CAN_FOCUS );
    gtk_widget_grab_focus(text_view);
    break;
  case VTLineMode:
    GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET(text_view), GTK_CAN_FOCUS );
    gtk_widget_grab_focus(input);
    break;
  }
}

void GTKTwoVT::hideCommands() {
  gtk_entry_set_visibility(GTK_ENTRY(input), false);
}

void GTKTwoVT::showCommands() {
  gtk_entry_set_visibility(GTK_ENTRY(input), true);
}

bool GTKTwoVT::showingCommands() {
  return GTK_WIDGET_VISIBLE(GTK_ENTRY(input)->editable);
}

void GTKTwoVT::scrollUp() {
  gint x, y;
  GtkTextIter iter;

  gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(text_view),
                              gtk_text_view_get_window_type(GTK_TEXT_VIEW(text_view), text_view->window),
                              0, 0,
                              &x, &y);
  
  gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(text_view), &iter, x, y);

  gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(text_view), &iter, false, true,
                         0.0, 1.0);
}

void GTKTwoVT::scrollDown() {

  gint x, y;
  GtkTextIter iter;

  gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(text_view),
                              gtk_text_view_get_window_type(GTK_TEXT_VIEW(text_view), text_view->window),
                              text_view->allocation.width, text_view->allocation.height,
                              &x, &y);

  gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(text_view), &iter, x, y);
  gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(text_view), &iter, false, true,
                         0.0, 0.0);
}

void GTKTwoVT::createTagTable() {
  int i;

  // Create the tag table for this connection.
  
  GtkTextTagTable * tag_table = gtk_text_buffer_get_tag_table(GTK_TEXT_BUFFER(buffer));
  if (!tag_table)
    abort();

  // @@ This VT should have its own colour table, rather than using one
  // stored in the prefs, the only thing stored in prefs should be the
  // colour specifications.
  struct colour_table * table = systemColour->getColourTable();

  // Create a foreground_default tag.

  GtkTextTag * tag = gtk_text_tag_table_lookup(tag_table, "foreground_default");
  GtkTextTag * reverse_tag = gtk_text_tag_table_lookup(tag_table, "foreground_reverse_default");

 // Will be in the range of 0 to 8 (8 = transparent)
  int index = conn->queryPreferences()->getPreferenceInteger("DefaultForegroundColour");
  GdkColor color;

  if (index == -1 || index == 8) {
    StringToRGB(conn->queryPreferences()->getPreference("Background_RGB"),
            &(color.red), &(color.green), &(color.blue));
  } else {
    color.red = table[index].red;
    color.green = table[index].green;
    color.blue = table[index].blue;
  }
  
  if (tag)
    g_object_set(tag, "foreground-gdk", &color, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "foreground_default",
                         "foreground-gdk",
                         &color,
                         NULL);
  if (reverse_tag)
    g_object_set(reverse_tag, "background-gdk", &color, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "foreground_reverse_default",
                         "background-gdk",
                         &color,
                         NULL);

  tag = gtk_text_tag_table_lookup(tag_table, "background_default");
  reverse_tag = gtk_text_tag_table_lookup(tag_table, "background_reverse_default");
  index = conn->queryPreferences()->getPreferenceInteger("DefaultBackgroundColour");
  
  if (index == -1 || index == 8) {
    StringToRGB(conn->queryPreferences()->getPreference("Background_RGB"),
            &(color.red), &(color.green), &(color.blue));
  } else {
    color.red = table[index].red;
    color.green = table[index].green;
    color.blue = table[index].blue;
  }

  if (tag)
    g_object_set(tag, "background-gdk", &color, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "background_default",
                         "background-gdk",
                         &color,
                         NULL);
  if (reverse_tag)
    g_object_set(reverse_tag, "foreground-gdk", &color, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "background_reverse_default",
                         "foreground-gdk",
                         &color,
                         NULL);

  // Create a tag for each of the foreground colours.
  for (i = 0; i < 16; i++) {
    char buf[1024];

    snprintf(buf, 1024, "fg_colour:%d", i);

    // Retrieve and allocate the colour.
    GdkColor color;
    color.red = table[i].red;
    color.green = table[i].green;
    color.blue = table[i].blue;
    gdk_color_alloc(gdk_colormap_get_system(), &color);

    tag = gtk_text_tag_table_lookup(tag_table, buf);
    if (tag)
      g_object_set(tag, "foreground-gdk", &color, NULL);
    else
      gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         buf,
                         "foreground-gdk",
                         &color,
                         NULL);
  }

  // Create a tag for each of the background colours.
  for (i = 0; i < 16; i++) {
    char buf[1024];

    snprintf(buf, 1024, "bg_colour:%d", i);

    // Retrieve and allocate the colour.
    GdkColor color;
    color.red = table[i].red;
    color.green = table[i].green;
    color.blue = table[i].blue;
    gdk_color_alloc(gdk_colormap_get_system(), &color);

    tag = gtk_text_tag_table_lookup(tag_table, buf);
    if (tag)
      g_object_set(tag, "background-gdk", &color, NULL);
    else
      gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         buf,
                         "background-gdk",
                         &color,
                         NULL);
  }

  PangoFontDescription * font = pango_font_description_from_string(conn->queryPreferences()->getPreference("OutputFont"));

  // Create the default_font tag
  tag = gtk_text_tag_table_lookup(tag_table, "default_font");
  if (tag)
    g_object_set(tag, "font-desc", font, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "default_font",
                         "font-desc",
                         font,
                         NULL);

  // Modify the widget to use it.
  gtk_widget_modify_font(text_view, font);
  pango_font_description_free(font);

  // Create the bold font tag.
  font = pango_font_description_from_string(conn->queryPreferences()->getPreference("BoldFont"));

  tag = gtk_text_tag_table_lookup(tag_table, "bold_font");
  if (tag)
    g_object_set(tag, "font-desc", font, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "bold_font",
                         "font-desc",
                         font,
                         NULL);
  pango_font_description_free(font);

  // Create the Italic font.
  font = pango_font_description_from_string(conn->queryPreferences()->getPreference("ItalicFont"));

  tag = gtk_text_tag_table_lookup(tag_table, "italic_font");
  if (tag)
    g_object_set(tag, "font-desc", font, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "italic_font",
                         "font-desc",
                         font,
                         NULL);
  pango_font_description_free(font);

  // underline PangoUnderline, underline-set boolean
  tag = gtk_text_tag_table_lookup(tag_table, "underline");
  if (tag)
    g_object_set(tag, "underline-set", singly_underlined, "underline", PANGO_UNDERLINE_SINGLE, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "underline",
                         "underline-set",
                         true,
                         "underline",
                         PANGO_UNDERLINE_SINGLE,
                         NULL);

  tag = gtk_text_tag_table_lookup(tag_table, "underline-cancel");
  if (tag)
    g_object_set(tag, "underline-set", singly_underlined, NULL);
  else
    gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(buffer),
                         "underline-cancel",
                         "underline-set",
                         false,
                         NULL);


  return;
}

void GTKTwoVT::setTitleBar(char * text) {
  mainWindow->setTitleBar(text);
}

void GTKTwoVT::setIcon(char * text) {
  mainWindow->setIcon(text);
}

struct colour_table * GTKTwoVT::getColourTable() {
  return systemColour->getColourTable();
}

Generated by  Doxygen 1.6.0   Back to index