/*
* 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.
*
*/
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xatom.h>
#include <cairo-xlib-xrender.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>
#include <compiz.h>
#include "text.h"
static int displayPrivateIndex;
typedef struct _TextDisplay
{
FileToImageProc fileToImage;
Atom visibleNameAtom;
} TextDisplay;
#define GET_TEXT_DISPLAY(d) \
((TextDisplay *) (d)->privates[displayPrivateIndex].ptr)
#define TEXT_DISPLAY(d) \
TextDisplay *td = GET_TEXT_DISPLAY (d)
static char*
textGetUtf8Property (CompDisplay *d,
Window id,
Atom atom)
{
Atom type;
int format;
unsigned long nitems;
unsigned long bytesAfter;
char *val;
int result;
char *retval;
result = XGetWindowProperty (d->display, id, atom, 0L, 65536, False,
d->utf8StringAtom, &type, &format, &nitems,
&bytesAfter, (unsigned char **)&val);
if (result != Success)
return NULL;
if (type != d->utf8StringAtom || format != 8 || nitems == 0)
{
if (val)
XFree (val);
return NULL;
}
retval = malloc (sizeof (char) * (nitems + 1));
if (retval)
{
strncpy (retval, val, nitems);
retval[nitems] = 0;
}
XFree (val);
return retval;
}
static char*
textGetTextProperty (CompDisplay *d,
Window id,
Atom atom)
{
XTextProperty text;
char *retval = NULL;
text.nitems = 0;
if (XGetTextProperty (d->display, id, &text, atom))
{
if (text.value)
{
retval = malloc (sizeof (char) * (text.nitems + 1));
if (retval)
{
strncpy (retval, (char *) text.value, text.nitems);
retval[text.nitems] = 0;
}
XFree (text.value);
}
}
return retval;
}
static char*
textGetWindowName (CompDisplay *d,
Window id)
{
char *name;
TEXT_DISPLAY (d);
name = textGetUtf8Property (d, id, td->visibleNameAtom);
if (!name)
name = textGetUtf8Property(d, id, d->wmNameAtom);
if (!name)
name = textGetTextProperty (d, id, XA_WM_NAME);
return name;
}
static Bool
textFileToImage (CompDisplay *d,
const char *path,
const char *name,
int *width,
int *height,
int *stride,
void **data)
{
Bool status = FALSE;
TEXT_DISPLAY (d);
if (path && name && strcmp(path, TEXT_ID) == 0)
{
cairo_t *cr;
cairo_surface_t *surface;
PangoLayout *layout;
Pixmap pixmap;
XRenderPictFormat *format;
PangoFontDescription *font;
CompTextAttrib *textAttrib;
Display *dpy = d->display;
Screen *screen;
int w, h;
textAttrib = (CompTextAttrib*) name; /* get it through the name */
screen = ScreenOfDisplay (dpy, textAttrib->screen->screenNum);
if (!screen)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't get screen for %d.",
textAttrib->screen->screenNum);
return FALSE;
}
format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
if (!format)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't get format.");
return FALSE;
}
pixmap = XCreatePixmap (dpy, textAttrib->screen->root, 1, 1, 32);
if (!pixmap)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't create pixmap.");
return FALSE;
}
surface = cairo_xlib_surface_create_with_xrender_format (dpy,
pixmap,
screen,
format, 1, 1);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't create surface.");
XFreePixmap (dpy, pixmap);
return FALSE;
}
cr = cairo_create (surface);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't create cairo context.");
cairo_surface_destroy (surface);
XFreePixmap (dpy, pixmap);
return FALSE;
}
/* init pango */
layout = pango_cairo_create_layout (cr);
if (!layout)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't create pango layout.");
cairo_destroy (cr);
cairo_surface_destroy (surface);
XFreePixmap (dpy, pixmap);
return FALSE;
}
font = pango_font_description_new ();
if (!font)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't create font description.");
g_object_unref (layout);
cairo_destroy (cr);
cairo_surface_destroy (surface);
XFreePixmap (dpy, pixmap);
return FALSE;
}
pango_font_description_set_family (font, textAttrib->family);
pango_font_description_set_absolute_size (font,
textAttrib->size *
PANGO_SCALE);
pango_font_description_set_style (font, PANGO_STYLE_NORMAL);
if (textAttrib->style & TEXT_STYLE_BOLD)
pango_font_description_set_weight (font, PANGO_WEIGHT_BOLD);
if (textAttrib->style & TEXT_STYLE_ITALIC)
pango_font_description_set_style (font, PANGO_STYLE_ITALIC);
pango_layout_set_font_description (layout, font);
if (textAttrib->ellipsize)
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
switch (textAttrib->renderMode) {
case TextRenderNormal:
{
char *text = (char*) textAttrib->data;
pango_layout_set_text (layout, text, -1);
}
break;
case TextRenderWindowTitle:
{
Window xid = (Window) textAttrib->data;
char *text = textGetWindowName (d, xid);
if (text)
{
pango_layout_set_text (layout, text, -1);
free (text);
}
else
{
pango_font_description_free (font);
g_object_unref (layout);
cairo_destroy (cr);
cairo_surface_destroy (surface);
XFreePixmap (dpy, pixmap);
return FALSE;
}
}
break;
default:
break;
}
pango_layout_get_pixel_size (layout, &w, &h);
w = MIN (textAttrib->maxwidth, w);
h = MIN (textAttrib->maxheight, h);
/* update the size of the pango layout */
pango_layout_set_width (layout, textAttrib->maxwidth * PANGO_SCALE);
cairo_surface_destroy (surface);
cairo_destroy (cr);
XFreePixmap (dpy, pixmap);
pixmap = XCreatePixmap (dpy, textAttrib->screen->root, w, h, 32);
if (!pixmap)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't create %d x %d pixmap.", w, h);
pango_font_description_free (font);
g_object_unref (layout);
return FALSE;
}
surface = cairo_xlib_surface_create_with_xrender_format (dpy, pixmap,
screen, format,
w, h);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't create surface.");
pango_font_description_free (font);
g_object_unref (layout);
XFreePixmap (dpy, pixmap);
return FALSE;
}
cr = cairo_create (surface);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
compLogMessage (d, "text", CompLogLevelError,
"Couldn't create cairo context.");
cairo_surface_destroy (surface);
pango_font_description_free (font);
g_object_unref (layout);
XFreePixmap (dpy, 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,
textAttrib->color[0] / 65535.0,
textAttrib->color[1] / 65535.0,
textAttrib->color[2] / 65535.0,
textAttrib->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;
}
UNWRAP (td, d, fileToImage);
status = (*d->fileToImage) (d, path, name, width, height, stride, data);
WRAP (td, d, fileToImage, textFileToImage);
return status;
}
static Bool
textInitDisplay (CompPlugin *p,
CompDisplay *d)
{
TextDisplay *td;
td = malloc (sizeof (TextDisplay));
if (!td)
return FALSE;
td->visibleNameAtom = XInternAtom (d->display,
"_NET_WM_VISIBLE_NAME", 0);
WRAP (td, d, fileToImage, textFileToImage);
d->privates[displayPrivateIndex].ptr = td;
return TRUE;
}
static void
textFiniDisplay (CompPlugin *p,
CompDisplay *d)
{
TEXT_DISPLAY (d);
UNWRAP (td, d, fileToImage);
free (td);
}
static Bool
textInit (CompPlugin *p)
{
displayPrivateIndex = allocateDisplayPrivateIndex ();
if (displayPrivateIndex < 0)
return FALSE;
return TRUE;
}
static void
textFini (CompPlugin *p)
{
freeDisplayPrivateIndex(displayPrivateIndex);
}
static int
textGetVersion (CompPlugin *p,
int version)
{
return ABIVERSION;
}
CompPluginVTable textVTable = {
"text",
textGetVersion,
0,
textInit,
textFini,
textInitDisplay,
textFiniDisplay,
0,
0,
0,
0,
0,
0,
0,
0
};
CompPluginVTable*
getCompPluginInfo (void)
{
return &textVTable;
}
syntax highlighted by Code2HTML, v. 0.9.1