/*
* text.c - adds text image support to beryl.
* Copyright: (C) 2006 Patrick Niklaus
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <cairo-xlib-xrender.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>
#include <beryl.h>
#include "beryl-text.h"
#define TEXT_DISPLAY_OPTION_NUM 0
static int displayPrivateIndex;
typedef struct _TextDisplay
{
CompOption opt[TEXT_DISPLAY_OPTION_NUM];
FileToImageProc fileToImage;
} TextDisplay;
#define GET_TEXT_DISPLAY(d) \
((TextDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define TEXT_DISPLAY(d) \
TextDisplay *td = GET_TEXT_DISPLAY (d)
#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
static Bool textFileToImage(CompDisplay *d,
const char *path,
const char *name,
int *width, int *height, int *stride, void **data)
{
Bool status = FALSE;
if (path && name && strcmp(path, TEXT_ID) == 0)
{
cairo_t *cr;
cairo_surface_t *surface;
PangoLayout *layout;
Pixmap pixmap;
XRenderPictFormat *format;
CompTextAttrib *text_attrib = (CompTextAttrib*) name; // get it through the name
int w,h;
Display *display = d->display;
Screen *screen = ScreenOfDisplay(display, text_attrib->screen->screenNum);
if (!screen) {
printf("ERROR: Couldn't get screen for %d...\n",
text_attrib->screen->screenNum);
return FALSE;
}
format = XRenderFindStandardFormat(display, PictStandardARGB32);
if (!format) {
printf("ERROR: Couldn't get format...\n");
return FALSE;
}
pixmap = XCreatePixmap(display, text_attrib->screen->root, 1, 1, 32);
if (!pixmap) {
printf("ERROR: Couldn't create pixmap...\n");
return FALSE;
}
surface = cairo_xlib_surface_create_with_xrender_format(
display, pixmap, screen, format, 1, 1);
if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
printf("ERROR: Couldn't create surface...\n");
XFreePixmap(display, pixmap);
return FALSE;
}
cr = cairo_create(surface);
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
printf("ERROR: Couldn't create cairo context...\n");
XFreePixmap(display, pixmap);
return FALSE;
}
// init pango
layout = pango_cairo_create_layout(cr);
if (!layout) {
printf("ERROR: Couldn't create pango layout...\n");
XFreePixmap(display, pixmap);
return FALSE;
}
PangoFontDescription *font = pango_font_description_new();
pango_font_description_set_family(font, text_attrib->family);
pango_font_description_set_absolute_size(font, text_attrib->size * PANGO_SCALE);
pango_font_description_set_style(font, PANGO_STYLE_NORMAL);
if (text_attrib->style & TEXT_STYLE_BOLD)
pango_font_description_set_weight(font, PANGO_WEIGHT_BOLD);
if (text_attrib->style & TEXT_STYLE_ITALIC)
pango_font_description_set_style(font, PANGO_STYLE_ITALIC);
pango_layout_set_font_description(layout, font);
if (text_attrib->ellipsize)
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
pango_layout_set_text(layout, text_attrib->text, -1);
pango_layout_get_pixel_size(layout, &w, &h);
w = MIN(text_attrib->maxwidth, w);
h = MIN(text_attrib->maxheight, h);
// update the size of the pango layout
pango_layout_set_width(layout, w*PANGO_SCALE);
cairo_surface_destroy(surface);
cairo_destroy(cr);
XFreePixmap(display, pixmap);
pixmap = XCreatePixmap(display, text_attrib->screen->root, w, h, 32);
surface = cairo_xlib_surface_create_with_xrender_format(display, pixmap,
screen, format, w, h);
if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
printf("ERROR: Couldn't create surface...\n");
XFreePixmap(display, pixmap);
return FALSE;
}
cr = cairo_create(surface);
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
printf("ERROR: Couldn't create cairo context...\n");
XFreePixmap(display, pixmap);
return FALSE;
}
pango_cairo_update_layout(cr,layout);
cairo_save(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_restore(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba(cr,
text_attrib->color[0] / 65535.0,
text_attrib->color[1] / 65535.0,
text_attrib->color[2] / 65535.0,
text_attrib->color[3] / 65535.0);
pango_cairo_show_layout(cr, layout);
g_object_unref(layout);
cairo_surface_destroy(surface);
cairo_destroy(cr);
pango_font_description_free(font);
*width = w;
*height = h;
*data = (void *)pixmap;
return TRUE;
}
TEXT_DISPLAY(d);
UNWRAP(td, d, fileToImage);
status = (*d->fileToImage) (d, path, name, width, height, stride, data);
WRAP(td, d, fileToImage, textFileToImage);
return status;
}
static void textDisplayInitOptions(TextDisplay *td)
{
//CompOption *o;
}
static CompOption *textGetDisplayOptions(CompDisplay *display, int *count)
{
if (display)
{
TEXT_DISPLAY(display);
*count = NUM_OPTIONS(td);
return td->opt;
} else {
TextDisplay *td = malloc(sizeof(TextDisplay));
textDisplayInitOptions(td);
*count = NUM_OPTIONS(td);
return td->opt;
}
}
static Bool
textSetDisplayOption(CompDisplay *display, char *name, CompOptionValue *value)
{
CompOption *o;
int index;
TEXT_DISPLAY(display);
o = compFindOption(td->opt, NUM_OPTIONS(td), name, &index);
if (!o)
return FALSE;
switch (index)
{
default:
break;
}
return FALSE;
}
static Bool textInitDisplay(CompPlugin *p, CompDisplay *d)
{
TextDisplay *td;
CompScreen *s;
td = malloc(sizeof(TextDisplay));
if (!td)
return FALSE;
WRAP(td, d, fileToImage, textFileToImage);
d->privates[displayPrivateIndex].ptr = td;
textDisplayInitOptions(td);
for (s = d->screens; s; s = s->next)
updateDefaultIcon(s);
return TRUE;
}
static void textFiniDisplay(CompPlugin *p, CompDisplay *d)
{
CompScreen *s;
TEXT_DISPLAY(d);
UNWRAP(td, d, fileToImage);
for (s = d->screens; s; s = s->next)
updateDefaultIcon(s);
free(td);
}
static Bool textInit(CompPlugin *p)
{
displayPrivateIndex = allocateDisplayPrivateIndex();
if (displayPrivateIndex < 0)
return FALSE;
return TRUE;
}
static void textFini(CompPlugin *p)
{
if (displayPrivateIndex >= 0)
freeDisplayPrivateIndex(displayPrivateIndex);
}
CompPluginFeature textFeatures[]={
{"TextToPixmap"}
};
CompPluginVTable textVTable = {
"text",
N_("Text"),
N_("Render text to texture plugin"),
textInit,
textFini,
textInitDisplay,
textFiniDisplay,
0,
0,
0,
0,
textGetDisplayOptions,
textSetDisplayOption,
0,
0,
0,
0,
textFeatures,
sizeof(textFeatures)/sizeof(textFeatures[0]),
BERYL_ABI_INFO,
"beryl-plugins-extra",
"imageformat",
0,
0,
True,
};
CompPluginVTable *getCompPluginInfo(void)
{
return &textVTable;
}
syntax highlighted by Code2HTML, v. 0.9.1