diff options
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqapplication_x11.cpp')
-rw-r--r-- | tqtinterface/qt4/src/kernel/tqapplication_x11.cpp | 754 |
1 files changed, 482 insertions, 272 deletions
diff --git a/tqtinterface/qt4/src/kernel/tqapplication_x11.cpp b/tqtinterface/qt4/src/kernel/tqapplication_x11.cpp index 48616bf..e7cf92f 100644 --- a/tqtinterface/qt4/src/kernel/tqapplication_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqapplication_x11.cpp @@ -92,7 +92,9 @@ #include "tqfileinfo.h" // Input method stuff - UNFINISHED -#include "tqinputcontext_p.h" +#ifndef TQT_NO_IM +#include "tqinputcontext.h" +#endif // TQT_NO_IM #include "tqinternal_p.h" // shared double buffer cleanup #if defined(TQT_THREAD_SUPPORT) @@ -114,6 +116,7 @@ extern "C" Bool XftInitFtLibrary(void); #include <string.h> #include <ctype.h> #include <locale.h> +#include <cstdlib> //#define X_NOT_BROKEN #ifdef X_NOT_BROKEN @@ -271,10 +274,16 @@ 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; @@ -284,6 +293,11 @@ Atom *qt_net_supported_list = 0; Window *qt_net_virtual_root_list = 0; +// X11 SYNC support +#ifndef TQT_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; @@ -308,6 +322,13 @@ static int xrandr_eventbase; // Display TQ_EXPORT bool qt_use_xrender = FALSE; +#ifndef TQT_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; @@ -1709,17 +1730,28 @@ void qt_init_internal( int *argcptr, char **argv, 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 TQT_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(); @@ -1756,6 +1788,15 @@ void qt_init_internal( int *argcptr, char **argv, } #endif // TQT_NO_XRENDER +#ifndef TQT_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 TQT_NO_XKB // If XKB is detected, set the GrabsUseXKBState option so input method // compositions continue to work (ie. deadkeys) @@ -2731,10 +2772,9 @@ static const char *appBTNCol = 0; // application btn color static const char *mwGeometry = 0; // main widget tqgeometry static const char *mwTitle = 0; // main widget title //Ming-Che 10/10 -static char *ximServer = 0; // XIM Server will connect to +char *qt_ximServer = 0; // XIM Server will connect to static bool mwIconic = FALSE; // main widget iconified //Ming-Che 10/10 -static bool noxim = FALSE; // connect to xim or not static Display *appDpy = 0; // X11 application display static char *appDpyName = 0; // X11 display name static bool appForeignDpy = FALSE; // we didn't create display @@ -2933,14 +2973,14 @@ static bool qt_x11EventFilter( XEvent* ev ) #if !defined(TQT_NO_XIM) -XIM qt_xim = 0; +//XIM qt_xim = 0; XIMStyle qt_xim_style = 0; +XIMStyle qt_xim_preferred_style = 0; static XIMStyle xim_default_style = XIMPreeditCallbacks | XIMStatusNothing; -static XIMStyle xim_preferred_style = 0; #endif -static int composingKeycode=0; -static TQTextCodec * input_mapper = 0; +int qt_ximComposingKeycode=0; +TQTextCodec * qt_input_mapper = 0; extern bool qt_check_clipboard_sentinel(); //def in qclipboard_x11.cpp extern bool qt_check_selection_sentinel(); //def in qclipboard_x11.cpp @@ -3051,8 +3091,7 @@ public: void setWFlags( WFlags f ) { TQWidget::setWFlags(f); } void clearWFlags( WFlags f ) { TQWidget::clearWFlags(f); } bool translateMouseEvent( const XEvent * ); - bool translateKeyEventInternal( const XEvent *, int& count, TQString& text, int& state, char& ascii, int &code, - TQEvent::Type &type, bool willRepeat=FALSE ); + bool translateKeyEventInternal( const XEvent *, int& count, TQString& text, int& state, char& ascii, int &code, TQEvent::Type &type, bool willRepeat=FALSE, bool statefulTranslation=TRUE ); bool translateKeyEvent( const XEvent *, bool grab ); bool translatePaintEvent( const XEvent * ); bool translateConfigEvent( const XEvent * ); @@ -3069,114 +3108,120 @@ public: // ************************************************************************ -// X Input Method support +// Input Method support // ************************************************************************ -#if !defined(TQT_NO_XIM) +/*! + An identifier name of the default input method. +*/ +TQString TQApplication::defaultIM = "imsw-multi"; -#if defined(TQ_C_CALLBACKS) -extern "C" { -#endif // TQ_C_CALLBACKS -#ifdef USE_X11R6_XIM - static void xim_create_callback(XIM /*im*/, - XPointer /*client_data*/, - XPointer /*call_data*/) - { - // qDebug("xim_create_callback"); - TQApplication::create_xim(); - } +/*! + This function handles the query about location of the widget + holding the TQInputContext instance for widget \a w. - static void xim_destroy_callback(XIM /*im*/, - XPointer /*client_data*/, - XPointer /*call_data*/) - { - // qDebug("xim_destroy_callback"); - TQApplication::close_xim(); - XRegisterIMInstantiateCallback(appDpy, 0, 0, 0, - (XIMProc) xim_create_callback, 0); - } + The input context is used for text input to widget \a w. By + default, it returns the top-level widget of \a w. -#endif // USE_X11R6_XIM + If you want to change the mapping of widget \w to TQInputContext + instance, reimplement both this function and + TQApplication::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. -#if defined(TQ_C_CALLBACKS) + See also 'Sharing input context between text widgets' and 'Preedit + preservation' section of the class description of TQInputContext. + + \sa TQInputContext, icHolderWidgets() +*/ +TQWidget *TQApplication::locateICHolderWidget( TQWidget *w ) +{ + return w->tqtopLevelWidget(); } -#endif // TQ_C_CALLBACKS -#endif // TQT_NO_XIM +/*! + This function returns all widgets holding TQInputContext. -/*! \internal - Creates the application input method. - */ -void TQApplication::create_xim() + By default, This function returns top-level widgets. So if you + want to change the mapping of a widget to TQInputContext instance, + you must override this function and locateICHolderWidget(). + + \sa locateICHolderWidget() +*/ +TQWidgetList *TQApplication::icHolderWidgets() { -#ifndef TQT_NO_XIM - qt_xim = XOpenIM( appDpy, 0, 0, 0 ); - if ( qt_xim ) { + return TQApplication::tqtopLevelWidgets(); +} -#ifdef USE_X11R6_XIM - XIMCallback destroy; - destroy.callback = (XIMProc) xim_destroy_callback; - destroy.client_data = 0; - if ( XSetIMValues( qt_xim, XNDestroyCallback, &destroy, (char *) 0 ) != 0 ) - qWarning( "Xlib dosn't support destroy callback"); -#endif // USE_X11R6_XIM - XIMStyles *styles = 0; - XGetIMValues(qt_xim, XNQueryInputStyle, &styles, (char *) 0, (char *) 0); - if ( styles ) { - int i; - for ( i = 0; !qt_xim_style && i < styles->count_styles; i++ ) { - if ( styles->supported_styles[i] == xim_preferred_style ) { - qt_xim_style = xim_preferred_style; - break; - } - } - // if the preferred input style couldn't be found, look for - // Nothing - for ( i = 0; !qt_xim_style && i < styles->count_styles; i++ ) { - if ( styles->supported_styles[i] == (XIMPreeditNothing | - XIMStatusNothing) ) { - qt_xim_style = XIMPreeditNothing | XIMStatusNothing; - break; - } - } - // ... and failing that, None. - for ( i = 0; !qt_xim_style && i < styles->count_styles; i++ ) { - if ( styles->supported_styles[i] == (XIMPreeditNone | - XIMStatusNone) ) { - qt_xim_style = XIMPreeditNone | XIMStatusNone; - break; - } - } +/*! + This function replaces all TQInputContext instances in the + application. The function's argument is the identifier name of + the newly selected input method. +*/ +void TQApplication::changeAllInputContext( const TQString &identifierName ) +{ + TQWidgetList *list = tqApp->icHolderWidgets(); + TQWidgetListIt it(*list); + while(it.current()) { + it.current()->changeInputContext( identifierName ); + ++it; + } + delete list; - // qDebug("TQApplication: using im style %lx", qt_xim_style); - XFree( (char *)styles ); - } + // defaultIM = identifierName ; // Change of defaultIM -- default input method -- may be enabled. +} - if ( qt_xim_style ) { -#ifdef USE_X11R6_XIM - XUnregisterIMInstantiateCallback(appDpy, 0, 0, 0, - (XIMProc) xim_create_callback, 0); -#endif // USE_X11R6_XIM +/*! + \internal + This is an internal function, you should never call this. - TQWidgetList *list= tqApp->tqtopLevelWidgets(); - TQWidgetListIt it(*list); - TQWidget * w; - while( (w=it.current()) != 0 ) { - ++it; - w->createTLSysExtra(); - } - delete list; - } else { - // Give up - qWarning( "No supported input style found." - " See InputMethod documentation."); - close_xim(); - } + \sa TQInputContext::imEventGenerated() +*/ +void TQApplication::postIMEvent( TQObject *receiver, TQIMEvent *event ) +{ + if ( event->type() == TQEvent::IMCompose ) { + // enable event compression to reduce preedit flicker on fast + // typing + postEvent( receiver, event ); + } else { + // cancel queued preedit update + if ( event->type() == TQEvent::IMEnd ) + removePostedEvents( receiver, TQEvent::IMCompose ); + + // to avoid event receiving order inversion between TQKeyEvent + // and TQIMEvent, 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 + TQApplication::defaultIM. +*/ +TQString TQApplication::defaultInputMethod() +{ + return TQApplication::defaultIM; +} + + +#if !defined(TQT_NO_IM_EXTENSIONS) +/*! \internal + Creates the application input method. +*/ +void TQApplication::create_im() +{ +#ifndef TQT_NO_XIM + if ( ! qt_xim_preferred_style ) // no configured input style, use the default + qt_xim_preferred_style = xim_default_style; #endif // TQT_NO_XIM } @@ -3184,6 +3229,43 @@ void TQApplication::create_xim() /*! \internal Closes the application input method. */ +void TQApplication::close_im() +{ + TQWidgetList *list = tqApp->icHolderWidgets(); + TQWidgetListIt it(*list); + while(it.current()) { + it.current()->destroyInputContext(); + ++it; + } + delete list; +} + +#else + +/*! \internal + Creates the application input method. +*/ +void TQApplication::create_xim() +{ +#ifndef TQT_NO_XIM + if ( ! qt_xim_preferred_style ) // no configured input style, use the default + qt_xim_preferred_style = xim_default_style; +#endif // TQT_NO_XIM + + TQWidgetList *list= tqApp->tqtopLevelWidgets(); + TQWidgetListIt it(*list); + TQWidget * w; + while( (w=it.current()) != 0 ) { + ++it; + w->createTLSysExtra(); + } + delete list; +} + + + /*! \internal + Closes the application input method. + */ void TQApplication::close_xim() { #ifndef TQT_NO_XIM @@ -3191,7 +3273,10 @@ void TQApplication::close_xim() // XCloseIM( qt_xim ); // We prefer a less serious memory leak - qt_xim = 0; + // if ( qt_xim ) + // qt_xim = 0; + +#endif // TQT_NO_XIM TQWidgetList *list = tqApp->tqtopLevelWidgets(); TQWidgetListIt it(*list); while(it.current()) { @@ -3199,9 +3284,8 @@ void TQApplication::close_xim() ++it; } delete list; -#endif // TQT_NO_XIM } - +#endif /***************************************************************************** Default X error handlers @@ -3572,18 +3656,40 @@ bool TQApplication::x11_apply_settings() settings.readBoolEntry("/qt/useRtlExtensions", FALSE); #ifndef TQT_NO_XIM - if (xim_preferred_style == 0) { + if (qt_xim_preferred_style == 0) { TQString ximInputStyle = settings.readEntry( "/qt/XIMInputStyle", TQObject::trUtf8( "On The Spot" ) ).lower(); if ( ximInputStyle == "on the spot" ) - xim_preferred_style = XIMPreeditCallbacks | XIMStatusNothing; + qt_xim_preferred_style = XIMPreeditCallbacks | XIMStatusNothing; else if ( ximInputStyle == "over the spot" ) - xim_preferred_style = XIMPreeditPosition | XIMStatusNothing; + qt_xim_preferred_style = XIMPreeditPosition | XIMStatusNothing; else if ( ximInputStyle == "off the spot" ) - xim_preferred_style = XIMPreeditArea | XIMStatusArea; + qt_xim_preferred_style = XIMPreeditArea | XIMStatusArea; else if ( ximInputStyle == "root" ) - xim_preferred_style = XIMPreeditNothing | XIMStatusNothing; + qt_xim_preferred_style = XIMPreeditNothing | XIMStatusNothing; + } +#endif + +#ifndef TQT_NO_IM + /* + The identifier name of an input method is acquired from the + configuration file as a default. If a environment variable + "TQT_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( "TQT_IM_SWITCHER" ) ) + defaultIM = getenv( "TQT_IM_SWITCHER" ); +#ifndef TQT_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 @@ -3619,19 +3725,19 @@ static void qt_set_input_encoding() // 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. - input_mapper = TQTextCodec::codecForLocale(); + qt_input_mapper = TQTextCodec::codecForLocale(); } else { if ( !qstricmp( data, "locale" ) ) - input_mapper = TQTextCodec::codecForLocale(); + qt_input_mapper = TQTextCodec::codecForLocale(); else - input_mapper = TQTextCodec::codecForName( data ); + qt_input_mapper = TQTextCodec::codecForName( data ); // make sure we have an input codec - if( !input_mapper ) - input_mapper = TQTextCodec::codecForName( "ISO 8859-1" ); + if( !qt_input_mapper ) + qt_input_mapper = TQTextCodec::codecForName( "ISO 8859-1" ); } - if ( input_mapper->mibEnum() == 11 ) // 8859-8 - input_mapper = TQTextCodec::codecForName( "ISO 8859-8-I"); + if ( qt_input_mapper->mibEnum() == 11 ) // 8859-8 + qt_input_mapper = TQTextCodec::codecForName( "ISO 8859-8-I"); if( data ) XFree( (char *)data ); } @@ -4071,6 +4177,8 @@ static Visual *tqfind_truecolor_visual( Display *dpy, int scr, int *depth, int * #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 @@ -4161,10 +4269,7 @@ void qt_init_internal( int *argcptr, char **argv, //Ming-Che 10/10 } else if ( arg == "-im" ) { if ( ++i < argc ) - ximServer = argv[i]; - } else if ( arg == "-noxim" ) { - noxim=TRUE; - // + qt_ximServer = argv[i]; } else if ( arg == "-iconic" ) { mwIconic = !mwIconic; } else if ( arg == "-ncols" ) { // xv and netscape use this name @@ -4184,17 +4289,17 @@ void qt_init_internal( int *argcptr, char **argv, if ( ++i < argc ) { TQCString s = TQCString(argv[i]).lower(); if ( s == "onthespot" ) - xim_preferred_style = XIMPreeditCallbacks | - XIMStatusNothing; + qt_xim_preferred_style = XIMPreeditCallbacks | + XIMStatusNothing; else if ( s == "overthespot" ) - xim_preferred_style = XIMPreeditPosition | - XIMStatusNothing; + qt_xim_preferred_style = XIMPreeditPosition | + XIMStatusNothing; else if ( s == "offthespot" ) - xim_preferred_style = XIMPreeditArea | - XIMStatusArea; + qt_xim_preferred_style = XIMPreeditArea | + XIMStatusArea; else if ( s == "root" ) - xim_preferred_style = XIMPreeditNothing | - XIMStatusNothing; + qt_xim_preferred_style = XIMPreeditNothing | + XIMStatusNothing; } #endif } else if ( arg == "-cmap" ) { // xv uses this name @@ -4642,34 +4747,13 @@ void qt_init_internal( int *argcptr, char **argv, TQApplication::setFont( f ); } -#ifndef TQT_NO_XIM - if ( ! xim_preferred_style ) // no configured input style, use the default - xim_preferred_style = xim_default_style; - - qt_xim = 0; - TQString ximServerName(ximServer); - if (ximServer) - ximServerName.prepend("@im="); - else - ximServerName = ""; - - if ( !XSupportsLocale() ) - qWarning("TQt: Locales not supported on X server"); - -#ifdef USE_X11R6_XIM - else if ( XSetLocaleModifiers (ximServerName.ascii()) == 0 ) - qWarning( "TQt: Cannot set locale modifiers: %s", - ximServerName.ascii()); - else if (! noxim) - XRegisterIMInstantiateCallback(appDpy, 0, 0, 0, - (XIMProc) xim_create_callback, 0); -#else // !USE_X11R6_XIM - else if ( XSetLocaleModifiers ("") == 0 ) - qWarning("TQt: Cannot set locale modifiers"); - else if (! noxim) - TQApplication::create_xim(); -#endif // USE_X11R6_XIM -#endif // TQT_NO_XIM +#if !defined(TQT_NO_IM) +#if !defined(TQT_NO_IM_EXTENSIONS) + TQApplication::create_im(); +#else + TQApplication::create_xim(); +#endif +#endif #if defined (TQT_TABLET_SUPPORT) int ndev, @@ -4918,9 +5002,12 @@ void qt_cleanup() XCloseDevice( appDpy, devEraser ); #endif -#if !defined(TQT_NO_XIM) - if ( qt_xim ) - TQApplication::close_xim(); +#if !defined(TQT_NO_IM) +#if !defined(TQT_NO_IM_EXTENSIONS) + TQApplication::close_im(); +#else + TQApplication::close_xim(); +#endif #endif if ( qt_is_gui_used ) { @@ -5673,6 +5760,10 @@ int TQApplication::x11ClientMessage(TQWidget* w, XEvent* event, bool passive_onl XSendEvent( event->xclient.display, event->xclient.window, False, SubstructureNotifyMask|SubstructureRedirectMask, event ); } +#ifndef TQT_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); @@ -5779,77 +5870,59 @@ int TQApplication::x11ProcessEvent( XEvent* event ) } } - int xkey_keycode = event->xkey.keycode; - if ( XFilterEvent( event, - keywidget ? keywidget->tqtopLevelWidget()->winId() : None ) ) { - if ( keywidget ) - composingKeycode = xkey_keycode; // ### not documented in xlib +#ifndef TQT_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 TQT_NO_XIM - if ( event->type != XKeyPress || ! (qt_xim_style & XIMPreeditCallbacks) ) - return 1; - - /* - * The Solaris htt input method will transform a ClientMessage - * event into a filtered KeyPress event, in which case our - * keywidget is still zero. - */ - if ( ! keywidget ) { - keywidget = (TQETWidget*)TQWidget::keyboardGrabber(); - if ( keywidget ) { - grabbed = TRUE; - } else { - if ( focus_widget ) - keywidget = (TQETWidget*)focus_widget; - if ( !keywidget ) { - if ( inPopupMode() ) // no focus widget, see if we have a popup - keywidget = (TQETWidget*) activePopupWidget(); - else if ( widget ) - keywidget = (TQETWidget*)widget->tqtopLevelWidget(); - } - } - } - - /* - if the composition string has been emptied, we need to send - an IMEnd event. however, we have no way to tell if the user - has cancelled input, or if the user has accepted the - composition. - - so, we have to look for the next keypress and see if it is - the 'commit' key press (keycode == 0). if it is, we deliver - an IMEnd event with the final text, otherwise we deliver an - IMEnd with empty text (meaning the user has cancelled the - input). - */ - TQInputContext *qic = - (TQInputContext *) keywidget->tqtopLevelWidget()->topData()->xic; - extern bool qt_compose_emptied; // qinputcontext_x11.cpp - if ( qic && qic->composing && qic->tqfocusWidget && qt_compose_emptied ) { - XEvent event2; - bool found = FALSE; - if ( XCheckTypedEvent( TQPaintDevice::x11AppDisplay(), - XKeyPress, &event2 ) ) { - if ( event2.xkey.keycode == 0 ) { - // found a key event with the 'commit' string - found = TRUE; - XPutBackEvent( TQPaintDevice::x11AppDisplay(), &event2 ); - } - } - - if ( !found ) { - // no key event, so the user must have cancelled the composition - TQIMEvent endevent( TQEvent::IMEnd, TQString::null, -1 ); - TQApplication::sendEvent( qic->tqfocusWidget, &endevent ); +// #ifndef TQT_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; - qic->tqfocusWidget = 0; - } + // for XIM handling + TQInputContext *qic = keywidget->getInputContext(); + if( qic && qic->x11FilterEvent( keywidget, event ) ) + return TRUE; - qt_compose_emptied = FALSE; + // filterEvent() accepts TQEvent *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 + // TQWheelEvent, TQTabletEvent 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; + TQEvent::Type type; + TQString 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. + TQKeyEvent keyevent( type, code, ascii, state, text, FALSE, count ); + + if( qic && qic->filterEvent( &keyevent ) ) + return TRUE; } -#endif // TQT_NO_XIM - - return 1; + } else +#endif // TQT_NO_IM + { + if ( XFilterEvent( event, None ) ) + return TRUE; } if ( qt_x11EventFilter(event) ) // send through app filter @@ -5946,7 +6019,8 @@ int TQApplication::x11ProcessEvent( XEvent* event ) #endif #ifndef TQT_NO_XRANDR - if (event->type == xrandr_eventbase + RRScreenChangeNotify) { + if (event->type == xrandr_eventbase + RRScreenChangeNotify + || ( event->type == ConfigureNotify && event->xconfigure.window == TQPaintDevice::x11AppRootWindow())) { // update Xlib internals with the latest screen configuration XRRUpdateConfiguration(event); @@ -6000,34 +6074,8 @@ int TQApplication::x11ProcessEvent( XEvent* event ) case XKeyRelease: { if ( keywidget && keywidget->isEnabled() ) { // should always exist -#ifndef TQT_NO_XIM - TQInputContext *qic = - (TQInputContext *) keywidget->tqtopLevelWidget()->topData()->xic; - - if ((qt_xim_style & XIMPreeditCallbacks) && event->xkey.keycode == 0 && - qic && qic->composing && qic->tqfocusWidget) { - // input method has sent us a commit string - TQCString data(513); - KeySym sym; // unused - Status status; // unused - TQString text; - int count = qic->lookupString( &(event->xkey), data, - &sym, &status ); - if ( count > 0 ) - text = input_mapper->toUnicode( data, count ); - - // qDebug( "sending IMEnd with %d chars", text.length() ); - TQIMEvent endevent( TQEvent::IMEnd, text, -1 ); - TQApplication::sendEvent( qic->tqfocusWidget, &endevent ); - - qic->tqfocusWidget = 0; - qic->text = TQString::null; - } else -#endif // !TQT_NO_XIM - { - // qDebug( "sending key event" ); - keywidget->translateKeyEvent( event, grabbed ); - } + // qDebug( "sending key event" ); + keywidget->translateKeyEvent( event, grabbed ); } break; } @@ -6514,7 +6562,7 @@ void TQApplication::closePopup( TQWidget *popup ) // Keyboard event translation // -static int translateButtonState( int s ) +int qt_x11_translateButtonState( int s ) { int bst = 0; if ( s & Button1Mask ) @@ -6580,7 +6628,7 @@ bool TQETWidget::translateMouseEvent( const XEvent *event ) pos.ry() = lastMotion.y; globalPos.rx() = lastMotion.x_root; globalPos.ry() = lastMotion.y_root; - state = translateButtonState( lastMotion.state ); + state = qt_x11_translateButtonState( lastMotion.state ); if ( qt_button_down && (state & (LeftButton | MidButton | RightButton ) ) == 0 ) @@ -6604,7 +6652,7 @@ bool TQETWidget::translateMouseEvent( const XEvent *event ) pos.ry() = xevent->xcrossing.y; globalPos.rx() = xevent->xcrossing.x_root; globalPos.ry() = xevent->xcrossing.y_root; - state = translateButtonState( xevent->xcrossing.state ); + state = qt_x11_translateButtonState( xevent->xcrossing.state ); if ( qt_button_down && (state & (LeftButton | MidButton | RightButton ) ) == 0 ) @@ -6616,7 +6664,7 @@ bool TQETWidget::translateMouseEvent( const XEvent *event ) pos.ry() = event->xbutton.y; globalPos.rx() = event->xbutton.x_root; globalPos.ry() = event->xbutton.y_root; - state = translateButtonState( event->xbutton.state ); + state = qt_x11_translateButtonState( event->xbutton.state ); switch ( event->xbutton.button ) { case Button1: button = LeftButton; break; case Button2: button = MidButton; break; @@ -7322,6 +7370,92 @@ static const KeySym KeyTbl[] = { // keyboard mapping table 0x1005FF10, TQt::Key_F11, // hardcoded Sun F36 (labeled F11) 0x1005FF11, TQt::Key_F12, // hardcoded Sun F37 (labeled F12) + // International input method support keys + + // International & multi-key character composition + XK_Multi_key, TQt::Key_Multi_key, + XK_Codeinput, TQt::Key_Codeinput, + XK_SingleCandidate, TQt::Key_SingleCandidate, + XK_MultipleCandidate, TQt::Key_MultipleCandidate, + XK_PreviousCandidate, TQt::Key_PreviousCandidate, + + // Misc Functions + XK_Mode_switch, TQt::Key_Mode_switch, + //XK_script_switch, TQt::Key_script_switch, + XK_script_switch, TQt::Key_Mode_switch, + + // Japanese keyboard support + XK_Kanji, TQt::Key_Kanji, + XK_Muhenkan, TQt::Key_Muhenkan, + //XK_Henkan_Mode, TQt::Key_Henkan_Mode, + XK_Henkan_Mode, TQt::Key_Henkan, + XK_Henkan, TQt::Key_Henkan, + XK_Romaji, TQt::Key_Romaji, + XK_Hiragana, TQt::Key_Hiragana, + XK_Katakana, TQt::Key_Katakana, + XK_Hiragana_Katakana, TQt::Key_Hiragana_Katakana, + XK_Zenkaku, TQt::Key_Zenkaku, + XK_Hankaku, TQt::Key_Hankaku, + XK_Zenkaku_Hankaku, TQt::Key_Zenkaku_Hankaku, + XK_Touroku, TQt::Key_Touroku, + XK_Massyo, TQt::Key_Massyo, + XK_Kana_Lock, TQt::Key_Kana_Lock, + XK_Kana_Shift, TQt::Key_Kana_Shift, + XK_Eisu_Shift, TQt::Key_Eisu_Shift, + XK_Eisu_toggle, TQt::Key_Eisu_toggle, + //XK_Kanji_Bangou, TQt::Key_Kanji_Bangou, + //XK_Zen_Koho, TQt::Key_Zen_Koho, + //XK_Mae_Koho, TQt::Key_Mae_Koho, + XK_Kanji_Bangou, TQt::Key_Codeinput, + XK_Zen_Koho, TQt::Key_MultipleCandidate, + XK_Mae_Koho, TQt::Key_PreviousCandidate, + +#ifdef XK_KOREAN + // Korean keyboard support + XK_Hangul, TQt::Key_Hangul, + XK_Hangul_Start, TQt::Key_Hangul_Start, + XK_Hangul_End, TQt::Key_Hangul_End, + XK_Hangul_Hanja, TQt::Key_Hangul_Hanja, + XK_Hangul_Jamo, TQt::Key_Hangul_Jamo, + XK_Hangul_Romaja, TQt::Key_Hangul_Romaja, + //XK_Hangul_Codeinput, TQt::Key_Hangul_Codeinput, + XK_Hangul_Codeinput, TQt::Key_Codeinput, + XK_Hangul_Jeonja, TQt::Key_Hangul_Jeonja, + XK_Hangul_Banja, TQt::Key_Hangul_Banja, + XK_Hangul_PreHanja, TQt::Key_Hangul_PreHanja, + XK_Hangul_PostHanja, TQt::Key_Hangul_PostHanja, + //XK_Hangul_SingleCandidate, TQt::Key_Hangul_SingleCandidate, + //XK_Hangul_MultipleCandidate, TQt::Key_Hangul_MultipleCandidate, + //XK_Hangul_PreviousCandidate, TQt::Key_Hangul_PreviousCandidate, + XK_Hangul_SingleCandidate, TQt::Key_SingleCandidate, + XK_Hangul_MultipleCandidate, TQt::Key_MultipleCandidate, + XK_Hangul_PreviousCandidate, TQt::Key_PreviousCandidate, + XK_Hangul_Special, TQt::Key_Hangul_Special, + //XK_Hangul_switch, TQt::Key_Hangul_switch, + XK_Hangul_switch, TQt::Key_Mode_switch, +#endif // XK_KOREAN + + // dead keys + XK_dead_grave, TQt::Key_Dead_Grave, + XK_dead_acute, TQt::Key_Dead_Acute, + XK_dead_circumflex, TQt::Key_Dead_Circumflex, + XK_dead_tilde, TQt::Key_Dead_Tilde, + XK_dead_macron, TQt::Key_Dead_Macron, + XK_dead_breve, TQt::Key_Dead_Breve, + XK_dead_abovedot, TQt::Key_Dead_Abovedot, + XK_dead_diaeresis, TQt::Key_Dead_Diaeresis, + XK_dead_abovering, TQt::Key_Dead_Abovering, + XK_dead_doubleacute, TQt::Key_Dead_Doubleacute, + XK_dead_caron, TQt::Key_Dead_Caron, + XK_dead_cedilla, TQt::Key_Dead_Cedilla, + XK_dead_ogonek, TQt::Key_Dead_Ogonek, + XK_dead_iota, TQt::Key_Dead_Iota, + XK_dead_voiced_sound, TQt::Key_Dead_Voiced_Sound, + XK_dead_semivoiced_sound, TQt::Key_Dead_Semivoiced_Sound, + XK_dead_belowdot, TQt::Key_Dead_Belowdot, + XK_dead_hook, TQt::Key_Dead_Hook, + XK_dead_horn, TQt::Key_Dead_Horn, + // Special multimedia keys // currently only tested with MS internet keyboard @@ -7539,9 +7673,9 @@ static TQChar keysymToUnicode(unsigned char byte3, unsigned char byte4) bool TQETWidget::translateKeyEventInternal( const XEvent *event, int& count, TQString& text, int& state, - char& ascii, int& code, TQEvent::Type &type, bool willRepeat ) + char& ascii, int& code, TQEvent::Type &type, bool willRepeat, bool statefulTranslation ) { - TQTextCodec *mapper = input_mapper; + TQTextCodec *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 @@ -7562,7 +7696,7 @@ bool TQETWidget::translateKeyEventInternal( const XEvent *event, int& count, XKeyEvent xkeyevent = event->xkey; // save the modifier state, we will use the keystate uint later by passing - // it to translateButtonState + // 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 @@ -7588,6 +7722,11 @@ bool TQETWidget::translateKeyEventInternal( const XEvent *event, int& count, if ( type == TQEvent::KeyPress ) { bool mb=FALSE; + // commit string handling is done by + // TQXIMInputContext::x11FilterEvent() and are passed to + // widgets via TQIMEvent regardless of XIM style, so the + // following code is commented out. +#if 0 if ( qt_xim ) { TQTLWExtra* xd = tlw->topData(); TQInputContext *qic = (TQInputContext *) xd->xic; @@ -7596,13 +7735,14 @@ bool TQETWidget::translateKeyEventInternal( const XEvent *event, int& count, count = qic->lookupString(&xkeyevent, chars, &key, &status); } } +#endif if ( !mb ) { count = XLookupString( &xkeyevent, chars.data(), chars.size(), &key, 0 ); } if ( count && !keycode ) { - keycode = composingKeycode; - composingKeycode = 0; + keycode = qt_ximComposingKeycode; + qt_ximComposingKeycode = 0; } if ( key ) keyDict->tqreplace( keycode, (void*)key ); @@ -7666,28 +7806,32 @@ bool TQETWidget::translateKeyEventInternal( const XEvent *event, int& count, } else { key = (int)(long)keyDict->tqfind( keycode ); if ( key ) - if( !willRepeat ) // Take out key of dictionary only if this call. + if( !willRepeat && statefulTranslation ) // Take out key of dictionary only if this call. keyDict->take( keycode ); long s = (long)textDict->tqfind( keycode ); if ( s ) { - textDict->take( keycode ); + if( statefulTranslation ) + textDict->take( keycode ); ascii = (char)(s-256); } } #endif // !TQT_NO_XIM - state = translateButtonState( keystate ); + state = qt_x11_translateButtonState( keystate ); static int directionKeyEvent = 0; - if ( qt_use_rtl_extensions && type == TQEvent::KeyRelease ) { + static unsigned int lastWinId = 0; + if ( qt_use_rtl_extensions && type == TQEvent::KeyRelease && statefulTranslation ) { if (directionKeyEvent == Key_Direction_R || directionKeyEvent == Key_Direction_L ) { type = TQEvent::KeyPress; code = directionKeyEvent; chars[0] = 0; directionKeyEvent = 0; + lastWinId = 0; return TRUE; } else { directionKeyEvent = 0; + lastWinId = 0; } } @@ -7697,10 +7841,14 @@ bool TQETWidget::translateKeyEventInternal( const XEvent *event, int& count, // (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 == TQEvent::KeyPress) + if ( qt_use_rtl_extensions && type == TQEvent::KeyPress && statefulTranslation ) if (key == XK_Control_L || key == XK_Control_R || key == XK_Shift_L || key == XK_Shift_R) { - if (!directionKeyEvent) + 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. @@ -7714,7 +7862,7 @@ bool TQETWidget::translateKeyEventInternal( const XEvent *event, int& count, // TQt keycodes between 128 and 255, but should rather use the // TQKeyEvent::text(). // - if ( key < 128 || (key < 256 && (!input_mapper || input_mapper->mibEnum()==4)) ) { + 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 @@ -7765,8 +7913,8 @@ bool TQETWidget::translateKeyEventInternal( const XEvent *event, int& count, chars[0] = 0; } - if ( qt_use_rtl_extensions && type == TQEvent::KeyPress ) { - if ( directionKeyEvent ) { + if ( qt_use_rtl_extensions && type == TQEvent::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; @@ -7838,8 +7986,10 @@ static Bool qt_keypress_scanner(Display *, XEvent *event, XPointer arg) qt_auto_repeat_data *d = (qt_auto_repeat_data *) arg; if (d->error || event->xkey.window != d->window || - event->xkey.keycode != d->keycode) + event->xkey.keycode != d->keycode) { + d->error = TRUE; return FALSE; + } if (event->type == XKeyPress) { d->error = (! d->release || event->xkey.time - d->timestamp > 10); @@ -7942,8 +8092,34 @@ bool TQETWidget::translateKeyEvent( const XEvent *event, bool grab ) translateKeyEventInternal( event, count, text, state, ascii, code, type ); } +#ifndef TQT_NO_IM + TQInputContext *qic = getInputContext(); +#endif + // compress keys if ( !text.isEmpty() && testWState(WState_CompressKeys) && +#ifndef TQT_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 // TQT_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 ) || @@ -8002,7 +8178,12 @@ bool TQETWidget::translateKeyEvent( const XEvent *event, bool grab ) // autorepeat compression makes sense for all widgets (Windows // does it automatically .... ) - if ( event->type == XKeyPress && text.length() <= 1 ) { + if ( event->type == XKeyPress && text.length() <= 1 +#ifndef TQT_NO_IM + // input methods need discrete key events + && ! qic +#endif// TQT_NO_IM + ) { XEvent dummy; for (;;) { @@ -8210,6 +8391,21 @@ bool TQETWidget::translateScrollDoneEvent( const XEvent *event ) return FALSE; } +#if defined(TQ_C_CALLBACKS) +extern "C" { +#endif +#ifndef TQT_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(TQ_C_CALLBACKS) +} +#endif // // ConfigureNotify (window move and resize) event translation @@ -8241,6 +8437,7 @@ bool TQETWidget::translateConfigEvent( const XEvent *event ) 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 ) ) @@ -8261,7 +8458,18 @@ bool TQETWidget::translateConfigEvent( const XEvent *event ) newCPos.ry() = otherEvent.xconfigure.y + otherEvent.xconfigure.border_width; } + ++compressed_configs; } +#ifndef TQT_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 } TQRect cr ( tqgeometry() ); @@ -8315,6 +8523,8 @@ bool TQETWidget::translateConfigEvent( const XEvent *event ) tqrepaint( !testWFlags(WResizeNoErase) || transbg ); } + incrementSyncCounter(); + return TRUE; } |