/* kxt.cpp - Xt enabled Qt classed (derived from Qt Extension QXt) Copyright (c) 2000,2001 Stefan Schimanski <1Stein@gmx.de> 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. */ /**************************************************************************** ** ** Implementation of Qt extension classes for Xt/Motif support. ** ** Created : 980107 ** ** Copyright (C) 1992-2000 Troll Tech AS. All rights reserved. ** ** This file is part of the Qt GUI Toolkit. ** ** This file may be distributed under the terms of the Q Public License ** as defined by Troll Tech AS of Norway and appearing in the file ** LICENSE.QPL included in the packaging of this file. ** ** Licensees holding valid Qt Professional Edition licenses may use this ** file in accordance with the Qt Professional Edition License Agreement ** provided with the Qt Professional Edition. ** ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for ** information about the Professional Edition licensing, or see ** http://www.trolltech.com/qpl/ for QPL licensing information. ** *****************************************************************************/ #include <tqglobal.h> #if QT_VERSION < 0x030100 #include <kapplication.h> #include <tqwidget.h> #include <tqobjectlist.h> #include <tqwidgetlist.h> #include <kdebug.h> #include <tqtimer.h> #include "kxt.h" #include <stdio.h> #include <string.h> #include <time.h> #include <limits.h> #include <X11/Xlib.h> #include <X11/Intrinsic.h> #include <X11/IntrinsicP.h> // for XtCreateWindow #include <X11/Shell.h> #include <X11/StringDefs.h> #include <X11/Xutil.h> #include <X11/Xos.h> const int XKeyPress = KeyPress; const int XKeyRelease = KeyRelease; #undef KeyPress #undef KeyRelease extern Atom qt_wm_state; //#define HAVE_MOTIF #ifdef HAVE_MOTIF #include <Xm/Xm.h> #endif typedef void (*SameAsXtTimerCallbackProc)(void*,void*); typedef void (*IntervalSetter)(int); typedef void (*ForeignEventProc)(XEvent*); extern XtEventDispatchProc qt_np_cascade_event_handler[LASTEvent]; // defined in qnpsupport.cpp void qt_reset_color_avail(); // defined in qcolor_x11.cpp int qt_activate_timers(); // defined in qapplication_x11.cpp timeval *qt_wait_timer(); // defined in qapplication_x11.cpp void qt_x11SendPostedEvents(); // defined in qapplication_x11.cpp int qt_event_handler( XEvent* event ); // defined in qnpsupport.cpp extern int qt_np_count; // defined in qnpsupport.cpp void qt_np_timeout( void* p, void* id ); // defined in qnpsupport.cpp void qt_np_add_timeoutcb( SameAsXtTimerCallbackProc cb ); // defined in qnpsupport.cpp void qt_np_remove_timeoutcb( SameAsXtTimerCallbackProc cb ); // defined in qnpsupport.cpp void qt_np_add_timer_setter( IntervalSetter is ); // defined in qnpsupport.cpp void qt_np_remove_timer_setter( IntervalSetter is ); // defined in qnpsupport.cpp extern XtIntervalId qt_np_timerid; // defined in qnpsupport.cpp extern void (*qt_np_leave_cb) (XLeaveWindowEvent*); // defined in qnpsupport.cpp void qt_np_add_event_proc( ForeignEventProc fep ); // defined in qnpsupport.cpp void qt_np_remove_event_proc( ForeignEventProc fep ); // defined in qnpsupport.cpp typedef struct { int empty; } QWidgetClassPart; typedef struct _QWidgetClassRec { CoreClassPart core_class; QWidgetClassPart qwidget_class; } QWidgetClassRec; //static QWidgetClassRec qwidgetClassRec; typedef struct { /* resources */ /* (none) */ /* private state */ KXtWidget* qxtwidget; } QWidgetPart; typedef struct _QWidgetRec { CorePart core; QWidgetPart qwidget; } QWidgetRec; static void reparentChildrenOf(TQWidget* parent) { if ( !parent->children() ) return; // nothing to do for ( TQObjectListIt it( *parent->children() ); it.current(); ++it ) { if ( it.current()->isWidgetType() ) { TQWidget* widget = (TQWidget*)it.current(); XReparentWindow( qt_xdisplay(), widget->winId(), parent->winId(), widget->x(), widget->y() ); if ( widget->isVisible() ) XMapWindow( qt_xdisplay(), widget->winId() ); } } } void qwidget_realize( Widget widget, XtValueMask* mask, XSetWindowAttributes* attributes ) { widgetClassRec.core_class.realize(widget, mask, attributes); KXtWidget* qxtw = ((QWidgetRec*)widget)->qwidget.qxtwidget; if (XtWindow(widget) != qxtw->winId()) { qxtw->create(XtWindow(widget), FALSE, FALSE); reparentChildrenOf(qxtw); } qxtw->show(); XMapWindow( qt_xdisplay(), qxtw->winId() ); } static QWidgetClassRec qwidgetClassRec = { { /* core fields */ /* superclass */ (WidgetClass) &widgetClassRec, /* class_name */ (char*)"TQWidget", /* widget_size */ sizeof(QWidgetRec), /* class_initialize */ 0, /* class_part_initialize */ 0, /* class_inited */ FALSE, /* initialize */ 0, /* initialize_hook */ 0, /* realize */ qwidget_realize, /* actions */ 0, /* num_actions */ 0, /* resources */ 0, /* num_resources */ 0, /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ 0, /* resize */ XtInheritResize, /* expose */ XtInheritExpose, /* set_values */ 0, /* set_values_hook */ 0, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ 0, /* accept_focus */ XtInheritAcceptFocus, /* version */ XtVersion, /* callback_private */ 0, /* tm_table */ XtInheritTranslations, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ 0 }, { /* qwidget fields */ /* empty */ 0 } }; static WidgetClass qWidgetClass = (WidgetClass)&qwidgetClassRec; static bool filters_installed = FALSE; static KXtApplication* qxtapp = 0; static XtAppContext appcon; static Boolean qt_event_handler_wrapper( XEvent* event ) { return (Boolean)qt_event_handler( event ); } static void installXtEventFilters() { if (filters_installed) return; // Get Xt out of our face - install filter on every event type for (int et=2; et < LASTEvent; et++) { qt_np_cascade_event_handler[et] = XtSetEventDispatcher( qt_xdisplay(), et, qt_event_handler_wrapper ); } filters_installed = TRUE; } static void removeXtEventFilters() { if (!filters_installed) return; // We aren't needed any more... slink back into the shadows. for (int et=2; et < LASTEvent; et++) { XtSetEventDispatcher( qt_xdisplay(), et, qt_np_cascade_event_handler[et] ); } filters_installed = FALSE; } // When we are in an event loop of TQApplication rather than the browser's // event loop (eg. for a modal dialog), we still send events to Xt. static void np_event_proc( XEvent* e ) { Widget xtw = XtWindowToWidget( e->xany.display, e->xany.window ); if ( xtw && qApp->loopLevel() > 0 ) { // Allow Xt to process the event qt_np_cascade_event_handler[e->type]( e ); } } static void np_set_timer( int interval ) { // Ensure we only have one timeout in progress - TQApplication is // computing the one amount of time we need to wait. if ( qt_np_timerid ) { XtRemoveTimeOut( qt_np_timerid ); } qt_np_timerid = XtAppAddTimeOut(appcon, interval, (XtTimerCallbackProc)qt_np_timeout, 0); } static void np_do_timers( void*, void* ) { qt_np_timerid = 0; // It's us, and we just expired, that's why we are here. qt_activate_timers(); timeval *tm = qt_wait_timer(); if (tm) { int interval = QMIN(tm->tv_sec,INT_MAX/1000)*1000 + tm->tv_usec/1000; np_set_timer( interval ); } qxtapp->sendPostedEvents(); } /*! \class KXtApplication qxt.h \brief Allows mixing of Xt/Motif and Qt widgets. \extension Xt/Motif The KXtApplication and KXtWidget classes allow old Xt or Motif widgets to be used in new Qt applications. They also allow Qt widgets to be used in primarily Xt/Motif applications. The facility is intended to aid migration from Xt/Motif to the more comfortable Qt system. */ static bool my_xt; /*! Constructs a TQApplication and initializes the Xt toolkit. The \a appclass, \a options, \a num_options, and \a resources arguments are passed on to XtAppSetFallbackResources and XtDisplayInitialize. Use this constructor when writing a new Qt application which needs to use some existing Xt/Motif widgets. */ KXtApplication::KXtApplication(int& argc, char** argv, const TQCString& rAppName, bool allowStyles, bool GUIenabled, XrmOptionDescRec *options, int num_options, char** resources) : KApplication(argc, argv, rAppName, allowStyles, GUIenabled) { my_xt = TRUE; XtToolkitInitialize(); appcon = XtCreateApplicationContext(); if (resources) XtAppSetFallbackResources(appcon, (char**)resources); XtDisplayInitialize(appcon, qt_xdisplay(), name(), rAppName, options, num_options, &argc, argv); init(); } /*! Constructs a TQApplication from the \a display of an already-initialized Xt application. Use this constructor when introducing Qt widgets into an existing Xt/Motif application. */ KXtApplication::KXtApplication(Display* dpy, int& argc, char** argv, const TQCString& rAppName, bool allowStyles, bool GUIenabled) : KApplication(dpy, argc, argv, rAppName, allowStyles, GUIenabled) { my_xt = FALSE; init(); appcon = XtDisplayToApplicationContext(dpy); } /*! Destructs the application. Does not close the Xt toolkit. */ KXtApplication::~KXtApplication() { Q_ASSERT(qxtapp==this); removeXtEventFilters(); qxtapp = 0; // the manpage says: "or just exit", that's what we do to avoid // double closing of the display // if (my_xt) { // XtDestroyApplicationContext(appcon); // } } void KXtApplication::init() { Q_ASSERT(qxtapp==0); qxtapp = this; installXtEventFilters(); qt_np_add_timeoutcb(np_do_timers); qt_np_add_timer_setter(np_set_timer); qt_np_add_event_proc(np_event_proc); qt_np_count++; /* TQTimer *timer = new TQTimer( this ); timer->start(500);*/ } /*! \class KXtWidget qxt.h \brief Allows mixing of Xt/Motif and Qt widgets. \extension Xt/Motif KXtWidget acts as a bridge between Xt and Qt. For utilizing old Xt widgets, it can be a QWidget based on a Xt widget class. For including Qt widgets in an existing Xt/Motif application, it can be a special Xt widget class that is a TQWidget. See the constructors for the different behaviors. */ void KXtWidget::init(const char* name, WidgetClass widget_class, Widget parent, TQWidget* qparent, ArgList args, Cardinal num_args, bool managed) { need_reroot=FALSE; xtparent = 0; if (parent ) { Q_ASSERT(!qparent); xtw = XtCreateWidget(name, widget_class, parent, args, num_args); if ( widget_class == qWidgetClass ) ((QWidgetRec*)xtw)->qwidget.qxtwidget = this; xtparent = parent; if (managed) XtManageChild(xtw); } else { Q_ASSERT(!managed); String n, c; XtGetApplicationNameAndClass(qt_xdisplay(), &n, &c); xtw = XtAppCreateShell(n, c, widget_class, qt_xdisplay(), args, num_args); if ( widget_class == qWidgetClass ) ((QWidgetRec*)xtw)->qwidget.qxtwidget = this; } if ( qparent ) { XtResizeWidget( xtw, 100, 100, 0 ); XtSetMappedWhenManaged(xtw, False); XtRealizeWidget(xtw); XSync(qt_xdisplay(), False); // I want all windows to be created now XReparentWindow(qt_xdisplay(), XtWindow(xtw), qparent->winId(), x(), y()); XtSetMappedWhenManaged(xtw, True); need_reroot=TRUE; } Arg reqargs[20]; Cardinal nargs=0; XtSetArg(reqargs[nargs], XtNx, x()); nargs++; XtSetArg(reqargs[nargs], XtNy, y()); nargs++; XtSetArg(reqargs[nargs], XtNwidth, width()); nargs++; XtSetArg(reqargs[nargs], XtNheight, height()); nargs++; //XtSetArg(reqargs[nargs], "mappedWhenManaged", False); nargs++; XtSetValues(xtw, reqargs, nargs); //#### destroy(); MLK if (!parent || XtIsRealized(parent)) XtRealizeWidget(xtw); } /*! Constructs a KXtWidget of the special Xt widget class known as "TQWidget" to the resource manager. Use this constructor to utilize Qt widgets in an Xt/Motif application. The KXtWidget is a TQWidget, so you can create subwidgets, layouts, etc. using Qt functionality. */ KXtWidget::KXtWidget(const char* name, Widget parent, bool managed) : TQWidget( 0, name, WResizeNoErase ) { init(name, qWidgetClass, parent, 0, 0, 0, managed); Arg reqargs[20]; Cardinal nargs=0; XtSetArg(reqargs[nargs], XtNborderWidth, 0); nargs++; XtSetValues(xtw, reqargs, nargs); } /*! Constructs a KXtWidget of the given \a widget_class. Use this constructor to utilize Xt or Motif widgets in a Qt application. The KXtWidget looks and behaves like the Xt class, but can be used like any TQWidget. Note that Xt requires that the most toplevel Xt widget is a shell. That means, if \a parent is a KXtWidget, the \a widget_class can be of any kind. If there isn't a parent or the parent is just a normal TQWidget, \a widget_class should be something like \c topLevelShellWidgetClass. If the \a managed parameter is TRUE and \a parent in not NULL, XtManageChild it used to manage the child. */ KXtWidget::KXtWidget(const char* name, WidgetClass widget_class, TQWidget *parent, ArgList args, Cardinal num_args, bool managed) : TQWidget( parent, name, WResizeNoErase ) { if ( !parent ) init(name, widget_class, 0, 0, args, num_args, managed); else if ( parent->inherits("KXtWidget") ) init(name, widget_class, ( (KXtWidget*)parent)->xtw , 0, args, num_args, managed); else init(name, widget_class, 0, parent, args, num_args, managed); create(XtWindow(xtw), FALSE, FALSE); } /*! Destructs the KXtWidget. */ KXtWidget::~KXtWidget() { // Delete children first, as Xt will destroy their windows // TQObjectList* list = queryList("TQWidget", 0, FALSE, FALSE); if ( list ) { TQWidget* c; TQObjectListIt it( *list ); while ( (c = (TQWidget*)it.current()) ) { delete c; ++it; } delete list; } if ( need_reroot ) { hide(); XReparentWindow(qt_xdisplay(), winId(), qApp->desktop()->winId(), x(), y()); } XtDestroyWidget(xtw); destroy( FALSE, FALSE ); } /*! \fn Widget KXtWidget::xtWidget() const Returns the Xt widget equivalent for the Qt widget. */ /*! Reimplemented to produce the Xt effect of getting focus when the mouse enters the widget. <em>This may be changed.</em> */ bool KXtWidget::x11Event( XEvent * e ) { if ( e->type == EnterNotify ) { if ( xtparent ) setActiveWindow(); } return TQWidget::x11Event( e ); } /*! Implement a degree of focus handling for Xt widgets. */ void KXtWidget::setActiveWindow() { if ( xtparent ) { if ( !TQWidget::isActiveWindow() && isActiveWindow() ) { XFocusChangeEvent e; e.type = FocusIn; e.window = winId(); e.mode = NotifyNormal; e.detail = NotifyInferior; XSendEvent( qt_xdisplay(), e.window, TRUE, NoEventMask, (XEvent*)&e ); } } else { TQWidget::setActiveWindow(); } } /*! Different from TQWidget::isActiveWindow() */ bool KXtWidget::isActiveWindow() const { Window win; int revert; XGetInputFocus( qt_xdisplay(), &win, &revert ); if ( win == None) return FALSE; TQWidget *w = find( (WId)win ); if ( w ) { // We know that window return w->topLevelWidget() == topLevelWidget(); } else { // Window still may be a parent (if top-level is foreign window) Window root, parent; Window cursor = winId(); Window *ch; unsigned int nch; while ( XQueryTree(qt_xdisplay(), cursor, &root, &parent, &ch, &nch) ) { if (ch) XFree( (char*)ch); if ( parent == win ) return TRUE; if ( parent == root ) return FALSE; cursor = parent; } return FALSE; } } /*!\reimp */ void KXtWidget::moveEvent( TQMoveEvent* ) { if ( xtparent ) return; XConfigureEvent c; c.type = ConfigureNotify; c.event = winId(); c.window = winId(); c.x = x(); c.y = y(); c.width = width(); c.height = height(); c.border_width = 0; XSendEvent( qt_xdisplay(), c.event, TRUE, NoEventMask, (XEvent*)&c ); XtMoveWidget( xtw, x(), y() ); } /*!\reimp */ void KXtWidget::resizeEvent( TQResizeEvent* ) { if ( xtparent ) return; XtWidgetGeometry preferred; (void ) XtQueryGeometry( xtw, 0, &preferred ); XConfigureEvent c; c.type = ConfigureNotify; c.event = winId(); c.window = winId(); c.x = x(); c.y = y(); c.width = width(); c.height = height(); c.border_width = 0; XSendEvent( qt_xdisplay(), c.event, TRUE, NoEventMask, (XEvent*)&c ); XtResizeWidget( xtw, width(), height(), preferred.border_width ); } #include "kxt.moc" #endif