VirtualBox

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

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

Recording: Settings handling fixes / overhaul. This adds the ability to handle per-screen settings, which can be different from the first screen (screen 0). Also fixed a couple of bugs regarding snapshot handling and persistence (committing, rolling back, ++) in that area. FE/VBoxManage now can also list the per-screen settings. Added some further @todos. bugref:9286

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

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