/*************************************************************************** main.cpp The interface between the QT plug-in and the Gambas interpreter (c) 2000-2007 Benoit Minisini 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #define __MAIN_CPP #include #include #include #include #include #include #include "gambas.h" #define QT_THREAD_SUPPORT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x030100 #include #endif #include "gb.qt.h" #include "CFont.h" #include "CScreen.h" #include "CWidget.h" #include "CWindow.h" #include "CButton.h" #include "CContainer.h" #include "CLabel.h" #include "CListBox.h" #include "CTextBox.h" #include "CTextArea.h" #include "CPictureBox.h" #include "CMenu.h" #include "CPanel.h" #include "CMouse.h" #include "CKey.h" #include "CColor.h" #include "CConst.h" #include "CCheckBox.h" #include "CFrame.h" #include "CRadioButton.h" #include "CTreeView.h" #include "CIconView.h" #include "CGridView.h" #include "CTabStrip.h" #include "CDialog.h" #include "CPicture.h" #include "CImage.h" #include "CClipboard.h" #include "CDraw.h" #include "CWatch.h" #include "CScrollView.h" #include "CDrawingArea.h" #include "CProgress.h" #include "CMessage.h" #include "CSlider.h" #include "CScrollBar.h" #include "CMovieBox.h" #include "CSpinBox.h" #include "CSplitter.h" #include "CWatcher.h" #ifndef NO_X_WINDOW #include "CEmbedder.h" #include "CTrayIcon.h" #include "x11.h" #endif #include "main.h" /*#define DEBUG*/ extern "C" { GB_INTERFACE GB EXPORT; } int MAIN_in_wait = 0; int MAIN_loop_level = 0; int MAIN_scale = 8; #ifndef NO_X_WINDOW int MAIN_x11_last_key_code = 0; #endif static bool in_event_loop = false; static int _no_destroy = 0; static QTranslator *qt = NULL; static GB_FUNCTION _application_keypress_func; static QWidget *_mouseGrabber = 0; static QWidget *_keyboardGrabber = 0; /*************************************************************************** MyMimeSourceFactory Create a QMimeSourceFactory to handle files stored in an archive ***************************************************************************/ class MyMimeSourceFactory: public QMimeSourceFactory { public: MyMimeSourceFactory(); virtual const QMimeSource* data(const QString& abs_name) const; private: QMap extensions; }; MyMimeSourceFactory::MyMimeSourceFactory() { extensions.replace("htm", "text/html;charset=UTF-8"); extensions.replace("html", "text/html;charset=UTF-8"); extensions.replace("txt", "text/plain"); extensions.replace("xml", "text/xml;charset=UTF-8"); extensions.replace("jpg", "image/jpeg"); extensions.replace("png", "image/png"); extensions.replace("gif", "image/gif"); } const QMimeSource* MyMimeSourceFactory::data(const QString& abs_name) const { char *addr; int len; QStoredDrag* sr = 0; char *path; //qDebug("MyMimeSourceFactory::data: %s", (char *)abs_name.latin1()); path = (char *)abs_name.latin1(); if (true) //abs_name[0] != '/') { if (GB.LoadFile(path, 0, &addr, &len)) GB.Error(NULL); else { QByteArray ba; ba.setRawData((const char *)addr, len); QFileInfo fi(abs_name); QString e = fi.extension(FALSE); QCString mimetype = "text/html"; //"application/octet-stream"; const char* imgfmt; if ( extensions.contains(e) ) mimetype = extensions[e].latin1(); else { QBuffer buffer(ba); buffer.open(IO_ReadOnly); if (( imgfmt = QImageIO::imageFormat( &buffer ) ) ) mimetype = QCString("image/")+QCString(imgfmt).lower(); buffer.close(); } sr = new QStoredDrag( mimetype ); sr->setEncodedData( ba ); ba.resetRawData((const char*)addr, len); //qDebug("MimeSource: %s %s", abs_name.latin1(), (const char *)mimetype); GB.ReleaseFile(&addr, len); } } return sr; } static MyMimeSourceFactory myMimeSourceFactory; /*************************************************************************** MyEventLoop Manage window deletion ***************************************************************************/ class MyEventLoop : public QEventLoop { public: MyEventLoop(); virtual bool processEvents( ProcessEventsFlags flags ); }; MyEventLoop::MyEventLoop() : QEventLoop() { } bool MyEventLoop::processEvents(ProcessEventsFlags flags) { bool ret; CWIDGET **ptr; CWIDGET *ob; MAIN_loop_level++; ret = QEventLoop::processEvents(flags); MAIN_loop_level--; if (_no_destroy) return ret; for(;;) { ptr = &CWIDGET_destroy_list; for(;;) { ob = *ptr; if (!ob) return ret; //if (MAIN_loop_level <= ob->level && !ob->flag.notified) if (!ob->flag.notified) { //qDebug("delete: %s %p", GB.GetClassName(ob), ob); //qDebug(">> delete %p (%p) :%p:%ld", ob, ob->widget, ob->ob.klass, ob->ob.ref); //*ptr = ob->next; delete ob->widget; break; //GB.Unref(POINTER(&ob)); //qDebug(" delete %p (%p) :%p:%ld #2", ob, ob->widget, ob->ob.klass, ob->ob.ref); //qDebug("<< delete %p (%p)", ob, ob->widget); } else { //qDebug("cannot delete: %s %p", GB.GetClassName(ob), ob); ptr = &ob->next; } } } //return ret; } void MAIN_process_events(void) { _no_destroy++; qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput, 0); _no_destroy--; } /** MyApplication **********************************************************/ MyApplication::MyApplication(int &argc, char **argv) : QApplication(argc, argv) { } static bool QT_EventFilter(QEvent *e) { QKeyEvent *kevent = (QKeyEvent *)e; bool cancel; CKEY_clear(true); GB.FreeString(&CKEY_info.text); GB.NewString(&CKEY_info.text, QT_ToUTF8(kevent->text()), 0); CKEY_info.state = kevent->state(); CKEY_info.code = kevent->key(); GB.Call(&_application_keypress_func, 0, FALSE); cancel = GB.Stopped(); CKEY_clear(false); return cancel; } static bool QT_Notify(CWIDGET *object, bool value) { bool old = object->flag.notified; //qDebug("QT_Notify: %s %p %d", GB.GetClassName(object), object, value); object->flag.notified = value; return old; } bool MyApplication::eventFilter(QObject *o, QEvent *e) { if (o->isWidgetType() && e->type() == QEvent::KeyPress) { if (QT_EventFilter(e)) return true; } return QObject::eventFilter(o, e); } bool MyApplication::notify(QObject *o, QEvent *e) { if (o->isWidgetType()) { CWIDGET *ob = CWidget::get(o); bool old, res; if (ob) { old = QT_Notify(ob, true); res = QApplication::notify(o, e); QT_Notify(ob, old); return res; } } return QApplication::notify(o, e); } #ifndef NO_X_WINDOW // Workaround for input methods that void the key code of KeyRelease eventFilter bool MyApplication::x11EventFilter(XEvent *e) { if (e->type == XKeyPress) MAIN_x11_last_key_code = e->xkey.keycode; else if (e->type == XKeyRelease) MAIN_x11_last_key_code = e->xkey.keycode; return false; } #endif /** MyTimer ****************************************************************/ MyTimer::MyTimer(GB_TIMER *t) : QObject(0) { timer = t; id = startTimer(t->delay); } MyTimer::~MyTimer() { killTimer(id); } void MyTimer::timerEvent(QTimerEvent *e) { GB.RaiseTimer(timer); } /***************************************************************************/ static void release_grab() { _mouseGrabber = QWidget::mouseGrabber(); _keyboardGrabber = QWidget::keyboardGrabber(); if (_mouseGrabber) { //qDebug("releaseMouse"); _mouseGrabber->releaseMouse(); } if (_keyboardGrabber) { //qDebug("releaseKeyboard"); _keyboardGrabber->releaseKeyboard(); } #ifndef NO_X_WINDOW if (qApp->activePopupWidget()) { QWidget *popup = qApp->activePopupWidget(); XUngrabPointer(popup->x11Display(), CurrentTime); XFlush(popup->x11Display()); } #endif } static void unrelease_grab() { if (_mouseGrabber) { //qDebug("grabMouse"); _mouseGrabber->grabMouse(); _mouseGrabber = 0; } if (_keyboardGrabber) { //qDebug("grabKeyboard"); _keyboardGrabber->grabKeyboard(); _keyboardGrabber = 0; } } static bool must_quit(void) { return CWindow::count == 0 && CWatch::count == 0 && in_event_loop; } static void check_quit_now(intptr_t param) { if (must_quit()) { #ifndef NO_X_WINDOW CTRAYICON_close_all(); qApp->syncX(); #endif qApp->exit(); } } void MAIN_check_quit(void) { GB.Post((GB_POST_FUNC)check_quit_now, 0); } void MAIN_update_scale(void) { QFontMetrics fm(QApplication::font()); MAIN_scale = fm.height() / 2; } static void QT_InitEventLoop(void) { new MyEventLoop(); } static void QT_Init(void) { static bool init = false; QFont f; if (init) return; #ifndef NO_X_WINDOW X11_init(QPaintDevice::x11AppDisplay(), QPaintDevice::x11AppRootWindow()); #endif /*fcntl(ConnectionNumber(qt_xdisplay()), F_SETFD, FD_CLOEXEC);*/ QMimeSourceFactory::addFactory(&myMimeSourceFactory); MAIN_update_scale(); if (GB.GetFunction(&_application_keypress_func, GB.FindClass(GB.Application.Startup()), "Application_KeyPress", "", "") == 0) qApp->installEventFilter(qApp); qApp->installEventFilter(&CWidget::manager); QStyleSheet::defaultSheet()->item("tt")->setFontFamily("Monospace"); QStyleSheet::defaultSheet()->item("pre")->setFontFamily("Monospace"); init = true; } static QString _init_lang; static bool _init_rtl; static void init_lang(QString locale, bool rtl) { qt = new QTranslator(); qt->load(QString( "qt_") + locale, QString(getenv("QTDIR")) + "/translations"); qApp->installTranslator(qt); if (rtl) qApp->setReverseLayout(true); } static void hook_lang(char *lang, int rtl) { QString locale(lang); if (!qApp) { _init_lang = locale; _init_rtl = rtl; return; } init_lang(locale, rtl); //locale = QTextCodec::locale(); } static void hook_main(int *argc, char **argv) { new MyApplication(*argc, argv); #if QT_VERSION <= 0x030005 qApp->unlock(); #endif //qApp->setStyle("windows"); QT_Init(); init_lang(_init_lang, _init_rtl); } static void hook_loop() { in_event_loop = true; if (!must_quit()) qApp->exec(); else MAIN_check_quit(); //qDebug("Exit event loop"); } static void hook_wait(int duration) { MAIN_in_wait++; #if QT_VERSION >= 0x030100 if (duration > 0) qApp->eventLoop()->processEvents(QEventLoop::AllEvents, duration); else qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput, duration); #else qApp->processEvents(duration); #endif MAIN_in_wait--; } static void hook_timer(GB_TIMER *timer, bool on) { if (timer->id) { delete (MyTimer *)(timer->id); timer->id = 0; } if (on) timer->id = (intptr_t)(new MyTimer(timer)); } static void hook_watch(int fd, int type, void *callback, intptr_t param) { CWatch::watch(fd, type, (GB_WATCH_CALLBACK)callback, param); } static void hook_post(void) { static MyPostCheck check; //qDebug("hook_post ?"); if (MyPostCheck::in_check) return; //qDebug("hook_post !"); MyPostCheck::in_check = true; QTimer::singleShot(0, &check, SLOT(check())); } static void hook_quit() { QWidgetList *list; QWidget *w; //qApp->closeAllWindows(); list = QApplication::topLevelWidgets(); w = list->first(); while (w) { //QApplication::postEvent(list->first(), new QEvent(EVENT_CLOSE)); w->close(); w = list->next(); } delete list; } static void hook_error(int code, char *error, char *where) { QString msg; qApp->restoreOverrideCursor(); while (qApp->activePopupWidget()) delete qApp->activePopupWidget(); CWatch::stop(); qApp->exit(); msg = "This application has raised an unexpected
error and must abort.


"; if (code > 0) { msg = msg + "[%1] %2.
%3"; msg = msg.arg(code).arg(error).arg(where); } else { msg = msg + "%1.
%2"; msg = msg.arg(error).arg(where); } release_grab(); QMessageBox::critical(0, TO_QSTRING(GB.Application.Name()), msg); unrelease_grab(); } static int hook_image(CIMAGE **pimage, GB_IMAGE_INFO *info) //void **pdata, int width, int height, int format) { CIMAGE *image = *pimage; QImage *img; if (!image) { img = new QImage(info->width, info->height, 32); img->setAlphaBuffer(GB_IMAGE_TRANSPARENT(info->format)); if (info->data) GB.Image.Convert(img->bits(), GB_IMAGE_BGRA, info->data, info->format, info->width, info->height); GB.New(POINTER(&image), GB.FindClass("Image"), NULL, NULL); delete image->image; image->image = img; *pimage = image; } else { info->data = image->image->bits(); info->width = image->image->width(); info->height = image->image->height(); info->format = image->image->hasAlphaBuffer() ? GB_IMAGE_BGRA : GB_IMAGE_BGRX; } return 0; } static int hook_picture(CPICTURE **ppicture, GB_PICTURE_INFO *info) { CPICTURE *picture = *ppicture; QImage *img; if (!picture) { if (info->format == GB_IMAGE_BGRA || info->format == GB_IMAGE_BGRX) img = new QImage((uchar *)info->data, info->width, info->height, 32, NULL, 0, QImage::LittleEndian); else { img = new QImage(info->width, info->height, 32); GB.Image.Convert(img->bits(), GB_IMAGE_BGRA, info->data, info->format, info->width, info->height); } img->setAlphaBuffer(info->format == GB_IMAGE_BGRA || info->format == GB_IMAGE_ARGB); GB.New(POINTER(&picture), GB.FindClass("Picture"), NULL, NULL); delete picture->pixmap; picture->pixmap = new QPixmap(*img); delete img; *ppicture = picture; } else { info->data = NULL; info->format = GB_IMAGE_BGRA; info->width = picture->pixmap->width(); info->height = picture->pixmap->height(); } return 0; } static void QT_InitWidget(QWidget *widget, void *object) { CWIDGET_new(widget, object); } static void *QT_GetObject(QWidget *widget) { return CWidget::get((QObject *)widget); } static QWidget *QT_GetContainer(void *object) { return QCONTAINER(object); } /*static bool QT_IsDestroyed(void *object) { return CWIDGET_test_flag(object, WF_DELETED); }*/ static QPixmap *QT_GetPixmap(CPICTURE *pict) { return pict->pixmap; } QMimeSourceFactory *QT_MimeSourceFactory(void) { return &myMimeSourceFactory; } const char *QT_ToUTF8(const QString &str) { static QCString buf[UTF8_NBUF]; static int cpt = 0; const char *res; buf[cpt] = str.utf8(); res = (const char *)buf[cpt]; cpt++; if (cpt >= UTF8_NBUF) cpt = 0; return res; } static void QT_CreateFont(const QFont &f, FONT_FUNC func, void *object) { CFONT_create(f, func, object); } static void *QT_GetDrawInterface() { return (void *)&DRAW_Interface; } extern "C" { GB_DESC *GB_CLASSES[] EXPORT = { CBorderDesc, CColorDesc, CColorInfoDesc, CAlignDesc, CArrangeDesc, CScrollDesc, CKeyDesc, CLineDesc, CFillDesc, CSelectDesc, CMessageDesc, CPictureDesc, CImageDesc, CFontDesc, CFontsDesc, CMouseDesc, CCursorDesc, CClipboardDesc, CDragDesc, CDesktopDesc, CApplicationTooltipDesc, CApplicationDesc, CControlDesc, CChildrenDesc, CContainerDesc, CUserControlDesc, CUserContainerDesc, CMenuChildrenDesc, CMenuDesc, CLabelDesc, CTextLabelDesc, CPictureBoxDesc, CSeparatorDesc, CButtonDesc, CToggleButtonDesc, CToolButtonDesc, CCheckBoxDesc, CRadioButtonDesc, CTextBoxSelectionDesc, CTextBoxDesc, CComboBoxItemDesc, CComboBoxDesc, CTextAreaSelectionDesc, CTextAreaDesc, CListBoxItemDesc, CListBoxDesc, CListViewItemDesc, CListViewDesc, CTreeViewItemDesc, CTreeViewDesc, CColumnViewItemDesc, CColumnViewColumnDesc, CColumnViewColumnsDesc, CColumnViewDesc, CIconViewItemDesc, CIconViewDesc, CGridItemDesc, CGridRowDesc, CGridColumnDesc, CGridRowsDesc, CGridColumnsDesc, CGridViewDataDesc, CGridViewDesc, CFrameDesc, CPanelDesc, CHBoxDesc, CVBoxDesc, CHPanelDesc, CVPanelDesc, CHSplitDesc, CVSplitDesc, CTabChildrenDesc, CTabDesc, CTabStripDesc, CScrollViewDesc, CDrawingAreaDesc, CProgressDesc, CSliderDesc, CSpinBoxDesc, CMovieBoxDesc, CScrollBarDesc, CWindowMenusDesc, CWindowControlsDesc, CWindowDesc, CWindowsDesc, CFormDesc, CDialogDesc, #ifndef NO_X_WINDOW CEmbedderDesc, CTrayIconDesc, CTrayIconsDesc, #endif CWatcherDesc, NULL }; void *GB_QT_1[] EXPORT = { (void *)1, (void *)QT_InitEventLoop, (void *)QT_Init, (void *)QT_InitWidget, (void *)QT_GetObject, (void *)QT_GetContainer, (void *)CWIDGET_border_simple, (void *)CWIDGET_border_full, (void *)CWIDGET_scrollbar, (void *)CCONTROL_font, (void *)QT_CreateFont, (void *)QT_MimeSourceFactory, (void *)QT_GetPixmap, (void *)QT_ToUTF8, (void *)QT_EventFilter, (void *)QT_Notify, (void *)QT_GetDrawInterface, (void *)CCONST_alignment, NULL }; #if QT_VERSION >= 0x030304 static void myMessageHandler(QtMsgType type, const char *msg ) { if ((::strncmp(msg, "QMultiInputContext::", strlen("QMultiInputContext::")) == 0) || (::strncmp(msg, "sending IM", strlen("sending IM")) == 0) || (::strncmp(msg, "receiving IM", strlen("receiving IM")) == 0) || (::strncmp(msg, "QInputContext: ", strlen("QInputContext: ")) == 0)) return; fprintf(stderr, "%s\n", msg); if (type == QtFatalMsg) abort(); } #endif const char *GB_INCLUDE EXPORT = "gb.draw"; int EXPORT GB_INIT(void) { #if QT_VERSION >= 0x030304 qInstallMsgHandler(myMessageHandler); #endif GB.Hook(GB_HOOK_MAIN, (void *)hook_main); GB.Hook(GB_HOOK_LOOP, (void *)hook_loop); GB.Hook(GB_HOOK_WAIT, (void *)hook_wait); GB.Hook(GB_HOOK_TIMER, (void *)hook_timer); GB.Hook(GB_HOOK_WATCH, (void *)hook_watch); GB.Hook(GB_HOOK_POST, (void *)hook_post); GB.Hook(GB_HOOK_QUIT, (void *)hook_quit); GB.Hook(GB_HOOK_ERROR, (void *)hook_error); GB.Hook(GB_HOOK_LANG, (void *)hook_lang); GB.Hook(GB_HOOK_IMAGE, (void *)hook_image); GB.Hook(GB_HOOK_PICTURE, (void *)hook_picture); GB.LoadComponent("gb.draw"); DRAW_init(); CLASS_Control = GB.FindClass("Control"); CLASS_Container = GB.FindClass("Container"); CLASS_UserControl = GB.FindClass("UserControl"); CLASS_UserContainer = GB.FindClass("UserContainer"); CLASS_Window = GB.FindClass("Window"); CLASS_Menu = GB.FindClass("Menu"); CLASS_Picture = GB.FindClass("Picture"); CLASS_Drawing = GB.FindClass("Drawing"); CLASS_DrawingArea = GB.FindClass("DrawingArea"); CLASS_Printer = GB.FindClass("Printer"); QT_InitEventLoop(); return TRUE; } void EXPORT GB_EXIT() { #ifndef NO_X_WINDOW X11_exit(); #endif //qApp->setStyle("windows"); delete qApp; } #ifndef NO_X_WINDOW int EXPORT GB_INFO(const char *key, void **value) { if (!strcasecmp(key, "DISPLAY")) { *value = (void *)QPaintDevice::x11AppDisplay(); return TRUE; } else if (!strcasecmp(key, "ROOT_WINDOW")) { *value = (void *)QPaintDevice::x11AppRootWindow(); return TRUE; } else return FALSE; } #endif #ifndef NO_X_WINDOW extern Time qt_x_time; #endif static void activate_main_window(int value) { CWINDOW *active; active = CWINDOW_Active; if (!active) active = CWINDOW_LastActive; if (!active) return; MyMainWindow *win = (MyMainWindow *)active->widget.widget; if (win && !win->isTopLevel()) win = (MyMainWindow *)win->topLevelWidget(); if (win) { #ifndef NO_X_WINDOW qt_x_time = CurrentTime; #endif win->raise(); win->setActiveWindow(); } } void EXPORT GB_SIGNAL(int signal, void *param) { switch(signal) { case GB_SIGNAL_DEBUG_BREAK: release_grab(); break; case GB_SIGNAL_DEBUG_FORWARD: //while (qApp->activePopupWidget()) // delete qApp->activePopupWidget(); qApp->syncX(); break; case GB_SIGNAL_DEBUG_CONTINUE: GB.Post((GB_POST_FUNC)activate_main_window, 0); unrelease_grab(); break; } } } // extern "C" /* class MyPostCheck */ bool MyPostCheck::in_check = false; void MyPostCheck::check(void) { //qDebug("MyPostCheck::check"); in_check = false; GB.CheckPost(); }