Fix crash in new on_close handler.
[mp-5.x.git] / mpv_qt4.cpp
blob63b3e9a46a97be1c01956a3e7565144b29cee6ed
1 /*
3 Minimum Profit - Programmer Text Editor
5 Qt4 driver.
7 Copyright (C) 2009/2010 Angel Ortega <angel@triptico.com>
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 http://www.triptico.com
27 /* override auto-generated definition in config.h */
28 extern "C" int qt4_drv_detect(int *argc, char ***argv);
30 #include "config.h"
32 #include <stdio.h>
33 #include <wchar.h>
34 #include <unistd.h>
35 #include "mpdm.h"
36 #include "mpsl.h"
37 #include "mp.h"
38 #include "mp.xpm"
40 #include <QtGui>
42 /** data **/
44 class MPWindow : public QMainWindow
46 public:
47 MPWindow(QWidget * parent = 0);
48 bool queryExit(void);
49 bool event(QEvent * event);
51 QSettings *settings;
54 class MPArea : public QWidget
56 Q_OBJECT
58 public:
59 MPArea(QWidget * parent = 0);
60 void inputMethodEvent(QInputMethodEvent * event);
61 void keyPressEvent(QKeyEvent * event);
62 void keyReleaseEvent(QKeyEvent * event);
63 void mousePressEvent(QMouseEvent * event);
64 void mouseReleaseEvent(QMouseEvent * event);
65 void mouseMoveEvent(QMouseEvent * event);
66 void wheelEvent(QWheelEvent * event);
67 void dragEnterEvent(QDragEnterEvent * event);
68 void dropEvent(QDropEvent * event);
69 bool event(QEvent * event);
71 QTimer *timer;
73 protected:
74 void paintEvent(QPaintEvent * event);
76 public slots: void from_scrollbar(int);
77 void from_filetabs(int);
78 void from_menu(QAction *);
79 void from_timer(void);
82 /* global data */
83 QApplication *app;
84 MPWindow *window;
85 QMenuBar *menubar;
86 //QStatusBar *statusbar;
87 QLabel *statusbar;
88 QTabBar *file_tabs;
90 #define MENU_CLASS QMenu
92 #include "mpv_qk_common.cpp"
94 static void draw_status(void)
96 statusbar->setText(str_to_qstring(mp_build_status_line()));
100 /** MPWindow methods **/
102 MPWindow::MPWindow(QWidget * parent):QMainWindow(parent)
104 QVBoxLayout *vb;
105 QHBoxLayout *hb;
106 int height;
108 setWindowTitle("mp " VERSION);
110 menubar = this->menuBar();
111 build_menu();
113 /* pick an optimal height for the menu & tabs */
114 height = menubar->sizeHint().height();
116 file_tabs = new QTabBar();
117 file_tabs->setFocusPolicy(Qt::NoFocus);
119 /* top area */
120 hb = new QHBoxLayout();
121 hb->setContentsMargins(0, 0, 0, 0);
123 hb->addWidget(menubar);
124 hb->addWidget(file_tabs);
125 QWidget *ta = new QWidget();
126 ta->setLayout(hb);
127 ta->setMaximumHeight(height);
129 /* main area */
130 hb = new QHBoxLayout();
131 hb->setContentsMargins(0, 0, 0, 0);
133 area = new MPArea();
134 scrollbar = new QScrollBar();
135 scrollbar->setFocusPolicy(Qt::NoFocus);
137 hb->addWidget(area);
138 hb->addWidget(scrollbar);
139 QWidget *cc = new QWidget();
140 cc->setLayout(hb);
142 /* the full container */
143 vb = new QVBoxLayout();
145 vb->addWidget(ta);
146 vb->addWidget(cc);
148 QWidget *mc = new QWidget();
149 mc->setLayout(vb);
151 statusbar = new QLabel();
152 this->statusBar()->addWidget(statusbar);
154 setCentralWidget(mc);
156 connect(scrollbar, SIGNAL(valueChanged(int)),
157 area, SLOT(from_scrollbar(int)));
159 connect(file_tabs, SIGNAL(currentChanged(int)),
160 area, SLOT(from_filetabs(int)));
162 connect(menubar, SIGNAL(triggered(QAction *)),
163 area, SLOT(from_menu(QAction *)));
165 this->setWindowIcon(QIcon(QPixmap(mp_xpm)));
167 settings = new QSettings("triptico.com", "MinimumProfit");
169 QPoint pos = settings->value("pos", QPoint(20, 20)).toPoint();
170 QSize size = settings->value("size", QSize(600, 400)).toSize();
172 move(pos);
173 resize(size);
177 static void save_settings(MPWindow * w)
179 w->settings->setValue("pos", w->pos());
180 w->settings->setValue("size", w->size());
181 w->settings->sync();
185 bool MPWindow::queryExit(void)
187 mp_process_event(MPDM_LS(L"close-window"));
189 save_settings(this);
191 return mp_exit_requested ? true : false;
195 bool MPWindow::event(QEvent * event)
197 /* do the processing */
198 bool r = QWidget::event(event);
200 if (mp_exit_requested) {
201 save_settings(this);
202 qt4_drv_shutdown(NULL, NULL);
203 QApplication::exit(0);
206 return r;
210 /** driver functions **/
212 static mpdm_t qt4_drv_alert(mpdm_t a, mpdm_t ctxt)
214 /* 1# arg: prompt */
215 QMessageBox::information(window, "mp " VERSION,
216 str_to_qstring(mpdm_aget(a, 0)));
218 return NULL;
222 static mpdm_t qt4_drv_confirm(mpdm_t a, mpdm_t ctxt)
224 int r;
226 /* 1# arg: prompt */
227 r = QMessageBox::question(window, "mp" VERSION,
228 str_to_qstring(mpdm_aget(a, 0)),
229 QMessageBox::Yes | QMessageBox::
230 No | QMessageBox::Cancel);
232 switch (r) {
233 case QMessageBox::Yes:
234 r = 1;
235 break;
237 case QMessageBox::No:
238 r = 2;
239 break;
241 case QMessageBox::Cancel:
242 r = 0;
243 break;
246 return MPDM_I(r);
250 static mpdm_t qt4_drv_openfile(mpdm_t a, mpdm_t ctxt)
252 QString r;
253 char tmp[128];
255 getcwd(tmp, sizeof(tmp));
257 /* 1# arg: prompt */
258 r = QFileDialog::getOpenFileName(window,
259 str_to_qstring(mpdm_aget(a, 0)), tmp);
261 return qstring_to_str(r);
265 static mpdm_t qt4_drv_savefile(mpdm_t a, mpdm_t ctxt)
267 QString r;
268 char tmp[128];
270 getcwd(tmp, sizeof(tmp));
272 /* 1# arg: prompt */
273 r = QFileDialog::getSaveFileName(window,
274 str_to_qstring(mpdm_aget(a, 0)), tmp);
276 return qstring_to_str(r);
280 class MPForm : public QDialog
282 public:
283 QDialogButtonBox * button_box;
285 MPForm(QWidget * parent = 0) : QDialog(parent)
287 button_box = new QDialogButtonBox(QDialogButtonBox::Ok |
288 QDialogButtonBox::Cancel);
290 connect(button_box, SIGNAL(accepted()), this, SLOT(accept()));
291 connect(button_box, SIGNAL(rejected()), this, SLOT(reject()));
296 static mpdm_t qt4_drv_form(mpdm_t a, mpdm_t ctxt)
298 int n;
299 mpdm_t widget_list;
300 QWidget *qlist[100];
301 mpdm_t r;
303 MPForm *dialog = new MPForm(window);
304 dialog->setWindowTitle("mp " VERSION);
306 dialog->setModal(true);
308 widget_list = mpdm_aget(a, 0);
310 QWidget *form = new QWidget();
311 QFormLayout *fl = new QFormLayout();
313 for (n = 0; n < mpdm_size(widget_list); n++) {
314 mpdm_t w = mpdm_aget(widget_list, n);
315 wchar_t *type;
316 mpdm_t t;
317 QLabel *ql = new QLabel("");
319 type = mpdm_string(mpdm_hget_s(w, L"type"));
321 if ((t = mpdm_hget_s(w, L"label")) != NULL) {
322 ql->setText(str_to_qstring(mpdm_gettext(t)));
325 t = mpdm_hget_s(w, L"value");
327 if (wcscmp(type, L"text") == 0) {
328 mpdm_t h;
329 QComboBox *qc = new QComboBox();
331 qc->setEditable(true);
332 qc->setMinimumContentsLength(30);
333 qc->setMaxVisibleItems(8);
335 if (t != NULL)
336 qc->setEditText(str_to_qstring(t));
338 qlist[n] = qc;
340 if ((h = mpdm_hget_s(w, L"history")) != NULL) {
341 int i;
343 /* has history; fill it */
344 h = mp_get_history(h);
346 for (i = mpdm_size(h) - 1; i >= 0; i--)
347 qc->addItem(str_to_qstring(mpdm_aget(h, i)));
350 /* select all the editable field */
351 qc->lineEdit()->selectAll();
353 fl->addRow(ql, qc);
355 else
356 if (wcscmp(type, L"password") == 0) {
357 QLineEdit *qe = new QLineEdit();
359 qe->setEchoMode(QLineEdit::Password);
361 qlist[n] = qe;
363 fl->addRow(ql, qe);
365 else
366 if (wcscmp(type, L"checkbox") == 0) {
367 QCheckBox *qc = new QCheckBox();
369 if (mpdm_ival(t))
370 qc->setCheckState(Qt::Checked);
372 qlist[n] = qc;
374 fl->addRow(ql, qc);
376 else
377 if (wcscmp(type, L"list") == 0) {
378 int i;
379 QListWidget *qlw = new QListWidget();
380 qlw->setMinimumWidth(480);
382 /* use a monospaced font */
383 qlw->setFont(QFont(QString("Mono")));
385 mpdm_t l = mpdm_hget_s(w, L"list");
387 for (i = 0; i < mpdm_size(l); i++)
388 qlw->addItem(str_to_qstring(mpdm_aget(l, i)));
390 qlw->setCurrentRow(mpdm_ival(t));
392 qlist[n] = qlw;
394 fl->addRow(ql, qlw);
397 if (n == 0)
398 qlist[n]->setFocus(Qt::OtherFocusReason);
401 form->setLayout(fl);
403 QVBoxLayout *ml = new QVBoxLayout();
404 ml->addWidget(form);
405 ml->addWidget(dialog->button_box);
407 dialog->setLayout(ml);
409 n = dialog->exec();
411 if (!n)
412 return NULL;
414 r = MPDM_A(mpdm_size(widget_list));
415 mpdm_ref(r);
417 /* fill the return values */
418 for (n = 0; n < mpdm_size(widget_list); n++) {
419 mpdm_t w = mpdm_aget(widget_list, n);
420 mpdm_t v = NULL;
421 wchar_t *type;
423 type = mpdm_string(mpdm_hget_s(w, L"type"));
425 if (wcscmp(type, L"text") == 0) {
426 mpdm_t h;
427 QComboBox *ql = (QComboBox *) qlist[n];
429 v = mpdm_ref(qstring_to_str(ql->currentText()));
431 /* if it has history, add to it */
432 if ((h = mpdm_hget_s(w, L"history")) != NULL &&
433 v != NULL && mpdm_cmp_s(v, L"") != 0) {
434 h = mp_get_history(h);
436 if (mpdm_cmp(v, mpdm_aget(h, -1)) != 0)
437 mpdm_push(h, v);
440 mpdm_unrefnd(v);
442 else
443 if (wcscmp(type, L"password") == 0) {
444 QLineEdit *ql = (QLineEdit *) qlist[n];
446 v = qstring_to_str(ql->text());
448 else
449 if (wcscmp(type, L"checkbox") == 0) {
450 QCheckBox *qb = (QCheckBox *) qlist[n];
452 v = MPDM_I(qb->checkState() == Qt::Checked);
454 else
455 if (wcscmp(type, L"list") == 0) {
456 QListWidget *ql = (QListWidget *) qlist[n];
458 v = MPDM_I(ql->currentRow());
461 mpdm_aset(r, v, n);
464 mpdm_unrefnd(r);
466 return r;
470 static void register_functions(void)
472 mpdm_t drv;
474 drv = mpdm_hget_s(mp, L"drv");
475 mpdm_hset_s(drv, L"main_loop", MPDM_X(qt4_drv_main_loop));
476 mpdm_hset_s(drv, L"shutdown", MPDM_X(qt4_drv_shutdown));
477 mpdm_hset_s(drv, L"clip_to_sys", MPDM_X(qt4_drv_clip_to_sys));
478 mpdm_hset_s(drv, L"sys_to_clip", MPDM_X(qt4_drv_sys_to_clip));
479 mpdm_hset_s(drv, L"update_ui", MPDM_X(qt4_drv_update_ui));
480 mpdm_hset_s(drv, L"timer", MPDM_X(qt4_drv_timer));
481 mpdm_hset_s(drv, L"busy", MPDM_X(qt4_drv_busy));
482 mpdm_hset_s(drv, L"alert", MPDM_X(qt4_drv_alert));
483 mpdm_hset_s(drv, L"confirm", MPDM_X(qt4_drv_confirm));
484 mpdm_hset_s(drv, L"openfile", MPDM_X(qt4_drv_openfile));
485 mpdm_hset_s(drv, L"savefile", MPDM_X(qt4_drv_savefile));
486 mpdm_hset_s(drv, L"form", MPDM_X(qt4_drv_form));
490 static mpdm_t qt4_drv_startup(mpdm_t a, mpdm_t ctxt)
491 /* driver initialization */
493 register_functions();
495 build_font(1);
496 build_colors();
498 window = new MPWindow();
499 window->show();
501 return NULL;
504 extern "C" Display * XOpenDisplay(char *);
506 extern "C" int qt4_drv_detect(int *argc, char ***argv)
508 mpdm_t drv;
509 Display *x11_display;
510 int n;
512 for (n = 0; n < *argc; n++) {
513 if (strcmp(argv[0][n], "-txt") == 0 ||
514 strcmp(argv[0][n], "-h") == 0)
515 return 0;
518 /* try connecting directly to the Xserver */
519 if ((x11_display = XOpenDisplay((char *) NULL)) == NULL)
520 return 0;
522 /* this is where it crashes if no X server */
523 app = new QApplication(x11_display);
525 drv = mpdm_hget_s(mp, L"drv");
526 mpdm_hset_s(drv, L"id", MPDM_LS(L"qt4"));
527 mpdm_hset_s(drv, L"startup", MPDM_X(qt4_drv_startup));
529 return 1;
532 #include "mpv_qt4.moc"