X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/f486ea184ba1d605110eab4862406c11554ed13e..02d50cbd5926b4ef1f88c6f9ca28486fa45508c0:/disobedience/settings.c diff --git a/disobedience/settings.c b/disobedience/settings.c index 75f7396..2c4ffeb 100644 --- a/disobedience/settings.c +++ b/disobedience/settings.c @@ -1,21 +1,19 @@ /* * This file is part of Disobedience - * Copyright (C) 2007 Richard Kettlewell + * Copyright (C) 2007, 2008 Richard Kettlewell * - * This program is free software; you can redistribute it and/or modify + * 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 + * the Free Software Foundation, either version 3 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. - * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. If not, see . */ /** @file disobedience/settings.c * @brief Disobedience settings @@ -34,88 +32,127 @@ #include "split.h" #include -/** @brief Background colors for tools - menus, icons, etc. */ -GdkColor tool_bg = { 0, 0xDC00, 0xDA00, 0xD500 }; +/** @brief HTML displayer */ +const char *browser = BROWSER; -/** @brief Background color for active tool */ -GdkColor tool_active; +/** @brief Default style for layouts */ +GtkStyle *layout_style; -/** @brief Foreground colors for tools */ -GdkColor tool_fg = { 0, 0x0000, 0x0000, 0x0000 }; +/** @brief Title-row style for layouts */ +GtkStyle *title_style; -/** @brief Foreground colors for inactive tools */ -GdkColor inactive_tool_fg = { 0, 0x8000, 0x8000, 0x8000 }; +/** @brief Even-row style for layouts */ +GtkStyle *even_style; -/** @brief Background color for the various layouts */ -GdkColor layout_bg = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; +/** @brief Odd-row style for layouts */ +GtkStyle *odd_style; -/** @brief Title-row background color */ -GdkColor title_bg = { 0, 0x0000, 0x0000, 0x0000 }; +/** @brief Active-row style for layouts */ +GtkStyle *active_style; -/** @brief Title-row foreground color */ -GdkColor title_fg = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; +/** @brief Style for tools */ +GtkStyle *tool_style; -/** @brief Even-row background color */ -GdkColor even_bg = { 0, 0xFFFF, 0xEC00, 0xEBFF }; +/** @brief Style for search results */ +GtkStyle *search_style; -/** @brief Odd-row background color */ -GdkColor odd_bg = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; +/** @brief Style for drag targets */ +GtkStyle *drag_style; -/** @brief Active-row background color */ -GdkColor active_bg = { 0, 0xE000, 0xFFFF, 0xE000 }; +/** @brief Table of styles */ +static const struct { + const char *name; + GtkStyle **style; +} styles[] = { + { "layout", &layout_style }, + { "title", &title_style }, + { "even", &even_style }, + { "odd", &odd_style }, + { "active", &active_style }, + { "tool", &tool_style }, + { "search", &search_style }, + { "drag", &drag_style }, +}; -/** @brief Item foreground color */ -GdkColor item_fg = { 0, 0x0000, 0x0000, 0x0000 }; +#define NSTYLES (sizeof styles / sizeof *styles) -/** @brief Selected background color */ -GdkColor selected_bg = { 0, 0x4B00, 0x6900, 0x8300 }; +/** @brief Table of state types */ +static const char *const states[] = { + "normal", + "active", + "prelight", + "selected", + "insensitive" +}; -/** @brief Selected foreground color */ -GdkColor selected_fg = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; +#define NSTATES (sizeof states / sizeof *states) -/** @brief Search results */ -GdkColor search_bg = { 0, 0xFFFF, 0xFFFF, 0x0000 }; +/** @brief Table of colors */ +static const struct { + const char *name; + size_t offset; +} colors[] = { + { "fg", offsetof(GtkStyle, fg) }, + { "bg", offsetof(GtkStyle, bg) }, +}; -/** @brief Drag target color */ -GdkColor drag_target = { 0, 0x6666, 0x6666, 0x6666 }; +#define NCOLORS (sizeof colors / sizeof *colors) -/** @brief HTML displayer */ -const char *browser = BROWSER; +/** @brief Initialize styles */ +void init_styles(void) { + layout_style = gtk_style_new(); + title_style = gtk_style_new(); + even_style = gtk_style_new(); + odd_style = gtk_style_new(); + active_style = gtk_style_new(); + search_style = gtk_style_new(); + tool_style = gtk_style_new(); + drag_style = gtk_style_new(); -struct colordesc { - GdkColor *color; - const char *name; - const char *description; -}; + /* Style defaults */ + + /* Layouts are basically black on white */ + layout_style->bg[GTK_STATE_NORMAL] = layout_style->white; + layout_style->fg[GTK_STATE_NORMAL] = layout_style->black; + + /* Title row is inverted */ + title_style->bg[GTK_STATE_NORMAL] = layout_style->fg[GTK_STATE_NORMAL]; + title_style->fg[GTK_STATE_NORMAL] = layout_style->bg[GTK_STATE_NORMAL]; -#define COLOR(name, description) { &name, #name, description } + /* Active row is pastel green */ + active_style->bg[GTK_STATE_NORMAL].red = 0xE000; + active_style->bg[GTK_STATE_NORMAL].green = 0xFFFF; + active_style->bg[GTK_STATE_NORMAL].blue = 0xE000; + active_style->fg[GTK_STATE_NORMAL] = layout_style->fg[GTK_STATE_NORMAL]; -/** @brief Table of configurable colors - * - * Some of the descriptions could be improve! - */ -static const struct colordesc colors[] = { - COLOR(tool_bg, "Tool background color"), - COLOR(tool_fg, "Tool foreground color"), - COLOR(layout_bg, "Layout background color"), - COLOR(title_bg, "Title row background color"), - COLOR(title_fg, "Title row foreground color"), - COLOR(even_bg, "Even row background color"), - COLOR(odd_bg, "Odd row background color"), - COLOR(active_bg, "Playing row background color"), - COLOR(item_fg, "Track foreground color"), - COLOR(selected_bg, "Selected item background color"), - COLOR(selected_fg, "Selected item foreground color"), - COLOR(search_bg, "Search result background color"), - COLOR(drag_target, "Drag target color"), -}; + /* Even rows are pastel red */ + even_style->bg[GTK_STATE_NORMAL].red = 0xFFFF; + even_style->bg[GTK_STATE_NORMAL].green = 0xEC00; + even_style->bg[GTK_STATE_NORMAL].blue = 0xEC00; + even_style->fg[GTK_STATE_NORMAL] = layout_style->fg[GTK_STATE_NORMAL]; -#define NCOLORS (sizeof colors / sizeof *colors) + /* Odd rows match the underlying layout */ + odd_style->bg[GTK_STATE_NORMAL] = layout_style->bg[GTK_STATE_NORMAL]; + odd_style->fg[GTK_STATE_NORMAL] = layout_style->fg[GTK_STATE_NORMAL]; + + /* Search results have a yellow background */ + search_style->fg[GTK_STATE_NORMAL] = layout_style->fg[GTK_STATE_NORMAL]; + search_style->bg[GTK_STATE_NORMAL].red = 0xFFFF; + search_style->bg[GTK_STATE_NORMAL].green = 0xFFFF; + search_style->bg[GTK_STATE_NORMAL].blue = 0x0000; + + /* Drag targets are grey */ + drag_style->bg[GTK_STATE_NORMAL].red = 0x6666; + drag_style->bg[GTK_STATE_NORMAL].green = 0x6666; + drag_style->bg[GTK_STATE_NORMAL].blue = 0x6666; + + /* Tools we leave at GTK+ defaults */ +} void save_settings(void) { char *dir, *path, *tmp; FILE *fp = 0; - size_t n; + size_t n, m, c; byte_xasprintf(&dir, "%s/.disorder", getenv("HOME")); byte_xasprintf(&path, "%s/disobedience", dir); @@ -126,19 +163,27 @@ void save_settings(void) { tmp, strerror(errno)); goto done; } - for(n = 0; n < NCOLORS; ++n) - if(fprintf(fp, "color %-20s 0x%04X 0x%04X 0x%04X\n", colors[n].name, - colors[n].color->red, - colors[n].color->green, - colors[n].color->blue) < 0) { - fpopup_msg(GTK_MESSAGE_ERROR, "error writing to %s: %s", - tmp, strerror(errno)); - goto done; - } + if(fprintf(fp, + "# automatically generated!\n\n") < 0) + goto write_error; + for(n = 0; n < NSTYLES; ++n) + for(c = 0; c < NCOLORS; ++c) + for(m = 0; m < NSTATES; ++m) { + const GdkColor *color = (GdkColor *)((char *)styles[n].style + colors[c].offset) + m; + if(fprintf(fp, "color %8s %12s %s 0x%04x 0x%04x 0x%04x\n", + styles[n].name, states[m], colors[c].name, + color->red, + color->green, + color->blue) < 0) + goto write_error; + } + if(fprintf(fp, "browser %s\n", browser) < 0) + goto write_error; if(fclose(fp) < 0) { + fp = 0; + write_error: fpopup_msg(GTK_MESSAGE_ERROR, "error writing to %s: %s", tmp, strerror(errno)); - fp = 0; goto done; } fp = 0; @@ -157,9 +202,9 @@ static inline unsigned clamp(unsigned n) { void load_settings(void) { char *path, *line; FILE *fp; - size_t n; char **vec; int nvec; + size_t n, m, c; byte_xasprintf(&path, "%s/.disorder/disobedience", getenv("HOME")); if(!(fp = fopen(path, "r"))) { @@ -172,22 +217,42 @@ void load_settings(void) { || !nvec) continue; if(!strcmp(vec[0], "color")) { - if(nvec != 5) { - error(0, "%s: malformed '%s' command", path, vec[0]); + GdkColor *color; + if(nvec != 7) { + disorder_error(0, "%s: malformed '%s' command", path, vec[0]); + continue; + } + for(n = 0; n < NSTYLES && strcmp(styles[n].name, vec[1]); ++n) + ; + if(n >= NSTYLES) { + disorder_error(0, "%s: unknown style '%s'", path, vec[1]); continue; } - for(n = 0; n < NCOLORS && strcmp(colors[n].name, vec[1]); ++n) + for(m = 0; m < NSTATES && strcmp(states[m], vec[2]); ++m) ; - if(n >= NCOLORS) { - error(0, "%s: unknown color '%s'", path, vec[1]); + if(m >= NSTATES) { + disorder_error(0, "%s: unknown state '%s'", path, vec[2]); + continue; + } + for(c = 0; c < NCOLORS && strcmp(colors[c].name, vec[3]); ++c) + ; + if(c >= NCOLORS) { + disorder_error(0, "%s: unknown color '%s'", path, vec[3]); + continue; + } + color = (GdkColor *)((char *)styles[n].style + colors[c].offset) + m; + color->red = strtoul(vec[4], 0, 0); + color->green = strtoul(vec[5], 0, 0); + color->blue = strtoul(vec[6], 0, 0); + } else if(!strcmp(vec[0], "browser")) { + if(nvec != 2) { + disorder_error(0, "%s: malformed '%s' command", path, vec[0]); continue; } - colors[n].color->red = strtoul(vec[2], 0, 0); - colors[n].color->green = strtoul(vec[3], 0, 0); - colors[n].color->blue = strtoul(vec[4], 0, 0); + browser = vec[1]; } else /* mention errors but otherwise ignore them */ - error(0, "%s: unknown command '%s'", path, vec[0]); + disorder_error(0, "%s: unknown command '%s'", path, vec[0]); } if(ferror(fp)) { fpopup_msg(GTK_MESSAGE_ERROR, "error reading %s: %s", @@ -195,49 +260,79 @@ void load_settings(void) { fclose(fp); } } - tool_active = tool_bg; - tool_active.red = clamp(105 * tool_active.red / 100); - tool_active.green = clamp(105 * tool_active.green / 100); - tool_active.blue = clamp(105 * tool_active.blue / 100); } -/** @brief Callback used by set_tool_colors() */ -static void set_tool_colors_callback(GtkWidget *w, - gpointer attribute((unused)) data) { - set_tool_colors(w); +/** @brief Recursively set tool widget colors + * + * This is currently unused; the idea was to allow for configurability without + * allowing GTK+ to override our use of color, but things seem generally better + * without this particular call. + */ +void set_tool_colors(GtkWidget attribute((unused)) *w) { } -/** @brief Recursively set tool widget colors */ -void set_tool_colors(GtkWidget *w) { - GtkWidget *child; - - gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &tool_bg); - gtk_widget_modify_bg(w, GTK_STATE_SELECTED, &selected_bg); - gtk_widget_modify_bg(w, GTK_STATE_PRELIGHT, &selected_bg); - gtk_widget_modify_bg(w, GTK_STATE_INSENSITIVE, &tool_bg); - gtk_widget_modify_fg(w, GTK_STATE_NORMAL, &tool_fg); - gtk_widget_modify_fg(w, GTK_STATE_SELECTED, &selected_fg); - gtk_widget_modify_fg(w, GTK_STATE_PRELIGHT, &selected_fg); - gtk_widget_modify_fg(w, GTK_STATE_INSENSITIVE, &inactive_tool_fg); - if(GTK_IS_CONTAINER(w)) - gtk_container_foreach(GTK_CONTAINER(w), set_tool_colors_callback, 0); - if(GTK_IS_MENU_ITEM(w) - && (child = gtk_menu_item_get_submenu(GTK_MENU_ITEM(w)))) - set_tool_colors(child); -} +/** @brief Pop up a settings editor widget */ +void popup_settings(void) { + static GtkWidget *settings_window; + GtkWidget *table; + unsigned row, col; -/** @brief Set the colors for a slider */ -void set_slider_colors(GtkWidget *w) { - if(!w) + if(settings_window) { + gtk_window_present(GTK_WINDOW(settings_window)); return; - gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &tool_bg); - gtk_widget_modify_bg(w, GTK_STATE_ACTIVE, &tool_bg); - gtk_widget_modify_bg(w, GTK_STATE_SELECTED, &tool_active); - gtk_widget_modify_bg(w, GTK_STATE_PRELIGHT, &tool_active); - gtk_widget_modify_fg(w, GTK_STATE_NORMAL, &tool_fg); - gtk_widget_modify_fg(w, GTK_STATE_ACTIVE, &tool_fg); - gtk_widget_modify_fg(w, GTK_STATE_SELECTED, &tool_fg); - gtk_widget_modify_fg(w, GTK_STATE_PRELIGHT, &tool_fg); + } + /* Create the window */ + settings_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_style(settings_window, tool_style); + gtk_window_set_title(GTK_WINDOW(settings_window), "Disobedience Settings"); + /* Clear the pointer to the window widget when it is closed */ + g_signal_connect(settings_window, "destroy", + G_CALLBACK(gtk_widget_destroyed), &settings_window); + + /* The color settings live in a big table */ + table = gtk_table_new(2 * NSTYLES + 1/*rows */, NSTATES + 1/*cols*/, + TRUE/*homogeneous*/); + /* Titles */ + for(row = 0; row < 2 * NSTYLES; ++row) { + char *legend; + + byte_xasprintf(&legend, "%s %s", styles[row / 2].name, + row % 2 ? "background" : "foreground"); + gtk_table_attach(GTK_TABLE(table), + gtk_label_new(legend), + 0, 1, + row + 1, row + 2, + GTK_FILL, GTK_FILL, + 1, 1); + } + for(col = 0; col < NSTATES; ++col) { + gtk_table_attach(GTK_TABLE(table), + gtk_label_new(states[col]), + col + 1, col + 2, + 0, 1, + GTK_FILL, GTK_FILL, + 1, 1); + } + /* The actual colors */ + for(row = 0; row < 2 * NSTYLES; ++row) { + for(col = 0; col < NSTATES; ++col) { + GdkColor *const c = &(row % 2 + ? (**styles[row / 2].style).bg + : (**styles[row / 2].style).fg)[col]; + gtk_table_attach(GTK_TABLE(table), + gtk_color_button_new_with_color(c), + col + 1, col + 2, + row + 1, row + 2, + GTK_FILL, GTK_FILL, + 1, 1); + } + } + gtk_container_add(GTK_CONTAINER(settings_window), frame_widget(table, NULL)); + gtk_widget_show_all(settings_window); + /* TODO: save settings + TODO: web browser + TODO: impose settings when they are set + */ } /*