AmendHub

Download

jcs

/

wifi_da

/

window.c

 

(View History)

jcs   window: Do updates on an off-screen bitmap to avoid flashing Latest amendment: 20 on 2023-10-24

1 /*
2 * Copyright (c) 2023 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include "wi-fi.h"
20
21 #define NO_DEVICE_TEXT "\pNo Device Found"
22 #define NO_NETWORK_TEXT "(No Network)"
23
24 #define DA_HEIGHT 25
25 #define DA_WIDTH 180
26
27 SICNHandle signal_icons;
28 ControlHandle ssid_list;
29 MenuHandle ssid_menu;
30 Rect ssid_menu_rect;
31 BitMap win_shadow;
32 short nwifi_scan_networks = 0;
33 struct wifi_network_entry wifi_menu_networks[nitems(wifi_scan_networks)] = { 0 };
34 short nwifi_menu_networks = 0;
35
36 WindowPtr
37 create_window(short ctlrefnum)
38 {
39 GrafPtr savePort, tport;
40 Rect bounds;
41
42 GetPort(&savePort);
43
44 /* screenBits is not available from a DA */
45 tport = (GrafPtr)NewPtr(sizeof(GrafPort));
46 OpenPort(tport);
47 /* upper right corner, but leave space for desktop icon */
48 bounds.top = 45;
49 bounds.bottom = bounds.top + DA_HEIGHT;
50 bounds.left = tport->portRect.right - DA_WIDTH - 70;
51 bounds.right = bounds.left + DA_WIDTH;
52 ClosePort(tport);
53
54 win = NewWindow(0L, &bounds, "\pWi-Fi", true, rDocProc, 0L, true, 0L);
55 ((WindowPeek)win)->windowKind = ctlrefnum;
56
57 win_shadow.rowBytes = (((DA_WIDTH - 1) / 16) + 1) * 2;
58 win_shadow.baseAddr = xmalloczero(win_shadow.rowBytes * DA_HEIGHT);
59 SetRect(&win_shadow.bounds, 0, 0, DA_WIDTH, DA_HEIGHT);
60
61 signal_icons = (SICNHandle)GetResource('SICN', OwnedResourceID(0));
62 if (signal_icons == NULL)
63 warn("Can't find SICN");
64
65 ssid_menu = NewMenu(OwnedResourceID(10), "\p");
66 InsMenuItem(ssid_menu, "\pFinding Wi-Fi...", 1);
67
68 SetRect(&ssid_menu_rect, 30, 3, 170, 21); /* ltrb */
69
70 #if 0 /* system 6 does not seem to support popupMenuProc */
71 ssid_list = NewControl(win, &ssid_menu_rect, 0, true, 0,
72 OwnedResourceID(SSID_MENU_ID), 0, popupMenuProc + popupFixedWidth, 0L);
73 #endif
74
75 update_window(true);
76
77 if (wifi_scsi_id == WIFI_SCSI_ID_FINDING)
78 wifi_scsi_id = scsi_find_wifi();
79
80 if (wifi_scsi_id == WIFI_SCSI_ID_NONE) {
81 da_state = STATE_IDLE;
82 SetItem(ssid_menu, 1, NO_DEVICE_TEXT);
83 update_window(true);
84 } else {
85 scsi_wifi_info(wifi_scsi_id, &wifi_cur_info);
86 da_state = STATE_SCANNING;
87 scsi_wifi_scan(wifi_scsi_id);
88 }
89
90 SetPort(savePort);
91
92 return win;
93 }
94
95 void
96 update_window(bool force)
97 {
98 Str255 menuText;
99 GrafPtr savePort;
100 Point p;
101 short i, icon;
102 RgnHandle tmpRgn;
103 Rect r, destRect;
104 BitMap bm, cur_bits;
105
106 GetPort(&savePort);
107 SetPort(win);
108
109 DEBUG_LOG(("redrawing window"));
110 cur_bits = win->portBits;
111 SetPortBits(&win_shadow);
112
113 if (!force)
114 BeginUpdate(win);
115
116 EraseRect(&win->portRect);
117 DrawControls(win);
118
119 /* system 6 does not seem to support popupMenuProc, fake it */
120 FrameRect(&ssid_menu_rect);
121 MoveTo(ssid_menu_rect.left + 1, ssid_menu_rect.bottom);
122 LineTo(ssid_menu_rect.right, ssid_menu_rect.bottom);
123 MoveTo(ssid_menu_rect.right, ssid_menu_rect.top + 1);
124 LineTo(ssid_menu_rect.right, ssid_menu_rect.bottom);
125 MoveTo(ssid_menu_rect.left + 15, 16);
126 TextFont(systemFont);
127 TextSize(0);
128 GetItem(ssid_menu, 1, &menuText);
129 DrawString(menuText);
130
131 HLock(signal_icons);
132
133 SetRect(&destRect, 6, 4, 22, 20); /* ltrb */
134
135 if (wifi_scsi_id == WIFI_SCSI_ID_NONE)
136 icon = SIGNAL_NO_DEVICE;
137 else if (wifi_scsi_id == WIFI_SCSI_ID_FINDING)
138 icon = SIGNAL_FINDING_DEVICE;
139 else if (wifi_cur_info.ssid[0] == '\0')
140 icon = SIGNAL_NONE;
141 else if (wifi_cur_info.rssi >= -60)
142 icon = SIGNAL_4;
143 else if (wifi_cur_info.rssi >= -70)
144 icon = SIGNAL_3;
145 else if (wifi_cur_info.rssi >= -75)
146 icon = SIGNAL_2;
147 else
148 icon = SIGNAL_1;
149
150 bm.baseAddr = (Ptr)(*signal_icons)[icon];
151 bm.rowBytes = 2;
152 SetRect(&bm.bounds, 0, 0, 16, 16);
153 CopyBits(&bm, &win->portBits, &bm.bounds, &destRect, srcOr, NULL);
154
155 HUnlock(signal_icons);
156
157 if (!force)
158 EndUpdate(win);
159
160 SetPortBits(&cur_bits);
161
162 CopyBits(&win_shadow, &win->portBits, &win_shadow.bounds,
163 &win_shadow.bounds, srcCopy, nil);
164
165 ValidRect(&win->portRect);
166 SetPort(savePort);
167 }
168
169 void
170 update_wifi_cur_info(void)
171 {
172 struct wifi_network_entry old_info;
173
174 if (wifi_scsi_id == WIFI_SCSI_ID_NONE)
175 return;
176
177 memcpy(&old_info, &wifi_cur_info, sizeof(old_info));
178
179 scsi_wifi_info(wifi_scsi_id, &wifi_cur_info);
180
181 if (memcmp(&old_info, &wifi_cur_info, sizeof(old_info)) != 0) {
182 if (memcmp(&old_info.ssid, &wifi_cur_info.ssid,
183 sizeof(old_info.ssid)) == 0) {
184 /* just updating RSSI */
185 DEBUG_LOG(("update_wifi_cur_info: just updating rssi to %d",
186 wifi_cur_info.rssi));
187 update_window(true);
188 } else {
189 DEBUG_LOG(("update_wifi_cur_info: updating ssid list"));
190 update_wifi_ssid_list(false);
191 }
192 }
193 }
194
195 void
196 update_wifi_ssid_list(bool update_networks)
197 {
198 char ssid[64] = { 0 };
199 short n, m, mitem;
200
201 if (wifi_scsi_id == WIFI_SCSI_ID_NONE)
202 return;
203
204 if (update_networks) {
205 nwifi_scan_networks = scsi_wifi_scan_results(wifi_scsi_id,
206 wifi_scan_networks, nitems(wifi_scan_networks));
207 DEBUG_LOG(("scsi_wifi_scan_results: %d", nwifi_scan_networks));
208
209 if (nwifi_scan_networks == 0) {
210 memcpy(&wifi_scan_networks, &wifi_cur_info,
211 sizeof(wifi_cur_info));
212 nwifi_scan_networks = 1;
213 }
214 }
215
216 /* put the current network first, if any */
217 memcpy(&wifi_menu_networks[0], &wifi_cur_info,
218 sizeof(wifi_menu_networks[0]));
219
220 nwifi_menu_networks = nwifi_scan_networks;
221 if (nwifi_menu_networks > nitems(wifi_menu_networks)) {
222 nwifi_menu_networks = nitems(wifi_menu_networks);
223 DEBUG_LOG(("capping nets to %d", nwifi_menu_networks));
224 }
225
226 /* add each additional network from the scan, excluding current */
227 for (n = 0, m = 1; n < nwifi_menu_networks; n++) {
228 if (strcmp(wifi_scan_networks[n].ssid,
229 wifi_cur_info.ssid) == 0) {
230 DEBUG_LOG(("skipping %s, is current",
231 wifi_scan_networks[n].ssid));
232 continue;
233 }
234
235 DEBUG_LOG(("net %d: %s", m, wifi_scan_networks[n].ssid));
236
237 memcpy(&wifi_menu_networks[m++], &wifi_scan_networks[n],
238 sizeof(wifi_menu_networks[0]));
239 }
240
241 nwifi_menu_networks = m;
242
243 if (wifi_menu_networks[0].ssid[0] == '\0')
244 strlcpy(wifi_menu_networks[0].ssid, NO_NETWORK_TEXT,
245 sizeof(wifi_menu_networks[0].ssid));
246
247 /* leave the first item and we'll set its text later */
248 while (CountMItems(ssid_menu) > 1)
249 DelMenuItem(ssid_menu, 2);
250
251 for (n = 0, mitem = 1; n < nwifi_menu_networks; n++) {
252 /*
253 * InsMenuItem supports meta chars in item text which can
254 * have side effects, so insert a blank item and then set its
255 * name with SetItem which does not suport meta chars.
256 */
257 strlcpy(ssid, wifi_menu_networks[n].ssid, sizeof(ssid));
258 CtoPstr(ssid);
259
260 if (n > 0)
261 InsMenuItem(ssid_menu, "\p...", mitem);
262
263 SetItem(ssid_menu, mitem, ssid);
264
265 if (wifi_cur_info.ssid[0] == '\0' && n == 0)
266 CheckItem(ssid_menu, mitem, true);
267 else
268 CheckItem(ssid_menu, mitem,
269 (strcmp(wifi_menu_networks[n].ssid,
270 wifi_cur_info.ssid) == 0));
271
272 mitem++;
273 }
274
275 update_window(true);
276 }
277
278 void
279 activate_window(bool activate)
280 {
281 Rect r;
282 GrafPtr savePort;
283
284 #if 0
285 GetPort(&savePort);
286 SetPort(win);
287 r = win->portRect;
288 r.top = r.bottom - 16;
289 r.left = r.left - 16;
290 InvalRect(&r);
291 SetPort(savePort);
292 #endif
293 }
294
295 void
296 destroy_window(void)
297 {
298 ReleaseResource(signal_icons);
299
300 if (!win)
301 return;
302
303 DisposeWindow(win);
304 win = 0;
305 }
306
307 void
308 window_mousedown(Point p)
309 {
310 char pass_storage[256];
311 char ssid[64];
312 Rect r, irect;
313 GrafPtr savePort;
314 short mitems, n, selitem, hit, itype;
315 long new_net;
316 struct wifi_network_entry *net;
317 struct wifi_join_request wjr;
318 DialogPtr dg;
319 EventRecord e;
320 ControlHandle ihandle;
321
322 GetPort(&savePort);
323 SetPort(win);
324
325 r = ssid_menu_rect;
326 LocalToGlobal(&r);
327
328 /* XXX: why does PtInRect not work here? */
329 if (!(p.h >= r.left && p.h <= r.left + r.right &&
330 p.v >= r.top && p.v <= r.top + r.bottom)) {
331 SetPort(savePort);
332 return;
333 }
334
335 if (wifi_scsi_id == WIFI_SCSI_ID_NONE)
336 return;
337
338 InsertMenu(ssid_menu, -1);
339
340 mitems = CountMItems(ssid_menu);
341 selitem = 1;
342 for (n = 0; n < mitems; n++) {
343 if (strcmp(wifi_menu_networks[n].ssid, wifi_cur_info.ssid) == 0) {
344 selitem = n + 1;
345 break;
346 }
347 }
348
349 new_net = PopUpMenuSelect(ssid_menu, r.top + 1, r.left + 1, selitem);
350
351 DeleteMenu((*ssid_menu)->menuID);
352 if (hiword(new_net) == 0 || loword(new_net) == selitem)
353 goto menu_done;
354
355 net = &wifi_menu_networks[loword(new_net) - 1];
356
357 memset(&wjr, 0, sizeof(wjr));
358 strlcpy(wjr.ssid, net->ssid, sizeof(wjr.ssid));
359
360 if (net->flags & WIFI_NETWORK_FLAG_AUTH) {
361 strlcpy(ssid, net->ssid, sizeof(ssid));
362 CtoPstr(ssid);
363 ParamText(ssid, "\p", "\p", "\p");
364 PtoCstr(ssid);
365
366 dg = GetNewDialog(OwnedResourceID(PASSWORD_DIALOG_ID), 0L,
367 (WindowPtr)-1L);
368 center_in_screen(((DialogPeek)dg)->window.port.portRect.right,
369 ((DialogPeek)dg)->window.port.portRect.bottom, false, &r);
370 MoveWindow(dg, r.left, r.top, false);
371
372 memset(pass_storage, 0, sizeof(pass_storage));
373 PasswordDialogFieldFilterSetup(PASSWORD_DIALOG_PASSWORD_FIELD_ID,
374 pass_storage, sizeof(pass_storage));
375
376 ShowWindow(dg);
377 SetPort(dg);
378
379 /* outline ok button */
380 GetDItem(dg, ok, &itype, &ihandle, &irect);
381 PenSize(3, 3);
382 InsetRect(&irect, -4, -4);
383 FrameRoundRect(&irect, 16, 16);
384 PenNormal();
385
386 for (;;) {
387 ModalDialog(PasswordDialogFieldFilter, &hit);
388 if (hit == ok || hit == cancel)
389 break;
390 }
391
392 if (hit != ok) {
393 PasswordDialogFieldFinish();
394 DisposDialog(dg);
395 goto menu_done;
396 }
397
398 //DEBUG_LOG(("pass is \"%s\"", pass_storage));
399 strlcpy(wjr.key, pass_storage, sizeof(wjr.key));
400
401 PasswordDialogFieldFinish();
402 DisposDialog(dg);
403 }
404
405 scsi_wifi_join(wifi_scsi_id, &wjr);
406
407 /* force an update of the list */
408 scsi_wifi_info(wifi_scsi_id, &wifi_cur_info);
409 update_wifi_ssid_list(false);
410
411 menu_done:
412 SetPort(savePort);
413 }