X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fmainwindow.cpp;h=f6bdda7aa72e3a2acc8d5c5705772b80fc9da7f2;hb=cec1e74674ff4e42e82c1333514efe4ce077ae6c;hp=f6e1f1eccf88b323906b7bb2418430074ddb005d;hpb=923f244f93a28b8be9f00d02242ce80ae35354d2;p=presencevnc diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f6e1f1e..f6bdda7 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,102 +1,144 @@ +/* + Presence VNC + Copyright (C) 2010 Christian Pulvermacher + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "connectdialog.h" +#include "fullscreenexitbutton.h" +#include "keymenu.h" #include "mainwindow.h" #include "preferences.h" +#include "scrollarea.h" #include "vncview.h" +#ifdef Q_WS_MAEMO_5 #include #include #include #include +#endif -#include MainWindow::MainWindow(QString url, int quality): QMainWindow(0), vnc_view(0), - scroll_area(new QScrollArea(0)) + scroll_area(new ScrollArea(0)), + key_menu(new KeyMenu(this)) { setWindowTitle("Presence VNC"); -// swipe_start = QPoint(0,0); + setContextMenuPolicy(Qt::NoContextMenu); +#ifdef Q_WS_MAEMO_5 setAttribute(Qt::WA_Maemo5StackedWindow); - QSettings settings; +#endif + + migrateConfiguration(); //set up toolbar toolbar = new QToolBar(0); - toolbar->setAttribute(Qt::WA_InputMethodEnabled, true); - toolbar->addAction("Mod", this, SLOT(showModifierMenu())); - toolbar->addAction("Tab", this, SLOT(sendTab())); - toolbar->addAction("Esc", this, SLOT(sendEsc())); - toolbar->addAction("PgUp", this, SLOT(sendPgUp())); - toolbar->addAction("PgDn", this, SLOT(sendPgDn())); -// toolbar->addAction("IM", toolbar, SLOT(setFocus())); //doesn't work + toolbar->addAction(QChar(0x2026), this, SLOT(showKeyMenu())); //"..." button + toolbar->addAction(tr("Tab"), this, SLOT(sendTab())); + toolbar->addAction(tr("Esc"), this, SLOT(sendEsc())); + toolbar->addAction(tr("PgUp"), this, SLOT(sendPgUp())); + toolbar->addAction(tr("PgDn"), this, SLOT(sendPgDn())); +#ifdef Q_WS_MAEMO_5 + toolbar->addAction(QIcon("/usr/share/icons/hicolor/48x48/hildon/chat_enter.png"), "", this, SLOT(sendReturn())); + toolbar->addAction(QIcon("/usr/share/icons/hicolor/48x48/hildon/control_keyboard.png"), "", this, SLOT(showInputPanel())); +#endif + + QSettings settings; + zoom_slider = new QSlider(Qt::Horizontal, 0); + zoom_slider->setRange(0, 100); + connect(zoom_slider, SIGNAL(valueChanged(int)), + this, SLOT(setZoomLevel(int))); + connect(zoom_slider, SIGNAL(sliderReleased()), + this, SLOT(forceRepaint())); + zoom_slider->setValue(settings.value("zoomlevel", 95).toInt()); + toolbar->addWidget(zoom_slider); + toolbar->addAction(QIcon("/usr/share/icons/hicolor/48x48/hildon/general_fullsize.png"), "", this, SLOT(toggleFullscreen())); addToolBar(toolbar); toolbar->setVisible(settings.value("show_toolbar", true).toBool()); + toolbar->setEnabled(false); //set up menu - QMenuBar *menu = new QMenuBar(this); - QAction *connect_action = new QAction("Connect", this); - disconnect_action = new QAction("Disconnect", this); -// menu->addAction(connect_action); -// menu->addAction(disconnect_action); - scaling = new QAction("Fit to Screen", this); - scaling->setCheckable(true); - scaling->setChecked(settings.value("rescale", true).toBool()); - menu->addAction(scaling); - QAction *show_toolbar = new QAction("Show Toolbar", this); + QAction *connect_action = new QAction(tr("Connect"), this); + disconnect_action = new QAction(tr("Disconnect"), this); + show_toolbar = new QAction(tr("Show Toolbar"), this); show_toolbar->setCheckable(true); show_toolbar->setChecked(settings.value("show_toolbar", true).toBool()); - menu->addAction(show_toolbar); - QAction *pref_action = new QAction("Preferences", this); - menu->addAction(pref_action); - QAction *about_action = new QAction("About", this); - menu->addAction(about_action); - - //menu->setAttribute(Qt::WA_Maemo5StackedWindow); - //menu->hide(); + QAction *pref_action = new QAction(tr("Preferences"), this); + QAction *about_action = new QAction(tr("About"), this); + +#ifdef Q_WS_MAEMO_5 + menuBar()->addAction(connect_action); + menuBar()->addAction(disconnect_action); + menuBar()->addAction(show_toolbar); + menuBar()->addAction(pref_action); + menuBar()->addAction(about_action); +#else + QMenu* session_menu = menuBar()->addMenu(tr("&Session")); + session_menu->addAction(connect_action); + session_menu->addAction(disconnect_action); + session_menu->addSeparator(); + session_menu->addAction(pref_action); + session_menu->addSeparator(); + session_menu->addAction(tr("&Quit"), this, SLOT(close())); + + QMenu* view_menu = menuBar()->addMenu(tr("&View")); + view_menu->addAction(show_toolbar); + + QMenu* help_menu = menuBar()->addMenu(tr("&Help")); + help_menu->addAction(about_action); +#endif connect(about_action, SIGNAL(triggered()), this, SLOT(about())); connect(pref_action, SIGNAL(triggered()), this, SLOT(showPreferences())); connect(connect_action, SIGNAL(triggered()), - this, SLOT(connectDialog())); + this, SLOT(showConnectDialog())); connect(disconnect_action, SIGNAL(triggered()), this, SLOT(disconnectFromHost())); connect(show_toolbar, SIGNAL(toggled(bool)), toolbar, SLOT(setVisible(bool))); connect(show_toolbar, SIGNAL(toggled(bool)), - this, SLOT(forceResizeDelayed())); + this, SLOT(updateScreenSpaceDelayed())); setCentralWidget(scroll_area); + new FullScreenExitButton(this); grabZoomKeys(true); reloadSettings(); - connect(QApplication::desktop(), SIGNAL(resized(int)), - this, SLOT(forceResize())); - if(url.isNull()) { disconnect_action->setEnabled(false); - toolbar->setEnabled(false); - connectDialog(); + showConnectDialog(); } else { vnc_view = new VncView(this, url, RemoteView::Quality(quality)); - connect(scaling, SIGNAL(toggled(bool)), - vnc_view, SLOT(enableScaling(bool))); connect(vnc_view, SIGNAL(statusChanged(RemoteView::RemoteStatus)), this, SLOT(statusChanged(RemoteView::RemoteStatus))); scroll_area->setWidget(vnc_view); vnc_view->start(); - vnc_view->enableScaling(scaling->isChecked()); } - - if(!vnc_view) //not connected - QTimer::singleShot(100, this, SLOT(close())); } void MainWindow::grabZoomKeys(bool grab) { +#ifdef Q_WS_MAEMO_5 unsigned long val = (grab)?1:0; Atom atom = XInternAtom(QX11Info::display(), "_HILDON_ZOOM_KEY_ATOM", False); if(!atom) { @@ -105,14 +147,15 @@ void MainWindow::grabZoomKeys(bool grab) } XChangeProperty(QX11Info::display(), winId(), atom, XA_INTEGER, 32, PropModeReplace, reinterpret_cast(&val), 1); +#endif } void MainWindow::closeEvent(QCloseEvent*) { grabZoomKeys(false); QSettings settings; - settings.setValue("show_toolbar", toolbar->isVisible()); - settings.setValue("rescale", scaling->isChecked()); + settings.setValue("show_toolbar", show_toolbar->isChecked()); + settings.setValue("zoomlevel", zoom_slider->value()); settings.sync(); hide(); @@ -122,63 +165,39 @@ void MainWindow::closeEvent(QCloseEvent*) { void MainWindow::about() { QMessageBox::about(this, tr("About Presence VNC"), - tr("

Presence VNC 0.1

\ -A touchscreen friendly VNC client\ -

©2010 Christian Pulvermacher <pulvermacher@gmx.de>

\ -

Based on KRDC, © 2007-2008 Urs Wolfer

\ -

This program is free software; License: GNU GPL 2 or later.

")); + tr("

Presence VNC 0.7

\ +

A touchscreen friendly VNC client

\ +

https://garage.maemo.org/projects/presencevnc

\ +

©2010 Christian Pulvermacher <pulvermacher@gmx.de>
\ +Based on KRDC, © 2007-2008 Urs Wolfer
\ +and LibVNCServer, © 2001-2003 Johannes E. Schindelin

\ +

This program is free software; License: GNU GPL 2 or later.

")); } -/* swipe not used, and doesn't work without scaling anyway :/ -virtual bool event(QEvent *event) { - if(event->type() == QEvent::MouseMove) { - QMouseEvent *ev = dynamic_cast(event); - if(!swipe_start.isNull()) { - QPoint diff = swipe_start - ev->pos(); - const int swipe_dist = 60; - if(diff.x() > swipe_dist and diff.y() < swipe_dist and diff.y() > -swipe_dist) { // - menu->show(); - swipe_start = QPoint(0,0); - } - } else if((width() - ev->x()) < 10) { - swipe_start = ev->pos(); - } - std::cout << "mousex: " << width() - ev->x() << "\n"; - //TODO: make scrolling over border result in wheel events? i get weird (out of range) mouse events when that happens - return true; - } else if(event->type() == QEvent::MouseButtonRelease) { - swipe_start = QPoint(0,0); - return true; - } else { -// std::cout << "event " << event->type() << "\n"; - return QScrollArea::event(event); - } +void MainWindow::showConnectDialog() +{ + ConnectDialog *connect_dialog = new ConnectDialog(this); + connect(connect_dialog, SIGNAL(connectToHost(QString, int, int)), + this, SLOT(connectToHost(QString, int, int))); + connect_dialog->exec(); } -*/ -void MainWindow::connectDialog() +void MainWindow::connectToHost(QString url, int quality, int listen_port) { - QSettings settings; - QString url = QInputDialog::getText(this, "Connect to Host", "VNC Server:", QLineEdit::Normal, settings.value("last_hostname", "").toString()); - if(url.isEmpty()) { //dialog dismissed or nothing entered - return; - } - settings.setValue("last_hostname", url); - url = "vnc://" + url; - disconnectFromHost(); - vnc_view = new VncView(this, url, RemoteView::Quality(2)); //TODO: get quality in dialog - scroll_area->setWidget(vnc_view); + vnc_view = new VncView(this, url, RemoteView::Quality(quality), listen_port); - connect(scaling, SIGNAL(toggled(bool)), - vnc_view, SLOT(enableScaling(bool))); connect(vnc_view, SIGNAL(statusChanged(RemoteView::RemoteStatus)), this, SLOT(statusChanged(RemoteView::RemoteStatus))); + scroll_area->setWidget(vnc_view); vnc_view->start(); - vnc_view->enableScaling(scaling->isChecked()); + disconnect_action->setEnabled(true); - toolbar->setEnabled(true); + + //reset key menu + delete key_menu; + key_menu = new KeyMenu(this); } void MainWindow::disconnectFromHost() @@ -186,15 +205,12 @@ void MainWindow::disconnectFromHost() if(!vnc_view) return; -//TODO: crashes when deleting vnc_view - no idea why - //vnc_view->startQuitting(); - //scroll_area->setWidget(0); - -// vnc_view->disconnect(); //remove all connections - //delete vnc_view; - //vnc_view = 0; disconnect_action->setEnabled(false); toolbar->setEnabled(false); + scroll_area->setWidget(0); + + delete vnc_view; + vnc_view = 0; } void MainWindow::statusChanged(RemoteView::RemoteStatus status) @@ -203,67 +219,91 @@ void MainWindow::statusChanged(RemoteView::RemoteStatus status) switch(status) { case RemoteView::Connecting: +#ifdef Q_WS_MAEMO_5 setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true); +#endif break; case RemoteView::Connected: +#ifdef Q_WS_MAEMO_5 setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); +#endif + toolbar->setEnabled(true); + + vnc_view->setZoomLevel(zoom_slider->value()); + vnc_view->forceFullRepaint(); break; case RemoteView::Disconnecting: - if(old_status != RemoteView::Disconnected) { //Disconnecting also occurs while connecting, so check last state - QMaemo5InformationBox::information(this, "Connection lost"); - close(); - } + if(old_status == RemoteView::Disconnected) //Disconnecting also occurs while connecting, so check last state + break; + + if(disconnect_action->isEnabled()) //don't show when manually disconnecting + scroll_area->showMessage(tr("Connection lost")); + + //clean up + scroll_area->setWidget(0); + vnc_view = 0; + disconnect_action->setEnabled(false); + toolbar->setEnabled(false); + + //exit fullscreen mode + if(windowState() & Qt::WindowFullScreen) + setWindowState(windowState() ^ Qt::WindowFullScreen); break; case RemoteView::Disconnected: +#ifdef Q_WS_MAEMO_5 setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); +#endif if(old_status == RemoteView::Disconnecting) { scroll_area->setWidget(0); //remove widget } break; + default: //avoid compiler warnings + break; } old_status = status; } -//when rescaling is enabled, this resizes the widget to use available screen space +void MainWindow::forceRepaint() +{ + if(vnc_view) + vnc_view->forceFullRepaint(); +} + +//updates available screen space for current zoom level //necessary when rotating, showing fullscreen, etc. -void MainWindow::forceResize() +void MainWindow::updateScreenSpace() { - if(vnc_view and scaling->isChecked()) { - vnc_view->resize(scroll_area->size()); + if(vnc_view) { + vnc_view->setZoomLevel(); } } -void MainWindow::forceResizeDelayed() +void MainWindow::updateScreenSpaceDelayed() { - QTimer::singleShot(500, this, SLOT(forceResize())); + QTimer::singleShot(500, this, SLOT(updateScreenSpace())); } void MainWindow::toggleFullscreen() { + bool in_fullscreen = windowState() & Qt::WindowFullScreen; + + //hide menu/toolbar in fullscreen (new state is !in_fullscreen) + toolbar->setVisible(show_toolbar->isChecked() and in_fullscreen); + +#ifndef Q_WS_MAEMO_5 + //menu bar is invisible by default on maemo + menuBar()->setVisible(in_fullscreen); +#endif + setWindowState(windowState() ^ Qt::WindowFullScreen); - forceResizeDelayed(); + updateScreenSpaceDelayed(); } -void MainWindow::showModifierMenu() +void MainWindow::showKeyMenu() { - static QMenu *mod_menu = new QMenu(tr("Modifiers"), this); - static QAction *win = mod_menu->addAction(tr("Win")); - static QAction *alt = mod_menu->addAction(tr("Alt")); - win->setCheckable(true); - alt->setCheckable(true); - - //show menu at top-left corner of toolbar - QAction *chosen = mod_menu->exec(toolbar->mapToGlobal(QPoint(0,0))); - if(!chosen) { - return; - } else if(chosen == alt) { - vnc_view->sendKey(Qt::Key_Alt); - } else if(chosen == win) { - vnc_view->sendKey(Qt::Key_Meta); - } else { - std::cout << "unhandled action?\n"; - } + key_menu->exec(); + vnc_view->sendKeySequence(key_menu->getKeySequence()); } void MainWindow::showPreferences() @@ -277,12 +317,65 @@ void MainWindow::showPreferences() void MainWindow::reloadSettings() { +#ifdef Q_WS_MAEMO_5 QSettings settings; int rotation = settings.value("screen_rotation", 0).toInt(); setAttribute(Qt::WA_Maemo5AutoOrientation, rotation == 0); setAttribute(Qt::WA_Maemo5LandscapeOrientation, rotation == 1); setAttribute(Qt::WA_Maemo5PortraitOrientation, rotation == 2); +#endif if(vnc_view) vnc_view->reloadSettings(); } + +void MainWindow::resizeEvent(QResizeEvent *event) +{ + QMainWindow::resizeEvent(event); + + updateScreenSpace(); + if(vnc_view) + vnc_view->setZoomLevel(zoom_slider->value()); + +#ifdef Q_WS_MAEMO_5 + //hide zoom slider in portrait mode + zoom_slider->setVisible(height() < width()); +#endif +} + +void MainWindow::showInputPanel() +{ +#ifdef Q_WS_MAEMO_5 + //TODO: when hardware keyboard is open, this will only cause the IM to mess up 'real' key events + vnc_view->setAttribute(Qt::WA_InputMethodEnabled, true); + vnc_view->setInputMethodHints(Qt::ImhNoAutoUppercase); //without this, IM starts with caps lock + + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(vnc_view, &event); +#endif +} + +void MainWindow::setZoomLevel(int level) +{ + if(!vnc_view) + return; + + //TODO: use getZoomFactor() instead + int old_width = vnc_view->width(); + QPoint center = vnc_view->visibleRegion().boundingRect().center(); + + vnc_view->setZoomLevel(level); + + int new_width = vnc_view->width(); + + //scroll to center, if zoom level actually changed + if(new_width != old_width) { + center = center * (double(new_width)/old_width); + scroll_area->ensureVisible(center.x(), center.y(), + vnc_view->visibleRegion().boundingRect().width()/2, + vnc_view->visibleRegion().boundingRect().height()/2); + vnc_view->update(); + + scroll_area->showMessage(tr("Zoom: %1\%").arg(qRound(100*vnc_view->getZoomFactor()))); + } +}