File indexing completed on 2024-04-28 16:55:26

0001 /*
0002  * Copyright © 2006 Novell, Inc.
0003  *
0004  * This program is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU General Public License
0006  * as published by the Free Software Foundation; either version 2
0007  * of the License, or (at your option) any later version.
0008  *
0009  * This program is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  * GNU General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU General Public License
0015  * along with this program; if not, write to the Free Software
0016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0017  *
0018  */
0019 
0020 #define NEED_BUTTON_BISTATES
0021 #define NEED_BUTTON_STATE_FLAGS
0022 #define NEED_BUTTON_ACTIONS
0023 #define NEED_BUTTON_FILE_NAMES
0024 #include <emerald.h>
0025 #include <engine.h>
0026 
0027 extern gboolean load_engine(gchar *, window_settings *);
0028 extern void load_engine_settings(GKeyFile *, window_settings *);
0029 extern int update_shadow(frame_settings *);
0030 
0031 #define C(name) { 0, XC_ ## name }
0032 #define BUTTON_NOT_VISIBLE(ddd, xxx) \
0033     ((ddd)->tobj_item_state[(xxx)] == 3 || !((ddd)->actions & button_actions[(xxx)]))
0034 
0035 //static gboolean enable_tooltips = TRUE;
0036 
0037 static gint get_b_offset(gint b)
0038 {
0039     int boffset[B_COUNT+1];
0040     gint i, b_t = 0;
0041 
0042     for (i = 0; i < B_COUNT; i++)
0043     {
0044         boffset[i] = b_t;
0045         if (btbistate[b_t])
0046         {
0047             boffset[i+1] = b_t;
0048             i++;
0049         }
0050         b_t++;
0051     }
0052     return boffset[b];
0053 }
0054 
0055 static gint get_b_t_offset(gint b_t)
0056 {
0057     int btoffset[B_T_COUNT];
0058     gint i, b = 0;
0059 
0060     for (i = 0; i < B_T_COUNT; i++)
0061     {
0062         btoffset[i] = b;
0063         b++;
0064         if (btbistate[i])
0065             b++;
0066     }
0067     return btoffset[b_t];
0068 }
0069 #if 0 /* ************************ */
0070 //window_settings *global_ws;
0071 static gint get_real_pos(window_settings * ws, gint tobj, decor_t * d)
0072 {
0073     switch (d->tobj_item_state[tobj])
0074     {
0075         case 1:
0076             return ((d->width + ws->left_space - ws->right_space +
0077                      d->tobj_size[0] - d->tobj_size[1] - d->tobj_size[2]) / 2 +
0078                     d->tobj_item_pos[tobj]);
0079         case 2:
0080             return (d->width - ws->right_space - d->tobj_size[2] +
0081                     d->tobj_item_pos[tobj]);
0082         case 3:
0083             return -1;
0084         default:
0085             return (ws->left_space + d->tobj_item_pos[tobj]);
0086     }
0087 }
0088 #endif
0089 static void update_window_extents(window_settings * ws)
0090 {
0091     //where 4 is v_corn_rad (8 is 2*4), 6 is...?
0092     // 0,       0,          L_EXT+4,    TT_H+4,     0,0,0,0
0093     // L_EXT+4  0,          -8,         T_EXT+2,    0,0,1,0
0094     // L_EXT-4, 0,          R_EXT+4,    TT_H+4,     1,0,0,0
0095     // 0,       T_EXT+6,    L_EXT,      TT_H-6,     0,0,0,1
0096     // L_EXT,   T_EXT+2,    0,          TT_H-2,     0,0,1,0
0097     // L_EXT,   T_EXT+6,    R_EXT,      TT_H-6,     1,0,0,1
0098     // 0,       TT_H,       L_EXT+4,    B_EXT+4,    0,1,0,0
0099     // L_EXT+4, TT_H+4,     -8,         B_EXT,      0,1,1,0
0100     // L_EXT-4, TT_H,       R_EXT+4,    B_EXT+4,    1,1,0,0
0101     gint l_ext = ws->win_extents.left;
0102     gint r_ext = ws->win_extents.right;
0103     gint t_ext = ws->win_extents.top;
0104     gint b_ext = ws->win_extents.bottom;
0105     gint tt_h = ws->titlebar_height;
0106 
0107     /*pos_t newpos[3][3] = {
0108       {
0109       {  0,  0, 10, 21,   0, 0, 0, 0 },
0110       { 10,  0, -8,  6,   0, 0, 1, 0 },
0111       {  2,  0, 10, 21,   1, 0, 0, 0 }
0112       }, {
0113       {  0, 10,  6, 11,   0, 0, 0, 1 },
0114       {  6,  6,  0, 15,   0, 0, 1, 0 },
0115       {  6, 10,  6, 11,   1, 0, 0, 1 }
0116       }, {
0117       {  0, 17, 10, 10,   0, 1, 0, 0 },
0118       { 10, 21, -8,  6,   0, 1, 1, 0 },
0119       {  2, 17, 10, 10,   1, 1, 0, 0 }
0120       }
0121       }; */
0122     pos_t newpos[3][3] = { {
0123         {0, 0, l_ext + 4, tt_h + 4, 0, 0, 0, 0},
0124             {l_ext + 4, 0, -8, t_ext + 2, 0, 0, 1, 0},
0125             {l_ext - 4, 0, r_ext + 4, tt_h + 4, 1, 0, 0, 0}
0126     }, {
0127         {0, t_ext + 6, l_ext, tt_h - 6, 0, 0, 0, 1},
0128             {l_ext, t_ext + 2, 0, tt_h - 2, 0, 0, 1, 0},
0129             {l_ext, t_ext + 6, r_ext, tt_h - 6, 1, 0, 0, 1}
0130     }, {
0131         {0, tt_h, l_ext + 4, b_ext + 4, 0, 1, 0,
0132             0},
0133             {l_ext + 4, tt_h + 4, -8, b_ext, 0, 1, 1,
0134                 0},
0135             {l_ext - 4, tt_h, r_ext + 4, b_ext + 4, 1,
0136                 1, 0, 0}
0137     }
0138     };
0139     memcpy(ws->pos, newpos, sizeof(pos_t) * 9);
0140 }
0141 #if 0
0142 static void
0143 gdk_cairo_set_source_color_alpha(cairo_t * cr, GdkColor * color, double alpha)
0144 {
0145     cairo_set_source_rgba(cr,
0146                           color->red / 65535.0,
0147                           color->green / 65535.0,
0148                           color->blue / 65535.0, alpha);
0149 }
0150 
0151 static void draw_shadow_background(decor_t * d, cairo_t * cr)
0152 {
0153     cairo_matrix_t matrix;
0154     double w, h, x2, y2;
0155     gint width, height;
0156     gint left, right, top, bottom;
0157     window_settings *ws = d->fs->ws;
0158 
0159     if (!ws->large_shadow_pixmap)
0160     {
0161         cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
0162         cairo_paint(cr);
0163 
0164         return;
0165     }
0166 
0167     gdk_drawable_get_size(ws->large_shadow_pixmap, &width, &height);
0168 
0169     left = ws->left_space + ws->left_corner_space;
0170     right = ws->right_space + ws->right_corner_space;
0171     top = ws->top_space + ws->top_corner_space;
0172     bottom = ws->bottom_space + ws->bottom_corner_space;
0173 
0174     if (d->width - left - right < 0)
0175     {
0176         left = d->width / 2;
0177         right = d->width - left;
0178     }
0179 
0180     if (d->height - top - bottom < 0)
0181     {
0182         top = d->height / 2;
0183         bottom = d->height - top;
0184     }
0185 
0186     w = d->width - left - right;
0187     h = d->height - top - bottom;
0188 
0189     x2 = d->width - right;
0190     y2 = d->height - bottom;
0191 
0192     /* top left */
0193     cairo_matrix_init_identity(&matrix);
0194     cairo_pattern_set_matrix(ws->shadow_pattern, &matrix);
0195     cairo_set_source(cr, ws->shadow_pattern);
0196     cairo_rectangle(cr, 0.0, 0.0, left, top);
0197     cairo_fill(cr);
0198 
0199     /* top */
0200     if (w > 0)
0201     {
0202         cairo_matrix_init_translate(&matrix, left, 0.0);
0203         cairo_matrix_scale(&matrix, 1.0 / w, 1.0);
0204         cairo_matrix_translate(&matrix, -left, 0.0);
0205         cairo_pattern_set_matrix(ws->shadow_pattern, &matrix);
0206         cairo_set_source(cr, ws->shadow_pattern);
0207         cairo_rectangle(cr, left, 0.0, w, top);
0208         cairo_fill(cr);
0209     }
0210 
0211     /* top right */
0212     cairo_matrix_init_translate(&matrix, width - right - x2, 0.0);
0213     cairo_pattern_set_matrix(ws->shadow_pattern, &matrix);
0214     cairo_set_source(cr, ws->shadow_pattern);
0215     cairo_rectangle(cr, x2, 0.0, right, top);
0216     cairo_fill(cr);
0217 
0218     /* left */
0219     if (h > 0)
0220     {
0221         cairo_matrix_init_translate(&matrix, 0.0, top);
0222         cairo_matrix_scale(&matrix, 1.0, 1.0 / h);
0223         cairo_matrix_translate(&matrix, 0.0, -top);
0224         cairo_pattern_set_matrix(ws->shadow_pattern, &matrix);
0225         cairo_set_source(cr, ws->shadow_pattern);
0226         cairo_rectangle(cr, 0.0, top, left, h);
0227         cairo_fill(cr);
0228     }
0229 
0230     /* right */
0231     if (h > 0)
0232     {
0233         cairo_matrix_init_translate(&matrix, width - right - x2, top);
0234         cairo_matrix_scale(&matrix, 1.0, 1.0 / h);
0235         cairo_matrix_translate(&matrix, 0.0, -top);
0236         cairo_pattern_set_matrix(ws->shadow_pattern, &matrix);
0237         cairo_set_source(cr, ws->shadow_pattern);
0238         cairo_rectangle(cr, x2, top, right, h);
0239         cairo_fill(cr);
0240     }
0241 
0242     /* bottom left */
0243     cairo_matrix_init_translate(&matrix, 0.0, height - bottom - y2);
0244     cairo_pattern_set_matrix(ws->shadow_pattern, &matrix);
0245     cairo_set_source(cr, ws->shadow_pattern);
0246     cairo_rectangle(cr, 0.0, y2, left, bottom);
0247     cairo_fill(cr);
0248 
0249     /* bottom */
0250     if (w > 0)
0251     {
0252         cairo_matrix_init_translate(&matrix, left, height - bottom - y2);
0253         cairo_matrix_scale(&matrix, 1.0 / w, 1.0);
0254         cairo_matrix_translate(&matrix, -left, 0.0);
0255         cairo_pattern_set_matrix(ws->shadow_pattern, &matrix);
0256         cairo_set_source(cr, ws->shadow_pattern);
0257         cairo_rectangle(cr, left, y2, w, bottom);
0258         cairo_fill(cr);
0259     }
0260 
0261     /* bottom right */
0262     cairo_matrix_init_translate(&matrix, width - right - x2,
0263                                 height - bottom - y2);
0264     cairo_pattern_set_matrix(ws->shadow_pattern, &matrix);
0265     cairo_set_source(cr, ws->shadow_pattern);
0266     cairo_rectangle(cr, x2, y2, right, bottom);
0267     cairo_fill(cr);
0268 }
0269 #endif
0270 
0271 static void draw_help_button(decor_t * d, cairo_t * cr, double s)
0272 {
0273     cairo_rel_move_to(cr, 0.0, 6.0);
0274     cairo_rel_line_to(cr, 0.0, 3.0);
0275     cairo_rel_line_to(cr, 4.5, 0.0);
0276     cairo_rel_line_to(cr, 0.0, 4.5);
0277     cairo_rel_line_to(cr, 3.0, 0.0);
0278     cairo_rel_line_to(cr, 0.0, -4.5);
0279 
0280     cairo_rel_line_to(cr, 4.5, 0.0);
0281 
0282     cairo_rel_line_to(cr, 0.0, -3.0);
0283     cairo_rel_line_to(cr, -4.5, 0.0);
0284     cairo_rel_line_to(cr, 0.0, -4.5);
0285     cairo_rel_line_to(cr, -3.0, 0.0);
0286     cairo_rel_line_to(cr, 0.0, 4.5);
0287 
0288     cairo_close_path(cr);
0289 }
0290 static void draw_close_button(decor_t * d, cairo_t * cr, double s)
0291 {
0292     cairo_rel_move_to(cr, 0.0, s);
0293 
0294     cairo_rel_line_to(cr, s, -s);
0295     cairo_rel_line_to(cr, s, s);
0296     cairo_rel_line_to(cr, s, -s);
0297     cairo_rel_line_to(cr, s, s);
0298 
0299     cairo_rel_line_to(cr, -s, s);
0300     cairo_rel_line_to(cr, s, s);
0301     cairo_rel_line_to(cr, -s, s);
0302     cairo_rel_line_to(cr, -s, -s);
0303 
0304     cairo_rel_line_to(cr, -s, s);
0305     cairo_rel_line_to(cr, -s, -s);
0306     cairo_rel_line_to(cr, s, -s);
0307 
0308     cairo_close_path(cr);
0309 }
0310 
0311 static void draw_max_button(decor_t * d, cairo_t * cr, double s)
0312 {
0313     cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
0314 
0315     cairo_rel_line_to(cr, 12.0, 0.0);
0316     cairo_rel_line_to(cr, 0.0, 12.0);
0317     cairo_rel_line_to(cr, -12.0, 0.0);
0318 
0319     cairo_close_path(cr);
0320 
0321     cairo_rel_move_to(cr, 2.0, s);
0322 
0323     cairo_rel_line_to(cr, 8.0, 0.0);
0324     cairo_rel_line_to(cr, 0.0, 10.0 - s);
0325     cairo_rel_line_to(cr, -8.0, 0.0);
0326 
0327     cairo_close_path(cr);
0328 }
0329 
0330 static void draw_unmax_button(decor_t * d, cairo_t * cr, double s)
0331 {
0332     cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
0333 
0334     cairo_rel_move_to(cr, 1.0, 1.0);
0335 
0336     cairo_rel_line_to(cr, 10.0, 0.0);
0337     cairo_rel_line_to(cr, 0.0, 10.0);
0338     cairo_rel_line_to(cr, -10.0, 0.0);
0339 
0340     cairo_close_path(cr);
0341 
0342     cairo_rel_move_to(cr, 2.0, s);
0343 
0344     cairo_rel_line_to(cr, 6.0, 0.0);
0345     cairo_rel_line_to(cr, 0.0, 8.0 - s);
0346     cairo_rel_line_to(cr, -6.0, 0.0);
0347 
0348     cairo_close_path(cr);
0349 }
0350 
0351 static void draw_min_button(decor_t * d, cairo_t * cr, double s)
0352 {
0353     cairo_rel_move_to(cr, 0.0, 8.0);
0354 
0355     cairo_rel_line_to(cr, 12.0, 0.0);
0356     cairo_rel_line_to(cr, 0.0, s);
0357     cairo_rel_line_to(cr, -12.0, 0.0);
0358 
0359     cairo_close_path(cr);
0360 }
0361 #if 0
0362 typedef void (*draw_proc) (cairo_t * cr);
0363 static void
0364 get_button_pos(window_settings * ws, gint b_t,
0365                decor_t * d, gdouble y1, gdouble * rx, gdouble * ry)
0366 {
0367     //y1 - 4.0 + ws->titlebar_height / 2,
0368     *ry = y1 + ws->button_offset;
0369     *rx = get_real_pos(ws, b_t, d);
0370 }
0371 #endif
0372 static void
0373 button_state_paint(cairo_t * cr,
0374                    alpha_color * color, alpha_color * color_2, guint state)
0375 {
0376     double alpha;
0377 
0378     if (state & IN_EVENT_WINDOW)
0379         alpha = 1.0;
0380     else
0381         alpha = color->alpha;
0382 
0383     if ((state & (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
0384         == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
0385     {
0386         cairo_set_source_rgba(cr, color->color.r, color->color.g,
0387                               color->color.b, alpha);
0388 
0389         cairo_fill_preserve(cr);
0390 
0391         cairo_set_source_alpha_color(cr, color_2);
0392 
0393         cairo_set_line_width(cr, 1.0);
0394         cairo_stroke(cr);
0395         cairo_set_line_width(cr, 2.0);
0396     }
0397     else
0398     {
0399         cairo_set_source_alpha_color(cr, color_2);
0400         cairo_stroke_preserve(cr);
0401 
0402         cairo_set_source_rgba(cr, color->color.r, color->color.g,
0403                               color->color.b, alpha);
0404 
0405         cairo_fill(cr);
0406     }
0407 }
0408 static int get_b_state(decor_t * d, int button)
0409 {
0410     int ret = d->active ? 0 : 3;
0411 
0412     if (d->button_states[button] & IN_EVENT_WINDOW)
0413     {
0414         ret++;
0415         if (d->button_states[button] & PRESSED_EVENT_WINDOW)
0416             ret++;
0417     }
0418     return ret;
0419 }
0420 static void
0421 draw_pixbuf(GdkPixbuf * pixbuf, cairo_t * cr,
0422             gdouble x, gdouble y, gdouble x2, gdouble y2, gdouble alpha)
0423 {
0424 #if 0
0425     cairo_save(cr);
0426     cairo_rectangle(cr, x, y, x2-x, y2-y);
0427     cairo_clip(cr);
0428     gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
0429     cairo_paint_with_alpha(cr, alpha);
0430     cairo_restore(cr);
0431 #endif
0432 }
0433 void
0434 draw_button_with_glow_alpha_bstate(gint b_t, decor_t * d, cairo_t * cr,
0435                                    gint y1, gdouble button_alpha,
0436                                    gdouble glow_alpha, int b_state)
0437 {
0438     gint b = b_t;
0439     gdouble x, y;
0440     gdouble x2, y2;
0441     gdouble glow_x, glow_y;             // glow top left coordinates
0442     gdouble glow_x2, glow_y2;   // glow bottom right coordinates
0443     window_settings *ws = d->fs->ws;
0444 
0445 #if 0
0446     if (b_state < 0)
0447         b_state = get_b_state(d, b_t);
0448 
0449     b = get_b_t_offset(b_t);
0450 
0451     if (btbistate[b_t])
0452         if (d->state & btstateflag[b_t])
0453             b++;
0454 
0455     if (BUTTON_NOT_VISIBLE(d, b_t))
0456         return;
0457 #endif
0458     button_region_t *button_region =
0459         (d->active ? &d->button_region[b_t] : &d->
0460          button_region_inact[b_t]);
0461     x = button_region->base_x1;
0462     y = button_region->base_y1;
0463 
0464     if (ws->use_pixmap_buttons)
0465     {
0466         x2 = button_region->base_x2;
0467         y2 = button_region->base_y2;
0468         draw_pixbuf(ws->ButtonPix[b_state + b * S_COUNT], cr, x, y, x2, y2,
0469                     button_alpha);
0470 
0471         if (glow_alpha > 1e-5)  // i.e. glow is on
0472         {
0473             glow_x = button_region->glow_x1;
0474             glow_y = button_region->glow_y1;
0475             glow_x2 = button_region->glow_x2;
0476             glow_y2 = button_region->glow_y2;
0477             if (d->active)
0478             {                                   // Draw glow
0479                 draw_pixbuf(ws->ButtonGlowPix[b], cr, glow_x, glow_y, glow_x2,
0480                             glow_y2, glow_alpha);
0481             }
0482             else                                // assume this function won't be called with glow_alpha>0
0483             {                                   // if ws->use_inactive_glow is false
0484                 // Draw inactive glow
0485                 draw_pixbuf(ws->ButtonInactiveGlowPix[b], cr, glow_x, glow_y,
0486                             glow_x2, glow_y2, glow_alpha);
0487             }
0488         }
0489     }
0490     else
0491     {
0492         y += 3;
0493         x += 1;
0494         cairo_set_line_width(cr, 2.0);
0495         cairo_move_to(cr, x, y);
0496         switch (b)
0497         {
0498             case B_CLOSE:
0499                 draw_close_button(d, cr, 3.1);
0500                 break;
0501             case B_MAXIMIZE:
0502                 draw_max_button(d, cr, 4.0);
0503                 break;
0504             case B_RESTORE:
0505                 draw_unmax_button(d, cr, 4.0);
0506                 break;
0507             case B_MINIMIZE:
0508                 draw_min_button(d, cr, 4.0);
0509                 break;
0510             case B_HELP:
0511                 cairo_move_to(cr, x, y);
0512                 draw_help_button(d, cr, 3.1);
0513                 break;
0514             default:
0515                 //FIXME - do something here
0516                 break;
0517         }
0518         button_state_paint(cr, &d->fs->button, &d->fs->button_halo,
0519                            b_state);
0520     }
0521 }
0522 #if 0
0523 static void
0524 draw_button_with_glow(gint b_t, decor_t * d, cairo_t * cr, gint y1,
0525                       gboolean with_glow)
0526 {
0527     draw_button_with_glow_alpha_bstate(b_t, d, cr, y1, 1.0,
0528                                        (with_glow ? 1.0 : 0.0), -1);
0529 }
0530 static void draw_button(gint b_t, decor_t * d, cairo_t * cr, gint y1)
0531 {
0532     draw_button_with_glow_alpha_bstate(b_t, d, cr, y1, 1.0, 0.0, -1);
0533 }
0534 static void reset_buttons_bg_and_fade(decor_t * d)
0535 {
0536     d->draw_only_buttons_region = FALSE;
0537     d->button_fade_info.cr = NULL;
0538     d->button_fade_info.timer = -1;
0539     int b_t;
0540 
0541     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0542     {
0543         d->button_fade_info.counters[b_t] = 0;
0544         d->button_fade_info.pulsating[b_t] = 0;
0545         d->button_region[b_t].base_x1 = -100;
0546         d->button_region[b_t].glow_x1 = -100;
0547         if (d->button_region[b_t].bg_pixmap)
0548             g_object_unref (G_OBJECT (d->button_region[b_t].bg_pixmap));
0549         d->button_region[b_t].bg_pixmap = NULL;
0550         d->button_region_inact[b_t].base_x1 = -100;
0551         d->button_region_inact[b_t].glow_x1 = -100;
0552         if (d->button_region_inact[b_t].bg_pixmap)
0553             g_object_unref (G_OBJECT (d->button_region_inact[b_t].bg_pixmap));
0554         d->button_region_inact[b_t].bg_pixmap = NULL;
0555         d->button_last_drawn_state[b_t] = 0;
0556     }
0557 }
0558 static void stop_button_fade(decor_t * d)
0559 {
0560     int j;
0561 
0562     if (d->button_fade_info.cr)
0563     {
0564         cairo_destroy(d->button_fade_info.cr);
0565         d->button_fade_info.cr = NULL;
0566     }
0567     if (d->button_fade_info.timer >= 0)
0568     {
0569         g_source_remove(d->button_fade_info.timer);
0570         d->button_fade_info.timer = -1;
0571     }
0572     for (j = 0; j < B_T_COUNT; j++)
0573         d->button_fade_info.counters[j] = 0;
0574 }
0575 static void draw_button_backgrounds(decor_t * d, int *necessary_update_type)
0576 {
0577     int b_t;
0578     window_settings *ws = d->fs->ws;
0579 
0580     // Draw button backgrounds
0581     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0582     {
0583         if (BUTTON_NOT_VISIBLE(d, b_t))
0584             continue;
0585         button_region_t *button_region = (d->active ? &d->button_region[b_t] :
0586                                           &d->button_region_inact[b_t]);
0587         gint src_x = 0, src_y = 0, w = 0, h = 0, dest_x = 0, dest_y = 0;
0588 
0589         if (necessary_update_type[b_t] == 1)
0590         {
0591             w = button_region->base_x2 - button_region->base_x1;
0592             h = button_region->base_y2 - button_region->base_y1;
0593             if (ws->use_pixmap_buttons)
0594             {
0595                 dest_x = button_region->base_x1;
0596                 dest_y = button_region->base_y1;
0597                 if ((ws->use_button_glow && d->active) ||
0598                     (ws->use_button_inactive_glow && !d->active))
0599                 {
0600                     src_x = button_region->base_x1 - button_region->glow_x1;
0601                     src_y = button_region->base_y1 - button_region->glow_y1;
0602                 }
0603             }
0604             else
0605             {
0606                 dest_x = button_region->base_x1 - 2;
0607                 dest_y = button_region->base_y1 + 1;
0608             }
0609         }
0610         else if (necessary_update_type[b_t] == 2)
0611         {
0612             dest_x = button_region->glow_x1;
0613             dest_y = button_region->glow_y1;
0614             w = button_region->glow_x2 - button_region->glow_x1;
0615             h = button_region->glow_y2 - button_region->glow_y1;
0616         }
0617         else
0618             return;
0619         if (button_region->bg_pixmap)
0620             gdk_draw_drawable(IS_VALID(d->buffer_pixmap) ? d->buffer_pixmap :
0621                                                            d->pixmap,
0622                               d->gc, button_region->bg_pixmap, src_x, src_y,
0623                               dest_x, dest_y, w, h);
0624         d->min_drawn_buttons_region.x1 =
0625             MIN(d->min_drawn_buttons_region.x1, dest_x);
0626         d->min_drawn_buttons_region.y1 =
0627             MIN(d->min_drawn_buttons_region.y1, dest_y);
0628         d->min_drawn_buttons_region.x2 =
0629             MAX(d->min_drawn_buttons_region.x2, dest_x + w);
0630         d->min_drawn_buttons_region.y2 =
0631             MAX(d->min_drawn_buttons_region.y2, dest_y + h);
0632     }
0633 }
0634 
0635 gint draw_buttons_timer_func(gpointer data)
0636 {
0637     button_fade_info_t *fade_info = (button_fade_info_t *) data;
0638     decor_t *d = (decor_t *) (fade_info->d);
0639     window_settings *ws = d->fs->ws;
0640     int num_steps = ws->button_fade_num_steps;
0641 
0642     /* decorations no longer available? */
0643     if (!d->buffer_pixmap && !d->pixmap)
0644     {
0645         stop_button_fade(d);
0646         return FALSE;
0647     }
0648 
0649     d->min_drawn_buttons_region.x1 = 10000;
0650     d->min_drawn_buttons_region.y1 = 10000;
0651     d->min_drawn_buttons_region.x2 = -100;
0652     d->min_drawn_buttons_region.y2 = -100;
0653 
0654     if (!fade_info->cr)
0655     {
0656         fade_info->cr =
0657             gdk_cairo_create(GDK_DRAWABLE
0658                              (IS_VALID(d->buffer_pixmap) ? d->buffer_pixmap :
0659                                                            d->pixmap));
0660         cairo_set_operator(fade_info->cr, CAIRO_OPERATOR_OVER);
0661     }
0662 
0663     // Determine necessary updates
0664     int b_t;
0665     int necessary_update_type[B_T_COUNT];       // 0: none, 1: only base, 2: base+glow
0666 
0667     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0668         necessary_update_type[b_t] = (ws->use_button_glow && d->active) ||
0669             (ws->use_button_inactive_glow && !d->active) ? 2:1;
0670     draw_button_backgrounds(d, necessary_update_type);
0671 
0672     // Draw the buttons that are in "non-hovered" or pressed state
0673     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0674     {
0675         if (BUTTON_NOT_VISIBLE(d, b_t) || fade_info->counters[b_t] ||
0676             necessary_update_type[b_t] == 0)
0677             continue;
0678         int b_state = get_b_state(d, b_t);
0679         int toBeDrawnState =
0680             (d->
0681              active ? (b_state == S_ACTIVE_PRESS ? 2 : 0) : (b_state ==
0682                                                              S_INACTIVE_PRESS
0683                                                              ? 5 : 3));
0684         draw_button_with_glow_alpha_bstate(b_t, d, fade_info->cr, fade_info->y1, 1.0, 0.0, toBeDrawnState);     // no glow here
0685     }
0686 
0687     // Draw the buttons that are in "hovered" state (fading in/out or at max fade)
0688     double button_alphas[B_T_COUNT];
0689 
0690     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0691     {
0692         button_alphas[b_t] = 0;
0693         if (BUTTON_NOT_VISIBLE(d, b_t) ||
0694             (!fade_info->pulsating[b_t] && !fade_info->counters[b_t]))
0695             continue;
0696 
0697         if (ws->button_fade_pulse_len_steps > 0 && fade_info->counters[b_t] &&
0698             fade_info->pulsating[b_t])
0699         {
0700             // If it is time, reverse the fade
0701             if (fade_info->counters[b_t] ==
0702                 -num_steps + ws->button_fade_pulse_len_steps)
0703                 fade_info->counters[b_t] = 1 - fade_info->counters[b_t];
0704             if (fade_info->counters[b_t] ==
0705                 num_steps + 1 + ws->button_fade_pulse_wait_steps)
0706                 fade_info->counters[b_t] =
0707                     1 - MIN(fade_info->counters[b_t], num_steps + 1);
0708         }
0709         if (ws->button_fade_pulse_len_steps > 0 &&
0710             fade_info->counters[b_t] == num_steps)
0711             fade_info->pulsating[b_t] = TRUE;   // start pulse
0712 
0713         if (fade_info->counters[b_t] != num_steps + 1 ||        // unless fade is at max
0714             (ws->button_fade_pulse_len_steps > 0 &&     // or at pulse max
0715              fade_info->counters[b_t] !=
0716              num_steps + 1 + ws->button_fade_pulse_wait_steps))
0717         {
0718             fade_info->counters[b_t]++; // increment fade counter
0719         }
0720         d->button_last_drawn_state[b_t] = fade_info->counters[b_t];
0721 
0722         gdouble alpha;
0723 
0724         if (fade_info->counters[b_t] > 0)
0725             alpha = (MIN(fade_info->counters[b_t], num_steps + 1) -
0726                      1) / (gdouble) num_steps;
0727         else
0728             alpha = -fade_info->counters[b_t] / (gdouble) num_steps;
0729 
0730         if (fade_info->counters[b_t] < num_steps + 1)   // not at max fade
0731         {
0732             // Draw button's non-hovered version (with 1-alpha)
0733             draw_button_with_glow_alpha_bstate(b_t, d, fade_info->cr,
0734                                                fade_info->y1, pow(1 - alpha,
0735                                                                   0.4), 0.0,
0736                                                d->active ? 0 : 3);
0737         }
0738         button_alphas[b_t] = alpha;
0739     }
0740     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0741     {
0742         if (button_alphas[b_t] > 1e-4)
0743         {
0744             gdouble glow_alpha = 0.0;
0745 
0746             if ((ws->use_button_glow && d->active) ||
0747                 (ws->use_button_inactive_glow && !d->active))
0748                 glow_alpha = button_alphas[b_t];
0749 
0750             // Draw button's hovered version (with alpha)
0751             draw_button_with_glow_alpha_bstate(b_t, d, fade_info->cr,
0752                                                fade_info->y1,
0753                                                button_alphas[b_t], glow_alpha,
0754                                                d->active ? 1 : 4);
0755         }
0756     }
0757 
0758     // Check if the fade has come to an end
0759     gboolean any_active_buttons = FALSE;
0760 
0761     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0762         if (!BUTTON_NOT_VISIBLE(d, b_t) &&
0763             ((fade_info->counters[b_t] &&
0764               fade_info->counters[b_t] < num_steps + 1) ||
0765              fade_info->pulsating[b_t]))
0766         {
0767             any_active_buttons = TRUE;
0768             break;
0769         }
0770 
0771     if (IS_VALID(d->buffer_pixmap) && !d->button_fade_info.first_draw &&
0772         d->min_drawn_buttons_region.x1 < 10000)
0773     {
0774         // if region is updated at least once
0775         gdk_draw_drawable(d->pixmap,
0776                           d->gc,
0777                           d->buffer_pixmap,
0778                           d->min_drawn_buttons_region.x1,
0779                           d->min_drawn_buttons_region.y1,
0780                           d->min_drawn_buttons_region.x1,
0781                           d->min_drawn_buttons_region.y1,
0782                           d->min_drawn_buttons_region.x2 -
0783                           d->min_drawn_buttons_region.x1,
0784                           d->min_drawn_buttons_region.y2 -
0785                           d->min_drawn_buttons_region.y1);
0786     }
0787     fade_info->first_draw = FALSE;
0788     if (!any_active_buttons)
0789     {
0790         cairo_destroy(fade_info->cr);
0791         fade_info->cr = NULL;
0792         if (fade_info->timer >= 0)
0793         {
0794             g_source_remove(fade_info->timer);
0795             fade_info->timer = -1;
0796         }
0797         return FALSE;
0798     }
0799     return TRUE;
0800 }
0801 static void draw_buttons_with_fade(decor_t * d, cairo_t * cr, double y1)
0802 {
0803     window_settings *ws = d->fs->ws;
0804     int b_t;
0805 
0806     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0807     {
0808         if (BUTTON_NOT_VISIBLE(d, b_t))
0809             continue;
0810         if (!(d->active ? d->button_region[b_t] : d->button_region_inact[b_t]).bg_pixmap)       // don't draw if bg_pixmaps are not valid
0811             return;
0812     }
0813     button_fade_info_t *fade_info = &(d->button_fade_info);
0814     gboolean button_pressed = FALSE;
0815 
0816     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0817     {
0818         if (BUTTON_NOT_VISIBLE(d, b_t))
0819             continue;
0820         int b_state = get_b_state(d, b_t);
0821 
0822         if (fade_info->counters[b_t] != 0 &&
0823             (b_state == S_ACTIVE_PRESS || b_state == S_INACTIVE_PRESS))
0824         {
0825             // Button pressed, stop fade
0826             fade_info->counters[b_t] = 0;
0827             button_pressed = TRUE;
0828         }
0829         else if (fade_info->counters[b_t] > 0 && (b_state == S_ACTIVE || b_state == S_INACTIVE))        // moved out
0830         {
0831             // Change fade in -> out and proceed 1 step
0832             fade_info->counters[b_t] =
0833                 1 - MIN(fade_info->counters[b_t],
0834                         ws->button_fade_num_steps + 1);
0835         }
0836         else if (fade_info->counters[b_t] < 0 &&
0837                  (b_state == S_ACTIVE_HOVER || b_state == S_INACTIVE_HOVER))
0838         {
0839             // Change fade out -> in and proceed 1 step
0840             fade_info->counters[b_t] = 1 - fade_info->counters[b_t];
0841         }
0842         else if (fade_info->counters[b_t] == 0 &&
0843                  (b_state == S_ACTIVE_HOVER || b_state == S_INACTIVE_HOVER))
0844         {
0845             // Start fade in
0846             fade_info->counters[b_t] = 1;
0847         }
0848         if (fade_info->pulsating[b_t] &&
0849             b_state != S_ACTIVE_HOVER && b_state != S_INACTIVE_HOVER)
0850         {
0851             // Stop pulse
0852             fade_info->pulsating[b_t] = FALSE;
0853         }
0854     }
0855 
0856     if (fade_info->timer == -1 || button_pressed)
0857         // button_pressed is needed because sometimes after a button is pressed,
0858         // this function is called twice, first with S_(IN)ACTIVE, then with S_(IN)ACTIVE_PRESS
0859         // where it should have been only once with S_(IN)ACTIVE_PRESS
0860     {
0861         fade_info->d = (gpointer) d;
0862         fade_info->y1 = y1;
0863         if (draw_buttons_timer_func((gpointer) fade_info) == TRUE)      // call once now
0864         {
0865             // and start a new timer for the next step
0866             fade_info->timer =
0867                 g_timeout_add(ws->button_fade_step_duration,
0868                               draw_buttons_timer_func,
0869                               (gpointer) fade_info);
0870         }
0871     }
0872 }
0873 static void draw_buttons_without_fade(decor_t * d, cairo_t * cr, double y1)
0874 {
0875     window_settings *ws = d->fs->ws;
0876 
0877     d->min_drawn_buttons_region.x1 = 10000;
0878     d->min_drawn_buttons_region.y1 = 10000;
0879     d->min_drawn_buttons_region.x2 = -100;
0880     d->min_drawn_buttons_region.y2 = -100;
0881 
0882     int b_t;
0883     int necessary_update_type[B_T_COUNT];       // 0: none, 1: only base, 2: base+glow
0884 
0885     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0886         necessary_update_type[b_t] = (ws->use_button_glow && d->active) ||
0887             (ws->use_button_inactive_glow && !d->active) ? 2:1;
0888     //necessary_update_type[b_t] = 2;
0889 
0890     draw_button_backgrounds(d, necessary_update_type);
0891 
0892     // Draw buttons
0893     gint button_hovered_on = -1;
0894 
0895     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0896     {
0897         if (necessary_update_type[b_t] == 0)
0898             continue;
0899         int b_state = get_b_state(d, b_t);
0900 
0901         if (ws->use_pixmap_buttons &&
0902             ((ws->use_button_glow && b_state == S_ACTIVE_HOVER) ||
0903              (ws->use_button_inactive_glow && b_state == S_INACTIVE_HOVER)))
0904         {
0905             // skip the one being hovered on, if any
0906             button_hovered_on = b_t;
0907         }
0908         else
0909             draw_button(b_t, d, cr, y1);
0910     }
0911     if (button_hovered_on >= 0)
0912     {
0913         // Draw the button and the glow for the button hovered on
0914         draw_button_with_glow(button_hovered_on, d, cr, y1, TRUE);
0915     }
0916 }
0917 static void update_button_regions(decor_t * d)
0918 {
0919     window_settings *ws = d->fs->ws;
0920     gint y1 = ws->top_space - ws->win_extents.top;
0921 
0922     gint b_t, b_t2;
0923     gdouble x, y;
0924     gdouble glow_x, glow_y;             // glow top left coordinates
0925 
0926     for (b_t = 0; b_t < B_T_COUNT; b_t++)
0927     {
0928         if (BUTTON_NOT_VISIBLE(d, b_t))
0929             continue;
0930         button_region_t *button_region = &(d->button_region[b_t]);
0931 
0932         if (button_region->bg_pixmap)
0933         {
0934             g_object_unref (G_OBJECT (button_region->bg_pixmap));
0935             button_region->bg_pixmap = NULL;
0936         }
0937         if (d->button_region_inact[b_t].bg_pixmap)
0938         {
0939             g_object_unref (G_OBJECT (d->button_region_inact[b_t].bg_pixmap));
0940             d->button_region_inact[b_t].bg_pixmap = NULL;
0941         }
0942         // Reset overlaps
0943         for (b_t2 = 0; b_t2 < b_t; b_t2++)
0944             if (!BUTTON_NOT_VISIBLE(d, b_t2))
0945                 d->button_region[b_t].overlap_buttons[b_t2] = FALSE;
0946         for (b_t2 = 0; b_t2 < b_t; b_t2++)
0947             if (!BUTTON_NOT_VISIBLE(d, b_t2))
0948                 d->button_region_inact[b_t].overlap_buttons[b_t2] = FALSE;
0949     }
0950     d->button_fade_info.first_draw = TRUE;
0951 
0952     if (ws->use_pixmap_buttons)
0953     {
0954         if ((d->active && ws->use_button_glow) ||
0955             (!d->active && ws->use_button_inactive_glow))
0956         {
0957             for (b_t = 0; b_t < B_T_COUNT; b_t++)
0958             {
0959                 if (BUTTON_NOT_VISIBLE(d, b_t))
0960                     continue;
0961                 get_button_pos(ws, b_t, d, y1, &x, &y);
0962                 button_region_t *button_region = &(d->button_region[b_t]);
0963 
0964                 glow_x = x - (ws->c_glow_size.w - ws->c_icon_size[b_t].w) / 2;
0965                 glow_y = y - (ws->c_glow_size.h - ws->c_icon_size[b_t].h) / 2;
0966 
0967                 button_region->base_x1 = x;
0968                 button_region->base_y1 = y;
0969                 button_region->base_x2 = x + ws->c_icon_size[b_t].w;
0970                 button_region->base_y2 = MIN(y + ws->c_icon_size[b_t].h,
0971                                              ws->top_space +
0972                                              ws->titlebar_height);
0973 
0974                 button_region->glow_x1 = glow_x;
0975                 button_region->glow_y1 = glow_y;
0976                 button_region->glow_x2 = glow_x + ws->c_glow_size.w;
0977                 button_region->glow_y2 = MIN(glow_y + ws->c_glow_size.h,
0978                                              ws->top_space +
0979                                              ws->titlebar_height);
0980 
0981                 // Update glow overlaps of each pair
0982 
0983                 for (b_t2 = 0; b_t2 < b_t; b_t2++)
0984                 {                               // coordinates for these b_t2's will be ready for this b_t here
0985                     if (BUTTON_NOT_VISIBLE(d, b_t2))
0986                         continue;
0987                     if ((button_region->base_x1 > d->button_region[b_t2].base_x1 &&     //right of b_t2
0988                          button_region->glow_x1 <= d->button_region[b_t2].base_x2) || (button_region->base_x1 < d->button_region[b_t2].base_x1 &&       //left of b_t2
0989                                                                                        button_region->
0990                                                                                        glow_x2
0991                                                                                        >=
0992                                                                                        d->
0993                                                                                        button_region
0994                                                                                        [b_t2].
0995                                                                                        base_x1))
0996                     {
0997                         button_region->overlap_buttons[b_t2] = TRUE;
0998                     }
0999                     else
1000                         button_region->overlap_buttons[b_t2] = FALSE;
1001 
1002                     // buttons' protruding glow length might be asymmetric
1003                     if ((d->button_region[b_t2].base_x1 > button_region->base_x1 &&     //left of b_t2
1004                          d->button_region[b_t2].glow_x1 <= button_region->base_x2) || (d->button_region[b_t2].base_x1 < button_region->base_x1 &&       //right of b_t2
1005                                                                                        d->
1006                                                                                        button_region
1007                                                                                        [b_t2].
1008                                                                                        glow_x2
1009                                                                                        >=
1010                                                                                        button_region->
1011                                                                                        base_x1))
1012                     {
1013                         d->button_region[b_t2].overlap_buttons[b_t] = TRUE;
1014                     }
1015                     else
1016                         d->button_region[b_t2].overlap_buttons[b_t] = FALSE;
1017                 }
1018             }
1019         }
1020         else
1021         {
1022             for (b_t = 0; b_t < B_T_COUNT; b_t++)
1023             {
1024                 if (BUTTON_NOT_VISIBLE(d, b_t))
1025                     continue;
1026                 get_button_pos(ws, b_t, d, y1, &x, &y);
1027                 button_region_t *button_region = &(d->button_region[b_t]);
1028 
1029                 button_region->base_x1 = x;
1030                 button_region->base_y1 = y;
1031                 button_region->base_x2 = x + ws->c_icon_size[b_t].w;
1032                 button_region->base_y2 = MIN(y + ws->c_icon_size[b_t].h,
1033                                              ws->top_space +
1034                                              ws->titlebar_height);
1035             }
1036         }
1037     }
1038     else
1039     {
1040         for (b_t = 0; b_t < B_T_COUNT; b_t++)
1041         {
1042             if (BUTTON_NOT_VISIBLE(d, b_t))
1043                 continue;
1044             get_button_pos(ws, b_t, d, y1, &x, &y);
1045             button_region_t *button_region = &(d->button_region[b_t]);
1046 
1047             button_region->base_x1 = x;
1048             button_region->base_y1 = y;
1049             button_region->base_x2 = x + 16;
1050             button_region->base_y2 = y + 16;
1051         }
1052     }
1053     for (b_t = 0; b_t < B_T_COUNT; b_t++)
1054     {
1055         button_region_t *button_region = &(d->button_region[b_t]);
1056         button_region_t *button_region_inact = &(d->button_region_inact[b_t]);
1057 
1058         memcpy(button_region_inact, button_region, sizeof(button_region_t));
1059     }
1060 }
1061 static void draw_window_decoration_real(decor_t * d, gboolean shadow_time)
1062 {
1063     cairo_t *cr;
1064     double x1, y1, x2, y2, h;
1065     int top;
1066     frame_settings *fs = d->fs;
1067     window_settings *ws = fs->ws;
1068 
1069     if (!d->pixmap)
1070         return;
1071 
1072     top = ws->win_extents.top + ws->titlebar_height;
1073 
1074     x1 = ws->left_space - ws->win_extents.left;
1075     y1 = ws->top_space - ws->win_extents.top;
1076     x2 = d->width - ws->right_space + ws->win_extents.right;
1077     y2 = d->height - ws->bottom_space + ws->win_extents.bottom;
1078 
1079     h = d->height - ws->top_space - ws->titlebar_height - ws->bottom_space;
1080 
1081     if (!d->draw_only_buttons_region)   // if not only drawing buttons
1082     {
1083         cr = gdk_cairo_create(GDK_DRAWABLE
1084                               (IS_VALID(d->buffer_pixmap) ? d->buffer_pixmap :
1085                                                             d->pixmap));
1086         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1087         cairo_set_line_width(cr, 1.0);
1088         cairo_save(cr);
1089         draw_shadow_background(d, cr);
1090         engine_draw_frame(d, cr);
1091         cairo_restore(cr);
1092         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1093         cairo_set_line_width(cr, 2.0);
1094 
1095         /*color.r = 1;
1096           color.g = 1;
1097           color.b = 1; */
1098 
1099         // the buttons were previously drawn here, so we need to save the cairo state here
1100         cairo_save(cr);
1101 
1102         if (d->layout && d->tobj_item_state[TBT_TITLE] != 3)
1103         {
1104             pango_layout_set_alignment(d->layout, ws->title_text_align);
1105             cairo_move_to(cr,
1106                           get_real_pos(ws, TBT_TITLE, d),
1107                           y1 + 2.0 + (ws->titlebar_height -
1108                                       ws->text_height) / 2.0);
1109 
1110             /* ===================active text colors */
1111             cairo_set_source_alpha_color(cr, &fs->text_halo);
1112             pango_cairo_layout_path(cr, d->layout);
1113             cairo_stroke(cr);
1114 
1115             cairo_set_source_alpha_color(cr, &fs->text);
1116 
1117             cairo_move_to(cr,
1118                           get_real_pos(ws, TBT_TITLE, d),
1119                           y1 + 2.0 + (ws->titlebar_height -
1120                                       ws->text_height) / 2.0);
1121 
1122             pango_cairo_show_layout(cr, d->layout);
1123         }
1124         if (d->icon && d->tobj_item_state[TBT_ICON] != 3)
1125         {
1126             cairo_translate(cr, get_real_pos(ws, TBT_ICON, d),
1127                             y1 - 5.0 + ws->titlebar_height / 2);
1128 
1129             cairo_set_source(cr, d->icon);
1130             cairo_rectangle(cr, 0.0, 0.0, 16.0, 16.0);
1131             cairo_clip(cr);
1132             cairo_paint(cr);
1133         }
1134         // Copy button region backgrounds to buffers
1135         // for fast drawing of buttons from now on
1136         // when drawing is done for buttons
1137         gboolean bg_pixmaps_update_needed = FALSE;
1138         int b_t;
1139 
1140         for (b_t = 0; b_t < B_T_COUNT; b_t++)
1141         {
1142             button_region_t *button_region =
1143                 (d->active ? &d->button_region[b_t] : &d->
1144                  button_region_inact[b_t]);
1145             if (BUTTON_NOT_VISIBLE(d, b_t))
1146                 continue;
1147             if (!button_region->bg_pixmap && button_region->base_x1 >= 0)       // if region is valid
1148             {
1149                 bg_pixmaps_update_needed = TRUE;
1150                 break;
1151             }
1152         }
1153         if (bg_pixmaps_update_needed && !shadow_time)
1154         {
1155             for (b_t = 0; b_t < B_T_COUNT; b_t++)
1156             {
1157                 if (BUTTON_NOT_VISIBLE(d, b_t))
1158                     continue;
1159 
1160                 button_region_t *button_region =
1161                     (d->active ? &d->button_region[b_t] : &d->
1162                      button_region_inact[b_t]);
1163                 gint rx, ry, rw, rh;
1164 
1165                 if (ws->use_pixmap_buttons &&
1166                     ((ws->use_button_glow && d->active) ||
1167                      (ws->use_button_inactive_glow && !d->active)))
1168                 {
1169                     if (button_region->glow_x1 == -100) // skip uninitialized regions
1170                         continue;
1171                     rx = button_region->glow_x1;
1172                     ry = button_region->glow_y1;
1173                     rw = button_region->glow_x2 - button_region->glow_x1;
1174                     rh = button_region->glow_y2 - button_region->glow_y1;
1175                 }
1176                 else
1177                 {
1178                     if (button_region->base_x1 == -100) // skip uninitialized regions
1179                         continue;
1180                     rx = button_region->base_x1;
1181                     ry = button_region->base_y1;
1182                     if (!ws->use_pixmap_buttons)        // offset: (-2,1)
1183                     {
1184                         rx -= 2;
1185                         ry++;
1186                     }
1187                     rw = button_region->base_x2 - button_region->base_x1;
1188                     rh = button_region->base_y2 - button_region->base_y1;
1189                 }
1190                 if (!button_region->bg_pixmap)
1191                     button_region->bg_pixmap = create_pixmap(rw, rh);
1192                 if (!button_region->bg_pixmap)
1193                 {
1194                     fprintf(stderr,
1195                             "%s: Error allocating buffer.\n", program_name);
1196                 }
1197                 else
1198                 {
1199                     gdk_draw_drawable(button_region->bg_pixmap, d->gc,
1200                                       IS_VALID(d->buffer_pixmap) ?
1201                                       d->buffer_pixmap : d->pixmap,
1202                                       rx, ry, 0, 0,
1203                                       rw, rh);
1204                 }
1205             }
1206         }
1207         cairo_restore(cr);              // and restore the state for button drawing
1208         /*if (!shadow_time)
1209           {
1210         //workaround for slowness, will grab and rotate the two side-pieces
1211         gint w, h;
1212         cairo_surface_t * csur;
1213         cairo_pattern_t * sr;
1214         cairo_matrix_t cm;
1215         cairo_destroy(cr);
1216         gint topspace = ws->top_space + ws->titlebar_height;
1217         cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap ? d->buffer_pixmap : d->pixmap));
1218         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1219 
1220         gdk_drawable_get_size(pbuff,&w,&h);
1221         csur = cairo_xlib_surface_create(
1222         GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1223         GDK_PIXMAP_XID(pbuff),
1224         GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(pbuff)),
1225         w,h);
1226 
1227         cairo_set_source_surface(cr, csur, 0, 0);
1228         sr = cairo_get_source(cr);
1229         cairo_pattern_get_matrix(sr, &cm);
1230 
1231         //draw all four quads from the old one to the new one
1232         //first top quad
1233         cairo_save(cr);
1234         cairo_rectangle(cr, 0, 0, d->width, topspace);
1235         cairo_clip(cr);
1236         cairo_pattern_set_matrix(sr, &cm);
1237         cairo_paint(cr);
1238         cairo_restore(cr);
1239 
1240         //then bottom, easiest this way
1241         cairo_save(cr);
1242         cairo_rectangle(cr, 0, topspace, d->width, ws->bottom_space);
1243         cairo_clip(cr);
1244         cm.y0 = d->height - (top_space + ws->bottom_space);
1245         cm.x0 = 0;
1246         cairo_pattern_set_matrix(sr,&cm);
1247         cairo_paint(cr);
1248         cairo_restore(cr);
1249 
1250         //now left
1251         cairo_save(cr);
1252         cairo_rectangle(cr, 0, topspace + ws->bottom_space,
1253         d->height-(topspace + ws->bottom_space), ws->left_space);
1254         cairo_clip(cr);
1255         cm.xx=0;
1256         cm.xy=1;
1257         cm.yx=1;
1258         cm.yy=0;
1259         cm.x0 = - topspace - ws->bottom_space;
1260         cm.y0 = topspace;
1261         cairo_pattern_set_matrix(sr,&cm);
1262         cairo_paint(cr);
1263         cairo_restore(cr);
1264 
1265         //now right
1266         cairo_save(cr);
1267         cairo_rectangle(cr, 0, topspace + ws->bottom_space + ws->left_space,
1268         d->height-(topspace + ws->bottom_space), ws->right_space);
1269         cairo_clip(cr);
1270         cm.y0 = topspace;
1271         cm.x0 = d->width-
1272         (topspace + ws->bottom_space + ws->left_space + ws->right_space);
1273         cairo_pattern_set_matrix(sr,&cm);
1274         cairo_paint(cr);
1275         cairo_restore(cr);
1276 
1277 
1278         cairo_destroy(cr);
1279         g_object_unref (G_OBJECT (pbuff));
1280         cairo_surface_destroy(csur);
1281     }
1282     */
1283     }
1284     // Draw buttons
1285 
1286     cr = gdk_cairo_create(GDK_DRAWABLE (IS_VALID(d->buffer_pixmap) ?
1287                                         d->buffer_pixmap : d->pixmap));
1288 
1289     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1290 
1291     if (ws->use_button_fade && ws->use_pixmap_buttons)
1292         draw_buttons_with_fade(d, cr, y1);
1293     else
1294         draw_buttons_without_fade(d, cr, y1);
1295 
1296     cairo_destroy(cr);
1297 
1298     if (IS_VALID(d->buffer_pixmap))
1299     {
1300         /*if (d->draw_only_buttons_region && d->min_drawn_buttons_region.x1 < 10000)    // if region is updated at least once
1301           {
1302           gdk_draw_drawable(d->pixmap,
1303           d->gc,
1304           d->buffer_pixmap,
1305           d->min_drawn_buttons_region.x1,
1306           d->min_drawn_buttons_region.y1,
1307           d->min_drawn_buttons_region.x1,
1308           d->min_drawn_buttons_region.y1,
1309           d->min_drawn_buttons_region.x2 -
1310           d->min_drawn_buttons_region.x1,
1311           d->min_drawn_buttons_region.y2 -
1312           d->min_drawn_buttons_region.y1);
1313           }
1314           else*/
1315         {
1316             gdk_draw_drawable(d->pixmap,
1317                               d->gc,
1318                               d->buffer_pixmap,
1319                               0,
1320                               0,
1321                               0,
1322                               0,
1323                               d->width,
1324                               d->height);
1325             //ws->top_space + ws->bottom_space +
1326             //ws->titlebar_height + 2);
1327         }
1328     }
1329 }
1330 
1331 static void draw_window_decoration(decor_t * d)
1332 {
1333     if (d->active)
1334     {
1335         d->pixmap = d->p_active;
1336         d->buffer_pixmap = d->p_active_buffer;
1337     }
1338     else
1339     {
1340         d->pixmap = d->p_inactive;
1341         d->buffer_pixmap = d->p_inactive_buffer;
1342     }
1343     if (d->draw_only_buttons_region)
1344         draw_window_decoration_real(d, FALSE);
1345     if (!d->only_change_active)
1346     {
1347         gboolean save = d->active;
1348         frame_settings *fs = d->fs;
1349 
1350         d->active = TRUE;
1351         d->fs = d->fs->ws->fs_act;
1352         d->pixmap = d->p_active;
1353         d->buffer_pixmap = d->p_active_buffer;
1354         draw_window_decoration_real(d, FALSE);
1355         d->active = FALSE;
1356         d->fs = d->fs->ws->fs_inact;
1357         d->pixmap = d->p_inactive;
1358         d->buffer_pixmap = d->p_inactive_buffer;
1359         draw_window_decoration_real(d, FALSE);
1360         d->active = save;
1361         d->fs = fs;
1362     }
1363     else
1364     {
1365         d->only_change_active = FALSE;
1366     }
1367     if (d->active)
1368     {
1369         d->pixmap = d->p_active;
1370         d->buffer_pixmap = d->p_active_buffer;
1371     }
1372     else
1373     {
1374         d->pixmap = d->p_inactive;
1375         d->buffer_pixmap = d->p_inactive_buffer;
1376     }
1377     if (d->prop_xid)
1378     {
1379         decor_update_window_property(d);
1380         d->prop_xid = 0;
1381     }
1382     d->draw_only_buttons_region = FALSE;
1383 }
1384 static void draw_shadow_window(decor_t * d)
1385 {
1386     draw_window_decoration_real(d, TRUE);
1387 }
1388 
1389 /* to save some memory, value is specific to current decorations */
1390 #define CORNER_REDUCTION 3
1391 
1392 static int update_shadow(frame_settings * fs)
1393 {
1394 #if 0
1395     Display *xdisplay = gdk_display;
1396     XRenderPictFormat *format;
1397     GdkPixmap *pixmap;
1398     Picture src, dst, tmp;
1399     XFixed *params;
1400     XFilters *filters;
1401     char *filter = NULL;
1402     int size, n_params = 0;
1403 #endif
1404     cairo_t *cr;
1405     decor_t d;
1406 
1407     bzero(&d, sizeof(decor_t));
1408     window_settings *ws = fs->ws;
1409 #if 0
1410     //    double        save_decoration_alpha;
1411     static XRenderColor color;
1412     static XRenderColor clear = { 0x0000, 0x0000, 0x0000, 0x0000 };
1413     static XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
1414 
1415     color.red = ws->shadow_color[0];
1416     color.green = ws->shadow_color[1];
1417     color.blue = ws->shadow_color[2];
1418     color.alpha = 0xffff;
1419 
1420     /* compute a gaussian convolution kernel */
1421     params = create_gaussian_kernel(ws->shadow_radius, ws->shadow_radius / 2.0, // SIGMA
1422                                     ws->shadow_radius,  // ALPHA
1423                                     ws->shadow_opacity, &size);
1424     if (!params)
1425         ws->shadow_offset_x = ws->shadow_offset_y = size = 0;
1426 
1427     if (ws->shadow_radius <= 0.0 && ws->shadow_offset_x == 0 &&
1428         ws->shadow_offset_y == 0)
1429         size = 0;
1430 
1431     n_params = size + 2;
1432     size = size / 2;
1433 #endif
1434     ws->left_space = ws->win_extents.left + size - ws->shadow_offset_x;
1435     ws->right_space = ws->win_extents.right + size + ws->shadow_offset_x;
1436     ws->top_space = ws->win_extents.top + size - ws->shadow_offset_y;
1437     ws->bottom_space = ws->win_extents.bottom + size + ws->shadow_offset_y;
1438 
1439 
1440     ws->left_space = MAX(ws->win_extents.left, ws->left_space);
1441     ws->right_space = MAX(ws->win_extents.right, ws->right_space);
1442     ws->top_space = MAX(ws->win_extents.top, ws->top_space);
1443     ws->bottom_space = MAX(ws->win_extents.bottom, ws->bottom_space);
1444 
1445     ws->shadow_left_space = MAX(0, size - ws->shadow_offset_x);
1446     ws->shadow_right_space = MAX(0, size + ws->shadow_offset_x);
1447     ws->shadow_top_space = MAX(0, size - ws->shadow_offset_y);
1448     ws->shadow_bottom_space = MAX(0, size + ws->shadow_offset_y);
1449 
1450     ws->shadow_left_corner_space = MAX(0, size + ws->shadow_offset_x);
1451     ws->shadow_right_corner_space = MAX(0, size - ws->shadow_offset_x);
1452     ws->shadow_top_corner_space = MAX(0, size + ws->shadow_offset_y);
1453     ws->shadow_bottom_corner_space = MAX(0, size - ws->shadow_offset_y);
1454 
1455     ws->left_corner_space =
1456         MAX(0, ws->shadow_left_corner_space - CORNER_REDUCTION);
1457     ws->right_corner_space =
1458         MAX(0, ws->shadow_right_corner_space - CORNER_REDUCTION);
1459     ws->top_corner_space =
1460         MAX(0, ws->shadow_top_corner_space - CORNER_REDUCTION);
1461     ws->bottom_corner_space =
1462         MAX(0, ws->shadow_bottom_corner_space - CORNER_REDUCTION);
1463 
1464     ws->normal_top_corner_space =
1465         MAX(0, ws->top_corner_space - ws->titlebar_height);
1466     ws->switcher_top_corner_space =
1467         MAX(0, ws->top_corner_space - SWITCHER_TOP_EXTRA);
1468     ws->switcher_bottom_corner_space =
1469         MAX(0, ws->bottom_corner_space - SWITCHER_SPACE);
1470 
1471     d.buffer_pixmap = NULL;
1472     d.layout = NULL;
1473     d.icon = NULL;
1474     d.state = 0;
1475     d.actions = 0;
1476     d.prop_xid = 0;
1477     d.draw = draw_shadow_window;
1478     d.active = TRUE;
1479     d.fs = fs;
1480 
1481     reset_buttons_bg_and_fade(&d);
1482 
1483     d.width =
1484         ws->left_space + ws->left_corner_space + 1 +
1485         ws->right_corner_space + ws->right_space;
1486     d.height =
1487         ws->top_space + ws->titlebar_height +
1488         ws->normal_top_corner_space + 2 + ws->bottom_corner_space +
1489         ws->bottom_space;
1490 #if 0
1491     /* all pixmaps are ARGB32 */
1492     format = XRenderFindStandardFormat(xdisplay, PictStandardARGB32);
1493 
1494     /* shadow color */
1495     src = XRenderCreateSolidFill(xdisplay, &color);
1496 
1497     if (ws->large_shadow_pixmap)
1498     {
1499         g_object_unref (G_OBJECT (ws->large_shadow_pixmap));
1500         ws->large_shadow_pixmap = NULL;
1501     }
1502 
1503     if (ws->shadow_pattern)
1504     {
1505         cairo_pattern_destroy(ws->shadow_pattern);
1506         ws->shadow_pattern = NULL;
1507     }
1508 
1509     if (ws->shadow_pixmap)
1510     {
1511         g_object_unref (G_OBJECT (ws->shadow_pixmap));
1512         ws->shadow_pixmap = NULL;
1513     }
1514 
1515     /* no shadow */
1516     if (size <= 0)
1517     {
1518         if (params)
1519             g_free(params);
1520 
1521         return 1;
1522     }
1523 
1524     pixmap = create_pixmap(d.width, d.height);
1525     if (!pixmap)
1526     {
1527         g_free(params);
1528         return 0;
1529     }
1530 
1531     /* query server for convolution filter */
1532     filters = XRenderQueryFilters(xdisplay, GDK_PIXMAP_XID(pixmap));
1533     if (filters)
1534     {
1535         int i;
1536 
1537         for (i = 0; i < filters->nfilter; i++)
1538         {
1539             if (strcmp(filters->filter[i], FilterConvolution) == 0)
1540             {
1541                 filter = FilterConvolution;
1542                 break;
1543             }
1544         }
1545 
1546         XFree(filters);
1547     }
1548 
1549     if (!filter)
1550     {
1551         fprintf(stderr, "can't generate shadows, X server doesn't support "
1552                 "convolution filters\n");
1553 
1554         g_free(params);
1555         g_object_unref (G_OBJECT (pixmap));
1556         return 1;
1557     }
1558 
1559     /* WINDOWS WITH DECORATION */
1560 
1561     d.pixmap = create_pixmap(d.width, d.height);
1562     if (!d.pixmap)
1563     {
1564         g_free(params);
1565         g_object_unref (G_OBJECT (pixmap));
1566         return 0;
1567     }
1568 
1569     /* draw decorations */
1570     (*d.draw) (&d);
1571 
1572     dst = XRenderCreatePicture(xdisplay, GDK_PIXMAP_XID(d.pixmap),
1573                                format, 0, NULL);
1574     tmp = XRenderCreatePicture(xdisplay, GDK_PIXMAP_XID(pixmap),
1575                                format, 0, NULL);
1576 
1577     /* first pass */
1578     params[0] = (n_params - 2) << 16;
1579     params[1] = 1 << 16;
1580 
1581     set_picture_transform(xdisplay, dst, ws->shadow_offset_x, 0);
1582     XRenderSetPictureFilter(xdisplay, dst, filter, params, n_params);
1583     XRenderComposite(xdisplay,
1584                      PictOpSrc,
1585                      src, dst, tmp, 0, 0, 0, 0, 0, 0, d.width, d.height);
1586 
1587     /* second pass */
1588     params[0] = 1 << 16;
1589     params[1] = (n_params - 2) << 16;
1590 
1591     set_picture_transform(xdisplay, tmp, 0, ws->shadow_offset_y);
1592     XRenderSetPictureFilter(xdisplay, tmp, filter, params, n_params);
1593     XRenderComposite(xdisplay,
1594                      PictOpSrc,
1595                      src, tmp, dst, 0, 0, 0, 0, 0, 0, d.width, d.height);
1596 
1597     XRenderFreePicture(xdisplay, tmp);
1598     XRenderFreePicture(xdisplay, dst);
1599 
1600     g_object_unref (G_OBJECT (pixmap));
1601 
1602     ws->large_shadow_pixmap = d.pixmap;
1603 
1604     cr = gdk_cairo_create(GDK_DRAWABLE(ws->large_shadow_pixmap));
1605     ws->shadow_pattern =
1606         cairo_pattern_create_for_surface(cairo_get_target(cr));
1607     cairo_pattern_set_filter(ws->shadow_pattern, CAIRO_FILTER_NEAREST);
1608     cairo_destroy(cr);
1609 
1610 
1611     /* WINDOWS WITHOUT DECORATIONS */
1612 
1613     d.width = ws->shadow_left_space + ws->shadow_left_corner_space + 1 +
1614         ws->shadow_right_space + ws->shadow_right_corner_space;
1615     d.height = ws->shadow_top_space + ws->shadow_top_corner_space + 1 +
1616         ws->shadow_bottom_space + ws->shadow_bottom_corner_space;
1617 
1618     pixmap = create_pixmap(d.width, d.height);
1619     if (!pixmap)
1620     {
1621         g_free(params);
1622         return 0;
1623     }
1624 
1625     d.pixmap = create_pixmap(d.width, d.height);
1626     if (!d.pixmap)
1627     {
1628         g_object_unref (G_OBJECT (pixmap));
1629         g_free(params);
1630         return 0;
1631     }
1632 
1633     dst = XRenderCreatePicture(xdisplay, GDK_PIXMAP_XID(d.pixmap),
1634                                format, 0, NULL);
1635 
1636     /* draw rectangle */
1637     XRenderFillRectangle(xdisplay, PictOpSrc, dst, &clear,
1638                          0, 0, d.width, d.height);
1639     XRenderFillRectangle(xdisplay, PictOpSrc, dst, &white,
1640                          ws->shadow_left_space,
1641                          ws->shadow_top_space,
1642                          d.width - ws->shadow_left_space -
1643                          ws->shadow_right_space,
1644                          d.height - ws->shadow_top_space -
1645                          ws->shadow_bottom_space);
1646 
1647     tmp = XRenderCreatePicture(xdisplay, GDK_PIXMAP_XID(pixmap),
1648                                format, 0, NULL);
1649 
1650     /* first pass */
1651     params[0] = (n_params - 2) << 16;
1652     params[1] = 1 << 16;
1653 
1654     set_picture_transform(xdisplay, dst, ws->shadow_offset_x, 0);
1655     XRenderSetPictureFilter(xdisplay, dst, filter, params, n_params);
1656     XRenderComposite(xdisplay,
1657                      PictOpSrc,
1658                      src, dst, tmp, 0, 0, 0, 0, 0, 0, d.width, d.height);
1659 
1660     /* second pass */
1661     params[0] = 1 << 16;
1662     params[1] = (n_params - 2) << 16;
1663 
1664     set_picture_transform(xdisplay, tmp, 0, ws->shadow_offset_y);
1665     XRenderSetPictureFilter(xdisplay, tmp, filter, params, n_params);
1666     XRenderComposite(xdisplay,
1667                      PictOpSrc,
1668                      src, tmp, dst, 0, 0, 0, 0, 0, 0, d.width, d.height);
1669 
1670     XRenderFreePicture(xdisplay, tmp);
1671     XRenderFreePicture(xdisplay, dst);
1672     XRenderFreePicture(xdisplay, src);
1673 
1674     g_object_unref (G_OBJECT (pixmap));
1675 
1676     g_free(params);
1677 
1678     ws->shadow_pixmap = d.pixmap;
1679 #endif
1680     return 1;
1681 }
1682 #endif /* ************************ */
1683 static void titlebar_font_changed(window_settings * ws)
1684 {
1685 #if 0
1686     PangoFontMetrics *metrics;
1687     PangoLanguage *lang;
1688 
1689     pango_context_set_font_description(ws->pango_context, ws->font_desc);
1690     lang = pango_context_get_language(ws->pango_context);
1691     metrics =
1692         pango_context_get_metrics(ws->pango_context, ws->font_desc, lang);
1693 
1694     ws->text_height = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics) +
1695                                    pango_font_metrics_get_descent(metrics));
1696 #endif
1697     ws->titlebar_height = ws->text_height;
1698     if (ws->titlebar_height < ws->min_titlebar_height)
1699         ws->titlebar_height = ws->min_titlebar_height;
1700 
1701 //    pango_font_metrics_unref(metrics);
1702 
1703 }
1704 
1705 static void load_buttons_image(window_settings * ws, gint y)
1706 {
1707     gchar *file;
1708     int x, pix_width, pix_height, rel_button;
1709 
1710     rel_button = get_b_offset(y);
1711 
1712 
1713 
1714     if (ws->ButtonArray[y])
1715         g_object_unref(ws->ButtonArray[y]);
1716     file = make_filename("buttons", b_types[y], "png");
1717     if (!file || !(ws->ButtonArray[y] = gdk_pixbuf_new_from_file(file, NULL)))
1718         ws->ButtonArray[y] = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 16 * S_COUNT, 16);     // create a blank pixbuf
1719     g_free(file);
1720 
1721     pix_width = gdk_pixbuf_get_width(ws->ButtonArray[y]) / S_COUNT;
1722     pix_height = gdk_pixbuf_get_height(ws->ButtonArray[y]);
1723     ws->c_icon_size[rel_button].w = pix_width;
1724     ws->c_icon_size[rel_button].h = pix_height;
1725     for (x = 0; x < S_COUNT; x++)
1726     {
1727         if (ws->ButtonPix[x + y * S_COUNT])
1728             g_object_unref(ws->ButtonPix[x + y * S_COUNT]);
1729 
1730         ws->ButtonPix[x + y * S_COUNT] =
1731             gdk_pixbuf_new_subpixbuf(ws->ButtonArray[y], x * pix_width, 0,
1732                                      pix_width, pix_height);
1733     }
1734 }
1735 static void load_buttons_glow_images(window_settings * ws)
1736 {
1737     gchar *file1 = NULL;
1738     gchar *file2 = NULL;
1739     int x, pix_width, pix_height;
1740     int pix_width2, pix_height2;
1741     gboolean success1 = FALSE;
1742     gboolean success2 = FALSE;
1743 
1744     if (ws->use_button_glow)
1745     {
1746         if (ws->ButtonGlowArray)
1747             g_object_unref(ws->ButtonGlowArray);
1748         file1 = make_filename("buttons", "glow", "png");
1749         if (file1 &&
1750             (ws->ButtonGlowArray = gdk_pixbuf_new_from_file(file1, NULL)))
1751             success1 = TRUE;
1752     }
1753     if (ws->use_button_inactive_glow)
1754     {
1755         if (ws->ButtonInactiveGlowArray)
1756             g_object_unref(ws->ButtonInactiveGlowArray);
1757         file2 = make_filename("buttons", "inactive_glow", "png");
1758         if (file2 &&
1759             (ws->ButtonInactiveGlowArray =
1760              gdk_pixbuf_new_from_file(file2, NULL)))
1761             success2 = TRUE;
1762     }
1763     if (success1 && success2)
1764     {
1765         pix_width = gdk_pixbuf_get_width(ws->ButtonGlowArray) / B_COUNT;
1766         pix_height = gdk_pixbuf_get_height(ws->ButtonGlowArray);
1767         pix_width2 =
1768             gdk_pixbuf_get_width(ws->ButtonInactiveGlowArray) / B_COUNT;
1769         pix_height2 = gdk_pixbuf_get_height(ws->ButtonInactiveGlowArray);
1770 
1771         if (pix_width != pix_width2 || pix_height != pix_height2)
1772         {
1773             g_warning
1774                 ("Choose same size glow images for active and inactive windows."
1775                  "\nInactive glow image is scaled for now.");
1776             // Scale the inactive one
1777             GdkPixbuf *tmp_pixbuf =
1778                 gdk_pixbuf_new(gdk_pixbuf_get_colorspace
1779                                (ws->ButtonGlowArray),
1780                                TRUE,
1781                                gdk_pixbuf_get_bits_per_sample(ws->
1782                                                               ButtonGlowArray),
1783                                pix_width * B_COUNT,
1784                                pix_height);
1785 
1786             gdk_pixbuf_scale(ws->ButtonInactiveGlowArray, tmp_pixbuf,
1787                              0, 0,
1788                              pix_width * B_COUNT, pix_height,
1789                              0, 0,
1790                              pix_width / (double)pix_width2,
1791                              pix_height / (double)pix_height2,
1792                              GDK_INTERP_BILINEAR);
1793             g_object_unref(ws->ButtonInactiveGlowArray);
1794             ws->ButtonInactiveGlowArray = tmp_pixbuf;
1795         }
1796     }
1797     else
1798     {
1799         pix_width = 16;
1800         pix_height = 16;
1801         if (success1)
1802         {
1803             pix_width = gdk_pixbuf_get_width(ws->ButtonGlowArray) / B_COUNT;
1804             pix_height = gdk_pixbuf_get_height(ws->ButtonGlowArray);
1805         }
1806         else if (success2)
1807         {
1808             pix_width =
1809                 gdk_pixbuf_get_width(ws->ButtonInactiveGlowArray) /
1810                 B_COUNT;
1811             pix_height = gdk_pixbuf_get_height(ws->ButtonInactiveGlowArray);
1812         }
1813         if (!success1 && ws->use_button_glow)
1814             ws->ButtonGlowArray = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, pix_width * B_COUNT, pix_height); // create a blank pixbuf
1815         if (!success2 && ws->use_button_inactive_glow)
1816             ws->ButtonInactiveGlowArray = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, pix_width * B_COUNT, pix_height); // create a blank pixbuf
1817     }
1818     ws->c_glow_size.w = pix_width;
1819     ws->c_glow_size.h = pix_height;
1820 
1821     if (ws->use_button_glow)
1822     {
1823         g_free(file1);
1824         for (x = 0; x < B_COUNT; x++)
1825         {
1826             if (ws->ButtonGlowPix[x])
1827                 g_object_unref(ws->ButtonGlowPix[x]);
1828             ws->ButtonGlowPix[x] =
1829                 gdk_pixbuf_new_subpixbuf(ws->ButtonGlowArray,
1830                                          x * pix_width, 0, pix_width,
1831                                          pix_height);
1832         }
1833     }
1834     if (ws->use_button_inactive_glow)
1835     {
1836         g_free(file2);
1837         for (x = 0; x < B_COUNT; x++)
1838         {
1839             if (ws->ButtonInactiveGlowPix[x])
1840                 g_object_unref(ws->ButtonInactiveGlowPix[x]);
1841             ws->ButtonInactiveGlowPix[x] =
1842                 gdk_pixbuf_new_subpixbuf(ws->ButtonInactiveGlowArray,
1843                                          x * pix_width, 0, pix_width,
1844                                          pix_height);
1845         }
1846     }
1847 }
1848 void load_button_image_setting(window_settings * ws)
1849 {
1850     gint i;
1851 
1852     for (i = 0; i < B_COUNT; i++)
1853         load_buttons_image(ws, i);
1854 
1855     // load active and inactive glow image
1856     if (ws->use_button_glow || ws->use_button_inactive_glow)
1857         load_buttons_glow_images(ws);
1858 }
1859 static void load_settings(window_settings * ws)
1860 {
1861     gchar *engine = NULL;
1862 
1863     gchar *path =
1864         g_strjoin("/", g_get_home_dir(), ".emerald/settings.ini", NULL);
1865     GKeyFile *f = g_key_file_new();
1866 
1867 //    copy_from_defaults_if_needed();
1868 
1869     //settings
1870     g_key_file_load_from_file(f, path, 0, NULL);
1871     g_free(path);
1872     load_int_setting(f, &ws->double_click_action, "double_click_action",
1873                      "titlebars");
1874     load_int_setting(f, &ws->button_hover_cursor, "hover_cursor", "buttons");
1875     load_bool_setting(f, &ws->use_decoration_cropping,
1876                       "use_decoration_cropping", "decorations");
1877     load_bool_setting(f, &ws->use_button_fade, "use_button_fade", "buttons");
1878     gint button_fade_step_duration = ws->button_fade_step_duration;
1879 
1880     load_int_setting(f, &button_fade_step_duration,
1881                      "button_fade_step_duration", "buttons");
1882     if (button_fade_step_duration > 0)
1883         ws->button_fade_step_duration = button_fade_step_duration;
1884     gint button_fade_total_duration = 250;
1885 
1886     load_int_setting(f, &button_fade_total_duration,
1887                      "button_fade_total_duration", "buttons");
1888     if (button_fade_total_duration > 0)
1889         ws->button_fade_num_steps =
1890             button_fade_total_duration / ws->button_fade_step_duration;
1891     if (ws->button_fade_num_steps == 0)
1892         ws->button_fade_num_steps = 1;
1893     gboolean use_button_fade_pulse = FALSE;
1894 
1895     load_bool_setting(f, &use_button_fade_pulse, "use_button_fade_pulse",
1896                       "buttons");
1897 
1898     ws->button_fade_pulse_wait_steps = 0;
1899     if (use_button_fade_pulse)
1900     {
1901         gint button_fade_pulse_min_opacity = 0;
1902 
1903         load_int_setting(f, &button_fade_pulse_min_opacity,
1904                          "button_fade_pulse_min_opacity", "buttons");
1905         ws->button_fade_pulse_len_steps =
1906             ws->button_fade_num_steps * (100 -
1907                                          button_fade_pulse_min_opacity) /
1908             100;
1909         gint button_fade_pulse_wait_duration = 0;
1910 
1911         load_int_setting(f, &button_fade_pulse_wait_duration,
1912                          "button_fade_pulse_wait_duration", "buttons");
1913         if (button_fade_pulse_wait_duration > 0)
1914             ws->button_fade_pulse_wait_steps =
1915                 button_fade_pulse_wait_duration /
1916                 ws->button_fade_step_duration;
1917     }
1918     else
1919         ws->button_fade_pulse_len_steps = 0;
1920 
1921 //    load_bool_setting(f, &enable_tooltips, "enable_tooltips", "buttons");
1922     load_int_setting(f, &ws->blur_type,
1923                      "blur_type", "decorations");
1924 
1925     //theme
1926     path = g_strjoin("/", g_get_home_dir(), ".emerald/theme/theme.ini", NULL);
1927     g_key_file_load_from_file(f, path, 0, NULL);
1928     g_free(path);
1929     load_string_setting(f, &engine, "engine", "engine");
1930 
1931     if (!load_engine(engine, ws))
1932     {
1933         if (engine)
1934             g_free(engine);
1935         engine = g_strdup("legacy");
1936         load_engine(engine, ws);
1937     }
1938     LFACSS(text, titlebar);
1939     LFACSS(text_halo, titlebar);
1940     LFACSS(button, buttons);
1941     LFACSS(button_halo, buttons);
1942     load_engine_settings(f, ws);
1943     load_font_setting(f, &ws->font_desc, "titlebar_font", "titlebar");
1944     load_bool_setting(f, &ws->use_pixmap_buttons, "use_pixmap_buttons",
1945                       "buttons");
1946     load_bool_setting(f, &ws->use_button_glow, "use_button_glow", "buttons");
1947     load_bool_setting(f, &ws->use_button_inactive_glow,
1948                       "use_button_inactive_glow", "buttons");
1949 
1950     if (ws->use_pixmap_buttons)
1951         load_button_image_setting(ws);
1952     load_shadow_color_setting(f, ws->shadow_color, "shadow_color", "shadow");
1953     load_int_setting(f, &ws->shadow_offset_x, "shadow_offset_x", "shadow");
1954     load_int_setting(f, &ws->shadow_offset_y, "shadow_offset_y", "shadow");
1955     load_float_setting(f, &ws->shadow_radius, "shadow_radius", "shadow");
1956     load_float_setting(f, &ws->shadow_opacity, "shadow_opacity", "shadow");
1957     load_string_setting(f, &ws->tobj_layout, "title_object_layout",
1958                         "titlebar");
1959     load_int_setting(f, &ws->button_offset, "vertical_offset", "buttons");
1960     load_int_setting(f, &ws->button_hoffset, "horizontal_offset", "buttons");
1961     load_int_setting(f, &ws->win_extents.top, "top", "borders");
1962     load_int_setting(f, &ws->win_extents.left, "left", "borders");
1963     load_int_setting(f, &ws->win_extents.right, "right", "borders");
1964     load_int_setting(f, &ws->win_extents.bottom, "bottom", "borders");
1965     load_int_setting(f, &ws->min_titlebar_height, "min_titlebar_height",
1966                      "titlebar");
1967     g_key_file_free(f);
1968 }
1969 void update_settings(window_settings * ws)
1970 {
1971 #if 0
1972     //assumes ws is fully allocated
1973 
1974     GdkDisplay *gdkdisplay;
1975 
1976     // Display    *xdisplay;
1977     GdkScreen *gdkscreen;
1978     WnckScreen *screen = wnck_screen_get_default();
1979     GList *windows;
1980 #endif
1981 
1982     load_settings(ws);
1983 
1984 #if 0
1985     gdkdisplay = gdk_display_get_default();
1986     // xdisplay   = gdk_x11_display_get_xdisplay (gdkdisplay);
1987     gdkscreen = gdk_display_get_default_screen(gdkdisplay);
1988 #endif
1989 
1990     titlebar_font_changed(ws);
1991     update_window_extents(ws);
1992     update_shadow(ws->fs_act);
1993 #if 0
1994     update_default_decorations(gdkscreen, ws->fs_act, ws->fs_inact);
1995 
1996     windows = wnck_screen_get_windows(screen);
1997     while (windows)
1998     {
1999         decor_t *d = g_object_get_data(G_OBJECT(windows->data), "decor");
2000 
2001         if (d->decorated)
2002         {
2003             d->width = d->height = 0;
2004             update_window_decoration_size(WNCK_WINDOW(windows->data));
2005             update_event_windows(WNCK_WINDOW(windows->data));
2006         }
2007         windows = windows->next;
2008     }
2009 #endif
2010 }
2011 
2012 window_settings *create_settings()
2013 {
2014     gchar *engine = NULL;
2015     int i;
2016 
2017     frame_settings *pfs;
2018     window_settings *ws;
2019 
2020     ws = malloc(sizeof(window_settings));
2021     bzero(ws, sizeof(window_settings));
2022 #if 0
2023     global_ws = ws;
2024     setlocale(LC_ALL, "");
2025     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
2026     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
2027     textdomain(GETTEXT_PACKAGE);
2028 #endif
2029 
2030     ws->win_extents.left = 6;
2031     ws->win_extents.top = 4;
2032     ws->win_extents.right = 6;
2033     ws->win_extents.bottom = 6;
2034     ws->corner_radius = 5;
2035     ws->shadow_radius = 15;
2036     ws->shadow_opacity = .8;
2037     ws->min_titlebar_height = 17;
2038     ws->double_click_action = DOUBLE_CLICK_SHADE;
2039     ws->button_hover_cursor = 1;
2040     ws->button_offset = 1;
2041     ws->button_hoffset = 1;
2042     ws->button_fade_step_duration = 50;
2043     ws->button_fade_num_steps = 5;
2044     ws->blur_type = BLUR_TYPE_NONE;
2045 
2046     ws->tobj_layout = g_strdup("IT::HNXC");     // DEFAULT TITLE OBJECT LAYOUT, does not use any odd buttons
2047     //ws->tobj_layout=g_strdup("CNX:IT:HM");
2048 
2049     pfs = malloc(sizeof(frame_settings));
2050     bzero(pfs, sizeof(frame_settings));
2051     pfs->ws = ws;
2052     ACOLOR(text, 1.0, 1.0, 1.0, 1.0);
2053     ACOLOR(text_halo, 0.0, 0.0, 0.0, 0.2);
2054     ACOLOR(button, 1.0, 1.0, 1.0, 0.8);
2055     ACOLOR(button_halo, 0.0, 0.0, 0.0, 0.2);
2056     ws->fs_act = pfs;
2057 
2058     pfs = malloc(sizeof(frame_settings));
2059     bzero(pfs, sizeof(frame_settings));
2060     pfs->ws = ws;
2061     ACOLOR(text, 0.8, 0.8, 0.8, 0.8);
2062     ACOLOR(text_halo, 0.0, 0.0, 0.0, 0.2);
2063     ACOLOR(button, 0.8, 0.8, 0.8, 0.8);
2064     ACOLOR(button_halo, 0.0, 0.0, 0.0, 0.2);
2065     ws->fs_inact = pfs;
2066 
2067     ws->round_top_left = TRUE;
2068     ws->round_top_right = TRUE;
2069     ws->round_bottom_left = TRUE;
2070     ws->round_bottom_right = TRUE;
2071 
2072     engine = g_strdup("legacy");
2073     load_engine(engine, ws);    // assumed to always return TRUE
2074 
2075 //    program_name = argv[0];
2076 
2077     //ws->ButtonBase = NULL;
2078     for (i = 0; i < (S_COUNT * B_COUNT); i++)
2079     {
2080         ws->ButtonPix[i] = NULL;
2081     }
2082     return ws;
2083 }
2084