Pango testing.

This commit is contained in:
QC 2014-08-02 20:02:37 +02:00
parent f87b55dde9
commit 6a45a18a4e
5 changed files with 101 additions and 71 deletions

View file

@ -7,13 +7,15 @@ LIBS=\
@xft_LIBS@\
@x11_LIBS@\
@xdgbasedir_LIBS@\
@xinerama_LIBS@
@xinerama_LIBS@\
@pango_LIBS@
AM_CFLAGS=\
@xft_CFLAGS@\
@x11_CFLAGS@\
@xdgbasedir_CFLAGS@\
@xinerama_CFLAGS@\
@pango_CFLAGS@\
-DMANPAGE_PATH="\"$(mandir)/man1/rofi.1\""\
-I$(top_srcdir)/include/\
-I$(top_srcdir)/config/\

View file

@ -31,6 +31,7 @@ PKG_CHECK_MODULES([xft], [xft])
PKG_CHECK_MODULES([x11], [x11])
PKG_CHECK_MODULES([xinerama], [xinerama])
PKG_CHECK_MODULES([xdgbasedir], [libxdg-basedir])
PKG_CHECK_MODULES([pango], [pango pangoxft])
AC_CONFIG_FILES([Makefile])

View file

@ -2,18 +2,21 @@
#define __TEXTBOX_H__
#include <X11/Xft/Xft.h>
#include <pango/pango.h>
#include <pango/pangoxft.h>
#include <pango/pango-fontmap.h>
typedef struct
{
unsigned long flags;
Window window, parent;
short x, y, w, h;
short cursor;
XftFont *font;
XftColor color_fg, color_bg;
char *text;
XIM xim;
XIC xic;
XGlyphInfo extents;
PangoLayout *layout;
} textbox;
@ -76,7 +79,6 @@ void textbox_hide ( textbox *tb );
* Clean with textbox_cleanup()
*/
void textbox_setup (
const char *font_str, const char *font_active_str,
const char *bg, const char *fg,
const char *hlbg, const char *hlfg
);
@ -86,4 +88,9 @@ void textbox_setup (
*/
void textbox_cleanup ();
int textbox_get_height ( textbox *tb );
int textbox_get_width ( textbox *tb );
int textbox_get_font_height ( textbox *tb );
int textbox_get_font_width ( textbox *tb );
#endif //__TEXTBOX_H__

View file

@ -1123,14 +1123,15 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom
0, 0, NORMAL, prompt );
textbox *text = textbox_create ( main_window, TB_AUTOHEIGHT | TB_EDITABLE,
( config.padding ) + prompt_tb->w,
( config.padding ) + textbox_get_width ( prompt_tb ),
( config.padding ),
( ( config.hmode == TRUE ) ?
element_width : ( w - ( 2 * ( config.padding ) ) ) ) - prompt_tb->w, 1,
element_width : ( w - ( 2 * ( config.padding ) ) ) )
- textbox_get_width ( prompt_tb ), 1,
NORMAL,
( input != NULL ) ? *input : "" );
int line_height = text->font->ascent + text->font->descent;
int line_height = textbox_get_height ( text ); //text->font->ascent + text->font->descent;
textbox_show ( text );
textbox_show ( prompt_tb );
@ -1722,10 +1723,10 @@ static void run_switcher ( int do_fork, SwitcherMode mode )
}
// Because of the above fork, we want to do this here.
// Make sure this is isolated to its own thread.
textbox_setup ( config.menu_font, active_font,
config.menu_bg, config.menu_fg,
config.menu_hlbg,
config.menu_hlfg );
textbox_setup (
config.menu_bg, config.menu_fg,
config.menu_hlbg,
config.menu_hlfg );
char *input = NULL;
// Dmenu is a special mode. You can cycle away from it.
if ( mode == DMENU_DIALOG ) {

View file

@ -37,22 +37,25 @@
#include <X11/Xft/Xft.h>
#include <ctype.h>
#include "rofi.h"
#include "textbox.h"
#define SIDE_MARGIN 2
extern Display *display;
/**
* Font + font color cache.
* Avoid re-loading font on every change on every textbox.
*/
XftFont *font = NULL;
XftFont *font_active = NULL;
XftColor color_fg;
XftColor color_bg;
XftColor color_hlfg;
XftColor color_hlbg;
XftColor color_fg;
XftColor color_bg;
XftColor color_hlfg;
XftColor color_hlbg;
PangoContext *p_context = NULL;
void textbox_moveresize ( textbox *tb, int x, int y, int w, int h );
@ -73,6 +76,12 @@ textbox* textbox_create ( Window parent,
tb->w = MAX ( 1, w );
tb->h = MAX ( 1, h );
tb->layout = pango_layout_new ( p_context );
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font );
pango_layout_set_font_description ( tb->layout, pfd );
pango_font_description_free ( pfd );
unsigned int cp = ( tbft == NORMAL ) ? color_bg.pixel : color_hlbg.pixel;
tb->window = XCreateSimpleWindow ( display, tb->parent, tb->x, tb->y, tb->w, tb->h, 0, None, cp );
@ -98,36 +107,36 @@ textbox* textbox_create ( Window parent,
// set an Xft font by name
void textbox_font ( textbox *tb, TextBoxFontType tbft )
{
PangoFontDescription *pfd = pango_font_description_from_string ( config.menu_font );
switch ( tbft )
{
case HIGHLIGHT:
tb->font = font;
tb->color_bg = color_hlbg;
tb->color_fg = color_hlfg;
break;
case ACTIVE:
tb->font = font_active;
pango_font_description_set_style ( pfd, PANGO_STYLE_ITALIC );
tb->color_bg = color_bg;
tb->color_fg = color_fg;
break;
case ACTIVE_HIGHLIGHT:
tb->font = font_active;
pango_font_description_set_style ( pfd, PANGO_STYLE_ITALIC );
tb->color_bg = color_hlbg;
tb->color_fg = color_hlfg;
break;
case NORMAL:
default:
tb->font = font;
tb->color_bg = color_bg;
tb->color_fg = color_fg;
break;
}
pango_layout_set_font_description ( tb->layout, pfd );
pango_font_description_free ( pfd );
}
// outer code may need line height, width, etc
void textbox_extents ( textbox *tb )
{
XftTextExtentsUtf8 ( display, tb->font, ( unsigned char * ) tb->text, strlen ( tb->text ), &tb->extents );
}
// set the default text to display
@ -137,7 +146,9 @@ void textbox_text ( textbox *tb, char *text )
free ( tb->text );
}
tb->text = strdup ( text );
tb->text = strdup ( text );
pango_layout_set_text ( tb->layout, tb->text, strlen ( tb->text ) );
tb->cursor = MAX ( 0, MIN ( ( int ) strlen ( text ), tb->cursor ) );
textbox_extents ( tb );
}
@ -154,17 +165,21 @@ void textbox_move ( textbox *tb, int x, int y )
void textbox_moveresize ( textbox *tb, int x, int y, int w, int h )
{
if ( tb->flags & TB_AUTOHEIGHT ) {
h = tb->font->ascent + tb->font->descent;
h = textbox_get_font_height ( tb );
}
if ( tb->flags & TB_AUTOWIDTH ) {
if ( w > 1 ) {
w = MIN ( w, tb->extents.width + 2 * SIDE_MARGIN );
w = MIN ( w, textbox_get_font_width ( tb ) + 2 * SIDE_MARGIN );
}
else{
w = tb->extents.width + 2 * SIDE_MARGIN;
w = textbox_get_font_width ( tb ) + 2 * SIDE_MARGIN;
}
}
else {
// set ellipsize
pango_layout_set_ellipsize ( tb->layout, PANGO_ELLIPSIZE_END );
}
if ( x != tb->x || y != tb->y || w != tb->w || h != tb->h ) {
tb->x = x;
@ -199,6 +214,9 @@ void textbox_free ( textbox *tb )
if ( tb->text ) {
free ( tb->text );
}
if ( tb->layout == NULL ) {
g_object_unref ( tb->layout );
}
XDestroyWindow ( display, tb->window );
free ( tb );
@ -206,11 +224,9 @@ void textbox_free ( textbox *tb )
void textbox_draw ( textbox *tb )
{
XGlyphInfo extents;
GC context = XCreateGC ( display, tb->window, 0, 0 );
Pixmap canvas = XCreatePixmap ( display, tb->window, tb->w, tb->h, DefaultDepth ( display, DefaultScreen ( display ) ) );
XftDraw *draw = XftDrawCreate ( display, canvas, DefaultVisual ( display, DefaultScreen ( display ) ), DefaultColormap ( display, DefaultScreen ( display ) ) );
GC context = XCreateGC ( display, tb->window, 0, 0 );
Pixmap canvas = XCreatePixmap ( display, tb->window, tb->w, tb->h, DefaultDepth ( display, DefaultScreen ( display ) ) );
XftDraw *draw = XftDrawCreate ( display, canvas, DefaultVisual ( display, DefaultScreen ( display ) ), DefaultColormap ( display, DefaultScreen ( display ) ) );
// clear canvas
XftDrawRect ( draw, &tb->color_bg, 0, 0, tb->w, tb->h );
@ -218,46 +234,26 @@ void textbox_draw ( textbox *tb )
char *text = tb->text ? tb->text : "";
int text_len = strlen ( text );
int length = text_len;
int line_height = tb->font->ascent + tb->font->descent;
int line_height = textbox_get_font_height ( tb );
int line_width = 0;
int cursor_x = 0;
int cursor_width = MAX ( 2, line_height / 10 );
if ( tb->flags & TB_EDITABLE ) {
int cursor_offset = 0;
cursor_offset = MIN ( tb->cursor, text_len );
pango_layout_set_text ( tb->layout, tb->text, strlen ( tb->text ) );
// Trailing spaces still go wrong....
// The replace by _ is needed, one way or the other.
// Make a copy, and replace all trailing spaces.
char *test = strdup ( text );
for ( int iter = strlen ( text ) - 1; iter >= 0 && test[iter] == ' '; iter-- ) {
test[iter] = '_';
}
// calc cursor position
XftTextExtentsUtf8 ( display, tb->font, ( unsigned char * ) test, cursor_offset, &extents );
if ( tb->flags & TB_EDITABLE ) {
PangoRectangle pos;
int cursor_offset = 0;
cursor_offset = MIN ( tb->cursor, text_len );
pango_layout_get_cursor_pos ( tb->layout, cursor_offset, &pos, NULL );
// Add a small 4px offset between cursor and last glyph.
cursor_x = extents.width + ( ( extents.width > 0 ) ? 2 : 0 );
free ( test );
cursor_x = pos.x / PANGO_SCALE;
}
// calc full input text width
// Calculate the right size, so no characters are cut off.
// TODO: Check performance of this.
do {
XftTextExtentsUtf8 ( display, tb->font, ( unsigned char * ) text, length, &extents );
line_width = extents.width;
if ( line_width <= ( tb->w - 2 * SIDE_MARGIN ) ) {
break;
}
pango_layout_set_width ( tb->layout, PANGO_SCALE * ( tb->w - 2 * SIDE_MARGIN ) );
for ( length -= 1; length > 0 && ( text[length] & 0xc0 ) == 0x80; length -= 1 ) {
;
}
} while ( line_width > 0 );
int x = SIDE_MARGIN, y = tb->font->ascent;
int x = SIDE_MARGIN, y = 0;
if ( tb->flags & TB_RIGHT ) {
x = tb->w - line_width;
@ -268,7 +264,9 @@ void textbox_draw ( textbox *tb )
}
// draw the text.
XftDrawStringUtf8 ( draw, &tb->color_fg, tb->font, x, y, ( unsigned char * ) text, length );
// XftDrawStringUtf8 ( draw, &tb->color_fg, tb->font, x, y, ( unsigned char * ) text, length );
pango_xft_render_layout ( draw, &( tb->color_fg ), tb->layout, x, y );
// draw the cursor
if ( tb->flags & TB_EDITABLE ) {
@ -422,38 +420,59 @@ int textbox_keypress ( textbox *tb, XEvent *ev )
*/
void textbox_setup (
const char *font_str, const char *font_active_str,
const char *bg, const char *fg,
const char *hlbg, const char *hlfg
)
{
Visual *visual = DefaultVisual ( display, DefaultScreen ( display ) );
Colormap colormap = DefaultColormap ( display, DefaultScreen ( display ) );
font = XftFontOpenName ( display, DefaultScreen ( display ), font_str );
font_active = XftFontOpenName ( display, DefaultScreen ( display ), font_active_str );
XftColorAllocName ( display, visual, colormap, fg, &color_fg );
XftColorAllocName ( display, visual, colormap, bg, &color_bg );
XftColorAllocName ( display, visual, colormap, hlfg, &color_hlfg );
XftColorAllocName ( display, visual, colormap, hlbg, &color_hlbg );
PangoFontMap *font_map = pango_xft_get_font_map ( display, DefaultScreen ( display ) );
p_context = pango_font_map_create_context ( font_map );
}
void textbox_cleanup ()
{
if ( font != NULL ) {
if ( p_context ) {
Visual *visual = DefaultVisual ( display, DefaultScreen ( display ) );
Colormap colormap = DefaultColormap ( display, DefaultScreen ( display ) );
XftFontClose ( display, font );
font = NULL;
XftFontClose ( display, font_active );
font_active = NULL;
XftColorFree ( display, visual, colormap, &color_fg );
XftColorFree ( display, visual, colormap, &color_bg );
XftColorFree ( display, visual, colormap, &color_hlfg );
XftColorFree ( display, visual, colormap, &color_hlbg );
g_object_unref ( p_context );
p_context = NULL;
}
}
int textbox_get_width ( textbox *tb )
{
return textbox_get_font_width ( tb ) + 2 * SIDE_MARGIN;
}
int textbox_get_height ( textbox *tb )
{
return textbox_get_font_height ( tb );
}
int textbox_get_font_height ( textbox *tb )
{
int height;
pango_layout_get_pixel_size ( tb->layout, NULL, &height );
return height;
}
int textbox_get_font_width ( textbox *tb )
{
int width;
pango_layout_get_pixel_size ( tb->layout, &width, NULL );
return width;
}