The opening window size, one rule for both hosts (window-22, 7 October 2026, the project lead on PC 2: "why did the app open super wide?"): scaling-21's 80 percent of the work area scaled above 1920 wide opened 2752 by 1152 on a 3440-wide area and 3072 by 864 on a two-monitor span, and a remembered WindowW/WindowH could carry that into later starts; now app/windows/opening_size.h: the PRIMARY monitor's work area (MonitorFromPoint primary, never the virtual desktop), width 80 percent capped at 1440 up to a 1920-wide display and 1920 beyond, height from the width at 16:10 bounded by the work area, never wider than 1.6 times the height, never under 900 by 600, never over the work area; a remembered frame kept only when it fits the work area, the minimum and the aspect cap, and never saved when it would not; the Mac window mirrors the rule on NSScreen.screens.first and discards an autosave frame that fails it; opening_size_test.c compiles on the gate with cc (known-failed first: it could not compile before the header, and 0.3.21's rule fails the 3440 by 1440 and the 3840 by 1080 cases); host.cpp touched (the shipper's named line)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
382b441a64
commit
0974737822
5 changed files with 77 additions and 15 deletions
|
|
@ -109,12 +109,18 @@ final class App: NSObject, NSApplicationDelegate, WKNavigationDelegate, WKUIDele
|
|||
}
|
||||
|
||||
func buildWindow() {
|
||||
// scaling-21 (7 October 2026): the window opens at about 80 percent of the screen's work area, capped at 1440 by 900
|
||||
// on a display up to 1920 wide and scaled up with the display beyond that; once the user resizes, the frame is
|
||||
// remembered per machine (the frame autosave name) and the computed size is only the first-run default
|
||||
let work = NSScreen.main?.visibleFrame ?? NSRect(x: 0, y: 0, width: 1440, height: 900)
|
||||
let scale = max(1.0, work.width / 1920.0)
|
||||
let opening = NSSize(width: max(900, min(work.width * 0.8, 1440 * scale)), height: max(600, min(work.height * 0.8, 900 * scale)))
|
||||
// window-22 (7 October 2026, the one rule with app/windows/opening_size.h): the PRIMARY screen's work area, 80 percent
|
||||
// wide capped at 1440 up to a 1920-wide display and 1920 beyond, height from the width at 16:10 bounded by the work
|
||||
// area less 40, never wider than 1.6 times the height, never under 900 by 600, never over the work area
|
||||
let work = (NSScreen.screens.first ?? NSScreen.main)?.visibleFrame ?? NSRect(x: 0, y: 0, width: 1440, height: 900)
|
||||
func openingSize(_ workW: CGFloat, _ workH: CGFloat) -> NSSize {
|
||||
let minW = min(workW, 900), minH = min(workH, 600), capW: CGFloat = workW <= 1920 ? 1440 : 1920
|
||||
var w = min(floor(workW * 0.8), capW); var h = min(floor(w / 1.6), workH - 40)
|
||||
w = max(w, minW); h = max(h, minH); w = min(w, floor(h * 1.6)); w = min(w, workW); h = min(h, workH)
|
||||
return NSSize(width: w, height: h)
|
||||
}
|
||||
func fits(_ f: NSRect) -> Bool { f.width >= 900 && f.height >= 600 && f.width <= work.width && f.height <= work.height && f.width <= f.height * 1.632 }
|
||||
let opening = openingSize(work.width, work.height)
|
||||
let size = snapshotPath == nil ? opening : snapshotSize
|
||||
window = NSWindow(contentRect: NSRect(origin: .zero, size: size), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false)
|
||||
window.title = "Igneum Miner"
|
||||
|
|
@ -124,7 +130,8 @@ final class App: NSObject, NSApplicationDelegate, WKNavigationDelegate, WKUIDele
|
|||
window.backgroundColor = obsidian
|
||||
window.minSize = NSSize(width: 900, height: 600)
|
||||
if snapshotPath == nil {
|
||||
if !window.setFrameUsingName("IgneumMinerMain") { window.center() }
|
||||
// the remembered frame is kept only when it fits the primary work area and the aspect cap, else discarded
|
||||
if !window.setFrameUsingName("IgneumMinerMain") || !fits(window.frame) { window.setContentSize(opening); window.center() }
|
||||
window.setFrameAutosaveName("IgneumMinerMain")
|
||||
} else { window.center() }
|
||||
window.delegate = self
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#define _UNICODE
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include "opening_size.h"
|
||||
#include <shellapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <dbt.h>
|
||||
|
|
@ -351,28 +352,25 @@ static void saveWindowSize(HWND hwnd) {
|
|||
if (IsIconic(hwnd) || IsZoomed(hwnd)) return;
|
||||
RECT r; if (!GetWindowRect(hwnd, &r)) return;
|
||||
DWORD w = (DWORD)(r.right - r.left), h = (DWORD)(r.bottom - r.top);
|
||||
if (w < 900 || h < 600) return;
|
||||
if (w < 900 || h < 600 || w > (DWORD)(h * 1.6)) return;
|
||||
HKEY k; if (RegCreateKeyExW(HKEY_CURRENT_USER, kSizeKey, 0, nullptr, 0, KEY_SET_VALUE, nullptr, &k, nullptr) != ERROR_SUCCESS) return;
|
||||
RegSetValueExW(k, L"WindowW", 0, REG_DWORD, (const BYTE*)&w, sizeof(w));
|
||||
RegSetValueExW(k, L"WindowH", 0, REG_DWORD, (const BYTE*)&h, sizeof(h));
|
||||
RegCloseKey(k);
|
||||
}
|
||||
static void openingSize(int& w, int& h, int& sx, int& sy) {
|
||||
// the PRIMARY monitor's work area, never the virtual desktop (window-22: a two-monitor span opened the app super wide)
|
||||
RECT work = { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) };
|
||||
SystemParametersInfoW(SPI_GETWORKAREA, 0, &work, 0);
|
||||
POINT origin = { 0, 0 }; HMONITOR mon = MonitorFromPoint(origin, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFO mi = { sizeof(mi) }; if (mon && GetMonitorInfoW(mon, &mi)) work = mi.rcWork; else SystemParametersInfoW(SPI_GETWORKAREA, 0, &work, 0);
|
||||
int ww = work.right - work.left, wh = work.bottom - work.top;
|
||||
double scale = ww > 1920 ? ww / 1920.0 : 1.0;
|
||||
double cw = 1440.0 * scale, ch = 900.0 * scale, aw = ww * 0.8, ah = wh * 0.8;
|
||||
w = (int)(aw < cw ? aw : cw); h = (int)(ah < ch ? ah : ch);
|
||||
if (w < 900) w = ww < 900 ? ww : 900;
|
||||
if (h < 600) h = wh < 600 ? wh : 600;
|
||||
HKEY k; DWORD sw = 0, sh = 0, n = sizeof(DWORD);
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, kSizeKey, 0, KEY_QUERY_VALUE, &k) == ERROR_SUCCESS) {
|
||||
RegQueryValueExW(k, L"WindowW", nullptr, nullptr, (LPBYTE)&sw, &n); n = sizeof(DWORD);
|
||||
RegQueryValueExW(k, L"WindowH", nullptr, nullptr, (LPBYTE)&sh, &n);
|
||||
RegCloseKey(k);
|
||||
if (sw >= 900 && sh >= 600 && (int)sw <= ww && (int)sh <= wh) { w = (int)sw; h = (int)sh; }
|
||||
}
|
||||
igneum_opening_size(ww, wh, (int)sw, (int)sh, &w, &h);
|
||||
sx = work.left + (ww - w) / 2; sy = work.top + (wh - h) / 2;
|
||||
}
|
||||
|
||||
|
|
|
|||
26
app/windows/opening_size.h
Normal file
26
app/windows/opening_size.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* The opening window size, one rule for both hosts (window-22, 7 October 2026, the project lead on PC 2: "why did the app open super
|
||||
wide?"). Inputs: the PRIMARY monitor's work area (never the virtual desktop spanning two monitors) and the remembered
|
||||
frame (0 when none). Width first: 80 percent of the work area, at most 1440 on a display up to 1920 wide and at most 1920
|
||||
beyond, whatever the display; height from the width at 16:10, bounded by the work area less 40 px; then the window is
|
||||
never wider than 1.6 times its height, never under 900 by 600 unless the work area itself is smaller, never over the work
|
||||
area. A remembered frame is kept only when it fits the work area, the minimum and the aspect cap, else discarded (a
|
||||
super-wide frame from an earlier host must not come back). Pure C99, no Windows headers: host.cpp includes it,
|
||||
opening_size_test.c compiles it on the gate, IgneumMiner.swift mirrors it line for line. */
|
||||
#ifndef IGNEUM_OPENING_SIZE_H
|
||||
#define IGNEUM_OPENING_SIZE_H
|
||||
static void igneum_opening_size(int workW, int workH, int savedW, int savedH, int* outW, int* outH) {
|
||||
int minW = workW < 900 ? workW : 900, minH = workH < 600 ? workH : 600;
|
||||
int capW = workW <= 1920 ? 1440 : 1920;
|
||||
int w = (int)(workW * 0.8); if (w > capW) w = capW;
|
||||
int h = (int)(w / 1.6); if (h > workH - 40) h = workH - 40;
|
||||
if (w < minW) w = minW;
|
||||
if (h < minH) h = minH;
|
||||
if (w > (int)(h * 1.6)) w = (int)(h * 1.6);
|
||||
if (w > workW) w = workW;
|
||||
if (h > workH) h = workH;
|
||||
/* a remembered frame: the user's own size, kept when it fits; the aspect cap carries a 2 percent tolerance so a hand-sized
|
||||
1329 by 825 (PC 2, 7 October 2026, aspect 1.611) is not thrown away for a few pixels */
|
||||
if (savedW >= 900 && savedH >= 600 && savedW <= workW && savedH <= workH && savedW <= (int)(savedH * 1.632)) { w = savedW; h = savedH; }
|
||||
*outW = w; *outH = h;
|
||||
}
|
||||
#endif
|
||||
30
app/windows/opening_size_test.c
Normal file
30
app/windows/opening_size_test.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* The opening window size (window-22, 7 October 2026, the project lead on PC 2: "why did the app open super wide?"): the rule in
|
||||
opening_size.h, shared by the Windows host (host.cpp) and mirrored in the Mac window (IgneumMiner.swift). Known-failed
|
||||
first: on 0.3.21's rule a 3440 by 1440 work area opened 2752 by 1152 and a 3840 by 1080 span opened 3072 by 864
|
||||
(the test could not compile before the header existed).
|
||||
cc -std=c99 -Wall -Wextra -o t app/windows/opening_size_test.c && ./t */
|
||||
#include <stdio.h>
|
||||
#include "opening_size.h"
|
||||
static int fails = 0;
|
||||
static void check(const char* name, int ww, int wh, int sw, int sh, int ew, int eh) {
|
||||
int w = 0, h = 0; igneum_opening_size(ww, wh, sw, sh, &w, &h);
|
||||
if (w != ew || h != eh) { printf("FAIL %s: work %dx%d saved %dx%d -> %dx%d, wanted %dx%d\n", name, ww, wh, sw, sh, w, h, ew, eh); fails++; }
|
||||
else printf("ok %s: %dx%d\n", name, w, h);
|
||||
}
|
||||
int main(void) {
|
||||
check("1080p desk: 1440 by 900", 1920, 1040, 0, 0, 1440, 900);
|
||||
check("1440p monitor: width capped at 1920, 16:10", 2560, 1400, 0, 0, 1920, 1200);
|
||||
check("4K: width capped at 1920 regardless of display", 3840, 2120, 0, 0, 1920, 1200);
|
||||
check("ultrawide 3440 by 1440: never wider than 1.6 times the height", 3440, 1400, 0, 0, 1920, 1200);
|
||||
check("two monitors spanned 3840 by 1080, if ever read as one area: the aspect cap holds", 3840, 1040, 0, 0, 1600, 1000);
|
||||
check("a remembered frame that fits is kept", 1920, 1040, 1400, 900, 1400, 900);
|
||||
check("PC 2, 7 October 2026: a 5120 by 2160 panel at 200 percent reads as 2560 by 1032; 0.3.21 opened 1920 by 826", 2560, 1032, 0, 0, 1587, 992);
|
||||
check("PC 2: the hand-sized 1329 by 825 (aspect 1.611) is kept under the 2 percent tolerance", 2560, 1032, 1329, 825, 1329, 825);
|
||||
check("a remembered frame at aspect 1.7 is discarded", 2560, 1032, 1700, 1000, 1587, 992);
|
||||
check("a remembered super-wide frame from the take-4 host is discarded", 1920, 1040, 2752, 1152, 1440, 900);
|
||||
check("a remembered frame wider than 1.6 times its height is discarded", 1920, 1040, 1800, 700, 1440, 900);
|
||||
check("a remembered frame under the minimum is discarded", 1920, 1040, 800, 500, 1440, 900);
|
||||
check("a small laptop: 80 percent wide, 16:10", 1280, 760, 0, 0, 1024, 640);
|
||||
check("a tiny work area: the work area itself", 800, 560, 0, 0, 800, 560);
|
||||
printf(fails ? "%d FAILED\n" : "all ok\n", fails); return fails ? 1 : 0;
|
||||
}
|
||||
|
|
@ -107,6 +107,7 @@ tree_checks() {
|
|||
run "heat gate reader self-test (a known hold passes, a known drift fails)" node tools/heat-gate.mjs --self-test
|
||||
run "relay unit tests" node --test relay/test/parse.test.mjs relay/test/auth.test.mjs relay/test/wake.test.mjs relay/test/ember.test.mjs
|
||||
run "miner app notice strip and update card tests" node --test app/igneum-app/ui/notices.test.mjs app/igneum-app/ui/update-card.test.mjs app/igneum-app/ui/view.test.mjs app/igneum-app/ui/tune-line.test.mjs app/igneum-app/ui/ui-ota.test.mjs app/igneum-app/ui/fold.test.mjs
|
||||
run "the opening window size: the one rule for both hosts (primary work area, 1920 and 16:10 caps, a remembered frame kept only when it fits)" bash -c 'cc -std=c99 -Wall -Wextra -o "${TMPDIR:-/tmp}/opening_size_test.$$" app/windows/opening_size_test.c && "${TMPDIR:-/tmp}/opening_size_test.$$"; rc=$?; rm -f "${TMPDIR:-/tmp}/opening_size_test.$$"; exit $rc'
|
||||
run "the Intel rotate-fold rewrite: Intel gets the shift form, AMD and NVIDIA untouched (proto-opencl/test_intel_rotr.c)" bash -c 'cc -std=c99 -Wall -Wextra -o "${TMPDIR:-/tmp}/test_intel_rotr.$$" proto-opencl/test_intel_rotr.c && "${TMPDIR:-/tmp}/test_intel_rotr.$$"; s=$?; rm -f "${TMPDIR:-/tmp}/test_intel_rotr.$$"; exit $s'
|
||||
run "no secret file names and no 64-hex secrets in the tree" bash -c 'bash tools/ci/no-secrets-check.sh --self-test && bash tools/ci/no-secrets-check.sh'
|
||||
run "miner app notice strip and update card tests" node --test app/igneum-app/ui/notices.test.mjs app/igneum-app/ui/update-card.test.mjs app/igneum-app/ui/view.test.mjs app/igneum-app/ui/tune-line.test.mjs
|
||||
|
|
|
|||
Loading…
Reference in a new issue