VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxCaps.cpp@ 95966

最後變更 在這個檔案從95966是 95966,由 vboxsync 提交於 3 年 前

Additions/VBoxTray: More cleanup: Moved the capabilities and console API into own modules, also the desktop tracking stuff. All lacks documentation, hard to find out what this all does, and why.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 10.1 KB
 
1/* $Id: VBoxCaps.cpp 95966 2022-08-01 15:40:29Z vboxsync $ */
2/** @file
3 * VBoxCaps.cpp - Capability APIs.
4 */
5
6/*
7 * Copyright (C) 2013-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <iprt/log.h>
19
20#include "VBoxTray.h"
21#include "VBoxTrayInternal.h"
22#include "VBoxSeamless.h"
23
24
25typedef enum VBOXCAPS_ENTRY_ACSTATE
26{
27 /* the given cap is released */
28 VBOXCAPS_ENTRY_ACSTATE_RELEASED = 0,
29 /* the given cap acquisition is in progress */
30 VBOXCAPS_ENTRY_ACSTATE_ACQUIRING,
31 /* the given cap is acquired */
32 VBOXCAPS_ENTRY_ACSTATE_ACQUIRED
33} VBOXCAPS_ENTRY_ACSTATE;
34
35
36struct VBOXCAPS_ENTRY;
37struct VBOXCAPS;
38
39typedef DECLCALLBACKPTR(void, PFNVBOXCAPS_ENTRY_ON_ENABLE,(struct VBOXCAPS *pConsole, struct VBOXCAPS_ENTRY *pCap, BOOL fEnabled));
40
41typedef struct VBOXCAPS_ENTRY
42{
43 uint32_t fCap;
44 uint32_t iCap;
45 VBOXCAPS_ENTRY_FUNCSTATE enmFuncState;
46 VBOXCAPS_ENTRY_ACSTATE enmAcState;
47 PFNVBOXCAPS_ENTRY_ON_ENABLE pfnOnEnable;
48} VBOXCAPS_ENTRY;
49
50
51typedef struct VBOXCAPS
52{
53 UINT_PTR idTimer;
54 VBOXCAPS_ENTRY aCaps[VBOXCAPS_ENTRY_IDX_COUNT];
55} VBOXCAPS;
56
57static VBOXCAPS gVBoxCaps;
58
59
60/* we need to perform Acquire/Release using the file handled we use for rewuesting events from VBoxGuest
61 * otherwise Acquisition mechanism will treat us as different client and will not propagate necessary requests
62 * */
63int VBoxAcquireGuestCaps(uint32_t fOr, uint32_t fNot, bool fCfg)
64{
65 Log(("VBoxAcquireGuestCaps or(0x%x), not(0x%x), cfx(%d)\n", fOr, fNot, fCfg));
66 int rc = VbglR3AcquireGuestCaps(fOr, fNot, fCfg);
67 if (RT_FAILURE(rc))
68 LogFlowFunc(("VBOXGUEST_IOCTL_GUEST_CAPS_ACQUIRE failed: %Rrc\n", rc));
69 return rc;
70}
71
72static DECLCALLBACK(void) vboxCapsOnEnableSeamless(struct VBOXCAPS *pConsole, struct VBOXCAPS_ENTRY *pCap, BOOL fEnabled)
73{
74 RT_NOREF(pConsole, pCap);
75 if (fEnabled)
76 {
77 Log(("vboxCapsOnEnableSeamless: ENABLED\n"));
78 Assert(pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED);
79 Assert(pCap->enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED);
80 VBoxSeamlessEnable();
81 }
82 else
83 {
84 Log(("vboxCapsOnEnableSeamless: DISABLED\n"));
85 Assert(pCap->enmAcState != VBOXCAPS_ENTRY_ACSTATE_ACQUIRED || pCap->enmFuncState != VBOXCAPS_ENTRY_FUNCSTATE_STARTED);
86 VBoxSeamlessDisable();
87 }
88}
89
90static void vboxCapsEntryAcStateSet(VBOXCAPS_ENTRY *pCap, VBOXCAPS_ENTRY_ACSTATE enmAcState)
91{
92 VBOXCAPS *pConsole = &gVBoxCaps;
93
94 Log(("vboxCapsEntryAcStateSet: new state enmAcState(%d); pCap: fCap(%d), iCap(%d), enmFuncState(%d), enmAcState(%d)\n",
95 enmAcState, pCap->fCap, pCap->iCap, pCap->enmFuncState, pCap->enmAcState));
96
97 if (pCap->enmAcState == enmAcState)
98 return;
99
100 VBOXCAPS_ENTRY_ACSTATE enmOldAcState = pCap->enmAcState;
101 pCap->enmAcState = enmAcState;
102
103 if (enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED)
104 {
105 if (pCap->enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
106 {
107 if (pCap->pfnOnEnable)
108 pCap->pfnOnEnable(pConsole, pCap, TRUE);
109 }
110 }
111 else if (enmOldAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED && pCap->enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
112 {
113 if (pCap->pfnOnEnable)
114 pCap->pfnOnEnable(pConsole, pCap, FALSE);
115 }
116}
117
118static void vboxCapsEntryFuncStateSet(VBOXCAPS_ENTRY *pCap, VBOXCAPS_ENTRY_FUNCSTATE enmFuncState)
119{
120 VBOXCAPS *pConsole = &gVBoxCaps;
121
122 Log(("vboxCapsEntryFuncStateSet: new state enmAcState(%d); pCap: fCap(%d), iCap(%d), enmFuncState(%d), enmAcState(%d)\n",
123 enmFuncState, pCap->fCap, pCap->iCap, pCap->enmFuncState, pCap->enmAcState));
124
125 if (pCap->enmFuncState == enmFuncState)
126 return;
127
128 VBOXCAPS_ENTRY_FUNCSTATE enmOldFuncState = pCap->enmFuncState;
129
130 pCap->enmFuncState = enmFuncState;
131
132 if (enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
133 {
134 Assert(enmOldFuncState == VBOXCAPS_ENTRY_FUNCSTATE_SUPPORTED);
135 if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED)
136 {
137 if (pCap->pfnOnEnable)
138 pCap->pfnOnEnable(pConsole, pCap, TRUE);
139 }
140 }
141 else if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED && enmOldFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED)
142 {
143 if (pCap->pfnOnEnable)
144 pCap->pfnOnEnable(pConsole, pCap, FALSE);
145 }
146}
147
148void VBoxCapsEntryFuncStateSet(uint32_t iCup, VBOXCAPS_ENTRY_FUNCSTATE enmFuncState)
149{
150 VBOXCAPS *pConsole = &gVBoxCaps;
151 VBOXCAPS_ENTRY *pCap = &pConsole->aCaps[iCup];
152 vboxCapsEntryFuncStateSet(pCap, enmFuncState);
153}
154
155int VBoxCapsInit()
156{
157 VBOXCAPS *pConsole = &gVBoxCaps;
158 memset(pConsole, 0, sizeof (*pConsole));
159 pConsole->aCaps[VBOXCAPS_ENTRY_IDX_SEAMLESS].fCap = VMMDEV_GUEST_SUPPORTS_SEAMLESS;
160 pConsole->aCaps[VBOXCAPS_ENTRY_IDX_SEAMLESS].iCap = VBOXCAPS_ENTRY_IDX_SEAMLESS;
161 pConsole->aCaps[VBOXCAPS_ENTRY_IDX_SEAMLESS].pfnOnEnable = vboxCapsOnEnableSeamless;
162 pConsole->aCaps[VBOXCAPS_ENTRY_IDX_GRAPHICS].fCap = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
163 pConsole->aCaps[VBOXCAPS_ENTRY_IDX_GRAPHICS].iCap = VBOXCAPS_ENTRY_IDX_GRAPHICS;
164 return VINF_SUCCESS;
165}
166
167int VBoxCapsReleaseAll()
168{
169 VBOXCAPS *pConsole = &gVBoxCaps;
170 Log(("VBoxCapsReleaseAll\n"));
171 int rc = VBoxAcquireGuestCaps(0, VMMDEV_GUEST_SUPPORTS_SEAMLESS | VMMDEV_GUEST_SUPPORTS_GRAPHICS, false);
172 if (!RT_SUCCESS(rc))
173 {
174 LogFlowFunc(("vboxCapsEntryReleaseAll VBoxAcquireGuestCaps failed rc %d\n", rc));
175 return rc;
176 }
177
178 if (pConsole->idTimer)
179 {
180 Log(("killing console timer\n"));
181 KillTimer(g_hwndToolWindow, pConsole->idTimer);
182 pConsole->idTimer = 0;
183 }
184
185 for (int i = 0; i < RT_ELEMENTS(pConsole->aCaps); ++i)
186 {
187 vboxCapsEntryAcStateSet(&pConsole->aCaps[i], VBOXCAPS_ENTRY_ACSTATE_RELEASED);
188 }
189
190 return rc;
191}
192
193void VBoxCapsTerm()
194{
195 VBOXCAPS *pConsole = &gVBoxCaps;
196 VBoxCapsReleaseAll();
197 memset(pConsole, 0, sizeof (*pConsole));
198}
199
200BOOL VBoxCapsEntryIsAcquired(uint32_t iCap)
201{
202 VBOXCAPS *pConsole = &gVBoxCaps;
203 return pConsole->aCaps[iCap].enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED;
204}
205
206BOOL VBoxCapsEntryIsEnabled(uint32_t iCap)
207{
208 VBOXCAPS *pConsole = &gVBoxCaps;
209 return pConsole->aCaps[iCap].enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED
210 && pConsole->aCaps[iCap].enmFuncState == VBOXCAPS_ENTRY_FUNCSTATE_STARTED;
211}
212
213BOOL VBoxCapsCheckTimer(WPARAM wParam)
214{
215 VBOXCAPS *pConsole = &gVBoxCaps;
216 if (wParam != pConsole->idTimer)
217 return FALSE;
218
219 uint32_t u32AcquiredCaps = 0;
220 BOOL fNeedNewTimer = FALSE;
221
222 for (int i = 0; i < RT_ELEMENTS(pConsole->aCaps); ++i)
223 {
224 VBOXCAPS_ENTRY *pCap = &pConsole->aCaps[i];
225 if (pCap->enmAcState != VBOXCAPS_ENTRY_ACSTATE_ACQUIRING)
226 continue;
227
228 int rc = VBoxAcquireGuestCaps(pCap->fCap, 0, false);
229 if (RT_SUCCESS(rc))
230 {
231 vboxCapsEntryAcStateSet(&pConsole->aCaps[i], VBOXCAPS_ENTRY_ACSTATE_ACQUIRED);
232 u32AcquiredCaps |= pCap->fCap;
233 }
234 else
235 {
236 Assert(rc == VERR_RESOURCE_BUSY);
237 fNeedNewTimer = TRUE;
238 }
239 }
240
241 if (!fNeedNewTimer)
242 {
243 KillTimer(g_hwndToolWindow, pConsole->idTimer);
244 /* cleanup timer data */
245 pConsole->idTimer = 0;
246 }
247
248 return TRUE;
249}
250
251int VBoxCapsEntryRelease(uint32_t iCap)
252{
253 VBOXCAPS *pConsole = &gVBoxCaps;
254 VBOXCAPS_ENTRY *pCap = &pConsole->aCaps[iCap];
255 if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_RELEASED)
256 {
257 LogFlowFunc(("invalid cap[%d] state[%d] on release\n", iCap, pCap->enmAcState));
258 return VERR_INVALID_STATE;
259 }
260
261 if (pCap->enmAcState == VBOXCAPS_ENTRY_ACSTATE_ACQUIRED)
262 {
263 int rc = VBoxAcquireGuestCaps(0, pCap->fCap, false);
264 AssertRC(rc);
265 }
266
267 vboxCapsEntryAcStateSet(pCap, VBOXCAPS_ENTRY_ACSTATE_RELEASED);
268
269 return VINF_SUCCESS;
270}
271
272int VBoxCapsEntryAcquire(uint32_t iCap)
273{
274 VBOXCAPS *pConsole = &gVBoxCaps;
275 Assert(VBoxConsoleIsAllowed());
276 VBOXCAPS_ENTRY *pCap = &pConsole->aCaps[iCap];
277 Log(("VBoxCapsEntryAcquire %d\n", iCap));
278 if (pCap->enmAcState != VBOXCAPS_ENTRY_ACSTATE_RELEASED)
279 {
280 LogFlowFunc(("invalid cap[%d] state[%d] on acquire\n", iCap, pCap->enmAcState));
281 return VERR_INVALID_STATE;
282 }
283
284 vboxCapsEntryAcStateSet(pCap, VBOXCAPS_ENTRY_ACSTATE_ACQUIRING);
285 int rc = VBoxAcquireGuestCaps(pCap->fCap, 0, false);
286 if (RT_SUCCESS(rc))
287 {
288 vboxCapsEntryAcStateSet(pCap, VBOXCAPS_ENTRY_ACSTATE_ACQUIRED);
289 return VINF_SUCCESS;
290 }
291
292 if (rc != VERR_RESOURCE_BUSY)
293 {
294 LogFlowFunc(("vboxCapsEntryReleaseAll VBoxAcquireGuestCaps failed rc %d\n", rc));
295 return rc;
296 }
297
298 LogFlowFunc(("iCap %d is busy!\n", iCap));
299
300 /* the cap was busy, most likely it is still used by other VBoxTray instance running in another session,
301 * queue the retry timer */
302 if (!pConsole->idTimer)
303 {
304 pConsole->idTimer = SetTimer(g_hwndToolWindow, TIMERID_VBOXTRAY_CAPS_TIMER, 100, (TIMERPROC)NULL);
305 if (!pConsole->idTimer)
306 {
307 DWORD dwErr = GetLastError();
308 LogFlowFunc(("SetTimer error %08X\n", dwErr));
309 return RTErrConvertFromWin32(dwErr);
310 }
311 }
312
313 return rc;
314}
315
316int VBoxCapsAcquireAllSupported()
317{
318 VBOXCAPS *pConsole = &gVBoxCaps;
319 Log(("VBoxCapsAcquireAllSupported\n"));
320 for (int i = 0; i < RT_ELEMENTS(pConsole->aCaps); ++i)
321 {
322 if (pConsole->aCaps[i].enmFuncState >= VBOXCAPS_ENTRY_FUNCSTATE_SUPPORTED)
323 {
324 Log(("VBoxCapsAcquireAllSupported acquiring cap %d, state %d\n", i, pConsole->aCaps[i].enmFuncState));
325 VBoxCapsEntryAcquire(i);
326 }
327 else
328 {
329 LogFlowFunc(("VBoxCapsAcquireAllSupported: WARN: cap %d not supported, state %d\n", i, pConsole->aCaps[i].enmFuncState));
330 }
331 }
332 return VINF_SUCCESS;
333}
334
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette