1 | /*
|
---|
2 | * Copyright (C) 1997-2006 Andrei Los.
|
---|
3 | * This file is part of the lSwitcher source package.
|
---|
4 | * lSwitcher is free software; you can redistribute it and/or modify
|
---|
5 | * it under the terms of the GNU General Public License as published
|
---|
6 | * by the Free Software Foundation, in version 2 as it comes in the
|
---|
7 | * "COPYING" file of the lSwitcher main distribution.
|
---|
8 | * This program is distributed in the hope that it will be useful,
|
---|
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
11 | * GNU General Public License for more details.
|
---|
12 | */
|
---|
13 |
|
---|
14 | #include "lswitch.h"
|
---|
15 | #include "common.h"
|
---|
16 | #include "fspopup.h"
|
---|
17 |
|
---|
18 | #include <string.h>
|
---|
19 | #include <stdio.h>
|
---|
20 | #include <process.h>
|
---|
21 | #define __PMPRINTF__
|
---|
22 | #include "PMPRINTF.H"
|
---|
23 |
|
---|
24 | #ifndef XWORKPLACE
|
---|
25 | #define INCL_LOADEXCEPTQ
|
---|
26 | #include "exceptq.h"
|
---|
27 | #endif
|
---|
28 |
|
---|
29 | static HMONITOR hmonKbd = (HMONITOR) 0;
|
---|
30 | static MONIN monInBuf = { 0 };
|
---|
31 | static MONOUT monOutBuf = { 0 };
|
---|
32 |
|
---|
33 | VOID FSMonitor(VOID * plswData)
|
---|
34 | {
|
---|
35 | static USHORT usCount;
|
---|
36 | static KEYPACKET keybuf;
|
---|
37 | ULONG ulPostCount;
|
---|
38 |
|
---|
39 | #ifndef XWORKPLACE
|
---|
40 | EXCEPTIONREGISTRATIONRECORD exRegRec;
|
---|
41 |
|
---|
42 | LoadExceptq(&exRegRec, "", NULL);
|
---|
43 | #endif
|
---|
44 |
|
---|
45 | DosSetPrty(PRTYS_THREAD, PRTYC_TIMECRITICAL, +31, 0);
|
---|
46 |
|
---|
47 | while (DosWaitEventSem(((PLSWDATA) plswData)->hevRunning, 0) ==
|
---|
48 | ERROR_TIMEOUT) {
|
---|
49 | usCount = sizeof(keybuf);
|
---|
50 | if (DosMonRead
|
---|
51 | ((PBYTE) & monInBuf, DCWW_WAIT, (PBYTE) & keybuf, &usCount))
|
---|
52 | break;
|
---|
53 | DosMonWrite((PBYTE) & monOutBuf, (PBYTE) & keybuf, usCount);
|
---|
54 |
|
---|
55 | /* keybuf.mnflags>>8 is the scan code; check for the Tab key release*/
|
---|
56 | if ((keybuf.cp.fsState >> 8) ==
|
---|
57 | (((PLSWDATA) plswData)->Settings.ucPopupHotKey == 1 ? 1 : 2)
|
---|
58 | && (keybuf.mnflags >> 8) == (SCAN_TAB | 0x80)) {
|
---|
59 | if (keybuf.cp.fsState & 3)
|
---|
60 | DosPostEventSem(((PLSWDATA) plswData)->hevShift);
|
---|
61 | else
|
---|
62 | DosResetEventSem(((PLSWDATA) plswData)->hevShift,
|
---|
63 | &ulPostCount);
|
---|
64 | DosPostEventSem(((PLSWDATA) plswData)->hevPopup);
|
---|
65 | break;
|
---|
66 | }
|
---|
67 | }
|
---|
68 | #ifndef XWORKPLACE
|
---|
69 | UninstallExceptq(&exRegRec);
|
---|
70 | #endif
|
---|
71 | }
|
---|
72 |
|
---|
73 | VOID FSMonDispat(VOID * pParm)
|
---|
74 | {
|
---|
75 | PLSWDATA plswData;
|
---|
76 | SEL selGSeg, selLSeg;
|
---|
77 | PGINFOSEG GSeg;
|
---|
78 | UCHAR ucCurrId = 0, ucId;
|
---|
79 | ULONG ulPostCount;
|
---|
80 | APIRET rc;
|
---|
81 | #ifndef XWORKPLACE
|
---|
82 | EXCEPTIONREGISTRATIONRECORD exRegRec;
|
---|
83 |
|
---|
84 | LoadExceptq(&exRegRec, "", NULL);
|
---|
85 | #endif
|
---|
86 | DebugHereIAm();
|
---|
87 | plswData = (PLSWDATA) pParm;
|
---|
88 |
|
---|
89 | DosGetInfoSeg(&selGSeg, &selLSeg);
|
---|
90 | GSeg = (PGINFOSEG) ((selGSeg & ~7) << 13);
|
---|
91 |
|
---|
92 | if (DosCreateEventSem(SEMFSPOPUPNAME, &plswData->hevPopup, 0, 0)) {
|
---|
93 | #ifndef XWORKPLACE
|
---|
94 | UninstallExceptq(&exRegRec);
|
---|
95 | #endif
|
---|
96 | return;
|
---|
97 | }
|
---|
98 | if (DosCreateEventSem(SEMSHIFTNAME, &plswData->hevShift, 0, 0)) {
|
---|
99 | #ifndef XWORKPLACE
|
---|
100 | UninstallExceptq(&exRegRec);
|
---|
101 | #endif
|
---|
102 | return;
|
---|
103 | }
|
---|
104 | rc = DosRequestMutexSem(plswData->htmxFSMonDispatRunning, SEM_INDEFINITE_WAIT );
|
---|
105 | PmpfF(("Mon RequestMSem %i", rc));
|
---|
106 | while (DosWaitEventSem(plswData->hevRunning, 10L) == ERROR_TIMEOUT) {
|
---|
107 | /* if we popup in PM reset the semaphore and post a triggering message;
|
---|
108 | if we popup in FS create a thread which will monitor the keyboard and
|
---|
109 | display the popup menu, post the semaphore one more time so that we do
|
---|
110 | not accidentally create one more such thread because the first one didn't
|
---|
111 | have time to issue VioPopUp and thus change current FS session;
|
---|
112 | the semaphore will be reset when a keyboard monitor for this thread is
|
---|
113 | created */
|
---|
114 | if (DosWaitEventSem(plswData->hevPopup, 200L) == 0 &&
|
---|
115 | (DosQueryEventSem(plswData->hevPopup, &ulPostCount),
|
---|
116 | ulPostCount == 1)) {
|
---|
117 | if (plswData->Settings.bPMPopupInFS) {
|
---|
118 | DosQueryEventSem(plswData->hevShift, &ulPostCount);
|
---|
119 | WinPostMsg(plswData->hwndPopup, WM_COMMAND,
|
---|
120 | MPFROMSHORT(ulPostCount >
|
---|
121 | 0 ? CMD_SCROLLLEFTFROMFS :
|
---|
122 | CMD_SCROLLRIGHTFROMFS),
|
---|
123 | MPFROM2SHORT(CMDSRC_OTHER, FALSE));
|
---|
124 | DosResetEventSem(plswData->hevPopup, &ulPostCount);
|
---|
125 | }
|
---|
126 | else {
|
---|
127 | DosPostEventSem(plswData->hevPopup);
|
---|
128 | plswData->itidFSMon =
|
---|
129 | _beginthread(FSPopUp, NULL, 0x4000, plswData);
|
---|
130 | }
|
---|
131 | }
|
---|
132 |
|
---|
133 | if ((ucId = GSeg->sgCurrent) != ucCurrId) {
|
---|
134 | ucCurrId = ucId;
|
---|
135 | if (hmonKbd != 0) {
|
---|
136 | DosMonClose(hmonKbd);
|
---|
137 | hmonKbd = 0;
|
---|
138 | }
|
---|
139 |
|
---|
140 | if (DosMonOpen("KBD$", &hmonKbd) == 0) {
|
---|
141 | monInBuf.cb = sizeof(MONIN);
|
---|
142 | monOutBuf.cb = sizeof(MONOUT);
|
---|
143 | if (DosMonReg
|
---|
144 | (hmonKbd, (PBYTE) & monInBuf, (PBYTE) & monOutBuf, 1,
|
---|
145 | ucCurrId) == 0) {
|
---|
146 | if (DosQueryEventSem(plswData->hevPopup, &ulPostCount),
|
---|
147 | ulPostCount == 0)
|
---|
148 | plswData->itidFSMon =
|
---|
149 | _beginthread(FSMonitor, NULL, 0x4000, plswData);
|
---|
150 | }
|
---|
151 | else {
|
---|
152 | DosMonClose(hmonKbd);
|
---|
153 | hmonKbd = 0;
|
---|
154 | }
|
---|
155 | }
|
---|
156 | else
|
---|
157 | hmonKbd = 0;
|
---|
158 | DosResetEventSem(plswData->hevPopup, &ulPostCount);
|
---|
159 | }
|
---|
160 |
|
---|
161 | }
|
---|
162 | DosSleep(200);
|
---|
163 | if (hmonKbd != 0)
|
---|
164 | DosMonClose(hmonKbd);
|
---|
165 | DebugHereIAm();
|
---|
166 | DosReleaseMutexSem(plswData->htmxFSMonDispatRunning);
|
---|
167 | #ifndef XWORKPLACE
|
---|
168 | UninstallExceptq(&exRegRec);
|
---|
169 | #endif
|
---|
170 | }
|
---|
171 |
|
---|
172 | /* this function returns the number of the item with given line number
|
---|
173 | counting from top in the popup menu */
|
---|
174 | SHORT ItemNumFromLineNum(LSWDATA * plswData, USHORT usLineNum)
|
---|
175 | {
|
---|
176 | SHORT item;
|
---|
177 |
|
---|
178 | item = usLineNum + plswData->iShift +
|
---|
179 | (plswData->Settings.bScrollItems ? plswData->usCurrItem : 0) -
|
---|
180 | (min(MAXTEXTITEMS, plswData->usItems) - 1) / 2;
|
---|
181 |
|
---|
182 | AdjustItem(item, plswData->usItems);
|
---|
183 | return item;
|
---|
184 | }
|
---|
185 |
|
---|
186 | /* this thread monitors keyboard activity during the popup */
|
---|
187 | VOID FSPopUp(VOID * pParm)
|
---|
188 | {
|
---|
189 | static USHORT usCount;
|
---|
190 | static KEYPACKET keybuf;
|
---|
191 | UCHAR ucScan;
|
---|
192 | USHORT usCounter, usPopOpt;
|
---|
193 | ULONG ulPostCount;
|
---|
194 | BOOL bDoSwitch, bForward, bNowSticky;
|
---|
195 | PLSWDATA plswData;
|
---|
196 |
|
---|
197 | #ifndef XWORKPLACE
|
---|
198 | EXCEPTIONREGISTRATIONRECORD exRegRec;
|
---|
199 |
|
---|
200 | LoadExceptq(&exRegRec, "", NULL);
|
---|
201 | #endif
|
---|
202 | DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, +31, 0);
|
---|
203 |
|
---|
204 | plswData = (PLSWDATA) pParm;
|
---|
205 | InitTaskArr(plswData, TRUE, FALSE, TRUE);
|
---|
206 |
|
---|
207 | if (DosQueryEventSem(plswData->hevShift, &ulPostCount), ulPostCount > 0)
|
---|
208 | plswData->usCurrItem = plswData->usItems - 1;
|
---|
209 | else
|
---|
210 | plswData->usCurrItem = 1;
|
---|
211 |
|
---|
212 | usPopOpt = 1;
|
---|
213 | VioPopUp(&usPopOpt, 0);
|
---|
214 |
|
---|
215 | /* wait until monitor dispatcher registeres a monitor for the popup session and
|
---|
216 | resets the semaphore */
|
---|
217 | usCounter = 0;
|
---|
218 | while (DosQueryEventSem(plswData->hevPopup, &ulPostCount),
|
---|
219 | ulPostCount != 0) {
|
---|
220 | DosSleep(5);
|
---|
221 | usCounter++;
|
---|
222 | if (usCounter > 200) {
|
---|
223 | VioEndPopUp(0);
|
---|
224 | #ifndef XWORKPLACE
|
---|
225 | UninstallExceptq(&exRegRec);
|
---|
226 | #endif
|
---|
227 | return;
|
---|
228 | }
|
---|
229 | }
|
---|
230 |
|
---|
231 | FSPopupMenu(plswData, 0);
|
---|
232 |
|
---|
233 | bDoSwitch = FALSE;
|
---|
234 | bNowSticky = FALSE;
|
---|
235 |
|
---|
236 | for (;;) {
|
---|
237 | usCount = sizeof(keybuf);
|
---|
238 | if (DosMonRead
|
---|
239 | ((PBYTE) & monInBuf, DCWW_WAIT, (PBYTE) & keybuf, &usCount))
|
---|
240 | break;
|
---|
241 | DosMonWrite((PBYTE) & monOutBuf, (PBYTE) & keybuf, usCount);
|
---|
242 | // printf("%x %x %x\n",keybuf.cp.fbStatus,keybuf.cp.fsState,keybuf.mnflags>>8);
|
---|
243 |
|
---|
244 | ucScan = keybuf.mnflags >> 8;
|
---|
245 | if (ucScan == (SCAN_TAB | 0x80) || ucScan == SCAN_UP
|
---|
246 | || ucScan == SCAN_DOWN) {
|
---|
247 | bForward = ((ucScan == (SCAN_TAB | 0x80) && !(keybuf.cp.fsState & 3)) || /*check shift status */
|
---|
248 | ucScan == SCAN_DOWN);
|
---|
249 | if (bForward) {
|
---|
250 | if (plswData->usCurrItem < plswData->usItems - 1)
|
---|
251 | plswData->usCurrItem++;
|
---|
252 | else
|
---|
253 | plswData->usCurrItem = 0;
|
---|
254 | }
|
---|
255 | else {
|
---|
256 | if (plswData->usCurrItem > 0)
|
---|
257 | plswData->usCurrItem--;
|
---|
258 | else
|
---|
259 | plswData->usCurrItem = plswData->usItems - 1;
|
---|
260 | }
|
---|
261 |
|
---|
262 | if (!plswData->Settings.bScrollItems
|
---|
263 | && plswData->usItems > MAXTEXTITEMS
|
---|
264 | && plswData->usCurrItem == ItemNumFromLineNum(plswData,
|
---|
265 | bForward ?
|
---|
266 | MAXTEXTITEMS :
|
---|
267 | -1)) {
|
---|
268 |
|
---|
269 | plswData->iShift +=
|
---|
270 | (SHORT) (bForward ? MAXTEXTITEMS : -MAXTEXTITEMS) / 3;
|
---|
271 | plswData->iShift -=
|
---|
272 | plswData->iShift / max((SHORT) plswData->usItems,
|
---|
273 | 1) * plswData->usItems;
|
---|
274 |
|
---|
275 | FSPopupMenu(plswData, 0);
|
---|
276 | }
|
---|
277 | else
|
---|
278 | FSPopupMenu(plswData, bForward ? 1 : -1);
|
---|
279 | }
|
---|
280 | else if (ucScan == (((plswData->Settings.bStickyPopup || bNowSticky) ? SCAN_ENTER : plswData->Settings.ucPopupHotKey == 0 ? SCAN_ALT : plswData->Settings.ucPopupHotKey == 1 ? SCAN_CTRL : SCAN_WINLEFT) | 0x80)) { /*Enter, Ctrl or Alt or LeftWin release */
|
---|
281 | bDoSwitch = TRUE;
|
---|
282 | break;
|
---|
283 | }
|
---|
284 | else if (ucScan == (SCAN_SPACE | 0x80) || /* space bar release */
|
---|
285 | ((plswData->Settings.bStickyPopup || bNowSticky)
|
---|
286 | && ucScan == SCAN_ESC))
|
---|
287 | break;
|
---|
288 | else if ((plswData->Settings.ucPopupHotKey == 0
|
---|
289 | && ucScan == (SCAN_CTRL | 0x80))
|
---|
290 | || (plswData->Settings.ucPopupHotKey == 1
|
---|
291 | && ucScan == (SCAN_ALT | 0x80))
|
---|
292 | || (plswData->Settings.ucPopupHotKey == 2
|
---|
293 | && (ucScan == (SCAN_CTRL | 0x80)
|
---|
294 | || ucScan == (SCAN_ALT | 0x80))))
|
---|
295 | bNowSticky = TRUE;
|
---|
296 | }
|
---|
297 | VioEndPopUp(0);
|
---|
298 |
|
---|
299 | if (bDoSwitch)
|
---|
300 | WinPostMsg(plswData->hwndPopup, WM_COMMAND,
|
---|
301 | MPFROMSHORT(CMD_SWITCHFROMFS), MPFROM2SHORT(CMDSRC_OTHER,
|
---|
302 | FALSE));
|
---|
303 | #ifndef XWORKPLACE
|
---|
304 | UninstallExceptq(&exRegRec);
|
---|
305 | #endif
|
---|
306 | }
|
---|
307 |
|
---|
308 | /* this function displays fullscreen popup menu.
|
---|
309 | cmd==0: initialize menu, cmd==1 move cursor to the next item, cmd==-1 to the
|
---|
310 | previous item */
|
---|
311 | void FSPopupMenu(LSWDATA * plswData, SHORT cmd)
|
---|
312 | {
|
---|
313 | static UCHAR ucAttr, ucLineBuf[TEXTSCRWID + 1], ucTitle[NAMELEN],
|
---|
314 | ucCell[2] =
|
---|
315 | { 32, MENUATTR }, ucMenuHgt, ucLineLen, ucMenuXLeft, ucMenuXRight,
|
---|
316 | ucMenuYTop, ucMenuYBottom;
|
---|
317 | USHORT k, usItem;
|
---|
318 | SHORT iLinesAboveSel;
|
---|
319 | VIOCURSORINFO CursorInfo = { 0 };
|
---|
320 |
|
---|
321 | if (cmd == 0) {
|
---|
322 | CursorInfo.attr = -1;
|
---|
323 | VioSetCurType(&CursorInfo, 0);
|
---|
324 | }
|
---|
325 |
|
---|
326 | if (plswData->Settings.bOldPopup) {
|
---|
327 | if (cmd != 0) {
|
---|
328 | memset(ucLineBuf, 0, sizeof(ucLineBuf));
|
---|
329 | GetItemTitle(plswData->TaskArr[plswData->usCurrItem].hsw,
|
---|
330 | ucLineBuf, sizeof(ucLineBuf), TRUE);
|
---|
331 | ucLineBuf[TEXTSCRWID - 1] = 0;
|
---|
332 | k = 0;
|
---|
333 | while (ucLineBuf[k])
|
---|
334 | k++;
|
---|
335 | memmove(&ucLineBuf[(TEXTSCRWID - k) >> 1], ucLineBuf, k);
|
---|
336 | memset(ucLineBuf, 0, (TEXTSCRWID - k) >> 1);
|
---|
337 | ucAttr = MENUATTR;
|
---|
338 | VioWrtCharStrAtt(ucLineBuf, TEXTSCRWID, 0, 0, &ucAttr, 0);
|
---|
339 | }
|
---|
340 | return;
|
---|
341 | }
|
---|
342 |
|
---|
343 | iLinesAboveSel =
|
---|
344 | (min(MAXTEXTITEMS, plswData->usItems) - 1) / 2 - plswData->iShift +
|
---|
345 | (plswData->Settings.bScrollItems ? 0 : plswData->usCurrItem);
|
---|
346 |
|
---|
347 | while (iLinesAboveSel > min(MAXTEXTITEMS, plswData->usItems) - 1
|
---|
348 | || iLinesAboveSel < 0)
|
---|
349 | iLinesAboveSel -= (iLinesAboveSel < 0 ? -1 : 1) * plswData->usItems;
|
---|
350 |
|
---|
351 | if (cmd == 0) {
|
---|
352 | ucLineLen = 0;
|
---|
353 | for (k = 0; k < plswData->usItems; k++) {
|
---|
354 | GetItemTitle(plswData->TaskArr[k].hsw, ucTitle, sizeof(ucTitle),
|
---|
355 | TRUE);
|
---|
356 | if (strlen(ucTitle) > ucLineLen)
|
---|
357 | ucLineLen = strlen(ucTitle);
|
---|
358 | }
|
---|
359 | ucLineLen += 2;
|
---|
360 | ucMenuHgt = min(MAXTEXTITEMS, plswData->usItems) + 2;
|
---|
361 | ucMenuXLeft = TEXTSCRWID / 2 - ucLineLen / 2;
|
---|
362 | ucMenuYTop = TEXTSCRHGT / 2 - ucMenuHgt / 2;
|
---|
363 | ucMenuXRight = ucMenuXLeft + ucLineLen;
|
---|
364 | ucMenuYBottom = ucMenuYTop + ucMenuHgt;
|
---|
365 |
|
---|
366 | for (k = 0; k < ucMenuHgt; k++) {
|
---|
367 | if (k == 0) {
|
---|
368 | memset(ucLineBuf, 205, ucLineLen);
|
---|
369 | ucLineBuf[0] = 201;
|
---|
370 | ucLineBuf[ucLineLen - 1] = 187;
|
---|
371 | }
|
---|
372 | else if (k == ucMenuHgt - 1) {
|
---|
373 | memset(ucLineBuf, 205, ucLineLen);
|
---|
374 | ucLineBuf[0] = 200;
|
---|
375 | ucLineBuf[ucLineLen - 1] = 188;
|
---|
376 | }
|
---|
377 | else {
|
---|
378 | usItem = ItemNumFromLineNum(plswData, k - 1); //-1 takes care of the frame
|
---|
379 | GetItemTitle(plswData->TaskArr[usItem].hsw, ucTitle,
|
---|
380 | sizeof(ucTitle), TRUE);
|
---|
381 | sprintf(ucLineBuf, "%c%-*s%c", 186, ucLineLen - 2, ucTitle,
|
---|
382 | 186);
|
---|
383 | }
|
---|
384 | ucAttr = MENUATTR;
|
---|
385 | VioWrtCharStrAtt(ucLineBuf, ucLineLen, ucMenuYTop + k,
|
---|
386 | ucMenuXLeft, &ucAttr, 0);
|
---|
387 | }
|
---|
388 | }
|
---|
389 | else {
|
---|
390 | if (plswData->Settings.bScrollItems) {
|
---|
391 | if (cmd == 1)
|
---|
392 | VioScrollUp(ucMenuYTop + 1, ucMenuXLeft + 1,
|
---|
393 | ucMenuYBottom - 2, ucMenuXRight - 2, 1, ucCell,
|
---|
394 | 0);
|
---|
395 | else
|
---|
396 | VioScrollDn(ucMenuYTop + 1, ucMenuXLeft + 1,
|
---|
397 | ucMenuYBottom - 2, ucMenuXRight - 2, 1, ucCell,
|
---|
398 | 0);
|
---|
399 |
|
---|
400 | usItem =
|
---|
401 | ItemNumFromLineNum(plswData, cmd == 1 ? ucMenuHgt - 3 : 0);
|
---|
402 | GetItemTitle(plswData->TaskArr[usItem].hsw, ucTitle,
|
---|
403 | sizeof(ucTitle), TRUE);
|
---|
404 | sprintf(ucLineBuf, "%c%-*s%c", 186, ucLineLen - 2, ucTitle, 186);
|
---|
405 | ucAttr = MENUATTR;
|
---|
406 | VioWrtCharStrAtt(ucLineBuf, ucLineLen,
|
---|
407 | cmd == 1 ? ucMenuYBottom - 2 : ucMenuYTop + 1,
|
---|
408 | ucMenuXLeft, &ucAttr, 0);
|
---|
409 | VioWrtNAttr(&ucAttr, ucLineLen - 2,
|
---|
410 | ucMenuYTop + iLinesAboveSel + (cmd == 1 ? 0 : 2),
|
---|
411 | ucMenuXLeft + 1, 0);
|
---|
412 | }
|
---|
413 | else {
|
---|
414 | ucAttr = MENUATTR;
|
---|
415 | VioWrtNAttr(&ucAttr, ucLineLen - 2, ucMenuYTop + iLinesAboveSel +
|
---|
416 | (cmd == 1 ? (iLinesAboveSel == 0 ? ucMenuHgt - 2 : 0)
|
---|
417 | : (iLinesAboveSel ==
|
---|
418 | ucMenuHgt - 3 ? 1 - iLinesAboveSel : 2)),
|
---|
419 | ucMenuXLeft + 1, 0);
|
---|
420 | }
|
---|
421 | }
|
---|
422 | ucAttr = CURSORATTR;
|
---|
423 | VioWrtNAttr(&ucAttr, ucLineLen - 2, ucMenuYTop + iLinesAboveSel + 1,
|
---|
424 | ucMenuXLeft + 1, 0);
|
---|
425 | }
|
---|