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 | #define INCL_DOSMEMMGR
|
---|
15 | #define INCL_DOSMODULEMGR
|
---|
16 | #define INCL_WIN
|
---|
17 |
|
---|
18 | #include "lswitch.h"
|
---|
19 | #include "taskbar.h"
|
---|
20 | #include <string.h>
|
---|
21 | #include <stdio.h>
|
---|
22 | #define __PMPRINTF__
|
---|
23 | #include "PMPRINTF.H"
|
---|
24 |
|
---|
25 | /*
|
---|
26 | Since the hooks may be called in the context of any thead having a message
|
---|
27 | queue, we must use shared memory to access the globals of lSwitcher daemon.
|
---|
28 | For the same reason the shared mem must be freed upon exiting the hook procs,
|
---|
29 | otherwise the caller will retain a reference to it and the shared mem object
|
---|
30 | will not be destroyed when lSwitcher exits
|
---|
31 | IMPORTANT !!! Don't use DosGetNamedSharedMed/DosFreeMem before it's REALLY
|
---|
32 | needed, check all other conditions first. These functions turn out to be
|
---|
33 | expensive performance-wise
|
---|
34 |
|
---|
35 | With version 2.6 this DLL, if compiled with Watcom C, does not use C RTL
|
---|
36 | (since Watcom RTL does not support multiple processes attached to a DLL
|
---|
37 | with a single data segment, which we need). Because of this stack overflow
|
---|
38 | is not checked for, and we want to reduce stack usage to a minimum
|
---|
39 | */
|
---|
40 |
|
---|
41 | HWND hwndMenuUp = NULLHANDLE, hwndTskBar = NULLHANDLE, hwndPopup = NULLHANDLE;
|
---|
42 | BOOL bWidget;
|
---|
43 |
|
---|
44 | APIRET ctrpDesktopWorkareaSupported(VOID);
|
---|
45 |
|
---|
46 | APIRET doshQueryProcAddr(PCSZ pcszModuleName, ULONG ulOrdinal, PFN *ppfn);
|
---|
47 |
|
---|
48 | //#ifndef XWORKPLACE
|
---|
49 | /*
|
---|
50 | * WinSetDesktopWorkArea:
|
---|
51 | * undocumented Warp 4 API to change the "desktop work
|
---|
52 | * area", which, among other things, sets the size for
|
---|
53 | * maximized windows.
|
---|
54 | *
|
---|
55 | * This is manually imported from PMMERGE.5468.
|
---|
56 | */
|
---|
57 |
|
---|
58 | BOOL APIENTRY WinSetDesktopWorkArea(HWND hwndDesktop,
|
---|
59 | PRECTL pwrcWorkArea);
|
---|
60 | typedef BOOL APIENTRY WINSETDESKTOPWORKAREA(HWND hwndDesktop,
|
---|
61 | PRECTL pwrcWorkArea);
|
---|
62 | typedef WINSETDESKTOPWORKAREA *PWINSETDESKTOPWORKAREA;
|
---|
63 |
|
---|
64 | /*
|
---|
65 | * WinQueryDesktopWorkArea:
|
---|
66 | * the reverse to the above.
|
---|
67 | *
|
---|
68 | * This is manually imported from PMMERGE.5469.
|
---|
69 | */
|
---|
70 |
|
---|
71 | BOOL APIENTRY WinQueryDesktopWorkArea(HWND hwndDesktop,
|
---|
72 | PRECTL pwrcWorkArea);
|
---|
73 | typedef BOOL APIENTRY WINQUERYDESKTOPWORKAREA(HWND hwndDesktop,
|
---|
74 | PRECTL pwrcWorkArea);
|
---|
75 | typedef WINQUERYDESKTOPWORKAREA *PWINQUERYDESKTOPWORKAREA;
|
---|
76 |
|
---|
77 | static PWINSETDESKTOPWORKAREA G_WinSetDesktopWorkArea = (PWINSETDESKTOPWORKAREA)-1;
|
---|
78 | static PWINQUERYDESKTOPWORKAREA G_WinQueryDesktopWorkArea = (PWINQUERYDESKTOPWORKAREA)-1;
|
---|
79 |
|
---|
80 | BOOL fWorkAreaSupported;
|
---|
81 | /**
|
---|
82 | * Check to see if PMMerge supports reducing the desktop
|
---|
83 | * Code adapted from xworkplace by Ulrich Mller & Paul Ratcliffe
|
---|
84 | **/
|
---|
85 | APIRET doshQueryProcAddr(PCSZ pcszModuleName, // in: module name (e.g. "PMMERGE")
|
---|
86 | ULONG ulOrdinal, // in: proc ordinal
|
---|
87 | PFN *ppfn) // out: proc address
|
---|
88 | {
|
---|
89 | HMODULE hmod;
|
---|
90 | APIRET arc;
|
---|
91 | if (!(arc = DosQueryModuleHandle((PSZ)pcszModuleName,
|
---|
92 | &hmod)))
|
---|
93 | {
|
---|
94 | if ((arc = DosQueryProcAddr(hmod,
|
---|
95 | ulOrdinal,
|
---|
96 | NULL,
|
---|
97 | ppfn)))
|
---|
98 | {
|
---|
99 | // the CP programming guide and reference says use
|
---|
100 | // DosLoadModule if DosQueryProcAddr fails with this error
|
---|
101 | if (arc == ERROR_INVALID_HANDLE)
|
---|
102 | {
|
---|
103 | if (!(arc = DosLoadModule(NULL,
|
---|
104 | 0,
|
---|
105 | (PSZ)pcszModuleName,
|
---|
106 | &hmod)))
|
---|
107 | {
|
---|
108 | arc = DosQueryProcAddr(hmod,
|
---|
109 | ulOrdinal,
|
---|
110 | NULL,
|
---|
111 | ppfn);
|
---|
112 | }
|
---|
113 | }
|
---|
114 | }
|
---|
115 | }
|
---|
116 |
|
---|
117 | return arc;
|
---|
118 | }
|
---|
119 | /**
|
---|
120 | * Check to see if PMMerge supports reducing the desktop
|
---|
121 | * Code adapted from xworkplace by Ulrich Mller & Paul Ratcliffe
|
---|
122 | **/
|
---|
123 | APIRET ctrpDesktopWorkareaSupported(VOID)
|
---|
124 | {
|
---|
125 | APIRET arc = ERROR_INVALID_ORDINAL;
|
---|
126 |
|
---|
127 | if ((ULONG)G_WinSetDesktopWorkArea == -1)
|
---|
128 | {
|
---|
129 | // first call:
|
---|
130 | if ( (!(arc = doshQueryProcAddr("PMMERGE",
|
---|
131 | 5468,
|
---|
132 | (PFN*)&G_WinSetDesktopWorkArea)))
|
---|
133 | && (!(arc = doshQueryProcAddr("PMMERGE",
|
---|
134 | 5469,
|
---|
135 | (PFN*)&G_WinQueryDesktopWorkArea)))
|
---|
136 | )
|
---|
137 | {
|
---|
138 | //lstInit(&G_llWorkAreaViews, FALSE);
|
---|
139 | fWorkAreaSupported = TRUE;
|
---|
140 | }
|
---|
141 | }
|
---|
142 |
|
---|
143 | if (arc)
|
---|
144 | {
|
---|
145 | G_WinSetDesktopWorkArea = NULL;
|
---|
146 | G_WinQueryDesktopWorkArea = NULL;
|
---|
147 | }
|
---|
148 |
|
---|
149 | return arc;
|
---|
150 | }
|
---|
151 |
|
---|
152 | //simple and dirty string to integer conversion
|
---|
153 | /*ULONG __atol(UCHAR * s)
|
---|
154 | {
|
---|
155 | SHORT k;
|
---|
156 | ULONG r, base;
|
---|
157 |
|
---|
158 | for (k = 0; s[k] != '\0'; k++) ;
|
---|
159 | for (--k, base = 1, r = 0; k >= 0; k--, base *= 10)
|
---|
160 | r += (s[k] - 48) * base;
|
---|
161 |
|
---|
162 | return r;
|
---|
163 | } */
|
---|
164 |
|
---|
165 | BOOL IsWindowClass(HWND hwnd, UCHAR * pszClassName)
|
---|
166 | {
|
---|
167 | static UCHAR ucBuf[32]; //reduce stack usage to minimum since we don't use stack probes
|
---|
168 | USHORT k;
|
---|
169 | BOOL bEqual;
|
---|
170 |
|
---|
171 | WinQueryClassName(hwnd, sizeof(ucBuf) - 1, ucBuf);
|
---|
172 | /* equivalent of strcmp, but we don't want to use the RTL */
|
---|
173 | for (k = 0, bEqual = TRUE; ucBuf[k] != '\0' && pszClassName[k] != '\0';
|
---|
174 | k++)
|
---|
175 | if (ucBuf[k] != pszClassName[k]) {
|
---|
176 | bEqual = FALSE;
|
---|
177 | break;
|
---|
178 | }
|
---|
179 |
|
---|
180 | return (bEqual && ucBuf[k] == '\0' && pszClassName[k] == '\0');
|
---|
181 | }
|
---|
182 |
|
---|
183 | BOOL IsDesktop(HWND hwnd)
|
---|
184 | {
|
---|
185 | return (hwnd == WinQueryWindow(HWND_DESKTOP, QW_BOTTOM) &&
|
---|
186 | (IsWindowClass(hwnd, "wpFolder window")));
|
---|
187 | }
|
---|
188 |
|
---|
189 | BOOL GetSharedMem(LSWDATA ** plswData)
|
---|
190 | {
|
---|
191 | return
|
---|
192 | (DosGetNamedSharedMem
|
---|
193 | ((PVOID *) plswData, SHAREMEM_NAME, PAG_READ | PAG_WRITE) == 0
|
---|
194 | && plswData != NULL);
|
---|
195 | }
|
---|
196 |
|
---|
197 | VOID SetPrty(ULONG pid, USHORT usPrty)
|
---|
198 | {
|
---|
199 | SHORT sPrtyC, sPrtyD;
|
---|
200 | BOOL bDesc;
|
---|
201 |
|
---|
202 | bDesc = (usPrty & 0x8000);
|
---|
203 | usPrty &= ~0x8000;
|
---|
204 | sPrtyC = (usPrty + PRTYD_MAXIMUM) >> 8;
|
---|
205 | sPrtyD = usPrty - (sPrtyC << 8);
|
---|
206 | DosSetPriority(bDesc ? PRTYS_PROCESSTREE : PRTYS_PROCESS, sPrtyC, sPrtyD,
|
---|
207 | pid);
|
---|
208 | }
|
---|
209 |
|
---|
210 | BOOL EXPENTRY lswInputHook(HAB hab, PQMSG pQmsg, ULONG fs)
|
---|
211 | {
|
---|
212 | LSWDATA *plswData;
|
---|
213 | POINTL ptl;
|
---|
214 | static BOOL bOnTop = FALSE;
|
---|
215 | static USHORT usOldY = 0xFFFF, cyScreen = 0, cyTskBar = 0; // this and the previous lines need to be static
|
---|
216 | static RECTL rcl; //reduce stack usage to minimum since we don't use stack probes
|
---|
217 | static HWND hwndBtn = 0;
|
---|
218 | PPIB ppib;
|
---|
219 |
|
---|
220 | DosGetInfoBlocks(NULL, &ppib);
|
---|
221 | if (ppib->pib_flstatus & PS_EXITLIST)
|
---|
222 | return FALSE;
|
---|
223 |
|
---|
224 | if (cyScreen == 0 || pQmsg->msg == WM_SYSVALUECHANGED)
|
---|
225 | cyScreen = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
|
---|
226 |
|
---|
227 | // get taskbar hwnd in case it changed
|
---|
228 | if (pQmsg->msg == WM_NULL && pQmsg->hwnd == 0 && GetSharedMem(&plswData)) {
|
---|
229 | hwndTskBar = plswData->hwndTaskBarClient;
|
---|
230 | DosFreeMem(plswData);
|
---|
231 | }
|
---|
232 |
|
---|
233 | if (pQmsg->msg == WM_MOUSEMOVE) {
|
---|
234 | if (pQmsg->hwnd != hwndBtn) {
|
---|
235 | if (WinQueryWindow(pQmsg->hwnd, QW_PARENT) == hwndTskBar
|
---|
236 | && IsWindowClass(pQmsg->hwnd, "#3")) {
|
---|
237 | hwndBtn = pQmsg->hwnd;
|
---|
238 | WinPostMsg(hwndTskBar, LSWM_MOUSEOVERBTN, MPFROMHWND(hwndBtn),
|
---|
239 | 0);
|
---|
240 | }
|
---|
241 | else if (hwndBtn != 0) {
|
---|
242 | hwndBtn = 0;
|
---|
243 | WinPostMsg(hwndTskBar, LSWM_MOUSEOVERBTN, MPFROMHWND(hwndBtn),
|
---|
244 | 0);
|
---|
245 | }
|
---|
246 | }
|
---|
247 |
|
---|
248 | if (!bWidget && hwndMenuUp == NULLHANDLE
|
---|
249 | && (WinQueryPointerPos(HWND_DESKTOP, &ptl), ptl.y != usOldY)) {
|
---|
250 | usOldY = ptl.y;
|
---|
251 | if ((!bOnTop && (ptl.y == 0 || ptl.y == cyScreen - 1)) ||
|
---|
252 | (bOnTop && ptl.y > 2 * cyTskBar
|
---|
253 | && ptl.y < cyScreen - 2 * cyTskBar)) {
|
---|
254 |
|
---|
255 | if (!GetSharedMem(&plswData))
|
---|
256 | return FALSE;
|
---|
257 | if ((!bOnTop
|
---|
258 | && plswData->Settings.bTaskBarTopScr ^ ptl.y == 0)
|
---|
259 | || (bOnTop && !WinIsWindowVisible(plswData->hwndMenu))) {
|
---|
260 | if (!bOnTop) {
|
---|
261 | WinQueryWindowRect(plswData->hwndTaskBar, &rcl);
|
---|
262 | cyTskBar = rcl.yTop;
|
---|
263 | }
|
---|
264 | WinSetWindowPos(plswData->hwndTaskBar,
|
---|
265 | HWND_TOP, 0, 0, 0,
|
---|
266 | 0, SWP_ZORDER | SWP_SHOW);
|
---|
267 | bOnTop ^= TRUE;
|
---|
268 | }
|
---|
269 | DosFreeMem(plswData);
|
---|
270 | }
|
---|
271 | }
|
---|
272 | }
|
---|
273 | else if (pQmsg->msg ==
|
---|
274 | WinFindAtom(WinQuerySystemAtomTable(), LSWM_GETPROCCMD)
|
---|
275 | && GetSharedMem(&plswData)) {
|
---|
276 | UCHAR *ucHandle;
|
---|
277 | USHORT usHandle = 0;
|
---|
278 |
|
---|
279 | strncpy(plswData->buf,
|
---|
280 | &ppib->pib_pchcmd[strlen(ppib->pib_pchcmd) + 1],
|
---|
281 | sizeof plswData->buf);
|
---|
282 | if (DosScanEnv("WP_OBJHANDLE", &ucHandle) == 0 && ucHandle != NULL)
|
---|
283 | strncpy(&plswData->buf[strlen(plswData->buf) + 1], ucHandle,
|
---|
284 | sizeof plswData->buf - strlen(plswData->buf) - 2);
|
---|
285 |
|
---|
286 | DosFreeMem(plswData);
|
---|
287 | WinPostMsg(hwndTskBar, LSWM_SWITCHLISTCHANGED, MPFROMLONG(4),
|
---|
288 | pQmsg->mp2);
|
---|
289 | //don't understand why we need to pass this over, but there is some system instability otherwise
|
---|
290 | }
|
---|
291 | else if (pQmsg->msg ==
|
---|
292 | WinFindAtom(WinQuerySystemAtomTable(), LSWM_SETPRIORITY)) {
|
---|
293 | SetPrty(LONGFROMMP(pQmsg->mp2), SHORT1FROMMP(pQmsg->mp1));
|
---|
294 | return TRUE;
|
---|
295 | }
|
---|
296 | return FALSE;
|
---|
297 | }
|
---|
298 |
|
---|
299 | /* we install this function as a pre-accelerator hook (undocumented). This hook
|
---|
300 | is called even before an application accelerator table is translated, which helps
|
---|
301 | to avoid compatibility problems with Ctrl-Tab hotkey */
|
---|
302 | BOOL EXPENTRY lswPreAccHook(HAB hab, PQMSG pQmsg, ULONG fs)
|
---|
303 | {
|
---|
304 | USHORT usFlags;
|
---|
305 | UCHAR ucScan;
|
---|
306 | LSWDATA *plswData;
|
---|
307 | BOOL bRet;
|
---|
308 | PPIB ppib;
|
---|
309 |
|
---|
310 | DosGetInfoBlocks(NULL, &ppib);
|
---|
311 | if (ppib->pib_flstatus & PS_EXITLIST)
|
---|
312 | return FALSE;
|
---|
313 |
|
---|
314 | if (pQmsg->msg != WM_CHAR
|
---|
315 | || (usFlags = SHORT1FROMMP(pQmsg->mp1), ucScan =
|
---|
316 | CHAR4FROMMP(pQmsg->mp1), (usFlags & KC_SCANCODE)) == 0)
|
---|
317 | return FALSE;
|
---|
318 |
|
---|
319 | bRet = FALSE;
|
---|
320 | /* tab w/ left Ctrl down. Trap the key either it's pressed or released,
|
---|
321 | so that it does not reach other applications and trigger something*/
|
---|
322 | /* Alt-Tab might work in alternative shells */
|
---|
323 | if (ucScan == SCAN_TAB
|
---|
324 | && ((usFlags & KC_CTRL) != 0 ^ (usFlags & KC_ALT) != 0)
|
---|
325 | && GetSharedMem(&plswData)) {
|
---|
326 | if ((plswData->Settings.ucPopupHotKey == 0 && (usFlags & KC_ALT))
|
---|
327 | || (plswData->Settings.ucPopupHotKey == 1 && (usFlags & KC_CTRL))) {
|
---|
328 | if (usFlags & KC_KEYUP)
|
---|
329 | WinPostMsg(plswData->hwndPopClient, WM_COMMAND, MPFROMSHORT
|
---|
330 | ((usFlags & KC_SHIFT) ? CMD_SCROLLLEFT :
|
---|
331 | CMD_SCROLLRIGHT), MPFROM2SHORT(CMDSRC_OTHER,
|
---|
332 | FALSE));
|
---|
333 | bRet = TRUE;
|
---|
334 | }
|
---|
335 | DosFreeMem(plswData);
|
---|
336 | }
|
---|
337 |
|
---|
338 | /* Show settings */
|
---|
339 | if (!(usFlags & KC_KEYUP) && (usFlags & KC_ALT) && (usFlags & KC_CTRL)
|
---|
340 | && GetSharedMem(&plswData)) {
|
---|
341 | if (ucScan == plswData->Settings.ucSettingsScan) {
|
---|
342 | WinPostMsg(plswData->hwndPopClient, WM_COMMAND,
|
---|
343 | MPFROMSHORT(CMD_SHOWSETTINGS),
|
---|
344 | MPFROM2SHORT(CMDSRC_OTHER, FALSE));
|
---|
345 | bRet = TRUE;
|
---|
346 | }
|
---|
347 | DosFreeMem(plswData);
|
---|
348 | }
|
---|
349 |
|
---|
350 | return bRet;
|
---|
351 | }
|
---|
352 |
|
---|
353 | VOID EXPENTRY lswSendHook(HAB hab, PSMHSTRUCT psmh, BOOL fInterTask)
|
---|
354 | {
|
---|
355 | LSWDATA *plswData;
|
---|
356 | HSWITCH hsw;
|
---|
357 | static SWCNTRL swctl; //reduce stack usage to a minimum since we don't use stack probes
|
---|
358 | static SWP swp;
|
---|
359 | ULONG ulFlags;
|
---|
360 | BOOL bPosChange, bActiveChange;
|
---|
361 | PPIB ppib;
|
---|
362 |
|
---|
363 | if (psmh->msg == SH_SWITCHLIST && IsWindowClass(psmh->hwnd, "WindowList") && //check msg target to avoid multiple messages
|
---|
364 | (((LONG) psmh->mp1 >= 1 && (LONG) psmh->mp1 <= 3)
|
---|
365 | || (LONG) psmh->mp1 == 0x10001) && GetSharedMem(&plswData)) {
|
---|
366 | if (plswData->bNowActive)
|
---|
367 | WinPostMsg(plswData->hwndPopClient, LSWM_SWITCHLISTCHANGED,
|
---|
368 | psmh->mp1, psmh->mp2);
|
---|
369 | if (plswData->Settings.bTaskBarOn)
|
---|
370 | WinPostMsg(plswData->hwndTaskBarClient, LSWM_SWITCHLISTCHANGED,
|
---|
371 | psmh->mp1, psmh->mp2);
|
---|
372 | if (WinIsWindow(hab, plswData->hwndParamDlg))
|
---|
373 | WinPostMsg(plswData->hwndParamDlg, LSWM_SWITCHLISTCHANGED,
|
---|
374 | psmh->mp1, psmh->mp2);
|
---|
375 | DosFreeMem(plswData);
|
---|
376 | return;
|
---|
377 | }
|
---|
378 |
|
---|
379 | DosGetInfoBlocks(NULL, &ppib);
|
---|
380 | if (ppib->pib_flstatus & PS_EXITLIST)
|
---|
381 | return;
|
---|
382 |
|
---|
383 | if (psmh->msg == WM_COMMAND && IsWindowClass(psmh->hwnd, "AltTabWindow") && (WinGetPhysKeyState(HWND_DESKTOP, 0x5e) & 0x8000) == 0 && // right Alt up
|
---|
384 | GetSharedMem(&plswData)) {
|
---|
385 | if (plswData->Settings.ucPopupHotKey == 0
|
---|
386 | && plswData->Settings.bPMSwitcher) {
|
---|
387 | BOOL bShift = (WinGetPhysKeyState(HWND_DESKTOP, 0x2a) & 0x8000) || // either Shift down
|
---|
388 | (WinGetPhysKeyState(HWND_DESKTOP, 0x36) & 0x8000);
|
---|
389 |
|
---|
390 | WinPostMsg(plswData->hwndPopClient, WM_COMMAND,
|
---|
391 | MPFROMSHORT(bShift ? CMD_SCROLLLEFT : CMD_SCROLLRIGHT),
|
---|
392 | MPFROM2SHORT(CMDSRC_OTHER, FALSE));
|
---|
393 | psmh->msg = WM_NULL;
|
---|
394 | }
|
---|
395 | DosFreeMem(plswData);
|
---|
396 | return;
|
---|
397 | }
|
---|
398 |
|
---|
399 | // make sure the taskbar does not show up and cover desktop menu
|
---|
400 | if (psmh->msg == WM_INITMENU && IsDesktop(psmh->hwnd))
|
---|
401 | hwndMenuUp = HWNDFROMMP(psmh->mp2);
|
---|
402 | if (psmh->msg == WM_MENUEND && HWNDFROMMP(psmh->mp2) == hwndMenuUp)
|
---|
403 | hwndMenuUp = NULLHANDLE;
|
---|
404 |
|
---|
405 | if (psmh->msg == WM_SETICON && WinQuerySwitchHandle(psmh->hwnd, 0) != 0 &&
|
---|
406 | GetSharedMem(&plswData)) {
|
---|
407 | if (plswData->bNowActive)
|
---|
408 | WinPostMsg(plswData->hwndPopClient, LSWM_WNDICONCHANGED,
|
---|
409 | psmh->mp1, MPFROMHWND(psmh->hwnd));
|
---|
410 | if (plswData->Settings.bTaskBarOn)
|
---|
411 | WinPostMsg(plswData->hwndTaskBarClient, LSWM_WNDICONCHANGED,
|
---|
412 | psmh->mp1, MPFROMHWND(psmh->hwnd));
|
---|
413 | DosFreeMem(plswData);
|
---|
414 | return;
|
---|
415 | }
|
---|
416 |
|
---|
417 | /* make just minimized or hidden window appear after the current one in
|
---|
418 | the switch list if the corresponding option is on in settings */
|
---|
419 | if (psmh->msg == WM_ADJUSTFRAMEPOS &&
|
---|
420 | (((PSWP) PVOIDFROMMP(psmh->mp1))->fl & (SWP_HIDE | SWP_MINIMIZE)) &&
|
---|
421 | !(WinGetPhysKeyState(HWND_DESKTOP, 0x38) & 0x8000) &&
|
---|
422 | WinQuerySwitchHandle(psmh->hwnd, 0) != 0
|
---|
423 | && IsWindowClass(psmh->hwnd, "#1") && GetSharedMem(&plswData)) {
|
---|
424 |
|
---|
425 | if (plswData->Settings.bChangeZOrder)
|
---|
426 | ((PSWP) PVOIDFROMMP(psmh->mp1))->hwndInsertBehind = HWND_TOP;
|
---|
427 | DosFreeMem(plswData);
|
---|
428 | return;
|
---|
429 | }
|
---|
430 |
|
---|
431 | if (psmh->msg == WM_DESTROY
|
---|
432 | && WinQueryWindow(psmh->hwnd, QW_PARENT) == WinQueryDesktopWindow(0,
|
---|
433 | 0)
|
---|
434 | && GetSharedMem(&plswData)) {
|
---|
435 | USHORT k;
|
---|
436 |
|
---|
437 | //the minimized window list holds the virtual desktop positions the windows were minimized from
|
---|
438 | for (k = 0; k < MINMAXITEMS; k++)
|
---|
439 | if (psmh->hwnd == plswData->MinMaxWnd[2 * k]) {
|
---|
440 | plswData->MinMaxWnd[2 * k] = 0;
|
---|
441 | break;
|
---|
442 | }
|
---|
443 | DosFreeMem(plswData);
|
---|
444 | return;
|
---|
445 | }
|
---|
446 |
|
---|
447 | if (psmh->msg == WM_MINMAXFRAME
|
---|
448 | && WinQueryWindow(psmh->hwnd, QW_PARENT) == WinQueryDesktopWindow(0,
|
---|
449 | 0)
|
---|
450 | && GetSharedMem(&plswData)) {
|
---|
451 |
|
---|
452 | USHORT k;
|
---|
453 |
|
---|
454 | ulFlags = ((PSWP) PVOIDFROMMP(psmh->mp1))->fl;
|
---|
455 | WinQueryWindowPos(psmh->hwnd, &swp);
|
---|
456 |
|
---|
457 | //the minimized window list holds the virtual desktop positions the windows were minimized from
|
---|
458 | for (k = 0; k < MINMAXITEMS; k++)
|
---|
459 | if ((ulFlags & SWP_MAXIMIZE)
|
---|
460 | && psmh->hwnd == plswData->MinMaxWnd[2 * k]) {
|
---|
461 | ((PSWP) PVOIDFROMMP(psmh->mp1))->x +=
|
---|
462 | (WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN) +
|
---|
463 | 8) * (((plswData->MinMaxWnd[2 * k + 1] & 0xFF00) >> 8) -
|
---|
464 | ((plswData->lCurrDesktop & 0xFF00) >> 8));
|
---|
465 | ((PSWP) PVOIDFROMMP(psmh->mp1))->y +=
|
---|
466 | (WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) +
|
---|
467 | 8) * ((plswData->MinMaxWnd[2 * k + 1] & 0xFF) -
|
---|
468 | (plswData->lCurrDesktop & 0xFF));
|
---|
469 | plswData->MinMaxWnd[2 * k] = 0;
|
---|
470 | break;
|
---|
471 | }
|
---|
472 | else if ((ulFlags & SWP_MINIMIZE) && (swp.fl & SWP_MAXIMIZE)
|
---|
473 | && plswData->MinMaxWnd[2 * k] == 0) {
|
---|
474 | plswData->MinMaxWnd[2 * k] = psmh->hwnd;
|
---|
475 | plswData->MinMaxWnd[2 * k + 1] = plswData->lCurrDesktop;
|
---|
476 | break;
|
---|
477 | }
|
---|
478 | DosFreeMem(plswData);
|
---|
479 | return;
|
---|
480 | }
|
---|
481 |
|
---|
482 | /* can't call WinPostMsg in WM_ACTIVATE hook because of some random crashes
|
---|
483 | if (!bWidget && psmh->msg==WM_ACTIVATE) {
|
---|
484 | WinPostMsg(hwndTskBar,LSWM_ACTIVEWNDCHANGED,0,0);
|
---|
485 | return;
|
---|
486 | }
|
---|
487 | */
|
---|
488 |
|
---|
489 | if (psmh->msg == WM_WINDOWPOSCHANGED &&
|
---|
490 | (ulFlags = ((PSWP) PVOIDFROMMP(psmh->mp1))->fl,
|
---|
491 | bPosChange =
|
---|
492 | (ulFlags &
|
---|
493 | (SWP_HIDE | SWP_SHOW | SWP_MINIMIZE | SWP_MAXIMIZE | SWP_RESTORE)),
|
---|
494 | bActiveChange =
|
---|
495 | (ulFlags &
|
---|
496 | (SWP_ACTIVATE | SWP_DEACTIVATE | SWP_FOCUSACTIVATE |
|
---|
497 | SWP_FOCUSDEACTIVATE)), (bPosChange
|
---|
498 | && (hsw =
|
---|
499 | WinQuerySwitchHandle(psmh->hwnd,
|
---|
500 | 0)) != 0
|
---|
501 | && (WinQuerySwitchEntry(hsw, &swctl),
|
---|
502 | swctl.hwnd == psmh->hwnd))
|
---|
503 | || bActiveChange) && GetSharedMem(&plswData)) {
|
---|
504 |
|
---|
505 | //notify the lswitcher app of window state changes
|
---|
506 | if (plswData->Settings.bTaskBarOn && bActiveChange)
|
---|
507 | WinPostMsg(plswData->hwndTaskBarClient, LSWM_ACTIVEWNDCHANGED,
|
---|
508 | MPFROMHWND(psmh->hwnd), psmh->mp1);
|
---|
509 | if (bPosChange) {
|
---|
510 | WinPostMsg(plswData->hwndPopClient, LSWM_WNDSTATECHANGED,
|
---|
511 | MPFROM2SHORT(hsw & 0xFFFF, (SHORT) (ulFlags & 0xFFFF)),
|
---|
512 | MPFROMHWND(psmh->hwnd));
|
---|
513 | if (plswData->Settings.bTaskBarOn)
|
---|
514 | WinPostMsg(plswData->hwndTaskBarClient, LSWM_WNDSTATECHANGED,
|
---|
515 | MPFROM2SHORT(hsw & 0xFFFF,
|
---|
516 | (SHORT) (ulFlags & 0xFFFF)),
|
---|
517 | MPFROMHWND(psmh->hwnd));
|
---|
518 | }
|
---|
519 | DosFreeMem(plswData);
|
---|
520 | return;
|
---|
521 | }
|
---|
522 | }
|
---|
523 |
|
---|
524 | LONG EXPENTRY lswHookInit(LSWDATA * plswData)
|
---|
525 | {
|
---|
526 | bWidget = plswData->bWidget;
|
---|
527 |
|
---|
528 | hwndTskBar = plswData->hwndTaskBarClient;
|
---|
529 | hwndPopup = plswData->hwndPopClient;
|
---|
530 |
|
---|
531 | if (DosQueryModuleHandle(DLL_NAME, &plswData->hmodHook))
|
---|
532 | return -1;
|
---|
533 |
|
---|
534 | if (!WinSetHook
|
---|
535 | (plswData->hab, NULLHANDLE, HK_SENDMSG, (PFN) lswSendHook,
|
---|
536 | plswData->hmodHook))
|
---|
537 | return -2;
|
---|
538 | if (!WinSetHook
|
---|
539 | (plswData->hab, NULLHANDLE, HK_PREACCEL, (PFN) lswPreAccHook,
|
---|
540 | plswData->hmodHook))
|
---|
541 | return -3;
|
---|
542 | if (!WinSetHook
|
---|
543 | (plswData->hab, NULLHANDLE, HK_INPUT, (PFN) lswInputHook,
|
---|
544 | plswData->hmodHook))
|
---|
545 | return -4;
|
---|
546 |
|
---|
547 | WinPostMsg(0, WM_NULL, 0, 0); //reset the hook
|
---|
548 |
|
---|
549 | return MAKEULONG(MAKEUSHORT(VERSIONMAJOR, VERSIONMINOR),
|
---|
550 | MAKEUSHORT(REVISION, 0));
|
---|
551 | }
|
---|
552 |
|
---|
553 | VOID EXPENTRY lswHookTerm(LSWDATA * plswData)
|
---|
554 | {
|
---|
555 | WinReleaseHook(plswData->hab, NULLHANDLE, HK_INPUT, (PFN) lswInputHook,
|
---|
556 | plswData->hmodHook);
|
---|
557 | WinReleaseHook(plswData->hab, NULLHANDLE, HK_PREACCEL,
|
---|
558 | (PFN) lswPreAccHook, plswData->hmodHook);
|
---|
559 | WinReleaseHook(plswData->hab, NULLHANDLE, HK_SENDMSG, (PFN) lswSendHook,
|
---|
560 | plswData->hmodHook);
|
---|
561 | }
|
---|
562 |
|
---|
563 | ULONG EXPENTRY lswHookGetVersion(void)
|
---|
564 | {
|
---|
565 | return MAKEULONG(MAKEUSHORT(VERSIONMAJOR, VERSIONMINOR),
|
---|
566 | MAKEUSHORT(REVISION, 0));
|
---|
567 | }
|
---|
568 | /**
|
---|
569 | * Update the desktop area as appropriate
|
---|
570 | * Code adapted from xworkplace by Ulrich Mller & Paul Ratcliffe
|
---|
571 | **/
|
---|
572 | BOOL EXPENTRY UpdateDesktopWorkarea(LSWDATA * plswData,
|
---|
573 | BOOL fForceFullSize) // in: if TRUE, desktop made full size
|
---|
574 | {
|
---|
575 | BOOL brc = FALSE;
|
---|
576 | static BOOL didOnce = FALSE;
|
---|
577 |
|
---|
578 | if (!didOnce) {
|
---|
579 | ctrpDesktopWorkareaSupported();
|
---|
580 | didOnce = TRUE;
|
---|
581 | }
|
---|
582 | // workareas supported on this system?
|
---|
583 | if (fWorkAreaSupported)
|
---|
584 | {
|
---|
585 | /*
|
---|
586 | * (2) Calculate new desktop workarea:
|
---|
587 | *
|
---|
588 | */
|
---|
589 | RECTL rclCurrent, rclNew;
|
---|
590 | ULONG ulCutBottom = 0, ulCutTop = 0,
|
---|
591 | // take frame sizing border into account
|
---|
592 | cyFrame = WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);
|
---|
593 | // get current first
|
---|
594 | G_WinQueryDesktopWorkArea(HWND_DESKTOP, &rclCurrent);
|
---|
595 | // compose new workarea; start out with screen size
|
---|
596 | rclNew.xLeft = 0;
|
---|
597 | rclNew.yBottom = 0;
|
---|
598 | rclNew.xRight = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
|
---|
599 | rclNew.yTop = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
|
---|
600 | // the workarea APIs want inclusive rectangles...
|
---|
601 | // I tested this, I get 1024 and 768 for the top right.
|
---|
602 |
|
---|
603 | if (!fForceFullSize) {
|
---|
604 | if (!plswData->Settings.bTaskBarTopScr)
|
---|
605 | {
|
---|
606 | // on bottom:
|
---|
607 | if (plswData->Settings.sTskBarCY + cyFrame > ulCutBottom)
|
---|
608 | ulCutBottom = plswData->Settings.sTskBarCY + cyFrame;
|
---|
609 | }
|
---|
610 | else
|
---|
611 | // on top:
|
---|
612 | if (plswData->Settings.sTskBarCY + cyFrame - 1 > ulCutTop)
|
---|
613 | ulCutTop = plswData->Settings.sTskBarCY + cyFrame - 1;
|
---|
614 | rclNew.yBottom += ulCutBottom;
|
---|
615 | rclNew.yTop -= ulCutTop;
|
---|
616 | }
|
---|
617 |
|
---|
618 | if (memcmp(&rclCurrent, &rclNew, sizeof(RECTL)) != 0)
|
---|
619 | {
|
---|
620 | // rectangle has changed:
|
---|
621 |
|
---|
622 | /*
|
---|
623 | * (3) Set new desktop workarea:
|
---|
624 | *
|
---|
625 | */
|
---|
626 |
|
---|
627 | G_WinSetDesktopWorkArea(HWND_DESKTOP, &rclNew);
|
---|
628 |
|
---|
629 | brc = TRUE;
|
---|
630 | }
|
---|
631 |
|
---|
632 | } // end if (fWorkAreaSupported)
|
---|
633 |
|
---|
634 | return brc;
|
---|
635 | }
|
---|
636 |
|
---|