summaryrefslogtreecommitdiffstats
path: root/src/kernel/qapplication_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/qapplication_x11.cpp')
-rw-r--r--src/kernel/qapplication_x11.cpp6653
1 files changed, 6653 insertions, 0 deletions
diff --git a/src/kernel/qapplication_x11.cpp b/src/kernel/qapplication_x11.cpp
new file mode 100644
index 0000000..e72bd63
--- /dev/null
+++ b/src/kernel/qapplication_x11.cpp
@@ -0,0 +1,6653 @@
+/****************************************************************************
+**
+** Implementation of X11 startup routines and event handling
+**
+** Created : 931029
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the kernel module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+// ### 4.0: examine Q_EXPORT's below. The respective symbols had all
+// been in use (e.g. in the KDE wm ) before the introduction of a version
+// map. One might want to turn some of them into propert public API and
+// provide a proper alternative for others. See also the exports in
+// qapplication_win.cpp which suggest a unification.
+
+// ### needed for solaris-g++ in beta5
+#define QT_CLEAN_NAMESPACE
+
+#include "qplatformdefs.h"
+
+// POSIX Large File Support redefines open -> open64
+#if defined(open)
+# undef open
+#endif
+
+// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
+#if defined(connect)
+# undef connect
+#endif
+
+// POSIX Large File Support redefines truncate -> truncate64
+#if defined(truncate)
+# undef truncate
+#endif
+
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include "qcolor_p.h"
+#include "qcursor.h"
+#include "qwidget.h"
+#include "qwidget_p.h"
+#include "qobjectlist.h"
+#include "qwidgetlist.h"
+#include "qwidgetintdict.h"
+#include "qbitarray.h"
+#include "qpainter.h"
+#include "qpixmapcache.h"
+#include "qdatetime.h"
+#include "qtextcodec.h"
+#include "qdatastream.h"
+#include "qbuffer.h"
+#include "qsocketnotifier.h"
+#include "qsessionmanager.h"
+#include "qvaluelist.h"
+#include "qdict.h"
+#include "qguardedptr.h"
+#include "qclipboard.h"
+#include "qwhatsthis.h" // ######## dependency
+#include "qsettings.h"
+#include "qstylefactory.h"
+#include "qfileinfo.h"
+
+// Input method stuff - UNFINISHED
+#ifndef QT_NO_IM
+#include "qinputcontext.h"
+#endif // QT_NO_IM
+#include "qinternal_p.h" // shared double buffer cleanup
+
+#if defined(QT_THREAD_SUPPORT)
+# include "qthread.h"
+#endif
+
+#if defined(QT_DEBUG) && defined(Q_OS_LINUX)
+# include "qfile.h"
+#endif
+
+#include "qt_x11_p.h"
+
+#if !defined(QT_NO_XFTFREETYPE)
+// XFree86 4.0.3 implementation is missing XftInitFtLibrary forward
+extern "C" Bool XftInitFtLibrary(void);
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <locale.h>
+#include <cstdlib>
+
+//#define X_NOT_BROKEN
+#ifdef X_NOT_BROKEN
+// Some X libraries are built with setlocale #defined to _Xsetlocale,
+// even though library users are then built WITHOUT such a definition.
+// This creates a problem - Qt might setlocale() one value, but then
+// X looks and doesn't see the value Qt set. The solution here is to
+// implement _Xsetlocale just in case X calls it - redirecting it to
+// the real libC version.
+//
+# ifndef setlocale
+extern "C" char *_Xsetlocale(int category, const char *locale);
+char *_Xsetlocale(int category, const char *locale)
+{
+ //qDebug("_Xsetlocale(%d,%s),category,locale");
+ return setlocale(category,locale);
+}
+# endif // setlocale
+#endif // X_NOT_BROKEN
+
+
+// resolve the conflict between X11's FocusIn and QEvent::FocusIn
+const int XFocusOut = FocusOut;
+const int XFocusIn = FocusIn;
+#undef FocusOut
+#undef FocusIn
+
+const int XKeyPress = KeyPress;
+const int XKeyRelease = KeyRelease;
+#undef KeyPress
+#undef KeyRelease
+
+
+// Fix old X libraries
+#ifndef XK_KP_Home
+#define XK_KP_Home 0xFF95
+#endif
+#ifndef XK_KP_Left
+#define XK_KP_Left 0xFF96
+#endif
+#ifndef XK_KP_Up
+#define XK_KP_Up 0xFF97
+#endif
+#ifndef XK_KP_Right
+#define XK_KP_Right 0xFF98
+#endif
+#ifndef XK_KP_Down
+#define XK_KP_Down 0xFF99
+#endif
+#ifndef XK_KP_Prior
+#define XK_KP_Prior 0xFF9A
+#endif
+#ifndef XK_KP_Next
+#define XK_KP_Next 0xFF9B
+#endif
+#ifndef XK_KP_End
+#define XK_KP_End 0xFF9C
+#endif
+#ifndef XK_KP_Insert
+#define XK_KP_Insert 0xFF9E
+#endif
+#ifndef XK_KP_Delete
+#define XK_KP_Delete 0xFF9F
+#endif
+
+
+/*****************************************************************************
+ Internal variables and functions
+ *****************************************************************************/
+static const char *appName; // application name
+static const char *appClass; // application class
+static const char *appFont = 0; // application font
+static const char *appBGCol = 0; // application bg color
+static const char *appFGCol = 0; // application fg color
+static const char *appBTNCol = 0; // application btn color
+static const char *mwGeometry = 0; // main widget geometry
+static const char *mwTitle = 0; // main widget title
+//Ming-Che 10/10
+char *qt_ximServer = 0; // XIM Server will connect to
+static bool mwIconic = FALSE; // main widget iconified
+//Ming-Che 10/10
+static Display *appDpy = 0; // X11 application display
+static char *appDpyName = 0; // X11 display name
+static bool appForeignDpy = FALSE; // we didn't create display
+static bool appSync = FALSE; // X11 synchronization
+#if defined(QT_DEBUG)
+static bool appNoGrab = FALSE; // X11 grabbing enabled
+static bool appDoGrab = FALSE; // X11 grabbing override (gdb)
+#endif
+static int appScreen; // X11 screen number
+static int appScreenCount; // X11 screen count
+static bool app_save_rootinfo = FALSE; // save root info
+static bool app_do_modal = FALSE; // modal mode
+static Window curWin = 0; // current window
+
+static GC* app_gc_ro = 0; // read-only GC
+static GC* app_gc_tmp = 0; // temporary GC
+static GC* app_gc_ro_m = 0; // read-only GC (monochrome)
+static GC* app_gc_tmp_m = 0; // temporary GC (monochrome)
+// symbols needed by extern QXEmbed class
+Q_EXPORT Atom qt_wm_protocols = 0; // window manager protocols
+Q_EXPORT Atom qt_wm_delete_window = 0; // delete window protocol
+Q_EXPORT Atom qt_wm_take_focus = 0; // take focus window protocol
+
+Atom qt_qt_scrolldone = 0; // scroll synchronization
+Atom qt_net_wm_context_help = 0; // context help
+Atom qt_net_wm_ping = 0; // _NET_WM_PING protocol
+
+static Atom qt_xsetroot_id = 0;
+Atom qt_xa_clipboard = 0;
+Atom qt_selection_property = 0;
+Atom qt_clipboard_sentinel = 0;
+Atom qt_selection_sentinel = 0;
+Q_EXPORT Atom qt_wm_state = 0;
+Atom qt_wm_change_state = 0;
+static Atom qt_settings_timestamp = 0; // Qt >=3 settings timestamp
+static Atom qt_input_encoding = 0; // Qt desktop properties
+static Atom qt_resource_manager = 0; // X11 Resource manager
+Atom qt_sizegrip = 0; // sizegrip
+Atom qt_wm_client_leader = 0;
+Q_EXPORT Atom qt_window_role = 0;
+Q_EXPORT Atom qt_sm_client_id = 0;
+Atom qt_xa_motif_wm_hints = 0;
+Atom qt_cde_running = 0;
+Atom qt_kwin_running = 0;
+Atom qt_kwm_running = 0;
+Atom qt_gbackground_properties = 0;
+Atom qt_x_incr = 0;
+Atom qt_utf8_string = 0;
+
+// detect broken window managers
+Atom qt_sgi_desks_manager = 0;
+bool qt_broken_wm = FALSE;
+static void qt_detect_broken_window_manager();
+
+// NET WM support
+Atom qt_net_supported = 0;
+Atom qt_net_wm_name = 0;
+Atom qt_net_wm_icon_name = 0;
+Atom qt_net_virtual_roots = 0;
+Atom qt_net_workarea = 0;
+Atom qt_net_wm_state = 0;
+Atom qt_net_wm_state_modal = 0;
+Atom qt_net_wm_state_max_v = 0;
+Atom qt_net_wm_state_max_h = 0;
+Atom qt_net_wm_state_fullscreen = 0;
+Atom qt_net_wm_state_above = 0;
+Atom qt_net_wm_window_type = 0;
+Atom qt_net_wm_window_type_normal = 0;
+Atom qt_net_wm_window_type_dialog = 0;
+Atom qt_net_wm_window_type_toolbar = 0;
+Atom qt_net_wm_window_type_menu = 0;
+Atom qt_net_wm_window_type_utility = 0;
+Atom qt_net_wm_window_type_splash = 0;
+Atom qt_net_wm_window_type_override = 0; // KDE extension
+Atom qt_net_wm_window_type_dropdown_menu = 0;
+Atom qt_net_wm_window_type_popup_menu = 0;
+Atom qt_net_wm_window_type_tooltip = 0;
+Atom qt_net_wm_window_type_combo = 0;
+Atom qt_net_wm_window_type_dnd = 0;
+Atom qt_net_wm_frame_strut = 0; // KDE extension
+Atom qt_net_wm_state_stays_on_top = 0; // KDE extension
+Atom qt_net_wm_pid = 0;
+Atom qt_net_wm_user_time = 0;
+Atom qt_net_wm_full_placement = 0; // KDE extension
+// Enlightenment support
+Atom qt_enlightenment_desktop = 0;
+
+// window managers list of supported "stuff"
+Atom *qt_net_supported_list = 0;
+// list of virtual root windows
+Window *qt_net_virtual_root_list = 0;
+
+
+// X11 SYNC support
+#ifndef QT_NO_XSYNC
+Atom qt_net_wm_sync_request_counter = 0;
+Atom qt_net_wm_sync_request = 0;
+#endif
+
+// client leader window
+Window qt_x11_wm_client_leader = 0;
+
+// function to update the workarea of the screen - in qdesktopwidget_x11.cpp
+extern void qt_desktopwidget_update_workarea();
+
+// current focus model
+static const int FocusModel_Unknown = -1;
+static const int FocusModel_Other = 0;
+static const int FocusModel_PointerRoot = 1;
+static int qt_focus_model = -1;
+
+#ifndef QT_NO_XRANDR
+// TRUE if Qt is compiled w/ XRandR support and XRandR exists on the connected
+// Display
+bool qt_use_xrandr = FALSE;
+static int xrandr_eventbase;
+#endif
+
+// TRUE if Qt is compiled w/ XRender support and XRender exists on the connected
+// Display
+Q_EXPORT bool qt_use_xrender = FALSE;
+
+#ifndef QT_NO_XSYNC
+// True if SYNC extension exists on the connected display
+bool qt_use_xsync = FALSE;
+static int xsync_eventbase;
+static int xsync_errorbase;
+#endif
+
+// modifier masks for alt/meta - detected when the application starts
+static long qt_alt_mask = 0;
+static long qt_meta_mask = 0;
+// modifier mask to remove mode switch from modifiers that have alt/meta set
+// this problem manifests itself on HP/UX 10.20 at least, and without it
+// modifiers do not work at all...
+static long qt_mode_switch_remove_mask = 0;
+
+// flags for extensions for special Languages, currently only for RTL languages
+static bool qt_use_rtl_extensions = FALSE;
+bool qt_hebrew_keyboard_hack = FALSE;
+
+static Window mouseActWindow = 0; // window where mouse is
+static int mouseButtonPressed = 0; // last mouse button pressed
+static int mouseButtonState = 0; // mouse button state
+static Time mouseButtonPressTime = 0; // when was a button pressed
+static short mouseXPos, mouseYPos; // mouse pres position in act window
+static short mouseGlobalXPos, mouseGlobalYPos; // global mouse press position
+
+extern QWidgetList *qt_modal_stack; // stack of modal widgets
+static bool ignoreNextMouseReleaseEvent = FALSE; // ignore the next mouse release
+ // event if return from a modal
+ // widget
+
+static QWidget *popupButtonFocus = 0;
+static QWidget *popupOfPopupButtonFocus = 0;
+static bool popupCloseDownMode = FALSE;
+static bool popupGrabOk;
+
+static bool sm_blockUserInput = FALSE; // session management
+
+int qt_xfocusout_grab_counter = 0;
+
+#if defined (QT_TABLET_SUPPORT)
+// since XInput event classes aren't created until we actually open an XInput
+// device, here is a static list that we will use later on...
+const int INVALID_EVENT = -1;
+const int TOTAL_XINPUT_EVENTS = 7;
+
+XDevice *devStylus = NULL;
+XDevice *devEraser = NULL;
+XEventClass event_list_stylus[TOTAL_XINPUT_EVENTS];
+XEventClass event_list_eraser[TOTAL_XINPUT_EVENTS];
+
+int qt_curr_events_stylus = 0;
+int qt_curr_events_eraser = 0;
+
+// well, luckily we only need to do this once.
+static int xinput_motion = INVALID_EVENT;
+static int xinput_key_press = INVALID_EVENT;
+static int xinput_key_release = INVALID_EVENT;
+static int xinput_button_press = INVALID_EVENT;
+static int xinput_button_release = INVALID_EVENT;
+
+// making this assumption on XFree86, since we can only use 1 device,
+// the pressure for the eraser and the stylus should be the same, if they aren't
+// well, they certainly have a strange pen then...
+static int max_pressure;
+extern bool chokeMouse;
+#endif
+
+// last timestamp read from QSettings
+static uint appliedstamp = 0;
+
+
+typedef int (*QX11EventFilter) (XEvent*);
+QX11EventFilter qt_set_x11_event_filter(QX11EventFilter filter);
+
+static QX11EventFilter qt_x11_event_filter = 0;
+Q_EXPORT QX11EventFilter qt_set_x11_event_filter(QX11EventFilter filter)
+{
+ QX11EventFilter old_filter = qt_x11_event_filter;
+ qt_x11_event_filter = filter;
+ return old_filter;
+}
+static bool qt_x11EventFilter( XEvent* ev )
+{
+ if ( qt_x11_event_filter && qt_x11_event_filter( ev ) )
+ return TRUE;
+ return qApp->x11EventFilter( ev );
+}
+
+
+
+
+
+#if !defined(QT_NO_XIM)
+//XIM qt_xim = 0;
+XIMStyle qt_xim_style = 0;
+XIMStyle qt_xim_preferred_style = 0;
+static XIMStyle xim_default_style = XIMPreeditCallbacks | XIMStatusNothing;
+#endif
+
+int qt_ximComposingKeycode=0;
+QTextCodec * qt_input_mapper = 0;
+
+Q_EXPORT Time qt_x_time = CurrentTime;
+Q_EXPORT Time qt_x_user_time = CurrentTime;
+extern bool qt_check_clipboard_sentinel(); //def in qclipboard_x11.cpp
+extern bool qt_check_selection_sentinel(); //def in qclipboard_x11.cpp
+
+static void qt_save_rootinfo();
+bool qt_try_modal( QWidget *, XEvent * );
+
+int qt_ncols_option = 216; // used in qcolor_x11.cpp
+int qt_visual_option = -1;
+bool qt_cmap_option = FALSE;
+QWidget *qt_button_down = 0; // widget got last button-down
+
+extern bool qt_tryAccelEvent( QWidget*, QKeyEvent* ); // def in qaccel.cpp
+
+struct QScrollInProgress {
+ static long serial;
+ QScrollInProgress( QWidget* w, int x, int y ) :
+ id( serial++ ), scrolled_widget( w ), dx( x ), dy( y ) {}
+ long id;
+ QWidget* scrolled_widget;
+ int dx, dy;
+};
+long QScrollInProgress::serial=0;
+static QPtrList<QScrollInProgress> *sip_list = 0;
+
+
+// stuff in qt_xdnd.cpp
+// setup
+extern void qt_xdnd_setup();
+// x event handling
+extern void qt_handle_xdnd_enter( QWidget *, const XEvent *, bool );
+extern void qt_handle_xdnd_position( QWidget *, const XEvent *, bool );
+extern void qt_handle_xdnd_status( QWidget *, const XEvent *, bool );
+extern void qt_handle_xdnd_leave( QWidget *, const XEvent *, bool );
+extern void qt_handle_xdnd_drop( QWidget *, const XEvent *, bool );
+extern void qt_handle_xdnd_finished( QWidget *, const XEvent *, bool );
+extern void qt_xdnd_handle_selection_request( const XSelectionRequestEvent * );
+extern bool qt_xdnd_handle_badwindow();
+
+extern void qt_motifdnd_handle_msg( QWidget *, const XEvent *, bool );
+extern void qt_x11_motifdnd_init();
+
+// client message atoms
+extern Atom qt_xdnd_enter;
+extern Atom qt_xdnd_position;
+extern Atom qt_xdnd_status;
+extern Atom qt_xdnd_leave;
+extern Atom qt_xdnd_drop;
+extern Atom qt_xdnd_finished;
+// xdnd selection atom
+extern Atom qt_xdnd_selection;
+extern bool qt_xdnd_dragging;
+
+// gui or non-gui from qapplication.cpp
+extern bool qt_is_gui_used;
+extern bool qt_app_has_font;
+
+static bool qt_x11_cmdline_font = false;
+
+
+extern bool qt_resolve_symlinks; // from qapplication.cpp
+
+// Paint event clipping magic
+extern void qt_set_paintevent_clipping( QPaintDevice* dev, const QRegion& region);
+extern void qt_clear_paintevent_clipping();
+
+
+// Palette handling
+extern QPalette *qt_std_pal;
+extern void qt_create_std_palette();
+
+void qt_x11_intern_atom( const char *, Atom * );
+
+static QPtrList<QWidget>* deferred_map_list = 0;
+static void qt_deferred_map_cleanup()
+{
+ delete deferred_map_list;
+ deferred_map_list = 0;
+}
+void qt_deferred_map_add( QWidget* w)
+{
+ if ( !deferred_map_list ) {
+ deferred_map_list = new QPtrList<QWidget>;
+ qAddPostRoutine( qt_deferred_map_cleanup );
+ }
+ deferred_map_list->append( w );
+}
+void qt_deferred_map_take( QWidget* w )
+{
+ if (deferred_map_list ) {
+ deferred_map_list->remove( w );
+ }
+}
+bool qt_deferred_map_contains( QWidget* w )
+{
+ if (!deferred_map_list)
+ return FALSE;
+ else
+ return deferred_map_list->contains( w );
+}
+
+
+class QETWidget : public QWidget // event translator widget
+{
+public:
+ void setWState( WFlags f ) { QWidget::setWState(f); }
+ void clearWState( WFlags f ) { QWidget::clearWState(f); }
+ void setWFlags( WFlags f ) { QWidget::setWFlags(f); }
+ void clearWFlags( WFlags f ) { QWidget::clearWFlags(f); }
+ bool translateMouseEvent( const XEvent * );
+ bool translateKeyEventInternal( const XEvent *, int& count, QString& text, int& state, char& ascii, int &code, QEvent::Type &type, bool willRepeat=FALSE, bool statefulTranslation=TRUE );
+ bool translateKeyEvent( const XEvent *, bool grab );
+ bool translatePaintEvent( const XEvent * );
+ bool translateConfigEvent( const XEvent * );
+ bool translateCloseEvent( const XEvent * );
+ bool translateScrollDoneEvent( const XEvent * );
+ bool translateWheelEvent( int global_x, int global_y, int delta, int state, Orientation orient );
+#if defined (QT_TABLET_SUPPORT)
+ bool translateXinputEvent( const XEvent* );
+#endif
+ bool translatePropertyEvent(const XEvent *);
+};
+
+
+
+
+// ************************************************************************
+// Input Method support
+// ************************************************************************
+
+/*!
+ An identifier name of the default input method.
+*/
+QString QApplication::defaultIM = "imsw-multi";
+
+
+/*!
+ This function handles the query about location of the widget
+ holding the QInputContext instance for widget \a w.
+
+ The input context is used for text input to widget \a w. By
+ default, it returns the top-level widget of \a w.
+
+ If you want to change the mapping of widget \w to QInputContext
+ instance, reimplement both this function and
+ QApplication::icHolderWidgets(). For example, suppose a tabbed web
+ browser. The browser should allocate a input context per tab
+ widget because users may switch the tabs and input a new text
+ during previous input contexts live.
+
+ See also 'Sharing input context between text widgets' and 'Preedit
+ preservation' section of the class description of QInputContext.
+
+ \sa QInputContext, icHolderWidgets()
+*/
+QWidget *QApplication::locateICHolderWidget( QWidget *w )
+{
+ return w->topLevelWidget();
+}
+
+
+/*!
+ This function returns all widgets holding QInputContext.
+
+ By default, This function returns top-level widgets. So if you
+ want to change the mapping of a widget to QInputContext instance,
+ you must override this function and locateICHolderWidget().
+
+ \sa locateICHolderWidget()
+*/
+QWidgetList *QApplication::icHolderWidgets()
+{
+ return QApplication::topLevelWidgets();
+}
+
+
+/*!
+ This function replaces all QInputContext instances in the
+ application. The function's argument is the identifier name of
+ the newly selected input method.
+*/
+void QApplication::changeAllInputContext( const QString &identifierName )
+{
+ QWidgetList *list = qApp->icHolderWidgets();
+ QWidgetListIt it(*list);
+ while(it.current()) {
+ it.current()->changeInputContext( identifierName );
+ ++it;
+ }
+ delete list;
+
+ // defaultIM = identifierName ; // Change of defaultIM -- default input method -- may be enabled.
+}
+
+
+/*!
+ \internal
+ This is an internal function, you should never call this.
+
+ \sa QInputContext::imEventGenerated()
+*/
+void QApplication::postIMEvent( QObject *receiver, QIMEvent *event )
+{
+ if ( event->type() == QEvent::IMCompose ) {
+ // enable event compression to reduce preedit flicker on fast
+ // typing
+ postEvent( receiver, event );
+ } else {
+ // cancel queued preedit update
+ if ( event->type() == QEvent::IMEnd )
+ removePostedEvents( receiver, QEvent::IMCompose );
+
+ // to avoid event receiving order inversion between QKeyEvent
+ // and QIMEvent, we must send IMStart and IMEnd via
+ // sendEvent().
+ sendEvent( receiver, event );
+ delete event;
+ }
+}
+
+
+/*!
+ This function returns the identifier name of the default input
+ method in this Application. The value is identical to the value of
+ QApplication::defaultIM.
+*/
+QString QApplication::defaultInputMethod()
+{
+ return QApplication::defaultIM;
+}
+
+
+#if !defined(QT_NO_IM_EXTENSIONS)
+/*! \internal
+ Creates the application input method.
+*/
+void QApplication::create_im()
+{
+#ifndef QT_NO_XIM
+ if ( ! qt_xim_preferred_style ) // no configured input style, use the default
+ qt_xim_preferred_style = xim_default_style;
+#endif // QT_NO_XIM
+}
+
+
+/*! \internal
+ Closes the application input method.
+*/
+void QApplication::close_im()
+{
+ QWidgetList *list = qApp->icHolderWidgets();
+ QWidgetListIt it(*list);
+ while(it.current()) {
+ it.current()->destroyInputContext();
+ ++it;
+ }
+ delete list;
+}
+
+#else
+
+/*! \internal
+ Creates the application input method.
+*/
+void QApplication::create_xim()
+{
+#ifndef QT_NO_XIM
+ if ( ! qt_xim_preferred_style ) // no configured input style, use the default
+ qt_xim_preferred_style = xim_default_style;
+#endif // QT_NO_XIM
+
+ QWidgetList *list= qApp->topLevelWidgets();
+ QWidgetListIt it(*list);
+ QWidget * w;
+ while( (w=it.current()) != 0 ) {
+ ++it;
+ w->createTLSysExtra();
+ }
+ delete list;
+}
+
+
+ /*! \internal
+ Closes the application input method.
+ */
+void QApplication::close_xim()
+{
+#ifndef QT_NO_XIM
+ // Calling XCloseIM gives a Purify FMR error
+ // XCloseIM( qt_xim );
+ // We prefer a less serious memory leak
+
+ // if ( qt_xim )
+ // qt_xim = 0;
+
+#endif // QT_NO_XIM
+ QWidgetList *list = qApp->topLevelWidgets();
+ QWidgetListIt it(*list);
+ while(it.current()) {
+ it.current()->destroyInputContext();
+ ++it;
+ }
+ delete list;
+}
+#endif
+
+/*****************************************************************************
+ Default X error handlers
+ *****************************************************************************/
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static bool x11_ignore_badwindow;
+static bool x11_badwindow;
+
+ // starts to ignore bad window errors from X
+void qt_ignore_badwindow()
+{
+ x11_ignore_badwindow = TRUE;
+ x11_badwindow = FALSE;
+}
+
+ // ends ignoring bad window errors and returns whether an error
+ // had happen.
+bool qt_badwindow()
+{
+ x11_ignore_badwindow = FALSE;
+ return x11_badwindow;
+}
+
+static int (*original_x_errhandler)( Display *dpy, XErrorEvent * );
+static int (*original_xio_errhandler)( Display *dpy );
+
+static int qt_x_errhandler( Display *dpy, XErrorEvent *err )
+{
+ if ( err->error_code == BadWindow ) {
+ x11_badwindow = TRUE;
+ if ( err->request_code == 25 /* X_SendEvent */ &&
+ qt_xdnd_handle_badwindow() )
+ return 0;
+ if ( x11_ignore_badwindow )
+ return 0;
+ } else if ( err->error_code == BadMatch &&
+ err->request_code == 42 /* X_SetInputFocus */ ) {
+ return 0;
+ }
+
+ char errstr[256];
+ XGetErrorText( dpy, err->error_code, errstr, 256 );
+ qWarning( "X Error: %s %d\n"
+ " Major opcode: %d\n"
+ " Minor opcode: %d\n"
+ " Resource id: 0x%lx",
+ errstr, err->error_code,
+ err->request_code,
+ err->minor_code,
+ err->resourceid );
+
+ // ### we really should distinguish between severe, non-severe and
+ // ### application specific errors
+
+ return 0;
+}
+
+
+static int qt_xio_errhandler( Display * )
+{
+ qWarning( "%s: Fatal IO error: client killed", appName );
+ qApp = 0;
+ exit( 1 );
+ //### give the application a chance for a proper shutdown instead,
+ //### exit(1) doesn't help.
+ return 0;
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+
+// Memory leak: if the app exits before qt_init_internal(), this dict
+// isn't released correctly.
+static QAsciiDict<Atom> *atoms_to_be_created = 0;
+static bool create_atoms_now = 0;
+
+/*****************************************************************************
+ qt_x11_intern_atom() - efficiently interns an atom, now or later.
+
+ If the application is being initialized, this function stores the
+ adddress of the atom and qt_init_internal will do the actual work
+ quickly. If the application is running, the atom is created here.
+
+ Neither argument may point to temporary variables.
+ *****************************************************************************/
+
+void qt_x11_intern_atom( const char *name, Atom *result)
+{
+ if ( !name || !result || *result )
+ return;
+
+ if ( create_atoms_now ) {
+ *result = XInternAtom( appDpy, name, False );
+ } else {
+ if ( !atoms_to_be_created ) {
+ atoms_to_be_created = new QAsciiDict<Atom>;
+ atoms_to_be_created->setAutoDelete( FALSE );
+ }
+ atoms_to_be_created->insert( name, result );
+ *result = 0;
+ }
+}
+
+
+static void qt_x11_process_intern_atoms()
+{
+ if ( atoms_to_be_created ) {
+#if defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 6)
+ int i = atoms_to_be_created->count();
+ Atom * res = (Atom *)malloc( i * sizeof( Atom ) );
+ Atom ** resp = (Atom **)malloc( i * sizeof( Atom* ) );
+ char ** names = (char **)malloc( i * sizeof(const char*));
+
+ i = 0;
+ QAsciiDictIterator<Atom> it( *atoms_to_be_created );
+ while( it.current() ) {
+ res[i] = 0;
+ resp[i] = it.current();
+ names[i] = qstrdup(it.currentKey());
+ i++;
+ ++it;
+ }
+ XInternAtoms( appDpy, names, i, False, res );
+ while( i ) {
+ i--;
+ delete [] names[i];
+ if ( res[i] && resp[i] )
+ *(resp[i]) = res[i];
+ }
+ free( res );
+ free( resp );
+ free( names );
+#else
+ QAsciiDictIterator<Atom> it( *atoms_to_be_created );
+ Atom * result;
+ const char * name;
+ while( (result = it.current()) != 0 ) {
+ name = it.currentKey();
+ ++it;
+ *result = XInternAtom( appDpy, name, False );
+ }
+#endif
+ delete atoms_to_be_created;
+ atoms_to_be_created = 0;
+ create_atoms_now = TRUE;
+ }
+}
+
+
+/*! \internal
+ apply the settings to the application
+*/
+bool QApplication::x11_apply_settings()
+{
+ if (! qt_std_pal)
+ qt_create_std_palette();
+
+ Atom type;
+ int format;
+ long offset = 0;
+ unsigned long nitems, after = 1;
+ unsigned char *data = 0;
+ QDateTime timestamp, settingsstamp;
+ bool update_timestamp = FALSE;
+
+ if (XGetWindowProperty(appDpy, QPaintDevice::x11AppRootWindow( 0 ),
+ qt_settings_timestamp, 0, 0,
+ False, AnyPropertyType, &type, &format, &nitems,
+ &after, &data) == Success && format == 8) {
+ if (data)
+ XFree(data);
+
+ QBuffer ts;
+ ts.open(IO_WriteOnly);
+
+ while (after > 0) {
+ XGetWindowProperty(appDpy, QPaintDevice::x11AppRootWindow( 0 ),
+ qt_settings_timestamp,
+ offset, 1024, False, AnyPropertyType,
+ &type, &format, &nitems, &after, &data);
+ if (format == 8) {
+ ts.writeBlock((const char *) data, nitems);
+ offset += nitems / 4;
+ }
+
+ XFree(data);
+ }
+
+ QDataStream d(ts.buffer(), IO_ReadOnly);
+ d >> timestamp;
+ }
+
+ QSettings settings;
+ settingsstamp = settings.lastModificationTime( "/qt/font" );
+ if (! settingsstamp.isValid())
+ return FALSE;
+
+ if ( appliedstamp && appliedstamp == settingsstamp.toTime_t() )
+ return TRUE;
+ appliedstamp = settingsstamp.toTime_t();
+
+ if (! timestamp.isValid() || settingsstamp > timestamp)
+ update_timestamp = TRUE;
+
+ /*
+ Qt settings. This is now they are written into the datastream.
+
+ /qt/Palette/ * - QPalette
+ /qt/font - QFont
+ /qt/libraryPath - QStringList
+ /qt/style - QString
+ /qt/doubleClickInterval - int
+ /qt/cursorFlashTime - int
+ /qt/wheelScrollLines - int
+ /qt/colorSpec - QString
+ /qt/defaultCodec - QString
+ /qt/globalStrut - QSize
+ /qt/GUIEffects - QStringList
+ /qt/Font Substitutions/ * - QStringList
+ /qt/Font Substitutions/... - QStringList
+ */
+
+ QString str;
+ QStringList strlist;
+ int i, num;
+ QPalette pal(QApplication::palette());
+ strlist = settings.readListEntry("/qt/Palette/active");
+ if (strlist.count() == QColorGroup::NColorRoles) {
+ for (i = 0; i < QColorGroup::NColorRoles; i++)
+ pal.setColor(QPalette::Active, (QColorGroup::ColorRole) i,
+ QColor(strlist[i]));
+ }
+ strlist = settings.readListEntry("/qt/Palette/inactive");
+ if (strlist.count() == QColorGroup::NColorRoles) {
+ for (i = 0; i < QColorGroup::NColorRoles; i++)
+ pal.setColor(QPalette::Inactive, (QColorGroup::ColorRole) i,
+ QColor(strlist[i]));
+ }
+ strlist = settings.readListEntry("/qt/Palette/disabled");
+ if (strlist.count() == QColorGroup::NColorRoles) {
+ for (i = 0; i < QColorGroup::NColorRoles; i++)
+ pal.setColor(QPalette::Disabled, (QColorGroup::ColorRole) i,
+ QColor(strlist[i]));
+ }
+
+ // workaround for KDE 3.0, which messes up the buttonText value of
+ // the disabled palette in QSettings
+ if ( pal.disabled().buttonText() == pal.active().buttonText() ) {
+ pal.setColor( QPalette::Disabled, QColorGroup::ButtonText,
+ pal.disabled().foreground() );
+ }
+
+ if (pal != *qt_std_pal && pal != QApplication::palette()) {
+ QApplication::setPalette(pal, TRUE);
+ *qt_std_pal = pal;
+ }
+
+ QFont font(QApplication::font());
+ if ( !qt_app_has_font && !qt_x11_cmdline_font ) {
+ // read new font
+ str = settings.readEntry("/qt/font");
+ if (! str.isNull() && ! str.isEmpty()) {
+ font.fromString(str);
+
+ if (font != QApplication::font())
+ QApplication::setFont(font, TRUE);
+ }
+ }
+
+ // read library (ie. plugin) path list
+ QString libpathkey =
+ QString("/qt/%1.%2/libraryPath").arg( QT_VERSION >> 16 ).arg( (QT_VERSION & 0xff00 ) >> 8 );
+ QStringList pathlist = settings.readListEntry(libpathkey, ':');
+ if (! pathlist.isEmpty()) {
+ QStringList::ConstIterator it = pathlist.begin();
+ while (it != pathlist.end())
+ QApplication::addLibraryPath(*it++);
+ }
+
+ // read new QStyle
+ extern bool qt_explicit_app_style; // defined in qapplication.cpp
+ QString stylename = settings.readEntry( "/qt/style" );
+ if ( !stylename.isEmpty() && !qt_explicit_app_style ) {
+ QApplication::setStyle( stylename );
+ // took the style from the user settings, so mark the explicit flag FALSE
+ qt_explicit_app_style = FALSE;
+ }
+
+ num =
+ settings.readNumEntry("/qt/doubleClickInterval",
+ QApplication::doubleClickInterval());
+ QApplication::setDoubleClickInterval(num);
+
+ num =
+ settings.readNumEntry("/qt/cursorFlashTime",
+ QApplication::cursorFlashTime());
+ QApplication::setCursorFlashTime(num);
+
+ num =
+ settings.readNumEntry("/qt/wheelScrollLines",
+ QApplication::wheelScrollLines());
+ QApplication::setWheelScrollLines(num);
+
+ QString colorspec = settings.readEntry("/qt/colorSpec", "default");
+ if (colorspec == "normal")
+ QApplication::setColorSpec(QApplication::NormalColor);
+ else if (colorspec == "custom")
+ QApplication::setColorSpec(QApplication::CustomColor);
+ else if (colorspec == "many")
+ QApplication::setColorSpec(QApplication::ManyColor);
+ else if (colorspec != "default")
+ colorspec = "default";
+
+ QString defaultcodec = settings.readEntry("/qt/defaultCodec", "none");
+ if (defaultcodec != "none") {
+ QTextCodec *codec = QTextCodec::codecForName(defaultcodec);
+ if (codec)
+ qApp->setDefaultCodec(codec);
+ }
+
+ QStringList strut = settings.readListEntry("/qt/globalStrut");
+ if (! strut.isEmpty()) {
+ if (strut.count() == 2) {
+ QSize sz(strut[0].toUInt(), strut[1].toUInt());
+
+ if (sz.isValid())
+ QApplication::setGlobalStrut(sz);
+ }
+ }
+
+ QStringList effects = settings.readListEntry("/qt/GUIEffects");
+
+ QApplication::setEffectEnabled( Qt::UI_General, effects.contains("general") );
+ QApplication::setEffectEnabled( Qt::UI_AnimateMenu, effects.contains("animatemenu") );
+ QApplication::setEffectEnabled( Qt::UI_FadeMenu, effects.contains("fademenu") );
+ QApplication::setEffectEnabled( Qt::UI_AnimateCombo, effects.contains("animatecombo") );
+ QApplication::setEffectEnabled( Qt::UI_AnimateTooltip, effects.contains("animatetooltip") );
+ QApplication::setEffectEnabled( Qt::UI_FadeTooltip, effects.contains("fadetooltip") );
+ QApplication::setEffectEnabled( Qt::UI_AnimateToolBox, effects.contains("animatetoolbox") );
+
+ QStringList fontsubs =
+ settings.entryList("/qt/Font Substitutions");
+ if (!fontsubs.isEmpty()) {
+ QStringList subs;
+ QString fam, skey;
+ QStringList::Iterator it = fontsubs.begin();
+ while (it != fontsubs.end()) {
+ fam = (*it++);
+ skey = "/qt/Font Substitutions/" + fam;
+ subs = settings.readListEntry(skey);
+ QFont::insertSubstitutions(fam, subs);
+ }
+ }
+
+ qt_broken_wm =
+ settings.readBoolEntry("/qt/brokenWindowManager", qt_broken_wm);
+
+ qt_resolve_symlinks =
+ settings.readBoolEntry("/qt/resolveSymlinks", TRUE);
+
+ qt_use_rtl_extensions =
+ settings.readBoolEntry("/qt/useRtlExtensions", FALSE);
+
+#ifndef QT_NO_XIM
+ if (qt_xim_preferred_style == 0) {
+ QString ximInputStyle =
+ settings.readEntry( "/qt/XIMInputStyle",
+ QObject::trUtf8( "On The Spot" ) ).lower();
+ if ( ximInputStyle == "on the spot" )
+ qt_xim_preferred_style = XIMPreeditCallbacks | XIMStatusNothing;
+ else if ( ximInputStyle == "over the spot" )
+ qt_xim_preferred_style = XIMPreeditPosition | XIMStatusNothing;
+ else if ( ximInputStyle == "off the spot" )
+ qt_xim_preferred_style = XIMPreeditArea | XIMStatusArea;
+ else if ( ximInputStyle == "root" )
+ qt_xim_preferred_style = XIMPreeditNothing | XIMStatusNothing;
+ }
+#endif
+
+#ifndef QT_NO_IM
+ /*
+ The identifier name of an input method is acquired from the
+ configuration file as a default. If a environment variable
+ "QT_IM_SWITCHER" is not empty it will overwrite the
+ configuration file. The "imsw-multi" becomes the default if the entry
+ is not configured.
+ */
+ if ( getenv( "QT_IM_SWITCHER" ) )
+ defaultIM = getenv( "QT_IM_SWITCHER" );
+#ifndef QT_NO_IM_EXTENSIONS
+ else
+ defaultIM = settings.readEntry( "/qt/DefaultInputMethodSwitcher", "imsw-multi" );
+#endif
+
+ // defaultIM is restricted to be an IM-switcher. An IM-switcher
+ // has a 'imsw-' prefix
+ if ( ! defaultIM.startsWith( "imsw-" ) ) {
+ defaultIM = "imsw-multi";
+ }
+#endif
+
+ if (update_timestamp) {
+ QBuffer stamp;
+ QDataStream s(stamp.buffer(), IO_WriteOnly);
+ s << settingsstamp;
+
+ XChangeProperty(appDpy, QPaintDevice::x11AppRootWindow( 0 ),
+ qt_settings_timestamp, qt_settings_timestamp, 8,
+ PropModeReplace, (unsigned char *) stamp.buffer().data(),
+ stamp.buffer().size());
+ }
+
+ return TRUE;
+}
+
+
+// read the _QT_INPUT_ENCODING property and apply the settings to
+// the application
+static void qt_set_input_encoding()
+{
+ Atom type;
+ int format;
+ ulong nitems, after = 1;
+ const char *data;
+
+ int e = XGetWindowProperty( appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_input_encoding, 0, 1024,
+ False, XA_STRING, &type, &format, &nitems,
+ &after, (unsigned char**)&data );
+ if ( e != Success || !nitems || type == None ) {
+ // Always use the locale codec, since we have no examples of non-local
+ // XIMs, and since we cannot get a sensible answer about the encoding
+ // from the XIM.
+ qt_input_mapper = QTextCodec::codecForLocale();
+
+ } else {
+ if ( !qstricmp( data, "locale" ) )
+ qt_input_mapper = QTextCodec::codecForLocale();
+ else
+ qt_input_mapper = QTextCodec::codecForName( data );
+ // make sure we have an input codec
+ if( !qt_input_mapper )
+ qt_input_mapper = QTextCodec::codecForName( "ISO 8859-1" );
+ }
+ if ( qt_input_mapper->mibEnum() == 11 ) // 8859-8
+ qt_input_mapper = QTextCodec::codecForName( "ISO 8859-8-I");
+ if( data )
+ XFree( (char *)data );
+}
+
+// set font, foreground and background from x11 resources. The
+// arguments may override the resource settings.
+static void qt_set_x11_resources( const char* font = 0, const char* fg = 0,
+ const char* bg = 0, const char* button = 0 )
+{
+ if ( !qt_std_pal )
+ qt_create_std_palette();
+
+ QCString resFont, resFG, resBG, resEF, sysFont;
+
+ QApplication::setEffectEnabled( Qt::UI_General, FALSE);
+ QApplication::setEffectEnabled( Qt::UI_AnimateMenu, FALSE);
+ QApplication::setEffectEnabled( Qt::UI_FadeMenu, FALSE);
+ QApplication::setEffectEnabled( Qt::UI_AnimateCombo, FALSE );
+ QApplication::setEffectEnabled( Qt::UI_AnimateTooltip, FALSE );
+ QApplication::setEffectEnabled( Qt::UI_FadeTooltip, FALSE );
+ QApplication::setEffectEnabled( Qt::UI_AnimateToolBox, FALSE );
+
+ if ( QApplication::desktopSettingsAware() && !QApplication::x11_apply_settings() ) {
+ int format;
+ ulong nitems, after = 1;
+ QCString res;
+ long offset = 0;
+ Atom type = None;
+
+ while (after > 0) {
+ uchar *data;
+ XGetWindowProperty( appDpy, QPaintDevice::x11AppRootWindow( 0 ),
+ qt_resource_manager,
+ offset, 8192, False, AnyPropertyType,
+ &type, &format, &nitems, &after,
+ &data );
+ res += (char*)data;
+ offset += 2048; // offset is in 32bit quantities... 8192/4 == 2048
+ if ( data )
+ XFree( (char *)data );
+ }
+
+ QCString key, value;
+ int l = 0, r;
+ QCString apn = appName;
+ QCString apc = appClass;
+ int apnl = apn.length();
+ int apcl = apc.length();
+ int resl = res.length();
+
+ while (l < resl) {
+ r = res.find( '\n', l );
+ if ( r < 0 )
+ r = resl;
+ while ( isspace((uchar) res[l]) )
+ l++;
+ bool mine = FALSE;
+ if ( res[l] == '*' &&
+ (res[l+1] == 'f' || res[l+1] == 'b' || res[l+1] == 'g' ||
+ res[l+1] == 'F' || res[l+1] == 'B' || res[l+1] == 'G' ||
+ res[l+1] == 's' || res[l+1] == 'S' ) ) {
+ // OPTIMIZED, since we only want "*[fbgs].."
+
+ QCString item = res.mid( l, r - l ).simplifyWhiteSpace();
+ int i = item.find( ":" );
+ key = item.left( i ).stripWhiteSpace().mid(1).lower();
+ value = item.right( item.length() - i - 1 ).stripWhiteSpace();
+ mine = TRUE;
+ } else if ( res[l] == appName[0] || (appClass && res[l] == appClass[0]) ) {
+ if (res.mid(l,apnl) == apn && (res[l+apnl] == '.' || res[l+apnl] == '*')) {
+ QCString item = res.mid( l, r - l ).simplifyWhiteSpace();
+ int i = item.find( ":" );
+ key = item.left( i ).stripWhiteSpace().mid(apnl+1).lower();
+ value = item.right( item.length() - i - 1 ).stripWhiteSpace();
+ mine = TRUE;
+ } else if (res.mid(l,apcl) == apc && (res[l+apcl] == '.' || res[l+apcl] == '*')) {
+ QCString item = res.mid( l, r - l ).simplifyWhiteSpace();
+ int i = item.find( ":" );
+ key = item.left( i ).stripWhiteSpace().mid(apcl+1).lower();
+ value = item.right( item.length() - i - 1 ).stripWhiteSpace();
+ mine = TRUE;
+ }
+ }
+
+ if ( mine ) {
+ if ( !font && key == "systemfont")
+ sysFont = value.left( value.findRev(':') ).copy();
+ if ( !font && key == "font")
+ resFont = value.copy();
+ else if ( !fg && key == "foreground" )
+ resFG = value.copy();
+ else if ( !bg && key == "background")
+ resBG = value.copy();
+ else if ( key == "guieffects")
+ resEF = value.copy();
+ // NOTE: if you add more, change the [fbg] stuff above
+ }
+
+ l = r + 1;
+ }
+ }
+ if ( !sysFont.isEmpty() )
+ resFont = sysFont;
+ if ( resFont.isEmpty() )
+ resFont = font;
+ if ( resFG.isEmpty() )
+ resFG = fg;
+ if ( resBG.isEmpty() )
+ resBG = bg;
+ if ( (!qt_app_has_font || qt_x11_cmdline_font) && !resFont.isEmpty() ) { // set application font
+ QFont fnt;
+ fnt.setRawName( resFont );
+
+ // the font we get may actually be an alias for another font,
+ // so we reset the application font to the real font info.
+ if ( ! fnt.exactMatch() ) {
+ QFontInfo fontinfo( fnt );
+ fnt.setFamily( fontinfo.family() );
+ fnt.setRawMode( fontinfo.rawMode() );
+
+ if ( ! fnt.rawMode() ) {
+ fnt.setItalic( fontinfo.italic() );
+ fnt.setWeight( fontinfo.weight() );
+ fnt.setUnderline( fontinfo.underline() );
+ fnt.setStrikeOut( fontinfo.strikeOut() );
+ fnt.setStyleHint( fontinfo.styleHint() );
+
+ if ( fnt.pointSize() <= 0 && fnt.pixelSize() <= 0 )
+ // size is all wrong... fix it
+ fnt.setPointSize( (int) ( ( fontinfo.pixelSize() * 72. /
+ (float) QPaintDevice::x11AppDpiY() ) +
+ 0.5 ) );
+ }
+ }
+
+ if ( fnt != QApplication::font() ) {
+ QApplication::setFont( fnt, TRUE );
+ }
+ }
+
+ if ( button || !resBG.isEmpty() || !resFG.isEmpty() ) {// set app colors
+ QColor btn;
+ QColor bg;
+ QColor fg;
+ if ( !resBG.isEmpty() )
+ bg = QColor(QString(resBG));
+ else
+ bg = qt_std_pal->active().background();
+ if ( !resFG.isEmpty() )
+ fg = QColor(QString(resFG));
+ else
+ fg = qt_std_pal->active().foreground();
+ if ( button )
+ btn = QColor( button );
+ else if ( !resBG.isEmpty() )
+ btn = bg;
+ else
+ btn = qt_std_pal->active().button();
+
+ int h,s,v;
+ fg.hsv(&h,&s,&v);
+ QColor base = Qt::white;
+ bool bright_mode = FALSE;
+ if (v >= 255-50) {
+ base = btn.dark(150);
+ bright_mode = TRUE;
+ }
+
+ QColorGroup cg( fg, btn, btn.light(),
+ btn.dark(), btn.dark(150), fg, Qt::white, base, bg );
+ if (bright_mode) {
+ cg.setColor( QColorGroup::HighlightedText, base );
+ cg.setColor( QColorGroup::Highlight, Qt::white );
+ } else {
+ cg.setColor( QColorGroup::HighlightedText, Qt::white );
+ cg.setColor( QColorGroup::Highlight, Qt::darkBlue );
+ }
+ QColor disabled( (fg.red()+btn.red())/2,
+ (fg.green()+btn.green())/2,
+ (fg.blue()+btn.blue())/2);
+ QColorGroup dcg( disabled, btn, btn.light( 125 ), btn.dark(), btn.dark(150),
+ disabled, Qt::white, Qt::white, bg );
+ if (bright_mode) {
+ dcg.setColor( QColorGroup::HighlightedText, base );
+ dcg.setColor( QColorGroup::Highlight, Qt::white );
+ } else {
+ dcg.setColor( QColorGroup::HighlightedText, Qt::white );
+ dcg.setColor( QColorGroup::Highlight, Qt::darkBlue );
+ }
+ QPalette pal( cg, dcg, cg );
+ if ( pal != *qt_std_pal && pal != QApplication::palette() )
+ QApplication::setPalette( pal, TRUE );
+ *qt_std_pal = pal;
+ }
+
+ if ( !resEF.isEmpty() ) {
+ QStringList effects = QStringList::split(" ",resEF);
+ QApplication::setEffectEnabled( Qt::UI_General, effects.contains("general") );
+ QApplication::setEffectEnabled( Qt::UI_AnimateMenu, effects.contains("animatemenu") );
+ QApplication::setEffectEnabled( Qt::UI_FadeMenu, effects.contains("fademenu") );
+ QApplication::setEffectEnabled( Qt::UI_AnimateCombo, effects.contains("animatecombo") );
+ QApplication::setEffectEnabled( Qt::UI_AnimateTooltip, effects.contains("animatetooltip") );
+ QApplication::setEffectEnabled( Qt::UI_FadeTooltip, effects.contains("fadetooltip") );
+ QApplication::setEffectEnabled( Qt::UI_AnimateToolBox, effects.contains("animatetoolbox") );
+ }
+}
+
+
+static void qt_detect_broken_window_manager()
+{
+ Atom type;
+ int format;
+ ulong nitems, after;
+ uchar *data = 0;
+
+ // look for SGI's 4Dwm
+ int e = XGetWindowProperty(appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_sgi_desks_manager, 0, 1, False, XA_WINDOW,
+ &type, &format, &nitems, &after, &data);
+ if (data)
+ XFree(data);
+
+ if (e == Success && type == XA_WINDOW && format == 32 && nitems == 1 && after == 0) {
+ // detected SGI 4Dwm
+ qt_broken_wm = TRUE;
+ }
+}
+
+
+// update the supported array
+void qt_get_net_supported()
+{
+ Atom type;
+ int format;
+ long offset = 0;
+ unsigned long nitems, after;
+ unsigned char *data = 0;
+
+ int e = XGetWindowProperty(appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_net_supported, 0, 0,
+ False, XA_ATOM, &type, &format, &nitems, &after, &data);
+ if (data)
+ XFree(data);
+
+ if (qt_net_supported_list)
+ delete [] qt_net_supported_list;
+ qt_net_supported_list = 0;
+
+ if (e == Success && type == XA_ATOM && format == 32) {
+ QBuffer ts;
+ ts.open(IO_WriteOnly);
+
+ while (after > 0) {
+ XGetWindowProperty(appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_net_supported, offset, 1024,
+ False, XA_ATOM, &type, &format, &nitems, &after, &data);
+
+ if (type == XA_ATOM && format == 32) {
+ ts.writeBlock((const char *) data, nitems * sizeof(long));
+ offset += nitems;
+ } else
+ after = 0;
+ if (data)
+ XFree(data);
+ }
+
+ // compute nitems
+ QByteArray buffer(ts.buffer());
+ nitems = buffer.size() / sizeof(Atom);
+ qt_net_supported_list = new Atom[nitems + 1];
+ Atom *a = (Atom *) buffer.data();
+ uint i;
+ for (i = 0; i < nitems; i++)
+ qt_net_supported_list[i] = a[i];
+ qt_net_supported_list[nitems] = 0;
+ }
+}
+
+
+bool qt_net_supports(Atom atom)
+{
+ if (! qt_net_supported_list)
+ return FALSE;
+
+ bool supported = FALSE;
+ int i = 0;
+ while (qt_net_supported_list[i] != 0) {
+ if (qt_net_supported_list[i++] == atom) {
+ supported = TRUE;
+ break;
+ }
+ }
+
+ return supported;
+}
+
+
+// update the virtual roots array
+void qt_get_net_virtual_roots()
+{
+ if (qt_net_virtual_root_list)
+ delete [] qt_net_virtual_root_list;
+ qt_net_virtual_root_list = 0;
+
+ if (! qt_net_supports(qt_net_virtual_roots))
+ return;
+
+ Atom type;
+ int format;
+ long offset = 0;
+ unsigned long nitems, after;
+ unsigned char *data;
+
+ int e = XGetWindowProperty(appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_net_virtual_roots, 0, 0,
+ False, XA_ATOM, &type, &format, &nitems, &after, &data);
+ if (data)
+ XFree(data);
+
+ if (e == Success && type == XA_ATOM && format == 32) {
+ QBuffer ts;
+ ts.open(IO_WriteOnly);
+
+ while (after > 0) {
+ XGetWindowProperty(appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_net_virtual_roots, offset, 1024,
+ False, XA_ATOM, &type, &format, &nitems, &after, &data);
+
+ if (type == XA_ATOM && format == 32) {
+ ts.writeBlock((const char *) data, nitems * 4);
+ offset += nitems;
+ } else
+ after = 0;
+ if (data)
+ XFree(data);
+ }
+
+ // compute nitems
+ QByteArray buffer(ts.buffer());
+ nitems = buffer.size() / sizeof(Window);
+ qt_net_virtual_root_list = new Window[nitems + 1];
+ Window *a = (Window *) buffer.data();
+ uint i;
+ for (i = 0; i < nitems; i++)
+ qt_net_virtual_root_list[i] = a[i];
+ qt_net_virtual_root_list[nitems] = 0;
+ }
+}
+
+void qt_x11_create_wm_client_leader()
+{
+ if ( qt_x11_wm_client_leader ) return;
+
+ qt_x11_wm_client_leader =
+ XCreateSimpleWindow( QPaintDevice::x11AppDisplay(),
+ QPaintDevice::x11AppRootWindow(),
+ 0, 0, 1, 1, 0, 0, 0 );
+
+ // set client leader property to itself
+ XChangeProperty( QPaintDevice::x11AppDisplay(),
+ qt_x11_wm_client_leader, qt_wm_client_leader,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)&qt_x11_wm_client_leader, 1 );
+
+ // If we are session managed, inform the window manager about it
+ QCString session = qApp->sessionId().latin1();
+ if ( !session.isEmpty() ) {
+ XChangeProperty( QPaintDevice::x11AppDisplay(),
+ qt_x11_wm_client_leader, qt_sm_client_id,
+ XA_STRING, 8, PropModeReplace,
+ (unsigned char *)session.data(), session.length() );
+ }
+}
+
+static void qt_net_update_user_time(QWidget *tlw)
+{
+ XChangeProperty(QPaintDevice::x11AppDisplay(), tlw->winId(), qt_net_wm_user_time, XA_CARDINAL,
+ 32, PropModeReplace, (unsigned char *) &qt_x_user_time, 1);
+}
+
+static void qt_check_focus_model()
+{
+ Window fw = None;
+ int unused;
+ XGetInputFocus( appDpy, &fw, &unused );
+ if ( fw == PointerRoot )
+ qt_focus_model = FocusModel_PointerRoot;
+ else
+ qt_focus_model = FocusModel_Other;
+}
+
+
+/*
+ Returns a truecolor visual (if there is one). 8-bit TrueColor visuals
+ are ignored, unless the user has explicitly requested -visual TrueColor.
+ The SGI X server usually has an 8 bit default visual, but the application
+ can also ask for a truecolor visual. This is what we do if
+ QApplication::colorSpec() is QApplication::ManyColor.
+*/
+
+static Visual *find_truecolor_visual( Display *dpy, int scr, int *depth, int *ncols )
+{
+ XVisualInfo *vi, rvi;
+ int best=0, n, i;
+ rvi.c_class = TrueColor;
+ rvi.screen = scr;
+ vi = XGetVisualInfo( dpy, VisualClassMask | VisualScreenMask,
+ &rvi, &n );
+ if ( vi ) {
+ for ( i=0; i<n; i++ ) {
+ if ( vi[i].depth > vi[best].depth )
+ best = i;
+ }
+ }
+ Visual *v = DefaultVisual(dpy,scr);
+ if ( !vi || (vi[best].visualid == XVisualIDFromVisual(v)) ||
+ (vi[best].depth <= 8 && qt_visual_option != TrueColor) )
+ {
+ *depth = DefaultDepth(dpy,scr);
+ *ncols = DisplayCells(dpy,scr);
+ } else {
+ v = vi[best].visual;
+ *depth = vi[best].depth;
+ *ncols = vi[best].colormap_size;
+ }
+ if ( vi )
+ XFree( (char *)vi );
+ return v;
+}
+
+
+/*****************************************************************************
+ qt_init() - initializes Qt for X11
+ *****************************************************************************/
+
+#define XK_MISCELLANY
+#define XK_LATIN1
+#define XK_KOREAN
+#define XK_XKB_KEYS
+#include <X11/keysymdef.h>
+
+// ### This should be static but it isn't because of the friend declaration
+// ### in qpaintdevice.h which then should have a static too but can't have
+// ### it because "storage class specifiers invalid in friend function
+// ### declarations" :-) Ideas anyone?
+void qt_init_internal( int *argcptr, char **argv,
+ Display *display, Qt::HANDLE visual, Qt::HANDLE colormap )
+{
+ setlocale( LC_ALL, "" ); // use correct char set mapping
+ setlocale( LC_NUMERIC, "C" ); // make sprintf()/scanf() work
+
+ if ( display ) {
+ // Qt part of other application
+
+ appForeignDpy = TRUE;
+ appDpy = display;
+
+ // Set application name and class
+ appName = qstrdup( "Qt-subapplication" );
+ char *app_class = 0;
+ if (argv) {
+ const char* p = strrchr( argv[0], '/' );
+ app_class = qstrdup(p ? p + 1 : argv[0]);
+ if (app_class[0])
+ app_class[0] = toupper(app_class[0]);
+ }
+ appClass = app_class;
+
+ // Install default error handlers
+ original_x_errhandler = XSetErrorHandler( qt_x_errhandler );
+ original_xio_errhandler = XSetIOErrorHandler( qt_xio_errhandler );
+ } else {
+ // Qt controls everything (default)
+
+ int argc = *argcptr;
+ int j;
+
+ // Install default error handlers
+ original_x_errhandler = XSetErrorHandler( qt_x_errhandler );
+ original_xio_errhandler = XSetIOErrorHandler( qt_xio_errhandler );
+
+ // Set application name and class
+ char *app_class = 0;
+ if (argv) {
+ const char *p = strrchr( argv[0], '/' );
+ appName = p ? p + 1 : argv[0];
+ app_class = qstrdup(appName);
+ if (app_class[0])
+ app_class[0] = toupper(app_class[0]);
+ }
+ appClass = app_class;
+
+ // Get command line params
+ j = argc ? 1 : 0;
+ for ( int i=1; i<argc; i++ ) {
+ if ( argv[i] && *argv[i] != '-' ) {
+ argv[j++] = argv[i];
+ continue;
+ }
+ QCString arg = argv[i];
+ if ( arg == "-display" ) {
+ if ( ++i < argc )
+ appDpyName = argv[i];
+ } else if ( arg == "-fn" || arg == "-font" ) {
+ if ( ++i < argc ) {
+ appFont = argv[i];
+ qt_x11_cmdline_font = true;
+ }
+ } else if ( arg == "-bg" || arg == "-background" ) {
+ if ( ++i < argc )
+ appBGCol = argv[i];
+ } else if ( arg == "-btn" || arg == "-button" ) {
+ if ( ++i < argc )
+ appBTNCol = argv[i];
+ } else if ( arg == "-fg" || arg == "-foreground" ) {
+ if ( ++i < argc )
+ appFGCol = argv[i];
+ } else if ( arg == "-name" ) {
+ if ( ++i < argc )
+ appName = argv[i];
+ } else if ( arg == "-title" ) {
+ if ( ++i < argc )
+ mwTitle = argv[i];
+ } else if ( arg == "-geometry" ) {
+ if ( ++i < argc )
+ mwGeometry = argv[i];
+ //Ming-Che 10/10
+ } else if ( arg == "-im" ) {
+ if ( ++i < argc )
+ qt_ximServer = argv[i];
+ } else if ( arg == "-iconic" ) {
+ mwIconic = !mwIconic;
+ } else if ( arg == "-ncols" ) { // xv and netscape use this name
+ if ( ++i < argc )
+ qt_ncols_option = QMAX(0,atoi(argv[i]));
+ } else if ( arg == "-visual" ) { // xv and netscape use this name
+ if ( ++i < argc ) {
+ QCString s = QCString(argv[i]).lower();
+ if ( s == "truecolor" ) {
+ qt_visual_option = TrueColor;
+ } else {
+ // ### Should we honor any others?
+ }
+ }
+#ifndef QT_NO_XIM
+ } else if ( arg == "-inputstyle" ) {
+ if ( ++i < argc ) {
+ QCString s = QCString(argv[i]).lower();
+ if ( s == "onthespot" )
+ qt_xim_preferred_style = XIMPreeditCallbacks |
+ XIMStatusNothing;
+ else if ( s == "overthespot" )
+ qt_xim_preferred_style = XIMPreeditPosition |
+ XIMStatusNothing;
+ else if ( s == "offthespot" )
+ qt_xim_preferred_style = XIMPreeditArea |
+ XIMStatusArea;
+ else if ( s == "root" )
+ qt_xim_preferred_style = XIMPreeditNothing |
+ XIMStatusNothing;
+ }
+#endif
+ } else if ( arg == "-cmap" ) { // xv uses this name
+ qt_cmap_option = TRUE;
+ }
+#if defined(QT_DEBUG)
+ else if ( arg == "-sync" )
+ appSync = !appSync;
+ else if ( arg == "-nograb" )
+ appNoGrab = !appNoGrab;
+ else if ( arg == "-dograb" )
+ appDoGrab = !appDoGrab;
+#endif
+ else
+ argv[j++] = argv[i];
+ }
+
+ *argcptr = j;
+
+#if defined(QT_DEBUG) && defined(Q_OS_LINUX)
+ if ( !appNoGrab && !appDoGrab ) {
+ QCString s;
+ s.sprintf( "/proc/%d/cmdline", getppid() );
+ QFile f( s );
+ if ( f.open( IO_ReadOnly ) ) {
+ s.truncate( 0 );
+ int c;
+ while ( (c = f.getch()) > 0 ) {
+ if ( c == '/' )
+ s.truncate( 0 );
+ else
+ s += (char)c;
+ }
+ if ( s == "gdb" ) {
+ appNoGrab = TRUE;
+ qDebug( "Qt: gdb: -nograb added to command-line options.\n"
+ "\t Use the -dograb option to enforce grabbing." );
+ }
+ f.close();
+ }
+ }
+#endif
+ // Connect to X server
+
+ if( qt_is_gui_used ) {
+ if ( ( appDpy = XOpenDisplay(appDpyName) ) == 0 ) {
+ qWarning( "%s: cannot connect to X server %s", appName,
+ XDisplayName(appDpyName) );
+ qApp = 0;
+ exit( 1 );
+ }
+
+ if ( appSync ) // if "-sync" argument
+ XSynchronize( appDpy, TRUE );
+ }
+ }
+ // Common code, regardless of whether display is foreign.
+
+ // Get X parameters
+
+ if( qt_is_gui_used ) {
+ appScreen = DefaultScreen(appDpy);
+ appScreenCount = ScreenCount(appDpy);
+
+ QPaintDevice::x_appdisplay = appDpy;
+ QPaintDevice::x_appscreen = appScreen;
+
+ // allocate the arrays for the QPaintDevice data
+ QPaintDevice::x_appdepth_arr = new int[ appScreenCount ];
+ QPaintDevice::x_appcells_arr = new int[ appScreenCount ];
+ QPaintDevice::x_approotwindow_arr = new Qt::HANDLE[ appScreenCount ];
+ QPaintDevice::x_appcolormap_arr = new Qt::HANDLE[ appScreenCount ];
+ QPaintDevice::x_appdefcolormap_arr = new bool[ appScreenCount ];
+ QPaintDevice::x_appvisual_arr = new void*[ appScreenCount ];
+ QPaintDevice::x_appdefvisual_arr = new bool[ appScreenCount ];
+ Q_CHECK_PTR( QPaintDevice::x_appdepth_arr );
+ Q_CHECK_PTR( QPaintDevice::x_appcells_arr );
+ Q_CHECK_PTR( QPaintDevice::x_approotwindow_arr );
+ Q_CHECK_PTR( QPaintDevice::x_appcolormap_arr );
+ Q_CHECK_PTR( QPaintDevice::x_appdefcolormap_arr );
+ Q_CHECK_PTR( QPaintDevice::x_appvisual_arr );
+ Q_CHECK_PTR( QPaintDevice::x_appdefvisual_arr );
+
+ int screen;
+ QString serverVendor( ServerVendor( appDpy) );
+ if (serverVendor.contains("XFree86") && VendorRelease(appDpy) < 40300000)
+ qt_hebrew_keyboard_hack = TRUE;
+
+ for ( screen = 0; screen < appScreenCount; ++screen ) {
+ QPaintDevice::x_appdepth_arr[ screen ] = DefaultDepth(appDpy, screen);
+ QPaintDevice::x_appcells_arr[ screen ] = DisplayCells(appDpy, screen);
+ QPaintDevice::x_approotwindow_arr[ screen ] = RootWindow(appDpy, screen);
+
+ // setup the visual and colormap for each screen
+ Visual *vis = 0;
+ if ( visual && screen == appScreen ) {
+ // use the provided visual on the default screen only
+ vis = (Visual *) visual;
+
+ // figure out the depth of the visual we are using
+ XVisualInfo *vi, rvi;
+ int n;
+ rvi.visualid = XVisualIDFromVisual(vis);
+ rvi.screen = screen;
+ vi = XGetVisualInfo( appDpy, VisualIDMask | VisualScreenMask, &rvi, &n );
+ if (vi) {
+ QPaintDevice::x_appdepth_arr[ screen ] = vi->depth;
+ QPaintDevice::x_appcells_arr[ screen ] = vi->visual->map_entries;
+ QPaintDevice::x_appvisual_arr[ screen ] = vi->visual;
+ QPaintDevice::x_appdefvisual_arr[ screen ] = FALSE;
+ XFree(vi);
+ } else {
+ // couldn't get info about the visual, use the default instead
+ vis = 0;
+ }
+ }
+
+ if (!vis) {
+ // use the default visual
+ vis = DefaultVisual(appDpy, screen);
+ QPaintDevice::x_appdefvisual_arr[ screen ] = TRUE;
+
+ if ( qt_visual_option == TrueColor ||
+ QApplication::colorSpec() == QApplication::ManyColor ) {
+ // find custom visual
+
+ int d, c;
+ vis = find_truecolor_visual( appDpy, screen, &d, &c );
+ QPaintDevice::x_appdepth_arr[ screen ] = d;
+ QPaintDevice::x_appcells_arr[ screen ] = c;
+
+ QPaintDevice::x_appvisual_arr[ screen ] = vis;
+ QPaintDevice::x_appdefvisual_arr[ screen ] =
+ (XVisualIDFromVisual(vis) ==
+ XVisualIDFromVisual(DefaultVisual(appDpy, screen)));
+ }
+
+ QPaintDevice::x_appvisual_arr[ screen ] = vis;
+ }
+
+ // we assume that 8bpp == pseudocolor, but this is not
+ // always the case (according to the X server), so we need
+ // to make sure that our internal data is setup in a way
+ // that is compatible with our assumptions
+ if ( vis->c_class == TrueColor &&
+ QPaintDevice::x_appdepth_arr[ screen ] == 8 &&
+ QPaintDevice::x_appcells_arr[ screen ] == 8 )
+ QPaintDevice::x_appcells_arr[ screen ] = 256;
+
+ if ( colormap && screen == appScreen ) {
+ // use the provided colormap for the default screen only
+ QPaintDevice::x_appcolormap_arr[ screen ] = colormap;
+ QPaintDevice::x_appdefcolormap_arr[ screen ] = FALSE;
+ } else {
+ if ( vis->c_class == TrueColor ) {
+ QPaintDevice::x_appdefcolormap_arr[ screen ] =
+ QPaintDevice::x_appdefvisual_arr[ screen ];
+ } else {
+ QPaintDevice::x_appdefcolormap_arr[ screen ] =
+ !qt_cmap_option && QPaintDevice::x_appdefvisual_arr[ screen ];
+ }
+
+ if ( QPaintDevice::x_appdefcolormap_arr[ screen ] ) {
+ // use default colormap
+ XStandardColormap *stdcmap;
+ VisualID vid =
+ XVisualIDFromVisual((Visual *)
+ QPaintDevice::x_appvisual_arr[ screen ]);
+ int i, count;
+
+ QPaintDevice::x_appcolormap_arr[ screen ] = 0;
+
+ if ( ! serverVendor.contains( "Hewlett-Packard" ) ) {
+ // on HPUX 10.20 local displays, the RGB_DEFAULT_MAP colormap
+ // doesn't give us correct colors. Why this happens, I have
+ // no clue, so we disable this for HPUX
+ if (XGetRGBColormaps(appDpy,
+ QPaintDevice::x11AppRootWindow( screen ),
+ &stdcmap, &count, XA_RGB_DEFAULT_MAP)) {
+ i = 0;
+ while (i < count &&
+ QPaintDevice::x_appcolormap_arr[ screen ] == 0) {
+ if (stdcmap[i].visualid == vid) {
+ QPaintDevice::x_appcolormap_arr[ screen ] =
+ stdcmap[i].colormap;
+ }
+ i++;
+ }
+
+ XFree( (char *)stdcmap );
+ }
+ }
+
+ if (QPaintDevice::x_appcolormap_arr[ screen ] == 0) {
+ QPaintDevice::x_appcolormap_arr[ screen ] =
+ DefaultColormap(appDpy, screen);
+ }
+ } else {
+ // create a custom colormap
+ QPaintDevice::x_appcolormap_arr[ screen ] =
+ XCreateColormap(appDpy, QPaintDevice::x11AppRootWindow( screen ),
+ vis, AllocNone);
+ }
+ }
+ }
+
+ // Set X paintdevice parameters for the default screen
+ QPaintDevice::x_appdepth = QPaintDevice::x_appdepth_arr[ appScreen ];
+ QPaintDevice::x_appcells = QPaintDevice::x_appcells_arr[ appScreen ];
+ QPaintDevice::x_approotwindow = QPaintDevice::x_approotwindow_arr[ appScreen ];
+ QPaintDevice::x_appcolormap = QPaintDevice::x_appcolormap_arr[ appScreen ];
+ QPaintDevice::x_appdefcolormap = QPaintDevice::x_appdefcolormap_arr[ appScreen ];
+ QPaintDevice::x_appvisual = QPaintDevice::x_appvisual_arr[ appScreen ];
+ QPaintDevice::x_appdefvisual = QPaintDevice::x_appdefvisual_arr[ appScreen ];
+
+ // Support protocols
+
+ qt_x11_intern_atom( "WM_PROTOCOLS", &qt_wm_protocols );
+ qt_x11_intern_atom( "WM_DELETE_WINDOW", &qt_wm_delete_window );
+ qt_x11_intern_atom( "WM_STATE", &qt_wm_state );
+ qt_x11_intern_atom( "WM_CHANGE_STATE", &qt_wm_change_state );
+ qt_x11_intern_atom( "WM_TAKE_FOCUS", &qt_wm_take_focus );
+ qt_x11_intern_atom( "WM_CLIENT_LEADER", &qt_wm_client_leader);
+ qt_x11_intern_atom( "WM_WINDOW_ROLE", &qt_window_role);
+ qt_x11_intern_atom( "SM_CLIENT_ID", &qt_sm_client_id);
+ qt_x11_intern_atom( "CLIPBOARD", &qt_xa_clipboard );
+ qt_x11_intern_atom( "RESOURCE_MANAGER", &qt_resource_manager );
+ qt_x11_intern_atom( "INCR", &qt_x_incr );
+ qt_x11_intern_atom( "_XSETROOT_ID", &qt_xsetroot_id );
+ qt_x11_intern_atom( "_QT_SELECTION", &qt_selection_property );
+ qt_x11_intern_atom( "_QT_CLIPBOARD_SENTINEL", &qt_clipboard_sentinel );
+ qt_x11_intern_atom( "_QT_SELECTION_SENTINEL", &qt_selection_sentinel );
+ qt_x11_intern_atom( "_QT_SCROLL_DONE", &qt_qt_scrolldone );
+ qt_x11_intern_atom( "_QT_INPUT_ENCODING", &qt_input_encoding );
+ qt_x11_intern_atom( "_QT_SIZEGRIP", &qt_sizegrip );
+ qt_x11_intern_atom( "_NET_WM_CONTEXT_HELP", &qt_net_wm_context_help );
+ qt_x11_intern_atom( "_NET_WM_PING", &qt_net_wm_ping );
+ qt_x11_intern_atom( "_MOTIF_WM_HINTS", &qt_xa_motif_wm_hints );
+ qt_x11_intern_atom( "DTWM_IS_RUNNING", &qt_cde_running );
+ qt_x11_intern_atom( "KWIN_RUNNING", &qt_kwin_running );
+ qt_x11_intern_atom( "KWM_RUNNING", &qt_kwm_running );
+ qt_x11_intern_atom( "GNOME_BACKGROUND_PROPERTIES", &qt_gbackground_properties );
+
+ QString atomname("_QT_SETTINGS_TIMESTAMP_");
+ atomname += XDisplayName(appDpyName);
+ qt_x11_intern_atom( atomname.latin1(), &qt_settings_timestamp );
+
+ qt_x11_intern_atom( "_NET_SUPPORTED", &qt_net_supported );
+ qt_x11_intern_atom( "_NET_VIRTUAL_ROOTS", &qt_net_virtual_roots );
+ qt_x11_intern_atom( "_NET_WORKAREA", &qt_net_workarea );
+ qt_x11_intern_atom( "_NET_WM_STATE", &qt_net_wm_state );
+ qt_x11_intern_atom( "_NET_WM_STATE_MODAL", &qt_net_wm_state_modal );
+ qt_x11_intern_atom( "_NET_WM_STATE_MAXIMIZED_VERT", &qt_net_wm_state_max_v );
+ qt_x11_intern_atom( "_NET_WM_STATE_MAXIMIZED_HORZ", &qt_net_wm_state_max_h );
+ qt_x11_intern_atom( "_NET_WM_STATE_FULLSCREEN", &qt_net_wm_state_fullscreen );
+ qt_x11_intern_atom( "_NET_WM_STATE_ABOVE", &qt_net_wm_state_above );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE", &qt_net_wm_window_type );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_NORMAL", &qt_net_wm_window_type_normal );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_DIALOG", &qt_net_wm_window_type_dialog );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_TOOLBAR", &qt_net_wm_window_type_toolbar );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_MENU", &qt_net_wm_window_type_menu );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_UTILITY", &qt_net_wm_window_type_utility );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_SPLASH", &qt_net_wm_window_type_splash );
+ qt_x11_intern_atom( "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", &qt_net_wm_window_type_override );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", &qt_net_wm_window_type_dropdown_menu );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_POPUP_MENU", &qt_net_wm_window_type_popup_menu );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_TOOLTIP", &qt_net_wm_window_type_tooltip );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_COMBO", &qt_net_wm_window_type_combo );
+ qt_x11_intern_atom( "_NET_WM_WINDOW_TYPE_DND", &qt_net_wm_window_type_dnd );
+ qt_x11_intern_atom( "_KDE_NET_WM_FRAME_STRUT", &qt_net_wm_frame_strut );
+ qt_x11_intern_atom( "_NET_WM_STATE_STAYS_ON_TOP",
+ &qt_net_wm_state_stays_on_top );
+ qt_x11_intern_atom( "_NET_WM_PID", &qt_net_wm_pid );
+ qt_x11_intern_atom( "_NET_WM_USER_TIME", &qt_net_wm_user_time );
+ qt_x11_intern_atom( "_NET_WM_FULL_PLACEMENT", &qt_net_wm_full_placement );
+ qt_x11_intern_atom( "ENLIGHTENMENT_DESKTOP", &qt_enlightenment_desktop );
+ qt_x11_intern_atom( "_NET_WM_NAME", &qt_net_wm_name );
+ qt_x11_intern_atom( "_NET_WM_ICON_NAME", &qt_net_wm_icon_name );
+ qt_x11_intern_atom( "UTF8_STRING", &qt_utf8_string );
+ qt_x11_intern_atom( "_SGI_DESKS_MANAGER", &qt_sgi_desks_manager );
+
+#ifndef QT_NO_XSYNC
+ qt_x11_intern_atom( "_NET_WM_SYNC_REQUEST_COUNTER", &qt_net_wm_sync_request_counter );
+ qt_x11_intern_atom( "_NET_WM_SYNC_REQUEST", &qt_net_wm_sync_request );
+#endif
+
+ qt_xdnd_setup();
+ qt_x11_motifdnd_init();
+
+ // Finally create all atoms
+ qt_x11_process_intern_atoms();
+
+ // look for broken window managers
+ qt_detect_broken_window_manager();
+
+ // initialize NET lists
+ qt_get_net_supported();
+ qt_get_net_virtual_roots();
+
+#ifndef QT_NO_XRANDR
+ // See if XRandR is supported on the connected display
+ int xrandr_errorbase;
+ Q_UNUSED( xrandr_eventbase );
+ if ( XRRQueryExtension( appDpy, &xrandr_eventbase, &xrandr_errorbase ) ) {
+ // XRandR is supported
+ qt_use_xrandr = TRUE;
+ }
+#endif // QT_NO_XRANDR
+
+#ifndef QT_NO_XRENDER
+ // See if XRender is supported on the connected display
+ int xrender_eventbase, xrender_errorbase;
+ if (XRenderQueryExtension(appDpy, &xrender_eventbase, &xrender_errorbase)) {
+ // XRender is supported, let's see if we have a PictFormat for the
+ // default visual
+ XRenderPictFormat *format =
+ XRenderFindVisualFormat(appDpy,
+ (Visual *) QPaintDevice::x_appvisual);
+ qt_use_xrender = (format != 0) && (QPaintDevice::x_appdepth != 8);
+ }
+#endif // QT_NO_XRENDER
+
+#ifndef QT_NO_XSYNC
+ // Try to initialize SYNC extension on the connected display
+ int xsync_major, xsync_minor;
+ if ( XSyncQueryExtension( appDpy, &xsync_eventbase, &xsync_errorbase ) &&
+ XSyncInitialize( appDpy, &xsync_major, &xsync_minor ) ) {
+ qt_use_xsync = TRUE;
+ }
+#endif
+
+#ifndef QT_NO_XKB
+ // If XKB is detected, set the GrabsUseXKBState option so input method
+ // compositions continue to work (ie. deadkeys)
+ unsigned int state = XkbPCF_GrabsUseXKBStateMask;
+ (void) XkbSetPerClientControls(appDpy, state, &state);
+#endif
+
+#if !defined(QT_NO_XFTFREETYPE)
+ // defined in qfont_x11.cpp
+ extern bool qt_has_xft;
+#ifndef QT_XFT2
+ if (!qt_use_xrender)
+ qt_has_xft = FALSE;
+ else
+#endif
+ qt_has_xft = XftInit(0) && XftInitFtLibrary();
+
+ if (qt_has_xft) {
+ char *dpi_str = XGetDefault(appDpy, "Xft", "dpi");
+ if (dpi_str) {
+ // use a custom DPI
+ char *end = 0;
+ int dpi = strtol(dpi_str, &end, 0);
+ if (dpi_str != end) {
+ for (int s = 0; s < ScreenCount(appDpy); ++s) {
+ QPaintDevice::x11SetAppDpiX(dpi, s);
+ QPaintDevice::x11SetAppDpiY(dpi, s);
+ }
+ }
+ }
+ }
+#endif // QT_NO_XFTFREETYPE
+
+ // look at the modifier mapping, and get the correct masks for alt/meta
+ // find the alt/meta masks
+ XModifierKeymap *map = XGetModifierMapping(appDpy);
+ if (map) {
+ int i, maskIndex = 0, mapIndex = 0;
+ for (maskIndex = 0; maskIndex < 8; maskIndex++) {
+ for (i = 0; i < map->max_keypermod; i++) {
+ if (map->modifiermap[mapIndex]) {
+ KeySym sym =
+ XKeycodeToKeysym(appDpy, map->modifiermap[mapIndex], 0);
+ if ( qt_alt_mask == 0 &&
+ ( sym == XK_Alt_L || sym == XK_Alt_R ) ) {
+ qt_alt_mask = 1 << maskIndex;
+ }
+ if ( qt_meta_mask == 0 &&
+ (sym == XK_Meta_L || sym == XK_Meta_R ) ) {
+ qt_meta_mask = 1 << maskIndex;
+ }
+ }
+ mapIndex++;
+ }
+ }
+
+ // not look for mode_switch in qt_alt_mask and qt_meta_mask - if it is
+ // present in one or both, then we set qt_mode_switch_remove_mask.
+ // see QETWidget::translateKeyEventInternal for an explanation
+ // of why this is needed
+ mapIndex = 0;
+ for ( maskIndex = 0; maskIndex < 8; maskIndex++ ) {
+ if ( qt_alt_mask != ( 1 << maskIndex ) &&
+ qt_meta_mask != ( 1 << maskIndex ) ) {
+ for ( i = 0; i < map->max_keypermod; i++ )
+ mapIndex++;
+ continue;
+ }
+
+ for ( i = 0; i < map->max_keypermod; i++ ) {
+ if ( map->modifiermap[ mapIndex ] ) {
+ KeySym sym =
+ XKeycodeToKeysym( appDpy, map->modifiermap[ mapIndex ], 0 );
+ if ( sym == XK_Mode_switch ) {
+ qt_mode_switch_remove_mask |= 1 << maskIndex;
+ }
+ }
+ mapIndex++;
+ }
+ }
+
+ XFreeModifiermap(map);
+ } else {
+ // assume defaults
+ qt_alt_mask = Mod1Mask;
+ qt_meta_mask = Mod4Mask;
+ qt_mode_switch_remove_mask = 0;
+ }
+
+ // Misc. initialization
+
+ QColor::initialize();
+ QFont::initialize();
+ QCursor::initialize();
+ QPainter::initialize();
+ }
+
+#if defined(QT_THREAD_SUPPORT)
+ QThread::initialize();
+#endif
+
+ if( qt_is_gui_used ) {
+ qApp->setName( appName );
+
+ int screen;
+ for ( screen = 0; screen < appScreenCount; ++screen ) {
+ XSelectInput( appDpy, QPaintDevice::x11AppRootWindow( screen ),
+ KeymapStateMask | EnterWindowMask | LeaveWindowMask |
+ PropertyChangeMask );
+
+#ifndef QT_NO_XRANDR
+ if (qt_use_xrandr)
+ XRRSelectInput( appDpy, QPaintDevice::x11AppRootWindow( screen ), True );
+#endif // QT_NO_XRANDR
+ }
+ }
+
+ if ( qt_is_gui_used ) {
+ qt_set_input_encoding();
+
+ qt_set_x11_resources( appFont, appFGCol, appBGCol, appBTNCol);
+
+ // be smart about the size of the default font. most X servers have helvetica
+ // 12 point available at 2 resolutions:
+ // 75dpi (12 pixels) and 100dpi (17 pixels).
+ // At 95 DPI, a 12 point font should be 16 pixels tall - in which case a 17
+ // pixel font is a closer match than a 12 pixel font
+ int ptsz =
+ (int) ( ( ( QPaintDevice::x11AppDpiY() >= 95 ? 17. : 12. ) *
+ 72. / (float) QPaintDevice::x11AppDpiY() ) + 0.5 );
+
+ if ( !qt_app_has_font && !qt_x11_cmdline_font ) {
+ QFont f( "Helvetica", ptsz );
+ QApplication::setFont( f );
+ }
+
+#if !defined(QT_NO_IM)
+#if !defined(QT_NO_IM_EXTENSIONS)
+ QApplication::create_im();
+#else
+ QApplication::create_xim();
+#endif
+#endif
+
+#if defined (QT_TABLET_SUPPORT)
+ int ndev,
+ i,
+ j;
+ bool gotStylus,
+ gotEraser;
+ XDeviceInfo *devices, *devs;
+ XInputClassInfo *ip;
+ XAnyClassPtr any;
+ XValuatorInfoPtr v;
+ XAxisInfoPtr a;
+ XDevice *dev;
+ XEventClass *ev_class;
+ int curr_event_count;
+
+#if !defined(Q_OS_IRIX)
+ // XFree86 divides a stylus and eraser into 2 devices, so we must do for both...
+ const QString XFREENAMESTYLUS = "stylus";
+ const QString XFREENAMEPEN = "pen";
+ const QString XFREENAMEERASER = "eraser";
+#endif
+
+ devices = XListInputDevices( appDpy, &ndev);
+ if ( devices == NULL ) {
+ qWarning( "Failed to get list of devices" );
+ ndev = -1;
+ }
+ dev = NULL;
+ for ( devs = devices, i = 0; i < ndev; i++, devs++ ) {
+ gotEraser = FALSE;
+#if defined(Q_OS_IRIX)
+
+ gotStylus = ( !strncmp(devs->name,
+ WACOM_NAME, sizeof(WACOM_NAME) - 1) );
+#else
+ QString devName = devs->name;
+ devName = devName.lower();
+ gotStylus = ( devName.startsWith(XFREENAMEPEN)
+ || devName.startsWith(XFREENAMESTYLUS) );
+ if ( !gotStylus )
+ gotEraser = devName.startsWith( XFREENAMEERASER );
+
+#endif
+ if ( gotStylus || gotEraser ) {
+ // I only wanted to do this once, so wrap pointers around these
+ curr_event_count = 0;
+
+ if ( gotStylus ) {
+ devStylus = XOpenDevice( appDpy, devs->id );
+ dev = devStylus;
+ ev_class = event_list_stylus;
+ } else if ( gotEraser ) {
+ devEraser = XOpenDevice( appDpy, devs->id );
+ dev = devEraser;
+ ev_class = event_list_eraser;
+ }
+ if ( dev == NULL ) {
+ qWarning( "Failed to open device" );
+ } else {
+ if ( dev->num_classes > 0 ) {
+ for ( ip = dev->classes, j = 0; j < devs->num_classes;
+ ip++, j++ ) {
+ switch ( ip->input_class ) {
+ case KeyClass:
+ DeviceKeyPress( dev, xinput_key_press,
+ ev_class[curr_event_count] );
+ curr_event_count++;
+ DeviceKeyRelease( dev, xinput_key_release,
+ ev_class[curr_event_count] );
+ curr_event_count++;
+ break;
+ case ButtonClass:
+ DeviceButtonPress( dev, xinput_button_press,
+ ev_class[curr_event_count] );
+ curr_event_count++;
+ DeviceButtonRelease( dev, xinput_button_release,
+ ev_class[curr_event_count] );
+ curr_event_count++;
+ break;
+ case ValuatorClass:
+ // I'm only going to be interested in motion when the
+ // stylus is already down anyway!
+ DeviceMotionNotify( dev, xinput_motion,
+ ev_class[curr_event_count] );
+ curr_event_count++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ // get the min/max value for pressure!
+ any = (XAnyClassPtr) ( devs->inputclassinfo );
+ if ( dev == devStylus ) {
+ qt_curr_events_stylus = curr_event_count;
+ for (j = 0; j < devs->num_classes; j++) {
+ if ( any->c_class == ValuatorClass ) {
+ v = (XValuatorInfoPtr) any;
+ a = (XAxisInfoPtr) ((char *) v +
+ sizeof (XValuatorInfo));
+#if defined (Q_OS_IRIX)
+ max_pressure = a[WAC_PRESSURE_I].max_value;
+#else
+ max_pressure = a[2].max_value;
+#endif
+ // got the max pressure no need to go further...
+ break;
+ }
+ any = (XAnyClassPtr) ((char *) any + any->length);
+ }
+ } else {
+ qt_curr_events_eraser = curr_event_count;
+ }
+ // at this point we are assuming there is only one
+ // wacom device...
+#if defined (Q_OS_IRIX)
+ if ( devStylus != NULL ) {
+#else
+ if ( devStylus != NULL && devEraser != NULL ) {
+#endif
+ break;
+ }
+ }
+ } // end for loop
+ XFreeDeviceList( devices );
+#endif // QT_TABLET_SUPPORT
+
+ } else {
+ // read some non-GUI settings when not using the X server...
+
+ if ( QApplication::desktopSettingsAware() ) {
+ QSettings settings;
+
+ // read library (ie. plugin) path list
+ QString libpathkey = QString("/qt/%1.%2/libraryPath")
+ .arg( QT_VERSION >> 16 )
+ .arg( (QT_VERSION & 0xff00 ) >> 8 );
+ QStringList pathlist =
+ settings.readListEntry(libpathkey, ':');
+ if (! pathlist.isEmpty()) {
+ QStringList::ConstIterator it = pathlist.begin();
+ while (it != pathlist.end())
+ QApplication::addLibraryPath(*it++);
+ }
+
+ QString defaultcodec = settings.readEntry("/qt/defaultCodec", "none");
+ if (defaultcodec != "none") {
+ QTextCodec *codec = QTextCodec::codecForName(defaultcodec);
+ if (codec)
+ qApp->setDefaultCodec(codec);
+ }
+
+ qt_resolve_symlinks =
+ settings.readBoolEntry("/qt/resolveSymlinks", TRUE);
+ }
+ }
+ }
+
+
+#ifndef QT_NO_STYLE
+ // run-time search for default style
+void QApplication::x11_initialize_style()
+{
+ Atom type;
+ int format;
+ unsigned long length, after;
+ uchar *data;
+ if ( !app_style &&
+ XGetWindowProperty( appDpy, QPaintDevice::x11AppRootWindow(), qt_kwin_running,
+ 0, 1, False, AnyPropertyType, &type, &format, &length,
+ &after, &data ) == Success && length ) {
+ if ( data ) XFree( (char *)data );
+ // kwin is there. check if KDE's styles are available,
+ // otherwise use windows style
+ if ( (app_style = QStyleFactory::create("highcolor") ) == 0 )
+ app_style = QStyleFactory::create("windows");
+ }
+ if ( !app_style &&
+ XGetWindowProperty( appDpy, QPaintDevice::x11AppRootWindow(), qt_kwm_running,
+ 0, 1, False, AnyPropertyType, &type, &format, &length,
+ &after, &data ) == Success && length ) {
+ if ( data ) XFree( (char *)data );
+ app_style = QStyleFactory::create("windows");
+ }
+ if ( !app_style &&
+ XGetWindowProperty( appDpy, QPaintDevice::x11AppRootWindow(), qt_cde_running,
+ 0, 1, False, AnyPropertyType, &type, &format, &length,
+ &after, &data ) == Success && length ) {
+ // DTWM is running, meaning most likely CDE is running...
+ if ( data ) XFree( (char *) data );
+ app_style = QStyleFactory::create( "cde" );
+ }
+ // maybe another desktop?
+ if ( !app_style &&
+ XGetWindowProperty( appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_gbackground_properties, 0, 1, False, AnyPropertyType,
+ &type, &format, &length, &after, &data ) == Success &&
+ length ) {
+ if ( data ) XFree( (char *)data );
+ // default to MotifPlus with hovering
+ app_style = QStyleFactory::create("motifplus" );
+ }
+}
+#endif
+
+void qt_init( int *argcptr, char **argv, QApplication::Type )
+{
+ qt_init_internal( argcptr, argv, 0, 0, 0 );
+}
+
+void qt_init( Display *display, Qt::HANDLE visual, Qt::HANDLE colormap )
+{
+ qt_init_internal( 0, 0, display, visual, colormap );
+}
+
+
+/*****************************************************************************
+ qt_cleanup() - cleans up when the application is finished
+ *****************************************************************************/
+
+void qt_cleanup()
+{
+ appliedstamp = 0;
+
+ if ( app_save_rootinfo ) // root window must keep state
+ qt_save_rootinfo();
+
+ if ( qt_is_gui_used ) {
+ QPixmapCache::clear();
+ QPainter::cleanup();
+ QCursor::cleanup();
+ QFont::cleanup();
+ QColor::cleanup();
+ QSharedDoubleBuffer::cleanup();
+ }
+#if defined(QT_THREAD_SUPPORT)
+ QThread::cleanup();
+#endif
+
+#if defined (QT_TABLET_SUPPORT)
+ if ( devStylus != NULL )
+ XCloseDevice( appDpy, devStylus );
+ if ( devEraser != NULL )
+ XCloseDevice( appDpy, devEraser );
+#endif
+
+#if !defined(QT_NO_IM)
+#if !defined(QT_NO_IM_EXTENSIONS)
+ QApplication::close_im();
+#else
+ QApplication::close_xim();
+#endif
+#endif
+
+ if ( qt_is_gui_used ) {
+ int screen;
+ for ( screen = 0; screen < appScreenCount; screen++ ) {
+ if ( ! QPaintDevice::x11AppDefaultColormap( screen ) )
+ XFreeColormap( QPaintDevice::x11AppDisplay(),
+ QPaintDevice::x11AppColormap( screen ) );
+ }
+ }
+
+#define QT_CLEANUP_GC(g) if (g) { for (int i=0;i<appScreenCount;i++){if(g[i])XFreeGC(appDpy,g[i]);} delete [] g; g = 0; }
+ QT_CLEANUP_GC(app_gc_ro);
+ QT_CLEANUP_GC(app_gc_ro_m);
+ QT_CLEANUP_GC(app_gc_tmp);
+ QT_CLEANUP_GC(app_gc_tmp_m);
+#undef QT_CLEANUP_GC
+
+ delete sip_list;
+ sip_list = 0;
+
+ // Reset the error handlers
+ XSetErrorHandler( original_x_errhandler );
+ XSetIOErrorHandler( original_xio_errhandler );
+
+ if ( qt_is_gui_used && !appForeignDpy )
+ XCloseDisplay( appDpy ); // close X display
+ appDpy = 0;
+
+ qt_x11_wm_client_leader = 0;
+
+ if ( QPaintDevice::x_appdepth_arr )
+ delete [] QPaintDevice::x_appdepth_arr;
+ if ( QPaintDevice::x_appcells_arr )
+ delete [] QPaintDevice::x_appcells_arr;
+ if ( QPaintDevice::x_appcolormap_arr )
+ delete []QPaintDevice::x_appcolormap_arr;
+ if ( QPaintDevice::x_appdefcolormap_arr )
+ delete [] QPaintDevice::x_appdefcolormap_arr;
+ if ( QPaintDevice::x_appvisual_arr )
+ delete [] QPaintDevice::x_appvisual_arr;
+ if ( QPaintDevice::x_appdefvisual_arr )
+ delete [] QPaintDevice::x_appdefvisual_arr;
+
+ if ( appForeignDpy ) {
+ delete [] (char *)appName;
+ appName = 0;
+ delete [] (char *)appClass;
+ appClass = 0;
+ }
+
+ if (qt_net_supported_list)
+ delete [] qt_net_supported_list;
+ qt_net_supported_list = 0;
+
+ if (qt_net_virtual_root_list)
+ delete [] qt_net_virtual_root_list;
+ qt_net_virtual_root_list = 0;
+}
+
+
+/*****************************************************************************
+ Platform specific global and internal functions
+ *****************************************************************************/
+
+void qt_save_rootinfo() // save new root info
+{
+ Atom type;
+ int format;
+ unsigned long length, after;
+ uchar *data;
+
+ if ( qt_xsetroot_id ) { // kill old pixmap
+ if ( XGetWindowProperty( appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_xsetroot_id, 0, 1,
+ True, AnyPropertyType, &type, &format,
+ &length, &after, &data ) == Success ) {
+ if ( type == XA_PIXMAP && format == 32 && length == 1 &&
+ after == 0 && data ) {
+ XKillClient( appDpy, *((Pixmap*)data) );
+ }
+ Pixmap dummy = XCreatePixmap( appDpy, QPaintDevice::x11AppRootWindow(),
+ 1, 1, 1 );
+ XChangeProperty( appDpy, QPaintDevice::x11AppRootWindow(),
+ qt_xsetroot_id, XA_PIXMAP, 32,
+ PropModeReplace, (uchar *)&dummy, 1 );
+ XSetCloseDownMode( appDpy, RetainPermanent );
+ }
+ }
+ if ( data )
+ XFree( (char *)data );
+}
+
+void qt_updated_rootinfo()
+{
+ app_save_rootinfo = TRUE;
+}
+
+bool qt_wstate_iconified( WId winid )
+{
+ Atom type;
+ int format;
+ unsigned long length, after;
+ uchar *data;
+ int r = XGetWindowProperty( appDpy, winid, qt_wm_state, 0, 2,
+ False, AnyPropertyType, &type, &format,
+ &length, &after, &data );
+ bool iconic = FALSE;
+ if ( r == Success && data && format == 32 ) {
+ // Q_UINT32 *wstate = (Q_UINT32*)data;
+ unsigned long *wstate = (unsigned long *) data;
+ iconic = (*wstate == IconicState );
+ XFree( (char *)data );
+ }
+ return iconic;
+}
+
+const char *qAppName() // get application name
+{
+ return appName;
+}
+
+const char *qAppClass() // get application class
+{
+ return appClass;
+}
+
+Display *qt_xdisplay() // get current X display
+{
+ return appDpy;
+}
+
+int qt_xscreen() // get current X screen
+{
+ return appScreen;
+}
+
+// ### REMOVE 4.0
+WId qt_xrootwin() // get X root window
+{
+ return QPaintDevice::x11AppRootWindow();
+}
+
+WId qt_xrootwin( int scrn ) // get X root window for screen
+{
+ return QPaintDevice::x11AppRootWindow( scrn );
+}
+
+bool qt_nograb() // application no-grab option
+{
+#if defined(QT_DEBUG)
+ return appNoGrab;
+#else
+ return FALSE;
+#endif
+}
+
+static GC create_gc( int scrn, bool monochrome )
+{
+ GC gc;
+ if ( monochrome ) {
+ Pixmap pm = XCreatePixmap( appDpy, RootWindow( appDpy, scrn ), 8, 8, 1 );
+ gc = XCreateGC( appDpy, pm, 0, 0 );
+ XFreePixmap( appDpy, pm );
+ } else {
+ if ( QPaintDevice::x11AppDefaultVisual( scrn ) ) {
+ gc = XCreateGC( appDpy, RootWindow( appDpy, scrn ), 0, 0 );
+ } else {
+ Window w;
+ XSetWindowAttributes a;
+ a.background_pixel = Qt::black.pixel( scrn );
+ a.border_pixel = Qt::black.pixel( scrn );
+ a.colormap = QPaintDevice::x11AppColormap( scrn );
+ w = XCreateWindow( appDpy, RootWindow( appDpy, scrn ), 0, 0, 100, 100,
+ 0, QPaintDevice::x11AppDepth( scrn ), InputOutput,
+ (Visual*)QPaintDevice::x11AppVisual( scrn ),
+ CWBackPixel|CWBorderPixel|CWColormap, &a );
+ gc = XCreateGC( appDpy, w, 0, 0 );
+ XDestroyWindow( appDpy, w );
+ }
+ }
+ XSetGraphicsExposures( appDpy, gc, False );
+ return gc;
+}
+
+GC qt_xget_readonly_gc( int scrn, bool monochrome ) // get read-only GC
+{
+ if ( scrn < 0 || scrn >= appScreenCount ) {
+ qDebug("invalid screen %d %d", scrn, appScreenCount );
+ QWidget* bla = 0;
+ bla->setName("hello");
+ }
+ GC gc;
+ if ( monochrome ) {
+ if ( !app_gc_ro_m ) // create GC for bitmap
+ memset( (app_gc_ro_m = new GC[appScreenCount]), 0, appScreenCount * sizeof( GC ) );
+ if ( !app_gc_ro_m[scrn] )
+ app_gc_ro_m[scrn] = create_gc( scrn, TRUE );
+ gc = app_gc_ro_m[scrn];
+ } else { // create standard GC
+ if ( !app_gc_ro )
+ memset( (app_gc_ro = new GC[appScreenCount]), 0, appScreenCount * sizeof( GC ) );
+ if ( !app_gc_ro[scrn] )
+ app_gc_ro[scrn] = create_gc( scrn, FALSE );
+ gc = app_gc_ro[scrn];
+ }
+ return gc;
+}
+
+GC qt_xget_temp_gc( int scrn, bool monochrome ) // get temporary GC
+{
+ if ( scrn < 0 || scrn >= appScreenCount ) {
+ qDebug("invalid screen (tmp) %d %d", scrn, appScreenCount );
+ QWidget* bla = 0;
+ bla->setName("hello");
+ }
+ GC gc;
+ if ( monochrome ) {
+ if ( !app_gc_tmp_m ) // create GC for bitmap
+ memset( (app_gc_tmp_m = new GC[appScreenCount]), 0, appScreenCount * sizeof( GC ) );
+ if ( !app_gc_tmp_m[scrn] )
+ app_gc_tmp_m[scrn] = create_gc( scrn, TRUE );
+ gc = app_gc_tmp_m[scrn];
+ } else { // create standard GC
+ if ( !app_gc_tmp )
+ memset( (app_gc_tmp = new GC[appScreenCount]), 0, appScreenCount * sizeof( GC ) );
+ if ( !app_gc_tmp[scrn] )
+ app_gc_tmp[scrn] = create_gc( scrn, FALSE );
+ gc = app_gc_tmp[scrn];
+ }
+ return gc;
+}
+
+
+/*****************************************************************************
+ Platform specific QApplication members
+ *****************************************************************************/
+
+/*!
+ \fn QWidget *QApplication::mainWidget() const
+
+ Returns the main application widget, or 0 if there is no main
+ widget.
+
+ \sa setMainWidget()
+*/
+
+/*!
+ Sets the application's main widget to \a mainWidget.
+
+ In most respects the main widget is like any other widget, except
+ that if it is closed, the application exits. Note that
+ QApplication does \e not take ownership of the \a mainWidget, so
+ if you create your main widget on the heap you must delete it
+ yourself.
+
+ You need not have a main widget; connecting lastWindowClosed() to
+ quit() is an alternative.
+
+ For X11, this function also resizes and moves the main widget
+ according to the \e -geometry command-line option, so you should
+ set the default geometry (using \l QWidget::setGeometry()) before
+ calling setMainWidget().
+
+ \sa mainWidget(), exec(), quit()
+*/
+
+void QApplication::setMainWidget( QWidget *mainWidget )
+{
+#if defined(QT_CHECK_STATE)
+ if ( mainWidget && mainWidget->parentWidget() &&
+ ! mainWidget->parentWidget()->isDesktop() )
+ qWarning( "QApplication::setMainWidget(): New main widget (%s/%s) "
+ "has a parent!",
+ mainWidget->className(), mainWidget->name() );
+#endif
+ main_widget = mainWidget;
+ if ( main_widget ) { // give WM command line
+ XSetWMProperties( main_widget->x11Display(), main_widget->winId(),
+ 0, 0, app_argv, app_argc, 0, 0, 0 );
+ if ( mwTitle )
+ XStoreName( main_widget->x11Display(), main_widget->winId(), (char*)mwTitle );
+ if ( mwGeometry ) { // parse geometry
+ int x, y;
+ int w, h;
+ int m = XParseGeometry( (char*)mwGeometry, &x, &y, (uint*)&w, (uint*)&h );
+ QSize minSize = main_widget->minimumSize();
+ QSize maxSize = main_widget->maximumSize();
+ if ( (m & XValue) == 0 )
+ x = main_widget->geometry().x();
+ if ( (m & YValue) == 0 )
+ y = main_widget->geometry().y();
+ if ( (m & WidthValue) == 0 )
+ w = main_widget->width();
+ if ( (m & HeightValue) == 0 )
+ h = main_widget->height();
+ w = QMIN(w,maxSize.width());
+ h = QMIN(h,maxSize.height());
+ w = QMAX(w,minSize.width());
+ h = QMAX(h,minSize.height());
+ if ( (m & XNegative) ) {
+ x = desktop()->width() + x - w;
+ qt_widget_tlw_gravity = NorthEastGravity;
+ }
+ if ( (m & YNegative) ) {
+ y = desktop()->height() + y - h;
+ qt_widget_tlw_gravity = (m & XNegative) ? SouthEastGravity : SouthWestGravity;
+ }
+ main_widget->setGeometry( x, y, w, h );
+ }
+ }
+}
+
+#ifndef QT_NO_CURSOR
+
+/*****************************************************************************
+ QApplication cursor stack
+ *****************************************************************************/
+
+extern void qt_x11_enforce_cursor( QWidget * w );
+
+typedef QPtrList<QCursor> QCursorList;
+
+static QCursorList *cursorStack = 0;
+
+/*!
+ \fn QCursor *QApplication::overrideCursor()
+
+ Returns the active application override cursor.
+
+ This function returns 0 if no application cursor has been defined
+ (i.e. the internal cursor stack is empty).
+
+ \sa setOverrideCursor(), restoreOverrideCursor()
+*/
+
+/*!
+ Sets the application override cursor to \a cursor.
+
+ Application override cursors are intended for showing the user
+ that the application is in a special state, for example during an
+ operation that might take some time.
+
+ This cursor will be displayed in all the application's widgets
+ until restoreOverrideCursor() or another setOverrideCursor() is
+ called.
+
+ Application cursors are stored on an internal stack.
+ setOverrideCursor() pushes the cursor onto the stack, and
+ restoreOverrideCursor() pops the active cursor off the stack.
+ Every setOverrideCursor() must eventually be followed by a
+ corresponding restoreOverrideCursor(), otherwise the stack will
+ never be emptied.
+
+ If \a replace is TRUE, the new cursor will replace the last
+ override cursor (the stack keeps its depth). If \a replace is
+ FALSE, the new stack is pushed onto the top of the stack.
+
+ Example:
+ \code
+ QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
+ calculateHugeMandelbrot(); // lunch time...
+ QApplication::restoreOverrideCursor();
+ \endcode
+
+ \sa overrideCursor(), restoreOverrideCursor(), QWidget::setCursor()
+*/
+
+void QApplication::setOverrideCursor( const QCursor &cursor, bool replace )
+{
+ if ( !cursorStack ) {
+ cursorStack = new QCursorList;
+ Q_CHECK_PTR( cursorStack );
+ cursorStack->setAutoDelete( TRUE );
+ }
+ app_cursor = new QCursor( cursor );
+ Q_CHECK_PTR( app_cursor );
+ if ( replace )
+ cursorStack->removeLast();
+ cursorStack->append( app_cursor );
+
+ QWidgetIntDictIt it( *((QWidgetIntDict*)QWidget::mapper) );
+ register QWidget *w;
+ while ( (w=it.current()) ) { // for all widgets that have
+ if ( w->testWState( WState_OwnCursor ) )
+ qt_x11_enforce_cursor( w );
+ ++it;
+ }
+ XFlush( appDpy ); // make X execute it NOW
+}
+
+/*!
+ Undoes the last setOverrideCursor().
+
+ If setOverrideCursor() has been called twice, calling
+ restoreOverrideCursor() will activate the first cursor set.
+ Calling this function a second time restores the original widgets'
+ cursors.
+
+ \sa setOverrideCursor(), overrideCursor().
+*/
+
+void QApplication::restoreOverrideCursor()
+{
+ if ( !cursorStack ) // no cursor stack
+ return;
+ cursorStack->removeLast();
+ app_cursor = cursorStack->last();
+ if ( QWidget::mapper != 0 && !closingDown() ) {
+ QWidgetIntDictIt it( *((QWidgetIntDict*)QWidget::mapper) );
+ register QWidget *w;
+ while ( (w=it.current()) ) { // set back to original cursors
+ if ( w->testWState( WState_OwnCursor ) )
+ qt_x11_enforce_cursor( w );
+ ++it;
+ }
+ XFlush( appDpy );
+ }
+ if ( !app_cursor ) {
+ delete cursorStack;
+ cursorStack = 0;
+ }
+}
+
+#endif
+
+/*!
+ \fn bool QApplication::hasGlobalMouseTracking()
+
+ Returns TRUE if global mouse tracking is enabled; otherwise
+ returns FALSE.
+
+ \sa setGlobalMouseTracking()
+*/
+
+/*!
+ Enables global mouse tracking if \a enable is TRUE, or disables it
+ if \a enable is FALSE.
+
+ Enabling global mouse tracking makes it possible for widget event
+ filters or application event filters to get all mouse move events,
+ even when no button is depressed. This is useful for special GUI
+ elements, e.g. tooltips.
+
+ Global mouse tracking does not affect widgets and their
+ mouseMoveEvent(). For a widget to get mouse move events when no
+ button is depressed, it must do QWidget::setMouseTracking(TRUE).
+
+ This function uses an internal counter. Each
+ setGlobalMouseTracking(TRUE) must have a corresponding
+ setGlobalMouseTracking(FALSE):
+ \code
+ // at this point global mouse tracking is off
+ QApplication::setGlobalMouseTracking( TRUE );
+ QApplication::setGlobalMouseTracking( TRUE );
+ QApplication::setGlobalMouseTracking( FALSE );
+ // at this point it's still on
+ QApplication::setGlobalMouseTracking( FALSE );
+ // but now it's off
+ \endcode
+
+ \sa hasGlobalMouseTracking(), QWidget::hasMouseTracking()
+*/
+
+void QApplication::setGlobalMouseTracking( bool enable )
+{
+ bool tellAllWidgets;
+ if ( enable ) {
+ tellAllWidgets = (++app_tracking == 1);
+ } else {
+ tellAllWidgets = (--app_tracking == 0);
+ }
+ if ( tellAllWidgets ) {
+ QWidgetIntDictIt it( *((QWidgetIntDict*)QWidget::mapper) );
+ register QWidget *w;
+ while ( (w=it.current()) ) {
+ if ( app_tracking > 0 ) { // switch on
+ if ( !w->testWState(WState_MouseTracking) ) {
+ w->setMouseTracking( TRUE );
+ w->clearWState( WState_MouseTracking );
+ }
+ } else { // switch off
+ if ( !w->testWState(WState_MouseTracking) ) {
+ w->setWState( WState_MouseTracking );
+ w->setMouseTracking( FALSE );
+ }
+ }
+ ++it;
+ }
+ }
+}
+
+
+/*****************************************************************************
+ Routines to find a Qt widget from a screen position
+ *****************************************************************************/
+
+Window qt_x11_findClientWindow( Window win, Atom property, bool leaf )
+{
+ Atom type = None;
+ int format, i;
+ ulong nitems, after;
+ uchar *data;
+ Window root, parent, target=0, *children=0;
+ uint nchildren;
+ if ( XGetWindowProperty( appDpy, win, property, 0, 0, FALSE, AnyPropertyType,
+ &type, &format, &nitems, &after, &data ) == Success ) {
+ if ( data )
+ XFree( (char *)data );
+ if ( type )
+ return win;
+ }
+ if ( !XQueryTree(appDpy,win,&root,&parent,&children,&nchildren) ) {
+ if ( children )
+ XFree( (char *)children );
+ return 0;
+ }
+ for ( i=nchildren-1; !target && i >= 0; i-- )
+ target = qt_x11_findClientWindow( children[i], property, leaf );
+ if ( children )
+ XFree( (char *)children );
+ return target;
+}
+
+
+/*!
+ Returns a pointer to the widget at global screen position \a
+ (x, y), or 0 if there is no Qt widget there.
+
+ If \a child is FALSE and there is a child widget at position \a
+ (x, y), the top-level widget containing it is returned. If \a child
+ is TRUE the child widget at position \a (x, y) is returned.
+
+ This function is normally rather slow.
+
+ \sa QCursor::pos(), QWidget::grabMouse(), QWidget::grabKeyboard()
+*/
+
+QWidget *QApplication::widgetAt( int x, int y, bool child )
+{
+ int screen = QCursor::x11Screen();
+ int lx, ly;
+
+ Window target;
+ if ( !XTranslateCoordinates(appDpy,
+ QPaintDevice::x11AppRootWindow(screen),
+ QPaintDevice::x11AppRootWindow(screen),
+ x, y, &lx, &ly, &target) ) {
+ return 0;
+ }
+ if ( !target || target == QPaintDevice::x11AppRootWindow(screen) )
+ return 0;
+ QWidget *w, *c;
+ w = QWidget::find( (WId)target );
+
+ if ( !w ) {
+ qt_ignore_badwindow();
+ target = qt_x11_findClientWindow( target, qt_wm_state, TRUE );
+ if (qt_badwindow() )
+ return 0;
+ w = QWidget::find( (WId)target );
+#if 0
+ if ( !w ) {
+ // Perhaps the widgets at (x,y) is inside a foreign application?
+ // Search all toplevel widgets to see if one is within target
+ QWidgetList *list = topLevelWidgets();
+ QWidget *widget = list->first();
+ while ( widget && !w ) {
+ Window ctarget = target;
+ if ( widget->isVisible() && !widget->isDesktop() ) {
+ Window wid = widget->winId();
+ while ( ctarget && !w ) {
+ XTranslateCoordinates(appDpy,
+ QPaintDevice::x11AppRootWindow(screen),
+ ctarget, x, y, &lx, &ly, &ctarget);
+ if ( ctarget == wid ) {
+ // Found
+ w = widget;
+ XTranslateCoordinates(appDpy,
+ QPaintDevice::x11AppRootWindow(screen),
+ ctarget, x, y, &lx, &ly, &ctarget);
+ }
+ }
+ }
+ widget = list->next();
+ }
+ delete list;
+ }
+#endif
+ }
+ if ( child && w ) {
+ if ( (c = w->childAt( w->mapFromGlobal(QPoint(x, y ) ) ) ) )
+ return c;
+ }
+ return w;
+}
+
+/*!
+ \overload QWidget *QApplication::widgetAt( const QPoint &pos, bool child )
+
+ Returns a pointer to the widget at global screen position \a pos,
+ or 0 if there is no Qt widget there.
+
+ If \a child is FALSE and there is a child widget at position \a
+ pos, the top-level widget containing it is returned. If \a child
+ is TRUE the child widget at position \a pos is returned.
+*/
+
+
+/*!
+ Flushes the X event queue in the X11 implementation. This normally
+ returns almost immediately. Does nothing on other platforms.
+
+ \sa syncX()
+*/
+
+void QApplication::flushX()
+{
+ if ( appDpy )
+ XFlush( appDpy );
+}
+
+/*!
+ Flushes the window system specific event queues.
+
+ If you are doing graphical changes inside a loop that does not
+ return to the event loop on asynchronous window systems like X11
+ or double buffered window systems like MacOS X, and you want to
+ visualize these changes immediately (e.g. Splash Screens), call
+ this function.
+
+ \sa flushX() sendPostedEvents() QPainter::flush()
+*/
+
+void QApplication::flush()
+{
+ flushX();
+}
+
+/*!
+ Synchronizes with the X server in the X11 implementation. This
+ normally takes some time. Does nothing on other platforms.
+
+ \sa flushX()
+*/
+
+void QApplication::syncX()
+{
+ if ( appDpy )
+ XSync( appDpy, False ); // don't discard events
+}
+
+
+/*!
+ Sounds the bell, using the default volume and sound.
+*/
+
+void QApplication::beep()
+{
+ if ( appDpy )
+ XBell( appDpy, 0 );
+}
+
+
+
+/*****************************************************************************
+ Special lookup functions for windows that have been reparented recently
+ *****************************************************************************/
+
+static QWidgetIntDict *wPRmapper = 0; // alternative widget mapper
+
+void qPRCreate( const QWidget *widget, Window oldwin )
+{ // QWidget::reparent mechanism
+ if ( !wPRmapper ) {
+ wPRmapper = new QWidgetIntDict;
+ Q_CHECK_PTR( wPRmapper );
+ }
+ wPRmapper->insert( (long)oldwin, widget ); // add old window to mapper
+ QETWidget *w = (QETWidget *)widget;
+ w->setWState( Qt::WState_Reparented ); // set reparented flag
+}
+
+void qPRCleanup( QWidget *widget )
+{
+ QETWidget *etw = (QETWidget *)widget;
+ if ( !(wPRmapper && etw->testWState(Qt::WState_Reparented)) )
+ return; // not a reparented widget
+ QWidgetIntDictIt it(*wPRmapper);
+ QWidget *w;
+ while ( (w=it.current()) ) {
+ int key = it.currentKey();
+ ++it;
+ if ( w == etw ) { // found widget
+ etw->clearWState( Qt::WState_Reparented ); // clear flag
+ wPRmapper->remove( key );// old window no longer needed
+ if ( wPRmapper->count() == 0 ) { // became empty
+ delete wPRmapper; // then reset alt mapper
+ wPRmapper = 0;
+ return;
+ }
+ }
+ }
+}
+
+static QETWidget *qPRFindWidget( Window oldwin )
+{
+ return wPRmapper ? (QETWidget*)wPRmapper->find((long)oldwin) : 0;
+}
+
+/*!
+ \internal
+*/
+int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only)
+{
+ QETWidget *widget = (QETWidget*)w;
+ if ( event->xclient.format == 32 && event->xclient.message_type ) {
+ if ( event->xclient.message_type == qt_wm_protocols ) {
+ Atom a = event->xclient.data.l[0];
+ if ( a == qt_wm_delete_window ) {
+ if ( passive_only ) return 0;
+ widget->translateCloseEvent(event);
+ }
+ else if ( a == qt_wm_take_focus ) {
+ QWidget * amw = activeModalWidget();
+ if ( (ulong) event->xclient.data.l[1] > qt_x_time )
+ qt_x_time = event->xclient.data.l[1];
+ if ( amw && amw != widget ) {
+ QWidget* groupLeader = widget;
+ while ( groupLeader && !groupLeader->testWFlags( Qt::WGroupLeader )
+ && groupLeader != amw )
+ groupLeader = groupLeader->parentWidget();
+ if ( !groupLeader ) {
+ QWidget *p = amw->parentWidget();
+ while (p && p != widget)
+ p = p->parentWidget();
+ if (!p || !qt_net_supported_list)
+ amw->raise(); // help broken window managers
+ amw->setActiveWindow();
+ }
+ }
+#ifndef QT_NO_WHATSTHIS
+ } else if ( a == qt_net_wm_context_help ) {
+ QWhatsThis::enterWhatsThisMode();
+#endif // QT_NO_WHATSTHIS
+ } else if ( a == qt_net_wm_ping ) {
+ // avoid send/reply loops
+ Window root = QPaintDevice::x11AppRootWindow( w->x11Screen() );
+ if (event->xclient.window != root) {
+ event->xclient.window = root;
+ XSendEvent( event->xclient.display, event->xclient.window,
+ False, SubstructureNotifyMask|SubstructureRedirectMask, event );
+ }
+#ifndef QT_NO_XSYNC
+ } else if (a == qt_net_wm_sync_request ) {
+ widget->handleSyncRequest( event );
+#endif
+ }
+ } else if ( event->xclient.message_type == qt_qt_scrolldone ) {
+ widget->translateScrollDoneEvent(event);
+ } else if ( event->xclient.message_type == qt_xdnd_position ) {
+ qt_handle_xdnd_position( widget, event, passive_only );
+ } else if ( event->xclient.message_type == qt_xdnd_enter ) {
+ qt_handle_xdnd_enter( widget, event, passive_only );
+ } else if ( event->xclient.message_type == qt_xdnd_status ) {
+ qt_handle_xdnd_status( widget, event, passive_only );
+ } else if ( event->xclient.message_type == qt_xdnd_leave ) {
+ qt_handle_xdnd_leave( widget, event, passive_only );
+ } else if ( event->xclient.message_type == qt_xdnd_drop ) {
+ qt_handle_xdnd_drop( widget, event, passive_only );
+ } else if ( event->xclient.message_type == qt_xdnd_finished ) {
+ qt_handle_xdnd_finished( widget, event, passive_only );
+ } else {
+ if ( passive_only ) return 0;
+ // All other are interactions
+ }
+ } else {
+ qt_motifdnd_handle_msg( widget, event, passive_only );
+ }
+
+ return 0;
+}
+
+/*!
+ This function does the core processing of individual X
+ \a{event}s, normally by dispatching Qt events to the right
+ destination.
+
+ It returns 1 if the event was consumed by special handling, 0 if
+ the \a event was consumed by normal handling, and -1 if the \a
+ event was for an unrecognized widget.
+
+ \sa x11EventFilter()
+*/
+int QApplication::x11ProcessEvent( XEvent* event )
+{
+ switch ( event->type ) {
+ case ButtonPress:
+ ignoreNextMouseReleaseEvent = FALSE;
+ qt_x_user_time = event->xbutton.time;
+ // fallthrough intended
+ case ButtonRelease:
+ qt_x_time = event->xbutton.time;
+ break;
+ case MotionNotify:
+ qt_x_time = event->xmotion.time;
+ break;
+ case XKeyPress:
+ qt_x_user_time = event->xkey.time;
+ // fallthrough intended
+ case XKeyRelease:
+ qt_x_time = event->xkey.time;
+ break;
+ case PropertyNotify:
+ qt_x_time = event->xproperty.time;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ qt_x_time = event->xcrossing.time;
+ break;
+ case SelectionClear:
+ qt_x_time = event->xselectionclear.time;
+ break;
+ default:
+ break;
+ }
+
+ QETWidget *widget = (QETWidget*)QWidget::find( (WId)event->xany.window );
+
+ if ( wPRmapper ) { // just did a widget reparent?
+ if ( widget == 0 ) { // not in std widget mapper
+ switch ( event->type ) { // only for mouse/key events
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ case XKeyPress:
+ case XKeyRelease:
+ widget = qPRFindWidget( event->xany.window );
+ break;
+ }
+ }
+ else if ( widget->testWState(WState_Reparented) )
+ qPRCleanup( widget ); // remove from alt mapper
+ }
+
+ QETWidget *keywidget=0;
+ bool grabbed=FALSE;
+ if ( event->type==XKeyPress || event->type==XKeyRelease ) {
+ keywidget = (QETWidget*)QWidget::keyboardGrabber();
+ if ( keywidget ) {
+ grabbed = TRUE;
+ } else {
+ if ( focus_widget )
+ keywidget = (QETWidget*)focus_widget;
+ if ( !keywidget ) {
+ if ( inPopupMode() ) // no focus widget, see if we have a popup
+ keywidget = (QETWidget*) activePopupWidget();
+ else if ( widget )
+ keywidget = (QETWidget*)widget->topLevelWidget();
+ }
+ }
+ }
+
+#ifndef QT_NO_IM
+ // Filtering input events by the input context. It has to be taken
+ // place before any other key event consumers such as eventfilters
+ // and accelerators because some input methods require quite
+ // various key combination and sequences. It often conflicts with
+ // accelerators and so on, so we must give the input context the
+ // filtering opportunity first to ensure all input methods work
+ // properly regardless of application design.
+
+// #ifndef QT_NO_IM_EXTENSIONS
+ if( keywidget && keywidget->isEnabled() && keywidget->isInputMethodEnabled() ) {
+// #else
+// if( keywidget && keywidget->isEnabled() ) {
+// #endif
+ if( ( event->type==XKeyPress || event->type==XKeyRelease ) &&
+ sm_blockUserInput ) // block user interaction during session management
+ return TRUE;
+
+ // for XIM handling
+ QInputContext *qic = keywidget->getInputContext();
+ if( qic && qic->x11FilterEvent( keywidget, event ) )
+ return TRUE;
+
+ // filterEvent() accepts QEvent *event rather than preexpanded key
+ // event attribute values. This is intended to pass other IM-related
+ // events in future. The IM-related events are supposed as
+ // QWheelEvent, QTabletEvent and so on. Other non IM-related events
+ // should not be forwarded to input contexts to prevent weird event
+ // handling.
+ if ( ( event->type == XKeyPress || event->type == XKeyRelease ) ) {
+ int code = -1;
+ int count = 0;
+ int state;
+ char ascii = 0;
+ QEvent::Type type;
+ QString text;
+
+ keywidget->translateKeyEventInternal( event, count, text,
+ state, ascii, code, type,
+ FALSE, FALSE );
+
+ // both key press/release is required for some complex
+ // input methods. don't eliminate anything.
+ QKeyEvent keyevent( type, code, ascii, state, text, FALSE, count );
+
+ if( qic && qic->filterEvent( &keyevent ) )
+ return TRUE;
+ }
+ } else
+#endif // QT_NO_IM
+ {
+ if ( XFilterEvent( event, None ) )
+ return TRUE;
+ }
+
+ if ( qt_x11EventFilter(event) ) // send through app filter
+ return 1;
+
+ if ( event->type == MappingNotify ) { // keyboard mapping changed
+ XRefreshKeyboardMapping( &event->xmapping );
+ return 0;
+ }
+
+ if ( event->type == PropertyNotify ) { // some properties changed
+ if ( event->xproperty.window == QPaintDevice::x11AppRootWindow( 0 ) ) {
+ // root properties for the first screen
+ if ( event->xproperty.atom == qt_clipboard_sentinel ) {
+ if (qt_check_clipboard_sentinel() )
+ emit clipboard()->dataChanged();
+ } else if ( event->xproperty.atom == qt_selection_sentinel ) {
+ if (qt_check_selection_sentinel() )
+ emit clipboard()->selectionChanged();
+ } else if ( obey_desktop_settings ) {
+ if ( event->xproperty.atom == qt_resource_manager )
+ qt_set_x11_resources();
+ else if ( event->xproperty.atom == qt_settings_timestamp )
+ QApplication::x11_apply_settings();
+ }
+ }
+ if ( event->xproperty.window == QPaintDevice::x11AppRootWindow() ) {
+ // root properties for the default screen
+ if ( event->xproperty.atom == qt_input_encoding ) {
+ qt_set_input_encoding();
+ } else if ( event->xproperty.atom == qt_net_supported ) {
+ qt_get_net_supported();
+ } else if ( event->xproperty.atom == qt_net_virtual_roots ) {
+ qt_get_net_virtual_roots();
+ } else if ( event->xproperty.atom == qt_net_workarea ) {
+ qt_desktopwidget_update_workarea();
+ }
+ } else if ( widget ) {
+ widget->translatePropertyEvent(event);
+ } else {
+ return -1; // don't know this window
+ }
+ return 0;
+ }
+
+ if ( !widget ) { // don't know this windows
+ QWidget* popup = QApplication::activePopupWidget();
+ if ( popup ) {
+
+ /*
+ That is more than suboptimal. The real solution should
+ do some keyevent and buttonevent translation, so that
+ the popup still continues to work as the user expects.
+ Unfortunately this translation is currently only
+ possible with a known widget. I'll change that soon
+ (Matthias).
+ */
+
+ // Danger - make sure we don't lock the server
+ switch ( event->type ) {
+ case ButtonPress:
+ case ButtonRelease:
+ case XKeyPress:
+ case XKeyRelease:
+ do {
+ popup->close();
+ } while ( (popup = qApp->activePopupWidget()) );
+ return 1;
+ }
+ }
+ return -1;
+ }
+
+ if ( event->type == XKeyPress || event->type == XKeyRelease )
+ widget = keywidget; // send XKeyEvents through keywidget->x11Event()
+
+ if ( app_do_modal ) // modal event handling
+ if ( !qt_try_modal(widget, event) ) {
+ if ( event->type == ClientMessage )
+ x11ClientMessage( widget, event, TRUE );
+ return 1;
+ }
+
+
+ if ( widget->x11Event(event) ) // send through widget filter
+ return 1;
+#if defined (QT_TABLET_SUPPORT)
+ if ( event->type == xinput_motion ||
+ event->type == xinput_button_release ||
+ event->type == xinput_button_press ) {
+ widget->translateXinputEvent( event );
+ return 0;
+ }
+#endif
+
+#ifndef QT_NO_XRANDR
+ if (event->type == xrandr_eventbase + RRScreenChangeNotify
+ || ( event->type == ConfigureNotify && event->xconfigure.window == QPaintDevice::x11AppRootWindow())) {
+ // update Xlib internals with the latest screen configuration
+ XRRUpdateConfiguration(event);
+
+ // update the size for desktop widget
+ int scr = XRRRootToScreen( appDpy, event->xany.window );
+ QWidget *w = desktop()->screen( scr );
+ QSize oldSize( w->size() );
+ w->crect.setWidth( DisplayWidth( appDpy, scr ) );
+ w->crect.setHeight( DisplayHeight( appDpy, scr ) );
+ if ( w->size() != oldSize ) {
+ QResizeEvent e( w->size(), oldSize );
+ QApplication::sendEvent( w, &e );
+ emit desktop()->resized( scr );
+ }
+ }
+#endif // QT_NO_XRANDR
+
+ switch ( event->type ) {
+
+ case ButtonRelease: // mouse event
+ if ( ignoreNextMouseReleaseEvent ) {
+ ignoreNextMouseReleaseEvent = FALSE;
+ break;
+ }
+ // fall through intended
+ case ButtonPress:
+ if (event->xbutton.root != RootWindow(widget->x11Display(), widget->x11Screen())
+ && ! qt_xdnd_dragging) {
+ while ( activePopupWidget() )
+ activePopupWidget()->close();
+ return 1;
+ }
+ if (event->type == ButtonPress)
+ qt_net_update_user_time(widget->topLevelWidget());
+ // fall through intended
+ case MotionNotify:
+#if defined(QT_TABLET_SUPPORT)
+ if ( !chokeMouse ) {
+#endif
+ widget->translateMouseEvent( event );
+#if defined(QT_TABLET_SUPPORT)
+ } else {
+ chokeMouse = FALSE;
+ }
+#endif
+ break;
+
+ case XKeyPress: // keyboard event
+ qt_net_update_user_time(widget->topLevelWidget());
+ // fallthrough intended
+ case XKeyRelease:
+ {
+ if ( keywidget && keywidget->isEnabled() ) { // should always exist
+ // qDebug( "sending key event" );
+ keywidget->translateKeyEvent( event, grabbed );
+ }
+ break;
+ }
+
+ case GraphicsExpose:
+ case Expose: // paint event
+ widget->translatePaintEvent( event );
+ break;
+
+ case ConfigureNotify: // window move/resize event
+ if ( event->xconfigure.event == event->xconfigure.window )
+ widget->translateConfigEvent( event );
+ break;
+
+ case XFocusIn: { // got focus
+ if ( widget->isDesktop() )
+ break;
+ if ( inPopupMode() ) // some delayed focus event to ignore
+ break;
+ if ( !widget->isTopLevel() )
+ break;
+ if ( event->xfocus.detail != NotifyAncestor &&
+ event->xfocus.detail != NotifyInferior &&
+ event->xfocus.detail != NotifyNonlinear )
+ break;
+ widget->createInputContext();
+ setActiveWindow( widget );
+ if ( qt_focus_model == FocusModel_PointerRoot ) {
+ // We got real input focus from somewhere, but we were in PointerRoot
+ // mode, so we don't trust this event. Check the focus model to make
+ // sure we know what focus mode we are using...
+ qt_check_focus_model();
+ }
+ }
+ break;
+
+ case XFocusOut: // lost focus
+ if ( widget->isDesktop() )
+ break;
+ if ( !widget->isTopLevel() )
+ break;
+ if ( event->xfocus.mode == NotifyGrab )
+ qt_xfocusout_grab_counter++;
+ if ( event->xfocus.mode != NotifyNormal )
+ break;
+ if ( event->xfocus.detail != NotifyAncestor &&
+ event->xfocus.detail != NotifyNonlinearVirtual &&
+ event->xfocus.detail != NotifyNonlinear )
+ break;
+ if ( !inPopupMode() && widget == active_window )
+ setActiveWindow( 0 );
+ break;
+
+ case EnterNotify: { // enter window
+ if ( QWidget::mouseGrabber() && widget != QWidget::mouseGrabber() )
+ break;
+ if ( inPopupMode() && widget->topLevelWidget() != activePopupWidget() )
+ break;
+ if ( event->xcrossing.mode != NotifyNormal ||
+ event->xcrossing.detail == NotifyVirtual ||
+ event->xcrossing.detail == NotifyNonlinearVirtual )
+ break;
+ if ( event->xcrossing.focus &&
+ !widget->isDesktop() && !widget->isActiveWindow() ) {
+ if ( qt_focus_model == FocusModel_Unknown ) // check focus model
+ qt_check_focus_model();
+ if ( qt_focus_model == FocusModel_PointerRoot ) // PointerRoot mode
+ setActiveWindow( widget );
+ }
+ qt_dispatchEnterLeave( widget, QWidget::find( curWin ) );
+ curWin = widget->winId();
+ widget->translateMouseEvent( event ); //we don't get MotionNotify, emulate it
+ }
+ break;
+
+ case LeaveNotify: { // leave window
+ if ( QWidget::mouseGrabber() && widget != QWidget::mouseGrabber() )
+ break;
+ if ( curWin && widget->winId() != curWin )
+ break;
+ if ( event->xcrossing.mode != NotifyNormal )
+ break;
+ if ( !widget->isDesktop() )
+ widget->translateMouseEvent( event ); //we don't get MotionNotify, emulate it
+
+ QWidget* enter = 0;
+ XEvent ev;
+ while ( XCheckMaskEvent( widget->x11Display(), EnterWindowMask | LeaveWindowMask , &ev )
+ && !qt_x11EventFilter( &ev )) {
+ QWidget* event_widget = QWidget::find( ev.xcrossing.window );
+ if( event_widget && event_widget->x11Event( &ev ) )
+ break;
+ if ( ev.type == LeaveNotify && ev.xcrossing.mode == NotifyNormal ){
+ enter = event_widget;
+ XPutBackEvent( widget->x11Display(), &ev );
+ break;
+ }
+ if ( ev.xcrossing.mode != NotifyNormal ||
+ ev.xcrossing.detail == NotifyVirtual ||
+ ev.xcrossing.detail == NotifyNonlinearVirtual )
+ continue;
+ enter = event_widget;
+ if ( ev.xcrossing.focus &&
+ enter && !enter->isDesktop() && !enter->isActiveWindow() ) {
+ if ( qt_focus_model == FocusModel_Unknown ) // check focus model
+ qt_check_focus_model();
+ if ( qt_focus_model == FocusModel_PointerRoot ) // PointerRoot mode
+ setActiveWindow( enter );
+ }
+ break;
+ }
+
+ if ( ( ! enter || enter->isDesktop() ) &&
+ event->xcrossing.focus && widget == active_window &&
+ qt_focus_model == FocusModel_PointerRoot // PointerRoot mode
+ ) {
+ setActiveWindow( 0 );
+ }
+
+ if ( !curWin )
+ qt_dispatchEnterLeave( widget, 0 );
+
+ qt_dispatchEnterLeave( enter, widget );
+ curWin = enter ? enter->winId() : 0;
+ }
+ break;
+
+ case UnmapNotify: // window hidden
+ if ( widget->isTopLevel() && widget->isShown() ) {
+ widget->topData()->spont_unmapped = 1;
+ QHideEvent e;
+ QApplication::sendSpontaneousEvent( widget, &e );
+ widget->hideChildren( TRUE );
+ }
+ break;
+
+ case MapNotify: // window shown
+ if ( widget->isTopLevel() &&
+ widget->topData()->spont_unmapped ) {
+ widget->topData()->spont_unmapped = 0;
+ widget->showChildren( TRUE );
+ QShowEvent e;
+ QApplication::sendSpontaneousEvent( widget, &e );
+ }
+ break;
+
+ case ClientMessage: // client message
+ return x11ClientMessage(widget,event,False);
+
+ case ReparentNotify: // window manager reparents
+ while ( XCheckTypedWindowEvent( widget->x11Display(),
+ widget->winId(),
+ ReparentNotify,
+ event ) )
+ ; // skip old reparent events
+ if ( event->xreparent.parent == QPaintDevice::x11AppRootWindow() ) {
+ if ( widget->isTopLevel() ) {
+ widget->topData()->parentWinId = event->xreparent.parent;
+ if ( qt_deferred_map_contains( widget ) ) {
+ qt_deferred_map_take( widget );
+ XMapWindow( appDpy, widget->winId() );
+ }
+ }
+ } else
+ // store the parent. Useful for many things, embedding for instance.
+ widget->topData()->parentWinId = event->xreparent.parent;
+ if ( widget->isTopLevel() ) {
+ // the widget frame strut should also be invalidated
+ widget->topData()->fleft = widget->topData()->fright =
+ widget->topData()->ftop = widget->topData()->fbottom = 0;
+
+ if ( qt_focus_model != FocusModel_Unknown ) {
+ // toplevel reparented...
+ QWidget *newparent = QWidget::find( event->xreparent.parent );
+ if ( ! newparent || newparent->isDesktop() ) {
+ // we dont' know about the new parent (or we've been
+ // reparented to root), perhaps a window manager
+ // has been (re)started? reset the focus model to unknown
+ qt_focus_model = FocusModel_Unknown;
+ }
+ }
+ }
+ break;
+
+ case SelectionRequest: {
+ XSelectionRequestEvent *req = &event->xselectionrequest;
+ if (! req)
+ break;
+
+ if ( qt_xdnd_selection && req->selection == qt_xdnd_selection ) {
+ qt_xdnd_handle_selection_request( req );
+
+ } else if (qt_clipboard) {
+ QCustomEvent e( QEvent::Clipboard, event );
+ QApplication::sendSpontaneousEvent( qt_clipboard, &e );
+ }
+ break;
+ }
+ case SelectionClear: {
+ XSelectionClearEvent *req = &event->xselectionclear;
+ // don't deliver dnd events to the clipboard, it gets confused
+ if (! req || qt_xdnd_selection && req->selection == qt_xdnd_selection)
+ break;
+
+ if (qt_clipboard) {
+ QCustomEvent e( QEvent::Clipboard, event );
+ QApplication::sendSpontaneousEvent( qt_clipboard, &e );
+ }
+ break;
+ }
+
+ case SelectionNotify: {
+ XSelectionEvent *req = &event->xselection;
+ // don't deliver dnd events to the clipboard, it gets confused
+ if (! req || qt_xdnd_selection && req->selection == qt_xdnd_selection)
+ break;
+
+ if (qt_clipboard) {
+ QCustomEvent e( QEvent::Clipboard, event );
+ QApplication::sendSpontaneousEvent( qt_clipboard, &e );
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*!
+ This virtual function is only implemented under X11.
+
+ If you create an application that inherits QApplication and
+ reimplement this function, you get direct access to all X events
+ that the are received from the X server.
+
+ Return TRUE if you want to stop the event from being processed.
+ Return FALSE for normal event dispatching.
+
+ \sa x11ProcessEvent()
+*/
+
+bool QApplication::x11EventFilter( XEvent * )
+{
+ return FALSE;
+}
+
+
+
+/*****************************************************************************
+ Modal widgets; Since Xlib has little support for this we roll our own
+ modal widget mechanism.
+ A modal widget without a parent becomes application-modal.
+ A modal widget with a parent becomes modal to its parent and grandparents..
+
+ qt_enter_modal()
+ Enters modal state
+ Arguments:
+ QWidget *widget A modal widget
+
+ qt_leave_modal()
+ Leaves modal state for a widget
+ Arguments:
+ QWidget *widget A modal widget
+ *****************************************************************************/
+
+bool qt_modal_state()
+{
+ return app_do_modal;
+}
+
+void qt_enter_modal( QWidget *widget )
+{
+ if ( !qt_modal_stack ) { // create modal stack
+ qt_modal_stack = new QWidgetList;
+ Q_CHECK_PTR( qt_modal_stack );
+ }
+ if (widget->parentWidget()) {
+ QEvent e(QEvent::WindowBlocked);
+ QApplication::sendEvent(widget->parentWidget(), &e);
+ }
+
+ qt_dispatchEnterLeave( 0, QWidget::find((WId)curWin) );
+ qt_modal_stack->insert( 0, widget );
+ app_do_modal = TRUE;
+ curWin = 0;
+ ignoreNextMouseReleaseEvent = FALSE;
+}
+
+
+void qt_leave_modal( QWidget *widget )
+{
+ if ( qt_modal_stack && qt_modal_stack->removeRef(widget) ) {
+ if ( qt_modal_stack->isEmpty() ) {
+ delete qt_modal_stack;
+ qt_modal_stack = 0;
+ QPoint p( QCursor::pos() );
+ QWidget* w = QApplication::widgetAt( p.x(), p.y(), TRUE );
+ qt_dispatchEnterLeave( w, QWidget::find( curWin ) ); // send synthetic enter event
+ curWin = w? w->winId() : 0;
+ }
+ }
+ app_do_modal = qt_modal_stack != 0;
+ ignoreNextMouseReleaseEvent = TRUE;
+
+ if (widget->parentWidget()) {
+ QEvent e(QEvent::WindowUnblocked);
+ QApplication::sendEvent(widget->parentWidget(), &e);
+ }
+}
+
+
+bool qt_try_modal( QWidget *widget, XEvent *event )
+{
+ if (qt_xdnd_dragging) {
+ // allow mouse events while DnD is active
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ return TRUE;
+ default:
+ break;
+ }
+ }
+
+ if ( qt_tryModalHelper( widget ) )
+ return TRUE;
+
+ bool block_event = FALSE;
+ switch ( event->type ) {
+ case ButtonPress: // disallow mouse/key events
+ case ButtonRelease:
+ case MotionNotify:
+ case XKeyPress:
+ case XKeyRelease:
+ case EnterNotify:
+ case LeaveNotify:
+ case ClientMessage:
+ block_event = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return !block_event;
+}
+
+
+/*****************************************************************************
+ Popup widget mechanism
+
+ openPopup()
+ Adds a widget to the list of popup widgets
+ Arguments:
+ QWidget *widget The popup widget to be added
+
+ closePopup()
+ Removes a widget from the list of popup widgets
+ Arguments:
+ QWidget *widget The popup widget to be removed
+ *****************************************************************************/
+
+
+static int openPopupCount = 0;
+void QApplication::openPopup( QWidget *popup )
+{
+ openPopupCount++;
+ if ( !popupWidgets ) { // create list
+ popupWidgets = new QWidgetList;
+ Q_CHECK_PTR( popupWidgets );
+ }
+ popupWidgets->append( popup ); // add to end of list
+
+ if ( popupWidgets->count() == 1 && !qt_nograb() ){ // grab mouse/keyboard
+ int r = XGrabKeyboard( popup->x11Display(), popup->winId(), FALSE,
+ GrabModeSync, GrabModeAsync, CurrentTime );
+ if ( (popupGrabOk = (r == GrabSuccess)) ) {
+ r = XGrabPointer( popup->x11Display(), popup->winId(), TRUE,
+ (uint)(ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | EnterWindowMask |
+ LeaveWindowMask | PointerMotionMask),
+ GrabModeSync, GrabModeAsync,
+ None, None, CurrentTime );
+
+ if ( (popupGrabOk = (r == GrabSuccess)) )
+ XAllowEvents( popup->x11Display(), SyncPointer, CurrentTime );
+ else
+ XUngrabKeyboard( popup->x11Display(), CurrentTime );
+ }
+ } else if ( popupGrabOk ) {
+ XAllowEvents( popup->x11Display(), SyncPointer, CurrentTime );
+ }
+
+ // popups are not focus-handled by the window system (the first
+ // popup grabbed the keyboard), so we have to do that manually: A
+ // new popup gets the focus
+ QFocusEvent::setReason( QFocusEvent::Popup );
+ if ( popup->focusWidget())
+ popup->focusWidget()->setFocus();
+ else
+ popup->setFocus();
+ QFocusEvent::resetReason();
+}
+
+void QApplication::closePopup( QWidget *popup )
+{
+ if ( !popupWidgets )
+ return;
+ popupWidgets->removeRef( popup );
+ if (popup == popupOfPopupButtonFocus) {
+ popupButtonFocus = 0;
+ popupOfPopupButtonFocus = 0;
+ }
+ if ( popupWidgets->count() == 0 ) { // this was the last popup
+ popupCloseDownMode = TRUE; // control mouse events
+ delete popupWidgets;
+ popupWidgets = 0;
+ if ( !qt_nograb() && popupGrabOk ) { // grabbing not disabled
+ if ( mouseButtonState != 0
+ || popup->geometry(). contains(QPoint(mouseGlobalXPos, mouseGlobalYPos) ) )
+ { // mouse release event or inside
+ XAllowEvents( popup->x11Display(), AsyncPointer,
+ CurrentTime );
+ } else { // mouse press event
+ mouseButtonPressTime -= 10000; // avoid double click
+ XAllowEvents( popup->x11Display(), ReplayPointer,CurrentTime );
+ }
+ XUngrabPointer( popup->x11Display(), CurrentTime );
+ XFlush( popup->x11Display() );
+ }
+ if ( active_window ) {
+ QFocusEvent::setReason( QFocusEvent::Popup );
+ if ( active_window->focusWidget() )
+ active_window->focusWidget()->setFocus();
+ else
+ active_window->setFocus();
+ QFocusEvent::resetReason();
+ }
+ } else {
+ // popups are not focus-handled by the window system (the
+ // first popup grabbed the keyboard), so we have to do that
+ // manually: A popup was closed, so the previous popup gets
+ // the focus.
+ QFocusEvent::setReason( QFocusEvent::Popup );
+ QWidget* aw = popupWidgets->getLast();
+ if (aw->focusWidget())
+ aw->focusWidget()->setFocus();
+ else
+ aw->setFocus();
+ QFocusEvent::resetReason();
+ if ( popupWidgets->count() == 1 && !qt_nograb() ){ // grab mouse/keyboard
+ int r = XGrabKeyboard( aw->x11Display(), aw->winId(), FALSE,
+ GrabModeSync, GrabModeAsync, CurrentTime );
+ if ( (popupGrabOk = (r == GrabSuccess)) ) {
+ r = XGrabPointer( aw->x11Display(), aw->winId(), TRUE,
+ (uint)(ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask | EnterWindowMask |
+ LeaveWindowMask | PointerMotionMask),
+ GrabModeSync, GrabModeAsync,
+ None, None, CurrentTime );
+
+ if ( (popupGrabOk = (r == GrabSuccess)) )
+ XAllowEvents( aw->x11Display(), SyncPointer, CurrentTime );
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+ Event translation; translates X11 events to Qt events
+ *****************************************************************************/
+
+//
+// Mouse event translation
+//
+// Xlib doesn't give mouse double click events, so we generate them by
+// comparing window, time and position between two mouse press events.
+//
+
+//
+// Keyboard event translation
+//
+
+int qt_x11_translateButtonState( int s )
+{
+ int bst = 0;
+ if ( s & Button1Mask )
+ bst |= Qt::LeftButton;
+ if ( s & Button2Mask )
+ bst |= Qt::MidButton;
+ if ( s & Button3Mask )
+ bst |= Qt::RightButton;
+ if ( s & ShiftMask )
+ bst |= Qt::ShiftButton;
+ if ( s & ControlMask )
+ bst |= Qt::ControlButton;
+ if ( s & qt_alt_mask )
+ bst |= Qt::AltButton;
+ if ( s & qt_meta_mask )
+ bst |= Qt::MetaButton;
+ return bst;
+}
+
+bool QETWidget::translateMouseEvent( const XEvent *event )
+{
+ static bool manualGrab = FALSE;
+ QEvent::Type type; // event parameters
+ QPoint pos;
+ QPoint globalPos;
+ int button = 0;
+ int state;
+ XEvent nextEvent;
+
+ if ( sm_blockUserInput ) // block user interaction during session management
+ return TRUE;
+
+ static int x_root_save = -1, y_root_save = -1;
+
+ if ( event->type == MotionNotify ) { // mouse move
+ if (event->xmotion.root != RootWindow(appDpy, x11Screen()) &&
+ ! qt_xdnd_dragging )
+ return FALSE;
+
+ XMotionEvent lastMotion = event->xmotion;
+ while( XPending( appDpy ) ) { // compres mouse moves
+ XNextEvent( appDpy, &nextEvent );
+ if ( nextEvent.type == ConfigureNotify
+ || nextEvent.type == PropertyNotify
+ || nextEvent.type == Expose
+ || nextEvent.type == NoExpose ) {
+ qApp->x11ProcessEvent( &nextEvent );
+ continue;
+ } else if ( nextEvent.type != MotionNotify ||
+ nextEvent.xmotion.window != event->xmotion.window ||
+ nextEvent.xmotion.state != event->xmotion.state ) {
+ XPutBackEvent( appDpy, &nextEvent );
+ break;
+ }
+ if ( !qt_x11EventFilter(&nextEvent)
+ && !x11Event( &nextEvent ) ) // send event through filter
+ lastMotion = nextEvent.xmotion;
+ else
+ break;
+ }
+ type = QEvent::MouseMove;
+ pos.rx() = lastMotion.x;
+ pos.ry() = lastMotion.y;
+ globalPos.rx() = lastMotion.x_root;
+ globalPos.ry() = lastMotion.y_root;
+ state = qt_x11_translateButtonState( lastMotion.state );
+ if ( qt_button_down && (state & (LeftButton |
+ MidButton |
+ RightButton ) ) == 0 )
+ qt_button_down = 0;
+
+ // throw away mouse move events that are sent multiple times to the same
+ // position
+ bool throw_away = FALSE;
+ if ( x_root_save == globalPos.x() &&
+ y_root_save == globalPos.y() )
+ throw_away = TRUE;
+ x_root_save = globalPos.x();
+ y_root_save = globalPos.y();
+ if ( throw_away )
+ return TRUE;
+ } else if ( event->type == EnterNotify || event->type == LeaveNotify) {
+ XEvent *xevent = (XEvent *)event;
+ //unsigned int xstate = event->xcrossing.state;
+ type = QEvent::MouseMove;
+ pos.rx() = xevent->xcrossing.x;
+ pos.ry() = xevent->xcrossing.y;
+ globalPos.rx() = xevent->xcrossing.x_root;
+ globalPos.ry() = xevent->xcrossing.y_root;
+ state = qt_x11_translateButtonState( xevent->xcrossing.state );
+ if ( qt_button_down && (state & (LeftButton |
+ MidButton |
+ RightButton ) ) == 0 )
+ qt_button_down = 0;
+ if ( !qt_button_down )
+ state = state & ~(LeftButton | MidButton | RightButton );
+ } else { // button press or release
+ pos.rx() = event->xbutton.x;
+ pos.ry() = event->xbutton.y;
+ globalPos.rx() = event->xbutton.x_root;
+ globalPos.ry() = event->xbutton.y_root;
+ state = qt_x11_translateButtonState( event->xbutton.state );
+ switch ( event->xbutton.button ) {
+ case Button1: button = LeftButton; break;
+ case Button2: button = MidButton; break;
+ case Button3: button = RightButton; break;
+ case Button4:
+ case Button5:
+ case 6:
+ case 7:
+ // the fancy mouse wheel.
+
+ // take care about grabbing. We do this here since it
+ // is clear that we return anyway
+ if ( qApp->inPopupMode() && popupGrabOk )
+ XAllowEvents( x11Display(), SyncPointer, CurrentTime );
+
+ // We are only interested in ButtonPress.
+ if (event->type == ButtonPress ){
+
+ // compress wheel events (the X Server will simply
+ // send a button press for each single notch,
+ // regardless whether the application can catch up
+ // or not)
+ int delta = 1;
+ XEvent xevent;
+ while ( XCheckTypedWindowEvent(x11Display(),winId(),
+ ButtonPress,&xevent) ){
+ if (xevent.xbutton.button != event->xbutton.button){
+ XPutBackEvent(x11Display(), &xevent);
+ break;
+ }
+ delta++;
+ }
+
+ // the delta is defined as multiples of
+ // WHEEL_DELTA, which is set to 120. Future wheels
+ // may offer a finer-resolution. A positive delta
+ // indicates forward rotation, a negative one
+ // backward rotation respectively.
+ int btn = event->xbutton.button;
+ delta *= 120 * ( (btn == Button4 || btn == 6) ? 1 : -1 );
+ bool hor = ( (btn == Button4 || btn == Button5) && (state&AltButton) ||
+ (btn == 6 || btn == 7) );
+ translateWheelEvent( globalPos.x(), globalPos.y(), delta, state, (hor)?Horizontal:Vertical );
+ }
+ return TRUE;
+ }
+ if ( event->type == ButtonPress ) { // mouse button pressed
+#if defined(Q_OS_IRIX) && defined(QT_TABLET_SUPPORT)
+ XEvent myEv;
+ if ( XCheckTypedEvent( appDpy, xinput_button_press, &myEv ) ) {
+ if ( translateXinputEvent( &myEv ) ) {
+ //Spontaneous event sent. Check if we need to continue.
+ if ( chokeMouse ) {
+ chokeMouse = FALSE;
+ return FALSE;
+ }
+ }
+ }
+#endif
+ qt_button_down = childAt( pos ); //magic for masked widgets
+ if ( !qt_button_down || !qt_button_down->testWFlags(WMouseNoMask) )
+ qt_button_down = this;
+ if ( mouseActWindow == event->xbutton.window &&
+ mouseButtonPressed == button &&
+ (long)event->xbutton.time -(long)mouseButtonPressTime
+ < QApplication::doubleClickInterval() &&
+ QABS(event->xbutton.x - mouseXPos) < 5 &&
+ QABS(event->xbutton.y - mouseYPos) < 5 ) {
+ type = QEvent::MouseButtonDblClick;
+ mouseButtonPressTime -= 2000; // no double-click next time
+ } else {
+ type = QEvent::MouseButtonPress;
+ mouseButtonPressTime = event->xbutton.time;
+ }
+ mouseButtonPressed = button; // save event params for
+ mouseXPos = pos.x(); // future double click tests
+ mouseYPos = pos.y();
+ mouseGlobalXPos = globalPos.x();
+ mouseGlobalYPos = globalPos.y();
+ } else { // mouse button released
+#if defined(Q_OS_IRIX) && defined(QT_TABLET_SUPPORT)
+ XEvent myEv;
+ if ( XCheckTypedEvent( appDpy, xinput_button_release, &myEv ) ) {
+ if ( translateXinputEvent( &myEv ) ) {
+ //Spontaneous event sent. Check if we need to continue.
+ if ( chokeMouse ) {
+ chokeMouse = FALSE;
+ return FALSE;
+ }
+ }
+ }
+#endif
+ if ( manualGrab ) { // release manual grab
+ manualGrab = FALSE;
+ XUngrabPointer( x11Display(), CurrentTime );
+ XFlush( x11Display() );
+ }
+
+ type = QEvent::MouseButtonRelease;
+ }
+ }
+ mouseActWindow = winId(); // save some event params
+ mouseButtonState = state;
+ if ( type == 0 ) // don't send event
+ return FALSE;
+
+ if ( qApp->inPopupMode() ) { // in popup mode
+ QWidget *popup = qApp->activePopupWidget();
+ if ( popup != this ) {
+ if ( testWFlags(WType_Popup) && rect().contains(pos) )
+ popup = this;
+ else // send to last popup
+ pos = popup->mapFromGlobal( globalPos );
+ }
+ bool releaseAfter = FALSE;
+ QWidget *popupChild = popup->childAt( pos );
+ QWidget *popupTarget = popupChild ? popupChild : popup;
+
+ if (popup != popupOfPopupButtonFocus){
+ popupButtonFocus = 0;
+ popupOfPopupButtonFocus = 0;
+ }
+
+ if ( !popupTarget->isEnabled() ) {
+ if ( popupGrabOk )
+ XAllowEvents( x11Display(), SyncPointer, CurrentTime );
+ }
+
+ switch ( type ) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ popupButtonFocus = popupChild;
+ popupOfPopupButtonFocus = popup;
+ break;
+ case QEvent::MouseButtonRelease:
+ releaseAfter = TRUE;
+ break;
+ default:
+ break; // nothing for mouse move
+ }
+
+ Display* dpy = x11Display(); // store display, send() may destroy us
+
+
+ int oldOpenPopupCount = openPopupCount;
+
+ if ( popupButtonFocus ) {
+ QMouseEvent e( type, popupButtonFocus->mapFromGlobal(globalPos),
+ globalPos, button, state );
+ QApplication::sendSpontaneousEvent( popupButtonFocus, &e );
+ if ( releaseAfter ) {
+ popupButtonFocus = 0;
+ popupOfPopupButtonFocus = 0;
+ }
+ } else if ( popupChild ) {
+ QMouseEvent e( type, popupChild->mapFromGlobal(globalPos),
+ globalPos, button, state );
+ QApplication::sendSpontaneousEvent( popupChild, &e );
+ } else {
+ QMouseEvent e( type, pos, globalPos, button, state );
+ QApplication::sendSpontaneousEvent( popup, &e );
+ }
+
+ if ( type == QEvent::MouseButtonPress && button == RightButton && ( openPopupCount == oldOpenPopupCount ) ) {
+ QWidget *popupEvent = popup;
+ if(popupButtonFocus)
+ popupEvent = popupButtonFocus;
+ else if(popupChild)
+ popupEvent = popupChild;
+ QContextMenuEvent e( QContextMenuEvent::Mouse, pos, globalPos, state );
+ QApplication::sendSpontaneousEvent( popupEvent, &e );
+ }
+
+ if ( releaseAfter )
+ qt_button_down = 0;
+
+ if ( qApp->inPopupMode() ) { // still in popup mode
+ if ( popupGrabOk )
+ XAllowEvents( dpy, SyncPointer, CurrentTime );
+ } else {
+ if ( type != QEvent::MouseButtonRelease && state != 0 &&
+ QWidget::find((WId)mouseActWindow) ) {
+ manualGrab = TRUE; // need to manually grab
+ XGrabPointer( dpy, mouseActWindow, False,
+ (uint)(ButtonPressMask | ButtonReleaseMask |
+ ButtonMotionMask |
+ EnterWindowMask | LeaveWindowMask),
+ GrabModeAsync, GrabModeAsync,
+ None, None, CurrentTime );
+ }
+ }
+
+ } else {
+ QWidget *widget = this;
+ QWidget *w = QWidget::mouseGrabber();
+ if ( !w )
+ w = qt_button_down;
+ if ( w && w != this ) {
+ widget = w;
+ pos = w->mapFromGlobal( globalPos );
+ }
+
+ if ( popupCloseDownMode ) {
+ popupCloseDownMode = FALSE;
+ if ( testWFlags(WType_Popup) ) // ignore replayed event
+ return TRUE;
+ }
+
+ if ( type == QEvent::MouseButtonRelease &&
+ (state & (~button) & ( LeftButton |
+ MidButton |
+ RightButton)) == 0 ) {
+ qt_button_down = 0;
+ }
+
+ int oldOpenPopupCount = openPopupCount;
+
+ QMouseEvent e( type, pos, globalPos, button, state );
+ QApplication::sendSpontaneousEvent( widget, &e );
+
+ if ( type == QEvent::MouseButtonPress && button == RightButton && ( openPopupCount == oldOpenPopupCount ) ) {
+ QContextMenuEvent e( QContextMenuEvent::Mouse, pos, globalPos, state );
+ QApplication::sendSpontaneousEvent( widget, &e );
+ }
+ }
+ return TRUE;
+}
+
+
+//
+// Wheel event translation
+//
+bool QETWidget::translateWheelEvent( int global_x, int global_y, int delta, int state, Orientation orient )
+{
+ // send the event to the widget or its ancestors
+ {
+ QWidget* popup = qApp->activePopupWidget();
+ if ( popup && topLevelWidget() != popup )
+ popup->close();
+ QWheelEvent e( mapFromGlobal(QPoint( global_x, global_y)),
+ QPoint(global_x, global_y), delta, state, orient );
+ if ( QApplication::sendSpontaneousEvent( this, &e ) )
+ return TRUE;
+ }
+
+ // send the event to the widget that has the focus or its ancestors, if different
+ QWidget *w = this;
+ if ( w != qApp->focusWidget() && ( w = qApp->focusWidget() ) ) {
+ QWidget* popup = qApp->activePopupWidget();
+ if ( popup && w != popup )
+ popup->hide();
+ QWheelEvent e( mapFromGlobal(QPoint( global_x, global_y)),
+ QPoint(global_x, global_y), delta, state, orient );
+ if ( QApplication::sendSpontaneousEvent( w, &e ) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+//
+// XInput Translation Event
+//
+#if defined (QT_TABLET_SUPPORT)
+bool QETWidget::translateXinputEvent( const XEvent *ev )
+{
+#if defined (Q_OS_IRIX)
+ // Wacom has put defines in their wacom.h file so it would be quite wise
+ // to use them, need to think of a decent way of not using
+ // it when it doesn't exist...
+ XDeviceState *s;
+ XInputClass *iClass;
+ XValuatorState *vs;
+ int j;
+#endif
+ QWidget *w = this;
+ QPoint global,
+ curr;
+ static int pressure = 0;
+ static int xTilt = 0,
+ yTilt = 0;
+ int deviceType = QTabletEvent::NoDevice;
+ QPair<int, int> tId;
+ XEvent xinputMotionEvent;
+ XEvent mouseMotionEvent;
+ XDevice *dev;
+ const XDeviceMotionEvent *motion = 0;
+ XDeviceButtonEvent *button = 0;
+ QEvent::Type t;
+
+ if ( ev->type == xinput_motion ) {
+ motion = (const XDeviceMotionEvent*)ev;
+ for (;;) {
+ if (!XCheckTypedWindowEvent(x11Display(), winId(), MotionNotify, &mouseMotionEvent))
+ break;
+ if (!XCheckTypedWindowEvent(x11Display(), winId(), xinput_motion, &xinputMotionEvent)) {
+ XPutBackEvent(x11Display(), &mouseMotionEvent);
+ break;
+ }
+ if (mouseMotionEvent.xmotion.time != motion->time) {
+ XPutBackEvent(x11Display(), &mouseMotionEvent);
+ XPutBackEvent(x11Display(), &xinputMotionEvent);
+ break;
+ }
+ motion = ((const XDeviceMotionEvent*)&xinputMotionEvent);
+ }
+ t = QEvent::TabletMove;
+ curr = QPoint( motion->x, motion->y );
+ } else {
+ if ( ev->type == xinput_button_press ) {
+ t = QEvent::TabletPress;
+ } else {
+ t = QEvent::TabletRelease;
+ }
+ button = (XDeviceButtonEvent*)ev;
+/*
+ qDebug( "\n\nXInput Button Event" );
+ qDebug( "serial:\t%d", button->serial );
+ qDebug( "send_event:\t%d", button->send_event );
+ qDebug( "display:\t%p", button->display );
+ qDebug( "window:\t%d", button->window );
+ qDebug( "deviceID:\t%d", button->deviceid );
+ qDebug( "root:\t%d", button->root );
+ qDebug( "subwindot:\t%d", button->subwindow );
+ qDebug( "x:\t%d", button->x );
+ qDebug( "y:\t%d", button->y );
+ qDebug( "x_root:\t%d", button->x_root );
+ qDebug( "y_root:\t%d", button->y_root );
+ qDebug( "state:\t%d", button->state );
+ qDebug( "button:\t%d", button->button );
+ qDebug( "same_screen:\t%d", button->same_screen );
+ qDebug( "time:\t%d", button->time );
+*/
+ curr = QPoint( button->x, button->y );
+ }
+#if defined(Q_OS_IRIX)
+ // default...
+ dev = devStylus;
+#else
+ if ( ev->type == xinput_motion ) {
+ if ( motion->deviceid == devStylus->device_id ) {
+ dev = devStylus;
+ deviceType = QTabletEvent::Stylus;
+ } else if ( motion->deviceid == devEraser->device_id ) {
+ dev = devEraser;
+ deviceType = QTabletEvent::Eraser;
+ }
+ } else {
+ if ( button->deviceid == devStylus->device_id ) {
+ dev = devStylus;
+ deviceType = QTabletEvent::Stylus;
+ } else if ( button->deviceid == devEraser->device_id ) {
+ dev = devEraser;
+ deviceType = QTabletEvent::Eraser;
+ }
+ }
+#endif
+
+ const int PRESSURE_LEVELS = 255;
+ // we got the maximum pressure at start time, since various tablets have
+ // varying levels of distinguishing pressure changes, let's standardize and
+ // scale everything to 256 different levels...
+ static int scaleFactor = -1;
+ if ( scaleFactor == -1 ) {
+ if ( max_pressure > PRESSURE_LEVELS )
+ scaleFactor = max_pressure / PRESSURE_LEVELS;
+ else
+ scaleFactor = PRESSURE_LEVELS / max_pressure;
+ }
+#if defined (Q_OS_IRIX)
+ s = XQueryDeviceState( appDpy, dev );
+ if ( s == NULL )
+ return FALSE;
+ iClass = s->data;
+ for ( j = 0; j < s->num_classes; j++ ) {
+ if ( iClass->c_class == ValuatorClass ) {
+ vs = (XValuatorState *)iClass;
+ // figure out what device we have, based on bitmasking...
+ if ( vs->valuators[WAC_TRANSDUCER_I]
+ & WAC_TRANSDUCER_PROX_MSK ) {
+ switch ( vs->valuators[WAC_TRANSDUCER_I]
+ & WAC_TRANSDUCER_MSK ) {
+ case WAC_PUCK_ID:
+ deviceType = QTabletEvent::Puck;
+ break;
+ case WAC_STYLUS_ID:
+ deviceType = QTabletEvent::Stylus;
+ break;
+ case WAC_ERASER_ID:
+ deviceType = QTabletEvent::Eraser;
+ break;
+ }
+ // Get a Unique Id for the device, Wacom gives us this ability
+ tId.first = vs->valuators[WAC_TRANSDUCER_I] & WAC_TRANSDUCER_ID_MSK;
+ tId.second = vs->valuators[WAC_SERIAL_NUM_I];
+ } else
+ deviceType = QTabletEvent::NoDevice;
+ // apparently Wacom needs a cast for the +/- values to make sense
+ xTilt = short(vs->valuators[WAC_XTILT_I]);
+ yTilt = short(vs->valuators[WAC_YTILT_I]);
+ if ( max_pressure > PRESSURE_LEVELS )
+ pressure = vs->valuators[WAC_PRESSURE_I] / scaleFactor;
+ else
+ pressure = vs->valuators[WAC_PRESSURE_I] * scaleFactor;
+ global = QPoint( vs->valuators[WAC_XCOORD_I],
+ vs->valuators[WAC_YCOORD_I] );
+ break;
+ }
+ iClass = (XInputClass*)((char*)iClass + iClass->length);
+ }
+ XFreeDeviceState( s );
+#else
+ if ( motion ) {
+ xTilt = short(motion->axis_data[3]);
+ yTilt = short(motion->axis_data[4]);
+ if ( max_pressure > PRESSURE_LEVELS )
+ pressure = motion->axis_data[2] / scaleFactor;
+ else
+ pressure = motion->axis_data[2] * scaleFactor;
+ global = QPoint( motion->axis_data[0], motion->axis_data[1] );
+ } else {
+ xTilt = short(button->axis_data[3]);
+ yTilt = short(button->axis_data[4]);
+ if ( max_pressure > PRESSURE_LEVELS )
+ pressure = button->axis_data[2] / scaleFactor;
+ else
+ pressure = button->axis_data[2] * scaleFactor;
+ global = QPoint( button->axis_data[0], button->axis_data[1] );
+ }
+ // The only way to get these Ids is to scan the XFree86 log, which I'm not going to do.
+ tId.first = tId.second = -1;
+#endif
+
+ QTabletEvent e( t, curr, global, deviceType, pressure, xTilt, yTilt, tId );
+ QApplication::sendSpontaneousEvent( w, &e );
+ return TRUE;
+}
+#endif
+
+bool QETWidget::translatePropertyEvent(const XEvent *event)
+{
+ if (!isTopLevel()) return TRUE;
+
+ Atom ret;
+ int format, e;
+ unsigned char *data = 0;
+ unsigned long nitems, after;
+
+ if (event->xproperty.atom == qt_net_wm_frame_strut) {
+ topData()->fleft = topData()->fright = topData()->ftop = topData()->fbottom = 0;
+ fstrut_dirty = 1;
+
+ if (event->xproperty.state == PropertyNewValue) {
+ e = XGetWindowProperty(appDpy, event->xproperty.window, qt_net_wm_frame_strut,
+ 0, 4, // struts are 4 longs
+ False, XA_CARDINAL, &ret, &format, &nitems, &after, &data);
+
+ if (e == Success && ret == XA_CARDINAL &&
+ format == 32 && nitems == 4) {
+ long *strut = (long *) data;
+ topData()->fleft = strut[0];
+ topData()->fright = strut[1];
+ topData()->ftop = strut[2];
+ topData()->fbottom = strut[3];
+ fstrut_dirty = 0;
+ }
+ }
+ } else if (event->xproperty.atom == qt_net_wm_state) {
+ bool max = FALSE;
+ bool full = FALSE;
+
+ if (event->xproperty.state == PropertyNewValue) {
+ // using length of 1024 should be safe for all current and
+ // possible NET states...
+ e = XGetWindowProperty(appDpy, event->xproperty.window, qt_net_wm_state, 0, 1024,
+ False, XA_ATOM, &ret, &format, &nitems, &after, &data);
+
+ if (e == Success && ret == XA_ATOM && format == 32 && nitems > 0) {
+ Atom *states = (Atom *) data;
+
+ unsigned long i;
+ for (i = 0; i < nitems; i++) {
+ if (states[i] == qt_net_wm_state_max_v || states[i] == qt_net_wm_state_max_h)
+ max = TRUE;
+ else if (states[i] == qt_net_wm_state_fullscreen)
+ full = TRUE;
+ }
+ }
+ }
+
+ bool send_event = FALSE;
+
+ if (qt_net_supports(qt_net_wm_state_max_v)
+ && qt_net_supports(qt_net_wm_state_max_h)) {
+ if (max && !isMaximized()) {
+ setWState(WState_Maximized);
+ send_event = TRUE;
+ } else if (!max && isMaximized()) {
+ clearWState(WState_Maximized);
+ send_event = TRUE;
+ }
+ }
+
+ if (qt_net_supports(qt_net_wm_state_fullscreen)) {
+ if (full && !isFullScreen()) {
+ setWState(WState_FullScreen);
+ send_event = TRUE;
+ } else if (!full && isFullScreen()) {
+ clearWState(WState_FullScreen);
+ send_event = TRUE;
+ }
+ }
+
+ if (send_event) {
+ QEvent e(QEvent::WindowStateChange);
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+ } else if (event->xproperty.atom == qt_wm_state) {
+ // the widget frame strut should also be invalidated
+ topData()->fleft = topData()->fright = topData()->ftop = topData()->fbottom = 0;
+ fstrut_dirty = 1;
+
+ if (event->xproperty.state == PropertyDelete) {
+ // the window manager has removed the WM State property,
+ // so it is now in the withdrawn state (ICCCM 4.1.3.1) and
+ // we are free to reuse this window
+ topData()->parentWinId = 0;
+ // map the window if we were waiting for a transition to
+ // withdrawn
+ if ( qt_deferred_map_contains( this ) ) {
+ qt_deferred_map_take( this );
+ XMapWindow( appDpy, winId() );
+ }
+ } else if (topData()->parentWinId != QPaintDevice::x11AppRootWindow(x11Screen())) {
+ // the window manager has changed the WM State property...
+ // we are wanting to see if we are withdrawn so that we
+ // can reuse this window... we only do this check *IF* we
+ // haven't been reparented to root - (the parentWinId !=
+ // QPaintDevice::x11AppRootWindow(x11Screen())) check
+ // above
+
+ e = XGetWindowProperty(appDpy, winId(), qt_wm_state, 0, 2, False, qt_wm_state,
+ &ret, &format, &nitems, &after, &data );
+
+ if (e == Success && ret == qt_wm_state && format == 32 && nitems > 0) {
+ long *state = (long *) data;
+ switch (state[0]) {
+ case WithdrawnState:
+ // if we are in the withdrawn state, we are free
+ // to reuse this window provided we remove the
+ // WM_STATE property (ICCCM 4.1.3.1)
+ XDeleteProperty(appDpy, winId(), qt_wm_state);
+
+ // set the parent id to zero, so that show() will
+ // work again
+ topData()->parentWinId = 0;
+ // map the window if we were waiting for a
+ // transition to withdrawn
+ if ( qt_deferred_map_contains( this ) ) {
+ qt_deferred_map_take( this );
+ XMapWindow( appDpy, winId() );
+ }
+ break;
+
+ case IconicState:
+ if (!isMinimized()) {
+ // window was minimized
+ setWState(WState_Minimized);
+ QEvent e(QEvent::WindowStateChange);
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+ break;
+
+ default:
+ if (isMinimized()) {
+ // window was un-minimized
+ clearWState(WState_Minimized);
+ QEvent e(QEvent::WindowStateChange);
+ QApplication::sendSpontaneousEvent(this, &e);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if (data)
+ XFree(data);
+
+ return TRUE;
+}
+
+#ifndef XK_ISO_Left_Tab
+#define XK_ISO_Left_Tab 0xFE20
+#endif
+
+// the next lines are taken from XFree > 4.0 (X11/XF86keysyms.h), defining some special
+// multimedia keys. They are included here as not every system has them.
+#define XF86XK_Standby 0x1008FF10
+#define XF86XK_AudioLowerVolume 0x1008FF11
+#define XF86XK_AudioMute 0x1008FF12
+#define XF86XK_AudioRaiseVolume 0x1008FF13
+#define XF86XK_AudioPlay 0x1008FF14
+#define XF86XK_AudioStop 0x1008FF15
+#define XF86XK_AudioPrev 0x1008FF16
+#define XF86XK_AudioNext 0x1008FF17
+#define XF86XK_HomePage 0x1008FF18
+#define XF86XK_Calculator 0x1008FF1D
+#define XF86XK_Mail 0x1008FF19
+#define XF86XK_Start 0x1008FF1A
+#define XF86XK_Search 0x1008FF1B
+#define XF86XK_AudioRecord 0x1008FF1C
+#define XF86XK_Back 0x1008FF26
+#define XF86XK_Forward 0x1008FF27
+#define XF86XK_Stop 0x1008FF28
+#define XF86XK_Refresh 0x1008FF29
+#define XF86XK_Favorites 0x1008FF30
+#define XF86XK_AudioPause 0x1008FF31
+#define XF86XK_AudioMedia 0x1008FF32
+#define XF86XK_MyComputer 0x1008FF33
+#define XF86XK_OpenURL 0x1008FF38
+#define XF86XK_Launch0 0x1008FF40
+#define XF86XK_Launch1 0x1008FF41
+#define XF86XK_Launch2 0x1008FF42
+#define XF86XK_Launch3 0x1008FF43
+#define XF86XK_Launch4 0x1008FF44
+#define XF86XK_Launch5 0x1008FF45
+#define XF86XK_Launch6 0x1008FF46
+#define XF86XK_Launch7 0x1008FF47
+#define XF86XK_Launch8 0x1008FF48
+#define XF86XK_Launch9 0x1008FF49
+#define XF86XK_LaunchA 0x1008FF4A
+#define XF86XK_LaunchB 0x1008FF4B
+#define XF86XK_LaunchC 0x1008FF4C
+#define XF86XK_LaunchD 0x1008FF4D
+#define XF86XK_LaunchE 0x1008FF4E
+#define XF86XK_LaunchF 0x1008FF4F
+// end of XF86keysyms.h
+
+
+
+static const KeySym KeyTbl[] = { // keyboard mapping table
+ XK_Escape, Qt::Key_Escape, // misc keys
+ XK_Tab, Qt::Key_Tab,
+ XK_ISO_Left_Tab, Qt::Key_Backtab,
+ XK_BackSpace, Qt::Key_Backspace,
+ XK_Return, Qt::Key_Return,
+ XK_Insert, Qt::Key_Insert,
+ XK_KP_Insert, Qt::Key_Insert,
+ XK_Delete, Qt::Key_Delete,
+ XK_KP_Delete, Qt::Key_Delete,
+ XK_Clear, Qt::Key_Delete,
+ XK_Pause, Qt::Key_Pause,
+ XK_Print, Qt::Key_Print,
+ XK_KP_Begin, Qt::Key_Clear,
+ 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq
+ 0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq
+ XK_Home, Qt::Key_Home, // cursor movement
+ XK_End, Qt::Key_End,
+ XK_Left, Qt::Key_Left,
+ XK_Up, Qt::Key_Up,
+ XK_Right, Qt::Key_Right,
+ XK_Down, Qt::Key_Down,
+ XK_Prior, Qt::Key_Prior,
+ XK_Next, Qt::Key_Next,
+ XK_KP_Home, Qt::Key_Home,
+ XK_KP_End, Qt::Key_End,
+ XK_KP_Left, Qt::Key_Left,
+ XK_KP_Up, Qt::Key_Up,
+ XK_KP_Right, Qt::Key_Right,
+ XK_KP_Down, Qt::Key_Down,
+ XK_KP_Prior, Qt::Key_Prior,
+ XK_KP_Next, Qt::Key_Next,
+ XK_Shift_L, Qt::Key_Shift, // modifiers
+ XK_Shift_R, Qt::Key_Shift,
+ XK_Shift_Lock, Qt::Key_Shift,
+ XK_Control_L, Qt::Key_Control,
+ XK_Control_R, Qt::Key_Control,
+ XK_Meta_L, Qt::Key_Meta,
+ XK_Meta_R, Qt::Key_Meta,
+ XK_Alt_L, Qt::Key_Alt,
+ XK_Alt_R, Qt::Key_Alt,
+ XK_Caps_Lock, Qt::Key_CapsLock,
+ XK_Num_Lock, Qt::Key_NumLock,
+ XK_Scroll_Lock, Qt::Key_ScrollLock,
+ XK_KP_Space, Qt::Key_Space, // numeric keypad
+ XK_KP_Tab, Qt::Key_Tab,
+ XK_KP_Enter, Qt::Key_Enter,
+ XK_KP_Equal, Qt::Key_Equal,
+ XK_KP_Multiply, Qt::Key_Asterisk,
+ XK_KP_Add, Qt::Key_Plus,
+ XK_KP_Separator, Qt::Key_Comma,
+ XK_KP_Subtract, Qt::Key_Minus,
+ XK_KP_Decimal, Qt::Key_Period,
+ XK_KP_Divide, Qt::Key_Slash,
+ XK_Super_L, Qt::Key_Super_L,
+ XK_Super_R, Qt::Key_Super_R,
+ XK_Menu, Qt::Key_Menu,
+ XK_Hyper_L, Qt::Key_Hyper_L,
+ XK_Hyper_R, Qt::Key_Hyper_R,
+ XK_Help, Qt::Key_Help,
+ 0x1000FF74, Qt::Key_BackTab, // hardcoded HP backtab
+ 0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
+ 0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
+
+ // International input method support keys
+
+ // International & multi-key character composition
+ XK_Multi_key, Qt::Key_Multi_key,
+ XK_Codeinput, Qt::Key_Codeinput,
+ XK_SingleCandidate, Qt::Key_SingleCandidate,
+ XK_MultipleCandidate, Qt::Key_MultipleCandidate,
+ XK_PreviousCandidate, Qt::Key_PreviousCandidate,
+
+ // Misc Functions
+ XK_Mode_switch, Qt::Key_Mode_switch,
+ //XK_script_switch, Qt::Key_script_switch,
+ XK_script_switch, Qt::Key_Mode_switch,
+
+ // Japanese keyboard support
+ XK_Kanji, Qt::Key_Kanji,
+ XK_Muhenkan, Qt::Key_Muhenkan,
+ //XK_Henkan_Mode, Qt::Key_Henkan_Mode,
+ XK_Henkan_Mode, Qt::Key_Henkan,
+ XK_Henkan, Qt::Key_Henkan,
+ XK_Romaji, Qt::Key_Romaji,
+ XK_Hiragana, Qt::Key_Hiragana,
+ XK_Katakana, Qt::Key_Katakana,
+ XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana,
+ XK_Zenkaku, Qt::Key_Zenkaku,
+ XK_Hankaku, Qt::Key_Hankaku,
+ XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku,
+ XK_Touroku, Qt::Key_Touroku,
+ XK_Massyo, Qt::Key_Massyo,
+ XK_Kana_Lock, Qt::Key_Kana_Lock,
+ XK_Kana_Shift, Qt::Key_Kana_Shift,
+ XK_Eisu_Shift, Qt::Key_Eisu_Shift,
+ XK_Eisu_toggle, Qt::Key_Eisu_toggle,
+ //XK_Kanji_Bangou, Qt::Key_Kanji_Bangou,
+ //XK_Zen_Koho, Qt::Key_Zen_Koho,
+ //XK_Mae_Koho, Qt::Key_Mae_Koho,
+ XK_Kanji_Bangou, Qt::Key_Codeinput,
+ XK_Zen_Koho, Qt::Key_MultipleCandidate,
+ XK_Mae_Koho, Qt::Key_PreviousCandidate,
+
+#ifdef XK_KOREAN
+ // Korean keyboard support
+ XK_Hangul, Qt::Key_Hangul,
+ XK_Hangul_Start, Qt::Key_Hangul_Start,
+ XK_Hangul_End, Qt::Key_Hangul_End,
+ XK_Hangul_Hanja, Qt::Key_Hangul_Hanja,
+ XK_Hangul_Jamo, Qt::Key_Hangul_Jamo,
+ XK_Hangul_Romaja, Qt::Key_Hangul_Romaja,
+ //XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
+ XK_Hangul_Codeinput, Qt::Key_Codeinput,
+ XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja,
+ XK_Hangul_Banja, Qt::Key_Hangul_Banja,
+ XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja,
+ XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja,
+ //XK_Hangul_SingleCandidate, Qt::Key_Hangul_SingleCandidate,
+ //XK_Hangul_MultipleCandidate, Qt::Key_Hangul_MultipleCandidate,
+ //XK_Hangul_PreviousCandidate, Qt::Key_Hangul_PreviousCandidate,
+ XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate,
+ XK_Hangul_MultipleCandidate, Qt::Key_MultipleCandidate,
+ XK_Hangul_PreviousCandidate, Qt::Key_PreviousCandidate,
+ XK_Hangul_Special, Qt::Key_Hangul_Special,
+ //XK_Hangul_switch, Qt::Key_Hangul_switch,
+ XK_Hangul_switch, Qt::Key_Mode_switch,
+#endif // XK_KOREAN
+
+ // dead keys
+ XK_dead_grave, Qt::Key_Dead_Grave,
+ XK_dead_acute, Qt::Key_Dead_Acute,
+ XK_dead_circumflex, Qt::Key_Dead_Circumflex,
+ XK_dead_tilde, Qt::Key_Dead_Tilde,
+ XK_dead_macron, Qt::Key_Dead_Macron,
+ XK_dead_breve, Qt::Key_Dead_Breve,
+ XK_dead_abovedot, Qt::Key_Dead_Abovedot,
+ XK_dead_diaeresis, Qt::Key_Dead_Diaeresis,
+ XK_dead_abovering, Qt::Key_Dead_Abovering,
+ XK_dead_doubleacute, Qt::Key_Dead_Doubleacute,
+ XK_dead_caron, Qt::Key_Dead_Caron,
+ XK_dead_cedilla, Qt::Key_Dead_Cedilla,
+ XK_dead_ogonek, Qt::Key_Dead_Ogonek,
+ XK_dead_iota, Qt::Key_Dead_Iota,
+ XK_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
+ XK_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
+ XK_dead_belowdot, Qt::Key_Dead_Belowdot,
+ XK_dead_hook, Qt::Key_Dead_Hook,
+ XK_dead_horn, Qt::Key_Dead_Horn,
+
+ // Special multimedia keys
+ // currently only tested with MS internet keyboard
+
+ // browsing keys
+ XF86XK_Back, Qt::Key_Back,
+ XF86XK_Forward, Qt::Key_Forward,
+ XF86XK_Stop, Qt::Key_Stop,
+ XF86XK_Refresh, Qt::Key_Refresh,
+ XF86XK_Favorites, Qt::Key_Favorites,
+ XF86XK_AudioMedia, Qt::Key_LaunchMedia,
+ XF86XK_OpenURL, Qt::Key_OpenUrl,
+ XF86XK_HomePage, Qt::Key_HomePage,
+ XF86XK_Search, Qt::Key_Search,
+
+ // media keys
+ XF86XK_AudioLowerVolume, Qt::Key_VolumeDown,
+ XF86XK_AudioMute, Qt::Key_VolumeMute,
+ XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp,
+ XF86XK_AudioPlay, Qt::Key_MediaPlay,
+ XF86XK_AudioStop, Qt::Key_MediaStop,
+ XF86XK_AudioPrev, Qt::Key_MediaPrev,
+ XF86XK_AudioNext, Qt::Key_MediaNext,
+ XF86XK_AudioRecord, Qt::Key_MediaRecord,
+
+ // launch keys
+ XF86XK_Mail, Qt::Key_LaunchMail,
+ XF86XK_MyComputer, Qt::Key_Launch0,
+ XF86XK_Calculator, Qt::Key_Launch1,
+ XF86XK_Standby, Qt::Key_Standby,
+
+ XF86XK_Launch0, Qt::Key_Launch2,
+ XF86XK_Launch1, Qt::Key_Launch3,
+ XF86XK_Launch2, Qt::Key_Launch4,
+ XF86XK_Launch3, Qt::Key_Launch5,
+ XF86XK_Launch4, Qt::Key_Launch6,
+ XF86XK_Launch5, Qt::Key_Launch7,
+ XF86XK_Launch6, Qt::Key_Launch8,
+ XF86XK_Launch7, Qt::Key_Launch9,
+ XF86XK_Launch8, Qt::Key_LaunchA,
+ XF86XK_Launch9, Qt::Key_LaunchB,
+ XF86XK_LaunchA, Qt::Key_LaunchC,
+ XF86XK_LaunchB, Qt::Key_LaunchD,
+ XF86XK_LaunchC, Qt::Key_LaunchE,
+ XF86XK_LaunchD, Qt::Key_LaunchF,
+
+ 0, 0
+};
+
+
+static QIntDict<void> *keyDict = 0;
+static QIntDict<void> *textDict = 0;
+
+static void deleteKeyDicts()
+{
+ if ( keyDict )
+ delete keyDict;
+ keyDict = 0;
+ if ( textDict )
+ delete textDict;
+ textDict = 0;
+}
+
+#if !defined(QT_NO_XIM)
+static const unsigned short katakanaKeysymsToUnicode[] = {
+ 0x0000, 0x3002, 0x300C, 0x300D, 0x3001, 0x30FB, 0x30F2, 0x30A1,
+ 0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30E3, 0x30E5, 0x30E7, 0x30C3,
+ 0x30FC, 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD,
+ 0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD,
+ 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC,
+ 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE,
+ 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9,
+ 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F3, 0x309B, 0x309C
+};
+
+static const unsigned short cyrillicKeysymsToUnicode[] = {
+ 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0000, 0x045e, 0x045f,
+ 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407,
+ 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0000, 0x040e, 0x040f,
+ 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
+ 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
+ 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
+ 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a,
+ 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
+ 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a
+};
+
+static const unsigned short greekKeysymsToUnicode[] = {
+ 0x0000, 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c,
+ 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015,
+ 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc,
+ 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
+ 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
+ 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+ 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+ 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+ 0x03c8, 0x03c9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static const unsigned short technicalKeysymsToUnicode[] = {
+ 0x0000, 0x23B7, 0x250C, 0x2500, 0x2320, 0x2321, 0x2502, 0x23A1,
+ 0x23A3, 0x23A4, 0x23A6, 0x239B, 0x239D, 0x239E, 0x23A0, 0x23A8,
+ 0x23AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222B,
+ 0x2234, 0x221D, 0x221E, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000,
+ 0x223C, 0x2243, 0x0000, 0x0000, 0x0000, 0x21D4, 0x21D2, 0x2261,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221A, 0x0000,
+ 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222A, 0x2227, 0x2228,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193, 0x0000
+};
+
+static const unsigned short specialKeysymsToUnicode[] = {
+ 0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x0000, 0x0000,
+ 0x2424, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA,
+ 0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252C,
+ 0x2502, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static const unsigned short publishingKeysymsToUnicode[] = {
+ 0x0000, 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009,
+ 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025,
+ 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a,
+ 0x2105, 0x0000, 0x0000, 0x2012, 0x2329, 0x0000, 0x232a, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000,
+ 0x0000, 0x2122, 0x2613, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25af,
+ 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033,
+ 0x0000, 0x271d, 0x0000, 0x25ac, 0x25c0, 0x25b6, 0x25cf, 0x25ae,
+ 0x25e6, 0x25ab, 0x25ad, 0x25b3, 0x25bd, 0x2606, 0x2022, 0x25aa,
+ 0x25b2, 0x25bc, 0x261c, 0x261e, 0x2663, 0x2666, 0x2665, 0x0000,
+ 0x2720, 0x2020, 0x2021, 0x2713, 0x2717, 0x266f, 0x266d, 0x2642,
+ 0x2640, 0x260e, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e, 0x0000
+};
+
+static const unsigned short aplKeysymsToUnicode[] = {
+ 0x0000, 0x0000, 0x0000, 0x003c, 0x0000, 0x0000, 0x003e, 0x0000,
+ 0x2228, 0x2227, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00af, 0x0000, 0x22a5, 0x2229, 0x230a, 0x0000, 0x005f, 0x0000,
+ 0x0000, 0x0000, 0x2218, 0x0000, 0x2395, 0x0000, 0x22a4, 0x25cb,
+ 0x0000, 0x0000, 0x0000, 0x2308, 0x0000, 0x0000, 0x222a, 0x0000,
+ 0x2283, 0x0000, 0x2282, 0x0000, 0x22a2, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x22a3, 0x0000, 0x0000, 0x0000
+};
+
+static const unsigned short koreanKeysymsToUnicode[] = {
+ 0x0000, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
+ 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
+ 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
+ 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x314f,
+ 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156, 0x3157,
+ 0x3158, 0x3159, 0x315a, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f,
+ 0x3160, 0x3161, 0x3162, 0x3163, 0x11a8, 0x11a9, 0x11aa, 0x11ab,
+ 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3,
+ 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb,
+ 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x316d,
+ 0x3171, 0x3178, 0x317f, 0x3181, 0x3184, 0x3186, 0x318d, 0x318e,
+ 0x11eb, 0x11f0, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9
+};
+
+
+static QChar keysymToUnicode(unsigned char byte3, unsigned char byte4)
+{
+ if ( byte3 == 0x04 ) {
+ // katakana
+ if ( byte4 > 0xa0 && byte4 < 0xe0 )
+ return QChar( katakanaKeysymsToUnicode[byte4 - 0xa0] );
+ else if ( byte4 == 0x7e )
+ return QChar( 0x203e ); // Overline
+ } else if ( byte3 == 0x06 ) {
+ // russian, use lookup table
+ if ( byte4 > 0xa0 )
+ return QChar( cyrillicKeysymsToUnicode[byte4 - 0xa0] );
+ } else if ( byte3 == 0x07 ) {
+ // greek
+ if ( byte4 > 0xa0 )
+ return QChar( greekKeysymsToUnicode[byte4 - 0xa0] );
+ } else if ( byte3 == 0x08 ) {
+ // technical
+ if ( byte4 > 0xa0 )
+ return QChar( technicalKeysymsToUnicode[byte4 - 0xa0] );
+ } else if ( byte3 == 0x09 ) {
+ // special
+ if ( byte4 >= 0xe0 )
+ return QChar( specialKeysymsToUnicode[byte4 - 0xe0] );
+ } else if ( byte3 == 0x0a ) {
+ // publishing
+ if ( byte4 > 0xa0 )
+ return QChar( publishingKeysymsToUnicode[byte4 - 0xa0] );
+ } else if ( byte3 == 0x0b ) {
+ // APL
+ if ( byte4 > 0xa0 )
+ return QChar( aplKeysymsToUnicode[byte4 - 0xa0] );
+ } else if ( byte3 == 0x0e ) {
+ // Korean
+ if ( byte4 > 0xa0 )
+ return QChar( koreanKeysymsToUnicode[byte4 - 0xa0] );
+ }
+ return QChar(0x0);
+}
+#endif
+
+
+bool QETWidget::translateKeyEventInternal( const XEvent *event, int& count,
+ QString& text,
+ int& state,
+ char& ascii, int& code, QEvent::Type &type, bool willRepeat, bool statefulTranslation )
+{
+ QTextCodec *mapper = qt_input_mapper;
+ // some XmbLookupString implementations don't return buffer overflow correctly,
+ // so we increase the input buffer to allow for long strings...
+ // 256 chars * 2 bytes + 1 null-term == 513 bytes
+ QCString chars(513);
+ QChar converted;
+ KeySym key = 0;
+
+ if ( !keyDict ) {
+ keyDict = new QIntDict<void>( 13 );
+ keyDict->setAutoDelete( FALSE );
+ textDict = new QIntDict<void>( 13 );
+ textDict->setAutoDelete( FALSE );
+ qAddPostRoutine( deleteKeyDicts );
+ }
+
+ QWidget* tlw = topLevelWidget();
+
+ XKeyEvent xkeyevent = event->xkey;
+
+ // save the modifier state, we will use the keystate uint later by passing
+ // it to qt_x11_translateButtonState
+ uint keystate = event->xkey.state;
+ // remove the modifiers where mode_switch exists... HPUX machines seem
+ // to have alt *AND* mode_switch both in Mod1Mask, which causes
+ // XLookupString to return things like 'å' (aring) for ALT-A. This
+ // completely breaks modifiers. If we remove the modifier for Mode_switch,
+ // then things work correctly...
+ xkeyevent.state &= ~qt_mode_switch_remove_mask;
+
+ type = (event->type == XKeyPress)
+ ? QEvent::KeyPress : QEvent::KeyRelease;
+#if defined(QT_NO_XIM)
+
+ count = XLookupString( &xkeyevent, chars.data(), chars.size(), &key, 0 );
+
+ if ( count == 1 )
+ ascii = chars[0];
+
+#else
+ // Implementation for X11R5 and newer, using XIM
+
+ int keycode = event->xkey.keycode;
+ Status status;
+
+ if ( type == QEvent::KeyPress ) {
+ bool mb=FALSE;
+ // commit string handling is done by
+ // QXIMInputContext::x11FilterEvent() and are passed to
+ // widgets via QIMEvent regardless of XIM style, so the
+ // following code is commented out.
+#if 0
+ if ( qt_xim ) {
+ QTLWExtra* xd = tlw->topData();
+ QInputContext *qic = (QInputContext *) xd->xic;
+ if ( qic ) {
+ mb=TRUE;
+ count = qic->lookupString(&xkeyevent, chars, &key, &status);
+ }
+ }
+#endif
+ if ( !mb ) {
+ count = XLookupString( &xkeyevent,
+ chars.data(), chars.size(), &key, 0 );
+ }
+ if ( count && !keycode ) {
+ keycode = qt_ximComposingKeycode;
+ qt_ximComposingKeycode = 0;
+ }
+ if ( key )
+ keyDict->replace( keycode, (void*)key );
+ // all keysyms smaller than that are actally keys that can be mapped
+ // to unicode chars
+ if ( count == 0 && key < 0xff00 ) {
+ unsigned char byte3 = (unsigned char )(key >> 8);
+ int mib = -1;
+ switch( byte3 ) {
+ case 0: // Latin 1
+ case 1: // Latin 2
+ case 2: //latin 3
+ case 3: // latin4
+ mib = byte3 + 4; break;
+ case 5: // arabic
+ mib = 82; break;
+ case 12: // Hebrew
+ mib = 85; break;
+ case 13: // Thai
+ mib = 2259; break;
+ case 4: // kana
+ case 6: // cyrillic
+ case 7: // greek
+ case 8: // technical, no mapping here at the moment
+ case 9: // Special
+ case 10: // Publishing
+ case 11: // APL
+ case 14: // Korean, no mapping
+ mib = -1; // manual conversion
+ mapper = 0;
+ converted = keysymToUnicode( byte3, key & 0xff );
+ case 0x20:
+ // currency symbols
+ if ( key >= 0x20a0 && key <= 0x20ac ) {
+ mib = -1; // manual conversion
+ mapper = 0;
+ converted = (uint)key;
+ }
+ break;
+ default:
+ break;
+ }
+ if ( mib != -1 ) {
+ mapper = QTextCodec::codecForMib( mib );
+ chars[0] = (unsigned char) (key & 0xff); // get only the fourth bit for conversion later
+ count++;
+ }
+ } else if ( key >= 0x1000000 && key <= 0x100ffff ) {
+ converted = (ushort) (key - 0x1000000);
+ mapper = 0;
+ }
+ if ( count < (int)chars.size()-1 )
+ chars[count] = '\0';
+ if ( count == 1 ) {
+ ascii = chars[0];
+ // +256 so we can store all eight-bit codes, including ascii 0,
+ // and independent of whether char is signed or not.
+ textDict->replace( keycode, (void*)(long)(256+ascii) );
+ }
+ tlw = 0;
+ } else {
+ key = (int)(long)keyDict->find( keycode );
+ if ( key )
+ if( !willRepeat && statefulTranslation ) // Take out key of dictionary only if this call.
+ keyDict->take( keycode );
+ long s = (long)textDict->find( keycode );
+ if ( s ) {
+ if( statefulTranslation )
+ textDict->take( keycode );
+ ascii = (char)(s-256);
+ }
+ }
+#endif // !QT_NO_XIM
+
+ state = qt_x11_translateButtonState( keystate );
+
+ static int directionKeyEvent = 0;
+ static unsigned int lastWinId = 0;
+ if ( qt_use_rtl_extensions && type == QEvent::KeyRelease && statefulTranslation ) {
+ if (directionKeyEvent == Key_Direction_R || directionKeyEvent == Key_Direction_L ) {
+ type = QEvent::KeyPress;
+ code = directionKeyEvent;
+ chars[0] = 0;
+ directionKeyEvent = 0;
+ lastWinId = 0;
+ return TRUE;
+ } else {
+ directionKeyEvent = 0;
+ lastWinId = 0;
+ }
+ }
+
+ // Watch for keypresses and if its a key belonging to the Ctrl-Shift
+ // direction-changing accel, remember it.
+ // We keep track of those keys instead of using the event's state
+ // (to figure out whether the Ctrl modifier is held while Shift is pressed,
+ // or Shift is held while Ctrl is pressed) since the 'state' doesn't tell
+ // us whether the modifier held is Left or Right.
+ if ( qt_use_rtl_extensions && type == QEvent::KeyPress && statefulTranslation )
+ if (key == XK_Control_L || key == XK_Control_R || key == XK_Shift_L || key == XK_Shift_R) {
+ if (!directionKeyEvent) {
+ directionKeyEvent = key;
+ // This code exists in order to check that
+ // the event is occurred in the same widget.
+ lastWinId = winId();
+ }
+ } else {
+ // this can no longer be a direction-changing accel.
+ // if any other key was pressed.
+ directionKeyEvent = Key_Space;
+ }
+
+ // Commentary in X11/keysymdef says that X codes match ASCII, so it
+ // is safe to use the locale functions to process X codes in ISO8859-1.
+ //
+ // This is mainly for compatibility - applications should not use the
+ // Qt keycodes between 128 and 255, but should rather use the
+ // QKeyEvent::text().
+ //
+ if ( key < 128 || (key < 256 && (!qt_input_mapper || qt_input_mapper->mibEnum()==4)) ) {
+ code = isprint((int)key) ? toupper((int)key) : 0; // upper-case key, if known
+ } else if ( key >= XK_F1 && key <= XK_F35 ) {
+ code = Key_F1 + ((int)key - XK_F1); // function keys
+ } else if ( key >= XK_KP_0 && key <= XK_KP_9) {
+ code = Key_0 + ((int)key - XK_KP_0); // numeric keypad keys
+ state |= Keypad;
+ } else {
+ int i = 0; // any other keys
+ while ( KeyTbl[i] ) {
+ if ( key == KeyTbl[i] ) {
+ code = (int)KeyTbl[i+1];
+ break;
+ }
+ i += 2;
+ }
+ switch ( key ) {
+ case XK_KP_Insert:
+ case XK_KP_Delete:
+ case XK_KP_Home:
+ case XK_KP_End:
+ case XK_KP_Left:
+ case XK_KP_Up:
+ case XK_KP_Right:
+ case XK_KP_Down:
+ case XK_KP_Prior:
+ case XK_KP_Next:
+ case XK_KP_Space:
+ case XK_KP_Tab:
+ case XK_KP_Enter:
+ case XK_KP_Equal:
+ case XK_KP_Multiply:
+ case XK_KP_Add:
+ case XK_KP_Separator:
+ case XK_KP_Subtract:
+ case XK_KP_Decimal:
+ case XK_KP_Divide:
+ state |= Keypad;
+ break;
+ default:
+ break;
+ }
+
+ if ( code == Key_Tab &&
+ (state & ShiftButton) == ShiftButton ) {
+ // map shift+tab to shift+backtab, QAccel knows about it
+ // and will handle it.
+ code = Key_Backtab;
+ chars[0] = 0;
+ }
+
+ if ( qt_use_rtl_extensions && type == QEvent::KeyPress && statefulTranslation ) {
+ if ( directionKeyEvent && lastWinId == winId() ) {
+ if ( key == XK_Shift_L && directionKeyEvent == XK_Control_L ||
+ key == XK_Control_L && directionKeyEvent == XK_Shift_L ) {
+ directionKeyEvent = Key_Direction_L;
+ } else if ( key == XK_Shift_R && directionKeyEvent == XK_Control_R ||
+ key == XK_Control_R && directionKeyEvent == XK_Shift_R ) {
+ directionKeyEvent = Key_Direction_R;
+ }
+ }
+ else if ( directionKeyEvent == Key_Direction_L || directionKeyEvent == Key_Direction_R ) {
+ directionKeyEvent = Key_Space; // invalid
+ }
+ }
+ }
+
+#if 0
+#ifndef Q_EE
+ static int c = 0;
+ extern void qt_dialog_default_key();
+#define Q_EE(x) c = (c == x || (!c && x == 0x1000) )? x+1 : 0
+ if ( tlw && state == '0' ) {
+ switch ( code ) {
+ case 0x4f: Q_EE(Key_Backtab); break;
+ case 0x52: Q_EE(Key_Tab); break;
+ case 0x54: Q_EE(Key_Escape); break;
+ case 0x4c:
+ if (c == Key_Return )
+ qt_dialog_default_key();
+ else
+ Q_EE(Key_Backspace);
+ break;
+ }
+ }
+#undef Q_EE
+#endif
+#endif
+
+ // convert chars (8bit) to text (unicode).
+ if ( mapper )
+ text = mapper->toUnicode(chars,count);
+ else if ( !mapper && converted.unicode() != 0x0 )
+ text = converted;
+ else
+ text = chars;
+ return TRUE;
+}
+
+
+struct qt_auto_repeat_data
+{
+ // match the window and keycode with timestamp delta of 10ms
+ Window window;
+ KeyCode keycode;
+ Time timestamp;
+
+ // queue scanner state
+ bool release;
+ bool error;
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static Bool qt_keypress_scanner(Display *, XEvent *event, XPointer arg)
+{
+ if (event->type != XKeyPress && event->type != XKeyRelease)
+ return FALSE;
+
+ qt_auto_repeat_data *d = (qt_auto_repeat_data *) arg;
+ if (d->error ||
+ event->xkey.window != d->window ||
+ event->xkey.keycode != d->keycode) {
+ d->error = TRUE;
+ return FALSE;
+ }
+
+ if (event->type == XKeyPress) {
+ d->error = (! d->release || event->xkey.time - d->timestamp > 10);
+ return (! d->error);
+ }
+
+ // must be XKeyRelease event
+ if (d->release) {
+ // found a second release
+ d->error = TRUE;
+ return FALSE;
+ }
+
+ // found a single release
+ d->release = TRUE;
+ d->timestamp = event->xkey.time;
+
+ return FALSE;
+}
+
+static Bool qt_keyrelease_scanner(Display *, XEvent *event, XPointer arg)
+{
+ const qt_auto_repeat_data *d = (const qt_auto_repeat_data *) arg;
+ return (event->type == XKeyRelease &&
+ event->xkey.window == d->window &&
+ event->xkey.keycode == d->keycode);
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+bool QETWidget::translateKeyEvent( const XEvent *event, bool grab )
+{
+ int code = -1;
+ int count = 0;
+ int state;
+ char ascii = 0;
+
+ if ( sm_blockUserInput ) // block user interaction during session management
+ return TRUE;
+
+ Display *dpy = x11Display();
+
+ if ( !isEnabled() )
+ return TRUE;
+
+ QEvent::Type type;
+ bool autor = FALSE;
+ QString text;
+
+ translateKeyEventInternal( event, count, text, state, ascii, code, type,
+ qt_mode_switch_remove_mask != 0 );
+
+ static uint curr_autorep = 0;
+ // was this the last auto-repeater?
+ qt_auto_repeat_data auto_repeat_data;
+ auto_repeat_data.window = event->xkey.window;
+ auto_repeat_data.keycode = event->xkey.keycode;
+ auto_repeat_data.timestamp = event->xkey.time;
+
+ if ( event->type == XKeyPress ) {
+ if ( curr_autorep == event->xkey.keycode ) {
+ autor = TRUE;
+ curr_autorep = 0;
+ }
+ } else {
+ // look ahead for auto-repeat
+ XEvent nextpress;
+
+ auto_repeat_data.release = TRUE;
+ auto_repeat_data.error = FALSE;
+ if (XCheckIfEvent(dpy, &nextpress, &qt_keypress_scanner,
+ (XPointer) &auto_repeat_data)) {
+ autor = TRUE;
+
+ // Put it back... we COULD send the event now and not need
+ // the static curr_autorep variable.
+ XPutBackEvent(dpy,&nextpress);
+ }
+ curr_autorep = autor ? event->xkey.keycode : 0;
+ }
+
+ // process accelerators before doing key compression
+ if ( type == QEvent::KeyPress && !grab ) {
+ // send accel events if the keyboard is not grabbed
+ QKeyEvent a( type, code, ascii, state, text, autor,
+ QMAX( QMAX(count,1), int(text.length())) );
+ if ( qt_tryAccelEvent( this, &a ) )
+ return TRUE;
+ }
+
+ long save = 0;
+ if ( qt_mode_switch_remove_mask != 0 ) {
+ save = qt_mode_switch_remove_mask;
+ qt_mode_switch_remove_mask = 0;
+
+ // translate the key event again, but this time apply any Mode_switch
+ // modifiers
+ translateKeyEventInternal( event, count, text, state, ascii, code, type );
+ }
+
+#ifndef QT_NO_IM
+ QInputContext *qic = getInputContext();
+#endif
+
+ // compress keys
+ if ( !text.isEmpty() && testWState(WState_CompressKeys) &&
+#ifndef QT_NO_IM
+ // Ordinary input methods require discrete key events to work
+ // properly, so key compression has to be disabled when input
+ // context exists.
+ //
+ // And further consideration, some complex input method
+ // require all key press/release events discretely even if
+ // the input method awares of key compression and compressed
+ // keys are ordinary alphabets. For example, the uim project
+ // is planning to implement "combinational shift" feature for
+ // a Japanese input method, uim-skk. It will work as follows.
+ //
+ // 1. press "r"
+ // 2. press "u"
+ // 3. release both "r" and "u" in arbitrary order
+ // 4. above key sequence generates "Ru"
+ //
+ // Of course further consideration about other participants
+ // such as key repeat mechanism is required to implement such
+ // feature.
+ ! qic &&
+#endif // QT_NO_IM
+ // do not compress keys if the key event we just got above matches
+ // one of the key ranges used to compute stopCompression
+ ! ( ( code >= Key_Escape && code <= Key_SysReq ) ||
+ ( code >= Key_Home && code <= Key_Next ) ||
+ ( code >= Key_Super_L && code <= Key_Direction_R ) ||
+ ( ( code == 0 ) && ( ascii == '\n' ) ) ) ) {
+ // the widget wants key compression so it gets it
+ int codeIntern = -1;
+ int countIntern = 0;
+ int stateIntern;
+ char asciiIntern = 0;
+ XEvent evRelease;
+ XEvent evPress;
+
+ // sync the event queue, this makes key compress work better
+ XSync( dpy, FALSE );
+
+ for (;;) {
+ QString textIntern;
+ if ( !XCheckTypedWindowEvent(dpy,event->xkey.window,
+ XKeyRelease,&evRelease) )
+ break;
+ if ( !XCheckTypedWindowEvent(dpy,event->xkey.window,
+ XKeyPress,&evPress) ) {
+ XPutBackEvent(dpy, &evRelease);
+ break;
+ }
+ QEvent::Type t;
+ translateKeyEventInternal( &evPress, countIntern, textIntern,
+ stateIntern, asciiIntern, codeIntern, t );
+ // use stopCompression to stop key compression for the following
+ // key event ranges:
+ bool stopCompression =
+ // 1) misc keys
+ ( codeIntern >= Key_Escape && codeIntern <= Key_SysReq ) ||
+ // 2) cursor movement
+ ( codeIntern >= Key_Home && codeIntern <= Key_Next ) ||
+ // 3) extra keys
+ ( codeIntern >= Key_Super_L && codeIntern <= Key_Direction_R ) ||
+ // 4) something that a) doesn't translate to text or b) translates
+ // to newline text
+ ((codeIntern == 0) && (asciiIntern == '\n'));
+ if (stateIntern == state && !textIntern.isEmpty() && !stopCompression) {
+ text += textIntern;
+ count += countIntern;
+ } else {
+ XPutBackEvent(dpy, &evPress);
+ XPutBackEvent(dpy, &evRelease);
+ break;
+ }
+ }
+ }
+
+ if ( save != 0 )
+ qt_mode_switch_remove_mask = save;
+
+ // autorepeat compression makes sense for all widgets (Windows
+ // does it automatically .... )
+ if ( event->type == XKeyPress && text.length() <= 1
+#ifndef QT_NO_IM
+ // input methods need discrete key events
+ && ! qic
+#endif// QT_NO_IM
+ ) {
+ XEvent dummy;
+
+ for (;;) {
+ auto_repeat_data.release = FALSE;
+ auto_repeat_data.error = FALSE;
+ if (! XCheckIfEvent(dpy, &dummy, &qt_keypress_scanner,
+ (XPointer) &auto_repeat_data))
+ break;
+ if (! XCheckIfEvent(dpy, &dummy, &qt_keyrelease_scanner,
+ (XPointer) &auto_repeat_data))
+ break;
+
+ count++;
+ if (!text.isEmpty())
+ text += text[0];
+ }
+ }
+
+ if (code == 0 && ascii == '\n') {
+ code = Key_Return;
+ ascii = '\r';
+ text = "\r";
+ }
+
+ // try the menukey first
+ if ( type == QEvent::KeyPress && code == Qt::Key_Menu ) {
+ QContextMenuEvent e( QContextMenuEvent::Keyboard, QPoint( 5, 5 ), mapToGlobal( QPoint( 5, 5 ) ), 0 );
+ QApplication::sendSpontaneousEvent( this, &e );
+ if( e.isAccepted() )
+ return TRUE;
+ }
+
+ QKeyEvent e( type, code, ascii, state, text, autor,
+ QMAX(QMAX(count,1), int(text.length())) );
+ return QApplication::sendSpontaneousEvent( this, &e );
+}
+
+
+//
+// Paint event translation
+//
+// When receiving many expose events, we compress them (union of all expose
+// rectangles) into one event which is sent to the widget.
+
+struct PaintEventInfo {
+ Window window;
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static Bool isPaintOrScrollDoneEvent( Display *, XEvent *ev, XPointer a )
+{
+ PaintEventInfo *info = (PaintEventInfo *)a;
+ if ( ev->type == Expose || ev->type == GraphicsExpose
+ || ev->type == ClientMessage
+ && ev->xclient.message_type == qt_qt_scrolldone )
+ {
+ if ( ev->xexpose.window == info->window )
+ return True;
+ }
+ return False;
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+
+// declared above: static QPtrList<QScrollInProgress> *sip_list = 0;
+
+void qt_insert_sip( QWidget* scrolled_widget, int dx, int dy )
+{
+ if ( !sip_list ) {
+ sip_list = new QPtrList<QScrollInProgress>;
+ sip_list->setAutoDelete( TRUE );
+ }
+
+ QScrollInProgress* sip = new QScrollInProgress( scrolled_widget, dx, dy );
+ sip_list->append( sip );
+
+ XClientMessageEvent client_message;
+ client_message.type = ClientMessage;
+ client_message.window = scrolled_widget->winId();
+ client_message.format = 32;
+ client_message.message_type = qt_qt_scrolldone;
+ client_message.data.l[0] = sip->id;
+
+ XSendEvent( appDpy, scrolled_widget->winId(), False, NoEventMask,
+ (XEvent*)&client_message );
+}
+
+int qt_sip_count( QWidget* scrolled_widget )
+{
+ if ( !sip_list )
+ return 0;
+
+ int sips=0;
+
+ for (QScrollInProgress* sip = sip_list->first();
+ sip; sip=sip_list->next())
+ {
+ if ( sip->scrolled_widget == scrolled_widget )
+ sips++;
+ }
+
+ return sips;
+}
+
+static
+bool translateBySips( QWidget* that, QRect& paintRect )
+{
+ if ( sip_list ) {
+ int dx=0, dy=0;
+ int sips=0;
+ for (QScrollInProgress* sip = sip_list->first();
+ sip; sip=sip_list->next())
+ {
+ if ( sip->scrolled_widget == that ) {
+ if ( sips ) {
+ dx += sip->dx;
+ dy += sip->dy;
+ }
+ sips++;
+ }
+ }
+ if ( sips > 1 ) {
+ paintRect.moveBy( dx, dy );
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool QETWidget::translatePaintEvent( const XEvent *event )
+{
+ setWState( WState_Exposed );
+ QRect paintRect( event->xexpose.x, event->xexpose.y,
+ event->xexpose.width, event->xexpose.height );
+ bool merging_okay = !testWFlags(WPaintClever);
+ XEvent xevent;
+ PaintEventInfo info;
+ info.window = winId();
+ bool should_clip = translateBySips( this, paintRect );
+
+ QRegion paintRegion( paintRect );
+
+ if ( merging_okay ) {
+ // WARNING: this is O(number_of_events * number_of_matching_events)
+ while ( XCheckIfEvent(x11Display(),&xevent,isPaintOrScrollDoneEvent,
+ (XPointer)&info) &&
+ !qt_x11EventFilter(&xevent) &&
+ !x11Event( &xevent ) ) // send event through filter
+ {
+ if ( xevent.type == Expose || xevent.type == GraphicsExpose ) {
+ QRect exposure(xevent.xexpose.x,
+ xevent.xexpose.y,
+ xevent.xexpose.width,
+ xevent.xexpose.height);
+ if ( translateBySips( this, exposure ) )
+ should_clip = TRUE;
+ paintRegion = paintRegion.unite( exposure );
+ } else {
+ translateScrollDoneEvent( &xevent );
+ }
+ }
+ }
+
+ if ( should_clip ) {
+ paintRegion = paintRegion.intersect( rect() );
+ if ( paintRegion.isEmpty() )
+ return TRUE;
+ }
+
+ QPaintEvent e( paintRegion );
+ setWState( WState_InPaintEvent );
+ if ( !isTopLevel() && backgroundOrigin() != WidgetOrigin )
+ erase( paintRegion );
+ qt_set_paintevent_clipping( this, paintRegion );
+ QApplication::sendSpontaneousEvent( this, &e );
+ qt_clear_paintevent_clipping();
+ clearWState( WState_InPaintEvent );
+ return TRUE;
+}
+
+//
+// Scroll-done event translation.
+//
+
+bool QETWidget::translateScrollDoneEvent( const XEvent *event )
+{
+ if ( !sip_list ) return FALSE;
+
+ long id = event->xclient.data.l[0];
+
+ // Remove any scroll-in-progress record for the given id.
+ for (QScrollInProgress* sip = sip_list->first(); sip; sip=sip_list->next()) {
+ if ( sip->id == id ) {
+ sip_list->remove( sip_list->current() );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+#ifndef QT_NO_XSYNC
+static Bool qt_net_wm_sync_request_scanner(Display*, XEvent* event, XPointer arg)
+{
+ return (event->type == ClientMessage && event->xclient.window == *(Window*)arg
+ && event->xclient.message_type == qt_wm_protocols
+ && event->xclient.data.l[ 0 ] == qt_net_wm_sync_request );
+}
+#endif
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+//
+// ConfigureNotify (window move and resize) event translation
+
+bool QETWidget::translateConfigEvent( const XEvent *event )
+{
+ // config pending is only set on resize, see qwidget_x11.cpp, internalSetGeometry()
+ bool was_resize = testWState( WState_ConfigPending );
+
+ clearWState(WState_ConfigPending);
+
+ if ( isTopLevel() ) {
+ QPoint newCPos( geometry().topLeft() );
+ QSize newSize( event->xconfigure.width, event->xconfigure.height );
+
+ bool trust = (topData()->parentWinId == None ||
+ topData()->parentWinId == QPaintDevice::x11AppRootWindow());
+
+ if (event->xconfigure.send_event || trust ) {
+ // if a ConfigureNotify comes from a real sendevent request, we can
+ // trust its values.
+ newCPos.rx() = event->xconfigure.x + event->xconfigure.border_width;
+ newCPos.ry() = event->xconfigure.y + event->xconfigure.border_width;
+ }
+
+ if ( isVisible() )
+ QApplication::syncX();
+
+ if (! extra || extra->compress_events) {
+ // ConfigureNotify compression for faster opaque resizing
+ XEvent otherEvent;
+ int compressed_configs = 0;
+ while ( XCheckTypedWindowEvent( x11Display(), winId(), ConfigureNotify,
+ &otherEvent ) ) {
+ if ( qt_x11EventFilter( &otherEvent ) )
+ continue;
+
+ if (x11Event( &otherEvent ) )
+ continue;
+
+ if ( otherEvent.xconfigure.event != otherEvent.xconfigure.window )
+ continue;
+
+ newSize.setWidth( otherEvent.xconfigure.width );
+ newSize.setHeight( otherEvent.xconfigure.height );
+
+ if ( otherEvent.xconfigure.send_event || trust ) {
+ newCPos.rx() = otherEvent.xconfigure.x +
+ otherEvent.xconfigure.border_width;
+ newCPos.ry() = otherEvent.xconfigure.y +
+ otherEvent.xconfigure.border_width;
+ }
+ ++compressed_configs;
+ }
+#ifndef QT_NO_XSYNC
+ // _NET_WM_SYNC_REQUEST compression
+ Window wid = winId();
+ while ( compressed_configs &&
+ XCheckIfEvent( x11Display(), &otherEvent,
+ qt_net_wm_sync_request_scanner, (XPointer)&wid ) ) {
+ handleSyncRequest( (void*)&otherEvent );
+ --compressed_configs;
+ }
+#endif
+ }
+
+ QRect cr ( geometry() );
+ if ( newSize != cr.size() ) { // size changed
+ was_resize = TRUE;
+ QSize oldSize = size();
+ cr.setSize( newSize );
+ crect = cr;
+
+ if ( isVisible() ) {
+ QResizeEvent e( newSize, oldSize );
+ QApplication::sendSpontaneousEvent( this, &e );
+ } else {
+ QResizeEvent * e = new QResizeEvent( newSize, oldSize );
+ QApplication::postEvent( this, e );
+ }
+ }
+
+ if ( newCPos != cr.topLeft() ) { // compare with cpos (exluding frame)
+ QPoint oldPos = geometry().topLeft();
+ cr.moveTopLeft( newCPos );
+ crect = cr;
+ if ( isVisible() ) {
+ QMoveEvent e( newCPos, oldPos ); // pos (including frame), not cpos
+ QApplication::sendSpontaneousEvent( this, &e );
+ } else {
+ QMoveEvent * e = new QMoveEvent( newCPos, oldPos );
+ QApplication::postEvent( this, e );
+ }
+ }
+ } else {
+ XEvent xevent;
+ while ( XCheckTypedWindowEvent(x11Display(),winId(), ConfigureNotify,&xevent) &&
+ !qt_x11EventFilter(&xevent) &&
+ !x11Event( &xevent ) ) // send event through filter
+ ;
+ }
+
+ bool transbg = backgroundOrigin() != WidgetOrigin;
+ // we ignore NorthWestGravity at the moment for reversed layout
+ if ( transbg ||
+ (!testWFlags( WStaticContents ) &&
+ testWState( WState_Exposed ) && was_resize ) ||
+ QApplication::reverseLayout() ) {
+ // remove unnecessary paint events from the queue
+ XEvent xevent;
+ while ( XCheckTypedWindowEvent( x11Display(), winId(), Expose, &xevent ) &&
+ ! qt_x11EventFilter( &xevent ) &&
+ ! x11Event( &xevent ) ) // send event through filter
+ ;
+ repaint( !testWFlags(WResizeNoErase) || transbg );
+ }
+
+ incrementSyncCounter();
+
+ return TRUE;
+}
+
+
+//
+// Close window event translation.
+//
+bool QETWidget::translateCloseEvent( const XEvent * )
+{
+ return close(FALSE);
+}
+
+
+/*!
+ Sets the text cursor's flash (blink) time to \a msecs
+ milliseconds. The flash time is the time required to display,
+ invert and restore the caret display. Usually the text cursor is
+ displayed for \a msecs/2 milliseconds, then hidden for \a msecs/2
+ milliseconds, but this may vary.
+
+ Note that on Microsoft Windows, calling this function sets the
+ cursor flash time for all windows.
+
+ \sa cursorFlashTime()
+*/
+void QApplication::setCursorFlashTime( int msecs )
+{
+ cursor_flash_time = msecs;
+}
+
+
+/*!
+ Returns the text cursor's flash (blink) time in milliseconds. The
+ flash time is the time required to display, invert and restore the
+ caret display.
+
+ The default value on X11 is 1000 milliseconds. On Windows, the
+ control panel value is used.
+
+ Widgets should not cache this value since it may be changed at any
+ time by the user changing the global desktop settings.
+
+ \sa setCursorFlashTime()
+*/
+int QApplication::cursorFlashTime()
+{
+ return cursor_flash_time;
+}
+
+/*!
+ Sets the time limit that distinguishes a double click from two
+ consecutive mouse clicks to \a ms milliseconds.
+
+ Note that on Microsoft Windows, calling this function sets the
+ double click interval for all windows.
+
+ \sa doubleClickInterval()
+*/
+
+void QApplication::setDoubleClickInterval( int ms )
+{
+ mouse_double_click_time = ms;
+}
+
+
+/*!
+ Returns the maximum duration for a double click.
+
+ The default value on X11 is 400 milliseconds. On Windows, the
+ control panel value is used.
+
+ \sa setDoubleClickInterval()
+*/
+
+int QApplication::doubleClickInterval()
+{
+ return mouse_double_click_time;
+}
+
+
+/*!
+ Sets the number of lines to scroll when the mouse wheel is rotated
+ to \a n.
+
+ If this number exceeds the number of visible lines in a certain
+ widget, the widget should interpret the scroll operation as a
+ single page up / page down operation instead.
+
+ \sa wheelScrollLines()
+*/
+void QApplication::setWheelScrollLines( int n )
+{
+ wheel_scroll_lines = n;
+}
+
+/*!
+ Returns the number of lines to scroll when the mouse wheel is
+ rotated.
+
+ \sa setWheelScrollLines()
+*/
+int QApplication::wheelScrollLines()
+{
+ return wheel_scroll_lines;
+}
+
+/*!
+ Enables the UI effect \a effect if \a enable is TRUE, otherwise
+ the effect will not be used.
+
+ Note: All effects are disabled on screens running at less than
+ 16-bit color depth.
+
+ \sa isEffectEnabled(), Qt::UIEffect, setDesktopSettingsAware()
+*/
+void QApplication::setEffectEnabled( Qt::UIEffect effect, bool enable )
+{
+ switch (effect) {
+ case UI_AnimateMenu:
+ if ( enable ) fade_menu = FALSE;
+ animate_menu = enable;
+ break;
+ case UI_FadeMenu:
+ if ( enable )
+ animate_menu = TRUE;
+ fade_menu = enable;
+ break;
+ case UI_AnimateCombo:
+ animate_combo = enable;
+ break;
+ case UI_AnimateTooltip:
+ if ( enable ) fade_tooltip = FALSE;
+ animate_tooltip = enable;
+ break;
+ case UI_FadeTooltip:
+ if ( enable )
+ animate_tooltip = TRUE;
+ fade_tooltip = enable;
+ break;
+ case UI_AnimateToolBox:
+ animate_toolbox = enable;
+ break;
+ default:
+ animate_ui = enable;
+ break;
+ }
+}
+
+/*!
+ Returns TRUE if \a effect is enabled; otherwise returns FALSE.
+
+ By default, Qt will try to use the desktop settings. Call
+ setDesktopSettingsAware(FALSE) to prevent this.
+
+ Note: All effects are disabled on screens running at less than
+ 16-bit color depth.
+
+ \sa setEffectEnabled(), Qt::UIEffect
+*/
+bool QApplication::isEffectEnabled( Qt::UIEffect effect )
+{
+ if ( QColor::numBitPlanes() < 16 || !animate_ui )
+ return FALSE;
+
+ switch( effect ) {
+ case UI_AnimateMenu:
+ return animate_menu;
+ case UI_FadeMenu:
+ return fade_menu;
+ case UI_AnimateCombo:
+ return animate_combo;
+ case UI_AnimateTooltip:
+ return animate_tooltip;
+ case UI_FadeTooltip:
+ return fade_tooltip;
+ case UI_AnimateToolBox:
+ return animate_toolbox;
+ default:
+ return animate_ui;
+ }
+}
+
+/*****************************************************************************
+ Session management support
+ *****************************************************************************/
+
+#ifndef QT_NO_SM_SUPPORT
+
+#include <X11/SM/SMlib.h>
+
+class QSessionManagerData
+{
+public:
+ QSessionManagerData( QSessionManager* mgr, QString& id, QString& key )
+ : sm( mgr ), sessionId( id ), sessionKey( key ) {}
+ QSessionManager* sm;
+ QStringList restartCommand;
+ QStringList discardCommand;
+ QString& sessionId;
+ QString& sessionKey;
+ QSessionManager::RestartHint restartHint;
+};
+
+class QSmSocketReceiver : public QObject
+{
+ Q_OBJECT
+public:
+ QSmSocketReceiver( int socket )
+ : QObject(0,0)
+ {
+ QSocketNotifier* sn = new QSocketNotifier( socket, QSocketNotifier::Read, this );
+ connect( sn, SIGNAL( activated(int) ), this, SLOT( socketActivated(int) ) );
+ }
+
+public slots:
+ void socketActivated(int);
+};
+
+
+static SmcConn smcConnection = 0;
+static bool sm_interactionActive;
+static bool sm_smActive;
+static int sm_interactStyle;
+static int sm_saveType;
+static bool sm_cancel;
+// static bool sm_waitingForPhase2; ### never used?!?
+static bool sm_waitingForInteraction;
+static bool sm_isshutdown;
+// static bool sm_shouldbefast; ### never used?!?
+static bool sm_phase2;
+static bool sm_in_phase2;
+
+static QSmSocketReceiver* sm_receiver = 0;
+
+static void resetSmState();
+static void sm_setProperty( const char* name, const char* type,
+ int num_vals, SmPropValue* vals);
+static void sm_saveYourselfCallback( SmcConn smcConn, SmPointer clientData,
+ int saveType, Bool shutdown , int interactStyle, Bool fast);
+static void sm_saveYourselfPhase2Callback( SmcConn smcConn, SmPointer clientData ) ;
+static void sm_dieCallback( SmcConn smcConn, SmPointer clientData ) ;
+static void sm_shutdownCancelledCallback( SmcConn smcConn, SmPointer clientData );
+static void sm_saveCompleteCallback( SmcConn smcConn, SmPointer clientData );
+static void sm_interactCallback( SmcConn smcConn, SmPointer clientData );
+static void sm_performSaveYourself( QSessionManagerData* );
+
+static void resetSmState()
+{
+// sm_waitingForPhase2 = FALSE; ### never used?!?
+ sm_waitingForInteraction = FALSE;
+ sm_interactionActive = FALSE;
+ sm_interactStyle = SmInteractStyleNone;
+ sm_smActive = FALSE;
+ sm_blockUserInput = FALSE;
+ sm_isshutdown = FALSE;
+// sm_shouldbefast = FALSE; ### never used?!?
+ sm_phase2 = FALSE;
+ sm_in_phase2 = FALSE;
+}
+
+
+// theoretically it's possible to set several properties at once. For
+// simplicity, however, we do just one property at a time
+static void sm_setProperty( const char* name, const char* type,
+ int num_vals, SmPropValue* vals)
+{
+ if (num_vals ) {
+ SmProp prop;
+ prop.name = (char*)name;
+ prop.type = (char*)type;
+ prop.num_vals = num_vals;
+ prop.vals = vals;
+
+ SmProp* props[1];
+ props[0] = &prop;
+ SmcSetProperties( smcConnection, 1, props );
+ }
+ else {
+ char* names[1];
+ names[0] = (char*) name;
+ SmcDeleteProperties( smcConnection, 1, names );
+ }
+}
+
+static void sm_setProperty( const QString& name, const QString& value)
+{
+ SmPropValue prop;
+ prop.length = value.length();
+ prop.value = (SmPointer) value.latin1();
+ sm_setProperty( name.latin1(), SmARRAY8, 1, &prop );
+}
+
+static void sm_setProperty( const QString& name, const QStringList& value)
+{
+ SmPropValue *prop = new SmPropValue[ value.count() ];
+ int count = 0;
+ for ( QStringList::ConstIterator it = value.begin(); it != value.end(); ++it ) {
+ prop[ count ].length = (*it).length();
+ prop[ count ].value = (char*)(*it).latin1();
+ ++count;
+ }
+ sm_setProperty( name.latin1(), SmLISTofARRAY8, count, prop );
+ delete [] prop;
+}
+
+
+// workaround for broken libsm, see below
+struct QT_smcConn {
+ unsigned int save_yourself_in_progress : 1;
+ unsigned int shutdown_in_progress : 1;
+};
+
+static void sm_saveYourselfCallback( SmcConn smcConn, SmPointer clientData,
+ int saveType, Bool shutdown , int interactStyle, Bool /*fast*/)
+{
+ if (smcConn != smcConnection )
+ return;
+ sm_cancel = FALSE;
+ sm_smActive = TRUE;
+ sm_isshutdown = shutdown;
+ sm_saveType = saveType;
+ sm_interactStyle = interactStyle;
+// sm_shouldbefast = fast; ### never used?!?
+
+ // ugly workaround for broken libSM. libSM should do that _before_
+ // actually invoking the callback in sm_process.c
+ ( (QT_smcConn*)smcConn )->save_yourself_in_progress = TRUE;
+ if ( sm_isshutdown )
+ ( (QT_smcConn*)smcConn )->shutdown_in_progress = TRUE;
+
+ sm_performSaveYourself( (QSessionManagerData*) clientData );
+ if ( !sm_isshutdown ) // we cannot expect a confirmation message in that case
+ resetSmState();
+}
+
+static void sm_performSaveYourself( QSessionManagerData* smd )
+{
+ if ( sm_isshutdown )
+ sm_blockUserInput = TRUE;
+
+ QSessionManager* sm = smd->sm;
+
+ // generate a new session key
+ timeval tv;
+ gettimeofday( &tv, 0 );
+ smd->sessionKey = QString::number( tv.tv_sec ) + "_" + QString::number(tv.tv_usec);
+
+ // tell the session manager about our program in best POSIX style
+ sm_setProperty( SmProgram, QString( qApp->argv()[0] ) );
+ // tell the session manager about our user as well.
+ struct passwd* entry = getpwuid( geteuid() );
+ if ( entry )
+ sm_setProperty( SmUserID, QString::fromLatin1( entry->pw_name ) );
+
+ // generate a restart and discard command that makes sense
+ QStringList restart;
+ restart << qApp->argv()[0] << "-session" << smd->sessionId + "_" + smd->sessionKey;
+ if (qstricmp(qAppName(), qAppClass()) != 0)
+ restart << "-name" << qAppName();
+ sm->setRestartCommand( restart );
+ QStringList discard;
+ sm->setDiscardCommand( discard );
+
+ switch ( sm_saveType ) {
+ case SmSaveBoth:
+ qApp->commitData( *sm );
+ if ( sm_isshutdown && sm_cancel)
+ break; // we cancelled the shutdown, no need to save state
+ // fall through
+ case SmSaveLocal:
+ qApp->saveState( *sm );
+ break;
+ case SmSaveGlobal:
+ qApp->commitData( *sm );
+ break;
+ default:
+ break;
+ }
+
+ if ( sm_phase2 && !sm_in_phase2 ) {
+ SmcRequestSaveYourselfPhase2( smcConnection, sm_saveYourselfPhase2Callback, (SmPointer*) smd );
+ sm_blockUserInput = FALSE;
+ }
+ else {
+ // close eventual interaction monitors and cancel the
+ // shutdown, if required. Note that we can only cancel when
+ // performing a shutdown, it does not work for checkpoints
+ if ( sm_interactionActive ) {
+ SmcInteractDone( smcConnection, sm_isshutdown && sm_cancel);
+ sm_interactionActive = FALSE;
+ }
+ else if ( sm_cancel && sm_isshutdown ) {
+ if ( sm->allowsErrorInteraction() ) {
+ SmcInteractDone( smcConnection, True );
+ sm_interactionActive = FALSE;
+ }
+ }
+
+ // set restart and discard command in session manager
+ sm_setProperty( SmRestartCommand, sm->restartCommand() );
+ sm_setProperty( SmDiscardCommand, sm->discardCommand() );
+
+ // set the restart hint
+ SmPropValue prop;
+ prop.length = sizeof( int );
+ int value = sm->restartHint();
+ prop.value = (SmPointer) &value;
+ sm_setProperty( SmRestartStyleHint, SmCARD8, 1, &prop );
+
+ // we are done
+ SmcSaveYourselfDone( smcConnection, !sm_cancel );
+ }
+}
+
+static void sm_dieCallback( SmcConn smcConn, SmPointer /* clientData */)
+{
+ if (smcConn != smcConnection )
+ return;
+ resetSmState();
+ QEvent quitEvent(QEvent::Quit);
+ QApplication::sendEvent(qApp, &quitEvent);
+}
+
+static void sm_shutdownCancelledCallback( SmcConn smcConn, SmPointer /* clientData */)
+{
+ if (smcConn != smcConnection )
+ return;
+ if ( sm_waitingForInteraction )
+ qApp->exit_loop();
+ resetSmState();
+}
+
+static void sm_saveCompleteCallback( SmcConn smcConn, SmPointer /*clientData */)
+{
+ if (smcConn != smcConnection )
+ return;
+ resetSmState();
+}
+
+static void sm_interactCallback( SmcConn smcConn, SmPointer /* clientData */ )
+{
+ if (smcConn != smcConnection )
+ return;
+ if ( sm_waitingForInteraction )
+ qApp->exit_loop();
+}
+
+static void sm_saveYourselfPhase2Callback( SmcConn smcConn, SmPointer clientData )
+{
+ if (smcConn != smcConnection )
+ return;
+ sm_in_phase2 = TRUE;
+ sm_performSaveYourself( (QSessionManagerData*) clientData );
+}
+
+
+void QSmSocketReceiver::socketActivated(int)
+{
+ IceProcessMessages( SmcGetIceConnection( smcConnection ), 0, 0);
+}
+
+
+#undef Bool
+#include "qapplication_x11.moc"
+
+QSessionManager::QSessionManager( QApplication * app, QString &id, QString& key )
+ : QObject( app, "session manager" )
+{
+ d = new QSessionManagerData( this, id, key );
+ d->restartHint = RestartIfRunning;
+
+ resetSmState();
+ char cerror[256];
+ char* myId = 0;
+ char* prevId = (char*)id.latin1(); // we know what we are doing
+
+ SmcCallbacks cb;
+ cb.save_yourself.callback = sm_saveYourselfCallback;
+ cb.save_yourself.client_data = (SmPointer) d;
+ cb.die.callback = sm_dieCallback;
+ cb.die.client_data = (SmPointer) d;
+ cb.save_complete.callback = sm_saveCompleteCallback;
+ cb.save_complete.client_data = (SmPointer) d;
+ cb.shutdown_cancelled.callback = sm_shutdownCancelledCallback;
+ cb.shutdown_cancelled.client_data = (SmPointer) d;
+
+ // avoid showing a warning message below
+ const char* session_manager = getenv("SESSION_MANAGER");
+ if ( !session_manager || !session_manager[0] )
+ return;
+
+ smcConnection = SmcOpenConnection( 0, 0, 1, 0,
+ SmcSaveYourselfProcMask |
+ SmcDieProcMask |
+ SmcSaveCompleteProcMask |
+ SmcShutdownCancelledProcMask,
+ &cb,
+ prevId,
+ &myId,
+ 256, cerror );
+
+ id = QString::fromLatin1( myId );
+ ::free( myId ); // it was allocated by C
+
+ QString error = cerror;
+ if (!smcConnection ) {
+ qWarning("Session management error: %s", error.latin1() );
+ }
+ else {
+ sm_receiver = new QSmSocketReceiver( IceConnectionNumber( SmcGetIceConnection( smcConnection ) ) );
+ }
+}
+
+QSessionManager::~QSessionManager()
+{
+ if ( smcConnection )
+ SmcCloseConnection( smcConnection, 0, 0 );
+ smcConnection = 0;
+ delete sm_receiver;
+ delete d;
+}
+
+QString QSessionManager::sessionId() const
+{
+ return d->sessionId;
+}
+
+QString QSessionManager::sessionKey() const
+{
+ return d->sessionKey;
+}
+
+
+void* QSessionManager::handle() const
+{
+ return (void*) smcConnection;
+}
+
+
+bool QSessionManager::allowsInteraction()
+{
+ if ( sm_interactionActive )
+ return TRUE;
+
+ if ( sm_waitingForInteraction )
+ return FALSE;
+
+ if ( sm_interactStyle == SmInteractStyleAny ) {
+ sm_waitingForInteraction = SmcInteractRequest( smcConnection, SmDialogNormal,
+ sm_interactCallback, (SmPointer*) this );
+ }
+ if ( sm_waitingForInteraction ) {
+ qApp->enter_loop();
+ sm_waitingForInteraction = FALSE;
+ if ( sm_smActive ) { // not cancelled
+ sm_interactionActive = TRUE;
+ sm_blockUserInput = FALSE;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool QSessionManager::allowsErrorInteraction()
+{
+ if ( sm_interactionActive )
+ return TRUE;
+
+ if ( sm_waitingForInteraction )
+ return FALSE;
+
+ if ( sm_interactStyle == SmInteractStyleAny || sm_interactStyle == SmInteractStyleErrors ) {
+ sm_waitingForInteraction = SmcInteractRequest( smcConnection, SmDialogError,
+ sm_interactCallback, (SmPointer*) this );
+ }
+ if ( sm_waitingForInteraction ) {
+ qApp->enter_loop();
+ sm_waitingForInteraction = FALSE;
+ if ( sm_smActive ) { // not cancelled
+ sm_interactionActive = TRUE;
+ sm_blockUserInput = FALSE;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void QSessionManager::release()
+{
+ if ( sm_interactionActive ) {
+ SmcInteractDone( smcConnection, False );
+ sm_interactionActive = FALSE;
+ if ( sm_smActive && sm_isshutdown )
+ sm_blockUserInput = TRUE;
+ }
+}
+
+void QSessionManager::cancel()
+{
+ sm_cancel = TRUE;
+}
+
+void QSessionManager::setRestartHint( QSessionManager::RestartHint hint)
+{
+ d->restartHint = hint;
+}
+
+QSessionManager::RestartHint QSessionManager::restartHint() const
+{
+ return d->restartHint;
+}
+
+void QSessionManager::setRestartCommand( const QStringList& command)
+{
+ d->restartCommand = command;
+}
+
+QStringList QSessionManager::restartCommand() const
+{
+ return d->restartCommand;
+}
+
+void QSessionManager::setDiscardCommand( const QStringList& command)
+{
+ d->discardCommand = command;
+}
+
+QStringList QSessionManager::discardCommand() const
+{
+ return d->discardCommand;
+}
+
+void QSessionManager::setManagerProperty( const QString& name, const QString& value)
+{
+ SmPropValue prop;
+ prop.length = value.length();
+ prop.value = (SmPointer) value.utf8().data();
+ sm_setProperty( name.latin1(), SmARRAY8, 1, &prop );
+}
+
+void QSessionManager::setManagerProperty( const QString& name, const QStringList& value)
+{
+ SmPropValue *prop = new SmPropValue[ value.count() ];
+ int count = 0;
+ for ( QStringList::ConstIterator it = value.begin(); it != value.end(); ++it ) {
+ prop[ count ].length = (*it).length();
+ prop[ count ].value = (char*)(*it).utf8().data();
+ ++count;
+ }
+ sm_setProperty( name.latin1(), SmLISTofARRAY8, count, prop );
+ delete [] prop;
+}
+
+bool QSessionManager::isPhase2() const
+{
+ return sm_in_phase2;
+}
+
+void QSessionManager::requestPhase2()
+{
+ sm_phase2 = TRUE;
+}
+
+
+#endif // QT_NO_SM_SUPPORT