jcs
/wallops
/amendments
/105
chatter: Fix background window updates
For some reason doing TEPinScroll in a TE of a background window, in
a background tab, does not honor the clip region and draws where it's
not supposed to. Handle this by setting a flag so when we switch to
that window and tab, we'll scroll it down before updating it.
Also ditch the tab bar shadow and just use the per-window shadow to
do all drawing. Add a reference counter to it so all callers don't
need to figure out if they're down the chain from an update that has
already called use_shadow.
jcs made amendment 105 2 months ago
--- chatter.c Fri Sep 13 17:51:11 2024
+++ chatter.c Mon Sep 16 09:24:57 2024
@@ -30,6 +30,7 @@
static Handle scrp_rec_h = NULL;
static Pattern tab_bar_pattern;
static Rect zerorect = { 0, 0, 0, 0 };
+static BitMap shadow_cur_bits;
void chatter_layout(struct chatter *chatter, bool init, Rect *init_bounds);
void chatter_draw_tab_bar(struct chatter *chatter);
@@ -348,10 +349,12 @@ chatter_focus_tab(struct chatter *chatter, struct chat
RgnHandle clip;
Rect r;
+ if (chatter->current_tab && chatter->current_tab == tab)
+ return;
+
+ chatter_use_shadow(chatter);
+
if (chatter->current_tab) {
- if (chatter->current_tab == tab)
- return;
-
/*
* Doing the HideControl takes out the top line of our tab bar,
* so clip to just above it
@@ -389,6 +392,12 @@ chatter_focus_tab(struct chatter *chatter, struct chat
chatter->current_tab = tab;
+ if (tab->need_downscroll) {
+ chatter_autoscroll(chatter, tab->messages_te,
+ tab->messages_scroller);
+ tab->need_downscroll = false;
+ }
+
HLock(tab->messages_te);
EraseRect(&(*(tab->messages_te))->viewRect);
TEActivate(tab->messages_te);
@@ -412,6 +421,7 @@ chatter_focus_tab(struct chatter *chatter, struct chat
DrawControls(chatter->win);
chatter_draw_tab_bar(chatter);
+ chatter_reveal_shadow(chatter);
if (chatter->focusable)
chatter_update_menu(chatter->focusable);
@@ -460,8 +470,6 @@ chatter_close(struct focusable *focusable)
}
}
- if (chatter->tab_bar.baseAddr)
- xfree(&chatter->tab_bar.baseAddr);
if (chatter->shadow.baseAddr)
xfree(&chatter->shadow.baseAddr);
@@ -541,6 +549,9 @@ chatter_idle(struct focusable *focusable, EventRecord
chatter_draw_tab_bar(chatter);
chatter_update_titlebar(chatter);
}
+
+ if (chatter->shadow_refcnt != 0)
+ panic("shadow refcnt %d", chatter->shadow_refcnt);
}
void
@@ -621,21 +632,6 @@ chatter_draw_tab_bar(struct chatter *chatter)
static const char no_connection[] = "Disconnected";
struct chatter_tab *tab;
- cur_bits = thePort->portBits;
-
- if (chatter->tab_bar.baseAddr == 0) {
- width = chatter->win->portRect.right - chatter->win->portRect.left;
- chatter->tab_bar.rowBytes = (((width - 1) / 16) + 1) * 2;
- chatter->tab_bar.baseAddr = xmalloczero(
- (long)chatter->tab_bar.rowBytes * TAB_BAR_HEIGHT);
- if (chatter->tab_bar.baseAddr == NULL)
- panic("malloc(%ld) failed: out of memory",
- (long)chatter->tab_bar.rowBytes * TAB_BAR_HEIGHT);
- SetRect(&chatter->tab_bar.bounds, 0, 0, width, TAB_BAR_HEIGHT);
- }
-
- SetPortBits(&chatter->tab_bar);
-
TextFont(geneva);
TextSize(9);
@@ -645,11 +641,13 @@ chatter_draw_tab_bar(struct chatter *chatter)
chatter->ntabs;
if (tab_width > MAX_TAB_WIDTH)
tab_width = MAX_TAB_WIDTH;
-
- r.top = 0;
- r.bottom = TAB_BAR_HEIGHT;
+
+ HLock(chatter->input_te);
r.left = 0;
r.right = chatter->win->portRect.right - chatter->win->portRect.left;
+ r.bottom = (*(chatter->input_te))->viewRect.top;
+ r.top = r.bottom - TAB_BAR_HEIGHT;
+ HUnlock(chatter->input_te);
FillRect(&r, tab_bar_pattern);
r.left--;
@@ -725,22 +723,6 @@ chatter_draw_tab_bar(struct chatter *chatter)
TextSize(10);
TextFace(0);
- SetPortBits(&cur_bits);
-
- HLock(chatter->input_te);
- r = chatter->tab_bar.bounds;
- r.bottom = (*(chatter->input_te))->viewRect.top;
- r.top += r.bottom - TAB_BAR_HEIGHT;
- HUnlock(chatter->input_te);
-
- SLIST_FOREACH(tab, &chatter->tabs_list, list) {
- tab->label_rect.top += r.top;
- tab->label_rect.bottom += r.top;
- }
-
- CopyBits(&chatter->tab_bar, &thePort->portBits,
- &chatter->tab_bar.bounds, &r, srcCopy, nil);
-
chatter_draw_grow_icon(chatter);
}
@@ -857,9 +839,7 @@ chatter_mouse_down(struct focusable *focusable, EventR
SLIST_FOREACH(ttab, &chatter->tabs_list, list) {
if (PtInRect(p, &ttab->label_rect)) {
- chatter_use_shadow(chatter);
chatter_focus_tab(chatter, ttab);
- chatter_reveal_shadow(chatter);
return;
}
}
@@ -912,10 +892,6 @@ chatter_resize(struct focusable *focusable, EventRecor
SizeWindow(focusable->win, width, height, true);
EraseRect(&chatter->win->portRect);
- /* chatter_draw_tab_bar will recreate this to the new size */
- if (chatter->tab_bar.baseAddr)
- xfree(&chatter->tab_bar.baseAddr);
-
/* update each tab that isn't the current one */
savergn = NewRgn();
GetClip(savergn);
@@ -1108,6 +1084,7 @@ chatter_printf(struct chatter *chatter, struct irc_con
StScrpRec *scrp_rec;
ScrpSTElement *scrp_ele, *prev_scrp_ele;
RgnHandle savergn;
+ GrafPtr old_port;
va_list argptr;
size_t len, n, buf_out_len, in_this_style;
time_t now = Time;
@@ -1258,18 +1235,29 @@ no_overflow:
HUnlock(scrp_rec_h);
HUnlock(tab->messages_te);
- chatter_autoscroll(chatter, tab->messages_te, tab->messages_scroller);
-
- if (chatter->current_tab == tab)
+ if (chatter->current_tab == tab && chatter->win == FrontWindow())
+ chatter_autoscroll(chatter, tab->messages_te,
+ tab->messages_scroller);
+ else
+ tab->need_downscroll = true;
+
+ if (chatter->current_tab == tab) {
tab->have_activity = false;
- else {
+ } else {
/* resume normal drawing */
SetClip(savergn);
DisposeRgn(savergn);
if (!had_activity) {
tab->have_activity = true;
- chatter_draw_tab_bar(chatter);
+ if (chatter->win == FrontWindow()) {
+ chatter_draw_tab_bar(chatter);
+ } else {
+ GetPort(&old_port);
+ SetPort(chatter->win);
+ InvalRect(&chatter->win->portRect);
+ SetPort(old_port);
+ }
}
}
@@ -1462,24 +1450,29 @@ chatter_remove_from_nick_list(struct chatter *chatter,
LDelRow(1, pos, tab->nick_list);
}
-static BitMap shadow_cur_bits;
-
void
chatter_use_shadow(struct chatter *chatter)
{
+ if (++chatter->shadow_refcnt != 1)
+ return;
+
shadow_cur_bits = thePort->portBits;
SetRect(&chatter->shadow.bounds, 0, 0,
chatter->win->portRect.right - chatter->win->portRect.left,
chatter->win->portRect.bottom - chatter->win->portRect.top);
SetPortBits(&chatter->shadow);
+ CopyBits(&chatter->win->portBits, &chatter->shadow,
+ &chatter->shadow.bounds, &chatter->shadow.bounds, srcCopy, nil);
}
void
chatter_reveal_shadow(struct chatter *chatter)
{
+ if (--chatter->shadow_refcnt != 0)
+ return;
+
SetPortBits(&shadow_cur_bits);
-
CopyBits(&chatter->shadow, &chatter->win->portBits,
&chatter->shadow.bounds, &chatter->shadow.bounds, srcCopy, nil);
ValidRect(&chatter->win->portRect);
--- chatter.h Fri Sep 13 17:30:22 2024
+++ chatter.h Mon Sep 16 09:16:13 2024
@@ -80,6 +80,7 @@ struct chatter_tab {
ListHandle nick_list;
Rect label_rect;
bool have_activity;
+ bool need_downscroll;
};
SLIST_HEAD(chatter_tabs_head, chatter_tab);
@@ -88,11 +89,11 @@ struct chatter {
WindowPtr win;
BitMap shadow;
Rect shadow_bounds;
+ short shadow_refcnt;
TEHandle input_te;
char input[IRC_MAX_MSG_SIZE];
bool quitting;
bool need_tab_bar_redraw;
- BitMap tab_bar;
short ntabs;
struct chatter_tabs_head tabs_list;
struct chatter_tab *current_tab;