[Commit] gwaterfall/src Makefile.am,NONE,1.1 main.c,NONE,1.1 waterfall.c,NONE,1.1 waterfall.h,NONE,1.1
Noah Levitt
commit@keithp.com
Sun, 27 Apr 2003 19:45:48 -0700
Committed by: nlevitt
Update of /local/src/CVS/gwaterfall/src
In directory home.keithp.com:/tmp/cvs-serv11286/src
Added Files:
Makefile.am main.c waterfall.c waterfall.h
Log Message:
Initial checkin.
--- NEW FILE: Makefile.am ---
##
## $Id: Makefile.am,v 1.1 2003/04/28 02:45:45 nlevitt Exp $
##
## Copyright (c) 2003 Noah Levitt
##
## This program is free software; the author gives unlimited permission to
## copy and/or distribute it, with or without modifications, as long as
## this notice is preserved.
##
## This program is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
##
AM_CFLAGS = $(WATERFALL_CFLAGS)
bin_PROGRAMS = waterfall
waterfall_SOURCES = main.c waterfall.c waterfall.h
waterfall_LDADD = @WATERFALL_LIBS@
--- NEW FILE: main.c ---
/*
* $Id: main.c,v 1.1 2003/04/28 02:45:45 nlevitt Exp $
*
* Copyright (c) 2003 Noah Levitt
*
* This program is free software; the author gives unlimited permission to
* copy and/or distribute it, with or without modifications, as long as
* this notice is preserved.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gtk/gtk.h>
#include <fontconfig/fontconfig.h>
#include <waterfall.h>
static GtkWidget *page_label = NULL;
static GtkWidget *style_combo = NULL;
static void
set_style_choices (Waterfall *waterfall)
{
FcObjectSet *set;
FcPattern *pattern;
FcFontSet *list;
GList *styles = NULL;
FcChar8 *style;
gint i;
if (style_combo == NULL)
return;
set = FcObjectSetBuild (FC_STYLE, 0);
pattern = FcPatternBuild (0, FC_FAMILY, FcTypeString,
waterfall_get_font_family (waterfall), 0);
g_assert (pattern != NULL);
list = FcFontList (0, pattern, set);
FcPatternDestroy (pattern);
g_assert (list->nfont > 0);
for (i = 0; i < list->nfont; i++)
{
FcPatternGetString (list->fonts[i], FC_STYLE, 0, &style);
styles = g_list_append (styles, style);
}
gtk_combo_set_popdown_strings (GTK_COMBO (style_combo), styles);
FcFontSetDestroy (list);
}
static void
family_changed (GtkEntry *entry,
Waterfall *waterfall)
{
const gchar *new_family = gtk_entry_get_text (entry);
/* ignore empty string (it sends these a lot) */
if (new_family[0] == '\0')
return;
waterfall_set_font_family (waterfall, new_family);
set_style_choices (waterfall);
}
static void
style_changed (GtkEntry *entry,
Waterfall *waterfall)
{
const gchar *new_style = gtk_entry_get_text (entry);
/* ignore empty string (it sends these a lot) */
if (new_style[0] == '\0')
return;
waterfall_set_font_style (waterfall, new_style);
}
static GtkWidget *
construct_font_family_chooser (Waterfall *waterfall)
{
GtkWidget *combo;
FcFontSet *list;
FcObjectSet *set = FcObjectSetBuild (FC_FAMILY, 0);
FcPattern *pattern = FcPatternCreate ();
GList *family_names = NULL;
FcChar8 *family_name;
int i;
combo = gtk_combo_new ();
gtk_widget_show (combo);
gtk_editable_set_editable (GTK_EDITABLE (GTK_COMBO (combo)->entry), FALSE);
g_signal_connect (GTK_COMBO (combo)->entry, "changed",
G_CALLBACK (family_changed), waterfall);
list = FcFontList (0, pattern, set);
FcObjectSetDestroy (set);
FcPatternDestroy (pattern);
g_assert (list->nfont > 0);
for (i = 0; i < list->nfont; i++)
{
FcPatternGetString (list->fonts[i], FC_FAMILY, 0, &family_name);
family_names = g_list_append (family_names, family_name);
}
family_names = g_list_sort (family_names, (GCompareFunc) FcStrCmpIgnoreCase);
gtk_combo_set_popdown_strings (GTK_COMBO (combo), family_names);
g_list_free (family_names);
FcFontSetDestroy (list);
return combo;
}
static GtkWidget *
construct_font_style_chooser (Waterfall *waterfall)
{
style_combo = gtk_combo_new ();
gtk_widget_show (style_combo);
gtk_editable_set_editable (GTK_EDITABLE (GTK_COMBO (style_combo)->entry),
FALSE);
g_signal_connect (GTK_COMBO (style_combo)->entry, "changed",
G_CALLBACK (style_changed), waterfall);
set_style_choices (waterfall);
return style_combo;
}
static void
hint_toggled (GtkToggleButton *toggle_button,
Waterfall *waterfall)
{
waterfall_set_hint (waterfall,
gtk_toggle_button_get_active (toggle_button));
}
static void
antialias_toggled (GtkToggleButton *toggle_button,
Waterfall *waterfall)
{
waterfall_set_antialias (waterfall,
gtk_toggle_button_get_active (toggle_button));
}
static void
min_size_changed (GtkAdjustment *adjustment,
Waterfall *waterfall)
{
waterfall_set_min_size (waterfall, gtk_adjustment_get_value (adjustment));
}
static void
max_size_changed (GtkAdjustment *adjustment,
Waterfall *waterfall)
{
waterfall_set_max_size (waterfall, gtk_adjustment_get_value (adjustment));
}
static void
increment_changed (GtkAdjustment *adjustment,
Waterfall *waterfall)
{
waterfall_set_increment (waterfall, gtk_adjustment_get_value (adjustment));
}
static GtkWidget *
construct_size_bar (Waterfall *waterfall)
{
GtkWidget *hbox;
GtkObject *adjustment;
GtkWidget *spin_button;
GtkWidget *label;
hbox = gtk_hbox_new (FALSE, 12);
gtk_widget_show (hbox);
label = gtk_label_new ("Smallest:");
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
adjustment = gtk_adjustment_new (waterfall_get_min_size (waterfall),
1.0, 1000.0, 2.0, 12.0, 0);
g_signal_connect (adjustment, "value-changed",
G_CALLBACK (min_size_changed), waterfall);
spin_button = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 0, 1);
gtk_widget_show (spin_button);
gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);
label = gtk_label_new ("Biggest:");
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
adjustment = gtk_adjustment_new (waterfall_get_max_size (waterfall),
1.0, 1000.0, 2.0, 12.0, 0);
g_signal_connect (adjustment, "value-changed",
G_CALLBACK (max_size_changed), waterfall);
spin_button = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 0, 1);
gtk_widget_show (spin_button);
gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);
label = gtk_label_new ("Increment:");
gtk_widget_show (label);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
adjustment = gtk_adjustment_new (waterfall_get_increment (waterfall),
0.1, 100.0, 0.1, 1.0, 0);
g_signal_connect (adjustment, "value-changed",
G_CALLBACK (increment_changed), waterfall);
spin_button = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 0, 1);
gtk_widget_show (spin_button);
gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);
return hbox;
}
static void
set_page_label (Waterfall *waterfall)
{
gchar *label;
gint page = waterfall_get_page (waterfall);
if (page == -1)
label = g_strdup ("Quick Brown"); /* strdup just so it can be freed */
else
label = g_strdup_printf ("U+%4.4X", page * WATERFALL_PAGE_SIZE);
gtk_label_set_text (GTK_LABEL (page_label), label);
g_free (label);
}
/* direction should be +1 or -1 */
static void
set_page (Waterfall *waterfall,
gint page,
gint direction)
{
while (waterfall_is_page_empty (waterfall, page)
&& page + direction <= WATERFALL_LAST_PAGE
&& page + direction >= -1)
page += direction;
waterfall_set_page (waterfall, page);
set_page_label (waterfall);
}
static void
back_back_clicked (GtkButton *button,
Waterfall *waterfall)
{
set_page (waterfall, waterfall_get_page (waterfall) - 16, -1);
}
static void
back_clicked (GtkButton *button,
Waterfall *waterfall)
{
set_page (waterfall, waterfall_get_page (waterfall) - 1, -1);
}
static void
forward_clicked (GtkButton *button,
Waterfall *waterfall)
{
set_page (waterfall, waterfall_get_page (waterfall) + 1, 1);
}
static void
forward_forward_clicked (GtkButton *button,
Waterfall *waterfall)
{
set_page (waterfall, waterfall_get_page (waterfall) + 16, 1);
}
static void
forward_forward_forward_clicked (GtkButton *button,
Waterfall *waterfall)
{
set_page (waterfall, WATERFALL_LAST_PAGE, 1);
}
static void
back_back_back_clicked (GtkButton *button,
Waterfall *waterfall)
{
set_page (waterfall, 0, -1);
}
static void
quick_brown_clicked (GtkButton *button,
Waterfall *waterfall)
{
set_page (waterfall, -1, -1);
}
static GtkWidget *
construct_page_navigator (Waterfall *waterfall)
{
GtkWidget *hbox;
GtkWidget *button;
hbox = gtk_hbox_new (FALSE, 3);
gtk_widget_show (hbox);
button = gtk_button_new_with_label (" <<< ");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (back_back_back_clicked), waterfall);
button = gtk_button_new_with_label (" << ");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (back_back_clicked), waterfall);
button = gtk_button_new_with_label (" < ");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (back_clicked), waterfall);
page_label = gtk_label_new (NULL);
gtk_widget_show (page_label);
gtk_label_set_selectable (GTK_LABEL (page_label), TRUE);
gtk_box_pack_start (GTK_BOX (hbox), page_label, FALSE, FALSE, 0);
set_page_label (waterfall);
button = gtk_button_new_with_label (" > ");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (forward_clicked), waterfall);
button = gtk_button_new_with_label (" >> ");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (forward_forward_clicked), waterfall);
button = gtk_button_new_with_label (" >>> ");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (forward_forward_forward_clicked), waterfall);
button = gtk_button_new_with_label ("Quick Brown");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (quick_brown_clicked), waterfall);
return hbox;
}
static GtkWidget *
construct_options_bar (Waterfall *waterfall)
{
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *check_button;
vbox = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox);
hbox = gtk_hbox_new (FALSE, 12);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox),
construct_font_family_chooser (waterfall),
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox),
construct_font_style_chooser (waterfall),
FALSE, FALSE, 0);
check_button = gtk_check_button_new_with_mnemonic ("_Hinting");
gtk_widget_show (check_button);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
waterfall_get_hint (waterfall));
gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (check_button), "toggled",
G_CALLBACK (hint_toggled), waterfall);
check_button = gtk_check_button_new_with_mnemonic ("_Anti-Aliasing");
gtk_widget_show (check_button);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
waterfall_get_antialias (waterfall));
gtk_box_pack_start (GTK_BOX (hbox), check_button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (check_button), "toggled",
G_CALLBACK (antialias_toggled), waterfall);
gtk_box_pack_start (GTK_BOX (hbox), construct_size_bar (waterfall),
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), construct_page_navigator (waterfall),
FALSE, FALSE, 0);
return vbox;
}
gint
main (gint argc, gchar **argv)
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *waterfall;
GtkWidget *scrolled_window;
GdkScreen *screen;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Waterfall");
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
screen = gtk_window_get_screen (GTK_WINDOW (window));
gtk_window_set_default_size (GTK_WINDOW (window),
gdk_screen_get_width (screen) * 3/4,
gdk_screen_get_height (screen) * 3/4);
vbox = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
waterfall = waterfall_new ();
gtk_widget_show (waterfall);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (scrolled_window);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
waterfall);
gtk_box_pack_start (GTK_BOX (vbox),
construct_options_bar (WATERFALL (waterfall)),
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), scrolled_window,
TRUE, TRUE, 0);
gtk_widget_show (window);
gtk_main ();
return 0;
}
--- NEW FILE: waterfall.c ---
/*
* $Id: waterfall.c,v 1.1 2003/04/28 02:45:45 nlevitt Exp $
*
* Copyright (c) 2003 Noah Levitt
*
* This program is free software; the author gives unlimited permission to
* copy and/or distribute it, with or without modifications, as long as
* this notice is preserved.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <X11/Xft/Xft.h>
#include <string.h>
#include "waterfall.h"
#define DEFAULT_STRING \
"the quick brown fox jumped over the lazy dog. " \
"THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG. " \
"0123456789!\"#$%&'()*+,-./:;<=>?@[\\]{|}~"
enum { BUFFER = 12 };
/* buf should have at least WATERFALL_PAGE_SIZE slots */
static void
get_string_for_page (Waterfall *waterfall,
gunichar *buf,
gint *len)
{
gint i;
if (waterfall->page == -1)
{
gchar *p = DEFAULT_STRING;
for (i = 0; p && i < WATERFALL_PAGE_SIZE; i++)
{
buf[i] = g_utf8_get_char (p);
p = g_utf8_find_next_char (p, NULL);
}
*len = i;
}
else
{
for (i = 0; i < WATERFALL_PAGE_SIZE; i++)
buf[i] = (gunichar) (waterfall->page * WATERFALL_PAGE_SIZE + i);
*len = WATERFALL_PAGE_SIZE;
}
}
static XftFont *
open_font (Waterfall *waterfall,
gdouble size)
{
FcPattern *pattern, *match;
FcResult result;
XftFont *font;
pattern = FcPatternCreate ();
if (waterfall->font_family != NULL)
FcPatternAddString (pattern, FC_FAMILY, waterfall->font_family);
if (waterfall->font_style != NULL)
FcPatternAddString (pattern, FC_STYLE, waterfall->font_style);
if (size)
FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
FcPatternAddBool (pattern, FC_HINTING, waterfall->hint);
FcPatternAddBool (pattern, FC_ANTIALIAS, waterfall->antialias);
match = XftFontMatch (GDK_DISPLAY (), gdk_x11_get_default_screen (),
pattern, &result);
FcPatternDestroy (pattern);
if (!match)
return NULL;
font = XftFontOpenPattern (GDK_DISPLAY (), match);
if (!font)
FcPatternDestroy (match);
return font;
}
static void
optimal_size (Waterfall *waterfall,
gint *width,
gint *height)
{
XGlyphInfo extents;
gdouble lines;
XftFont *big_font, *small_font, *theme_font;
gchar *buf;
small_font = open_font (waterfall, waterfall->min_size);
big_font = open_font (waterfall, waterfall->max_size);
theme_font = XftFontOpenName (GDK_DISPLAY (), gdk_x11_get_default_screen (),
pango_font_description_to_string (
GTK_WIDGET (waterfall)->style->font_desc));
XftTextExtentsUtf8 (GDK_DISPLAY (), big_font, DEFAULT_STRING,
strlen (DEFAULT_STRING), &extents);
*width = extents.width + BUFFER;
buf = g_strdup_printf ("%5.1f", waterfall->max_size);
XftTextExtentsUtf8 (GDK_DISPLAY (), theme_font, buf, strlen (buf), &extents);
*width += extents.width + BUFFER;
g_free (buf);
if (*width > 6000)
{
g_warning ("Calculated width %d is too big, clipping at 6000.", *width);
*width = 6000;
}
lines = (waterfall->max_size - waterfall->min_size)
/ waterfall->increment + 1;
*height = 0.5 * (big_font->height + small_font->height) * lines + BUFFER;
if (*height > 3000)
{
g_warning ("Calculated height %d is too big, clipping at 3000.", *height);
*height = 3000;
}
XftFontClose (GDK_DISPLAY (), big_font);
XftFontClose (GDK_DISPLAY (), small_font);
XftFontClose (GDK_DISPLAY (), theme_font);
}
static void
draw_pixmap (Waterfall *waterfall)
{
Colormap colormap;
Drawable drawable;
Visual *visual;
gint width, height;
XGlyphInfo extents;
XftFont *theme_font;
XftColor fg;
XftFont *font;
XftDraw *xftdraw;
gdouble size;
gint y;
gint size_width; /* width allotted to "12.0", etc */
gchar *buf;
gunichar ucs[128];
gint ucs_len;
width = GTK_WIDGET (waterfall)->allocation.width;
height = GTK_WIDGET (waterfall)->allocation.height;
theme_font = XftFontOpenName (GDK_DISPLAY (), gdk_x11_get_default_screen (),
pango_font_description_to_string (
GTK_WIDGET (waterfall)->style->font_desc));
waterfall->pixmap = gdk_pixmap_new (GTK_WIDGET (waterfall)->window,
width, height, -1);
gdk_draw_rectangle (GDK_DRAWABLE (waterfall->pixmap),
GTK_WIDGET (waterfall)->style->base_gc[GTK_STATE_NORMAL],
TRUE, 0, 0, width, height);
colormap = gdk_x11_colormap_get_xcolormap (
gdk_drawable_get_colormap (GTK_WIDGET (waterfall)->window));
drawable = gdk_x11_drawable_get_xid (GDK_DRAWABLE (waterfall->pixmap));
visual = gdk_x11_visual_get_xvisual (
gtk_widget_get_visual (GTK_WIDGET (waterfall)));
xftdraw = XftDrawCreate (GDK_DISPLAY (), drawable, visual, colormap);
fg.color.red = GTK_WIDGET (waterfall)->style->fg[GTK_STATE_NORMAL].red;
fg.color.green = GTK_WIDGET (waterfall)->style->fg[GTK_STATE_NORMAL].green;
fg.color.blue = GTK_WIDGET (waterfall)->style->fg[GTK_STATE_NORMAL].blue;
fg.color.alpha = 0xffff;
buf = g_strdup_printf ("%5.1f", waterfall->max_size);
XftTextExtentsUtf8 (GDK_DISPLAY (), theme_font, buf, strlen (buf), &extents);
size_width = extents.width + BUFFER;
g_free (buf);
for (y = 0, size = waterfall->min_size; size <= waterfall->max_size;
size += waterfall->increment)
{
font = open_font (waterfall, size);
y += font->height;
buf = g_strdup_printf ("%5.1f", size);
XftDrawStringUtf8 (xftdraw, &fg, theme_font, 0, y, buf, strlen (buf));
g_free (buf);
get_string_for_page (waterfall, ucs, &ucs_len);
XftDrawString32(xftdraw, &fg, font, size_width, y, ucs, ucs_len);
XftFontClose (GDK_DISPLAY (), font);
}
XftFontClose (GDK_DISPLAY (), theme_font);
XftDrawDestroy (xftdraw);
}
static gint
expose_event (Waterfall *waterfall,
GdkEventExpose *event)
{
gdk_window_set_back_pixmap (GTK_WIDGET (waterfall)->window, NULL, FALSE);
if (waterfall->pixmap == NULL)
draw_pixmap (waterfall);
gdk_draw_drawable (GTK_WIDGET (waterfall)->window,
GTK_WIDGET (waterfall)->style->fg_gc[GTK_STATE_NORMAL],
waterfall->pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
static void
size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
}
void
waterfall_init (Waterfall *waterfall)
{
waterfall->font_family = NULL;
waterfall->font_style = NULL;
waterfall->min_size = 5.0;
waterfall->max_size = 36.0;
waterfall->increment = 1.0;
waterfall->hint = TRUE;
waterfall->antialias = TRUE;
waterfall->page = -1;
gtk_widget_set_events (GTK_WIDGET (waterfall), GDK_EXPOSURE_MASK);
g_signal_connect (G_OBJECT (waterfall), "expose-event",
G_CALLBACK (expose_event), NULL);
g_signal_connect (G_OBJECT (waterfall), "size-allocate",
G_CALLBACK (size_allocate), NULL);
}
GType waterfall_get_type ()
{
static GType waterfall_type = 0;
if (!waterfall_type)
{
static const GTypeInfo waterfall_info =
{
sizeof (WaterfallClass),
NULL, /* base_init */
NULL, /* base_finalize */
NULL, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (Waterfall),
0, /* n_preallocs */
(GInstanceInitFunc) waterfall_init,
};
waterfall_type = g_type_register_static (GTK_TYPE_DRAWING_AREA,
"Waterfall",
&waterfall_info, 0);
}
return waterfall_type;
}
GtkWidget *
waterfall_new ()
{
return GTK_WIDGET (g_object_new (waterfall_get_type (), NULL));
}
static void
queue_redraw (Waterfall *waterfall)
{
gint width, height;
if (waterfall->pixmap)
{
g_object_unref (waterfall->pixmap);
waterfall->pixmap = NULL;
}
optimal_size (waterfall, &width, &height);
gtk_widget_set_size_request (GTK_WIDGET (waterfall), width, height);
gtk_widget_queue_draw (GTK_WIDGET (waterfall));
}
void
waterfall_set_font_family (Waterfall *waterfall,
const gchar *new_family)
{
if (waterfall->font_family)
g_free (waterfall->font_family);
if (waterfall->font)
XftFontClose (GDK_DISPLAY (), waterfall->font);
waterfall->font_family = g_strdup (new_family);
waterfall->font = open_font (waterfall, waterfall->min_size);
queue_redraw (waterfall);
}
const gchar *
waterfall_get_font_family (Waterfall *waterfall)
{
return waterfall->font_family;
}
void
waterfall_set_font_style (Waterfall *waterfall,
const gchar *new_style)
{
if (waterfall->font_style)
g_free (waterfall->font_style);
if (waterfall->font)
XftFontClose (GDK_DISPLAY (), waterfall->font);
waterfall->font_style = g_strdup (new_style);
waterfall->font = open_font (waterfall, waterfall->min_size);
queue_redraw (waterfall);
}
const gchar *
waterfall_get_font_style (Waterfall *waterfall)
{
return waterfall->font_style;
}
gboolean
waterfall_get_hint (Waterfall *waterfall)
{
return waterfall->hint;
}
void
waterfall_set_hint (Waterfall *waterfall,
gboolean hint)
{
if (hint != waterfall->hint)
{
waterfall->hint = hint;
queue_redraw (waterfall);
}
}
gboolean
waterfall_get_antialias (Waterfall *waterfall)
{
return waterfall->antialias;
}
void
waterfall_set_antialias (Waterfall *waterfall,
gboolean antialias)
{
if (antialias != waterfall->antialias)
{
waterfall->antialias = antialias;
queue_redraw (waterfall);
}
}
gdouble
waterfall_get_min_size (Waterfall *waterfall)
{
return waterfall->min_size;
}
gdouble
waterfall_get_max_size (Waterfall *waterfall)
{
return waterfall->max_size;
}
gdouble
waterfall_get_increment (Waterfall *waterfall)
{
return waterfall->increment;
}
void
waterfall_set_min_size (Waterfall *waterfall,
gdouble min_size)
{
if (min_size != waterfall->min_size)
{
waterfall->min_size = min_size;
queue_redraw (waterfall);
}
}
void
waterfall_set_max_size (Waterfall *waterfall,
gdouble max_size)
{
if (max_size == waterfall->max_size)
return;
waterfall->max_size = max_size;
queue_redraw (waterfall);
}
void
waterfall_set_increment (Waterfall *waterfall,
gdouble increment)
{
if (increment == waterfall->increment)
return;
waterfall->increment = increment;
queue_redraw (waterfall);
}
gint
waterfall_get_page (Waterfall *waterfall)
{
return waterfall->page;
}
void
waterfall_set_page (Waterfall *waterfall,
gint page)
{
if (page > WATERFALL_LAST_PAGE)
page = WATERFALL_LAST_PAGE;
else if (page < -1)
page = -1;
if (page != waterfall->page)
{
waterfall->page = page;
queue_redraw (waterfall);
}
}
gboolean
waterfall_is_page_empty (Waterfall *waterfall,
gint page)
{
FcCharSet *charset;
FcChar32 count;
guint i;
if (page == -1)
return FALSE;
charset = FcCharSetCreate ();
for (i = 0; i < WATERFALL_PAGE_SIZE; i++)
FcCharSetAddChar (charset, page * WATERFALL_PAGE_SIZE + i);
count = FcCharSetIntersectCount (waterfall->font->charset, charset);
FcCharSetDestroy (charset);
return count == 0;
}
--- NEW FILE: waterfall.h ---
/*
* $Id: waterfall.h,v 1.1 2003/04/28 02:45:45 nlevitt Exp $
*
* Copyright (c) 2003 Noah Levitt
*
* This program is free software; the author gives unlimited permission to
* copy and/or distribute it, with or without modifications, as long as
* this notice is preserved.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef WATERFALL_H
#define WATERFALL_H
#include <gtk/gtk.h>
#include <X11/Xft/Xft.h>
G_BEGIN_DECLS
#define WATERFALL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
waterfall_get_type (), Waterfall))
#define WATERFALL_CLASS(clazz) (G_TYPE_CHECK_CLASS_CAST ((clazz), \
waterfall_get_type (),\
WaterfallClass))
#define IS_WATERFALL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
waterfall_get_type ()))
typedef struct _Waterfall Waterfall;
typedef struct _WaterfallClass WaterfallClass;
enum { UNICODE_MAX = 0x10ffff };
enum { WATERFALL_PAGE_SIZE = 128 };
enum { WATERFALL_LAST_PAGE = UNICODE_MAX / WATERFALL_PAGE_SIZE };
struct _Waterfall
{
GtkDrawingArea parent;
GdkPixmap *pixmap;
XftDraw *xftdraw;
gchar *font_family;
gchar *font_style;
XftFont *font;
gdouble min_size;
gdouble max_size;
gdouble increment;
gboolean hint;
gboolean antialias;
gint page;
};
struct _WaterfallClass
{
GtkDrawingAreaClass parent_class;
};
GType waterfall_get_type ();
GtkWidget *waterfall_new ();
const gchar * waterfall_get_font_family (Waterfall *waterfall);
void waterfall_set_font_family (Waterfall *waterfall,
const gchar *new_family);
void waterfall_set_font_style (Waterfall *waterfall,
const gchar *new_style);
const gchar * waterfall_get_font_style (Waterfall *waterfall);
void waterfall_set_antialias (Waterfall *waterfall,
gboolean antialias);
void waterfall_set_hint (Waterfall *waterfall,
gboolean hint);
gboolean waterfall_get_antialias (Waterfall *waterfall);
gboolean waterfall_get_hint (Waterfall *waterfall);
gdouble waterfall_get_min_size (Waterfall *waterfall);
gdouble waterfall_get_max_size (Waterfall *waterfall);
gdouble waterfall_get_increment (Waterfall *waterfall);
void waterfall_set_min_size (Waterfall *waterfall,
gdouble min_size);
void waterfall_set_max_size (Waterfall *waterfall,
gdouble max_size);
void waterfall_set_increment (Waterfall *waterfall,
gdouble increment);
gint waterfall_get_page (Waterfall *waterfall);
void waterfall_set_page (Waterfall *waterfall,
gint page);
gboolean waterfall_is_page_empty (Waterfall *waterfall,
gint page);
G_END_DECLS
#endif /* #ifndef WATERFALL_H */