jcs
/wallops
/amendments
/6
chatter: More performant text display, hide on close
Properly handle multiple focusables and restack as needed
jcs made amendment 6 over 2 years ago
--- chatter.c Wed Feb 2 17:38:22 2022
+++ chatter.c Fri Feb 4 21:19:53 2022
@@ -26,16 +26,17 @@
void chatter_layout(struct chatter *chatter, bool init, Rect *init_bounds);
void chatter_key_down(struct focusable *focusable, EventRecord *event);
void chatter_mouse_down(struct focusable *focusable, EventRecord *event);
-void chatter_menu(struct focusable *focusable, short menu, short item);
+bool chatter_menu(struct focusable *focusable, short menu, short item);
void chatter_idle(struct focusable *focusable, EventRecord *event);
void chatter_update(struct focusable *focusable, EventRecord *event);
+void chatter_resume(struct focusable *focusable, EventRecord *event);
void chatter_close(struct focusable *focusable, EventRecord *event);
void chatter_atexit(struct focusable *focusable);
void
chatter_init(const char *server, const unsigned short port,
const char *nick, const char *ident, const char *realname,
- bool show_motd)
+ const char *channel)
{
struct focusable *focusable;
struct chatter *chatter;
@@ -53,7 +54,7 @@ chatter_init(const char *server, const unsigned short
chatter->irc_nick = xstrdup(nick);
chatter->irc_ident = xstrdup(ident);
chatter->irc_realname = xstrdup(realname);
- chatter->irc_show_motd = show_motd;
+ chatter->irc_channel_autojoin = xstrdup(channel);
bounds.left = padding;
bounds.top = screenBits.bounds.top + padding +
@@ -86,7 +87,8 @@ chatter_init(const char *server, const unsigned short
focusable->close = chatter_close;
focusable->atexit = chatter_atexit;
focusable->menu = chatter_menu;
- show_focusable(focusable);
+ focusable->resume = chatter_resume;
+ add_focusable(focusable);
}
void
@@ -112,6 +114,7 @@ chatter_layout(struct chatter *chatter, bool init, Rec
inset_bounds = bounds;
InsetRect(&inset_bounds, 3, 1);
chatter->input_te = TENew(&inset_bounds, &bounds);
+ TEActivate(chatter->input_te);
} else {
(*(chatter->input_te))->viewRect = bounds;
InsetRect(&bounds, 3, 1);
@@ -157,6 +160,8 @@ chatter_layout(struct chatter *chatter, bool init, Rec
inset_bounds = bounds;
InsetRect(&inset_bounds, 4, 4);
chatter->messages_te = TEStylNew(&inset_bounds, &bounds);
+ (*(chatter->messages_te))->caretHook = NullCaretHook;
+ TEActivate(chatter->messages_te);
} else {
(*(chatter->messages_te))->viewRect = bounds;
InsetRect(&bounds, 4, 4);
@@ -168,12 +173,21 @@ chatter_layout(struct chatter *chatter, bool init, Rec
}
void
+chatter_resume(struct focusable *focusable, EventRecord *event)
+{
+ struct chatter *chatter = (struct chatter *)(focusable->cookie);
+
+ show_focusable(focusable);
+}
+
+void
chatter_close(struct focusable *focusable, EventRecord *event)
{
struct chatter *chatter = (struct chatter *)(focusable->cookie);
- irc_close(chatter);
- close_focusable(focusable);
+ //irc_close(chatter);
+ //close_focusable(focusable);
+ hide_focusable(focusable);
}
void
@@ -215,7 +229,6 @@ chatter_idle(struct focusable *focusable, EventRecord
{
struct chatter *chatter = (struct chatter *)(focusable->cookie);
- TEIdle(chatter->messages_te);
TEIdle(chatter->input_te);
irc_process(chatter);
}
@@ -260,9 +273,11 @@ chatter_update(struct focusable *focusable, EventRecor
case activateEvt:
if (event->modifiers & activeFlag) {
LActivate(true, chatter->nick_list);
+ //TEActivate(chatter->messages_te);
TEActivate(chatter->input_te);
} else {
LActivate(false, chatter->nick_list);
+ TEDeactivate(chatter->messages_te);
TEDeactivate(chatter->input_te);
}
break;
@@ -304,6 +319,11 @@ chatter_mouse_down(struct focusable *focusable, EventR
if (PtInRect(p, &r)) {
TEClick(p, ((event->modifiers & shiftKey) != 0),
chatter->messages_te);
+ HLock(chatter->messages_te);
+ if ((*(chatter->messages_te))->selStart !=
+ (*(chatter->messages_te))->selEnd)
+ TESetSelect(0, 0, chatter->input_te);
+ HUnlock(chatter->messages_te);
return;
}
@@ -311,6 +331,11 @@ chatter_mouse_down(struct focusable *focusable, EventR
if (PtInRect(p, &r)) {
TEClick(p, ((event->modifiers & shiftKey) != 0),
chatter->input_te);
+ HLock(chatter->input_te);
+ if ((*(chatter->input_te))->selStart !=
+ (*(chatter->input_te))->selEnd)
+ TESetSelect(0, 0, chatter->messages_te);
+ HUnlock(chatter->input_te);
return;
}
@@ -340,7 +365,7 @@ chatter_mouse_down(struct focusable *focusable, EventR
}
}
-void
+bool
chatter_menu(struct focusable *focusable, short menu, short item)
{
struct chatter *chatter = (struct chatter *)(focusable->cookie);
@@ -349,16 +374,27 @@ chatter_menu(struct focusable *focusable, short menu,
case EDIT_MENU_ID:
switch (item) {
case EDIT_MENU_CUT_ID:
- TECut(chatter->messages_te);
- break;
+ TECut(chatter->input_te);
+ return true;
case EDIT_MENU_COPY_ID:
- TECopy(chatter->messages_te);
- break;
+ HLock(chatter->input_te);
+ HLock(chatter->messages_te);
+ if ((*(chatter->input_te))->selStart !=
+ (*(chatter->input_te))->selEnd)
+ TECopy(chatter->input_te);
+ else if ((*(chatter->messages_te))->selStart !=
+ (*(chatter->messages_te))->selEnd)
+ TECopy(chatter->messages_te);
+ HUnlock(chatter->messages_te);
+ HUnlock(chatter->input_te);
+ return true;
case EDIT_MENU_PASTE_ID:
- TEPaste(chatter->messages_te);
- break;
+ TEPaste(chatter->input_te);
+ return true;
}
}
+
+ return false;
}
#if 0
@@ -410,15 +446,18 @@ chatter_key_down(struct focusable *focusable, EventRec
TEKey(k, chatter->input_te);
}
+static Handle scrp_rec_h = NULL;
+#define CHATTER_SCRAP_ELEMENTS 20
+
size_t
chatter_printf(struct chatter *chatter, const char *format, ...)
{
static char buf[600], buf_out[600];
- TextStyle style;
+ StScrpRec *scrp_rec;
+ ScrpSTElement *scrp_ele, *prev_scrp_ele;
va_list argptr;
- size_t len, n, buf_out_len;
+ size_t len, n, buf_out_len, in_this_style;
time_t now = Time;
- short mask;
bool stop_formatting = false;
len = 0;
@@ -435,70 +474,90 @@ chatter_printf(struct chatter *chatter, const char *fo
len += vsnprintf(buf + len, sizeof(buf) - len, format, argptr);
va_end(argptr);
- TESetSelect(1024 * 32, 1024 * 32, chatter->messages_te);
-
- style.tsFont = CHATTER_FONT;
- style.tsFace = 0;
- style.tsSize = CHATTER_FONT_SIZE;
- mask = doFace | doSize | doFont;
-
- for (n = 0, buf_out_len = 0; n < len; n++) {
+ if (scrp_rec_h == NULL) {
+ scrp_rec_h = xNewHandle(4 + (20 * CHATTER_SCRAP_ELEMENTS));
+ HLock(scrp_rec_h);
+ memset(*scrp_rec_h, 0, (4 + (20 * CHATTER_SCRAP_ELEMENTS)));
+ } else
+ HLock(scrp_rec_h);
+
+ scrp_rec = (StScrpRec *)(*scrp_rec_h);
+ scrp_rec->scrpNStyles = 1;
+ scrp_ele = &scrp_rec->scrpStyleTab[scrp_rec->scrpNStyles - 1];
+ scrp_ele->scrpStartChar = 0;
+ scrp_ele->scrpHeight = CHATTER_FONT_SIZE + 3;
+ scrp_ele->scrpAscent = CHATTER_FONT_SIZE;
+ scrp_ele->scrpFont = CHATTER_FONT;
+ scrp_ele->scrpSize = CHATTER_FONT_SIZE;
+ scrp_ele->scrpFace = 0;
+
+ for (n = 0, buf_out_len = 0, in_this_style = 0; n < len; n++) {
if (!stop_formatting && buf[n] == '$') {
- if (buf_out_len) {
- buf_out[buf_out_len] = '\0';
- TESetStyle(mask, &style, false, chatter->messages_te);
- TEStylInsert(buf_out, buf_out_len, 0,
- chatter->messages_te);
- buf_out[0] = '\0';
- buf_out_len = 0;
+ if (in_this_style > 0) {
+ scrp_rec->scrpNStyles++;
+ if (scrp_rec->scrpNStyles >= CHATTER_SCRAP_ELEMENTS)
+ panic("chatter_printf: too many elements");
+ prev_scrp_ele = scrp_ele;
+ scrp_ele = &scrp_rec->scrpStyleTab[
+ scrp_rec->scrpNStyles - 1];
+ /* carry style forward */
+ memcpy(scrp_ele, prev_scrp_ele, sizeof(ScrpSTElement));
}
+ scrp_ele->scrpStartChar = buf_out_len;
switch (buf[n + 1]) {
case 'B':
- style.tsFace = bold | condense;
+ scrp_ele->scrpFace |= bold | condense;
break;
case 'U':
- style.tsFace = underline;
+ scrp_ele->scrpFace |= underline;
break;
case 's':
- style.tsSize--;
+ scrp_ele->scrpSize--;
break;
case 'S':
- style.tsSize++;
+ scrp_ele->scrpSize++;
break;
case '/':
stop_formatting = true;
/* FALLTHROUGH */
case '0':
- style.tsFace = 0;
- style.tsSize = CHATTER_FONT_SIZE;
+ scrp_ele->scrpHeight = CHATTER_FONT_SIZE + 3;
+ scrp_ele->scrpAscent = CHATTER_FONT_SIZE;
+ scrp_ele->scrpFont = CHATTER_FONT;
+ scrp_ele->scrpSize = CHATTER_FONT_SIZE;
+ scrp_ele->scrpFace = 0;
break;
}
n++;
continue;
}
buf_out[buf_out_len++] = buf[n];
+ in_this_style++;
}
- if (buf_out_len) {
- TESetStyle(mask, &style, false, chatter->messages_te);
- TEStylInsert(buf_out, buf_out_len, 0, chatter->messages_te);
+ if (!buf_out_len) {
+ HUnlock(scrp_rec_h);
+ return 0;
}
+ TESetSelect(1024 * 32, 1024 * 32, chatter->messages_te);
+ TEStylInsert(buf_out, buf_out_len, scrp_rec_h, chatter->messages_te);
+ HUnlock(scrp_rec_h);
TEPinScroll(0, -INT_MAX, chatter->messages_te);
SetCtlValue(chatter->messages_scroller,
GetCtlMax(chatter->messages_scroller));
UpdateScrollbarForTE(chatter->messages_scroller,
chatter->messages_te, false);
- return len;
+ return buf_out_len;
}
void
chatter_sync_nick_list(struct chatter *chatter)
{
Cell cell = { 0, 0 };
- size_t n, i, j;
+ size_t n, i, j, ops, voices;
char nick[32];
short ret;
struct irc_channel_nick tnick;
@@ -530,23 +589,33 @@ chatter_sync_nick_list(struct chatter *chatter)
}
cell.v = 0;
+ ops = voices = 0;
for (n = 0; n < chatter->irc_channel->nusers; n++) {
- if (chatter->irc_channel->users[n].flags == IRC_NICK_FLAG_OP)
+ if (chatter->irc_channel->users[n].flags & IRC_NICK_FLAG_OP) {
j = snprintf(nick, sizeof(nick), "@%s",
chatter->irc_channel->users[n].nick);
- else if (chatter->irc_channel->users[n].flags ==
- IRC_NICK_FLAG_VOICE)
+ ops++;
+ } else if (chatter->irc_channel->users[n].flags &
+ IRC_NICK_FLAG_VOICE) {
j = snprintf(nick, sizeof(nick), "+%s",
chatter->irc_channel->users[n].nick);
- else
+ voices++;
+ } else
j = snprintf(nick, sizeof(nick), "%s",
chatter->irc_channel->users[n].nick);
LAddRow(1, cell.v, chatter->nick_list);
LSetCell(&nick, j, cell, chatter->nick_list);
cell.v++;
}
+
+ chatter_printf(chatter, "$B%s$0: Total of $B%ld$0 nick%s $B("
+ "%ld$0 op%s, $B%ld$0 voice%s$B)$0", chatter->irc_channel->name,
+ chatter->irc_channel->nusers,
+ chatter->irc_channel->nusers == 1 ? "" : "s",
+ ops, ops == 1 ? "" : "s",
+ voices, voices == 1 ? "" : "s");
}
LDoDraw(true, chatter->nick_list);
InvalRect(&(*(chatter->nick_list))->rView);
-}
+}
--- chatter.h Wed Feb 2 17:23:54 2022
+++ chatter.h Fri Feb 4 21:06:25 2022
@@ -25,7 +25,7 @@
#define PROGRAM_NAME "wallops"
-#define CHATTER_FONT applFont
+#define CHATTER_FONT geneva
#define CHATTER_FONT_SIZE 10
#define MBAR_ID 128
@@ -48,35 +48,37 @@
#define CONNECT_NICK_ID 4
#define CONNECT_IDENT_ID 5
#define CONNECT_REALNAME_ID 6
-#define CONNECT_SHOW_MOTD_ID 7
+#define CONNECT_CHANNEL_ID 7
#define STR_SERVER_ID 1000
#define STR_PORT_ID 1001
#define STR_NICK_ID 1002
#define STR_IDENT_ID 1003
#define STR_REALNAME_ID 1004
-#define STR_SHOW_MOTD_ID 1005
+#define STR_CHANNEL_ID 1005
#define DEFAULT_SERVER_NAME "irc.libera.chat"
#define DEFAULT_PORT "6667"
#define DEFAULT_IDENT "wallops"
-#define DEFAULT_REALNAME "A Mac User"
+#define DEFAULT_REALNAME "A Macintosh User"
+#define DEFAULT_CHANNEL "#cyberpals"
struct focusable {
WindowPtr win;
+ bool visible;
void *cookie;
void (*idle)(struct focusable *focusable, EventRecord *event);
void (*update)(struct focusable *focusable, EventRecord *event);
void (*key_down)(struct focusable *focusable, EventRecord *event);
void (*mouse_down)(struct focusable *focusable, EventRecord *event);
- void (*menu)(struct focusable *focusable, short menu, short item);
+ bool (*menu)(struct focusable *focusable, short menu, short item);
void (*close)(struct focusable *focusable, EventRecord *event);
void (*suspend)(struct focusable *focusable, EventRecord *event);
void (*resume)(struct focusable *focusable, EventRecord *event);
void (*atexit)(struct focusable *focusable);
};
-extern struct focusable *cur_focusable;
-extern struct focusable *last_focusable;
+extern struct focusable **focusables;
+extern short nfocusables;
struct chatter {
WindowPtr win;
@@ -91,7 +93,7 @@ struct chatter {
char *irc_nick;
char *irc_ident;
char *irc_realname;
- bool irc_show_motd;
+ char *irc_channel_autojoin;
struct irc_channel *irc_channel;
TCPiopb irc_rcv_pb, irc_send_pb, irc_close_pb;
TCPStatusPB irc_status_pb;
@@ -107,11 +109,17 @@ struct chatter {
unsigned char irc_tcp_buf[(4 * 1500) + 1024];
};
+void notify(void);
+void cancel_notification(void);
+
+void add_focusable(struct focusable *focusable);
void show_focusable(struct focusable *focusable);
void close_focusable(struct focusable *focusable);
+void hide_focusable(struct focusable *focusable);
void chatter_init(const char *server, const unsigned short port,
- const char *nick, const char *ident, const char *realname, bool show_motd);
+ const char *nick, const char *ident, const char *realname,
+ const char *channel);
void chatter_update_titlebar(struct chatter *chatter);
size_t chatter_printf(struct chatter *chatter, const char *format, ...);
void chatter_sync_nick_list(struct chatter *chatter);
--- irc.c Wed Feb 2 16:32:44 2022
+++ irc.c Fri Feb 4 12:58:13 2022
@@ -46,9 +46,9 @@ irc_process(struct chatter *chatter)
switch (chatter->irc_state) {
case IRC_STATE_UNINITED:
- chatter_printf(chatter, "$B*** Welcome to %s$/", PROGRAM_NAME);
+ chatter_printf(chatter, "$B***$0 Welcome to %s", PROGRAM_NAME);
chatter->irc_state = IRC_STATE_CONNECTING;
- //irc_init(chatter);
+ irc_init(chatter);
break;
case IRC_STATE_CONNECTED:
irc_login(chatter);
@@ -126,6 +126,8 @@ irc_init(struct chatter *chatter)
void
irc_abort(struct chatter *chatter)
{
+ _TCPClose(&chatter->irc_close_pb, chatter->irc_stream, nil, nil,
+ false);
_TCPAbort(&chatter->irc_close_pb, chatter->irc_stream, nil, nil,
false);
_TCPRelease(&chatter->irc_close_pb, chatter->irc_stream, nil, nil,
@@ -276,6 +278,12 @@ irc_login(struct chatter *chatter)
"USER %s 8 * :%s\r\n", chatter->irc_ident, chatter->irc_realname);
irc_send(chatter, chatter->irc_line, len);
+ if (chatter->irc_channel_autojoin) {
+ len = snprintf(chatter->irc_line, sizeof(chatter->irc_line),
+ "JOIN %s\r\n", chatter->irc_channel_autojoin);
+ irc_send(chatter, chatter->irc_line, len);
+ }
+
chatter->irc_state = IRC_STATE_IDLE;
}
@@ -486,13 +494,6 @@ done_parsing:
case 266:
/* server stats, unhelpful */
return;
- case 372:
- case 375:
- case 376:
- /* MOTD */
- if (!chatter->irc_show_motd)
- return;
- goto print_msg;
case 311:
case 312:
case 317:
@@ -500,6 +501,9 @@ done_parsing:
case 338:
/* WHOIS stuff */
goto print_msg;
+ case 328:
+ /* channel URL, we probably can't do anything with it anyway */
+ return;
case 332:
/* TOPIC */
chatter_printf(chatter, "$B***$0 Topic for $B%s$0:$/ %s",
@@ -529,6 +533,11 @@ done_parsing:
if (chatter->irc_channel)
chatter_sync_nick_list(chatter);
return;
+ case 372:
+ case 375:
+ case 376:
+ /* MOTD */
+ goto print_msg;
default:
goto unknown;
}
@@ -566,22 +575,32 @@ irc_process_input(struct chatter *chatter, char *str)
if (strcmp(arg0, "msg") == 0) {
arg1 = strsep(&str, " ");
- chatter_printf(chatter, "$B[$0msg$B($0%s$B)]$0$/ %s", arg1,
- str);
+ if (arg1 == NULL || str == NULL)
+ goto not_enough_params;
+ chatter_printf(chatter, "$B[$0msg$B($0%s$B)]$0$/ %s", arg1, str);
irc_printf(chatter, "PRIVMSG %s :%s\r\n", arg1, str);
} else if (strcmp(arg0, "join") == 0) {
+ if (str == NULL)
+ goto not_enough_params;
irc_printf(chatter, "JOIN %s\r\n", str);
} else if (strcmp(arg0, "part") == 0) {
- if (str[0] == '\0' && chatter->irc_channel)
+ if (str == NULL && chatter->irc_channel)
irc_printf(chatter, "PART %s\r\n", chatter->irc_channel->name);
else
irc_printf(chatter, "PART %s\r\n", str);
} else if (strcmp(arg0, "quit") == 0) {
- irc_printf(chatter, "QUIT :%s\r\n", str[0] == '\0' ? "&" : str);
+ irc_printf(chatter, "QUIT :%s\r\n", str == NULL ? "&" : str);
} else if (strcmp(arg0, "quote") == 0) {
+ if (str == NULL)
+ goto not_enough_params;
irc_printf(chatter, "%s\r\n", str);
} else
chatter_printf(chatter, "unrecognized command \"$B%s$0\"", arg0);
+
+ return;
+
+not_enough_params:
+ chatter_printf(chatter, "$B***$0 Not enough parameters given");
}
void
--- main.c Wed Feb 2 16:28:11 2022
+++ main.c Fri Feb 4 21:31:47 2022
@@ -21,10 +21,9 @@
#include "util.h"
MenuHandle apple_menu, file_menu;
-struct focusable *cur_focusable = NULL;
-struct focusable *last_focusable = NULL;
-ip_addr socks_proxy_ip = 0;
-ip_port socks_proxy_port = 0;
+struct focusable **focusables = NULL;
+short nfocusables = 0;
+NMRec notification = { 0 };
enum {
CONFIG_TYPE_STRING,
@@ -50,13 +49,13 @@ struct config_field {
CONNECT_IDENT_ID, STR_IDENT_ID, DEFAULT_IDENT },
{ "Realname", CONFIG_TYPE_STRING, 1, 0,
CONNECT_REALNAME_ID, STR_REALNAME_ID, DEFAULT_REALNAME },
- { "Show MOTD", CONFIG_TYPE_SHORT, 0, 1,
- CONNECT_SHOW_MOTD_ID, 0, "" },
+ { "Channel", CONFIG_TYPE_STRING, 0, 0,
+ CONNECT_CHANNEL_ID, STR_CHANNEL_ID, DEFAULT_CHANNEL },
};
void update_menu(void);
void handle_exit(void);
-short handle_menu(long menu_id);
+bool handle_menu(long menu_id);
short show_connect_dialog(void);
int
@@ -67,8 +66,9 @@ main(void)
WindowPtr event_win;
GrafPtr old_port;
AppFile finder_file;
+ struct focusable *found_focusable;
short event_in, n;
- char key, *socks_proxy_host;
+ char key;
SetApplLimit(GetApplLimit() - (1024 * 8));
@@ -94,31 +94,40 @@ main(void)
panic("no file menu");
update_menu();
DrawMenuBar();
-
+
show_connect_dialog();
for (;;) {
SystemTask();
GetNextEvent(everyEvent, &event);
+ if (event.what != nullEvent) {
+ event_in = FindWindow(event.where, &event_win);
+ found_focusable = NULL;
+ for (n = 0; n < nfocusables; n++) {
+ if (focusables[n]->win == event_win)
+ found_focusable = focusables[n];
+ }
+ }
+
switch (event.what) {
case nullEvent:
- /* TODO: idle all chatters, not just current */
- if (cur_focusable && cur_focusable->idle)
- cur_focusable->idle(cur_focusable, &event);
+ for (n = 0; n < nfocusables; n++) {
+ if (focusables[n]->idle)
+ focusables[n]->idle(focusables[n], &event);
+ }
break;
case keyDown:
case autoKey:
key = event.message & charCodeMask;
if ((event.modifiers & cmdKey) != 0 &&
- handle_menu(MenuKey(key)) == 1)
+ handle_menu(MenuKey(key)) == true)
break;
- if (cur_focusable && cur_focusable->key_down)
- cur_focusable->key_down(cur_focusable, &event);
+ if (nfocusables && focusables[0]->visible &&
+ focusables[0]->key_down)
+ focusables[0]->key_down(focusables[0], &event);
break;
- case mouseDown:
- event_in = FindWindow(event.where, &event_win);
-
+ case mouseDown:
switch (event_in) {
case inMenuBar:
handle_menu(MenuSelect(event.where));
@@ -130,24 +139,17 @@ main(void)
DragWindow(event_win, event.where, &screenBits.bounds);
break;
case inGoAway:
- if (TrackGoAway(event_win, event.where) && cur_focusable &&
- cur_focusable->close)
- cur_focusable->close(cur_focusable, &event);
+ if (TrackGoAway(event_win, event.where) &&
+ found_focusable && found_focusable->close)
+ found_focusable->close(found_focusable, &event);
break;
case inContent:
if (event_win != FrontWindow()) {
- SelectWindow(event_win);
- if (last_focusable &&
- last_focusable->win == event_win) {
- struct focusable *fcur;
- fcur = cur_focusable;
- cur_focusable = last_focusable;
- last_focusable = fcur;
- }
+ if (found_focusable)
+ show_focusable(found_focusable);
}
- if (cur_focusable && cur_focusable->win == event_win &&
- cur_focusable->mouse_down)
- cur_focusable->mouse_down(cur_focusable, &event);
+ if (found_focusable && found_focusable->mouse_down)
+ found_focusable->mouse_down(found_focusable, &event);
break;
}
break;
@@ -161,8 +163,8 @@ main(void)
BeginUpdate(event_win);
}
- if (cur_focusable && cur_focusable->update)
- cur_focusable->update(cur_focusable, &event);
+ if (found_focusable && found_focusable->update)
+ found_focusable->update(found_focusable, &event);
if (event.what == updateEvt) {
EndUpdate(event_win);
@@ -175,13 +177,17 @@ main(void)
switch (event.message & (1 << 0)) {
case 0:
/* suspend */
- if (cur_focusable && cur_focusable->suspend)
- cur_focusable->suspend(cur_focusable, &event);
+ for (n = 0; n < nfocusables; n++) {
+ if (focusables[n]->suspend)
+ focusables[n]->suspend(focusables[n], &event);
+ }
break;
case 1:
/* resume */
- if (cur_focusable && cur_focusable->resume)
- cur_focusable->resume(cur_focusable, &event);
+ for (n = 0; n < nfocusables; n++) {
+ if (focusables[n]->resume)
+ focusables[n]->resume(focusables[n], &event);
+ }
break;
}
}
@@ -195,7 +201,7 @@ main(void)
short
show_connect_dialog(void)
{
- Str255 txt, server, ports, nick, ident, realname;
+ Str255 txt, server, ports, nick, ident, realname, channel;
StringHandle h;
DialogPtr dlg;
Handle ihandle;
@@ -203,7 +209,6 @@ show_connect_dialog(void)
size_t size, n;
long port;
short hit, itype, ret;
- bool show_motd = false;
if ((dlg = GetNewDialog(CONNECT_DLOG_ID, nil, (WindowPtr)-1)) == NULL)
panic("Can't find connection DLOG %d", CONNECT_DLOG_ID);
@@ -290,8 +295,8 @@ verify:
case CONNECT_REALNAME_ID:
strlcpy((char *)&realname, (char *)txt, sizeof(realname));
break;
- case CONNECT_SHOW_MOTD_ID:
- show_motd = (atoi((char *)txt) == 1);
+ case CONNECT_CHANNEL_ID:
+ strlcpy((char *)&channel, (char *)txt, sizeof(channel));
break;
}
@@ -312,13 +317,13 @@ verify:
DisposeDialog(dlg);
chatter_init((char *)&server, port, (char *)&nick, (char *)&ident,
- (char *)&realname, show_motd);
+ (char *)&realname, (char *)&channel);
}
-short
+bool
handle_menu(long menu_id)
{
- short ret = 0;
+ bool ret = false;
switch (HiWord(menu_id)) {
case APPLE_MENU_ID:
@@ -345,7 +350,7 @@ handle_menu(long menu_id)
} else
warn("Can't find version number!");
- ret = 1;
+ ret = true;
break;
}
}
@@ -354,14 +359,16 @@ handle_menu(long menu_id)
switch (LoWord(menu_id)) {
case FILE_MENU_CONNECT_ID:
show_connect_dialog();
+ ret = true;
break;
case FILE_MENU_QUIT_ID:
- exit(0);
+ ret = true;
+ ExitToShell();
}
break;
default:
- if (cur_focusable && cur_focusable->menu)
- cur_focusable->menu(cur_focusable, HiWord(menu_id),
+ if (nfocusables && focusables[0]->visible && focusables[0]->menu)
+ ret = focusables[0]->menu(focusables[0], HiWord(menu_id),
LoWord(menu_id));
}
@@ -377,30 +384,108 @@ update_menu(void)
void
handle_exit(void)
{
- /* TODO: close all chatters, not just current */
- if (cur_focusable)
- cur_focusable->atexit(cur_focusable);
+ short n;
+
+ for (n = 0; n < nfocusables; n++) {
+ if (focusables[n]->atexit)
+ focusables[n]->atexit(focusables[n]);
+ }
}
void
+add_focusable(struct focusable *focusable)
+{
+ nfocusables++;
+ focusables = xreallocarray(focusables, sizeof(Ptr), nfocusables);
+
+ if (nfocusables > 1)
+ memmove(focusables + sizeof(Ptr), focusables,
+ sizeof(Ptr) * (nfocusables - 1));
+
+ focusables[0] = focusable;
+
+ show_focusable(focusable);
+}
+
+void
show_focusable(struct focusable *focusable)
{
- if (cur_focusable)
- last_focusable = cur_focusable;
- cur_focusable = focusable;
+ struct focusable *last, *tmp;
+ short n;
+ if (nfocusables > 1 || focusables[0] != focusable) {
+ last = focusables[0];
+ focusables[0] = focusable;
+ for (n = 1; n < nfocusables; n++) {
+ tmp = focusables[n];
+ focusables[n] = last;
+ last = tmp;
+ if (last == focusable)
+ break;
+ }
+ }
+
+ focusable->visible = true;
ShowWindow(focusable->win);
+ SelectWindow(focusable->win);
}
void
close_focusable(struct focusable *focusable)
{
- if (cur_focusable == focusable) {
- cur_focusable = NULL;
- if (last_focusable)
- cur_focusable = last_focusable;
- } else if (last_focusable == focusable)
- last_focusable = NULL;
+ short n;
- CloseWindow(focusable->win);
+ if (focusable->visible)
+ CloseWindow(focusable->win);
+
+ for (n = 0; n < nfocusables; n++) {
+ if (focusables[n] == focusable) {
+ for (; n < nfocusables - 1; n++)
+ focusables[n] = focusables[n + 1];
+ break;
+ }
+ }
+
+ nfocusables--;
+ focusables = xreallocarray(focusables, sizeof(Ptr), nfocusables);
+
+ if (nfocusables && focusables[0]->visible)
+ SelectWindow(focusables[0]->win);
+}
+
+void
+hide_focusable(struct focusable *focusable)
+{
+ short n;
+
+ HideWindow(focusable->win);
+ focusable->visible = false;
+
+ for (n = 0; n < nfocusables; n++) {
+ if (focusables[n] == focusable) {
+ for (; n < nfocusables - 1; n++)
+ focusables[n] = focusables[n + 1];
+ break;
+ }
+ }
+ focusables[nfocusables - 1] = focusable;
+}
+
+void
+notify(void)
+{
+ cancel_notification();
+ memset(¬ification, 0, sizeof(notification));
+ notification.qType = nmType;
+ notification.nmMark = 1;
+ notification.nmSound = (Handle)-1;
+ notification.nmIcon = GetResource('SICN', 128);
+ //notification.nmResp = (NMProcPtr *)¬ification_response;
+ NMInstall(¬ification);
+}
+
+void
+cancel_notification(void)
+{
+ NMRemove(¬ification);
}
--- util.c Wed Feb 2 09:29:51 2022
+++ util.c Thu Feb 3 16:34:58 2022
@@ -1157,4 +1157,14 @@ ModalDialogFilter(DialogPtr dlg, EventRecord *event, s
}
return false;
-}
+}
+
+/* (*(some_te))->caretHook = NullCaretHook; */
+pascal void
+NullCaretHook(void)
+{
+ asm {
+ move.l (a7)+,d0
+ rts
+ }
+}
--- util.h Wed Feb 2 09:19:50 2022
+++ util.h Thu Feb 3 16:26:22 2022
@@ -122,5 +122,6 @@ void SetTrackControlTE(TEHandle te);
pascal void TrackMouseDownInControl(ControlHandle control, short part);
pascal bool ModalDialogFilter(DialogPtr dlg, EventRecord *event,
short *hit);
+pascal void NullCaretHook(void);
#endif