AmendHub

Download:

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(&notification, 0, sizeof(notification)); + notification.qType = nmType; + notification.nmMark = 1; + notification.nmSound = (Handle)-1; + notification.nmIcon = GetResource('SICN', 128); + //notification.nmResp = (NMProcPtr *)&notification_response; + NMInstall(&notification); +} + +void +cancel_notification(void) +{ + NMRemove(&notification); } --- 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