4 * Part of gwm, the Gratuitous Window Manager,
5 * by Gary Wong, <gtw@gnu.org>.
7 * Copyright (C) 2009 Gary Wong
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of version 3 of the GNU General Public License as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <fontconfig/fontconfig.h>
29 #include FT_FREETYPE_H
34 #include <xcb/render.h>
40 #include "decorate-render.h"
45 STYLE_TITLE
, STYLE_MENU
, NUM_STYLES
48 #define TITLE_FONT_SIZE 12
49 #define MENU_FONT_SIZE 14
52 #define STRING(x) STRING2(x)
53 #define TITLE_FONT_SIZE_STRING STRING( TITLE_FONT_SIZE )
54 #define MENU_FONT_SIZE_STRING STRING( MENU_FONT_SIZE )
59 #define FEEDBACK_WIDTH 96 /* width of size feedback window */
60 #define FEEDBACK_HEIGHT 24 /* height of size feedback window */
62 static const FcChar8
*const style_names
[ NUM_STYLES
] = {
63 /* FIXME make this configurable */
64 (FcChar8
*) "sans:pixelsize=" TITLE_FONT_SIZE_STRING
":bold",
65 (FcChar8
*) "sans:pixelsize=" MENU_FONT_SIZE_STRING
77 int *fonts
; /* indices into font table above */
80 } styles
[ NUM_STYLES
];
82 static FT_Library ftl
;
84 static const uint16_t decoration_cols
[ NUM_COLS
][ 3 ] = {
85 { 0x2222, 0x3333, 0xEEEE }, /* COL_FRAME_ACTIVE */
86 { 0xAAAA, 0xAAAA, 0xAAAA }, /* COL_FRAME_INACTIVE */
87 { 0x0000, 0x0000, 0x0000 }, /* COL_BORDER */
88 { 0xFFFF, 0x0000, 0x0000 }, /* COL_BUTTON_ACTIVE */
89 { 0xCCCC, 0xCCCC, 0xCCCC }, /* COL_BUTTON_INACTIVE */
90 { 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_TITLE_ACTIVE */
91 { 0x3333, 0x3333, 0x3333 }, /* COL_TITLE_INACTIVE */
92 { 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_FEEDBACK_BACK */
93 { 0x0000, 0x0000, 0x0000 }, /* COL_FEEDBACK_FORE */
94 { 0x2222, 0x3333, 0xEEEE }, /* COL_MENU_ACTIVE_BACK */
95 { 0xFFFF, 0xFFFF, 0xFFFF }, /* COL_MENU_ACTIVE_FORE */
96 { 0xCCCC, 0xCCCC, 0xCCCC }, /* COL_MENU_INACTIVE_BACK */
97 { 0x0000, 0x0000, 0x0000 } /* COL_MENU_INACTIVE_FORE */
100 #define METRIC_CACHE_SIZE_BITS 14
101 #define METRIC_CACHE_SIZE ( 1 << METRIC_CACHE_SIZE_BITS )
102 #define METRIC_CACHE_ASSOC_BITS 2
103 #define METRIC_CACHE_ASSOC ( 1 << METRIC_CACHE_ASSOC_BITS )
105 #define GLYPH_CACHE_SIZE_BITS 11
106 #define GLYPH_CACHE_SIZE ( 1 << GLYPH_CACHE_SIZE_BITS )
107 #define GLYPH_CACHE_ASSOC_BITS 3
108 #define GLYPH_CACHE_ASSOC ( 1 << GLYPH_CACHE_ASSOC_BITS )
110 #if GLYPH_CACHE_SIZE_BITS + GLYPH_CACHE_ASSOC_BITS > 16
111 #error "Glyph cache is too big for 16-bit indices."
114 static struct metric_cache_line
{
116 uint32_t c
; /* character code */
119 } metric_cache
[ METRIC_CACHE_SIZE
][ METRIC_CACHE_ASSOC
];
121 static struct glyph_cache_line
{
123 uint32_t c
; /* character code */
125 } glyph_cache
[ GLYPH_CACHE_SIZE
][ GLYPH_CACHE_ASSOC
];
127 static unsigned int current_time
;
129 static struct font
*lookup_font( enum style_id style
, uint32_t c
) {
133 if( !FcCharSetHasChar( styles
[ style
].charset
, c
) )
136 for( i
= 0; i
< styles
[ style
].num_fonts
; i
++ ) {
137 struct font
*font
= fonts
+ styles
[ style
].fonts
[ i
];
139 if( FcCharSetHasChar( font
->charset
, c
) ) {
142 FcMatrix
*matrix
= NULL
;
144 int index
= 0, hintstyle
= FC_HINT_MEDIUM
;
146 FcBool hinting
= TRUE
, autohint
= FALSE
, globaladvance
= TRUE
,
147 embeddedbitmap
= TRUE
;
149 if( FcPatternGetString( font
->pattern
, FC_FILE
, 0,
151 FcPatternGetDouble( font
->pattern
, FC_PIXEL_SIZE
, 0,
155 FcPatternGetInteger( font
->pattern
, FC_INDEX
, 0, &index
);
156 FcPatternGetMatrix( font
->pattern
, FC_MATRIX
, 0, &matrix
);
158 if( FT_New_Face( ftl
, (char *) filename
, index
, &font
->face
) )
161 FT_Set_Pixel_Sizes( font
->face
, 0, (int) ( size
+ 0.5 ) );
164 ft_matrix
.xx
= matrix
->xx
* 64.0;
165 ft_matrix
.xy
= matrix
->xy
* 64.0;
166 ft_matrix
.yx
= matrix
->yx
* 64.0;
167 ft_matrix
.yy
= matrix
->yy
* 64.0;
168 FT_Set_Transform( font
->face
, &ft_matrix
, NULL
);
171 FT_Select_Charmap( font
->face
, FT_ENCODING_UNICODE
);
173 FcPatternGetBool( font
->pattern
, FC_HINTING
, 0, &hinting
);
174 FcPatternGetInteger( font
->pattern
, FC_HINT_STYLE
, 0,
176 FcPatternGetBool( font
->pattern
, FC_AUTOHINT
, 0, &autohint
);
177 FcPatternGetBool( font
->pattern
, FC_GLOBAL_ADVANCE
, 0,
179 FcPatternGetBool( font
->pattern
, FC_EMBEDDED_BITMAP
, 0,
182 font
->load_flags
= FT_LOAD_DEFAULT
;
185 font
->load_flags
|= FT_LOAD_NO_HINTING
;
187 switch( hintstyle
) {
189 font
->load_flags
|= FT_LOAD_NO_HINTING
;
193 font
->load_flags
|= FT_LOAD_TARGET_LIGHT
;
198 font
->load_flags
|= FT_LOAD_TARGET_NORMAL
;
202 font
->load_flags
|= FT_LOAD_TARGET_MONO
;
207 font
->load_flags
|= FT_LOAD_FORCE_AUTOHINT
;
210 font
->load_flags
|= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
212 if( !embeddedbitmap
)
213 font
->load_flags
|= FT_LOAD_NO_BITMAP
;
223 static void query_metrics( enum style_id style
, uint32_t c
,
224 int *x_off
, int *y_off
) {
226 int row
= c
& ( METRIC_CACHE_SIZE
- 1 );
230 for( i
= 0; i
< METRIC_CACHE_ASSOC
; i
++ )
231 if( metric_cache
[ row
][ i
].style
== style
&&
232 metric_cache
[ row
][ i
].c
== c
) {
234 metric_cache
[ row
][ i
].time
= current_time
;
235 *x_off
= metric_cache
[ row
][ i
].x_off
;
236 *y_off
= metric_cache
[ row
][ i
].y_off
;
240 font
= lookup_font( style
, c
);
243 if( FT_Load_Char( font
->face
, c
, font
->load_flags
) ) {
244 /* Couldn't load metrics. Don't bother evicting anything. */
249 /* Search for a line to evict. */
250 for( i
= 1, max
= 0; i
< METRIC_CACHE_ASSOC
; i
++ )
251 if( current_time
- metric_cache
[ row
][ i
].time
>
252 current_time
- metric_cache
[ row
][ max
].time
)
255 metric_cache
[ row
][ max
].style
= style
;
256 metric_cache
[ row
][ max
].c
= c
;
257 metric_cache
[ row
][ max
].time
= current_time
;
258 *x_off
= metric_cache
[ row
][ max
].x_off
=
259 ( font
->face
->glyph
->advance
.x
+ 0x20 ) >> 6;
260 *y_off
= metric_cache
[ row
][ max
].y_off
=
261 ( font
->face
->glyph
->advance
.y
+ 0x20 ) >> 6;
264 static int query_glyph( enum style_id style
, uint32_t c
) {
266 int row
= c
& ( GLYPH_CACHE_SIZE
- 1 );
269 for( i
= 0; i
< GLYPH_CACHE_ASSOC
; i
++ )
270 if( glyph_cache
[ row
][ i
].style
== style
&&
271 glyph_cache
[ row
][ i
].c
== c
) {
273 glyph_cache
[ row
][ i
].time
= current_time
;
274 return ( row
<< GLYPH_CACHE_ASSOC_BITS
) | i
;
280 static int replace_glyph( enum style_id style
, uint32_t c
) {
282 int row
= c
& ( GLYPH_CACHE_SIZE
- 1 );
285 /* Search for a line to evict. */
286 for( i
= 1, max
= 0; i
< METRIC_CACHE_ASSOC
; i
++ ) {
287 assert( glyph_cache
[ row
][ i
].style
!= style
||
288 glyph_cache
[ row
][ i
].c
!= c
);
289 if( current_time
- glyph_cache
[ row
][ i
].time
>
290 current_time
- glyph_cache
[ row
][ max
].time
)
294 if( glyph_cache
[ row
][ max
].time
== current_time
)
295 /* Cache line set is full, and nothing is old enough to evict. */
298 glyph_cache
[ row
][ max
].style
= style
;
299 glyph_cache
[ row
][ max
].c
= c
;
300 glyph_cache
[ row
][ max
].time
= current_time
;
302 return ( row
<< GLYPH_CACHE_ASSOC_BITS
) | max
;
305 static xcb_render_glyphset_t glyphset
;
306 static struct picture
{
307 xcb_render_picture_t pic
;
308 enum decoration_col col
;
309 } *pictures
; /* indexed by screen */
311 static xcb_void_cookie_t
render_text( xcb_drawable_t drawable
, int screen
,
312 int col
, int x
, int y
,
313 const char *text
, enum style_id style
,
314 const xcb_rectangle_t
*clip
) {
316 xcb_render_picture_t src
, dest
;
317 xcb_rectangle_t rect
;
318 xcb_render_color_t rc
;
320 const unsigned char *p
;
323 if( !text
|| !( len
= utf8_length( (const unsigned char *) text
) ) ) {
324 xcb_void_cookie_t r
= { 0 };
329 buf
= alloca( len
* sizeof *buf
);
331 for( i
= 0, p
= (const unsigned char *) text
; i
< len
; i
++ )
332 buf
[ i
] = utf8_next( &p
);
334 src
= pictures
[ screen
].pic
;
336 dest
= xcb_generate_id( c
);
337 xcb_render_create_picture( c
, dest
, drawable
,
338 gwm_screens
[ screen
].root_pictformat
, 0, NULL
);
341 xcb_render_set_picture_clip_rectangles( c
, dest
, 0, 0, 1, clip
);
343 if( pictures
[ screen
].col
!= col
) {
344 rc
.red
= decoration_cols
[ col
][ 0 ];
345 rc
.green
= decoration_cols
[ col
][ 1 ];
346 rc
.blue
= decoration_cols
[ col
][ 2 ];
352 xcb_render_fill_rectangles( c
, XCB_RENDER_PICT_OP_SRC
, src
, rc
, 1,
355 pictures
[ screen
].col
= col
;
360 uint32_t glyphids
[ 0x80 ];
361 xcb_render_glyphinfo_t glyphs
[ 0x80 ];
362 int num_glyphs
; /* number of glyphs in AddGlyphs request */
363 /* Buffer for "data" parameter of AddGlyphs request. We want
364 this to be big enough to hold at least one glyph, but no
365 bigger than the biggest request the server will accept (once
366 the other parameters are included). All servers must
367 accept requests of 16,384 bytes or smaller (see X Window
368 System Protocol, section 8), so this is safe. */
369 uint8_t data
[ 0x2000 ], *p
;
370 /* Buffer for "glyphcmds" parameter of CompositeGlyphs16
371 request. We always send exactly one command, which has an
372 8-byte header and at most a 254 glyph string. */
373 uint8_t param
[ 8 + ( 0xFE << 1 ) ], *out
;
374 int num_chars
; /* number of characters for CompositeGlyphs16 */
381 memset( param
, 0, 4 );
382 *( (uint16_t *) ( param
+ 4 ) ) = x
;
383 *( (uint16_t *) ( param
+ 6 ) ) = y
;
387 while( i
< len
&& num_chars
< 0xFF ) {
390 if( ( index
= query_glyph( style
, buf
[ i
] ) ) < 0 ) {
396 if( ( index
= replace_glyph( style
, buf
[ i
] ) ) < 0 )
397 /* Cache set full: spill the partial string to make
398 room for later glyphs. */
401 if( !( font
= lookup_font( style
, buf
[ i
] ) ) ||
402 FT_Load_Char( font
->face
, buf
[ i
], font
->load_flags
|
404 ( bitmap_size
= ( ( font
->face
->glyph
->bitmap
.width
+
406 font
->face
->glyph
->bitmap
.rows
) > sizeof data
) {
407 /* We couldn't load the character, or it was so
408 huge that it won't fit in an empty AddGlyph
409 data buffer. We'll have to send the server
410 an empty glyph and carry on. */
414 slot
= font
->face
->glyph
;
416 if( ( p
- data
) + bitmap_size
> sizeof data
||
417 num_glyphs
== sizeof glyphids
/ sizeof *glyphids
) {
418 /* Can't fit this glyph into the existing request:
419 transmit what we have... */
420 xcb_render_add_glyphs( c
, glyphset
, num_glyphs
, glyphids
,
421 glyphs
, p
- data
, data
);
423 /* ...and start building another AddGlyph request. */
428 glyphids
[ num_glyphs
] = index
;
433 FT_Bitmap_New( &bitmap
);
434 FT_Bitmap_Convert( ftl
, &slot
->bitmap
, &bitmap
, 4 );
436 glyphs
[ num_glyphs
].width
= bitmap
.width
;
437 glyphs
[ num_glyphs
].height
= bitmap
.rows
;
438 glyphs
[ num_glyphs
].x
= -slot
->bitmap_left
;
439 glyphs
[ num_glyphs
].y
= slot
->bitmap_top
;
440 glyphs
[ num_glyphs
].x_off
=
441 ( slot
->advance
.x
+ 0x20 ) >> 6;
442 glyphs
[ num_glyphs
].y_off
=
443 ( slot
->advance
.y
+ 0x20 ) >> 6;
445 memcpy( p
, bitmap
.buffer
, bitmap
.pitch
* bitmap
.rows
);
447 if( bitmap
.num_grays
!= 0x100 ) {
449 *end
= p
+ bitmap
.pitch
* bitmap
.rows
;
451 for( c
= p
; c
< end
; c
++ )
452 *c
= ( (unsigned int) *c
* 0xFF /
453 ( bitmap
.num_grays
- 1 ) );
456 p
+= bitmap
.pitch
* bitmap
.rows
;
458 FT_Bitmap_Done( ftl
, &bitmap
);
460 glyphs
[ num_glyphs
].width
= 0;
461 glyphs
[ num_glyphs
].height
= 0;
462 glyphs
[ num_glyphs
].x
= 0;
463 glyphs
[ num_glyphs
].y
= 0;
464 glyphs
[ num_glyphs
].x_off
= 0;
465 glyphs
[ num_glyphs
].y_off
= 0;
471 *( (uint16_t *) out
) = index
;
474 query_metrics( style
, buf
[ i
], &dx
, &dy
);
483 xcb_render_add_glyphs( c
, glyphset
, num_glyphs
, glyphids
, glyphs
,
490 param
[ 0 ] = num_chars
;
492 xcb_render_composite_glyphs_16( c
, XCB_RENDER_PICT_OP_OVER
, src
, dest
,
493 XCB_NONE
, glyphset
, 0, 0, out
- param
,
497 return xcb_render_free_picture( c
, dest
);
500 static int text_width( enum style_id style
, const char *text
) {
502 const unsigned char *p
= (const unsigned char *) text
;
508 query_metrics( style
, utf8_next( &p
), &dx
, &dy
);
515 extern void render_update_window( struct gwm_window
*window
) {
517 if( !window
->cleared
)
518 xcb_clear_area( c
, FALSE
, window
->w
, window
->update
.x
, window
->update
.y
,
519 window
->update
.width
, window
->update
.height
);
521 if( window
->type
== WINDOW_FRAME
) {
522 char *name
= window
->u
.frame
.child
->u
.managed
.name
;
524 render_text( window
->w
, window
->screen
, window
== focus_frame
?
525 COL_TITLE_ACTIVE
: COL_TITLE_INACTIVE
,
526 button_size( window
->u
.frame
.button
, TRUE
) + 4,
527 TITLE_FONT_SIZE
, name
? name
: "(Untitled)",
528 STYLE_TITLE
, &window
->update
);
529 } else if( window
->type
== WINDOW_MENUITEM
) {
530 struct gwm_window
*menu
= window
->u
.menuitem
.menu
;
532 render_text( window
->w
, window
->screen
,
533 menu
->u
.menu
.active_item
>= 0 &&
534 menu
->u
.menu
.items
[ menu
->u
.menu
.active_item
] == window
?
535 COL_MENU_ACTIVE_FORE
: COL_MENU_INACTIVE_FORE
,
536 MENU_X_PAD
, MENU_FONT_SIZE
,
537 window
->u
.menuitem
.label
, STYLE_MENU
, &window
->update
);
538 } else if( window
->type
== WINDOW_FEEDBACK
) {
541 sprintf( text
, "%dx%d", window
->u
.feedback
.fb_width
,
542 window
->u
.feedback
.fb_height
);
544 render_text( window
->w
, window
->screen
, COL_FEEDBACK_FORE
,
545 ( FEEDBACK_WIDTH
- text_width( STYLE_TITLE
, text
) ) >> 1,
546 16, text
, STYLE_TITLE
, &window
->update
);
550 extern void render_window_size( struct gwm_window
*window
, int *width
,
553 switch( window
->type
) {
554 case WINDOW_MENUITEM
:
555 if( window
->u
.menuitem
.label
) {
556 *width
= text_width( STYLE_MENU
, window
->u
.menuitem
.label
) +
558 *height
= MENU_FONT_SIZE
+ ( MENU_Y_PAD
<< 1 );
560 *width
= MENU_X_PAD
<< 1;
561 *height
= MENU_Y_PAD
<< 1;
565 case WINDOW_FEEDBACK
:
566 *width
= FEEDBACK_WIDTH
;
567 *height
= FEEDBACK_HEIGHT
;
575 static uint16_t luma( int col
) {
577 return ( decoration_cols
[ col
][ 0 ] * 0x4C8BU
+
578 decoration_cols
[ col
][ 1 ] * 0x9646U
+
579 decoration_cols
[ col
][ 2 ] * 0x1D2FU
) >> 16;
582 static void handle_alloc_color( unsigned int sequence
, void *reply
,
583 xcb_generic_error_t
*error
,
584 union callback_param p
) {
586 xcb_alloc_color_reply_t
*r
= reply
;
587 int screen
= p
.l
>> 16, col
= p
.l
& 0xFFFF;
590 if( error
->error_code
!= XCB_ALLOC
)
593 /* No standard RGB map available, and we couldn't allocate a shared
594 colour. Fall back to black or white. */
595 gwm_screens
[ screen
].pixels
[ col
] = luma( col
) >= 0x8000 ?
596 screens
[ screen
]->white_pixel
: screens
[ screen
]->black_pixel
;
602 gwm_screens
[ screen
].pixels
[ col
] = r
->pixel
;
608 static void handle_get_default_map( unsigned int sequence
, void *reply
,
609 xcb_generic_error_t
*error
,
610 union callback_param p
) {
612 int col
, got_cols
= FALSE
;
621 xcb_get_property_reply_t
*prop
= reply
;
623 /* RGB_COLOR_MAP property -- see ICCCM 2.0, section 6.4. */
624 xcb_colormap_t colormap
;
625 uint32_t red_max
, red_mult
, green_max
, green_mult
, blue_max
,
626 blue_mult
, base_pixel
;
627 xcb_visualid_t visual_id
;
629 } *std_cmaps
= xcb_get_property_value( prop
);
630 int num_cmaps
= ( xcb_get_property_value_length( prop
) << 2 ) /
634 if( prop
->format
== 32 )
635 for( i
= 0; i
< num_cmaps
; i
++ )
636 if( std_cmaps
[ i
].visual_id
==
637 gwm_screens
[ p
.l
].root_visual
->visual_id
) {
639 for( col
= 0; col
< NUM_COLS
; col
++ ) {
640 int r0
, g0
, b0
, r
, g
, b
;
642 if( gwm_screens
[ p
.l
].root_visual
->_class
==
643 XCB_VISUAL_CLASS_STATIC_GRAY
||
644 gwm_screens
[ p
.l
].root_visual
->_class
==
645 XCB_VISUAL_CLASS_GRAY_SCALE
) {
649 r0
= decoration_cols
[ col
][ 0 ];
650 g0
= decoration_cols
[ col
][ 1 ];
651 b0
= decoration_cols
[ col
][ 2 ];
654 r
= ( r0
* std_cmaps
[ i
].red_max
+ 0x8000 ) >> 16;
655 g
= ( g0
* std_cmaps
[ i
].green_max
+ 0x8000 ) >> 16;
656 b
= ( b0
* std_cmaps
[ i
].blue_max
+ 0x8000 ) >> 16;
658 gwm_screens
[ p
.l
].pixels
[ col
] =
659 std_cmaps
[ i
].base_pixel
+
660 r
* std_cmaps
[ i
].red_mult
+
661 g
* std_cmaps
[ i
].green_mult
+
662 b
* std_cmaps
[ i
].blue_mult
;
673 /* No useful default maps found; try allocating directly. */
674 for( col
= 0; col
< NUM_COLS
; col
++ ) {
676 union callback_param cp
;
678 if( gwm_screens
[ p
.l
].root_visual
->_class
==
679 XCB_VISUAL_CLASS_STATIC_GRAY
||
680 gwm_screens
[ p
.l
].root_visual
->_class
==
681 XCB_VISUAL_CLASS_GRAY_SCALE
)
682 r
= g
= b
= luma( col
);
684 r
= decoration_cols
[ col
][ 0 ];
685 g
= decoration_cols
[ col
][ 1 ];
686 b
= decoration_cols
[ col
][ 2 ];
689 cp
.l
= ( p
.l
<< 16 ) | col
;
690 /* Ideally, we would like a guarantee that this operation will
691 complete before the pixel values are ever looked up. In
692 practice, it will, and it is too messy to insert a
693 sync_with_callback() before every single pixel reference. */
694 handle_async_reply( xcb_alloc_color(
695 c
, screens
[ p
.l
]->default_colormap
,
696 r
, g
, b
).sequence
, handle_alloc_color
,
701 static void decorate_compat_init( void ) {
704 const char *cursor_font_name
= "cursor";
705 xcb_font_t cursor_font
;
706 static const int cursor_glyphs
[ NUM_CURSORS
] = {
716 68, /* CURSOR_ARROW */
717 88 /* CURSOR_DESTROY */
720 cursor_font
= xcb_generate_id( c
);
721 xcb_open_font( c
, cursor_font
, strlen( cursor_font_name
),
723 for( i
= 0; i
< NUM_CURSORS
; i
++ ) {
724 cursors
[ i
] = xcb_generate_id( c
);
725 xcb_create_glyph_cursor( c
, cursors
[ i
], cursor_font
, cursor_font
,
726 cursor_glyphs
[ i
], cursor_glyphs
[ i
] | 1,
727 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF );
729 xcb_close_font( c
, cursor_font
);
731 /* Retrieve any RGB_DEFAULT_MAP properties on the roots. */
732 for( i
= 0; i
< num_screens
; i
++ ) {
733 union callback_param cp
;
736 handle_async_reply( xcb_get_property( c
, FALSE
, screens
[ i
]->root
,
737 RGB_DEFAULT_MAP
, RGB_COLOR_MAP
,
738 0, 0x10000 ).sequence
,
739 handle_get_default_map
, cp
);
743 extern void decorate_render_init( void ) {
746 FcFontSet
*sets
[ NUM_STYLES
];
747 FcPattern
*style_pats
[ NUM_STYLES
];
755 fatal( "font configuration error" );
757 if( ( err
= FT_Init_FreeType( &ftl
) ) )
758 fatal( "typeface initialisation error %d", err
);
760 for( i
= 0, total
= 0; i
< NUM_STYLES
; i
++ ) {
761 if( !( style_pats
[ i
] = FcNameParse( style_names
[ i
] ) ) )
762 fatal( "could not parse font \"%s\"\n", style_names
[ i
] );
764 FcConfigSubstitute( NULL
, style_pats
[ i
], FcMatchPattern
);
765 FcDefaultSubstitute( style_pats
[ i
] );
767 sets
[ i
] = FcFontSort( NULL
, style_pats
[ i
], TRUE
,
768 &styles
[ i
].charset
, &r
);
770 total
+= sets
[ i
]->nfont
;
773 fonts
= xmalloc( total
* sizeof *fonts
);
774 hashes
= alloca( total
* sizeof *hashes
);
776 for( i
= 0; i
< NUM_STYLES
; i
++ ) {
779 styles
[ i
].fonts
= xmalloc( sets
[ i
]->nfont
*
780 sizeof (struct font
*) );
782 for( j
= 0; j
< sets
[ i
]->nfont
; j
++ ) {
785 if( ( pat
= FcFontRenderPrepare( NULL
, style_pats
[ i
],
786 sets
[ i
]->fonts
[ j
] ) ) ) {
787 FcChar32 hash
= FcPatternHash( pat
);
790 for( search
= 0; search
< num_fonts
; search
++ )
791 if( hashes
[ search
] == hash
&&
792 FcPatternEqual( fonts
[ search
].pattern
, pat
) ) {
793 FcPatternDestroy( pat
);
797 if( search
== num_fonts
) {
798 hashes
[ num_fonts
] = hash
;
799 fonts
[ num_fonts
].pattern
= pat
;
800 FcPatternGetCharSet( pat
, FC_CHARSET
, 0,
801 &fonts
[ num_fonts
].charset
);
802 fonts
[ num_fonts
].face
= NULL
;
806 styles
[ i
].fonts
[ styles
[ i
].num_fonts
] = search
;
807 styles
[ i
].num_fonts
++;
811 styles
[ i
].fonts
= xrealloc( styles
[ i
].fonts
,
812 styles
[ i
].num_fonts
*
813 sizeof (struct font
*) );
815 FcFontSetDestroy( sets
[ i
] );
816 FcPatternDestroy( style_pats
[ i
] );
819 fonts
= xrealloc( fonts
, num_fonts
* sizeof *fonts
);
821 glyphset
= xcb_generate_id( c
);
822 xcb_render_create_glyph_set( c
, glyphset
, fmt_a8
);
824 pixmap
= xcb_generate_id( c
);
826 pictures
= xmalloc( num_screens
* sizeof *pictures
);
828 n
= XCB_RENDER_REPEAT_NORMAL
;
829 for( i
= 0; i
< num_screens
; i
++ ) {
830 xcb_create_pixmap( c
, screens
[ i
]->root_depth
, pixmap
,
831 screens
[ i
]->root
, 1, 1 );
833 pictures
[ i
].pic
= xcb_generate_id( c
);
834 xcb_render_create_picture( c
, pictures
[ i
].pic
, pixmap
,
835 gwm_screens
[ i
].root_pictformat
,
836 XCB_RENDER_CP_REPEAT
, &n
);
837 pictures
[ i
].col
= -1;
839 xcb_free_pixmap( c
, pixmap
);
842 decorate_compat_init(); /* FIXME this is for pixel values (backgrounds)
846 extern void decorate_render_done( void ) {
851 for( i
= 0; i
< NUM_STYLES
; i
++ ) {
852 FcCharSetDestroy( styles
[ i
].charset
);
853 free( styles
[ i
].fonts
);
856 for( i
= 0; i
< num_fonts
; i
++ ) {
857 FcPatternDestroy( fonts
[ i
].pattern
);
858 FT_Done_Face( fonts
[ i
].face
);
865 FT_Done_FreeType( ftl
);