VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/RecordingSettingsImpl.cpp@ 95918

Last change on this file since 95918 was 95918, checked in by vboxsync, 3 years ago

Recording/Main: Integrated r152624 from 6.1 into trunk (More code for per-screen settings. ​As we always want to have screen 0 enabled by default (if not explicitly set otherwise), the per-screen settings need to know which screen ID it's assigned to, to treat the defaults right). bugref:9286

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.3 KB
Line 
1/* $Id: RecordingSettingsImpl.cpp 95918 2022-07-28 14:56:13Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox COM class implementation - Machine capture settings.
5 */
6
7/*
8 * Copyright (C) 2018-2022 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#define LOG_GROUP LOG_GROUP_MAIN_RECORDINGSETTINGS
20#include "LoggingNew.h"
21
22#include "RecordingSettingsImpl.h"
23#include "RecordingScreenSettingsImpl.h"
24#include "MachineImpl.h"
25
26#include <iprt/cpp/utils.h>
27#include <VBox/settings.h>
28
29#include "AutoStateDep.h"
30#include "AutoCaller.h"
31#include "Global.h"
32
33////////////////////////////////////////////////////////////////////////////////
34//
35// RecordSettings private data definition
36//
37////////////////////////////////////////////////////////////////////////////////
38
39struct RecordingSettings::Data
40{
41 Data()
42 : pMachine(NULL)
43 { }
44
45 Machine * const pMachine;
46 const ComObjPtr<RecordingSettings> pPeer;
47 RecordingScreenSettingsObjMap mapScreenObj;
48
49 // use the XML settings structure in the members for simplicity
50 Backupable<settings::RecordingCommonSettings> bd;
51};
52
53DEFINE_EMPTY_CTOR_DTOR(RecordingSettings)
54
55HRESULT RecordingSettings::FinalConstruct()
56{
57 return BaseFinalConstruct();
58}
59
60void RecordingSettings::FinalRelease()
61{
62 uninit();
63 BaseFinalRelease();
64}
65
66/**
67 * Initializes the recording settings object.
68 *
69 * @returns COM result indicator
70 */
71HRESULT RecordingSettings::init(Machine *aParent)
72{
73 LogFlowThisFuncEnter();
74 LogFlowThisFunc(("aParent: %p\n", aParent));
75
76 ComAssertRet(aParent, E_INVALIDARG);
77
78 /* Enclose the state transition NotReady->InInit->Ready */
79 AutoInitSpan autoInitSpan(this);
80 AssertReturn(autoInitSpan.isOk(), E_FAIL);
81
82 m = new Data();
83
84 /* share the parent weakly */
85 unconst(m->pMachine) = aParent;
86
87 m->bd.allocate();
88
89 i_applyDefaults();
90
91 autoInitSpan.setSucceeded();
92
93 LogFlowThisFuncLeave();
94 return S_OK;
95}
96
97/**
98 * Initializes the capture settings object given another capture settings object
99 * (a kind of copy constructor). This object shares data with
100 * the object passed as an argument.
101 *
102 * @note This object must be destroyed before the original object
103 * it shares data with is destroyed.
104 *
105 * @note Locks @a aThat object for reading.
106 */
107HRESULT RecordingSettings::init(Machine *aParent, RecordingSettings *aThat)
108{
109 LogFlowThisFuncEnter();
110 LogFlowThisFunc(("aParent: %p, aThat: %p\n", aParent, aThat));
111
112 ComAssertRet(aParent && aThat, E_INVALIDARG);
113
114 /* Enclose the state transition NotReady->InInit->Ready */
115 AutoInitSpan autoInitSpan(this);
116 AssertReturn(autoInitSpan.isOk(), E_FAIL);
117
118 m = new Data();
119
120 unconst(m->pMachine) = aParent;
121 unconst(m->pPeer) = aThat;
122
123 AutoCaller thatCaller(aThat);
124 AssertComRCReturnRC(thatCaller.rc());
125
126 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
127
128 m->bd.share(aThat->m->bd);
129
130 /* Make sure to add a reference when sharing the screen objects with aThat. */
131 for (RecordingScreenSettingsObjMap::const_iterator itScreenThat = aThat->m->mapScreenObj.begin();
132 itScreenThat != aThat->m->mapScreenObj.end();
133 ++itScreenThat)
134 itScreenThat->second->i_reference();
135
136 m->mapScreenObj = aThat->m->mapScreenObj;
137
138 autoInitSpan.setSucceeded();
139
140 LogFlowThisFuncLeave();
141 return S_OK;
142}
143
144/**
145 * Initializes the guest object given another guest object
146 * (a kind of copy constructor). This object makes a private copy of data
147 * of the original object passed as an argument.
148 *
149 * @note Locks @a aThat object for reading.
150 */
151HRESULT RecordingSettings::initCopy(Machine *aParent, RecordingSettings *aThat)
152{
153 LogFlowThisFuncEnter();
154 LogFlowThisFunc(("aParent: %p, aThat: %p\n", aParent, aThat));
155
156 ComAssertRet(aParent && aThat, E_INVALIDARG);
157
158 /* Enclose the state transition NotReady->InInit->Ready */
159 AutoInitSpan autoInitSpan(this);
160 AssertReturn(autoInitSpan.isOk(), E_FAIL);
161
162 m = new Data();
163
164 unconst(m->pMachine) = aParent;
165 // mPeer is left null
166
167 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
168 m->bd.attachCopy(aThat->m->bd);
169
170 HRESULT hrc = S_OK;
171
172 for (RecordingScreenSettingsObjMap::const_iterator itScreenThat = aThat->m->mapScreenObj.begin();
173 itScreenThat != aThat->m->mapScreenObj.end();
174 ++itScreenThat)
175 {
176 ComObjPtr<RecordingScreenSettings> pSettings;
177 pSettings.createObject();
178 hrc = pSettings->initCopy(this, itScreenThat->second);
179 if (FAILED(hrc)) return hrc;
180
181 try
182 {
183 m->mapScreenObj[itScreenThat->first] = pSettings;
184 }
185 catch (...)
186 {
187 hrc = E_OUTOFMEMORY;
188 }
189 }
190
191 if (SUCCEEDED(hrc))
192 autoInitSpan.setSucceeded();
193
194 LogFlowThisFuncLeave();
195 return hrc;
196}
197
198/**
199 * Uninitializes the instance and sets the ready flag to FALSE.
200 * Called either from FinalRelease() or by the parent when it gets destroyed.
201 */
202void RecordingSettings::uninit()
203{
204 LogFlowThisFuncEnter();
205
206 /* Enclose the state transition Ready->InUninit->NotReady */
207 AutoUninitSpan autoUninitSpan(this);
208 if (autoUninitSpan.uninitDone())
209 return;
210
211 /* Make sure to destroy screen objects attached to this object.
212 * Note: This also decrements the refcount of a screens object, in case it's shared among other recording settings. */
213 i_destroyAllScreenObj(m->mapScreenObj);
214
215 m->bd.free();
216
217 unconst(m->pPeer) = NULL;
218 unconst(m->pMachine) = NULL;
219
220 delete m;
221 m = NULL;
222
223 LogFlowThisFuncLeave();
224}
225
226// IRecordSettings properties
227/////////////////////////////////////////////////////////////////////////////
228
229HRESULT RecordingSettings::getEnabled(BOOL *enabled)
230{
231 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
232
233 *enabled = m->bd->fEnabled;
234
235 return S_OK;
236}
237
238HRESULT RecordingSettings::setEnabled(BOOL enable)
239{
240 /* the machine needs to be mutable */
241 AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
242 if (FAILED(adep.rc())) return adep.rc();
243
244 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
245
246 const bool fEnabled = RT_BOOL(enable);
247
248 HRESULT rc = S_OK;
249
250 if (m->bd->fEnabled != fEnabled)
251 {
252 m->bd.backup();
253 m->bd->fEnabled = fEnabled;
254
255 alock.release();
256
257 rc = m->pMachine->i_onRecordingChange(enable);
258 if (FAILED(rc))
259 {
260 /*
261 * Normally we would do the actual change _after_ i_onRecordingChange() succeeded.
262 * We cannot do this because that function uses RecordSettings::GetEnabled to
263 * determine if it should start or stop capturing. Therefore we need to manually
264 * undo change.
265 */
266 alock.acquire();
267 m->bd->fEnabled = m->bd.backedUpData()->fEnabled;
268 }
269 else
270 {
271 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS); // pMachine is const, needs no locking
272 m->pMachine->i_setModified(Machine::IsModified_Recording);
273
274 /* Make sure to release the mutable dependency lock from above before
275 * actually saving the settings. */
276 adep.release();
277
278 /** Save settings if online - @todo why is this required? -- @bugref{6818} */
279 if (Global::IsOnline(m->pMachine->i_getMachineState()))
280 rc = m->pMachine->i_saveSettings(NULL, mlock);
281 }
282 }
283
284 return rc;
285}
286
287HRESULT RecordingSettings::getScreens(std::vector<ComPtr<IRecordingScreenSettings> > &aRecordScreenSettings)
288{
289 LogFlowThisFuncEnter();
290
291 AssertPtr(m->pMachine);
292 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
293 m->pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam());
294 ULONG cMonitors = 0;
295 if (!pGraphicsAdapter.isNull())
296 pGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitors);
297
298 i_syncToMachineDisplays(cMonitors);
299
300 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
301
302 HRESULT hrc = S_OK;
303
304 try
305 {
306 aRecordScreenSettings.clear();
307 aRecordScreenSettings.resize(m->mapScreenObj.size());
308 }
309 catch (...)
310 {
311 hrc = E_OUTOFMEMORY;
312 }
313
314 if (FAILED(hrc))
315 return hrc;
316
317 RecordingScreenSettingsObjMap::const_iterator itScreenObj = m->mapScreenObj.begin();
318 size_t i = 0;
319 while (itScreenObj != m->mapScreenObj.end())
320 {
321 itScreenObj->second.queryInterfaceTo(aRecordScreenSettings[i].asOutParam());
322 AssertBreakStmt(aRecordScreenSettings[i].isNotNull(), hrc = E_POINTER);
323 ++i;
324 ++itScreenObj;
325 }
326
327 Assert(aRecordScreenSettings.size() == m->mapScreenObj.size());
328
329 return hrc;
330}
331
332HRESULT RecordingSettings::getScreenSettings(ULONG uScreenId, ComPtr<IRecordingScreenSettings> &aRecordScreenSettings)
333{
334 LogFlowThisFuncEnter();
335
336 AssertPtr(m->pMachine);
337 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
338 m->pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam());
339 ULONG cMonitors = 0;
340 if (!pGraphicsAdapter.isNull())
341 pGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitors);
342
343 i_syncToMachineDisplays(cMonitors);
344
345 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
346
347 if (uScreenId + 1 > m->mapScreenObj.size())
348 return setError(E_INVALIDARG, tr("Invalid screen ID specified"));
349
350 RecordingScreenSettingsObjMap::const_iterator itScreen = m->mapScreenObj.find(uScreenId);
351 if (itScreen != m->mapScreenObj.end())
352 {
353 itScreen->second.queryInterfaceTo(aRecordScreenSettings.asOutParam());
354 return S_OK;
355 }
356
357 return VBOX_E_OBJECT_NOT_FOUND;
358}
359
360// IRecordSettings methods
361/////////////////////////////////////////////////////////////////////////////
362
363// public methods only for internal purposes
364/////////////////////////////////////////////////////////////////////////////
365
366/**
367 * Adds a screen settings object to a particular map.
368 *
369 * @returns IPRT status code. VERR_ALREADY_EXISTS if the object in question already exists.
370 * @param screenSettingsMap Map to add screen settings to.
371 * @param idScreen Screen ID to add settings for.
372 * @param data Recording screen settings to use for that screen.
373 */
374int RecordingSettings::i_createScreenObj(RecordingScreenSettingsObjMap &screenSettingsMap,
375 uint32_t idScreen, const settings::RecordingScreenSettings &data)
376{
377 AssertReturn(screenSettingsMap.find(idScreen) == screenSettingsMap.end(), VERR_ALREADY_EXISTS);
378
379 int vrc = VINF_SUCCESS;
380
381 ComObjPtr<RecordingScreenSettings> recordingScreenSettings;
382 HRESULT hrc = recordingScreenSettings.createObject();
383 if (SUCCEEDED(hrc))
384 {
385 hrc = recordingScreenSettings->init(this, idScreen, data);
386 if (SUCCEEDED(hrc))
387 {
388 try
389 {
390 screenSettingsMap[idScreen] = recordingScreenSettings;
391 }
392 catch (std::bad_alloc &)
393 {
394 vrc = VERR_NO_MEMORY;
395 }
396 }
397 }
398
399 LogThisFunc(("%p: Screen %RU32 -> %Rrc\n", recordingScreenSettings.m_p, idScreen, vrc));
400 return vrc;
401}
402
403/**
404 * Removes a screen settings object from a particular map.
405 *
406 * If the internal reference count hits 0, the screen settings object will be destroyed.
407 * This means that this screen settings object is not being used anymore by other recording settings (as shared data).
408 *
409 * @returns IPRT status code.
410 * @retval VERR_NOT_FOUND if specified screen was not found.
411 * @param screenSettingsMap Map to remove screen settings from.
412 * @param idScreen ID of screen to remove.
413 */
414int RecordingSettings::i_destroyScreenObj(RecordingScreenSettingsObjMap &screenSettingsMap, uint32_t idScreen)
415{
416 AssertReturn(screenSettingsMap.find(idScreen) != screenSettingsMap.end(), VERR_NOT_FOUND);
417
418 RecordingScreenSettingsObjMap::iterator itScreen = screenSettingsMap.find(idScreen);
419
420 /* Make sure to consume the pointer before the one of the
421 * iterator gets released. */
422 ComObjPtr<RecordingScreenSettings> pScreenSettings = itScreen->second;
423
424 screenSettingsMap.erase(itScreen);
425
426 LogThisFunc(("%p: Screen %RU32, cRefs=%RI32\n", pScreenSettings.m_p, idScreen, pScreenSettings->i_getReferences()));
427
428 pScreenSettings->i_release();
429
430 /* Only destroy the object if nobody else keeps a reference to it anymore. */
431 if (pScreenSettings->i_getReferences() == 0)
432 {
433 LogThisFunc(("%p: Screen %RU32 -> Null\n", pScreenSettings.m_p, idScreen));
434 pScreenSettings.setNull();
435 }
436
437 return VINF_SUCCESS;
438}
439
440/**
441 * Destroys all screen settings objects of a particular map.
442 *
443 * @returns IPRT status code.
444 * @param screenSettingsMap Map to destroy screen settings objects for.
445 */
446int RecordingSettings::i_destroyAllScreenObj(RecordingScreenSettingsObjMap &screenSettingsMap)
447{
448 LogFlowThisFuncEnter();
449
450 int vrc = VINF_SUCCESS;
451
452 RecordingScreenSettingsObjMap::iterator itScreen = screenSettingsMap.begin();
453 while (itScreen != screenSettingsMap.end())
454 {
455 vrc = i_destroyScreenObj(screenSettingsMap, itScreen->first);
456 if (RT_FAILURE(vrc))
457 break;
458
459 itScreen = screenSettingsMap.begin();
460 }
461
462 Assert(screenSettingsMap.size() == 0);
463 return vrc;
464}
465
466/**
467 * Loads settings from the given settings.
468 * May be called once right after this object creation.
469 *
470 * @param data Capture settings to load from.
471 *
472 * @note Locks this object for writing.
473 */
474HRESULT RecordingSettings::i_loadSettings(const settings::RecordingSettings &data)
475{
476 LogFlowThisFuncEnter();
477
478 AutoCaller autoCaller(this);
479 AssertComRCReturnRC(autoCaller.rc());
480
481 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
482
483 HRESULT hrc = S_OK;
484
485 LogFlowThisFunc(("Data has %zu screens\n", data.mapScreens.size()));
486
487 settings::RecordingScreenSettingsMap::const_iterator itScreenData = data.mapScreens.begin();
488 while (itScreenData != data.mapScreens.end())
489 {
490 RecordingScreenSettingsObjMap::iterator itScreen = m->mapScreenObj.find(itScreenData->first);
491 if (itScreen != m->mapScreenObj.end())
492 {
493 hrc = itScreen->second->i_loadSettings(itScreenData->second);
494 if (FAILED(hrc))
495 break;
496 }
497 else
498 {
499 int vrc = i_createScreenObj(m->mapScreenObj,
500 itScreenData->first /* uScreenId */, itScreenData->second /* Settings */);
501 if (RT_FAILURE(vrc))
502 {
503 hrc = E_OUTOFMEMORY; /* Most likely. */
504 break;
505 }
506 }
507
508 ++itScreenData;
509 }
510
511 if (SUCCEEDED(hrc))
512 {
513 ComAssertComRCRet(hrc, hrc);
514 AssertReturn(m->mapScreenObj.size() == data.mapScreens.size(), E_UNEXPECTED);
515
516 // simply copy
517 m->bd.assignCopy(&data.common);
518 }
519
520 LogFlowThisFunc(("Returning %Rhrc\n", hrc));
521 return hrc;
522}
523
524/**
525 * Resets the internal object state by destroying all screen settings objects.
526 */
527void RecordingSettings::i_reset(void)
528{
529 LogFlowThisFuncEnter();
530
531 i_destroyAllScreenObj(m->mapScreenObj);
532}
533
534/**
535 * Saves settings to the given settings.
536 *
537 * @param data Where to store the capture settings to.
538 *
539 * @note Locks this object for reading.
540 */
541HRESULT RecordingSettings::i_saveSettings(settings::RecordingSettings &data)
542{
543 LogFlowThisFuncEnter();
544
545 AutoCaller autoCaller(this);
546 AssertComRCReturnRC(autoCaller.rc());
547
548 AssertPtr(m->pMachine);
549 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
550 m->pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam());
551 ULONG cMonitors = 0;
552 if (!pGraphicsAdapter.isNull())
553 pGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitors);
554
555 int rc2 = i_syncToMachineDisplays(cMonitors);
556 AssertRC(rc2);
557
558 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
559
560 data.common = *m->bd.data();
561
562 HRESULT hrc = S_OK;
563
564 for (RecordingScreenSettingsObjMap::const_iterator itScreen = m->mapScreenObj.begin();
565 itScreen != m->mapScreenObj.end();
566 ++itScreen)
567 {
568 hrc = itScreen->second->i_saveSettings(data.mapScreens[itScreen->first /* Screen ID */]);
569 if (FAILED(hrc))
570 break;
571 }
572
573 LogFlowThisFuncLeave();
574 return hrc;
575}
576
577void RecordingSettings::i_rollback(void)
578{
579 /* sanity */
580 AutoCaller autoCaller(this);
581 AssertComRCReturnVoid(autoCaller.rc());
582
583 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
584
585 m->bd.rollback();
586
587 for (RecordingScreenSettingsObjMap::const_iterator itScreen = m->mapScreenObj.begin();
588 itScreen != m->mapScreenObj.end();
589 ++itScreen)
590 {
591 itScreen->second->i_rollback();
592 }
593}
594
595void RecordingSettings::i_commit(void)
596{
597 /* sanity */
598 AutoCaller autoCaller(this);
599 AssertComRCReturnVoid(autoCaller.rc());
600
601 /* sanity too */
602 AutoCaller peerCaller(m->pPeer);
603 AssertComRCReturnVoid(peerCaller.rc());
604
605 /* lock both for writing since we modify both (mPeer is "master" so locked
606 * first) */
607 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
608
609 if (m->bd.isBackedUp())
610 {
611 m->bd.commit();
612 if (m->pPeer)
613 {
614 /* attach new data to the peer and reshare it */
615 m->pPeer->m->bd.attach(m->bd);
616 }
617
618 for (RecordingScreenSettingsObjMap::const_iterator itScreenObj = m->mapScreenObj.begin();
619 itScreenObj != m->mapScreenObj.end();
620 ++itScreenObj)
621 {
622 itScreenObj->second->i_commit();
623 if (m->pPeer)
624 m->pPeer->i_commit();
625 }
626 }
627}
628
629HRESULT RecordingSettings::i_copyFrom(RecordingSettings *aThat)
630{
631 AssertPtrReturn(aThat, E_INVALIDARG);
632
633 /* sanity */
634 AutoCaller autoCaller(this);
635 AssertComRCReturn(autoCaller.rc(), VBOX_E_INVALID_OBJECT_STATE);
636
637 /* sanity too */
638 AutoCaller thatCaller(aThat);
639 AssertComRCReturn(thatCaller.rc(), VBOX_E_INVALID_OBJECT_STATE);
640
641 /* peer is not modified, lock it for reading (aThat is "master" so locked
642 * first) */
643 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
644 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
645
646 /* this will back up current data */
647 m->bd.assignCopy(aThat->m->bd);
648
649 HRESULT hrc = S_OK;
650
651 for (RecordingScreenSettingsObjMap::const_iterator itScreenThat = aThat->m->mapScreenObj.begin();
652 itScreenThat != aThat->m->mapScreenObj.end();
653 ++itScreenThat)
654 {
655 RecordingScreenSettingsObjMap::iterator itScreen = m->mapScreenObj.find(itScreenThat->first);
656 if (itScreen != m->mapScreenObj.end())
657 {
658 itScreen->second->i_copyFrom(itScreenThat->second);
659 }
660 else
661 {
662 int vrc = i_createScreenObj(m->mapScreenObj,
663 itScreenThat->first /* uScreenId */, itScreenThat->second->i_getData() /* Settings */);
664 if (RT_FAILURE(vrc))
665 {
666 hrc = E_OUTOFMEMORY; /* Most likely. */
667 break;
668 }
669 }
670 }
671
672 return hrc;
673}
674
675void RecordingSettings::i_applyDefaults(void)
676{
677 /* sanity */
678 AutoCaller autoCaller(this);
679 AssertComRCReturnVoid(autoCaller.rc());
680
681 AssertPtr(m->pMachine);
682 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
683 m->pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam());
684 ULONG cMonitors = 0;
685 if (!pGraphicsAdapter.isNull())
686 pGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitors);
687
688 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
689
690 /* Initialize default capturing settings here. */
691 m->bd->fEnabled = false;
692
693 /* First, do a reset so that all internal screen settings objects are destroyed. */
694 i_reset();
695 /* Second, sync (again) to configured machine displays to (re-)create screen settings objects. */
696 i_syncToMachineDisplays(cMonitors);
697}
698
699/**
700 * Returns the full path to the default recording file.
701 */
702int RecordingSettings::i_getDefaultFilename(Utf8Str &strFile, uint32_t idScreen, bool fWithFileExtension)
703{
704 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
705
706 strFile = m->pMachine->i_getSettingsFileFull(); // path/to/machinesfolder/vmname/vmname.vbox
707 strFile.stripSuffix();
708 strFile.append(Utf8StrFmt("-screen%RU32", idScreen));
709 if (fWithFileExtension)
710 strFile.append(".webm");
711
712 return VINF_SUCCESS;
713}
714
715/**
716 * Determines whether the recording settings currently can be changed or not.
717 *
718 * @returns \c true if the settings can be changed, \c false if not.
719 */
720bool RecordingSettings::i_canChangeSettings(void)
721{
722 AutoAnyStateDependency adep(m->pMachine);
723 if (FAILED(adep.rc()))
724 return false;
725
726 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
727
728 /* Only allow settings to be changed when recording is disabled when the machine is running. */
729 if ( Global::IsOnline(adep.machineState())
730 && m->bd->fEnabled)
731 {
732 return false;
733 }
734
735 return true;
736}
737
738/**
739 * Gets called when the machine object needs to know that the recording settings
740 * have been changed.
741 */
742void RecordingSettings::i_onSettingsChanged(void)
743{
744 LogFlowThisFuncEnter();
745
746 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
747 m->pMachine->i_setModified(Machine::IsModified_Recording);
748 mlock.release();
749
750 LogFlowThisFuncLeave();
751}
752
753/**
754 * Synchronizes the screen settings (COM) objects and configuration data
755 * to the number of the machine's configured displays.
756 *
757 * Note: This function ASSUMES that we always have configured VM displays
758 * as a consequtive sequence with no holes in between.
759 */
760int RecordingSettings::i_syncToMachineDisplays(uint32_t cDisplays)
761{
762 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
763
764 LogThisFunc(("%p: cDisplays=%RU32 vs. %zu\n", this, cDisplays, m->mapScreenObj.size()));
765
766 /* If counts match, take a shortcut. */
767 if (cDisplays == m->mapScreenObj.size())
768 return VINF_SUCCESS;
769
770 /* Create all new screen settings objects which are not there yet. */
771 for (ULONG i = 0; i < cDisplays; i++)
772 {
773 if (m->mapScreenObj.find(i) == m->mapScreenObj.end())
774 {
775 settings::RecordingScreenSettings defaultScreenSettings(i /* Screen ID */); /* Apply default settings. */
776
777 int vrc2 = i_createScreenObj(m->mapScreenObj, i /* Screen ID */, defaultScreenSettings);
778 AssertRC(vrc2);
779 }
780 }
781
782 /* Remove all left over screen settings objects which are not needed anymore. */
783 for (ULONG i = cDisplays; i < (ULONG)m->mapScreenObj.size(); i++)
784 {
785 int vrc2 = i_destroyScreenObj(m->mapScreenObj, i /* Screen ID */);
786 AssertRC(vrc2);
787 }
788
789 Assert(m->mapScreenObj.size() == cDisplays);
790
791 LogFlowThisFuncLeave();
792 return VINF_SUCCESS;
793}
794
Note: See TracBrowser for help on using the repository browser.

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