Mercurial > pidgin
view finch/libgnt/gntbox.c @ 17148:9a649a04fd74
When the /pidgin/debug/enabled pref is toggled, wait until the next
iteration through the event loop before drawing or hiding the window.
This fixes the bug where we lost the width and height prefs for the
debug window because of the following sequence of event
1. Init gtkdebug window, set default width and height
2. Read in pref for /pidgin/debug/enabled and show debug window using
default width and height
3. Read in pref for /pidgin/debug/width and height, but it's too
late! The window has already been drawn using the default
width and height!
This is a pretty minor thing, but it was bugging me. I don't like
having to always make the debug window bigger when I start Pidgin.
The downside of this change is that we won't see as much debug output
in the window when starting Pidgin.
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 22 May 2007 07:08:57 +0000 |
parents | 92fa7d6e75b0 |
children | 8410511f4dbb 05d7fe2320a9 |
line wrap: on
line source
#include "gntbox.h" #include "gntutils.h" #include <string.h> enum { SIGS = 1, }; static GntWidgetClass *parent_class = NULL; static GntWidget * find_focusable_widget(GntBox *box); static void add_to_focus(gpointer value, gpointer data) { GntBox *box = GNT_BOX(data); GntWidget *w = GNT_WIDGET(value); if (GNT_IS_BOX(w)) g_list_foreach(GNT_BOX(w)->list, add_to_focus, box); else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_CAN_TAKE_FOCUS)) box->focus = g_list_append(box->focus, w); } static void get_title_thingies(GntBox *box, char *title, int *p, int *r) { GntWidget *widget = GNT_WIDGET(box); int len; char *end = (char*)gnt_util_onscreen_width_to_pointer(title, widget->priv.width - 4, &len); if (p) *p = (widget->priv.width - len) / 2; if (r) *r = (widget->priv.width + len) / 2; *end = '\0'; } static void gnt_box_draw(GntWidget *widget) { GntBox *box = GNT_BOX(widget); if (box->focus == NULL && widget->parent == NULL) g_list_foreach(box->list, add_to_focus, box); g_list_foreach(box->list, (GFunc)gnt_widget_draw, NULL); gnt_box_sync_children(box); if (box->title && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) { int pos, right; char *title = g_strdup(box->title); get_title_thingies(box, title, &pos, &right); if (gnt_widget_has_focus(widget)) wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TITLE)); else wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_TITLE_D)); mvwaddch(widget->window, 0, pos-1, ACS_RTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); mvwaddstr(widget->window, 0, pos, title); mvwaddch(widget->window, 0, right, ACS_LTEE | COLOR_PAIR(GNT_COLOR_NORMAL)); g_free(title); } GNTDEBUG; } static void reposition_children(GntWidget *widget) { GList *iter; GntBox *box = GNT_BOX(widget); int w, h, curx, cury, max; gboolean has_border = FALSE; w = h = 0; max = 0; curx = widget->priv.x; cury = widget->priv.y; if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER)) { has_border = TRUE; curx += 1; cury += 1; } for (iter = box->list; iter; iter = iter->next) { if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(iter->data), GNT_WIDGET_INVISIBLE)) continue; gnt_widget_set_position(GNT_WIDGET(iter->data), curx, cury); gnt_widget_get_size(GNT_WIDGET(iter->data), &w, &h); if (box->vertical) { if (h) { cury += h + box->pad; if (max < w) max = w; } } else { if (w) { curx += w + box->pad; if (max < h) max = h; } } } if (has_border) { curx += 1; cury += 1; max += 2; } if (box->list) { if (box->vertical) cury -= box->pad; else curx -= box->pad; } if (box->vertical) { widget->priv.width = max; widget->priv.height = cury - widget->priv.y; } else { widget->priv.width = curx - widget->priv.x; widget->priv.height = max; } } static void gnt_box_set_position(GntWidget *widget, int x, int y) { GList *iter; int changex, changey; changex = widget->priv.x - x; changey = widget->priv.y - y; for (iter = GNT_BOX(widget)->list; iter; iter = iter->next) { GntWidget *w = GNT_WIDGET(iter->data); gnt_widget_set_position(w, w->priv.x - changex, w->priv.y - changey); } } static void gnt_box_size_request(GntWidget *widget) { GntBox *box = GNT_BOX(widget); GList *iter; int maxw = 0, maxh = 0; g_list_foreach(box->list, (GFunc)gnt_widget_size_request, NULL); for (iter = box->list; iter; iter = iter->next) { int w, h; gnt_widget_get_size(GNT_WIDGET(iter->data), &w, &h); if (maxh < h) maxh = h; if (maxw < w) maxw = w; } for (iter = box->list; iter; iter = iter->next) { int w, h; GntWidget *wid = GNT_WIDGET(iter->data); gnt_widget_get_size(wid, &w, &h); if (box->homogeneous) { if (box->vertical) h = maxh; else w = maxw; } if (box->fill) { if (box->vertical) w = maxw; else h = maxh; } gnt_widget_set_size(wid, w, h); } reposition_children(widget); } static void gnt_box_map(GntWidget *widget) { if (widget->priv.width == 0 || widget->priv.height == 0) { gnt_widget_size_request(widget); find_focusable_widget(GNT_BOX(widget)); } GNTDEBUG; } /* Ensures that the current widget can take focus */ static GntWidget * find_focusable_widget(GntBox *box) { /* XXX: Make sure the widget is visible? */ if (box->focus == NULL && GNT_WIDGET(box)->parent == NULL) g_list_foreach(box->list, add_to_focus, box); if (box->active == NULL && box->focus) box->active = box->focus->data; return box->active; } static void find_next_focus(GntBox *box) { gpointer last = box->active; do { GList *iter = g_list_find(box->focus, box->active); if (iter && iter->next) box->active = iter->next->data; else if (box->focus) box->active = box->focus->data; if (!GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_INVISIBLE)) break; } while (box->active != last); } static void find_prev_focus(GntBox *box) { gpointer last = box->active; if (!box->focus) return; do { GList *iter = g_list_find(box->focus, box->active); if (!iter) box->active = box->focus->data; else if (!iter->prev) box->active = g_list_last(box->focus)->data; else box->active = iter->prev->data; if (!GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_INVISIBLE)) break; } while (box->active != last); } static gboolean gnt_box_key_pressed(GntWidget *widget, const char *text) { GntBox *box = GNT_BOX(widget); GntWidget *now; if (box->active == NULL && !find_focusable_widget(box)) return FALSE; if (gnt_widget_key_pressed(box->active, text)) return TRUE; now = box->active; if (text[0] == 27) { if (strcmp(text, GNT_KEY_LEFT) == 0) { find_prev_focus(box); } else if (strcmp(text, GNT_KEY_RIGHT) == 0) { find_next_focus(box); } } else if (text[0] == '\t') { find_next_focus(box); } if (now && now != box->active) { gnt_widget_set_focus(now, FALSE); gnt_widget_set_focus(box->active, TRUE); return TRUE; } return FALSE; } static void gnt_box_lost_focus(GntWidget *widget) { GntWidget *w = GNT_BOX(widget)->active; if (w) gnt_widget_set_focus(w, FALSE); gnt_widget_draw(widget); } static void gnt_box_gained_focus(GntWidget *widget) { GntWidget *w = GNT_BOX(widget)->active; if (w) gnt_widget_set_focus(w, TRUE); gnt_widget_draw(widget); } static void gnt_box_destroy(GntWidget *w) { GntBox *box = GNT_BOX(w); gnt_box_remove_all(box); gnt_screen_release(w); } static void gnt_box_expose(GntWidget *widget, int x, int y, int width, int height) { WINDOW *win = newwin(height, width, widget->priv.y + y, widget->priv.x + x); copywin(widget->window, win, y, x, 0, 0, height - 1, width - 1, FALSE); wrefresh(win); delwin(win); } static gboolean gnt_box_confirm_size(GntWidget *widget, int width, int height) { GList *iter; GntBox *box = GNT_BOX(widget); int wchange, hchange; if (!box->list) return TRUE; wchange = widget->priv.width - width; hchange = widget->priv.height - height; if (wchange == 0 && hchange == 0) return TRUE; /* Quit playing games */ /* XXX: Right now, I am trying to just apply all the changes to * just one widget. It should be possible to distribute the * changes to all the widgets in the box. */ for (iter = box->list; iter; iter = iter->next) { GntWidget *wid = iter->data; int w, h; gnt_widget_get_size(wid, &w, &h); if (gnt_widget_confirm_size(wid, w - wchange, h - hchange)) { GList *i; for (i = box->list; i; i = i->next) { int tw, th; if (i == iter) continue; gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); if (box->vertical) { if (!gnt_widget_confirm_size(i->data, tw - wchange, th)) { /* If we are decreasing the size and the widget is going * to be too large to fit into the box, then do not allow * resizing. */ if (wchange > 0 && tw >= widget->priv.width) return FALSE; } } else { if (!gnt_widget_confirm_size(i->data, tw, th - hchange)) { if (hchange > 0 && th >= widget->priv.height) return FALSE; return FALSE; } } } #if 0 gnt_widget_set_size(wid, w - wchange, h - hchange); if (box->vertical) hchange = 0; else wchange = 0; for (i = box->list; i; i = i->next) { int tw, th; if (i == iter) continue; gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); gnt_widget_set_size(i->data, tw - wchange, th - hchange); } #endif g_object_set_data(G_OBJECT(box), "size-queued", wid); return TRUE; } } return FALSE; } static void gnt_box_size_changed(GntWidget *widget, int oldw, int oldh) { int wchange, hchange; GList *i; GntBox *box = GNT_BOX(widget); GntWidget *wid; int tw, th; wchange = widget->priv.width - oldw; hchange = widget->priv.height - oldh; wid = g_object_get_data(G_OBJECT(box), "size-queued"); if (wid) { gnt_widget_get_size(wid, &tw, &th); gnt_widget_set_size(wid, tw + wchange, th + hchange); g_object_set_data(G_OBJECT(box), "size-queued", NULL); } if (box->vertical) hchange = 0; else wchange = 0; for (i = box->list; i; i = i->next) { if (wid != i->data) { gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th); gnt_widget_set_size(i->data, tw + wchange, th + hchange); } } reposition_children(widget); } static gboolean gnt_box_clicked(GntWidget *widget, GntMouseEvent event, int cx, int cy) { GList *iter; for (iter = GNT_BOX(widget)->list; iter; iter = iter->next) { int x, y, w, h; GntWidget *wid = iter->data; gnt_widget_get_position(wid, &x, &y); gnt_widget_get_size(wid, &w, &h); if (cx >= x && cx < x + w && cy >= y && cy < y + h) { if (event <= GNT_MIDDLE_MOUSE_DOWN && GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_CAN_TAKE_FOCUS)) { while (widget->parent) widget = widget->parent; gnt_box_give_focus_to_child(GNT_BOX(widget), wid); } return gnt_widget_clicked(wid, event, cx, cy); } } return FALSE; } static void gnt_box_class_init(GntBoxClass *klass) { parent_class = GNT_WIDGET_CLASS(klass); parent_class->destroy = gnt_box_destroy; parent_class->draw = gnt_box_draw; parent_class->expose = gnt_box_expose; parent_class->map = gnt_box_map; parent_class->size_request = gnt_box_size_request; parent_class->set_position = gnt_box_set_position; parent_class->key_pressed = gnt_box_key_pressed; parent_class->clicked = gnt_box_clicked; parent_class->lost_focus = gnt_box_lost_focus; parent_class->gained_focus = gnt_box_gained_focus; parent_class->confirm_size = gnt_box_confirm_size; parent_class->size_changed = gnt_box_size_changed; GNTDEBUG; } static void gnt_box_init(GTypeInstance *instance, gpointer class) { GntWidget *widget = GNT_WIDGET(instance); GntBox *box = GNT_BOX(widget); /* Initially make both the height and width resizable. * Update the flags as necessary when widgets are added to it. */ GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); box->pad = 1; box->fill = TRUE; GNTDEBUG; } /****************************************************************************** * GntBox API *****************************************************************************/ GType gnt_box_get_gtype(void) { static GType type = 0; if(type == 0) { static const GTypeInfo info = { sizeof(GntBoxClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc)gnt_box_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof(GntBox), 0, /* n_preallocs */ gnt_box_init, /* instance_init */ NULL /* value_table */ }; type = g_type_register_static(GNT_TYPE_WIDGET, "GntBox", &info, 0); } return type; } GntWidget *gnt_box_new(gboolean homo, gboolean vert) { GntWidget *widget = g_object_new(GNT_TYPE_BOX, NULL); GntBox *box = GNT_BOX(widget); box->homogeneous = homo; box->vertical = vert; box->alignment = vert ? GNT_ALIGN_LEFT : GNT_ALIGN_MID; return widget; } void gnt_box_add_widget(GntBox *b, GntWidget *widget) { b->list = g_list_append(b->list, widget); widget->parent = GNT_WIDGET(b); } void gnt_box_set_title(GntBox *b, const char *title) { char *prev = b->title; GntWidget *w = GNT_WIDGET(b); b->title = g_strdup(title); if (w->window && !GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_NO_BORDER)) { /* Erase the old title */ int pos, right; get_title_thingies(b, prev, &pos, &right); mvwhline(w->window, 0, pos - 1, ACS_HLINE | COLOR_PAIR(GNT_COLOR_NORMAL), right - pos + 2); g_free(prev); } } void gnt_box_set_pad(GntBox *box, int pad) { box->pad = pad; /* XXX: Perhaps redraw if already showing? */ } void gnt_box_set_toplevel(GntBox *box, gboolean set) { GntWidget *widget = GNT_WIDGET(box); if (set) { GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); } else { GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); } } void gnt_box_sync_children(GntBox *box) { GList *iter; GntWidget *widget = GNT_WIDGET(box); int pos = 1; if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER)) pos = 0; for (iter = box->list; iter; iter = iter->next) { GntWidget *w = GNT_WIDGET(iter->data); int height, width; int x, y; if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_INVISIBLE)) continue; if (GNT_IS_BOX(w)) gnt_box_sync_children(GNT_BOX(w)); gnt_widget_get_size(w, &width, &height); x = w->priv.x - widget->priv.x; y = w->priv.y - widget->priv.y; if (box->vertical) { x = pos; if (box->alignment == GNT_ALIGN_RIGHT) x += widget->priv.width - width; else if (box->alignment == GNT_ALIGN_MID) x += (widget->priv.width - width)/2; if (x + width > widget->priv.width - pos) x -= x + width - (widget->priv.width - pos); } else { y = pos; if (box->alignment == GNT_ALIGN_BOTTOM) y += widget->priv.height - height; else if (box->alignment == GNT_ALIGN_MID) y += (widget->priv.height - height)/2; if (y + height >= widget->priv.height - pos) y = widget->priv.height - height - pos; } copywin(w->window, widget->window, 0, 0, y, x, y + height - 1, x + width - 1, FALSE); gnt_widget_set_position(w, x + widget->priv.x, y + widget->priv.y); } } void gnt_box_set_alignment(GntBox *box, GntAlignment alignment) { box->alignment = alignment; } void gnt_box_remove(GntBox *box, GntWidget *widget) { box->list = g_list_remove(box->list, widget); if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS) && GNT_WIDGET(box)->parent == NULL && box->focus) { if (widget == box->active) { find_next_focus(box); if (box->active == widget) /* There's only one widget */ box->active = NULL; } box->focus = g_list_remove(box->focus, widget); } if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(box), GNT_WIDGET_MAPPED)) gnt_widget_draw(GNT_WIDGET(box)); } void gnt_box_remove_all(GntBox *box) { g_list_foreach(box->list, (GFunc)gnt_widget_destroy, NULL); g_list_free(box->list); g_list_free(box->focus); box->list = NULL; box->focus = NULL; GNT_WIDGET(box)->priv.width = 0; GNT_WIDGET(box)->priv.height = 0; } void gnt_box_readjust(GntBox *box) { GList *iter; GntWidget *wid; int width, height; if (GNT_WIDGET(box)->parent != NULL) return; for (iter = box->list; iter; iter = iter->next) { GntWidget *w = iter->data; if (GNT_IS_BOX(w)) gnt_box_readjust(GNT_BOX(w)); else { GNT_WIDGET_UNSET_FLAGS(w, GNT_WIDGET_MAPPED); w->priv.width = 0; w->priv.height = 0; } } wid = GNT_WIDGET(box); GNT_WIDGET_UNSET_FLAGS(wid, GNT_WIDGET_MAPPED); wid->priv.width = 0; wid->priv.height = 0; if (wid->parent == NULL) { g_list_free(box->focus); box->focus = NULL; box->active = NULL; gnt_widget_size_request(wid); gnt_widget_get_size(wid, &width, &height); gnt_screen_resize_widget(wid, width, height); find_focusable_widget(box); } } void gnt_box_set_fill(GntBox *box, gboolean fill) { box->fill = fill; } void gnt_box_move_focus(GntBox *box, int dir) { GntWidget *now; if (box->active == NULL) { find_focusable_widget(box); return; } now = box->active; if (dir == 1) find_next_focus(box); else if (dir == -1) find_prev_focus(box); if (now && now != box->active) { gnt_widget_set_focus(now, FALSE); gnt_widget_set_focus(box->active, TRUE); } if (GNT_WIDGET(box)->window) gnt_widget_draw(GNT_WIDGET(box)); } void gnt_box_give_focus_to_child(GntBox *box, GntWidget *widget) { GList *find = g_list_find(box->focus, widget); gpointer now = box->active; if (find) box->active = widget; if (now && now != box->active) { gnt_widget_set_focus(now, FALSE); gnt_widget_set_focus(box->active, TRUE); } if (GNT_WIDGET(box)->window) gnt_widget_draw(GNT_WIDGET(box)); }