add preferences dialog
[presencevnc] / src / mainwindow.cpp
1 #include "mainwindow.h"
2 #include "preferences.h"
3 #include "vncview.h"
4
5 #include <QtMaemo5>
6 #include <QX11Info>
7
8 #include <X11/Xlib.h>
9 #include <X11/Xatom.h>
10
11 #include <iostream>
12
13 MainWindow::MainWindow(QString url, int quality):
14         QMainWindow(0),
15         vnc_view(0),
16         scroll_area(new QScrollArea(0))
17 {
18         setWindowTitle("Presence VNC");
19 //      swipe_start = QPoint(0,0);
20         setAttribute(Qt::WA_Maemo5StackedWindow);
21         QSettings settings;
22
23         //set up toolbar
24         toolbar = new QToolBar(0);
25         toolbar->addAction("Mod", this, SLOT(showModifierMenu()));
26         toolbar->addAction("Tab", this, SLOT(sendTab()));
27         toolbar->addAction("Esc", this, SLOT(sendEsc()));
28         toolbar->addAction("PgUp", this, SLOT(sendPgUp()));
29         toolbar->addAction("PgDn", this, SLOT(sendPgDn()));
30         toolbar->addAction(QIcon("/usr/share/icons/hicolor/48x48/hildon/general_fullsize.png"), "", this, SLOT(toggleFullscreen()));
31         addToolBar(toolbar);
32         toolbar->setVisible(settings.value("show_toolbar", true).toBool());
33
34         //set up menu
35         QMenuBar *menu = new QMenuBar(this);
36         QAction *connect_action = new QAction("Connect", this);
37         disconnect_action = new QAction("Disconnect", this);
38         menu->addAction(connect_action);
39         menu->addAction(disconnect_action);
40         scaling = new QAction("Rescale Remote Screen", this);
41         scaling->setCheckable(true);
42         scaling->setChecked(settings.value("rescale", true).toBool());
43         menu->addAction(scaling);
44         QAction *show_toolbar = new QAction("Show Toolbar", this);
45         show_toolbar->setCheckable(true);
46         show_toolbar->setChecked(settings.value("show_toolbar", true).toBool());
47         menu->addAction(show_toolbar);
48         QAction *pref_action = new QAction("Preferences", this);
49         menu->addAction(pref_action);
50         QAction *about_action = new QAction("About", this);
51         menu->addAction(about_action);
52
53         //menu->setAttribute(Qt::WA_Maemo5StackedWindow);
54         //menu->hide();
55
56         connect(about_action, SIGNAL(triggered()),
57                 this, SLOT(about()));
58         connect(pref_action, SIGNAL(triggered()),
59                 this, SLOT(showPreferences()));
60         connect(connect_action, SIGNAL(triggered()),
61                 this, SLOT(connectDialog()));
62         connect(disconnect_action, SIGNAL(triggered()),
63                 this, SLOT(disconnectFromHost()));
64         connect(show_toolbar, SIGNAL(toggled(bool)),
65                 toolbar, SLOT(setVisible(bool)));
66         connect(show_toolbar, SIGNAL(toggled(bool)),
67                 this, SLOT(forceResizeDelayed()));
68
69         setCentralWidget(scroll_area);
70
71         grabZoomKeys(true);
72         loadPreferences();
73
74         connect(QApplication::desktop(), SIGNAL(resized(int)),
75                 this, SLOT(forceResize()));
76
77         if(url.isNull()) {
78                 disconnect_action->setEnabled(false);
79                 toolbar->setEnabled(false);
80                 connectDialog();
81         } else {
82                 vnc_view = new VncView(0, url, RemoteView::Quality(quality));
83                 connect(scaling, SIGNAL(toggled(bool)),
84                         vnc_view, SLOT(enableScaling(bool)));
85                 connect(vnc_view, SIGNAL(statusChanged(RemoteView::RemoteStatus)),
86                         this, SLOT(statusChanged(RemoteView::RemoteStatus)));
87                 scroll_area->setWidget(vnc_view);
88                 vnc_view->start();
89                 vnc_view->enableScaling(scaling->isChecked());
90         }
91 }
92
93 void MainWindow::grabZoomKeys(bool grab)
94 {
95         unsigned long val = (grab)?1:0;
96         Atom atom = XInternAtom(QX11Info::display(), "_HILDON_ZOOM_KEY_ATOM", False);
97         if(!atom) {
98                 qWarning("Couldn't get zoom key atom");
99                 return;
100         }
101         XChangeProperty(QX11Info::display(), winId(), atom, XA_INTEGER,
102                 32, PropModeReplace, reinterpret_cast<unsigned char *>(&val), 1);
103 }
104
105 void MainWindow::closeEvent(QCloseEvent*) {
106         grabZoomKeys(false);
107
108         QSettings settings;
109         settings.setValue("show_toolbar", toolbar->isVisible());
110         settings.setValue("rescale", scaling->isChecked());
111         settings.sync();
112
113         hide();
114
115         disconnectFromHost();
116 }
117
118 void MainWindow::about() {
119         QMessageBox::about(this, tr("About Presence VNC"),
120                 tr("<center><h1>Presence VNC 0.1 beta</h1>\
121 A touch screen friendly VNC client\
122 <small><p>&copy;2010 Christian Pulvermacher &lt;pulvermacher@gmx.de&gt</p>\
123 <p>Based on KRDC, &copy; 2007-2008 Urs Wolfer</small></center>\
124 <p>This program is free software; License: <a href=\"http://www.gnu.org/licenses/gpl-2.0.html\">GNU GPL 2</a> or later.</p>"));
125 }
126
127 /* swipe not used, and doesn't work without scaling anyway :/
128 virtual bool event(QEvent *event) {
129         if(event->type() == QEvent::MouseMove) {
130                 QMouseEvent *ev = dynamic_cast<QMouseEvent* >(event);
131                 if(!swipe_start.isNull()) {
132                         QPoint diff = swipe_start - ev->pos();
133                         const int swipe_dist = 60;
134                         if(diff.x() > swipe_dist and diff.y() < swipe_dist and diff.y() > -swipe_dist) { //
135                                 menu->show();
136                                 swipe_start = QPoint(0,0);
137                         }
138                 } else if((width() - ev->x()) < 10) {
139                         swipe_start = ev->pos();
140                 }
141                 std::cout << "mousex: " << width() - ev->x() << "\n";
142                 //TODO: make scrolling over border result in wheel events? i get weird (out of range) mouse events when that happens
143                 return true;
144         } else if(event->type() == QEvent::MouseButtonRelease) {
145                 swipe_start = QPoint(0,0);
146                 return true;
147         } else {
148 //                      std::cout << "event " << event->type() << "\n";
149                 return QScrollArea::event(event);
150         }
151 }
152 */
153
154 void MainWindow::connectDialog()
155 {
156         QSettings settings;
157         QString url = QInputDialog::getText(this, "Connect to Host", "VNC Server:", QLineEdit::Normal, settings.value("last_hostname", "").toString());
158         if(url.isEmpty()) { //dialog dismissed or nothing entered
159                 return;
160         }
161         settings.setValue("last_hostname", url);
162         url = "vnc://" + url;
163
164         disconnectFromHost();
165
166         vnc_view = new VncView(0, url, RemoteView::Quality(2)); //TODO: get quality in dialog
167         scroll_area->setWidget(vnc_view);
168
169         connect(scaling, SIGNAL(toggled(bool)),
170                 vnc_view, SLOT(enableScaling(bool)));
171         connect(vnc_view, SIGNAL(statusChanged(RemoteView::RemoteStatus)),
172                 this, SLOT(statusChanged(RemoteView::RemoteStatus)));
173         vnc_view->start();
174         vnc_view->enableScaling(scaling->isChecked());
175         disconnect_action->setEnabled(true);
176         toolbar->setEnabled(true);
177 }
178
179 void MainWindow::disconnectFromHost()
180 {
181         if(!vnc_view)
182                 return;
183
184         vnc_view->startQuitting();
185         scroll_area->setWidget(0);
186
187         vnc_view->disconnect(); //remove all connections
188         delete vnc_view;
189         vnc_view = 0;
190         disconnect_action->setEnabled(false);
191         toolbar->setEnabled(false);
192 }
193
194 void MainWindow::statusChanged(RemoteView::RemoteStatus status)
195 {
196         static RemoteView::RemoteStatus old_status = RemoteView::Disconnected;
197
198         switch(status) {
199         case RemoteView::Connecting:
200                 setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true);
201                 break;
202         case RemoteView::Connected:
203                 setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false);
204                 break;
205         case RemoteView::Disconnecting:
206                 if(old_status != RemoteView::Disconnected) { //Disconnecting also occurs while connecting, so check last state
207                         QMaemo5InformationBox::information(this, "Connection lost");
208                 }
209                 break;
210         case RemoteView::Disconnected:
211                 if(old_status == RemoteView::Disconnecting) {
212                         scroll_area->setWidget(0); //remove widget
213                 }
214                 break;
215         }
216
217         old_status = status;
218 }
219
220 //when rescaling is enabled, this resizes the widget to use available screen space
221 //necessary when rotating, showing fullscreen, etc.
222 void MainWindow::forceResize()
223 {
224         if(vnc_view and scaling->isChecked()) {
225                 vnc_view->resize(scroll_area->size());
226         }
227
228
229 void MainWindow::forceResizeDelayed()
230 {
231         QTimer::singleShot(500, this, SLOT(forceResize()));
232 }
233
234 void MainWindow::toggleFullscreen()
235 {
236         setWindowState(windowState() ^ Qt::WindowFullScreen); 
237         forceResizeDelayed();
238 }
239
240 void MainWindow::showModifierMenu()
241 {
242         static QMenu *mod_menu = new QMenu(tr("Modifiers"), this);
243         static QAction *win = mod_menu->addAction(tr("Win"));
244         static QAction *alt = mod_menu->addAction(tr("Alt"));
245         win->setCheckable(true);
246         alt->setCheckable(true);
247
248         //show menu at top-left corner of toolbar
249         QAction *chosen = mod_menu->exec(toolbar->mapToGlobal(QPoint(0,0)));
250         if(!chosen) {
251                 return;
252         } else if(chosen == alt) {
253                 vnc_view->sendKey(Qt::Key_Alt);
254         } else if(chosen == win) {
255                 vnc_view->sendKey(Qt::Key_Meta);
256         } else {
257                 std::cout << "unhandled action?\n";
258         }
259 }
260
261 void MainWindow::showPreferences()
262 {
263         Preferences *p = new Preferences(this);
264         p->exec();
265         delete p;
266
267         loadPreferences();
268 }
269
270 void MainWindow::loadPreferences()
271 {
272         QSettings settings;
273         int rotation = settings.value("screen_rotation", 0).toInt();
274         setAttribute(Qt::WA_Maemo5AutoOrientation, rotation == 0);
275         setAttribute(Qt::WA_Maemo5LandscapeOrientation, rotation == 1);
276         setAttribute(Qt::WA_Maemo5PortraitOrientation, rotation == 2);
277 }