Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Aminet/MintPRINT.readme
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Short: IPP/AirPrint driver and setup tool
Author: Darren Banfi (boingball)
Uploader: boingball@gmail.com
Type: driver/print
Version: 1.3.3
Version: 1.3.4
Requires: 68000+; AmigaOS 2.04+; TCP/IP stack providing bsdsocket.library
Architecture: m68k-amigaos >= 2.04

Expand Down Expand Up @@ -225,9 +225,12 @@ cross-project collaboration: sharing compatibility findings and pointers to rele
allowing MintPRINT's implementation to be compared against AmiAirPrint, and
helping identify gaps in classic application and printer compatibility.

What's new in 1.3.3
What's new in 1.3.4
-------------------

- MintPrint Settings can always be closed: if the saved printer is
switched off, the startup status refresh no longer ignores the close
gadget, and it gives up sooner.
- Final driver revision 41.19.
- Test Print uses the selected Unit1-Unit7 profile for that one job without
replacing the active printer.
Expand Down
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,27 @@ Keep the full version-by-version history here. The front page and Aminet
readme should carry only a short summary of the latest version, with a link
to this page; replace that summary when preparing the next release.

[1.3.3](#133) | [1.3.2](#132) | [1.3.1](#131) | [1.3.0](#130) | [1.2.7](#127) | [1.2.6](#126) | [1.2.5](#125) | [1.2.4](#124) | [1.2.3](#123) | [1.2.2](#122) | [1.2.1](#121) | [1.2.0](#120) | [1.1.0](#110) | [1.0.3b](#103b) | [1.0.3](#103) | [1.0.2](#102) | [1.0.0](#100)
[1.3.4](#134) | [1.3.3](#133) | [1.3.2](#132) | [1.3.1](#131) | [1.3.0](#130) | [1.2.7](#127) | [1.2.6](#126) | [1.2.5](#125) | [1.2.4](#124) | [1.2.3](#123) | [1.2.2](#122) | [1.2.1](#121) | [1.2.0](#120) | [1.1.0](#110) | [1.0.3b](#103b) | [1.0.3](#103) | [1.0.2](#102) | [1.0.0](#100)

## 1.3.4

MintPRINT 1.3.4 fixes MintPrint Settings becoming impossible to close while
the saved printer is switched off.

- **The window can always be closed during a Query.** On opening, MintPrint
Settings refreshes the saved printer's status before it starts handling
window events, and the network code discarded every pending window message
while it waited. With the printer off, close-gadget clicks were lost until
every retry had timed out. A close click now cancels the Query and quits;
Ctrl-C cancels the Query and leaves the window open.
- **A saved port 631 is no longer retried twice.** A successful Query saves
the endpoint as `ip:631`, which the retry logic expanded to 631 and then
631 again. A switched-off printer now gives up after two attempts (about
16 seconds) instead of four.
- **Cached capabilities survive a failed Query.** A Query empties the
capability lists before connecting; when the printer does not answer, the
lists are now reloaded from that endpoint's cache so they match the
dropdowns still on screen. Ink levels are not cached and stay cleared.

## 1.3.3

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ MintPrint Settings for setup, discovery and test printing.
<img width="525" height="327" alt="image" src="https://github.com/user-attachments/assets/ba4cfd1f-8b0f-4aee-91b9-a6b221712ca5" />


## What's new in 1.3.3
## What's new in 1.3.4

- **MintPrint Settings can always be closed:** if the saved printer is switched
off, the startup status refresh no longer ignores the close gadget, and it
gives up sooner.
- **Final driver revision 41.19.**
- **Selected-unit Test Print:** testing Unit1-Unit7 uses that profile for the
one job without replacing the active printer.
Expand Down
129 changes: 90 additions & 39 deletions src/MintPrintSettings.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ static BOOL mp_copy_file(CONST_STRPTR src, CONST_STRPTR dst);

// Define the USED macro for GCC
#define USED __attribute__((used))
#define MINTPRINT_SETTINGS_VERSION "1.3.3"
#define MINTPRINT_SETTINGS_VERSION "1.3.4"
#define MINTPRINT_DRIVER_DEST ((CONST_STRPTR)"DEVS:Printers/MintPRINT")

/* MintPrint Settings now ships as a single drawer containing both bundled
Expand All @@ -229,7 +229,7 @@ static BOOL mp_read_driver_version(CONST_STRPTR path, struct MPDriverVersion *ou

/* Visible both to AmigaOS's Version command and in the About requester. */
static const char USED mintprint_version[] =
"$VER: MintPrintSettings " MINTPRINT_SETTINGS_VERSION " (04.09.2026)";
"$VER: MintPrintSettings " MINTPRINT_SETTINGS_VERSION " (23.10.2026)";

// Simple extension check
BOOL has_extension(const char *filename, const char *ext) {
Expand Down Expand Up @@ -7488,6 +7488,36 @@ static void mp_spool_win_process(void)
mp_spool_win_close();
}

/* Set while a Query is in flight when the user asks to stop it: the main
* window's close gadget (which also sets mp_quit_requested, so
* process_window_events() exits as soon as the Query unwinds) or Ctrl-C.
* perform_query_flow() clears mp_query_cancelled at its start and end. */
static BOOL mp_query_cancelled = FALSE;
static BOOL mp_quit_requested = FALSE;

/* Keeps the main window responsive during blocking network work. Every
* pending IntuiMessage is still replied to, as the plain drain loops this
* replaces did, but a close-gadget click is no longer silently thrown
* away: a real-hardware report had the startup printer-status refresh
* (which runs before process_window_events() starts) swallow every close
* click while it retried a switched-off printer, leaving no way to quit.
* Returns TRUE once the current Query should stop. */
static BOOL mp_pump_gui_during_query(void) {
if (window) {
struct IntuiMessage *imsg;
while ((imsg = GT_GetIMsg(window->UserPort))) {
if (imsg->Class == IDCMP_CLOSEWINDOW) {
mp_quit_requested = TRUE;
mp_query_cancelled = TRUE;
}
GT_ReplyIMsg(imsg);
}
}
if (CheckSignal(SIGBREAKF_CTRL_C))
mp_query_cancelled = TRUE;
return (BOOL)(mp_query_cancelled || mp_quit_requested);
}

/* Bounded, GUI-responsive connect(): socket -> IoctlSocket(FIONBIO on) ->
* connect() -> if EINPROGRESS, WaitSelect() on the write+exception sets in
* short chunks (pumping GUI events between them) until connected, refused,
Expand All @@ -7507,7 +7537,8 @@ static void mp_spool_win_process(void)
* mode being unavailable on this NDK/stack.
*
* Returns 0 on success, -1 on failure (errno set: from SO_ERROR when the
* stack reported one, or ETIMEDOUT for this function's own timeout). The
* stack reported one, ETIMEDOUT for this function's own timeout, or EINTR
* when mp_pump_gui_during_query() reports a user cancel). The
* socket is always left blocking again before returning, whatever the
* outcome, so callers don't need to know this happened. */
static int mp_connect_with_timeout(int sockfd, struct sockaddr_in *addr, int timeout_secs) {
Expand Down Expand Up @@ -7551,11 +7582,11 @@ static int mp_connect_with_timeout(int sockfd, struct sockaddr_in *addr, int tim
struct timeval tv;
long ready;

if (window) {
struct IntuiMessage *imsg;
while ((imsg = GT_GetIMsg(window->UserPort))) {
GT_ReplyIMsg(imsg);
}
if (mp_pump_gui_during_query()) {
printf("connect: cancelled by user\n");
errno = EINTR;
outcome = -1;
break;
}

FD_ZERO(&wfds);
Expand Down Expand Up @@ -8452,17 +8483,14 @@ int query_printer_attributes(const char *ip, int port, char *response, int maxle
* genuinely transient truncated response) so perform_query_flow()
* can tell "this endpoint doesn't answer at all" apart from "that
* attempt was flaky" and skip straight to the next port instead
* of repeating a now-deterministically-bounded connect failure. */
return -2;
* of repeating a now-deterministically-bounded connect failure.
* -3 = the user cancelled (close gadget or Ctrl-C), so no more
* attempts at all. */
return mp_query_cancelled ? -3 : -2;
}

// Process GUI events
if (window) {
struct IntuiMessage *imsg;
while ((imsg = GT_GetIMsg(window->UserPort))) {
GT_ReplyIMsg(imsg);
}
}
mp_pump_gui_during_query();

// Send request
printf("Sending request...\n");
Expand All @@ -8482,12 +8510,7 @@ int query_printer_attributes(const char *ip, int port, char *response, int maxle
free(ipp_payload);

// Process GUI events
if (window) {
struct IntuiMessage *imsg;
while ((imsg = GT_GetIMsg(window->UserPort))) {
GT_ReplyIMsg(imsg);
}
}
mp_pump_gui_during_query();

// Receive response in bounded, GUI-responsive chunks. HTTP permits three
// body framing modes here: Content-Length, Transfer-Encoding: chunked, or
Expand Down Expand Up @@ -8611,11 +8634,14 @@ int query_printer_attributes(const char *ip, int port, char *response, int maxle

query_receive_pump_gui:
// Process GUI events to keep the mouse responsive
if (window) {
struct IntuiMessage *imsg;
while ((imsg = GT_GetIMsg(window->UserPort))) {
GT_ReplyIMsg(imsg);
}
if (mp_pump_gui_during_query()) {
printf("Query cancelled while waiting for response\n");
snprintf(response, maxlen, "Query cancelled");
CloseSocket(sockfd);
free(name);
free(value);
operation_in_progress = FALSE;
return -3;
}
}

Expand Down Expand Up @@ -9038,12 +9064,9 @@ int query_printer_attributes(const char *ip, int port, char *response, int maxle
}

attributes_processed++;
if (window) {
struct IntuiMessage *imsg;
while ((imsg = GT_GetIMsg(window->UserPort))) {
GT_ReplyIMsg(imsg);
}
}
/* Parsing is local and short - note a close click here so
* it isn't lost, but let the parse finish. */
mp_pump_gui_during_query();
}

if (pos == group_start_pos) {
Expand Down Expand Up @@ -9188,9 +9211,17 @@ static void perform_query_flow(struct Window *win, const char *ip_only, int port
* always calls with port_hint 0, and manual entry without a ":port"
* does too), try 631 first so we don't latch onto an 80 response that
* "succeeds" but is missing capabilities like scaling. An explicit
* user-typed port is still tried first, ahead of the 631 fallback. */
* user-typed port is still tried first, ahead of the 631 fallback.
* A successful Query saves the endpoint as "ip:port", so a saved 631
* comes back here as port_hint 631 - that used to become {631, 631},
* retrying the same dead port twice over before giving up on a
* switched-off printer. A hint of 631 is now tried on its own. */
int ports_to_try[2];
if (port_hint > 0) {
int num_ports = 2;
if (port_hint == 631) {
ports_to_try[0] = 631;
num_ports = 1;
} else if (port_hint > 0) {
ports_to_try[0] = port_hint;
ports_to_try[1] = 631;
} else {
Expand All @@ -9200,12 +9231,14 @@ static void perform_query_flow(struct Window *win, const char *ip_only, int port
int i, attempt;
BOOL ok = FALSE;

mp_query_cancelled = FALSE;

// A scan can fail an individual attempt for purely transient network
// reasons (a slow/incomplete response - see query_printer_attributes).
// Retry a few times per port before moving on, rather than treating one
// flaky attempt as "the printer has no capabilities".
for (i = 0; i < 2 && !ok; i++) {
for (attempt = 0; attempt < 3 && !ok; attempt++) {
for (i = 0; i < num_ports && !ok && !mp_query_cancelled; i++) {
for (attempt = 0; attempt < 3 && !ok && !mp_query_cancelled; attempt++) {
int qrc;
printf("Trying %s:%d (attempt %d/3)...\n", ip_only, ports_to_try[i], attempt + 1);
qrc = query_printer_attributes(ip_only, ports_to_try[i], response,
Expand Down Expand Up @@ -9233,6 +9266,8 @@ static void perform_query_flow(struct Window *win, const char *ip_only, int port
apply_job_defaults_to_gadgets(win);
mp_check_any_engine_supported(win);
ok = TRUE;
} else if (qrc == -3) {
break;
} else {
printf("Query attempt %d/3 on %s:%d failed\n", attempt + 1, ip_only, ports_to_try[i]);
/* -2 = connect() itself couldn't be established (see
Expand Down Expand Up @@ -9262,7 +9297,17 @@ static void perform_query_flow(struct Window *win, const char *ip_only, int port

if (!ok) {
custom_printf("CLEAR");
custom_printf("Scan failed - please try Query again");
if (mp_query_cancelled)
custom_printf("Query cancelled");
else
custom_printf("Scan failed - please try Query again");
/* query_printer_attributes() emptied the capability lists before
* it tried to connect. When this endpoint has a cache (the usual
* case: a saved printer that is simply switched off) put those
* lists back, so they match the dropdowns still on screen. Ink
* levels are not cached, so they stay cleared. */
if (load_capability_cache_for_current_endpoint())
printf("Keeping cached printer capabilities\n");
mp_clear_printer_icon();
mp_load_printer_icon_cache(FALSE);
} else {
Expand All @@ -9275,6 +9320,7 @@ static void perform_query_flow(struct Window *win, const char *ip_only, int port
mp_draw_marker_strips();
mp_draw_sides_hint();
mp_draw_printer_icon();
mp_query_cancelled = FALSE;
}

/* Allocate the Query response only while a Query is running. Classic
Expand Down Expand Up @@ -10307,7 +10353,9 @@ void process_window_events(struct Window *win) {
ULONG imsgClass;
UWORD imsgCode;
struct Gadget *gad;
BOOL terminated = FALSE;
/* A close click during the startup printer-status refresh (which runs
* before this loop) has already been seen by mp_pump_gui_during_query(). */
BOOL terminated = mp_quit_requested;
char ip_only[64];
int port = -1;

Expand Down Expand Up @@ -10781,6 +10829,9 @@ void process_window_events(struct Window *win) {

}

/* Closed while a Query started from this message was running. */
if (mp_quit_requested)
terminated = TRUE;
imsg = GT_GetIMsg(win->UserPort);
}
}
Expand Down
Loading