2 * (c) 2007, Quest Software, Inc. All rights reserved.
4 * This file is part of XScreenSaver,
5 * Copyright (c) 1993-2009 Jamie Zawinski <jwz@jwz.org>
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation. No representations are made about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
23 #define LINE_SPACING 1.2
26 mlstring_allocate(const char *msg);
29 mlstring_calculate(mlstring *str, XFontStruct *font);
32 mlstring_new(const char *msg, XFontStruct *font, Dimension wrap_width)
36 if (!(newstr = mlstring_allocate(msg)))
39 newstr->font_id = font->fid;
41 mlstring_wrap(newstr, font, wrap_width);
47 mlstring_allocate(const char *msg)
51 struct mlstr_line *cur, *prev = NULL;
58 ml = calloc(1, sizeof(mlstring));
63 for (s = msg; !the_end; msg = ++s)
65 /* New string struct */
66 cur = calloc(1, sizeof(struct mlstr_line));
73 /* Find the \n or end of string */
87 /* Duplicate the string */
88 cur->line = malloc(linelength + 1);
92 strncpy(cur->line, msg, linelength);
93 cur->line[linelength] = '\0';
96 prev->next_line = cur;
113 * This function does not have any unit tests.
116 mlstring_free(mlstring *str) {
117 struct mlstr_line *cur, *next;
119 for (cur = str->lines; cur; cur = next) {
120 next = cur->next_line;
130 mlstring_wrap(mlstring *mstring, XFontStruct *font, Dimension width)
132 short char_width = font->max_bounds.width;
133 int line_length, wrap_at;
134 struct mlstr_line *mstr, *newml;
136 /* An alternative implementation of this function would be to keep trying
137 * XTextWidth() on space-delimited substrings until the longest one less
138 * than 'width' is found, however there shouldn't be much difference
139 * between that, and this implementation.
142 for (mstr = mstring->lines; mstr; mstr = mstr->next_line)
144 if (XTextWidth(font, mstr->line, strlen(mstr->line)) > width)
147 line_length = width / char_width;
148 if (line_length == 0)
151 /* First try to soft wrap by finding a space */
152 for (wrap_at = line_length; wrap_at >= 0 && !isspace(mstr->line[wrap_at]); --wrap_at);
154 if (wrap_at == -1) /* No space found, hard wrap */
155 wrap_at = line_length;
157 wrap_at++; /* Leave the space at the end of the line. */
159 newml = calloc(1, sizeof(*newml));
160 if (!newml) /* OOM, don't bother trying to wrap */
163 if (NULL == (newml->line = strdup(mstr->line + wrap_at)))
170 /* Terminate the existing string at its end */
171 mstr->line[wrap_at] = '\0';
173 newml->next_line = mstr->next_line;
174 mstr->next_line = newml;
178 mlstring_calculate(mstring, font);
182 #define MAX(x, y) ((x) > (y) ? (x) : (y))
185 * Calculates the overall extents (width + height of the multi-line string).
186 * This function is called as part of mlstring_new().
187 * It does not have any unit testing.
190 mlstring_calculate(mlstring *str, XFontStruct *font) {
191 struct mlstr_line *line;
193 str->font_height = font->ascent + font->descent;
194 str->overall_height = 0;
195 str->overall_width = 0;
197 /* XXX: Should there be some baseline calculations to help XDrawString later on? */
198 str->font_ascent = font->ascent;
200 for (line = str->lines; line; line = line->next_line)
202 line->line_width = XTextWidth(font, line->line, strlen(line->line));
203 str->overall_width = MAX(str->overall_width, line->line_width);
204 /* Don't add line spacing for the first line */
205 str->overall_height += (font->ascent + font->descent) *
206 (line == str->lines ? 1 : LINE_SPACING);
211 mlstring_draw(Display *dpy, Drawable dialog, GC gc, mlstring *string, int x, int y) {
212 struct mlstr_line *line;
217 y += string->font_ascent;
219 XSetFont(dpy, gc, string->font_id);
221 for (line = string->lines; line; line = line->next_line)
223 XDrawString(dpy, dialog, gc, x, y, line->line, strlen(line->line));
224 y += string->font_height * LINE_SPACING;
228 /* vim:ts=8:sw=2:noet