VirtualBox

source: vbox/trunk/src/VBox/Debugger/VBoxDbgBase.cpp@ 103068

Last change on this file since 103068 was 101107, checked in by vboxsync, 15 months ago

VBoxDbg: Rewrote the automatic window positioning to make it more flexible and to try keep the console window wide enough for at least 80 columns of text.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 KB
Line 
1/* $Id: VBoxDbgBase.cpp 101107 2023-09-13 14:01:58Z vboxsync $ */
2/** @file
3 * VBox Debugger GUI - Base classes.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DBGG
33#include <iprt/errcore.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <limits.h>
37#include "VBoxDbgBase.h"
38#include "VBoxDbgGui.h"
39
40#include <QApplication>
41#include <QWidgetList>
42
43
44
45VBoxDbgBase::VBoxDbgBase(VBoxDbgGui *a_pDbgGui)
46 : m_pDbgGui(a_pDbgGui), m_pUVM(NULL), m_pVMM(NULL), m_hGUIThread(RTThreadNativeSelf())
47{
48 NOREF(m_pDbgGui); /* shut up warning. */
49
50 /*
51 * Register
52 */
53 m_pUVM = a_pDbgGui->getUvmHandle();
54 m_pVMM = a_pDbgGui->getVMMFunctionTable();
55 if (m_pUVM && m_pVMM)
56 {
57 m_pVMM->pfnVMR3RetainUVM(m_pUVM);
58
59 int rc = m_pVMM->pfnVMR3AtStateRegister(m_pUVM, atStateChange, this);
60 AssertRC(rc);
61 }
62}
63
64
65VBoxDbgBase::~VBoxDbgBase()
66{
67 /*
68 * If the VM is still around.
69 */
70 /** @todo need to do some locking here? */
71 PUVM pUVM = ASMAtomicXchgPtrT(&m_pUVM, NULL, PUVM);
72 PCVMMR3VTABLE pVMM = ASMAtomicXchgPtrT(&m_pVMM, NULL, PCVMMR3VTABLE);
73 if (pUVM && pVMM)
74 {
75 int rc = pVMM->pfnVMR3AtStateDeregister(pUVM, atStateChange, this);
76 AssertRC(rc);
77
78 pVMM->pfnVMR3ReleaseUVM(pUVM);
79 }
80}
81
82
83int
84VBoxDbgBase::stamReset(const QString &rPat)
85{
86 QByteArray Utf8Array = rPat.toUtf8();
87 const char *pszPat = !rPat.isEmpty() ? Utf8Array.constData() : NULL;
88 PUVM pUVM = m_pUVM;
89 PCVMMR3VTABLE pVMM = m_pVMM;
90 if ( pUVM
91 && pVMM
92 && pVMM->pfnVMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
93 return pVMM->pfnSTAMR3Reset(pUVM, pszPat);
94 return VERR_INVALID_HANDLE;
95}
96
97
98int
99VBoxDbgBase::stamEnum(const QString &rPat, PFNSTAMR3ENUM pfnEnum, void *pvUser)
100{
101 QByteArray Utf8Array = rPat.toUtf8();
102 const char *pszPat = !rPat.isEmpty() ? Utf8Array.constData() : NULL;
103 PUVM pUVM = m_pUVM;
104 PCVMMR3VTABLE pVMM = m_pVMM;
105 if ( pUVM
106 && pVMM
107 && pVMM->pfnVMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
108 return pVMM->pfnSTAMR3Enum(pUVM, pszPat, pfnEnum, pvUser);
109 return VERR_INVALID_HANDLE;
110}
111
112
113int
114VBoxDbgBase::dbgcCreate(PCDBGCIO pIo, unsigned fFlags)
115{
116 PUVM pUVM = m_pUVM;
117 PCVMMR3VTABLE pVMM = m_pVMM;
118 if ( pUVM
119 && pVMM
120 && pVMM->pfnVMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
121 return pVMM->pfnDBGCCreate(pUVM, pIo, fFlags);
122 return VERR_INVALID_HANDLE;
123}
124
125
126/*static*/ DECLCALLBACK(void)
127VBoxDbgBase::atStateChange(PUVM pUVM, PCVMMR3VTABLE pVMM, VMSTATE enmState, VMSTATE /*enmOldState*/, void *pvUser)
128{
129 VBoxDbgBase *pThis = (VBoxDbgBase *)pvUser; NOREF(pUVM);
130 switch (enmState)
131 {
132 case VMSTATE_TERMINATED:
133 {
134 /** @todo need to do some locking here? */
135 PUVM pUVM2 = ASMAtomicXchgPtrT(&pThis->m_pUVM, NULL, PUVM);
136 PCVMMR3VTABLE pVMM2 = ASMAtomicXchgPtrT(&pThis->m_pVMM, NULL, PCVMMR3VTABLE);
137 if (pUVM2 && pVMM2)
138 {
139 Assert(pUVM2 == pUVM);
140 Assert(pVMM2 == pVMM);
141 pThis->sigTerminated();
142 pVMM->pfnVMR3ReleaseUVM(pUVM2);
143 }
144 break;
145 }
146
147 case VMSTATE_DESTROYING:
148 pThis->sigDestroying();
149 break;
150
151 default:
152 break;
153 }
154 RT_NOREF(pVMM);
155}
156
157
158void
159VBoxDbgBase::sigDestroying()
160{
161}
162
163
164void
165VBoxDbgBase::sigTerminated()
166{
167}
168
169
170
171
172//
173//
174//
175// V B o x D b g B a s e W i n d o w
176// V B o x D b g B a s e W i n d o w
177// V B o x D b g B a s e W i n d o w
178//
179//
180//
181
182unsigned VBoxDbgBaseWindow::m_cxBorder = 0;
183unsigned VBoxDbgBaseWindow::m_cyBorder = 0;
184
185
186VBoxDbgBaseWindow::VBoxDbgBaseWindow(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent, const char *a_pszTitle)
187 : QWidget(a_pParent, Qt::Window), VBoxDbgBase(a_pDbgGui), m_pszTitle(a_pszTitle), m_fPolished(false)
188 , m_x(INT_MAX), m_y(INT_MAX), m_cx(0), m_cy(0), m_cxMinHint(0), m_enmAttraction(VBoxDbgBaseWindow::kAttractionVmNone)
189{
190 /* Set the title, using the parent one as prefix when possible: */
191 if (!parent())
192 {
193 QString strMachineName = a_pDbgGui->getMachineName();
194 if (strMachineName.isEmpty())
195 setWindowTitle(QString("VBoxDbg - %1").arg(m_pszTitle));
196 else
197 setWindowTitle(QString("%1 - VBoxDbg - %2").arg(strMachineName).arg(m_pszTitle));
198 }
199 else
200 {
201 setWindowTitle(QString("%1 - %2").arg(parentWidget()->windowTitle()).arg(m_pszTitle));
202
203 /* Install an event filter so we can make adjustments when the parent title changes: */
204 parent()->installEventFilter(this);
205 }
206}
207
208
209VBoxDbgBaseWindow::~VBoxDbgBaseWindow()
210{
211
212}
213
214
215void
216VBoxDbgBaseWindow::vShow()
217{
218 show();
219 /** @todo this ain't working right. HELP! */
220 setWindowState(windowState() & ~Qt::WindowMinimized);
221 //activateWindow();
222 //setFocus();
223 vPolishSizeAndPos();
224}
225
226
227void
228VBoxDbgBaseWindow::vReposition(int a_x, int a_y, unsigned a_cx, unsigned a_cy, bool a_fResize)
229{
230 /* Don't modify if maximized.
231 We miss the desired size + position here, but never mind for now. */
232 if (!(windowState() & Qt::WindowMaximized))
233 {
234 if (a_fResize)
235 {
236 m_cx = a_cx;
237 m_cy = a_cy;
238
239 QSize const BorderSize = vGetBorderSize();
240 resize(a_cx - BorderSize.width(), a_cy - BorderSize.height());
241 }
242
243 m_x = a_x;
244 m_y = a_y;
245 move(a_x, a_y);
246 }
247}
248
249
250QSize
251VBoxDbgBaseWindow::vGetBorderSize()
252{
253 QSize BorderSize = frameSize() - size();
254
255#ifdef Q_WS_X11 /* (from the qt gui) */
256 /*
257 * On X11, there is no way to determine frame geometry (including WM
258 * decorations) before the widget is shown for the first time. Stupidly
259 * enumerate other top level widgets to find the thickest frame.
260 */
261 if (BorderSize == QSize(0, 0))
262 {
263 if (!m_cxBorder && !m_cyBorder) /* (only till we're successful) */
264 {
265 int cxExtra = 0;
266 int cyExtra = 0;
267
268 QWidgetList WidgetList = QApplication::topLevelWidgets();
269 for (QListIterator<QWidget *> it(WidgetList); it.hasNext(); )
270 {
271 QWidget *pCurWidget = it.next();
272 if (pCurWidget->isVisible())
273 {
274 int const cxFrame = pCurWidget->frameGeometry().width() - pCurWidget->width();
275 cxExtra = qMax(cxExtra, cxFrame);
276 int const cyFrame = pCurWidget->frameGeometry().height() - pCurWidget->height();
277 cyExtra = qMax(cyExtra, cyFrame);
278 if (cyExtra && cxExtra)
279 break;
280 }
281 }
282
283 if (cxExtra || cyExtra)
284 {
285 m_cxBorder = cxExtra;
286 m_cyBorder = cyExtra;
287 }
288 }
289 BorderSize.setWidth(m_cxBorder);
290 BorderSize.setHeight(m_cyBorder);
291 }
292#endif /* X11 */
293
294 return BorderSize;
295}
296
297
298bool
299VBoxDbgBaseWindow::event(QEvent *a_pEvt)
300{
301 bool fRc = QWidget::event(a_pEvt);
302 if ( a_pEvt->type() == QEvent::Paint
303 || a_pEvt->type() == QEvent::UpdateRequest
304 || a_pEvt->type() == QEvent::LayoutRequest) /** @todo Someone with Qt knowledge should figure out how to properly do this. */
305 vPolishSizeAndPos();
306 return fRc;
307}
308
309
310bool VBoxDbgBaseWindow::eventFilter(QObject *pWatched, QEvent *pEvent)
311{
312 /* We're only interested in title changes to the parent so we can amend our own title: */
313 if ( pWatched == parent()
314 && pEvent->type() == QEvent::WindowTitleChange)
315 setWindowTitle(QString("%1 - %2").arg(parentWidget()->windowTitle()).arg(m_pszTitle));
316
317 /* Forward to base-class: */
318 return QWidget::eventFilter(pWatched, pEvent);
319}
320
321
322void
323VBoxDbgBaseWindow::vPolishSizeAndPos()
324{
325 /* Ignore if already done or no size set. */
326 if ( m_fPolished
327 || (m_x == INT_MAX && m_y == INT_MAX))
328 return;
329
330 if (!m_fPolished && VBoxDbgBaseWindow::vGetBorderSize() != QSize(0,0))
331 m_fPolished = true;
332
333 vReposition(m_x, m_y, m_cx, m_cy, m_cx || m_cy);
334}
335
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