mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-23 10:22:52 +00:00
kemu: move from kde-playground
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
35abd48879
commit
2e624b94dc
8 changed files with 886 additions and 0 deletions
|
@ -38,6 +38,7 @@ macro_optional_add_subdirectory(kdeplasma-addons)
|
||||||
macro_optional_add_subdirectory(lokalize)
|
macro_optional_add_subdirectory(lokalize)
|
||||||
macro_optional_add_subdirectory(libksane)
|
macro_optional_add_subdirectory(libksane)
|
||||||
macro_optional_add_subdirectory(kcolorchooser)
|
macro_optional_add_subdirectory(kcolorchooser)
|
||||||
|
macro_optional_add_subdirectory(kemu)
|
||||||
macro_optional_add_subdirectory(kfloppy)
|
macro_optional_add_subdirectory(kfloppy)
|
||||||
macro_optional_add_subdirectory(kgpg)
|
macro_optional_add_subdirectory(kgpg)
|
||||||
macro_optional_add_subdirectory(kmix)
|
macro_optional_add_subdirectory(kmix)
|
||||||
|
|
20
kemu/CMakeLists.txt
Normal file
20
kemu/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
project(kemu)
|
||||||
|
|
||||||
|
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
find_package(KDE4 4.19.0 REQUIRED)
|
||||||
|
include(KDE4Defaults)
|
||||||
|
include_directories(${KDE4_INCLUDES})
|
||||||
|
add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(kemu_sources
|
||||||
|
main.cpp
|
||||||
|
kemumainwindow.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(kemu ${kemu_sources})
|
||||||
|
target_link_libraries(kemu ${KDE4_KDEUI_LIBS} ${KDE4_KFILE_LIBS})
|
||||||
|
|
||||||
|
install(TARGETS kemu DESTINATION ${KDE4_BIN_INSTALL_DIR})
|
||||||
|
install(FILES kemuui.rc DESTINATION ${KDE4_DATA_INSTALL_DIR}/kemu)
|
||||||
|
install(PROGRAMS kemu.desktop DESTINATION ${KDE4_XDG_APPS_INSTALL_DIR})
|
9
kemu/kemu.desktop
Normal file
9
kemu/kemu.desktop
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Icon=applications-engineering
|
||||||
|
Name=KEmu
|
||||||
|
GenericName=KEmu
|
||||||
|
Comment=Simple QEMU frontend for KDE
|
||||||
|
Exec=kemu --icon '%i' --caption '%c' %U
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Qt;KDE;
|
327
kemu/kemu.ui
Normal file
327
kemu/kemu.ui
Normal file
|
@ -0,0 +1,327 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>KEmuWindow</class>
|
||||||
|
<widget class="QMainWindow" name="KEmuWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>KEmu</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset theme="applications-engineering">
|
||||||
|
<normaloff/>
|
||||||
|
</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="2" column="0">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Minimum</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="startStopButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Start</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="system-run">
|
||||||
|
<normaloff/>
|
||||||
|
</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Minimum</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" rowspan="2" colspan="3">
|
||||||
|
<widget class="KEditListWidget" name="machinesList">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>300</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3" rowspan="3">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>CD-ROM image</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="KUrlRequester" name="CDROMInput"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hard Disk image</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="systemComboBox"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>System type</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="KUrlRequester" name="HardDiskInput"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Video output</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QComboBox" name="videoComboBox">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>cirrus</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>vmware</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>qxl</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>xenfb</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>tcx</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>cg3</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>virtio</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Random Access Memory</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="KIntNumInput" name="RAMInput">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>32</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0" colspan="2">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>471</width>
|
||||||
|
<height>373</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="KVMCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Kernel-based Virtual Machine </string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="1">
|
||||||
|
<widget class="KLineEdit" name="argumentsLineEdit"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="KIntNumInput" name="CPUInput">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Extra arguments</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>CPU cores</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="ACPICheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Advanced Configuration and Power Interface</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QComboBox" name="audioComboBox">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>sb16</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>es1370</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>ac97</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>adlib</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>gus</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>cs4231a</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>hda</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>pcspk</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>all</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Audio output</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>KEditListWidget</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>keditlistwidget.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>KLineEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>klineedit.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>KUrlRequester</class>
|
||||||
|
<extends>QFrame</extends>
|
||||||
|
<header>kurlrequester.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>KIntNumInput</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>knuminput.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
411
kemu/kemumainwindow.cpp
Normal file
411
kemu/kemumainwindow.cpp
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
/* This file is part of the KDE libraries
|
||||||
|
Copyright (C) 2016 Ivailo Monev <xakepa10@gmail.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <KAction>
|
||||||
|
#include <KActionCollection>
|
||||||
|
#include <KLocale>
|
||||||
|
#include <KIcon>
|
||||||
|
#include <KFileDialog>
|
||||||
|
#include <KInputDialog>
|
||||||
|
#include <KStandardDirs>
|
||||||
|
#include <KStatusBar>
|
||||||
|
#include <KDebug>
|
||||||
|
#include <ksettings.h>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include "kemumainwindow.h"
|
||||||
|
#include "ui_kemu.h"
|
||||||
|
|
||||||
|
KEmuMainWindow::KEmuMainWindow(QWidget *parent, Qt::WindowFlags flags)
|
||||||
|
: KXmlGuiWindow(parent, flags), m_loading(false), m_installed(false), m_kemuui(new Ui_KEmuWindow)
|
||||||
|
{
|
||||||
|
m_kemuui->setupUi(this);
|
||||||
|
|
||||||
|
KAction *a = actionCollection()->addAction("harddisk_create", this, SLOT(createHardDisk()));
|
||||||
|
a->setText(i18n("Create Hard Disk image"));
|
||||||
|
a->setIcon(KIcon("drive-harddisk"));
|
||||||
|
a->setShortcut(KStandardShortcut::openNew());
|
||||||
|
a->setWhatsThis(i18n("Create a new Hard Disk image for later use."));
|
||||||
|
|
||||||
|
KAction *b = actionCollection()->addAction("file_quit", this, SLOT(quit()));
|
||||||
|
b->setText(i18n("Quit"));
|
||||||
|
b->setIcon(KIcon("application-exit"));
|
||||||
|
b->setShortcut(KStandardShortcut::quit());
|
||||||
|
b->setWhatsThis(i18n("Close the application."));
|
||||||
|
|
||||||
|
setupGUI();
|
||||||
|
setAutoSaveSettings();
|
||||||
|
|
||||||
|
setWindowIcon(KIcon("applications-engineering"));
|
||||||
|
m_kemuui->groupBox->setEnabled(false);
|
||||||
|
m_kemuui->startStopButton->setText(i18n("Start"));
|
||||||
|
m_kemuui->startStopButton->setIcon(KIcon("system-run"));
|
||||||
|
m_kemuui->CPUInput->setMaximum(QThread::idealThreadCount());
|
||||||
|
statusBar()->showMessage(i18n("No machines running"));
|
||||||
|
connect(m_kemuui->machinesList->listView()->selectionModel(),
|
||||||
|
SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||||
|
this, SLOT(machineChanged(QItemSelection,QItemSelection)));
|
||||||
|
connect(m_kemuui->machinesList, SIGNAL(added(QString)), this, SLOT(addMachine(QString)));
|
||||||
|
connect(m_kemuui->startStopButton, SIGNAL(clicked()), this, SLOT(startStopMachine()));
|
||||||
|
connect(m_kemuui->machinesList, SIGNAL(removed(QString)), this, SLOT(removeMachine(QString)));
|
||||||
|
|
||||||
|
static const QStringList qemuBins = QStringList() << "qemu-system-aarch64"
|
||||||
|
<< "qemu-system-alpha"
|
||||||
|
<< "qemu-system-arm"
|
||||||
|
<< "qemu-system-cris"
|
||||||
|
<< "qemu-system-i386"
|
||||||
|
<< "qemu-system-lm32"
|
||||||
|
<< "qemu-system-m68k"
|
||||||
|
<< "qemu-system-microblaze"
|
||||||
|
<< "qemu-system-microblazeel"
|
||||||
|
<< "qemu-system-mips"
|
||||||
|
<< "qemu-system-mips64"
|
||||||
|
<< "qemu-system-mips64el"
|
||||||
|
<< "qemu-system-mipsel"
|
||||||
|
<< "qemu-system-moxie"
|
||||||
|
<< "qemu-system-or32"
|
||||||
|
<< "qemu-system-ppc"
|
||||||
|
<< "qemu-system-ppc64"
|
||||||
|
<< "qemu-system-ppcemb"
|
||||||
|
<< "qemu-system-s390x"
|
||||||
|
<< "qemu-system-sh4"
|
||||||
|
<< "qemu-system-sh4eb"
|
||||||
|
<< "qemu-system-sparc"
|
||||||
|
<< "qemu-system-sparc64"
|
||||||
|
<< "qemu-system-tricore"
|
||||||
|
<< "qemu-system-unicore32"
|
||||||
|
<< "qemu-system-x86_64"
|
||||||
|
<< "qemu-system-xtensa"
|
||||||
|
<< "qemu-system-xtensaeb";
|
||||||
|
foreach (const QString bin, qemuBins) {
|
||||||
|
if(!KStandardDirs::findExe(bin).isEmpty()) {
|
||||||
|
m_installed = true;
|
||||||
|
m_kemuui->systemComboBox->addItem(bin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings = new KSettings("kemu", KSettings::SimpleConfig);
|
||||||
|
#ifndef QT_KATIE
|
||||||
|
foreach(const QString machine, m_settings->childGroups()) {
|
||||||
|
#else
|
||||||
|
QStringList addedmachines;
|
||||||
|
foreach(const QString key, m_settings->keys()) {
|
||||||
|
const int sepindex = key.indexOf("/");
|
||||||
|
if (sepindex < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QString machine = key.left(sepindex);
|
||||||
|
if (addedmachines.contains(machine)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addedmachines.append(machine);
|
||||||
|
#endif
|
||||||
|
if (m_settings->value(machine + "/enable").toBool() == true) {
|
||||||
|
m_kemuui->machinesList->insertItem(machine);
|
||||||
|
machineLoad(machine);
|
||||||
|
} else {
|
||||||
|
kDebug() << "garbage machine" << machine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const QString lastSelected = m_settings->value("lastselected").toString();
|
||||||
|
if (!lastSelected.isEmpty()) {
|
||||||
|
m_kemuui->machinesList->listView()->keyboardSearch(lastSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!m_installed) {
|
||||||
|
m_kemuui->startStopButton->setEnabled(false);
|
||||||
|
QMessageBox::critical(this, i18n("QEMU not available"), i18n("QEMU not available"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo kvmdev("/dev/kvm");
|
||||||
|
if (!kvmdev.exists()) {
|
||||||
|
const QString modprobeBin = KStandardDirs::findExe("modprobe");
|
||||||
|
if (!modprobeBin.isEmpty()) {
|
||||||
|
QProcess modprobe(this);
|
||||||
|
modprobe.start(modprobeBin, QStringList() << "-b" << "kvm");
|
||||||
|
modprobe.waitForFinished();
|
||||||
|
if (!kvmdev.exists()) {
|
||||||
|
QMessageBox::warning(this, i18n("KVM not available"), i18n("KVM not available"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
kDebug() << "modprobe not found";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_kemuui->CDROMInput, SIGNAL(textChanged(QString)), this, SLOT(machineSave(QString)));
|
||||||
|
connect(m_kemuui->HardDiskInput, SIGNAL(textChanged(QString)), this, SLOT(machineSave(QString)));
|
||||||
|
connect(m_kemuui->systemComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(machineSave(QString)));
|
||||||
|
connect(m_kemuui->videoComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(machineSave(QString)));
|
||||||
|
connect(m_kemuui->audioComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(machineSave(QString)));
|
||||||
|
connect(m_kemuui->RAMInput, SIGNAL(valueChanged(int)), this, SLOT(machineSave(int)));
|
||||||
|
connect(m_kemuui->CPUInput, SIGNAL(valueChanged(int)), this, SLOT(machineSave(int)));
|
||||||
|
connect(m_kemuui->KVMCheckBox, SIGNAL(stateChanged(int)), this, SLOT(machineSave(int)));
|
||||||
|
connect(m_kemuui->ACPICheckBox, SIGNAL(stateChanged(int)), this, SLOT(machineSave(int)));
|
||||||
|
connect(m_kemuui->argumentsLineEdit, SIGNAL(textChanged(QString)), this, SLOT(machineSave(QString)));
|
||||||
|
}
|
||||||
|
|
||||||
|
KEmuMainWindow::~KEmuMainWindow()
|
||||||
|
{
|
||||||
|
saveAutoSaveSettings();
|
||||||
|
const QString lastSelected = m_kemuui->machinesList->currentText();
|
||||||
|
if (!lastSelected.isEmpty()) {
|
||||||
|
m_settings->setValue("lastselected", lastSelected);
|
||||||
|
}
|
||||||
|
m_settings->sync();
|
||||||
|
m_settings->deleteLater();
|
||||||
|
foreach(QProcess* machineProcess, m_machines) {
|
||||||
|
const QString machine = m_machines.key(machineProcess);
|
||||||
|
kDebug() << "stopping machine" << machine;
|
||||||
|
machineProcess->terminate();
|
||||||
|
machineProcess->deleteLater();
|
||||||
|
m_machines.remove(machine);
|
||||||
|
}
|
||||||
|
delete m_kemuui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::createHardDisk()
|
||||||
|
{
|
||||||
|
const QString qemuImg = KStandardDirs::findExe("qemu-img");
|
||||||
|
if (qemuImg.isEmpty()) {
|
||||||
|
QMessageBox::warning(this, i18n("Requirements not met"),
|
||||||
|
i18n("qemu-img not found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QString diskPath = KFileDialog::getSaveFileName(KUrl(), QString(), this, i18n("Hard Disk path"));
|
||||||
|
if (!diskPath.isEmpty()) {
|
||||||
|
bool ok = false;
|
||||||
|
const int diskSize = KInputDialog::getInteger(i18n("Hard Disk size"),
|
||||||
|
i18n("Hard Disk size in MegaBytes"), 10, 10, INT_MAX, 1, 10, &ok, this);
|
||||||
|
if (ok) {
|
||||||
|
QProcess imageProcess(this);
|
||||||
|
imageProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
imageProcess.start(qemuImg, QStringList() << "create" << "-f" << "raw"
|
||||||
|
<< diskPath << QByteArray(QByteArray::number(diskSize) + QByteArray("M")));
|
||||||
|
imageProcess.waitForFinished();
|
||||||
|
if (imageProcess.exitCode() == 0) {
|
||||||
|
QMessageBox::information(this, i18n("Success"),
|
||||||
|
i18n("Image successfully created"));
|
||||||
|
} else {
|
||||||
|
QMessageBox::warning(this, i18n("QEMU error"),
|
||||||
|
i18n("An error occured:\n%1", QString(imageProcess.readAll())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::quit()
|
||||||
|
{
|
||||||
|
qApp->quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::updateStatus()
|
||||||
|
{
|
||||||
|
if (m_machines.size() == 0) {
|
||||||
|
statusBar()->showMessage(i18n("No machines running"));
|
||||||
|
} else {
|
||||||
|
QString machineNames;
|
||||||
|
bool firstmachine = true;
|
||||||
|
foreach (const QString name, m_machines.keys()) {
|
||||||
|
if (firstmachine) {
|
||||||
|
machineNames += name;
|
||||||
|
firstmachine = false;
|
||||||
|
} else {
|
||||||
|
machineNames += ", " + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const QString statusText = i18n("Machines running: %1 (%2)", machineNames, m_machines.size());
|
||||||
|
statusBar()->showMessage(statusText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::machineSave(const QString ignored)
|
||||||
|
{
|
||||||
|
Q_UNUSED(ignored);
|
||||||
|
if (m_loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QString machine = m_kemuui->machinesList->currentText();
|
||||||
|
kDebug() << "saving machine" << machine;
|
||||||
|
m_settings->setValue(machine + "/cdrom", m_kemuui->CDROMInput->url().prettyUrl());
|
||||||
|
m_settings->setValue(machine + "/harddisk", m_kemuui->HardDiskInput->url().prettyUrl());
|
||||||
|
m_settings->setValue(machine + "/system", m_kemuui->systemComboBox->currentText());
|
||||||
|
m_settings->setValue(machine + "/video", m_kemuui->videoComboBox->currentText());
|
||||||
|
m_settings->setValue(machine + "/audio", m_kemuui->audioComboBox->currentText());
|
||||||
|
m_settings->setValue(machine + "/ram", m_kemuui->RAMInput->value());
|
||||||
|
m_settings->setValue(machine + "/cpu", m_kemuui->CPUInput->value());
|
||||||
|
m_settings->setValue(machine + "/kvm", m_kemuui->KVMCheckBox->isChecked());
|
||||||
|
m_settings->setValue(machine + "/acpi", m_kemuui->ACPICheckBox->isChecked());
|
||||||
|
m_settings->setValue(machine + "/args", m_kemuui->argumentsLineEdit->text());
|
||||||
|
m_settings->sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::machineSave(int ignored)
|
||||||
|
{
|
||||||
|
Q_UNUSED(ignored);
|
||||||
|
machineSave(QString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KEmuMainWindow::machineLoad(const QString machine)
|
||||||
|
{
|
||||||
|
m_loading = true;
|
||||||
|
kDebug() << "loading machine" << machine;
|
||||||
|
m_kemuui->CDROMInput->setUrl(m_settings->value(machine + "/cdrom").toUrl());
|
||||||
|
m_kemuui->HardDiskInput->setUrl(m_settings->value(machine + "/harddisk").toUrl());
|
||||||
|
const QString system = m_settings->value(machine + "/system").toString();
|
||||||
|
const int systemIndex = m_kemuui->systemComboBox->findText(system);
|
||||||
|
m_kemuui->systemComboBox->setCurrentIndex(systemIndex);
|
||||||
|
const QString video = m_settings->value(machine + "/video", "virtio").toString();
|
||||||
|
const int videoIndex = m_kemuui->videoComboBox->findText(video);
|
||||||
|
m_kemuui->videoComboBox->setCurrentIndex(videoIndex);
|
||||||
|
const QString audio = m_settings->value(machine + "/audio", "ac97").toString();
|
||||||
|
const int audioIndex = m_kemuui->audioComboBox->findText(audio);
|
||||||
|
m_kemuui->audioComboBox->setCurrentIndex(audioIndex);
|
||||||
|
m_kemuui->RAMInput->setValue(m_settings->value(machine + "/ram", 32).toInt());
|
||||||
|
m_kemuui->CPUInput->setValue(m_settings->value(machine + "/cpu", 1).toInt());
|
||||||
|
m_kemuui->KVMCheckBox->setChecked(m_settings->value(machine + "/kvm", false).toBool());
|
||||||
|
m_kemuui->ACPICheckBox->setChecked(m_settings->value(machine + "/acpi", false).toBool());
|
||||||
|
m_kemuui->argumentsLineEdit->setText(m_settings->value(machine + "/args").toString());
|
||||||
|
m_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::machineChanged(QItemSelection ignored, QItemSelection ignored2)
|
||||||
|
{
|
||||||
|
Q_UNUSED(ignored);
|
||||||
|
Q_UNUSED(ignored2);
|
||||||
|
const QString machine = m_kemuui->machinesList->currentText();
|
||||||
|
if (!machine.isEmpty()) {
|
||||||
|
QFileInfo kvmdev("/dev/kvm");
|
||||||
|
m_kemuui->KVMCheckBox->setEnabled(kvmdev.exists());
|
||||||
|
|
||||||
|
m_kemuui->startStopButton->setEnabled(m_installed);
|
||||||
|
m_kemuui->groupBox->setEnabled(true);
|
||||||
|
if (m_machines.contains(machine)) {
|
||||||
|
kDebug() << "machine is running" << machine;
|
||||||
|
m_kemuui->startStopButton->setText(i18n("Stop"));
|
||||||
|
m_kemuui->startStopButton->setIcon(KIcon("system-shutdown"));
|
||||||
|
} else {
|
||||||
|
kDebug() << "machine is stopped" << machine;
|
||||||
|
m_kemuui->startStopButton->setText(i18n("Start"));
|
||||||
|
m_kemuui->startStopButton->setIcon(KIcon("system-run"));
|
||||||
|
}
|
||||||
|
machineLoad(machine);
|
||||||
|
} else {
|
||||||
|
m_kemuui->startStopButton->setEnabled(false);
|
||||||
|
m_kemuui->groupBox->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::machineFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
|
{
|
||||||
|
QProcess *machineProcess = qobject_cast<QProcess*>(sender());
|
||||||
|
disconnect(machineProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
|
||||||
|
this, SLOT(machineFinished(int,QProcess::ExitStatus)));
|
||||||
|
if (exitCode != 0) {
|
||||||
|
QMessageBox::warning(this, i18n("QEMU error"),
|
||||||
|
i18n("An error occured:\n%1", QString(machineProcess->readAll())));
|
||||||
|
}
|
||||||
|
m_kemuui->startStopButton->setText(i18n("Start"));
|
||||||
|
m_kemuui->startStopButton->setIcon(KIcon("system-run"));
|
||||||
|
const QString machine = m_machines.key(machineProcess);
|
||||||
|
m_machines.remove(machine);
|
||||||
|
machineProcess->deleteLater();
|
||||||
|
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::addMachine(const QString machine)
|
||||||
|
{
|
||||||
|
m_settings->setValue(machine + "/enable", true);
|
||||||
|
// TODO: set defaults?
|
||||||
|
m_settings->sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::startStopMachine()
|
||||||
|
{
|
||||||
|
const QString machine = m_kemuui->machinesList->currentText();
|
||||||
|
if (!machine.isEmpty()) {
|
||||||
|
if (m_machines.contains(machine)) {
|
||||||
|
kDebug() << "stopping machine" << machine;
|
||||||
|
QProcess* machineProcess = m_machines.take(machine);
|
||||||
|
machineProcess->terminate();
|
||||||
|
machineProcess->deleteLater();
|
||||||
|
m_kemuui->startStopButton->setText(i18n("Start"));
|
||||||
|
m_kemuui->startStopButton->setIcon(KIcon("system-run"));
|
||||||
|
} else {
|
||||||
|
kDebug() << "starting machine" << machine;
|
||||||
|
QStringList machineArgs;
|
||||||
|
machineArgs << "-name" << machine;
|
||||||
|
const QString CDRom = m_kemuui->CDROMInput->url().prettyUrl();
|
||||||
|
if (!CDRom.isEmpty()) {
|
||||||
|
machineArgs << "-cdrom" << CDRom;
|
||||||
|
}
|
||||||
|
const QString HardDisk = m_kemuui->HardDiskInput->url().prettyUrl();
|
||||||
|
if (!HardDisk.isEmpty()) {
|
||||||
|
machineArgs << "-hda" << HardDisk;
|
||||||
|
}
|
||||||
|
if (CDRom.isEmpty() && HardDisk.isEmpty()) {
|
||||||
|
QMessageBox::warning(this, i18n("Requirements not met"),
|
||||||
|
i18n("Either CD-ROM or Hard Disk image must be set"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
machineArgs << "-vga" << m_kemuui->videoComboBox->currentText();
|
||||||
|
machineArgs << "-soundhw" << m_kemuui->audioComboBox->currentText();
|
||||||
|
machineArgs << "-m" << QByteArray::number(m_kemuui->RAMInput->value());
|
||||||
|
machineArgs << "-smp" << QByteArray::number(m_kemuui->CPUInput->value());
|
||||||
|
if (m_kemuui->KVMCheckBox->isEnabled() && m_kemuui->KVMCheckBox->isChecked()) {
|
||||||
|
machineArgs << "-enable-kvm";
|
||||||
|
}
|
||||||
|
if (!m_kemuui->ACPICheckBox->isChecked()) {
|
||||||
|
machineArgs << "-no-acpi";
|
||||||
|
}
|
||||||
|
const QString extraArgs = m_kemuui->argumentsLineEdit->text();
|
||||||
|
if (!extraArgs.isEmpty()) {
|
||||||
|
foreach (const QString argument, extraArgs.split(" ")) {
|
||||||
|
machineArgs << argument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QProcess* machineProcess = new QProcess(this);
|
||||||
|
machineProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
m_kemuui->startStopButton->setText(i18n("Stop"));
|
||||||
|
m_kemuui->startStopButton->setIcon(KIcon("system-shutdown"));
|
||||||
|
m_machines.insert(machine, machineProcess);
|
||||||
|
connect(machineProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
|
||||||
|
this, SLOT(machineFinished(int,QProcess::ExitStatus)));
|
||||||
|
machineProcess->start(m_kemuui->systemComboBox->currentText(), machineArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KEmuMainWindow::removeMachine(const QString machine)
|
||||||
|
{
|
||||||
|
if (m_machines.contains(machine)) {
|
||||||
|
kDebug() << "stopping machine" << machine;
|
||||||
|
QProcess* machineProcess = m_machines.take(machine);
|
||||||
|
machineProcess->terminate();
|
||||||
|
machineProcess->deleteLater();
|
||||||
|
}
|
||||||
|
kDebug() << "removing machine" << machine;
|
||||||
|
m_settings->setValue(machine + "/enable", false);
|
||||||
|
m_settings->sync();
|
||||||
|
}
|
62
kemu/kemumainwindow.h
Normal file
62
kemu/kemumainwindow.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* This file is part of the KDE libraries
|
||||||
|
Copyright (C) 2016 Ivailo Monev <xakepa10@gmail.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEMUMAINWINDOW_H
|
||||||
|
#define KEMUMAINWINDOW_H
|
||||||
|
|
||||||
|
#include <KXmlGuiWindow>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class Ui_KEmuWindow;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class KEmuMainWindow: public KXmlGuiWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
KEmuMainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
|
||||||
|
~KEmuMainWindow();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void createHardDisk();
|
||||||
|
void quit();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void machineLoad(const QString machine);
|
||||||
|
void machineSave(const QString ignored);
|
||||||
|
void machineSave(int ignored);
|
||||||
|
void machineChanged(QItemSelection ignored, QItemSelection ignored2);
|
||||||
|
void machineFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
void addMachine(const QString machine);
|
||||||
|
void startStopMachine();
|
||||||
|
void removeMachine(const QString machine);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateStatus();
|
||||||
|
|
||||||
|
bool m_loading;
|
||||||
|
bool m_installed;
|
||||||
|
Ui_KEmuWindow *m_kemuui;
|
||||||
|
QSettings *m_settings;
|
||||||
|
QHash<QString,QProcess*> m_machines;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEMUMAINWINDOW_H
|
13
kemu/kemuui.rc
Normal file
13
kemu/kemuui.rc
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
|
||||||
|
<kpartgui name="kemu" version="1" >
|
||||||
|
<MenuBar>
|
||||||
|
<Menu name="file"><text>&File</text>
|
||||||
|
<Action name="harddisk_create"/>
|
||||||
|
<Separator/>
|
||||||
|
<Action name="file_quit"/>
|
||||||
|
</Menu>
|
||||||
|
</MenuBar>
|
||||||
|
|
||||||
|
<ToolBar name="mainToolBar" disable="1"><text>Main Toolbar</text>
|
||||||
|
</ToolBar>
|
||||||
|
</kpartgui>
|
43
kemu/main.cpp
Normal file
43
kemu/main.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/* This file is part of the KDE libraries
|
||||||
|
Copyright (C) 2016 Ivailo Monev <xakepa10@gmail.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License version 2, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public License
|
||||||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <KAboutData>
|
||||||
|
#include <KCmdLineArgs>
|
||||||
|
#include <KApplication>
|
||||||
|
#include "kemumainwindow.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
KAboutData aboutData("kemu", 0, ki18n("KEmu"),
|
||||||
|
"1.0.0", ki18n("Simple QEMU frontend for KDE."),
|
||||||
|
KAboutData::License_GPL_V2,
|
||||||
|
ki18n("(c) 2016 Ivailo Monev"),
|
||||||
|
KLocalizedString(),
|
||||||
|
"http://github.com/fluxer/katana"
|
||||||
|
);
|
||||||
|
|
||||||
|
aboutData.addAuthor(ki18n("Ivailo Monev"),
|
||||||
|
ki18n("Maintainer"),
|
||||||
|
"xakepa10@gmail.com");
|
||||||
|
aboutData.setProgramIconName(QLatin1String("applications-engineering"));
|
||||||
|
KCmdLineArgs::init(argc, argv, &aboutData);
|
||||||
|
KApplication *kemuapp = new KApplication();
|
||||||
|
KEmuMainWindow *kemuwindow = new KEmuMainWindow();
|
||||||
|
kemuwindow->show();
|
||||||
|
return kemuapp->exec();
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue