medit/moo/mooterm/mooterm-draw.c

985 lines
30 KiB
C
Raw Normal View History

2005-06-22 11:20:32 -07:00
/*
* mooterm/mootermdraw.c
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#define MOOTERM_COMPILATION
#include "mooterm/mooterm-private.h"
#include "mooterm/mooterm-selection.h"
#include "mooterm/mootermbuffer-private.h"
#include <string.h>
2005-06-22 11:20:32 -07:00
#define CHARS \
"`1234567890-=~!@#$%^&*()_+qwertyuiop[]\\QWERTYUIOP"\
"{}|asdfghjkl;'ASDFGHJKL:\"zxcvbnm,./ZXCVBNM<>?"
#define HOW_MANY(x, y) (((x) + (y) - 1) / (y))
static gboolean process_updates (MooTerm *term)
{
gdk_window_process_updates (GTK_WIDGET(term)->window, FALSE);
term->priv->pending_expose = 0;
return FALSE;
}
static void add_update_timeout (MooTerm *term)
{
if (!term->priv->pending_expose)
{
term->priv->pending_expose =
g_timeout_add_full (EXPOSE_PRIORITY,
EXPOSE_TIMEOUT,
(GSourceFunc) process_updates,
term,
NULL);
}
}
static void remove_update_timeout (MooTerm *term)
{
if (term->priv->pending_expose)
g_source_remove (term->priv->pending_expose);
term->priv->pending_expose = 0;
}
2005-06-22 11:20:32 -07:00
void moo_term_init_font_stuff (MooTerm *term)
{
PangoContext *ctx;
PangoFontDescription *font;
if (term->priv->font_info)
moo_term_font_info_free (term->priv->font_info);
2005-06-22 11:20:32 -07:00
ctx = gtk_widget_create_pango_context (GTK_WIDGET (term));
g_return_if_fail (ctx != NULL);
font = pango_font_description_from_string (DEFAULT_MONOSPACE_FONT);
if (!font)
font = pango_font_description_from_string (DEFAULT_MONOSPACE_FONT2);
if (font)
{
pango_context_set_font_description (ctx, font);
pango_font_description_free (font);
}
term->priv->font_info = moo_term_font_info_new (ctx);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
term->priv->layout = pango_layout_new (ctx);
2005-06-22 11:20:32 -07:00
g_object_unref (ctx);
2005-07-16 19:36:26 -07:00
gtk_widget_set_size_request (GTK_WIDGET (term),
term->priv->font_info->width * MIN_TERMINAL_WIDTH,
term->priv->font_info->height * MIN_TERMINAL_HEIGHT);
2005-06-22 11:20:32 -07:00
}
void moo_term_font_info_calculate (TermFontInfo *info)
2005-06-22 11:20:32 -07:00
{
PangoRectangle logical;
PangoLayout *layout;
PangoLayoutIter *iter;
g_assert (info->ctx != NULL);
layout = pango_layout_new (info->ctx);
pango_layout_set_text (layout, CHARS, strlen(CHARS));
pango_layout_get_extents (layout, NULL, &logical);
info->width = HOW_MANY (logical.width, strlen (CHARS));
info->width = PANGO_PIXELS (info->width);
iter = pango_layout_get_iter (layout);
info->height = PANGO_PIXELS (logical.height);
info->ascent = PANGO_PIXELS (pango_layout_iter_get_baseline (iter));
pango_layout_iter_free (iter);
g_object_unref (layout);
}
void moo_term_font_info_set_font (TermFontInfo *info,
PangoFontDescription *font_desc)
2005-06-22 11:20:32 -07:00
{
g_return_if_fail (font_desc != NULL);
pango_context_set_font_description (info->ctx, font_desc);
moo_term_font_info_calculate (info);
2005-06-22 11:20:32 -07:00
}
TermFontInfo *moo_term_font_info_new (PangoContext *ctx)
2005-06-22 11:20:32 -07:00
{
TermFontInfo *info = g_new0 (TermFontInfo, 1);
info->ctx = ctx;
g_object_ref (ctx);
moo_term_font_info_calculate (info);
2005-06-22 11:20:32 -07:00
return info;
}
void moo_term_font_info_free (TermFontInfo *info)
2005-06-22 11:20:32 -07:00
{
if (info)
{
g_object_unref (info->ctx);
g_free (info);
}
}
2005-07-19 07:01:41 -07:00
void moo_term_invalidate_all (MooTerm *term)
{
GdkRectangle rec = {0, 0, term->priv->width, term->priv->height};
moo_term_invalidate_rect (term, &rec);
}
2005-07-06 16:41:14 -07:00
void moo_term_invalidate_rect (MooTerm *term,
GdkRectangle *rect)
2005-06-22 11:20:32 -07:00
{
2005-07-20 08:52:15 -07:00
if (GTK_WIDGET_REALIZED (term))
{
GdkRectangle r = {
rect->x * term->priv->font_info->width,
rect->y * term->priv->font_info->height,
rect->width * term->priv->font_info->width,
rect->height * term->priv->font_info->height
};
gdk_window_invalidate_rect (GTK_WIDGET(term)->window,
&r, FALSE);
moo_term_invalidate_content_rect (term, rect);
add_update_timeout (term);
}
2005-07-06 16:41:14 -07:00
}
void moo_term_setup_palette (MooTerm *term)
{
2005-07-07 00:01:19 -07:00
int i;
2005-07-06 16:41:14 -07:00
GtkWidget *widget = GTK_WIDGET (term);
GdkColormap *colormap;
GdkGCValues vals;
2005-07-07 00:01:19 -07:00
GdkColor colors[MOO_TERM_COLOR_MAX];
2005-06-22 11:20:32 -07:00
2005-07-20 10:00:21 -07:00
g_return_if_fail (GTK_WIDGET_REALIZED (widget));
2005-06-22 11:20:32 -07:00
term->priv->fg[0] =
gdk_gc_new_with_values (widget->window, &vals, 0);
term->priv->fg[1] =
2005-07-20 10:00:21 -07:00
gdk_gc_new_with_values (widget->window, &vals, 0);
term->priv->bg =
gdk_gc_new_with_values (widget->window, &vals, 0);
2005-07-06 16:41:14 -07:00
gdk_gc_set_foreground (term->priv->fg[0], &(widget->style->black));
gdk_gc_set_foreground (term->priv->fg[0], &(widget->style->black));
2005-07-20 10:00:21 -07:00
gdk_gc_set_foreground (term->priv->bg, &(widget->style->white));
2005-07-06 16:41:14 -07:00
gdk_window_set_background (widget->window, &(widget->style->white));
colormap = gdk_colormap_get_system ();
g_return_if_fail (colormap != NULL);
2005-07-07 00:01:19 -07:00
gdk_color_parse ("black", &colors[MOO_TERM_BLACK]);
gdk_color_parse ("red", &colors[MOO_TERM_RED]);
gdk_color_parse ("green", &colors[MOO_TERM_GREEN]);
gdk_color_parse ("yellow", &colors[MOO_TERM_YELLOW]);
gdk_color_parse ("blue", &colors[MOO_TERM_BLUE]);
gdk_color_parse ("magenta", &colors[MOO_TERM_MAGENTA]);
gdk_color_parse ("cyan", &colors[MOO_TERM_CYAN]);
gdk_color_parse ("white", &colors[MOO_TERM_WHITE]);
2005-07-06 16:41:14 -07:00
for (i = 0; i < MOO_TERM_COLOR_MAX; ++i)
2005-07-07 00:01:19 -07:00
gdk_colormap_alloc_color (colormap, &colors[i], TRUE, TRUE);
2005-07-06 16:41:14 -07:00
for (i = 0; i < MOO_TERM_COLOR_MAX; ++i)
2005-06-22 11:20:32 -07:00
{
2005-07-07 00:01:19 -07:00
vals.foreground = colors[i];
2005-07-06 16:41:14 -07:00
2005-07-20 10:00:21 -07:00
term->priv->color[NORMAL][i] =
2005-07-06 16:41:14 -07:00
gdk_gc_new_with_values (widget->window,
&vals,
2005-07-20 10:00:21 -07:00
GDK_GC_FOREGROUND);
term->priv->color[BOLD][i] =
2005-07-06 16:41:14 -07:00
gdk_gc_new_with_values (widget->window,
&vals,
2005-07-20 10:00:21 -07:00
GDK_GC_FOREGROUND);
2005-07-06 16:41:14 -07:00
}
}
2005-06-22 11:20:32 -07:00
2005-07-15 02:46:44 -07:00
static void invalidate_screen_cell (MooTerm *term,
guint row,
guint column)
2005-07-06 16:41:14 -07:00
{
2005-07-15 02:46:44 -07:00
int scrollback, top_line;
GdkRectangle small_rect = {0, 0, 1, 1};
2005-06-22 11:20:32 -07:00
2005-07-15 02:46:44 -07:00
scrollback = buf_scrollback (term->priv->buffer);
top_line = term_top_line (term);
2005-06-22 11:20:32 -07:00
2005-07-15 02:46:44 -07:00
small_rect.x = column;
small_rect.y = row + scrollback - top_line;
2005-07-07 00:01:19 -07:00
2005-07-19 07:01:41 -07:00
moo_term_invalidate_rect (term, &small_rect);
2005-07-15 02:46:44 -07:00
}
2005-06-22 11:20:32 -07:00
2005-07-07 00:01:19 -07:00
2005-07-15 02:46:44 -07:00
void moo_term_cursor_moved (MooTerm *term,
MooTermBuffer *buf)
{
int new_row, new_col;
2005-06-22 11:20:32 -07:00
2005-07-20 08:52:15 -07:00
if (buf != term->priv->buffer)
2005-07-15 02:46:44 -07:00
return;
2005-07-15 02:46:44 -07:00
new_row = buf_cursor_row (buf);
new_col = buf_cursor_col (buf);
if (term->priv->cursor_visible && term->priv->blink_cursor_visible)
2005-07-15 02:46:44 -07:00
{
invalidate_screen_cell (term,
term->priv->cursor_row,
term->priv->cursor_col);
2005-07-20 08:52:15 -07:00
invalidate_screen_cell (term, new_row, new_col);
2005-07-15 02:46:44 -07:00
}
2005-07-20 08:52:15 -07:00
term->priv->cursor_col = new_col;
term->priv->cursor_row = new_row;
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
void moo_term_init_back_pixmap (MooTerm *term)
2005-06-22 11:20:32 -07:00
{
2005-07-06 16:41:14 -07:00
if (term->priv->back_pixmap)
2005-06-22 11:20:32 -07:00
return;
2005-07-06 16:41:14 -07:00
term->priv->back_pixmap =
gdk_pixmap_new (GTK_WIDGET(term)->window,
term->priv->font_info->width * term->priv->width,
term->priv->font_info->height * term->priv->height,
2005-07-06 16:41:14 -07:00
-1);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
term->priv->clip = gdk_gc_new (term->priv->back_pixmap);
gdk_gc_set_clip_origin (term->priv->clip, 0, 0);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
moo_term_invalidate_content_all (term);
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
void moo_term_resize_back_pixmap (MooTerm *term)
2005-06-22 11:20:32 -07:00
{
2005-07-06 16:41:14 -07:00
if (term->priv->font_changed)
{
GdkPixmap *pix;
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
term->priv->font_changed = FALSE;
pix = gdk_pixmap_new (term->priv->back_pixmap,
term->priv->font_info->width * term->priv->width,
term->priv->font_info->height * term->priv->height,
2005-07-06 16:41:14 -07:00
-1);
g_object_unref (term->priv->back_pixmap);
term->priv->back_pixmap = pix;
moo_term_invalidate_content_all (term);
}
else
2005-06-22 11:20:32 -07:00
{
2005-07-06 16:41:14 -07:00
GdkPixmap *pix;
GdkRegion *region;
guint char_width = term->priv->font_info->width;
guint char_height = term->priv->font_info->height;
int old_width, old_height;
int width = char_width * term->priv->width;
int height = char_height * term->priv->height;
2005-07-06 16:41:14 -07:00
GdkRectangle rec = {0, 0, width, height};
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
pix = gdk_pixmap_new (term->priv->back_pixmap,
width, height, -1);
2005-06-22 11:20:32 -07:00
2005-07-07 00:01:19 -07:00
gdk_drawable_get_size (term->priv->back_pixmap,
&old_width, &old_height);
2005-07-06 16:41:14 -07:00
gdk_gc_set_clip_rectangle (term->priv->clip, &rec);
gdk_draw_drawable (pix, term->priv->clip,
term->priv->back_pixmap,
0, 0, 0, 0,
MIN (width, old_width),
MIN (height, old_height));
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
if (width > old_width)
{
rec.x = old_width / char_width;
rec.width = (width - old_width) / char_width;
rec.y = 0;
rec.height = height / char_height;
moo_term_invalidate_content_rect (term, &rec);
}
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
if (height > old_height)
{
rec.x = 0;
rec.width = width / char_width;
rec.y = old_height / char_height;
rec.height = (height - old_height) / char_height;
moo_term_invalidate_content_rect (term, &rec);
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
rec.x = rec.y = 0;
rec.width = width / char_width;
rec.height = height / char_height;
if (term->priv->changed_content)
2005-06-22 11:20:32 -07:00
{
2005-07-06 16:41:14 -07:00
region = gdk_region_rectangle (&rec);
gdk_region_intersect (term->priv->changed_content, region);
gdk_region_destroy (region);
}
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
g_object_unref (term->priv->back_pixmap);
term->priv->back_pixmap = pix;
}
}
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
/* absolute row */
static void term_draw_range (MooTerm *term,
guint row,
guint start,
guint len);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
void moo_term_update_back_pixmap (MooTerm *term)
{
GdkRectangle *rects = NULL;
int n_rects;
int i, j;
int top_line = term_top_line (term);
int width = term->priv->width;
int height = term->priv->height;
2005-07-06 16:41:14 -07:00
GdkRectangle clip = {0, 0, width, height};
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
if (!term->priv->changed_content)
return;
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
gdk_region_get_rectangles (term->priv->changed_content,
&rects, &n_rects);
for (i = 0; i < n_rects; ++i)
{
if (gdk_rectangle_intersect (&rects[i], &clip, &rects[i]))
{
for (j = 0; j < rects[i].height; ++j)
term_draw_range (term, top_line + rects[i].y + j,
rects[i].x, rects[i].width);
}
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
g_free (rects);
gdk_region_destroy (term->priv->changed_content);
term->priv->changed_content = NULL;
}
void moo_term_invalidate_content_all (MooTerm *term)
{
GdkRectangle rect = {0, 0, term->priv->width, term->priv->height};
2005-07-06 16:41:14 -07:00
moo_term_invalidate_content_rect (term, &rect);
}
void moo_term_invalidate_content_rect(MooTerm *term,
GdkRectangle *rect)
{
if (term->priv->changed_content)
gdk_region_union_with_rect (term->priv->changed_content, rect);
else
term->priv->changed_content = gdk_region_rectangle (rect);
2005-06-22 11:20:32 -07:00
}
gboolean moo_term_expose_event (GtkWidget *widget,
GdkEventExpose *event)
{
GdkRectangle text_rec = {0, 0, 0, 0};
GdkRegion *text_reg;
MooTerm *term = MOO_TERM (widget);
guint char_width = term->priv->font_info->width;
guint char_height = term->priv->font_info->height;
g_assert (term_top_line (term) <= buf_scrollback (term->priv->buffer));
2005-06-22 11:20:32 -07:00
remove_update_timeout (term);
text_rec.width = term->priv->width * char_width;
text_rec.height = term->priv->height * char_height;
2005-06-22 11:20:32 -07:00
if (event->area.x + event->area.width >= text_rec.width)
{
gdk_draw_rectangle (widget->window,
2005-07-20 10:00:21 -07:00
term->priv->bg, TRUE,
2005-06-22 11:20:32 -07:00
text_rec.width, 0,
char_width,
widget->allocation.height);
}
if (event->area.y + event->area.height >= text_rec.height)
{
gdk_draw_rectangle (widget->window,
2005-07-20 10:00:21 -07:00
term->priv->bg, TRUE,
2005-06-22 11:20:32 -07:00
0, text_rec.height,
widget->allocation.width,
char_height);
}
text_reg = gdk_region_rectangle (&text_rec);
gdk_region_intersect (event->region, text_reg);
gdk_region_destroy (text_reg);
if (!gdk_region_empty (event->region))
{
2005-07-06 16:41:14 -07:00
moo_term_update_back_pixmap (term);
gdk_gc_set_clip_region (term->priv->clip,
event->region);
gdk_draw_drawable (event->window,
term->priv->clip,
term->priv->back_pixmap,
0, 0, 0, 0,
text_rec.width,
text_rec.height);
}
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
return TRUE;
}
/****************************************************************************/
/* Drawing
*/
static void term_draw_range_simple (MooTerm *term,
guint abs_row,
guint start,
guint len,
int selected);
static void term_draw_cells (MooTerm *term,
guint abs_row,
guint start,
guint len,
MooTermTextAttr *attr,
int selected);
static void term_draw_cursor (MooTerm *term);
2005-07-06 16:41:14 -07:00
static void term_draw_range (MooTerm *term,
guint abs_row,
guint start,
guint len)
{
int selected;
guint first = start;
guint last = start + len;
g_return_if_fail (len != 0);
g_assert (start + len <= term->priv->width);
2005-07-06 16:41:14 -07:00
g_assert (abs_row < buf_total_height (term->priv->buffer));
if (term->priv->cursor_visible && term->priv->blink_cursor_visible &&
2005-07-15 02:46:44 -07:00
term->priv->cursor_row + buf_scrollback (term->priv->buffer) == abs_row)
2005-07-06 16:41:14 -07:00
{
guint cursor = buf_cursor_col (term->priv->buffer);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
if (cursor >= start && cursor < start + len)
2005-06-22 11:20:32 -07:00
{
2005-07-06 16:41:14 -07:00
if (cursor > start)
term_draw_range (term, abs_row,
start, cursor - start);
2005-06-22 11:20:32 -07:00
term_draw_cursor (term);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
if (cursor < start + len - 1)
term_draw_range (term, abs_row,
cursor + 1, start + len - 1 - cursor);
return;
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
}
2005-06-22 11:20:32 -07:00
selected = moo_term_row_selected (term, abs_row);
2005-07-06 16:41:14 -07:00
switch (selected)
{
case FULL_SELECTED:
case NOT_SELECTED:
2005-07-19 07:01:41 -07:00
term_draw_range_simple (term, abs_row, first, len, selected);
2005-07-06 16:41:14 -07:00
break;
case PART_SELECTED:
2005-06-22 11:20:32 -07:00
{
guint l_row, l_col, r_row, r_col;
moo_term_get_selection_bounds (term, &l_row, &l_col,
&r_row, &r_col);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
if (l_row == r_row)
{
g_assert (abs_row == l_row);
if (r_col <= first || last <= l_col)
{
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, len, FALSE);
2005-07-06 16:41:14 -07:00
}
else if (l_col <= first && last <= r_col)
{
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, len, TRUE);
2005-07-06 16:41:14 -07:00
}
else if (first < l_col)
{
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, l_col - first, FALSE);
2005-07-06 16:41:14 -07:00
term_draw_range_simple (term, abs_row, l_col,
2005-07-19 07:01:41 -07:00
MIN (last, r_col) - l_col, TRUE);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
if (r_col < last)
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
r_col, last - r_col, FALSE);
2005-07-06 16:41:14 -07:00
}
else
{
term_draw_range_simple (term, abs_row, first,
2005-07-19 07:01:41 -07:00
MIN (last, r_col) - first, TRUE);
2005-07-06 16:41:14 -07:00
if (r_col < last)
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
r_col, last - r_col, FALSE);
2005-07-06 16:41:14 -07:00
}
}
else if (l_row == abs_row)
2005-06-22 11:20:32 -07:00
{
2005-07-06 16:41:14 -07:00
if (last <= l_col)
{
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, len, FALSE);
2005-07-06 16:41:14 -07:00
}
else if (l_col <= first)
{
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, len, TRUE);
2005-07-06 16:41:14 -07:00
}
else
{
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, l_col - first, FALSE);
2005-07-06 16:41:14 -07:00
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
l_col, last - l_col, TRUE);
2005-07-06 16:41:14 -07:00
}
}
else
{
g_assert (abs_row == r_row);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
if (last <= r_col)
{
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, len, TRUE);
2005-07-06 16:41:14 -07:00
}
else if (r_col <= first)
{
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, len, FALSE);
2005-07-06 16:41:14 -07:00
}
else {
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
first, r_col - first, TRUE);
2005-07-06 16:41:14 -07:00
term_draw_range_simple (term, abs_row,
2005-07-19 07:01:41 -07:00
r_col, last - r_col, FALSE);
2005-07-06 16:41:14 -07:00
}
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
break;
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
default:
g_assert_not_reached ();
2005-06-22 11:20:32 -07:00
}
}
2005-07-06 16:41:14 -07:00
static void term_draw_range_simple (MooTerm *term,
guint abs_row,
guint start,
guint len,
gboolean selected)
2005-06-22 11:20:32 -07:00
{
2005-07-06 16:41:14 -07:00
MooTermLine *line = buf_line (term->priv->buffer, abs_row);
guint char_width = term->priv->font_info->width;
guint char_height = term->priv->font_info->height;
int y = (abs_row - term_top_line (term)) * char_height;
2005-07-20 10:00:21 -07:00
GdkGC *bg;
guint invert;
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
g_assert (selected == 0 || selected == 1);
2005-06-22 11:20:32 -07:00
2005-07-20 10:00:21 -07:00
invert = (selected ? 1 : 0) + (term->priv->colors_inverted ? 1 : 0);
invert %= 2;
if (!invert)
bg = term->priv->bg;
2005-07-16 11:31:03 -07:00
else
bg = term->priv->fg[NORMAL];
2005-07-16 11:31:03 -07:00
2005-07-06 16:41:14 -07:00
if (start >= line->len)
{
gdk_draw_rectangle (term->priv->back_pixmap,
2005-07-20 10:00:21 -07:00
bg,
2005-07-06 16:41:14 -07:00
TRUE,
start * char_width,
y,
2005-07-07 00:01:19 -07:00
len * char_width,
char_height);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
return;
}
else if (start + len > line->len)
{
gdk_draw_rectangle (term->priv->back_pixmap,
2005-07-20 10:00:21 -07:00
bg,
2005-07-06 16:41:14 -07:00
TRUE,
line->len * char_width,
y,
2005-07-07 00:01:19 -07:00
(start + len - line->len) * char_width,
char_height);
2005-07-06 16:41:14 -07:00
len = line->len - start;
}
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
g_assert (start + len <= line->len);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
while (len)
2005-06-22 11:20:32 -07:00
{
2005-07-06 16:41:14 -07:00
guint i;
MooTermTextAttr *attr = &line->data[start].attr;
2005-07-19 07:01:41 -07:00
for (i = 1; i < len && !ATTR_CMP (attr, &line->data[start + i].attr); ++i) ;
2005-07-06 16:41:14 -07:00
term_draw_cells (term, abs_row, start, i, attr, selected);
len -= i;
start += i;
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
}
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
static void term_draw_cells (MooTerm *term,
guint abs_row,
guint start,
guint len,
MooTermTextAttr *attr,
gboolean selected)
{
static char buf[8 * MAX_TERMINAL_WIDTH];
guint buf_len;
GdkGC *fg = NULL;
GdkGC *bg = NULL;
2005-07-20 10:00:21 -07:00
guint bold;
guint invert;
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
MooTermLine *line = buf_line (term->priv->buffer, abs_row);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
g_assert (len != 0);
g_assert (start + len <= line->len);
2005-06-22 11:20:32 -07:00
2005-07-19 07:01:41 -07:00
buf_len = moo_term_line_get_chars (line, buf, start, len);
2005-07-06 16:41:14 -07:00
g_return_if_fail (buf_len != 0);
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
pango_layout_set_text (term->priv->layout, buf, buf_len);
2005-06-22 11:20:32 -07:00
2005-07-20 10:00:21 -07:00
bold = attr->mask & MOO_TERM_TEXT_BOLD ? BOLD : NORMAL;
2005-07-06 16:41:14 -07:00
if (attr->mask & MOO_TERM_TEXT_FOREGROUND)
2005-06-22 11:20:32 -07:00
{
2005-07-20 10:00:21 -07:00
g_return_if_fail (attr->foreground < MOO_TERM_COLOR_MAX);
fg = term->priv->color[bold][attr->foreground];
}
else
{
fg = term->priv->fg[bold];
2005-06-22 11:20:32 -07:00
}
2005-07-06 16:41:14 -07:00
if (attr->mask & MOO_TERM_TEXT_BACKGROUND)
2005-06-22 11:20:32 -07:00
{
2005-07-20 10:00:21 -07:00
g_return_if_fail (attr->foreground < MOO_TERM_COLOR_MAX);
bg = term->priv->color[bold][attr->background];
}
else
{
bg = term->priv->bg;
2005-07-06 16:41:14 -07:00
}
2005-06-22 11:20:32 -07:00
2005-07-20 10:00:21 -07:00
invert = (selected ? 1 : 0) + (term->priv->colors_inverted ? 1 : 0) +
(attr->mask & MOO_TERM_TEXT_REVERSE ? 1 : 0);
invert %= 2;
2005-06-22 11:20:32 -07:00
2005-07-20 10:00:21 -07:00
if (invert)
2005-07-16 11:31:03 -07:00
{
GdkGC *tmp = fg;
fg = bg;
bg = tmp;
}
2005-07-06 16:41:14 -07:00
gdk_draw_rectangle (term->priv->back_pixmap,
bg,
TRUE,
start * term->priv->font_info->width,
(abs_row - term_top_line (term)) * term->priv->font_info->height,
2005-07-07 00:01:19 -07:00
len * term->priv->font_info->width,
term->priv->font_info->height);
2005-07-06 16:41:14 -07:00
gdk_draw_layout (term->priv->back_pixmap,
fg,
start * term->priv->font_info->width,
(abs_row - term_top_line (term)) * term->priv->font_info->height,
term->priv->layout);
2005-07-20 10:00:21 -07:00
if ((attr->mask & MOO_TERM_TEXT_BOLD) && term->priv->settings.allow_bold)
gdk_draw_layout (term->priv->back_pixmap,
fg,
start * term->priv->font_info->width + 1,
(abs_row - term_top_line (term)) * term->priv->font_info->height,
term->priv->layout);
if (attr->mask & MOO_TERM_TEXT_UNDERLINE)
gdk_draw_line (term->priv->back_pixmap,
fg,
start * term->priv->font_info->width,
(abs_row - term_top_line (term)) * term->priv->font_info->height + term->priv->font_info->ascent + 1,
(start + len) * term->priv->font_info->width + 1,
(abs_row - term_top_line (term)) * term->priv->font_info->height + term->priv->font_info->ascent + 1);
2005-07-06 16:41:14 -07:00
}
2005-06-22 11:20:32 -07:00
2005-07-06 16:41:14 -07:00
static void term_draw_cursor (MooTerm *term)
2005-07-06 16:41:14 -07:00
{
2005-07-20 10:00:21 -07:00
guint scrollback = buf_scrollback (term->priv->buffer);
guint abs_row = term->priv->cursor_row + scrollback;
guint column = term->priv->cursor_col;
2005-07-07 00:01:19 -07:00
MooTermLine *line = buf_line (term->priv->buffer, abs_row);
2005-07-20 10:00:21 -07:00
if (line->len > column)
2005-07-07 00:01:19 -07:00
{
2005-07-20 10:00:21 -07:00
return term_draw_cells (term, abs_row, column, 1,
&line->data[column].attr,
!moo_term_cell_selected (term, abs_row, column));
2005-07-07 00:01:19 -07:00
}
else
{
2005-07-20 10:00:21 -07:00
GdkGC *color;
guint invert;
2005-07-07 00:01:19 -07:00
2005-07-20 10:00:21 -07:00
invert = 1 + (moo_term_cell_selected (term, abs_row, column) ? 1 : 0) +
(term->priv->colors_inverted ? 1 : 0);
invert %= 2;
2005-07-16 11:31:03 -07:00
2005-07-20 10:00:21 -07:00
if (invert)
color = term->priv->fg[NORMAL];
2005-07-20 10:00:21 -07:00
else
color = term->priv->bg;
2005-07-07 00:01:19 -07:00
2005-07-20 10:00:21 -07:00
gdk_draw_rectangle (term->priv->back_pixmap,
color,
TRUE,
column * term->priv->font_info->width,
(abs_row - term_top_line (term)) * term->priv->font_info->height,
term->priv->font_info->width,
term->priv->font_info->height);
2005-07-07 00:01:19 -07:00
}
2005-06-22 11:20:32 -07:00
}
void moo_term_buf_content_changed(MooTerm *term,
MooTermBuffer *buf)
2005-06-22 11:20:32 -07:00
{
GdkRectangle *rect = NULL;
GdkRegion *dirty, *changed;
int n_rect, i;
guint top_line, scrollback;
int height;
changed = buf_get_changed (buf);
if (buf != term->priv->buffer || !changed || gdk_region_empty (changed))
return;
2005-06-22 11:20:32 -07:00
/* TODO TODO TODO*/
buf->priv->changed = NULL;
buf->priv->changed_all = FALSE;
top_line = term_top_line (term);
scrollback = buf_scrollback (buf);
height = term->priv->height;
g_assert (top_line <= scrollback);
if (top_line != scrollback)
2005-06-22 11:20:32 -07:00
{
GdkRectangle clip = {0, 0, term->priv->width, height};
GdkRegion *tmp;
2005-06-22 11:20:32 -07:00
gdk_region_offset (changed, 0, scrollback - top_line);
2005-06-22 11:20:32 -07:00
tmp = gdk_region_rectangle (&clip);
gdk_region_intersect (changed, tmp);
gdk_region_destroy (tmp);
}
2005-07-06 16:41:14 -07:00
if (gdk_region_empty (changed))
{
gdk_region_destroy (changed);
return;
}
2005-06-22 11:20:32 -07:00
gdk_region_get_rectangles (changed, &rect, &n_rect);
g_return_if_fail (rect != NULL);
2005-06-22 11:20:32 -07:00
dirty = gdk_region_new ();
2005-06-22 11:20:32 -07:00
for (i = 0; i < n_rect; ++i)
{
moo_term_invalidate_content_rect (term, &rect[i]);
2005-06-22 11:20:32 -07:00
rect[i].x *= term->priv->font_info->width;
rect[i].y *= term->priv->font_info->height;
rect[i].width *= term->priv->font_info->width;
rect[i].height *= term->priv->font_info->height;
2005-06-22 11:20:32 -07:00
gdk_region_union_with_rect (dirty, &rect[i]);
}
2005-06-22 11:20:32 -07:00
gdk_window_invalidate_region (GTK_WIDGET(term)->window,
dirty, FALSE);
add_update_timeout (term);
2005-06-22 11:20:32 -07:00
g_free (rect);
gdk_region_destroy (changed);
gdk_region_destroy (dirty);
}
2005-07-06 16:41:14 -07:00
2005-06-22 11:20:32 -07:00
void moo_term_force_update (MooTerm *term)
{
GdkRegion *region;
GdkWindow *window = GTK_WIDGET (term)->window;
region = gdk_window_get_update_area (window);
2005-07-06 16:41:14 -07:00
if (region)
{
GdkEvent *event = gdk_event_new (GDK_EXPOSE);
event->expose.window = g_object_ref (window);
event->expose.send_event = TRUE;
gdk_region_get_clipbox (region, &event->expose.area);
event->expose.region = region;
gtk_main_do_event (event);
gdk_event_free (event);
2005-06-22 11:20:32 -07:00
}
}
void moo_term_invert_colors (MooTerm *term,
gboolean invert)
{
2005-07-16 11:31:03 -07:00
if (invert != term->priv->colors_inverted)
{
moo_term_invalidate_all (term);
term->priv->colors_inverted = invert;
}
}
void moo_term_set_cursor_visible (MooTerm *term,
gboolean visible)
{
term->priv->cursor_visible = visible;
2005-07-20 08:52:15 -07:00
invalidate_screen_cell (term,
term->priv->cursor_row,
term->priv->cursor_col);
}
2005-07-15 02:46:44 -07:00
2005-07-20 08:52:15 -07:00
static gboolean blink (MooTerm *term)
{
term->priv->blink_cursor_visible =
!term->priv->blink_cursor_visible;
2005-07-20 08:52:15 -07:00
invalidate_screen_cell (term,
term->priv->cursor_row,
term->priv->cursor_col);
return TRUE;
}
static void start_cursor_blinking (MooTerm *term)
2005-07-20 08:52:15 -07:00
{
if (!term->priv->cursor_blink_timeout_id && term->priv->cursor_blinks)
term->priv->cursor_blink_timeout_id =
g_timeout_add (term->priv->cursor_blink_time,
2005-07-20 08:52:15 -07:00
(GSourceFunc) blink,
term);
}
static void stop_cursor_blinking (MooTerm *term)
2005-07-20 08:52:15 -07:00
{
if (term->priv->cursor_blink_timeout_id)
2005-07-20 10:00:21 -07:00
{
g_source_remove (term->priv->cursor_blink_timeout_id);
term->priv->cursor_blink_timeout_id = 0;
term->priv->blink_cursor_visible = TRUE;
2005-07-20 10:00:21 -07:00
invalidate_screen_cell (term,
term->priv->cursor_row,
term->priv->cursor_col);
}
}
void moo_term_pause_cursor_blinking (MooTerm *term)
{
if (term->priv->cursor_blinks)
{
stop_cursor_blinking (term);
start_cursor_blinking (term);
}
}
void moo_term_set_cursor_blinks (MooTerm *term,
gboolean blinks)
{
term->priv->cursor_blinks = blinks;
if (blinks)
start_cursor_blinking (term);
else
stop_cursor_blinking (term);
g_object_notify (G_OBJECT (term), "cursor-blinks");
}