Merge branch 'buttons' into wip/mikabox
authorMikael Magnusson <mikachu@gmail.com>
Sun, 13 Jul 2008 16:10:52 +0000 (18:10 +0200)
committerMikael Magnusson <mikachu@gmail.com>
Sun, 13 Jul 2008 16:20:02 +0000 (18:20 +0200)
Conflicts:
openbox/client_menu.c
openbox/framerender.c
render/render.c
render/render.h
render/theme.c
render/theme.h

1  2 
Makefile.am
openbox/client_menu.c
openbox/framerender.c
openbox/prompt.c
render/render.c
render/render.h
render/theme.c
render/theme.h

diff --cc Makefile.am
Simple merge
index 171ec16ddf37e256d2a93d7ad9c677045a5baef2,ee0d067c31eaf6e0f1860901e774f787bdee86ea..faeab2a8c2080206f1452a91e4625e7ef7077188
@@@ -239,52 -237,44 +239,52 @@@ static void layer_menu_execute(ObMenuEn
  static gboolean send_to_menu_update(ObMenuFrame *frame, gpointer data)
  {
      ObMenu *menu = frame->menu;
 +    ObClient *c = frame->client;
      guint i;
      ObMenuEntry *e;
 +    GList *it;
  
 -    menu_clear_entries(menu);
 -
 -    if (frame->client == NULL || !client_normal(frame->client))
 +    if (c == NULL || !client_normal(c))
          return FALSE; /* don't show the menu */
  
 -    for (i = 0; i <= screen_num_desktops; ++i) {
 -        const gchar *name;
 -        guint desk;
 +    if (!data)
 +        menu_clear_entries(menu);
  
 -        if (i >= screen_num_desktops) {
 -            menu_add_separator(menu, -1, NULL);
 +    if (!menu->entries) {
 +        for (i = 0; i <= screen_num_desktops; ++i) {
 +            const gchar *name;
 +            guint desk;
  
 -            desk = DESKTOP_ALL;
 -            name = _("All desktops");
 -        } else {
 -            desk = i;
 -            name = screen_desktop_names[i];
 -        }
 +            if (i == screen_num_desktops) {
 +                menu_add_separator(menu, -1, NULL);
  
 -        e = menu_add_normal(menu, desk, name, NULL, FALSE);
 -        e->id = desk;
 -        if (desk == DESKTOP_ALL) {
 -            e->data.normal.mask = ob_rr_theme->btn_desk->mask;
 -            e->data.normal.mask_normal_color = ob_rr_theme->menu_color;
 -            e->data.normal.mask_selected_color =
 -                ob_rr_theme->menu_selected_color;
 -            e->data.normal.mask_disabled_color =
 -                ob_rr_theme->menu_disabled_color;
 -            e->data.normal.mask_disabled_selected_color =
 -                ob_rr_theme->menu_disabled_selected_color;
 +                desk = DESKTOP_ALL;
 +                name = _("All desktops");
 +            } else {
 +                desk = i;
 +                name = screen_desktop_names[i];
 +            }
 +
 +            e = menu_add_normal(menu, desk, name, NULL, FALSE);
 +            e->id = desk;
          }
 +    }
 +
 +    for (it = menu->entries; it; it = g_list_next(it)) {
 +        ObMenuEntry *e = it->data;
 +        guint desk = e->id;
  
 -        if (frame->client->desktop == desk)
 -            e->data.normal.enabled = FALSE;
 +        e->data.normal.enabled = c->desktop != desk;
 +
 +        if ((desk == DESKTOP_ALL && c->desktop != DESKTOP_ALL) ||
 +            (c->desktop == DESKTOP_ALL && desk == screen_desktop))
 +        {
-             e->data.normal.mask = ob_rr_theme->desk_mask;
++            e->data.normal.mask = ob_rr_theme->btn_desk->mask;
 +            set_icon_color(e);
 +        } else
 +            e->data.normal.mask = NULL;
      }
 +
      return TRUE; /* show the menu */
  }
  
@@@ -395,20 -382,32 +395,20 @@@ void client_menu_startup(void
      menu_add_submenu(menu, CLIENT_LAYER, LAYER_MENU_NAME);
  
      e = menu_add_normal(menu, CLIENT_RESTORE, _("R_estore"), NULL, TRUE);
-     e->data.normal.mask = ob_rr_theme->max_toggled_mask;
+     e->data.normal.mask = ob_rr_theme->btn_max->toggled_mask;
 -    e->data.normal.mask_normal_color = ob_rr_theme->menu_color;
 -    e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color;
 -    e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color;
 -    e->data.normal.mask_disabled_selected_color =
 -        ob_rr_theme->menu_disabled_selected_color;
 +    set_icon_color(e);
  
      menu_add_normal(menu, CLIENT_MOVE, _("_Move"), NULL, TRUE);
  
      menu_add_normal(menu, CLIENT_RESIZE, _("Resi_ze"), NULL, TRUE);
  
      e = menu_add_normal(menu, CLIENT_ICONIFY, _("Ico_nify"), NULL, TRUE);
-     e->data.normal.mask = ob_rr_theme->iconify_mask;
+     e->data.normal.mask = ob_rr_theme->btn_iconify->mask;
 -    e->data.normal.mask_normal_color = ob_rr_theme->menu_color;
 -    e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color;
 -    e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color;
 -    e->data.normal.mask_disabled_selected_color =
 -        ob_rr_theme->menu_disabled_selected_color;
 +    set_icon_color(e);
  
      e = menu_add_normal(menu, CLIENT_MAXIMIZE, _("Ma_ximize"), NULL, TRUE);
-     e->data.normal.mask = ob_rr_theme->max_mask;
+     e->data.normal.mask = ob_rr_theme->btn_max->mask;
 -    e->data.normal.mask_normal_color = ob_rr_theme->menu_color;
 -    e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color;
 -    e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color;
 -    e->data.normal.mask_disabled_selected_color =
 -        ob_rr_theme->menu_disabled_selected_color;
 +    set_icon_color(e);
  
      menu_add_normal(menu, CLIENT_SHADE, _("_Roll up/down"), NULL, TRUE);
  
      menu_add_separator(menu, -1, NULL);
  
      e = menu_add_normal(menu, CLIENT_CLOSE, _("_Close"), NULL, TRUE);
-     e->data.normal.mask = ob_rr_theme->close_mask;
+     e->data.normal.mask = ob_rr_theme->btn_close->mask;
 -    e->data.normal.mask_normal_color = ob_rr_theme->menu_color;
 -    e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color;
 -    e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color;
 -    e->data.normal.mask_disabled_selected_color =
 -        ob_rr_theme->menu_disabled_selected_color;
 +    set_icon_color(e);
  }
index bf71d2c34a937097f59557a6f320a49196839aa0,57425059c2f4d25129c388cf888b8b06ba68b82e..2a126532f8353a38582627617ccbe2aae24c7f67
@@@ -124,119 -124,121 +124,119 @@@ void framerender_frame(ObFrame *self
      if (self->decorations & OB_FRAME_DECOR_TITLEBAR) {
          RrAppearance *t, *l, *m, *n, *i, *d, *s, *c, *clear;
          if (self->focused) {
 -
 -            t = self->a_focused_title;
 -            l = self->a_focused_label;
 -
 +            t = ob_rr_theme->a_focused_title;
 +            l = ob_rr_theme->a_focused_label;
              m = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ?
-                  ob_rr_theme->a_disabled_focused_max :
+                  ob_rr_theme->btn_max->a_disabled_focused :
                   (self->client->max_vert || self->client->max_horz ?
                    (self->max_press ?
-                    ob_rr_theme->a_toggled_focused_pressed_max :
+                    ob_rr_theme->btn_max->a_toggled_focused_pressed :
                     (self->max_hover ?
-                     ob_rr_theme->a_toggled_hover_focused_max :
-                     ob_rr_theme->a_toggled_focused_unpressed_max)) :
+                     ob_rr_theme->btn_max->a_toggled_hover_focused :
+                     ob_rr_theme->btn_max->a_toggled_focused_unpressed)) :
                    (self->max_press ?
-                    ob_rr_theme->a_focused_pressed_max :
+                    ob_rr_theme->btn_max->a_focused_pressed :
                     (self->max_hover ?
-                     ob_rr_theme->a_hover_focused_max :
-                     ob_rr_theme->a_focused_unpressed_max))));
+                     ob_rr_theme->btn_max->a_hover_focused :
+                     ob_rr_theme->btn_max->a_focused_unpressed))));
 -            n = self->a_icon;
 +            n = ob_rr_theme->a_icon;
              i = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ?
-                  ob_rr_theme->a_disabled_focused_iconify :
+                  ob_rr_theme->btn_iconify->a_disabled_focused :
                   (self->iconify_press ?
-                   ob_rr_theme->a_focused_pressed_iconify :
+                   ob_rr_theme->btn_iconify->a_focused_pressed :
                    (self->iconify_hover ?
-                    ob_rr_theme->a_hover_focused_iconify :
-                    ob_rr_theme->a_focused_unpressed_iconify)));
+                    ob_rr_theme->btn_iconify->a_hover_focused :
+                    ob_rr_theme->btn_iconify->a_focused_unpressed)));
              d = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ?
-                  ob_rr_theme->a_disabled_focused_desk :
+                  ob_rr_theme->btn_desk->a_disabled_focused :
                   (self->client->desktop == DESKTOP_ALL ?
                    (self->desk_press ?
-                    ob_rr_theme->a_toggled_focused_pressed_desk :
+                    ob_rr_theme->btn_desk->a_toggled_focused_pressed :
                     (self->desk_hover ?
-                     ob_rr_theme->a_toggled_hover_focused_desk :
-                     ob_rr_theme->a_toggled_focused_unpressed_desk)) :
+                     ob_rr_theme->btn_desk->a_toggled_hover_focused :
+                     ob_rr_theme->btn_desk->a_toggled_focused_unpressed)) :
                    (self->desk_press ?
-                    ob_rr_theme->a_focused_pressed_desk :
+                    ob_rr_theme->btn_desk->a_focused_pressed :
                     (self->desk_hover ?
-                     ob_rr_theme->a_hover_focused_desk :
-                     ob_rr_theme->a_focused_unpressed_desk))));
+                     ob_rr_theme->btn_desk->a_hover_focused :
+                     ob_rr_theme->btn_desk->a_focused_unpressed))));
              s = (!(self->decorations & OB_FRAME_DECOR_SHADE) ?
-                  ob_rr_theme->a_disabled_focused_shade :
+                  ob_rr_theme->btn_shade->a_disabled_focused :
                   (self->client->shaded ?
                    (self->shade_press ?
-                    ob_rr_theme->a_toggled_focused_pressed_shade :
+                    ob_rr_theme->btn_shade->a_toggled_focused_pressed :
                     (self->shade_hover ?
-                     ob_rr_theme->a_toggled_hover_focused_shade :
-                     ob_rr_theme->a_toggled_focused_unpressed_shade)) :
+                     ob_rr_theme->btn_shade->a_toggled_hover_focused :
+                     ob_rr_theme->btn_shade->a_toggled_focused_unpressed)) :
                    (self->shade_press ?
-                    ob_rr_theme->a_focused_pressed_shade :
+                    ob_rr_theme->btn_shade->a_focused_pressed :
                     (self->shade_hover ?
-                     ob_rr_theme->a_hover_focused_shade :
-                     ob_rr_theme->a_focused_unpressed_shade))));
+                     ob_rr_theme->btn_shade->a_hover_focused :
+                     ob_rr_theme->btn_shade->a_focused_unpressed))));
              c = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ?
-                  ob_rr_theme->a_disabled_focused_close :
+                  ob_rr_theme->btn_close->a_disabled_focused :
                   (self->close_press ?
-                   ob_rr_theme->a_focused_pressed_close :
+                   ob_rr_theme->btn_close->a_focused_pressed :
                    (self->close_hover ?
-                    ob_rr_theme->a_hover_focused_close :
-                    ob_rr_theme->a_focused_unpressed_close)));
+                    ob_rr_theme->btn_close->a_hover_focused :
+                    ob_rr_theme->btn_close->a_focused_unpressed)));
          } else {
 -            t = self->a_unfocused_title;
 -            l = self->a_unfocused_label;
 +            t = ob_rr_theme->a_unfocused_title;
 +            l = ob_rr_theme->a_unfocused_label;
              m = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ?
-                  ob_rr_theme->a_disabled_unfocused_max :
+                  ob_rr_theme->btn_max->a_disabled_unfocused :
                   (self->client->max_vert || self->client->max_horz ?
                    (self->max_press ?
-                    ob_rr_theme->a_toggled_unfocused_pressed_max :
+                    ob_rr_theme->btn_max->a_toggled_unfocused_pressed :
                     (self->max_hover ?
-                     ob_rr_theme->a_toggled_hover_unfocused_max :
-                     ob_rr_theme->a_toggled_unfocused_unpressed_max)) :
+                     ob_rr_theme->btn_max->a_toggled_hover_unfocused :
+                     ob_rr_theme->btn_max->a_toggled_unfocused_unpressed)) :
                    (self->max_press ?
-                    ob_rr_theme->a_unfocused_pressed_max :
+                    ob_rr_theme->btn_max->a_unfocused_pressed :
                     (self->max_hover ?
-                     ob_rr_theme->a_hover_unfocused_max :
-                     ob_rr_theme->a_unfocused_unpressed_max))));
+                     ob_rr_theme->btn_max->a_hover_unfocused :
+                     ob_rr_theme->btn_max->a_unfocused_unpressed))));
 -            n = self->a_icon;
 +            n = ob_rr_theme->a_icon;
              i = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ?
-                  ob_rr_theme->a_disabled_unfocused_iconify :
+                  ob_rr_theme->btn_iconify->a_disabled_unfocused :
                   (self->iconify_press ?
-                   ob_rr_theme->a_unfocused_pressed_iconify :
+                   ob_rr_theme->btn_iconify->a_unfocused_pressed :
                    (self->iconify_hover ?
-                    ob_rr_theme->a_hover_unfocused_iconify :
-                    ob_rr_theme->a_unfocused_unpressed_iconify)));
+                    ob_rr_theme->btn_iconify->a_hover_unfocused :
+                    ob_rr_theme->btn_iconify->a_unfocused_unpressed)));
              d = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ?
-                  ob_rr_theme->a_disabled_unfocused_desk :
+                  ob_rr_theme->btn_desk->a_disabled_unfocused :
                   (self->client->desktop == DESKTOP_ALL ?
                    (self->desk_press ?
-                    ob_rr_theme->a_toggled_unfocused_pressed_desk :
+                    ob_rr_theme->btn_desk->a_toggled_unfocused_pressed :
                     (self->desk_hover ?
-                     ob_rr_theme->a_toggled_hover_unfocused_desk :
-                     ob_rr_theme->a_toggled_unfocused_unpressed_desk)) :
+                     ob_rr_theme->btn_desk->a_toggled_hover_unfocused :
+                     ob_rr_theme->btn_desk->a_toggled_unfocused_unpressed)) :
                    (self->desk_press ?
-                    ob_rr_theme->a_unfocused_pressed_desk :
+                    ob_rr_theme->btn_desk->a_unfocused_pressed :
                     (self->desk_hover ?
-                     ob_rr_theme->a_hover_unfocused_desk :
-                     ob_rr_theme->a_unfocused_unpressed_desk))));
+                     ob_rr_theme->btn_desk->a_hover_unfocused :
+                     ob_rr_theme->btn_desk->a_unfocused_unpressed))));
              s = (!(self->decorations & OB_FRAME_DECOR_SHADE) ?
-                  ob_rr_theme->a_disabled_unfocused_shade :
+                  ob_rr_theme->btn_shade->a_disabled_unfocused :
                   (self->client->shaded ?
                    (self->shade_press ?
-                    ob_rr_theme->a_toggled_unfocused_pressed_shade :
+                    ob_rr_theme->btn_shade->a_toggled_unfocused_pressed :
                     (self->shade_hover ?
-                     ob_rr_theme->a_toggled_hover_unfocused_shade :
-                     ob_rr_theme->a_toggled_unfocused_unpressed_shade)) :
+                     ob_rr_theme->btn_shade->a_toggled_hover_unfocused :
+                     ob_rr_theme->btn_shade->a_toggled_unfocused_unpressed)) :
                    (self->shade_press ?
-                    ob_rr_theme->a_unfocused_pressed_shade :
+                    ob_rr_theme->btn_shade->a_unfocused_pressed :
                     (self->shade_hover ?
-                     ob_rr_theme->a_hover_unfocused_shade :
-                     ob_rr_theme->a_unfocused_unpressed_shade))));
+                     ob_rr_theme->btn_shade->a_hover_unfocused :
+                     ob_rr_theme->btn_shade->a_unfocused_unpressed))));
              c = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ?
-                  ob_rr_theme->a_disabled_unfocused_close :
+                  ob_rr_theme->btn_close->a_disabled_unfocused :
                   (self->close_press ?
-                   ob_rr_theme->a_unfocused_pressed_close :
+                   ob_rr_theme->btn_close->a_unfocused_pressed :
                    (self->close_hover ?
-                    ob_rr_theme->a_hover_unfocused_close :
-                    ob_rr_theme->a_unfocused_unpressed_close)));
+                    ob_rr_theme->btn_close->a_hover_unfocused :
+                    ob_rr_theme->btn_close->a_unfocused_unpressed)));
          }
          clear = ob_rr_theme->a_clear;
  
index 52223f1949911e477a9449502be81e13b8cbb86a,0000000000000000000000000000000000000000..720bb3103919d87c795f33f74860fb7c2d0fe81b
mode 100644,000000..100644
--- /dev/null
@@@ -1,653 -1,0 +1,653 @@@
-     prompt_a_button = RrAppearanceCopy(ob_rr_theme->a_focused_unpressed_close);
-     prompt_a_focus = RrAppearanceCopy(ob_rr_theme->a_hover_focused_close);
-     prompt_a_press = RrAppearanceCopy(ob_rr_theme->a_focused_pressed_close);
-     prompt_a_pfocus = RrAppearanceCopy(ob_rr_theme->a_focused_pressed_close);
 +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 +
 +   prompt.c for the Openbox window manager
 +   Copyright (c) 2008        Dana Jansens
 +
 +   This program is free software; you can redistribute it and/or modify
 +   it under the terms of the GNU General Public License as published by
 +   the Free Software Foundation; either version 2 of the License, or
 +   (at your option) any later version.
 +
 +   This program is distributed in the hope that it will be useful,
 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +   GNU General Public License for more details.
 +
 +   See the COPYING file for a copy of the GNU General Public License.
 +*/
 +
 +#include "prompt.h"
 +#include "openbox.h"
 +#include "screen.h"
 +#include "client.h"
 +#include "group.h"
 +#include "event.h"
 +#include "obt/display.h"
 +#include "obt/keyboard.h"
 +#include "obt/prop.h"
 +#include "gettext.h"
 +
 +static GList *prompt_list = NULL;
 +
 +/* we construct these */
 +static RrAppearance *prompt_a_bg;
 +static RrAppearance *prompt_a_button;
 +static RrAppearance *prompt_a_focus;
 +static RrAppearance *prompt_a_press;
 +static RrAppearance *prompt_a_pfocus;
 +/* we change the max width which would screw with others */
 +static RrAppearance *prompt_a_msg;
 +
 +/* sizing stuff */
 +#define OUTSIDE_MARGIN 4
 +#define MSG_BUTTON_SEPARATION 4
 +#define BUTTON_SEPARATION 4
 +#define BUTTON_VMARGIN 4
 +#define BUTTON_HMARGIN 12
 +#define MAX_WIDTH 400
 +
 +static void prompt_layout(ObPrompt *self);
 +static void render_all(ObPrompt *self);
 +static void render_button(ObPrompt *self, ObPromptElement *e);
 +static void prompt_resize(ObPrompt *self, gint w, gint h);
 +static void prompt_run_callback(ObPrompt *self, gint result);
 +
 +void prompt_startup(gboolean reconfig)
 +{
 +    RrColor *c_button, *c_focus, *c_press, *c_pfocus;
 +
 +    /* note: this is not a copy, don't free it */
 +    prompt_a_bg = ob_rr_theme->osd_hilite_bg;
 +
++    prompt_a_button = RrAppearanceCopy(ob_rr_theme->btn_close->a_focused_unpressed);
++    prompt_a_focus = RrAppearanceCopy(ob_rr_theme->btn_close->a_hover_focused);
++    prompt_a_press = RrAppearanceCopy(ob_rr_theme->btn_close->a_focused_pressed);
++    prompt_a_pfocus = RrAppearanceCopy(ob_rr_theme->btn_close->a_focused_pressed);
 +
 +    c_button = prompt_a_button->texture[0].data.mask.color;
 +    c_focus = prompt_a_focus->texture[0].data.mask.color;
 +    c_press = prompt_a_press->texture[0].data.mask.color;
 +    c_pfocus = prompt_a_press->texture[0].data.mask.color;
 +
 +    RrAppearanceRemoveTextures(prompt_a_button);
 +    RrAppearanceRemoveTextures(prompt_a_focus);
 +    RrAppearanceRemoveTextures(prompt_a_press);
 +    RrAppearanceRemoveTextures(prompt_a_pfocus);
 +
 +    /* texture[0] is the text and texture[1-4] (for prompt_a_focus and
 +       prompt_a_pfocus) is lineart to show where keyboard focus is */
 +    RrAppearanceAddTextures(prompt_a_button, 1);
 +    RrAppearanceAddTextures(prompt_a_focus, 5);
 +    RrAppearanceAddTextures(prompt_a_press, 1);
 +    RrAppearanceAddTextures(prompt_a_pfocus, 5);
 +
 +    /* totally cheating here.. */
 +    prompt_a_button->texture[0] = ob_rr_theme->osd_hilite_label->texture[0];
 +    prompt_a_focus->texture[0] = ob_rr_theme->osd_hilite_label->texture[0];
 +    prompt_a_press->texture[0] = ob_rr_theme->osd_hilite_label->texture[0];
 +    prompt_a_pfocus->texture[0] = ob_rr_theme->osd_hilite_label->texture[0];
 +
 +    prompt_a_button->texture[0].data.text.justify = RR_JUSTIFY_CENTER;
 +    prompt_a_focus->texture[0].data.text.justify = RR_JUSTIFY_CENTER;
 +    prompt_a_press->texture[0].data.text.justify = RR_JUSTIFY_CENTER;
 +    prompt_a_pfocus->texture[0].data.text.justify = RR_JUSTIFY_CENTER;
 +
 +    prompt_a_button->texture[0].data.text.color = c_button;
 +    prompt_a_focus->texture[0].data.text.color = c_focus;
 +    prompt_a_press->texture[0].data.text.color = c_press;
 +    prompt_a_pfocus->texture[0].data.text.color = c_press;
 +
 +    prompt_a_focus->texture[1].data.lineart.color = c_focus;
 +    prompt_a_focus->texture[2].data.lineart.color = c_focus;
 +    prompt_a_focus->texture[3].data.lineart.color = c_focus;
 +    prompt_a_focus->texture[4].data.lineart.color = c_focus;
 +
 +    prompt_a_pfocus->texture[1].data.lineart.color = c_press;
 +    prompt_a_pfocus->texture[2].data.lineart.color = c_press;
 +    prompt_a_pfocus->texture[3].data.lineart.color = c_press;
 +    prompt_a_pfocus->texture[4].data.lineart.color = c_press;
 +
 +    prompt_a_msg = RrAppearanceCopy(ob_rr_theme->osd_hilite_label);
 +    prompt_a_msg->texture[0].data.text.flow = TRUE;
 +
 +    if (reconfig) {
 +        GList *it;
 +        for (it = prompt_list; it; it = g_list_next(it)) {
 +            ObPrompt *p = it->data;
 +            prompt_layout(p);
 +            render_all(p);
 +        }
 +    }
 +}
 +
 +void prompt_shutdown(gboolean reconfig)
 +{
 +    GList *it;
 +
 +    if (!reconfig) {
 +        for (it = prompt_list; it; it = g_list_next(it)) {
 +            ObPrompt *p = it->data;
 +            if (p->cleanup) p->cleanup(p, p->data);
 +        }
 +
 +        g_assert(prompt_list == NULL);
 +    }
 +
 +    RrAppearanceFree(prompt_a_button);
 +    RrAppearanceFree(prompt_a_focus);
 +    RrAppearanceFree(prompt_a_press);
 +    RrAppearanceFree(prompt_a_pfocus);
 +    RrAppearanceFree(prompt_a_msg);
 +}
 +
 +ObPrompt* prompt_new(const gchar *msg, const gchar *title,
 +                     const ObPromptAnswer *answers, gint n_answers,
 +                     gint default_result, gint cancel_result,
 +                     ObPromptCallback func, ObPromptCleanup cleanup,
 +                     gpointer data)
 +{
 +    ObPrompt *self;
 +    XSetWindowAttributes attrib;
 +    gint i;
 +
 +    attrib.override_redirect = FALSE;
 +
 +    self = g_new0(ObPrompt, 1);
 +    self->ref = 1;
 +    self->func = func;
 +    self->cleanup = cleanup;
 +    self->data = data;
 +    self->default_result = default_result;
 +    self->cancel_result = cancel_result;
 +    self->super.type = OB_WINDOW_CLASS_PROMPT;
 +    self->super.window = XCreateWindow(obt_display, obt_root(ob_screen),
 +                                       0, 0, 1, 1, 0,
 +                                       CopyFromParent, InputOutput,
 +                                       CopyFromParent,
 +                                       CWOverrideRedirect,
 +                                       &attrib);
 +
 +    /* make it a dialog type window */
 +    OBT_PROP_SET32(self->super.window, NET_WM_WINDOW_TYPE, ATOM,
 +                   OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG));
 +
 +    /* set the window's title */
 +    if (title)
 +        OBT_PROP_SETS(self->super.window, NET_WM_NAME, utf8, title);
 +
 +    /* listen for key presses on the window */
 +    self->event_mask = KeyPressMask;
 +
 +    /* set up the text message widow */
 +    self->msg.text = g_strdup(msg);
 +    self->msg.window = XCreateWindow(obt_display, self->super.window,
 +                                     0, 0, 1, 1, 0,
 +                                     CopyFromParent, InputOutput,
 +                                     CopyFromParent, 0, NULL);
 +    XMapWindow(obt_display, self->msg.window);
 +
 +    /* set up the buttons from the answers */
 +
 +    self->n_buttons = n_answers;
 +    if (!self->n_buttons)
 +        self->n_buttons = 1;
 +
 +    self->button = g_new0(ObPromptElement, self->n_buttons);
 +
 +    if (n_answers == 0) {
 +        g_assert(self->n_buttons == 1); /* should be set to this above.. */
 +        self->button[0].text = g_strdup(_("OK"));
 +    }
 +    else {
 +        g_assert(self->n_buttons > 0);
 +        for (i = 0; i < self->n_buttons; ++i) {
 +            self->button[i].text = g_strdup(answers[i].text);
 +            self->button[i].result = answers[i].result;
 +        }
 +    }
 +
 +    for (i = 0; i < self->n_buttons; ++i) {
 +        self->button[i].window = XCreateWindow(obt_display, self->super.window,
 +                                               0, 0, 1, 1, 0,
 +                                               CopyFromParent, InputOutput,
 +                                               CopyFromParent, 0, NULL);
 +        XMapWindow(obt_display, self->button[i].window);
 +        window_add(&self->button[i].window, PROMPT_AS_WINDOW(self));
 +
 +        /* listen for button presses on the buttons */
 +        XSelectInput(obt_display, self->button[i].window,
 +                     ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
 +    }
 +
 +    prompt_list = g_list_prepend(prompt_list, self);
 +
 +    return self;
 +}
 +
 +void prompt_ref(ObPrompt *self)
 +{
 +    ++self->ref;
 +}
 +
 +void prompt_unref(ObPrompt *self)
 +{
 +    if (self && --self->ref == 0) {
 +        gint i;
 +
 +        if (self->mapped)
 +            prompt_hide(self);
 +
 +        prompt_list = g_list_remove(prompt_list, self);
 +
 +        for (i = 0; i < self->n_buttons; ++i) {
 +            window_remove(self->button[i].window);
 +            XDestroyWindow(obt_display, self->button[i].window);
 +        }
 +
 +        XDestroyWindow(obt_display, self->msg.window);
 +        XDestroyWindow(obt_display, self->super.window);
 +        g_free(self);
 +    }
 +}
 +
 +static void prompt_layout(ObPrompt *self)
 +{
 +    gint l, r, t, b;
 +    gint i;
 +    gint allbuttonsw, allbuttonsh, buttonx;
 +    gint w, h;
 +    gint maxw;
 +
 +    RrMargins(prompt_a_bg, &l, &t, &r, &b);
 +    l += OUTSIDE_MARGIN;
 +    t += OUTSIDE_MARGIN;
 +    r += OUTSIDE_MARGIN;
 +    b += OUTSIDE_MARGIN;
 +
 +    {
 +        Rect *area = screen_physical_area_all_monitors();
 +        maxw = MIN(MAX_WIDTH, area->width*4/5);
 +        g_free(area);
 +    }
 +
 +    /* find the button sizes and how much space we need for them */
 +    allbuttonsw = allbuttonsh = 0;
 +    for (i = 0; i < self->n_buttons; ++i) {
 +        gint bw, bh;
 +
 +        prompt_a_button->texture[0].data.text.string = self->button[i].text;
 +        prompt_a_focus->texture[0].data.text.string = self->button[i].text;
 +        prompt_a_press->texture[0].data.text.string = self->button[i].text;
 +        prompt_a_pfocus->texture[0].data.text.string = self->button[i].text;
 +        RrMinSize(prompt_a_button, &bw, &bh);
 +        self->button[i].width = bw;
 +        self->button[i].height = bh;
 +        RrMinSize(prompt_a_focus, &bw, &bh);
 +        self->button[i].width = MAX(self->button[i].width, bw);
 +        self->button[i].height = MAX(self->button[i].height, bh);
 +        RrMinSize(prompt_a_press, &bw, &bh);
 +        self->button[i].width = MAX(self->button[i].width, bw);
 +        self->button[i].height = MAX(self->button[i].height, bh);
 +        RrMinSize(prompt_a_pfocus, &bw, &bh);
 +        self->button[i].width = MAX(self->button[i].width, bw);
 +        self->button[i].height = MAX(self->button[i].height, bh);
 +
 +        self->button[i].width += BUTTON_HMARGIN * 2;
 +        self->button[i].height += BUTTON_VMARGIN * 2;
 +
 +        allbuttonsw += self->button[i].width + (i > 0 ? BUTTON_SEPARATION : 0);
 +        allbuttonsh = MAX(allbuttonsh, self->button[i].height);
 +    }
 +
 +    self->msg_wbound = MAX(allbuttonsw, maxw);
 +
 +    /* measure the text message area */
 +    prompt_a_msg->texture[0].data.text.string = self->msg.text;
 +    prompt_a_msg->texture[0].data.text.maxwidth = self->msg_wbound;
 +    RrMinSize(prompt_a_msg, &self->msg.width, &self->msg.height);
 +
 +    /* width and height inside the outer margins */
 +    w = MAX(self->msg.width, allbuttonsw);
 +    h = self->msg.height + MSG_BUTTON_SEPARATION + allbuttonsh;
 +
 +    /* position the text message */
 +    self->msg.x = l + (w - self->msg.width) / 2;
 +    self->msg.y = t;
 +
 +    /* position the button buttons on the right of the dialog */
 +    buttonx = l + w;
 +    for (i = self->n_buttons - 1; i >= 0; --i) {
 +        self->button[i].x = buttonx - self->button[i].width;
 +        buttonx -= self->button[i].width + BUTTON_SEPARATION;
 +        self->button[i].y = t + h - allbuttonsh;
 +        self->button[i].y += (allbuttonsh - self->button[i].height) / 2;
 +    }
 +
 +    /* size and position the toplevel window */
 +    prompt_resize(self, w + l + r, h + t + b);
 +
 +    /* move and resize the internal windows */
 +    XMoveResizeWindow(obt_display, self->msg.window,
 +                      self->msg.x, self->msg.y,
 +                      self->msg.width, self->msg.height);
 +    for (i = 0; i < self->n_buttons; ++i)
 +        XMoveResizeWindow(obt_display, self->button[i].window,
 +                          self->button[i].x, self->button[i].y,
 +                          self->button[i].width, self->button[i].height);
 +}
 +
 +static void prompt_resize(ObPrompt *self, gint w, gint h)
 +{
 +    XConfigureRequestEvent req;
 +    XSizeHints hints;
 +
 +    self->width = w;
 +    self->height = h;
 +
 +    /* the user can't resize the prompt */
 +    hints.flags = PMinSize | PMaxSize;
 +    hints.min_width = hints.max_width = w;
 +    hints.min_height = hints.max_height = h;
 +    XSetWMNormalHints(obt_display, self->super.window, &hints);
 +
 +    if (self->mapped) {
 +        /* send a configure request like a normal client would */
 +        req.type = ConfigureRequest;
 +        req.display = obt_display;
 +        req.parent = obt_root(ob_screen);
 +        req.window = self->super.window;
 +        req.width = w;
 +        req.height = h;
 +        req.value_mask = CWWidth | CWHeight;
 +        XSendEvent(req.display, req.window, FALSE, StructureNotifyMask,
 +                   (XEvent*)&req);
 +    }
 +    else
 +        XResizeWindow(obt_display, self->super.window, w, h);
 +}
 +
 +static void setup_button_focus_tex(ObPromptElement *e, RrAppearance *a,
 +                                   gboolean on)
 +{
 +    gint i, l, r, t, b;
 +
 +    for (i = 1; i < 5; ++i)
 +        a->texture[i].type = on ? RR_TEXTURE_LINE_ART : RR_TEXTURE_NONE;
 +
 +    if (!on) return;
 +
 +    RrMargins(a, &l, &t, &r, &b);
 +    l += MIN(BUTTON_HMARGIN, BUTTON_VMARGIN) / 2;
 +    r += MIN(BUTTON_HMARGIN, BUTTON_VMARGIN) / 2;
 +    t += MIN(BUTTON_HMARGIN, BUTTON_VMARGIN) / 2;
 +    b += MIN(BUTTON_HMARGIN, BUTTON_VMARGIN) / 2;
 +
 +    /* top line */
 +    a->texture[1].data.lineart.x1 = l;
 +    a->texture[1].data.lineart.x2 = e->width - r - 1;
 +    a->texture[1].data.lineart.y1 = t;
 +    a->texture[1].data.lineart.y2 = t;
 +
 +    /* bottom line */
 +    a->texture[2].data.lineart.x1 = l;
 +    a->texture[2].data.lineart.x2 = e->width - r - 1;
 +    a->texture[2].data.lineart.y1 = e->height - b - 1;
 +    a->texture[2].data.lineart.y2 = e->height - b - 1;
 +
 +    /* left line */
 +    a->texture[3].data.lineart.x1 = l;
 +    a->texture[3].data.lineart.x2 = l;
 +    a->texture[3].data.lineart.y1 = t;
 +    a->texture[3].data.lineart.y2 = e->height - b - 1;
 +
 +    /* right line */
 +    a->texture[4].data.lineart.x1 = e->width - r - 1;
 +    a->texture[4].data.lineart.x2 = e->width - r - 1;
 +    a->texture[4].data.lineart.y1 = t;
 +    a->texture[4].data.lineart.y2 = e->height - b - 1;
 +}
 +
 +static void render_button(ObPrompt *self, ObPromptElement *e)
 +{
 +    RrAppearance *a;
 +
 +    if (e->pressed && self->focus == e) a = prompt_a_pfocus;
 +    else if (self->focus == e)          a = prompt_a_focus;
 +    else if (e->pressed)                a = prompt_a_press;
 +    else                                a = prompt_a_button;
 +
 +    a->surface.parent = prompt_a_bg;
 +    a->surface.parentx = e->x;
 +    a->surface.parenty = e->y;
 +
 +    /* draw the keyfocus line */
 +    if (a == prompt_a_pfocus || a == prompt_a_focus)
 +        setup_button_focus_tex(e, a, TRUE);
 +
 +    a->texture[0].data.text.string = e->text;
 +    RrPaint(a, e->window, e->width, e->height);
 +
 +    /* turn off the keyfocus line so that it doesn't affect size calculations
 +     */
 +    if (a == prompt_a_pfocus || a == prompt_a_focus)
 +        setup_button_focus_tex(e, a, FALSE);
 +}
 +
 +static void render_all(ObPrompt *self)
 +{
 +    gint i;
 +
 +    RrPaint(prompt_a_bg, self->super.window, self->width, self->height);
 +
 +    prompt_a_msg->surface.parent = prompt_a_bg;
 +    prompt_a_msg->surface.parentx = self->msg.x;
 +    prompt_a_msg->surface.parenty = self->msg.y;
 +
 +    prompt_a_msg->texture[0].data.text.string = self->msg.text;
 +    prompt_a_msg->texture[0].data.text.maxwidth = self->msg_wbound;
 +    RrPaint(prompt_a_msg, self->msg.window, self->msg.width, self->msg.height);
 +
 +    for (i = 0; i < self->n_buttons; ++i)
 +        render_button(self, &self->button[i]);
 +}
 +
 +void prompt_show(ObPrompt *self, ObClient *parent, gboolean modal)
 +{
 +    gint i;
 +
 +    if (self->mapped) {
 +        /* activate the prompt */
 +        OBT_PROP_MSG(ob_screen, self->super.window, NET_ACTIVE_WINDOW,
 +                     1, /* from an application.. */
 +                     event_curtime,
 +                     0,
 +                     0, 0);
 +        return;
 +    }
 +
 +    /* set the focused button (if not found then the first button is used) */
 +    self->focus = &self->button[0];
 +    for (i = 0; i < self->n_buttons; ++i)
 +        if (self->button[i].result == self->default_result) {
 +            self->focus = &self->button[i];
 +            break;
 +        }
 +
 +    if (parent) {
 +        Atom states[1];
 +        gint nstates;
 +        Window p;
 +        XWMHints h;
 +
 +        if (parent->group) {
 +            /* make it transient for the window's group */
 +            h.flags = WindowGroupHint;
 +            h.window_group = parent->group->leader;
 +            p = obt_root(ob_screen);
 +        }
 +        else {
 +            /* make it transient for the window directly */
 +            h.flags = 0;
 +            p = parent->window;
 +        }
 +
 +        XSetWMHints(obt_display, self->super.window, &h);
 +        OBT_PROP_SET32(self->super.window, WM_TRANSIENT_FOR, WINDOW, p);
 +
 +        states[0] = OBT_PROP_ATOM(NET_WM_STATE_MODAL);
 +        nstates = (modal ? 1 : 0);
 +        OBT_PROP_SETA32(self->super.window, NET_WM_STATE, ATOM,
 +                        states, nstates);
 +    }
 +    else
 +        OBT_PROP_ERASE(self->super.window, WM_TRANSIENT_FOR);
 +
 +    /* set up the dialog and render it */
 +    prompt_layout(self);
 +    render_all(self);
 +
 +    client_manage(self->super.window, self);
 +
 +    self->mapped = TRUE;
 +}
 +
 +void prompt_hide(ObPrompt *self)
 +{
 +    XUnmapWindow(obt_display, self->super.window);
 +    self->mapped = FALSE;
 +}
 +
 +gboolean prompt_key_event(ObPrompt *self, XEvent *e)
 +{
 +    gboolean shift;
 +    guint shift_mask;
 +
 +    if (e->type != KeyPress) return FALSE;
 +
 +    shift_mask = obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT);
 +    shift = !!(e->xkey.state & shift_mask);
 +
 +    /* only accept shift */
 +    if (e->xkey.state != 0 && e->xkey.state != shift_mask)
 +        return FALSE;
 +
 +    if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
 +        prompt_cancel(self);
 +    else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN) ||
 +             e->xkey.keycode == ob_keycode(OB_KEY_SPACE))
 +    {
 +        prompt_run_callback(self, self->focus->result);
 +    }
 +    else if (e->xkey.keycode == ob_keycode(OB_KEY_TAB) ||
 +             e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
 +             e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
 +    {
 +        gint i;
 +        gboolean left;
 +        ObPromptElement *oldfocus;
 +
 +        left = e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
 +            (e->xkey.keycode == ob_keycode(OB_KEY_TAB) && shift);
 +        oldfocus = self->focus;
 +
 +        for (i = 0; i < self->n_buttons; ++i)
 +            if (self->focus == &self->button[i]) break;
 +        i += (left ? -1 : 1);
 +        if (i < 0) i = self->n_buttons - 1;
 +        else if (i >= self->n_buttons) i = 0;
 +        self->focus = &self->button[i];
 +
 +        if (oldfocus != self->focus) render_button(self, oldfocus);
 +        render_button(self, self->focus);
 +    }
 +    return TRUE;
 +}
 +
 +gboolean prompt_mouse_event(ObPrompt *self, XEvent *e)
 +{
 +    gint i;
 +    ObPromptElement *but;
 +
 +    if (e->type != ButtonPress && e->type != ButtonRelease &&
 +        e->type != MotionNotify) return FALSE;
 +
 +    /* find the button */
 +    but = NULL;
 +    for (i = 0; i < self->n_buttons; ++i)
 +        if (self->button[i].window ==
 +            (e->type == MotionNotify ? e->xmotion.window : e->xbutton.window))
 +        {
 +            but = &self->button[i];
 +            break;
 +        }
 +    if (!but) return FALSE;
 +
 +    if (e->type == ButtonPress) {
 +        ObPromptElement *oldfocus;
 +
 +        oldfocus = self->focus;
 +
 +        but->pressed = TRUE;
 +        self->focus = but;
 +
 +        if (oldfocus != but) render_button(self, oldfocus);
 +        render_button(self, but);
 +    }
 +    else if (e->type == ButtonRelease) {
 +        if (but->pressed)
 +            prompt_run_callback(self, but->result);
 +    }
 +    else if (e->type == MotionNotify) {
 +        gboolean press;
 +
 +        press = (e->xmotion.x >= 0 && e->xmotion.y >= 0 &&
 +                 e->xmotion.x < but->width && e->xmotion.y < but->height);
 +
 +        if (press != but->pressed) {
 +            but->pressed = press;
 +            render_button(self, but);
 +        }
 +    }
 +    return TRUE;
 +}
 +
 +void prompt_cancel(ObPrompt *self)
 +{
 +    prompt_run_callback(self, self->cancel_result);
 +}
 +
 +static gboolean prompt_show_message_cb(ObPrompt *p, int res, gpointer data)
 +{
 +    return TRUE; /* call the cleanup func */
 +}
 +
 +static void prompt_show_message_cleanup(ObPrompt *p, gpointer data)
 +{
 +    prompt_unref(p);
 +}
 +
 +ObPrompt* prompt_show_message(const gchar *msg, const gchar *title,
 +                              const gchar *answer)
 +{
 +    ObPrompt *p;
 +    ObPromptAnswer ans[] = {
 +        { answer, 0 }
 +    };
 +
 +    p = prompt_new(msg, title, ans, 1, 0, 0,
 +                   prompt_show_message_cb, prompt_show_message_cleanup, NULL);
 +    prompt_show(p, NULL, FALSE);
 +    return p;
 +}
 +
 +static void prompt_run_callback(ObPrompt *self, gint result)
 +{
 +    prompt_ref(self);
 +    if (self->func) {
 +        gboolean clean = self->func(self, self->focus->result, self->data);
 +        if (clean && self->cleanup)
 +            self->cleanup(self, self->data);
 +    }
 +    prompt_hide(self);
 +    prompt_unref(self);
 +}
diff --cc render/render.c
index 7c00c1462509496fde0b99969748605889f0c04d,63b7e4c8b993cb6735130563f361d0dcc6fa3cb9..52cc70ec222b76675facbbbe91baa185482ff25c
@@@ -310,29 -276,41 +310,29 @@@ RrAppearance *RrAppearanceCopy(RrAppear
      return copy;
  }
  
 -/* now decrements ref counter, and frees only if ref <= 0 */
  void RrAppearanceFree(RrAppearance *a)
  {
-     if (a) {
-         RrSurface *p;
-         if (a->pixmap != None) XFreePixmap(RrDisplay(a->inst), a->pixmap);
-         if (a->xftdraw != NULL) XftDrawDestroy(a->xftdraw);
-         if (a->textures)
-             g_free(a->texture);
-         p = &a->surface;
-         RrColorFree(p->primary);
-         RrColorFree(p->secondary);
-         RrColorFree(p->border_color);
-         RrColorFree(p->interlace_color);
-         RrColorFree(p->bevel_dark);
-         RrColorFree(p->bevel_light);
-         RrColorFree(p->split_primary);
-         RrColorFree(p->split_secondary);
-         g_free(p->pixel_data);
-         p->pixel_data = NULL;
-         g_free(a);
-     }
 -    gint i;
 -
+     if (!a) return;
+     RrSurface *p;
+     if (a->pixmap != None) XFreePixmap(RrDisplay(a->inst), a->pixmap);
+     if (a->xftdraw != NULL) XftDrawDestroy(a->xftdraw);
 -    for (i = 0; i < a->textures; ++i)
 -        if (a->texture[i].type == RR_TEXTURE_RGBA) {
 -            g_free(a->texture[i].data.rgba.cache);
 -            a->texture[i].data.rgba.cache = NULL;
 -        }
+     if (a->textures)
+         g_free(a->texture);
+     p = &a->surface;
+     RrColorFree(p->primary);
+     RrColorFree(p->secondary);
+     RrColorFree(p->border_color);
+     RrColorFree(p->interlace_color);
+     RrColorFree(p->bevel_dark);
+     RrColorFree(p->bevel_light);
+     RrColorFree(p->split_primary);
+     RrColorFree(p->split_secondary);
+     g_free(p->pixel_data);
+     p->pixel_data = NULL;
+     g_free(a);
 -
 -    /* set a to NULL so its testable afterwards if it still exists */
 -    a = NULL;
  }
  
 -
  static void pixel_data_to_pixmap(RrAppearance *l,
                                   gint x, gint y, gint w, gint h)
  {
diff --cc render/render.h
index b15d4060b3b506898cc926dc856432a6033efba1,3ae88d66e946551c40df2d698eadff765d464970..4595a920292175f7f817cb933b041a64646226c5
@@@ -43,9 -42,7 +43,10 @@@ typedef struct _RrTextureLineArt   RrTe
  typedef struct _RrPixmapMask       RrPixmapMask;
  typedef struct _RrInstance         RrInstance;
  typedef struct _RrColor            RrColor;
 +typedef struct _RrImage            RrImage;
 +typedef struct _RrImagePic         RrImagePic;
 +typedef struct _RrImageCache       RrImageCache;
+ typedef struct _RrButton           RrButton;
  
  typedef guint32 RrPixel32;
  typedef guint16 RrPixel16;
@@@ -223,41 -201,52 +224,87 @@@ struct _RrAppearance 
      gint w, h;
  };
  
 +/*! Holds a RGBA image picture */
 +struct _RrImagePic {
 +    gint width, height;
 +    RrPixel32 *data;
 +    /* The sum of all the pixels.  This is used to compare pictures if their
 +       hashes match. */
 +    gint sum;
 +};
 +
 +typedef void (*RrImageDestroyFunc)(RrImage *image);
 +
 +/*! An RrImage is a sort of meta-image.  It can contain multiple versions of
 +  an image at different sizes, which may or may not be completely different
 +  pictures */
 +struct _RrImage {
 +    gint ref;
 +    RrImageCache *cache;
 +
 +    /*! An array of "originals", that is of RrPictures that have been added
 +      to the image in various sizes, and that have not been resized.  These
 +      are explicitly added to the RrImage. */
 +    RrImagePic **original;
 +    gint n_original;
 +    /*! An array of "resized" pictures.  When an "original" RrPicture
 +      needs to be resized for drawing, it is saved in here so that it doesn't
 +      need to be resized again.  These are automatically added to the
 +      RrImage. */
 +    RrImagePic **resized;
 +    gint n_resized;
 + 
 +    /* This function (if not NULL) will be called just before destroying
 +      RrImage. */
 +    RrImageDestroyFunc destroy_func;
 +};
 +
+ struct _RrButton {
+     const RrInstance *inst;
+     /* colors */
+     RrColor *focused_unpressed_color;
+     RrColor *unfocused_unpressed_color;
+     RrColor *focused_pressed_color;
+     RrColor *unfocused_pressed_color;
+     RrColor *disabled_focused_color;
+     RrColor *disabled_unfocused_color;
+     RrColor *hover_focused_color;
+     RrColor *hover_unfocused_color;
+     RrColor *toggled_hover_focused_color;
+     RrColor *toggled_hover_unfocused_color;
+     RrColor *toggled_focused_pressed_color;
+     RrColor *toggled_unfocused_pressed_color;
+     RrColor *toggled_focused_unpressed_color;
+     RrColor *toggled_unfocused_unpressed_color;
+     
+     /* masks */
+     RrPixmapMask *mask;
+     RrPixmapMask *pressed_mask;
+     RrPixmapMask *disabled_mask;
+     RrPixmapMask *hover_mask;
+     RrPixmapMask *toggled_mask;
+     RrPixmapMask *toggled_hover_mask;
+     RrPixmapMask *toggled_pressed_mask;
+    
+     /* textures */
+     RrAppearance *a_focused_unpressed;
+     RrAppearance *a_unfocused_unpressed;
+     RrAppearance *a_focused_pressed;
+     RrAppearance *a_unfocused_pressed;
+     RrAppearance *a_disabled_focused;
+     RrAppearance *a_disabled_unfocused;
+     RrAppearance *a_hover_focused;
+     RrAppearance *a_hover_unfocused;
+     RrAppearance *a_toggled_focused_unpressed;
+     RrAppearance *a_toggled_unfocused_unpressed;
+     RrAppearance *a_toggled_focused_pressed;
+     RrAppearance *a_toggled_unfocused_pressed;
+     RrAppearance *a_toggled_hover_focused;
+     RrAppearance *a_toggled_hover_unfocused;
+ };
  /* these are the same on all endian machines because it seems to be dependant
     on the endianness of the gfx card, not the cpu. */
  #define RrDefaultAlphaOffset 24
@@@ -302,11 -292,11 +350,14 @@@ GC       RrColorGC    (RrColor *c)
  RrAppearance *RrAppearanceNew  (const RrInstance *inst, gint numtex);
  RrAppearance *RrAppearanceCopy (RrAppearance *a);
  void          RrAppearanceFree (RrAppearance *a);
 +void          RrAppearanceRemoveTextures(RrAppearance *a);
  void          RrAppearanceAddTextures(RrAppearance *a, gint numtex);
 +/*! Always call this when changing the type of a texture in an appearance */
 +void          RrAppearanceClearTextures(RrAppearance *a);
  
+ RrButton *RrButtonNew (const RrInstance *inst);
+ void      RrButtonFree(RrButton *b);
  RrFont *RrFontOpen          (const RrInstance *inst, const gchar *name,
                               gint size, RrFontWeight weight, RrFontSlant slant);
  RrFont *RrFontOpenDefault   (const RrInstance *inst);
diff --cc render/theme.c
index 29a187cb7c418c2215952448a73551f60211cf6d,9806bac6f75ef89cd1d33189a23051713aae3805..667eafc9daaf2defe9caa4ddfe4a7795c4ca0610
@@@ -49,6 -45,42 +49,48 @@@ static gboolean read_appearance(XrmData
  static int parse_inline_number(const char *p);
  static RrPixel32* read_c_image(gint width, gint height, const guint8 *data);
  static void set_default_appearance(RrAppearance *a);
+ static void read_button_colors(XrmDatabase db, const RrInstance *inst, 
+                                const RrTheme *theme, RrButton *btn, 
+                                const gchar *btnname);
+ #define READ_INT(x_resstr, x_var, x_min, x_max, x_def) \
+     if (!read_int(db, x_resstr, & x_var) || \
+             x_var < x_min || x_var > x_max) \
+         x_var = x_def;
++#define READ_INT_(x_resstr, x_resstr_fallback, x_var, x_min, x_max, x_def) \
++    if (!read_int(db, x_resstr, & x_var) && \
++        !read_int(db, x_resstr_fallback, & x_var) || \
++            x_var < x_min || x_var > x_max) \
++        x_var = x_def;
++
+ #define READ_COLOR(x_resstr, x_var, x_def) \
+     if (!read_color(db, inst, x_resstr, & x_var)) \
+         x_var = x_def;
+ #define READ_COLOR_(x_res1, x_res2, x_var, x_def) \
+     if (!read_color(db, inst, x_res1, & x_var) && \
+         !read_color(db, inst, x_res2, & x_var)) \
+         x_var = x_def;
+ #define READ_MASK_COPY(x_file, x_var, x_copysrc) \
+     if (!read_mask(inst, path, theme, x_file, & x_var)) \
+         x_var = RrPixmapMaskCopy(x_copysrc);
+ #define READ_APPEARANCE(x_resstr, x_var, x_parrel) \
+     if (!read_appearance(db, inst, x_resstr, x_var, x_parrel)) \
+         set_default_appearance(x_var);
+ #define READ_APPEARANCE_COPY(x_resstr, x_var, x_parrel, x_defval) \
+     if (!read_appearance(db, inst, x_resstr, x_var, x_parrel)) {\
+         RrAppearanceFree(x_var); \
+         x_var = RrAppearanceCopy(x_defval); }
+ #define READ_APPEARANCE_(x_res1, x_res2, x_var, x_parrel, x_defval) \
+     if (!read_appearance(db, inst, x_res1, x_var, x_parrel) && \
+         !read_appearance(db, inst, x_res2, x_var, x_parrel)) {\
+         RrAppearanceFree(x_var); \
+         x_var = RrAppearanceCopy(x_defval); }
  
  RrTheme* RrThemeNew(const RrInstance *inst, const gchar *name,
                      gboolean allow_fallback,
          theme->osd_font = RrFontOpenDefault(inst);
  
      /* load direct dimensions */
-     if ((!read_int(db, "menu.overlap.x", &theme->menu_overlap_x) &&
-          !read_int(db, "menu.overlap", &theme->menu_overlap_x)) ||
-         theme->menu_overlap_x < -100 || theme->menu_overlap_x > 100)
-         theme->menu_overlap_x = 0;
-     if ((!read_int(db, "menu.overlap.y", &theme->menu_overlap_y) &&
-          !read_int(db, "menu.overlap", &theme->menu_overlap_y)) ||
-         theme->menu_overlap_y < -100 || theme->menu_overlap_y > 100)
-         theme->menu_overlap_y = 0;
-     if (!read_int(db, "window.handle.width", &theme->handle_height) ||
-         theme->handle_height < 0 || theme->handle_height > 100)
-         theme->handle_height = 6;
-     if (!read_int(db, "padding.width", &theme->paddingx) ||
-         theme->paddingx < 0 || theme->paddingx > 100)
-         theme->paddingx = 3;
-     if (!read_int(db, "padding.height", &theme->paddingy) ||
-         theme->paddingy < 0 || theme->paddingy > 100)
-         theme->paddingy = theme->paddingx;
-     if (!read_int(db, "border.width", &theme->fbwidth) ||
-         theme->fbwidth < 0 || theme->fbwidth > 100)
-         theme->fbwidth = 1;
-     /* menu border width inherits from the frame border width */
-     if (!read_int(db, "menu.border.width", &theme->mbwidth) ||
-         theme->mbwidth < 0 || theme->mbwidth > 100)
-         theme->mbwidth = theme->fbwidth;
-     /* osd border width inherits from the frame border width */
-     if (!read_int(db, "osd.border.width", &theme->obwidth) ||
-         theme->obwidth < 0 || theme->obwidth > 100)
-         theme->obwidth = theme->fbwidth;
-     if (!read_int(db, "window.client.padding.width", &theme->cbwidthx) ||
-         theme->cbwidthx < 0 || theme->cbwidthx > 100)
-         theme->cbwidthx = theme->paddingx;
-     if (!read_int(db, "window.client.padding.height", &theme->cbwidthy) ||
-         theme->cbwidthy < 0 || theme->cbwidthy > 100)
-         theme->cbwidthy = theme->cbwidthx;
-     if (!read_int(db, "menu.separator.width", &theme->menu_sep_width) ||
-         theme->menu_sep_width < 1 || theme->menu_sep_width > 100)
-         theme->menu_sep_width = 1;
-     if (!read_int(db, "menu.separator.padding.width",
-                   &theme->menu_sep_paddingx) ||
-         theme->menu_sep_paddingx < 0 || theme->menu_sep_paddingx > 100)
-         theme->menu_sep_paddingx = 6;
-     if (!read_int(db, "menu.separator.padding.height",
-                   &theme->menu_sep_paddingy) ||
-         theme->menu_sep_paddingy < 0 || theme->menu_sep_paddingy > 100)
-         theme->menu_sep_paddingy = 3;
 -    READ_INT("menu.overlap", theme->menu_overlap, -100, 100, 0);
++    READ_INT_("menu.overlap.x", "menu.overlap", theme->menu_overlap_x, -100, 100, 0)
++    READ_INT_("menu.overlap.y", "menu.overlap", theme->menu_overlap_y, -100, 100, 0)
+     READ_INT("window.handle.width", theme->handle_height, 0, 100, 6);
+     READ_INT("padding.width", theme->paddingx, 0, 100, 3);
+     READ_INT("padding.height", theme->paddingy, 0, 100, theme->paddingx);
+     READ_INT("border.width", theme->fbwidth, 0, 100, 1);
+     READ_INT("menu.border.width", theme->mbwidth, 0, 100, theme->fbwidth);
+     READ_INT("osd.border.width", theme->obwidth, 0, 100, theme->fbwidth);
+     READ_INT("window.client.padding.width", theme->cbwidthx, 0, 100,
+              theme->paddingx);
+     READ_INT("window.client.padding.height", theme->cbwidthy, 0, 100,
+              theme->cbwidthx);
++    READ_INT("menu.separator.width", theme->menu_sep_width, 1, 100, 1);
++    READ_INT("menu.separator.padding.width", theme->menu_sep_paddingx, 0, 100, 6);
++    READ_INT("menu.separator.padding.height", theme->menu_sep_paddingx, 0, 100, 3);
  
      /* load colors */
-     if (!read_color(db, inst,
-                     "window.active.border.color",
-                     &theme->frame_focused_border_color) &&
-         !read_color(db, inst,
-                     "border.color",
-                     &theme->frame_focused_border_color))
-         theme->frame_focused_border_color = RrColorNew(inst, 0, 0, 0);
+     READ_COLOR_("window.active.border.color", "border.color",
+                 theme->frame_focused_border_color, RrColorNew(inst, 0, 0, 0));
 -    /* title separator focused color inherits from focused boder color */
 +    /* title separator focused color inherits from focused border color */
-     if (!read_color(db, inst,
-                     "window.active.title.separator.color",
-                     &theme->title_separator_focused_color))
-         theme->title_separator_focused_color =
-             RrColorNew(inst,
-                        theme->frame_focused_border_color->r,
-                        theme->frame_focused_border_color->g,
-                        theme->frame_focused_border_color->b);
+     READ_COLOR("window.active.title.separator.color",
+                theme->title_separator_focused_color,
+                RrColorCopy(theme->frame_focused_border_color));
      /* unfocused border color inherits from frame focused border color */
-     if (!read_color(db, inst,
-                     "window.inactive.border.color",
-                     &theme->frame_unfocused_border_color))
-         theme->frame_unfocused_border_color =
-             RrColorNew(inst, theme->frame_focused_border_color->r,
-                        theme->frame_focused_border_color->g,
-                        theme->frame_focused_border_color->b);
+     READ_COLOR("window.inactive.border.color",
+                theme->frame_unfocused_border_color,
+                RrColorCopy(theme->frame_focused_border_color));
 -    /* title separator unfocused color inherits from unfocused boder color */
 +    /* title separator unfocused color inherits from unfocused border color */
-     if (!read_color(db, inst,
-                     "window.inactive.title.separator.color",
-                     &theme->title_separator_unfocused_color))
-         theme->title_separator_unfocused_color =
-             RrColorNew(inst,
-                        theme->frame_unfocused_border_color->r,
-                        theme->frame_unfocused_border_color->g,
-                        theme->frame_unfocused_border_color->b);
+     READ_COLOR("window.inactive.title.separator.color",
+                theme->title_separator_unfocused_color,
+                RrColorCopy(theme->frame_unfocused_border_color));
  
      /* menu border color inherits from frame focused border color */
-     if (!read_color(db, inst, "menu.border.color", &theme->menu_border_color))
-         theme->menu_border_color =
-             RrColorNew(inst,
-                        theme->frame_focused_border_color->r,
-                        theme->frame_focused_border_color->g,
-                        theme->frame_focused_border_color->b);
+     READ_COLOR("menu.border.color", theme->menu_border_color,
+                RrColorCopy(theme->frame_focused_border_color));
      /* osd border color inherits from frame focused border color */
-     if (!read_color(db, inst, "osd.border.color", &theme->osd_border_color))
-         theme->osd_border_color =
-             RrColorNew(inst,
-                        theme->frame_focused_border_color->r,
-                        theme->frame_focused_border_color->g,
-                        theme->frame_focused_border_color->b);
-     if (!read_color(db, inst,
-                     "window.active.client.color",
-                     &theme->cb_focused_color))
-         theme->cb_focused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
-     if (!read_color(db, inst,
-                     "window.inactive.client.color",
-                     &theme->cb_unfocused_color))
-         theme->cb_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
-     if (!read_color(db, inst,
-                     "window.active.label.text.color",
-                     &theme->title_focused_color))
-         theme->title_focused_color = RrColorNew(inst, 0x0, 0x0, 0x0);
-     if (!read_color(db, inst, "osd.label.text.color", &theme->osd_color))
-         theme->osd_color = RrColorNew(inst,
-                                       theme->title_focused_color->r,
-                                       theme->title_focused_color->g,
-                                       theme->title_focused_color->b);
-     if (!read_color(db, inst,
-                     "window.inactive.label.text.color",
-                     &theme->title_unfocused_color))
-         theme->title_unfocused_color = RrColorNew(inst, 0xff, 0xff, 0xff);
-     if (!read_color(db, inst,
-                     "window.active.button.unpressed.image.color",
-                     &theme->titlebut_focused_unpressed_color))
-         theme->titlebut_focused_unpressed_color = RrColorNew(inst, 0, 0, 0);
-     if (!read_color(db, inst,
-                     "window.inactive.button.unpressed.image.color",
-                     &theme->titlebut_unfocused_unpressed_color))
-         theme->titlebut_unfocused_unpressed_color =
-             RrColorNew(inst, 0xff, 0xff, 0xff);
-     if (!read_color(db, inst,
-                     "window.active.button.pressed.image.color",
-                     &theme->titlebut_focused_pressed_color))
-         theme->titlebut_focused_pressed_color =
-             RrColorNew(inst,
-                        theme->titlebut_focused_unpressed_color->r,
-                        theme->titlebut_focused_unpressed_color->g,
-                        theme->titlebut_focused_unpressed_color->b);
-     if (!read_color(db, inst,
-                     "window.inactive.button.pressed.image.color",
-                     &theme->titlebut_unfocused_pressed_color))
-         theme->titlebut_unfocused_pressed_color =
-             RrColorNew(inst,
-                        theme->titlebut_unfocused_unpressed_color->r,
-                        theme->titlebut_unfocused_unpressed_color->g,
-                        theme->titlebut_unfocused_unpressed_color->b);
-     if (!read_color(db, inst,
-                     "window.active.button.disabled.image.color",
-                     &theme->titlebut_disabled_focused_color))
-         theme->titlebut_disabled_focused_color =
-             RrColorNew(inst, 0xff, 0xff, 0xff);
-     if (!read_color(db, inst,
-                     "window.inactive.button.disabled.image.color",
-                     &theme->titlebut_disabled_unfocused_color))
-         theme->titlebut_disabled_unfocused_color = RrColorNew(inst, 0, 0, 0);
-     if (!read_color(db, inst,
-                     "window.active.button.hover.image.color",
-                     &theme->titlebut_hover_focused_color))
-         theme->titlebut_hover_focused_color =
-             RrColorNew(inst,
-                        theme->titlebut_focused_unpressed_color->r,
-                        theme->titlebut_focused_unpressed_color->g,
-                        theme->titlebut_focused_unpressed_color->b);
-     if (!read_color(db, inst,
-                     "window.inactive.button.hover.image.color",
-                     &theme->titlebut_hover_unfocused_color))
-         theme->titlebut_hover_unfocused_color =
-             RrColorNew(inst,
-                        theme->titlebut_unfocused_unpressed_color->r,
-                        theme->titlebut_unfocused_unpressed_color->g,
-                        theme->titlebut_unfocused_unpressed_color->b);
-     if (!read_color(db, inst,
-                     "window.active.button.toggled.unpressed.image.color",
-                     &theme->titlebut_toggled_focused_unpressed_color) &&
-         !read_color(db, inst,
-                     "window.active.button.toggled.image.color",
-                     &theme->titlebut_toggled_focused_unpressed_color))
-         theme->titlebut_toggled_focused_unpressed_color =
-             RrColorNew(inst,
-                        theme->titlebut_focused_pressed_color->r,
-                        theme->titlebut_focused_pressed_color->g,
-                        theme->titlebut_focused_pressed_color->b);
-     if (!read_color(db, inst,
-                     "window.inactive.button.toggled.unpressed.image.color",
-                     &theme->titlebut_toggled_unfocused_unpressed_color) &&
-         !read_color(db, inst,
-                     "window.inactive.button.toggled.image.color",
-                     &theme->titlebut_toggled_unfocused_unpressed_color))
-         theme->titlebut_toggled_unfocused_unpressed_color =
-             RrColorNew(inst,
-                        theme->titlebut_unfocused_pressed_color->r,
-                        theme->titlebut_unfocused_pressed_color->g,
-                        theme->titlebut_unfocused_pressed_color->b);
-     if (!read_color(db, inst,
-                     "window.active.button.toggled.hover.image.color",
-                     &theme->titlebut_toggled_hover_focused_color))
-         theme->titlebut_toggled_hover_focused_color =
-             RrColorNew(inst,
-                        theme->titlebut_toggled_focused_unpressed_color->r,
-                        theme->titlebut_toggled_focused_unpressed_color->g,
-                        theme->titlebut_toggled_focused_unpressed_color->b);
-     if (!read_color(db, inst,
-                     "window.inactive.button.toggled.hover.image.color",
-                     &theme->titlebut_toggled_hover_unfocused_color))
-         theme->titlebut_toggled_hover_unfocused_color =
-             RrColorNew(inst,
-                        theme->titlebut_toggled_unfocused_unpressed_color->r,
-                        theme->titlebut_toggled_unfocused_unpressed_color->g,
-                        theme->titlebut_toggled_unfocused_unpressed_color->b);
-     if (!read_color(db, inst,
-                     "window.active.button.toggled.pressed.image.color",
-                     &theme->titlebut_toggled_focused_pressed_color))
-         theme->titlebut_toggled_focused_pressed_color =
-             RrColorNew(inst,
-                        theme->titlebut_focused_pressed_color->r,
-                        theme->titlebut_focused_pressed_color->g,
-                        theme->titlebut_focused_pressed_color->b);
-     if (!read_color(db, inst,
-                     "window.inactive.button.toggled.pressed.image.color",
-                     &theme->titlebut_toggled_unfocused_pressed_color))
-         theme->titlebut_toggled_unfocused_pressed_color =
-             RrColorNew(inst,
-                        theme->titlebut_unfocused_pressed_color->r,
-                        theme->titlebut_unfocused_pressed_color->g,
-                        theme->titlebut_unfocused_pressed_color->b);
-     if (!read_color(db, inst,
-                     "menu.title.text.color", &theme->menu_title_color))
-         theme->menu_title_color = RrColorNew(inst, 0, 0, 0);
-     if (!read_color(db, inst,
-                     "menu.items.text.color", &theme->menu_color))
-         theme->menu_color = RrColorNew(inst, 0xff, 0xff, 0xff);
-     if (!read_color(db, inst,
-                     "menu.items.disabled.text.color",
-                     &theme->menu_disabled_color))
-         theme->menu_disabled_color = RrColorNew(inst, 0, 0, 0);
-     if (!read_color(db, inst,
-                     "menu.items.active.disabled.text.color",
-                     &theme->menu_disabled_selected_color))
-         theme->menu_disabled_selected_color =
-             RrColorNew(inst,
-                        theme->menu_disabled_color->r,
-                        theme->menu_disabled_color->g,
-                        theme->menu_disabled_color->b);
-     if (!read_color(db, inst,
-                     "menu.items.active.text.color",
-                     &theme->menu_selected_color))
-         theme->menu_selected_color = RrColorNew(inst, 0, 0, 0);
-     if (!read_color(db, inst,
-                     "menu.separator.color", &theme->menu_sep_color))
-         theme->menu_sep_color = RrColorNew(inst,
-                                            theme->menu_color->r,
-                                            theme->menu_color->g,
-                                            theme->menu_color->b);
+     READ_COLOR("osd.border.color", theme->osd_border_color,
+                RrColorCopy(theme->frame_focused_border_color));
+     READ_COLOR("window.active.client.color", theme->cb_focused_color,
+                RrColorNew(inst, 0xff, 0xff, 0xff));
+     READ_COLOR("window.inactive.client.color", theme->cb_unfocused_color,
+                RrColorNew(inst, 0xff, 0xff, 0xff));
+     READ_COLOR("window.active.label.text.color", theme->title_focused_color,
+                RrColorNew(inst, 0x0, 0x0, 0x0));
+     READ_COLOR("osd.label.text.color", theme->osd_color,
+                RrColorCopy(theme->title_focused_color));
+     READ_COLOR("window.inactive.label.text.color",
+                theme->title_unfocused_color,
+                RrColorNew(inst, 0xff, 0xff, 0xff));
+     READ_COLOR("window.active.button.unpressed.image.color",
+                theme->titlebut_focused_unpressed_color,
+                RrColorNew(inst, 0, 0, 0));
+     READ_COLOR("window.inactive.button.unpressed.image.color",
+                theme->titlebut_unfocused_unpressed_color,
+                RrColorNew(inst, 0xff, 0xff, 0xff));
+     READ_COLOR("window.active.button.pressed.image.color",
+                theme->titlebut_focused_pressed_color,
+                RrColorCopy(theme->titlebut_focused_unpressed_color));
+     READ_COLOR("window.inactive.button.pressed.image.color",
+                theme->titlebut_unfocused_pressed_color,
+                RrColorCopy(theme->titlebut_unfocused_unpressed_color));
+     READ_COLOR("window.active.button.disabled.image.color",
+                theme->titlebut_disabled_focused_color,
+                RrColorNew(inst, 0xff, 0xff, 0xff));
+     READ_COLOR("window.inactive.button.disabled.image.color",
+                theme->titlebut_disabled_unfocused_color,
+                RrColorNew(inst, 0, 0, 0));
+     READ_COLOR("window.active.button.hover.image.color",
+                theme->titlebut_hover_focused_color,
+                RrColorCopy(theme->titlebut_focused_unpressed_color));
+     READ_COLOR("window.inactive.button.hover.image.color",
+                theme->titlebut_hover_unfocused_color,
+                RrColorCopy(theme->titlebut_unfocused_unpressed_color));
+     READ_COLOR_("window.active.button.toggled.unpressed.image.color",
+                 "window.active.button.toggled.image.color",
+                 theme->titlebut_toggled_focused_unpressed_color,
+                 RrColorCopy(theme->titlebut_focused_pressed_color));
+     READ_COLOR_("window.inactive.button.toggled.unpressed.image.color",
+                 "window.inactive.button.toggled.image.color",
+                 theme->titlebut_toggled_unfocused_unpressed_color,
+                 RrColorCopy(theme->titlebut_unfocused_pressed_color));
+     READ_COLOR("window.active.button.toggled.hover.image.color",
+                theme->titlebut_toggled_hover_focused_color,
+                RrColorCopy(theme->titlebut_toggled_focused_unpressed_color));
+     READ_COLOR("window.inactive.button.toggled.hover.image.color",
+                theme->titlebut_toggled_hover_unfocused_color,
+                RrColorCopy(theme->titlebut_toggled_unfocused_unpressed_color));
+     READ_COLOR("window.active.button.toggled.pressed.image.color",
+                theme->titlebut_toggled_focused_pressed_color,
+                RrColorCopy(theme->titlebut_focused_pressed_color));
+     READ_COLOR("window.inactive.button.toggled.pressed.image.color",
+                theme->titlebut_toggled_unfocused_pressed_color,
+                RrColorCopy(theme->titlebut_unfocused_pressed_color));
+     READ_COLOR("menu.title.text.color", theme->menu_title_color,
+                RrColorNew(inst, 0, 0, 0));
+     READ_COLOR("menu.items.text.color", theme->menu_color,
+                RrColorNew(inst, 0xff, 0xff, 0xff));
+     READ_COLOR("menu.bullet.image.color", theme->menu_bullet_color,
+                RrColorCopy(theme->menu_color));
+    
+     READ_COLOR("menu.items.disabled.text.color", theme->menu_disabled_color,
+                RrColorNew(inst, 0, 0, 0));
+     READ_COLOR("menu.items.active.disabled.text.color",
+                theme->menu_disabled_selected_color,
+                RrColorCopy(theme->menu_disabled_color));
+     READ_COLOR("menu.items.active.text.color", theme->menu_selected_color,
+                RrColorNew(inst, 0, 0, 0));
++    READ_COLOR("menu.separator.color", theme->menu_sep_color,
++               RrColorCopy(theme->menu_color));
++
+     READ_COLOR("menu.bullet.selected.image.color", 
+                theme->menu_bullet_selected_color,
+                RrColorCopy(theme->menu_selected_color));
+  
  
      /* load the image masks */
  
      theme->def_win_icon = read_c_image(OB_DEFAULT_ICON_WIDTH,
                                         OB_DEFAULT_ICON_HEIGHT,
                                         OB_DEFAULT_ICON_pixel_data);
 +    theme->def_win_icon_w = OB_DEFAULT_ICON_WIDTH;
 +    theme->def_win_icon_h = OB_DEFAULT_ICON_HEIGHT;
  
      /* read the decoration textures */
-     if (!read_appearance(db, inst,
-                          "window.active.title.bg", theme->a_focused_title,
-                          FALSE))
-         set_default_appearance(theme->a_focused_title);
-     if (!read_appearance(db, inst,
-                          "window.inactive.title.bg", theme->a_unfocused_title,
-                          FALSE))
-         set_default_appearance(theme->a_unfocused_title);
-     if (!read_appearance(db, inst,
-                          "window.active.label.bg", theme->a_focused_label,
-                          TRUE))
-         set_default_appearance(theme->a_focused_label);
-     if (!read_appearance(db, inst,
-                          "window.inactive.label.bg", theme->a_unfocused_label,
-                          TRUE))
-         set_default_appearance(theme->a_unfocused_label);
-     if (!read_appearance(db, inst,
-                          "window.active.handle.bg", theme->a_focused_handle,
-                          FALSE))
-         set_default_appearance(theme->a_focused_handle);
-     if (!read_appearance(db, inst,
-                          "window.inactive.handle.bg",theme->a_unfocused_handle,
-                          FALSE))
-         set_default_appearance(theme->a_unfocused_handle);
-     if (!read_appearance(db, inst,
-                          "window.active.grip.bg", theme->a_focused_grip,
-                          TRUE))
-         set_default_appearance(theme->a_focused_grip);
-     if (!read_appearance(db, inst,
-                          "window.inactive.grip.bg", theme->a_unfocused_grip,
-                          TRUE))
-         set_default_appearance(theme->a_unfocused_grip);
-     if (!read_appearance(db, inst,
-                          "menu.items.bg", theme->a_menu,
-                          FALSE))
-         set_default_appearance(theme->a_menu);
-     if (!read_appearance(db, inst,
-                          "menu.title.bg", theme->a_menu_title,
-                          TRUE))
-         set_default_appearance(theme->a_menu_title);
-     if (!read_appearance(db, inst,
-                          "menu.items.active.bg", theme->a_menu_selected,
-                          TRUE))
-         set_default_appearance(theme->a_menu_selected);
+     READ_APPEARANCE("window.active.title.bg", theme->a_focused_title, FALSE);
+     READ_APPEARANCE("window.inactive.title.bg", theme->a_unfocused_title,
+                     FALSE);
+     READ_APPEARANCE("window.active.label.bg", theme->a_focused_label, TRUE);
+     READ_APPEARANCE("window.inactive.label.bg", theme->a_unfocused_label,
+                     TRUE);
+     READ_APPEARANCE("window.active.handle.bg", theme->a_focused_handle, FALSE);
+     READ_APPEARANCE("window.inactive.handle.bg",theme->a_unfocused_handle,
+                     FALSE);
+     READ_APPEARANCE("window.active.grip.bg", theme->a_focused_grip, TRUE);
+     READ_APPEARANCE("window.inactive.grip.bg", theme->a_unfocused_grip, TRUE);
+     READ_APPEARANCE("menu.items.bg", theme->a_menu, FALSE);
+     READ_APPEARANCE("menu.title.bg", theme->a_menu_title, TRUE);
+     READ_APPEARANCE("menu.items.active.bg", theme->a_menu_selected, TRUE);
      theme->a_menu_disabled_selected =
          RrAppearanceCopy(theme->a_menu_selected);
  
@@@ -1437,8 -1466,9 +1490,10 @@@ void RrThemeFree(RrTheme *theme
          RrColorFree(theme->titlebut_focused_unpressed_color);
          RrColorFree(theme->titlebut_unfocused_unpressed_color);
          RrColorFree(theme->menu_title_color);
 +        RrColorFree(theme->menu_sep_color);
          RrColorFree(theme->menu_color);
+         RrColorFree(theme->menu_bullet_color);
+         RrColorFree(theme->menu_bullet_selected_color);
          RrColorFree(theme->menu_selected_color);
          RrColorFree(theme->menu_disabled_color);
          RrColorFree(theme->menu_disabled_selected_color);
          RrColorFree(theme->menu_text_disabled_selected_shadow_color);
  
          g_free(theme->def_win_icon);
-         RrPixmapMaskFree(theme->max_mask);
-         RrPixmapMaskFree(theme->max_toggled_mask);
-         RrPixmapMaskFree(theme->max_toggled_hover_mask);
-         RrPixmapMaskFree(theme->max_toggled_pressed_mask);
-         RrPixmapMaskFree(theme->max_disabled_mask);
-         RrPixmapMaskFree(theme->max_hover_mask);
-         RrPixmapMaskFree(theme->max_pressed_mask);
-         RrPixmapMaskFree(theme->desk_mask);
-         RrPixmapMaskFree(theme->desk_toggled_mask);
-         RrPixmapMaskFree(theme->desk_toggled_hover_mask);
-         RrPixmapMaskFree(theme->desk_toggled_pressed_mask);
-         RrPixmapMaskFree(theme->desk_disabled_mask);
-         RrPixmapMaskFree(theme->desk_hover_mask);
-         RrPixmapMaskFree(theme->desk_pressed_mask);
-         RrPixmapMaskFree(theme->shade_mask);
-         RrPixmapMaskFree(theme->shade_toggled_mask);
-         RrPixmapMaskFree(theme->shade_toggled_hover_mask);
-         RrPixmapMaskFree(theme->shade_toggled_pressed_mask);
-         RrPixmapMaskFree(theme->shade_disabled_mask);
-         RrPixmapMaskFree(theme->shade_hover_mask);
-         RrPixmapMaskFree(theme->shade_pressed_mask);
-         RrPixmapMaskFree(theme->iconify_mask);
-         RrPixmapMaskFree(theme->iconify_disabled_mask);
-         RrPixmapMaskFree(theme->iconify_hover_mask);
-         RrPixmapMaskFree(theme->iconify_pressed_mask);
-         RrPixmapMaskFree(theme->close_mask);
-         RrPixmapMaskFree(theme->close_disabled_mask);
-         RrPixmapMaskFree(theme->close_hover_mask);
-         RrPixmapMaskFree(theme->close_pressed_mask);
+         
          RrPixmapMaskFree(theme->menu_bullet_mask);
 +        RrPixmapMaskFree(theme->down_arrow_mask);
 +        RrPixmapMaskFree(theme->up_arrow_mask);
  
          RrFontClose(theme->win_font_focused);
          RrFontClose(theme->win_font_unfocused);
          RrFontClose(theme->menu_title_font);
          RrFontClose(theme->menu_font);
 -        
 +        RrFontClose(theme->osd_font);
 +
-         RrAppearanceFree(theme->a_disabled_focused_max);
-         RrAppearanceFree(theme->a_disabled_unfocused_max);
-         RrAppearanceFree(theme->a_hover_focused_max);
-         RrAppearanceFree(theme->a_hover_unfocused_max);
-         RrAppearanceFree(theme->a_toggled_hover_focused_max);
-         RrAppearanceFree(theme->a_toggled_hover_unfocused_max);
-         RrAppearanceFree(theme->a_toggled_focused_unpressed_max);
-         RrAppearanceFree(theme->a_toggled_focused_pressed_max);
-         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_max);
-         RrAppearanceFree(theme->a_toggled_unfocused_pressed_max);
-         RrAppearanceFree(theme->a_focused_unpressed_max);
-         RrAppearanceFree(theme->a_focused_pressed_max);
-         RrAppearanceFree(theme->a_unfocused_unpressed_max);
-         RrAppearanceFree(theme->a_unfocused_pressed_max);
-         RrAppearanceFree(theme->a_disabled_focused_close);
-         RrAppearanceFree(theme->a_disabled_unfocused_close);
-         RrAppearanceFree(theme->a_hover_focused_close);
-         RrAppearanceFree(theme->a_hover_unfocused_close);
-         RrAppearanceFree(theme->a_focused_unpressed_close);
-         RrAppearanceFree(theme->a_focused_pressed_close);
-         RrAppearanceFree(theme->a_unfocused_unpressed_close);
-         RrAppearanceFree(theme->a_unfocused_pressed_close);
-         RrAppearanceFree(theme->a_disabled_focused_desk);
-         RrAppearanceFree(theme->a_disabled_unfocused_desk);
-         RrAppearanceFree(theme->a_hover_focused_desk);
-         RrAppearanceFree(theme->a_hover_unfocused_desk);
-         RrAppearanceFree(theme->a_toggled_hover_focused_desk);
-         RrAppearanceFree(theme->a_toggled_hover_unfocused_desk);
-         RrAppearanceFree(theme->a_toggled_focused_unpressed_desk);
-         RrAppearanceFree(theme->a_toggled_focused_pressed_desk);
-         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_desk);
-         RrAppearanceFree(theme->a_toggled_unfocused_pressed_desk);
-         RrAppearanceFree(theme->a_focused_unpressed_desk);
-         RrAppearanceFree(theme->a_focused_pressed_desk);
-         RrAppearanceFree(theme->a_unfocused_unpressed_desk);
-         RrAppearanceFree(theme->a_unfocused_pressed_desk);
-         RrAppearanceFree(theme->a_disabled_focused_shade);
-         RrAppearanceFree(theme->a_disabled_unfocused_shade);
-         RrAppearanceFree(theme->a_hover_focused_shade);
-         RrAppearanceFree(theme->a_hover_unfocused_shade);
-         RrAppearanceFree(theme->a_toggled_hover_focused_shade);
-         RrAppearanceFree(theme->a_toggled_hover_unfocused_shade);
-         RrAppearanceFree(theme->a_toggled_focused_unpressed_shade);
-         RrAppearanceFree(theme->a_toggled_focused_pressed_shade);
-         RrAppearanceFree(theme->a_toggled_unfocused_unpressed_shade);
-         RrAppearanceFree(theme->a_toggled_unfocused_pressed_shade);
-         RrAppearanceFree(theme->a_focused_unpressed_shade);
-         RrAppearanceFree(theme->a_focused_pressed_shade);
-         RrAppearanceFree(theme->a_unfocused_unpressed_shade);
-         RrAppearanceFree(theme->a_unfocused_pressed_shade);
-         RrAppearanceFree(theme->a_disabled_focused_iconify);
-         RrAppearanceFree(theme->a_disabled_unfocused_iconify);
-         RrAppearanceFree(theme->a_hover_focused_iconify);
-         RrAppearanceFree(theme->a_hover_unfocused_iconify);
-         RrAppearanceFree(theme->a_focused_unpressed_iconify);
-         RrAppearanceFree(theme->a_focused_pressed_iconify);
-         RrAppearanceFree(theme->a_unfocused_unpressed_iconify);
-         RrAppearanceFree(theme->a_unfocused_pressed_iconify);
          RrAppearanceFree(theme->a_focused_grip);
          RrAppearanceFree(theme->a_unfocused_grip);
          RrAppearanceFree(theme->a_focused_title);
diff --cc render/theme.h
index da8e80d3be72c62f30a2cfacaa2d021350bee36f,88178c8cb3a94f524992818ce21445da57a31cb6..542826ac8acc2442f5cb401bed8a2eec3358bf91
@@@ -87,8 -83,9 +87,10 @@@ struct _RrTheme 
      RrColor *titlebut_focused_unpressed_color;
      RrColor *titlebut_unfocused_unpressed_color;
      RrColor *menu_title_color;
 +    RrColor *menu_sep_color;
      RrColor *menu_color;
+     RrColor *menu_bullet_color;
+     RrColor *menu_bullet_selected_color;
      RrColor *menu_selected_color;
      RrColor *menu_disabled_color;
      RrColor *menu_disabled_selected_color;
      gchar    menu_text_disabled_selected_shadow_alpha;
  
      /* style settings - pics */
 -    RrPixel32 *def_win_icon; /* 48x48 RGBA */
 +    RrPixel32 *def_win_icon; /* RGBA */
 +    gint       def_win_icon_w;
 +    gint       def_win_icon_h;
  
      /* style settings - masks */
-     RrPixmapMask *max_mask;
-     RrPixmapMask *max_hover_mask;
-     RrPixmapMask *max_pressed_mask;
-     RrPixmapMask *max_toggled_mask;
-     RrPixmapMask *max_toggled_hover_mask;
-     RrPixmapMask *max_toggled_pressed_mask;
-     RrPixmapMask *max_disabled_mask;
-     RrPixmapMask *iconify_mask;
-     RrPixmapMask *iconify_hover_mask;
-     RrPixmapMask *iconify_pressed_mask;
-     RrPixmapMask *iconify_disabled_mask;
-     RrPixmapMask *desk_mask;
-     RrPixmapMask *desk_hover_mask;
-     RrPixmapMask *desk_pressed_mask;
-     RrPixmapMask *desk_toggled_mask;
-     RrPixmapMask *desk_toggled_hover_mask;
-     RrPixmapMask *desk_toggled_pressed_mask;
-     RrPixmapMask *desk_disabled_mask;
-     RrPixmapMask *shade_mask;
-     RrPixmapMask *shade_hover_mask;
-     RrPixmapMask *shade_pressed_mask;
-     RrPixmapMask *shade_toggled_mask;
-     RrPixmapMask *shade_toggled_hover_mask;
-     RrPixmapMask *shade_toggled_pressed_mask;
-     RrPixmapMask *shade_disabled_mask;
-     RrPixmapMask *close_mask;
-     RrPixmapMask *close_hover_mask;
-     RrPixmapMask *close_disabled_mask;
-     RrPixmapMask *close_pressed_mask;
      RrPixmapMask *menu_bullet_mask; /* submenu pointer */
  #if 0
      RrPixmapMask *menu_toggle_mask; /* menu boolean */
  #endif
  
 +    RrPixmapMask *down_arrow_mask;
 +    RrPixmapMask *up_arrow_mask;
 +
+     /* buttons */
+     RrButton *btn_max;
+     RrButton *btn_close;
+     RrButton *btn_desk;
+     RrButton *btn_shade;
+     RrButton *btn_iconify;
      /* global appearances */
-     RrAppearance *a_disabled_focused_max;
-     RrAppearance *a_disabled_unfocused_max;
-     RrAppearance *a_hover_focused_max;
-     RrAppearance *a_hover_unfocused_max;
-     RrAppearance *a_focused_unpressed_max;
-     RrAppearance *a_focused_pressed_max;
-     RrAppearance *a_unfocused_unpressed_max;
-     RrAppearance *a_unfocused_pressed_max;
-     RrAppearance *a_toggled_hover_focused_max;
-     RrAppearance *a_toggled_hover_unfocused_max;
-     RrAppearance *a_toggled_focused_unpressed_max;
-     RrAppearance *a_toggled_focused_pressed_max;
-     RrAppearance *a_toggled_unfocused_unpressed_max;
-     RrAppearance *a_toggled_unfocused_pressed_max;
-     RrAppearance *a_disabled_focused_close;
-     RrAppearance *a_disabled_unfocused_close;
-     RrAppearance *a_hover_focused_close;
-     RrAppearance *a_hover_unfocused_close;
-     RrAppearance *a_focused_unpressed_close;
-     RrAppearance *a_focused_pressed_close;
-     RrAppearance *a_unfocused_unpressed_close;
-     RrAppearance *a_unfocused_pressed_close;
-     RrAppearance *a_disabled_focused_desk;
-     RrAppearance *a_disabled_unfocused_desk;
-     RrAppearance *a_hover_focused_desk;
-     RrAppearance *a_hover_unfocused_desk;
-     RrAppearance *a_focused_unpressed_desk;
-     RrAppearance *a_focused_pressed_desk;
-     RrAppearance *a_unfocused_unpressed_desk;
-     RrAppearance *a_unfocused_pressed_desk;
-     RrAppearance *a_toggled_hover_focused_desk;
-     RrAppearance *a_toggled_hover_unfocused_desk;
-     RrAppearance *a_toggled_focused_unpressed_desk;
-     RrAppearance *a_toggled_focused_pressed_desk;
-     RrAppearance *a_toggled_unfocused_unpressed_desk;
-     RrAppearance *a_toggled_unfocused_pressed_desk;
-     RrAppearance *a_disabled_focused_shade;
-     RrAppearance *a_disabled_unfocused_shade;
-     RrAppearance *a_hover_focused_shade;
-     RrAppearance *a_hover_unfocused_shade;
-     RrAppearance *a_focused_unpressed_shade;
-     RrAppearance *a_focused_pressed_shade;
-     RrAppearance *a_unfocused_unpressed_shade;
-     RrAppearance *a_unfocused_pressed_shade;
-     RrAppearance *a_toggled_hover_focused_shade;
-     RrAppearance *a_toggled_hover_unfocused_shade;
-     RrAppearance *a_toggled_focused_unpressed_shade;
-     RrAppearance *a_toggled_focused_pressed_shade;
-     RrAppearance *a_toggled_unfocused_unpressed_shade;
-     RrAppearance *a_toggled_unfocused_pressed_shade;
-     RrAppearance *a_disabled_focused_iconify;
-     RrAppearance *a_disabled_unfocused_iconify;
-     RrAppearance *a_hover_focused_iconify;
-     RrAppearance *a_hover_unfocused_iconify;
-     RrAppearance *a_focused_unpressed_iconify;
-     RrAppearance *a_focused_pressed_iconify;
-     RrAppearance *a_unfocused_unpressed_iconify;
-     RrAppearance *a_unfocused_pressed_iconify;
      RrAppearance *a_focused_grip;
      RrAppearance *a_unfocused_grip;
      RrAppearance *a_focused_title;