diff options
Diffstat (limited to 'tqtinterface/qt4/src/kernel')
25 files changed, 2901 insertions, 1072 deletions
diff --git a/tqtinterface/qt4/src/kernel/qt_kernel.pri b/tqtinterface/qt4/src/kernel/qt_kernel.pri index aa76de0..f10ed74 100644 --- a/tqtinterface/qt4/src/kernel/qt_kernel.pri +++ b/tqtinterface/qt4/src/kernel/qt_kernel.pri @@ -34,7 +34,6 @@ kernel { $$KERNEL_H/tqimage.h \ $$KERNEL_P/tqimageformatinterface_p.h \ $$KERNEL_H/tqimageformatplugin.h \ - $$KERNEL_P/tqinputcontext_p.h \ $$KERNEL_H/tqkeycode.h \ $$KERNEL_H/tqkeysequence.h \ $$KERNEL_H/tqlayout.h \ @@ -99,6 +98,12 @@ kernel { $$KERNEL_CPP/tqfontengine_p.h \ $$KERNEL_CPP/tqtextlayout_p.h + unix:x11 { + HEADERS += $$KERNEL_H/tqinputcontext.h + } else { + HEADERS += $$KERNEL_P/tqinputcontext_p.h + } + win32:SOURCES += $$KERNEL_CPP/tqapplication_win.cpp \ $$KERNEL_CPP/tqclipboard_win.cpp \ $$KERNEL_CPP/tqcolor_win.cpp \ @@ -130,6 +135,7 @@ kernel { $$KERNEL_CPP/tqdesktopwidget_x11.cpp \ $$KERNEL_CPP/tqeventloop_x11.cpp \ $$KERNEL_CPP/tqfont_x11.cpp \ + $$KERNEL_CPP/tqinputcontext.cpp \ $$KERNEL_CPP/tqinputcontext_x11.cpp \ $$KERNEL_CPP/tqmotifdnd_x11.cpp \ $$KERNEL_CPP/tqpixmap_x11.cpp \ diff --git a/tqtinterface/qt4/src/kernel/tqapplication.cpp b/tqtinterface/qt4/src/kernel/tqapplication.cpp index af193c9..74d2f08 100644 --- a/tqtinterface/qt4/src/kernel/tqapplication.cpp +++ b/tqtinterface/qt4/src/kernel/tqapplication.cpp @@ -4113,6 +4113,35 @@ void TQApplication::postEvent( TQObject *receiver, TQEvent *event ) }; } +#if !defined(TQT_NO_IM) + // if this is one of the compressible IM events, do compression + else if ( event->type() == TQEvent::IMCompose ) { + l->last(); + TQPostEvent * cur = 0; + for ( ;; ) { + while ( (cur=l->current()) != 0 && + ( cur->receiver != receiver || + cur->event == 0 || + cur->event->type() != event->type() || + cur->event->type() != TQEvent::IMStart ) ) + l->prev(); + if ( l->current() != 0 ) { + // IMCompose must not be compressed with another one + // beyond its IMStart boundary + if ( cur->event->type() == TQEvent::IMStart ) { + break; + } else if ( cur->event->type() == TQEvent::IMCompose ) { + TQIMComposeEvent * e = (TQIMComposeEvent *)(cur->event); + *e = *(TQIMComposeEvent *)event; + delete event; + return; + } + } + break; + }; + } +#endif + // if no compression could be done, just append something event->posted = TRUE; TQPostEvent * pe = new TQPostEvent( receiver, event ); @@ -4259,6 +4288,23 @@ void TQApplication::sendPostedEvents( TQObject *receiver, int event_type ) void TQApplication::removePostedEvents( TQObject *receiver ) { + removePostedEvents( receiver, 0 ); +} + +/*! + Removes all events that have the event type \a event_type posted + using postEvent() for \a receiver. + + The events are \e not dispatched, instead they are removed from the + queue. + + If \a event_type is 0, all the events are removed from the queue. + + \threadsafe +*/ + +void TQApplication::removePostedEvents( TQObject *receiver, int event_type ) +{ if ( !receiver ) return; @@ -4277,18 +4323,24 @@ void TQApplication::removePostedEvents( TQObject *receiver ) // leave the TQPostEvent objects; they'll be deleted by // sendPostedEvents(). TQPostEventList * l = receiver->postedEvents; - receiver->postedEvents = 0; l->first(); TQPostEvent * pe; while( (pe=l->current()) != 0 ) { - if ( pe->event ) { - pe->event->posted = FALSE; - delete pe->event; - pe->event = 0; + if ( !event_type || pe->event->type() == event_type ) { + if ( pe->event ) { + pe->event->posted = FALSE; + delete pe->event; + pe->event = 0; + } + l->remove(); + } else { + l->next(); } - l->remove(); } - delete l; + if ( !event_type || !l->count() ) { + receiver->postedEvents = 0; + delete l; + } } @@ -4473,6 +4525,8 @@ void TQApplication::setActiveWindow( TQWidget* act ) focus_widget = 0; #ifdef TQ_WS_WIN TQInputContext::accept( tmp ); +#elif defined(TQ_WS_X11) + tmp->unfocusInputContext(); #endif TQApplication::sendSpontaneousEvent( tmp, &out ); } else if ( active_window ) { diff --git a/tqtinterface/qt4/src/kernel/tqapplication.h b/tqtinterface/qt4/src/kernel/tqapplication.h index 2be7c02..e5e2ea9 100644 --- a/tqtinterface/qt4/src/kernel/tqapplication.h +++ b/tqtinterface/qt4/src/kernel/tqapplication.h @@ -67,6 +67,9 @@ class TQSessionManager; class TQStyle; class TQTranslator; class TQEventLoop; +#if defined(TQ_WS_X11) +class TQIMEvent; +#endif #if defined(TQ_WS_TQWS) class TQWSDecoration; #endif @@ -467,8 +470,19 @@ public: virtual void saveState( TQSessionManager& sm ); #endif #if defined(TQ_WS_X11) +#if !defined(TQT_NO_IM_EXTENSIONS) + virtual TQWidget *locateICHolderWidget( TQWidget *w ); + virtual TQWidgetList *icHolderWidgets(); + static void create_im(); + static void close_im(); +#else + TQWidget *locateICHolderWidget( TQWidget *w ); + TQWidgetList *icHolderWidgets(); static void create_xim(); static void close_xim(); +#endif + static TQString defaultInputMethod(); + void changeAllInputContext( const TQString & ); static bool x11_apply_settings(); #endif void wakeUpGuiThread(); @@ -523,6 +537,12 @@ private: friend void qt_init(int *, char **, TQApplication::Type); #endif +#if defined(TQ_WS_X11) +private slots: + void postIMEvent( TQObject *receiver, TQIMEvent *event ); +#endif + +private: #ifdef TQT_THREAD_SUPPORT static TQMutex *qt_mutex; #endif // TQT_THREAD_SUPPORT @@ -572,9 +592,12 @@ private: static TQString* session_key; bool is_session_restored; #endif -#if defined(TQ_WS_X11) && !defined (TQT_NO_STYLE ) +#if defined(TQ_WS_X11) +#if !defined (TQT_NO_STYLE) static void x11_initialize_style(); #endif + static TQString defaultIM; // default input method's name in this application. +#endif static TQSize app_strut; #ifndef TQT_NO_COMPONENT @@ -591,6 +614,7 @@ private: static bool sendSpontaneousEvent( TQObject *receiver, TQEvent *event ); static void removePostedEvent( TQEvent * ); + static void removePostedEvents( TQObject *receiver, int event_type ); friend class TQWidget; friend class TQETWidget; 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; } diff --git a/tqtinterface/qt4/src/kernel/tqclipboard_x11.cpp b/tqtinterface/qt4/src/kernel/tqclipboard_x11.cpp index 14e7f08..9fd90e4 100644 --- a/tqtinterface/qt4/src/kernel/tqclipboard_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqclipboard_x11.cpp @@ -111,6 +111,7 @@ static int pending_timer_id = 0; static bool pending_clipboard_changed = FALSE; static bool pending_selection_changed = FALSE; +TQ_EXPORT bool qt_qclipboard_bailout_hack = false; // event capture mechanism for qt_xclb_wait_for_event static bool waiting_for_data = FALSE; @@ -142,6 +143,15 @@ static Bool checkForClipboardEvents(Display *, XEvent *e, XPointer) || e->xselectionclear.selection == qt_xa_clipboard))); } +static bool selection_request_pending = false; + +static Bool check_selection_request_pending( Display*, XEvent* e, XPointer ) + { + if( e->type == SelectionRequest && e->xselectionrequest.owner == owner->winId()) + selection_request_pending = true; + return False; + } + bool qt_xclb_wait_for_event( Display *dpy, Window win, int type, XEvent *event, int timeout ) { @@ -193,6 +203,14 @@ bool qt_xclb_wait_for_event( Display *dpy, Window win, int type, XEvent *event, do { if ( XCheckTypedWindowEvent(dpy,win,type,event) ) return TRUE; + if( qt_qclipboard_bailout_hack ) { + XEvent dummy; + selection_request_pending = false; + if ( owner != NULL ) + XCheckIfEvent(dpy,&dummy,check_selection_request_pending,NULL); + if( selection_request_pending ) + return TRUE; + } // process other clipboard events, since someone is probably requesting data from us XEvent e; diff --git a/tqtinterface/qt4/src/kernel/tqdesktopwidget_x11.cpp b/tqtinterface/qt4/src/kernel/tqdesktopwidget_x11.cpp index e2bd9f9..84da179 100644 --- a/tqtinterface/qt4/src/kernel/tqdesktopwidget_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqdesktopwidget_x11.cpp @@ -111,7 +111,7 @@ TQDesktopWidgetPrivate::~TQDesktopWidgetPrivate() screens[i] = 0; } - delete [] screens; + free(screens); } if ( rects ) delete [] rects; @@ -121,6 +121,8 @@ TQDesktopWidgetPrivate::~TQDesktopWidgetPrivate() void TQDesktopWidgetPrivate::init() { // get the screen count + int newScreenCount; + #ifndef TQT_NO_XINERAMA XineramaScreenInfo *xinerama_screeninfo = 0; int unused; @@ -130,23 +132,26 @@ void TQDesktopWidgetPrivate::init() if (use_xinerama) { xinerama_screeninfo = - XineramaQueryScreens(TQPaintDevice::x11AppDisplay(), &screenCount); + XineramaQueryScreens(TQPaintDevice::x11AppDisplay(), &newScreenCount); + + if (xinerama_screeninfo) defaultScreen = 0; } else #endif // TQT_NO_XINERAMA { defaultScreen = DefaultScreen(TQPaintDevice::x11AppDisplay()); - screenCount = ScreenCount(TQPaintDevice::x11AppDisplay()); + newScreenCount = ScreenCount(TQPaintDevice::x11AppDisplay()); + use_xinerama = false; } delete [] rects; - rects = new TQRect[ screenCount ]; + rects = new TQRect[ newScreenCount ]; delete [] workareas; - workareas = new TQRect[ screenCount ]; + workareas = new TQRect[ newScreenCount ]; // get the tqgeometry of each screen - int i, x, y, w, h; - for ( i = 0; i < screenCount; i++ ) { + int i, j, x, y, w, h; + for ( i = 0, j = 0; i < newScreenCount; i++ ) { #ifndef TQT_NO_XINERAMA if (use_xinerama) { @@ -163,11 +168,33 @@ void TQDesktopWidgetPrivate::init() h = HeightOfScreen(ScreenOfDisplay(TQPaintDevice::x11AppDisplay(), i)); } - rects[i].setRect(x, y, w, h); workareas[i] = TQRect(); + rects[j].setRect(x, y, w, h); + + // overlapping? + if (j > 0 && rects[j-1].intersects(rects[j])) { + // pick the bigger one, ignore the other + if ((rects[j].width()*rects[j].height()) > + (rects[j-1].width()*rects[j-1].height())) + rects[j-1] = rects[j]; + } + else + j++; } + if (screens) { + // leaks TQWidget* pointers on purpose, can't delete them as pointer escapes + screens = (TQWidget**) realloc(screens, j * sizeof(TQWidget*)); + if (j > screenCount) + memset(&screens[screenCount], 0, (j-screenCount) * sizeof(TQWidget*)); + } + + screenCount = j; + #ifndef TQT_NO_XINERAMA + if (use_xinerama && screenCount == 1) + use_xinerama = false; + if (xinerama_screeninfo) XFree(xinerama_screeninfo); #endif // TQT_NO_XINERAMA @@ -220,8 +247,7 @@ TQWidget *TQDesktopWidget::screen( int screen ) screen = d->defaultScreen; if ( ! d->screens ) { - d->screens = new TQWidget*[ d->screenCount ]; - memset( d->screens, 0, d->screenCount * sizeof( TQWidget * ) ); + d->screens = (TQWidget**) calloc( d->screenCount, sizeof(TQWidget*)); d->screens[ d->defaultScreen ] = this; } diff --git a/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp b/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp index 7882349..3ba66b9 100644 --- a/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqdnd_x11.cpp @@ -52,13 +52,15 @@ #include "tqdragobject.h" #include "tqobjectlist.h" #include "tqcursor.h" +#include "tqbitmap.h" +#include "tqpainter.h" #include "tqt_x11_p.h" // conflict resolution -// unused, may be used again later: const int XKeyPress = KeyPress; -// unused, may be used again later: const int XKeyRelease = KeyRelease; +const int XKeyPress = KeyPress; +const int XKeyRelease = KeyRelease; #undef KeyPress #undef KeyRelease @@ -114,6 +116,8 @@ Atom qt_xdnd_finished; Atom qt_xdnd_type_list; const int qt_xdnd_version = 4; +extern int qt_x11_translateButtonState( int s ); + // Actions // // The Xdnd spec allows for user-defined actions. This could be implemented @@ -199,6 +203,8 @@ static Time qt_xdnd_target_current_time; static int qt_xdnd_current_screen = -1; // state of dragging... true if dragging, false if not bool qt_xdnd_dragging = FALSE; +// need to check state of keyboard modifiers +static bool need_modifiers_check = FALSE; // dict of payload data, sorted by type atom static TQIntDict<TQByteArray> * qt_xdnd_target_data = 0; @@ -257,21 +263,49 @@ class TQShapedPixmapWidget : public TQWidget { public: TQShapedPixmapWidget(int screen = -1) : TQWidget(TQApplication::desktop()->screen( screen ), - 0, (Qt::WindowType)(WStyle_Customize | WStyle_Tool | WStyle_NoBorder | WX11BypassWM) ) + 0, (Qt::WindowType)(WStyle_Customize | WStyle_Tool | WStyle_NoBorder | WX11BypassWM) ), oldpmser( 0 ), oldbmser( 0 ) { + x11SetWindowType( X11WindowTypeDND ); } - void setPixmap(TQPixmap pm) + void setPixmap(TQPixmap pm, TQPoint hot) { - const TQBitmap* mask = pm.tqmask(); - if ( mask ) { + int bmser = pm.tqmask() ? pm.tqmask()->serialNumber() : 0; + if( oldpmser == pm.serialNumber() && oldbmser == bmser + && oldhot == hot ) + return; + oldpmser = pm.serialNumber(); + oldbmser = bmser; + oldhot = hot; + bool hotspot_in = !(hot.x() < 0 || hot.y() < 0 || hot.x() >= pm.width() || hot.y() >= pm.height()); +// if the pixmap has hotspot in its area, make a "hole" in it at that position +// this will allow XTranslateCoordinates() to find directly the window below the cursor instead +// of finding this pixmap, and therefore there won't be needed any (slow) search for the window +// using findRealWindow() + if( hotspot_in ) { + TQBitmap tqmask = pm.tqmask() ? *pm.tqmask() : TQBitmap( pm.width(), pm.height()); + if( !pm.tqmask()) + tqmask.fill( TQt::color1 ); + TQPainter p( &tqmask ); + p.setPen( TQt::color0 ); + p.drawPoint( hot.x(), hot.y()); + p.end(); + pm.setMask( tqmask ); + setMask( tqmask ); + } else if ( pm.tqmask() ) { setMask( *mask ); } else { clearMask(); } resize(pm.width(),pm.height()); setErasePixmap(pm); + erase(); } + +private: + int oldpmser; + int oldbmser; + TQPoint oldhot; }; static TQShapedPixmapWidget * qt_xdnd_deco = 0; @@ -875,8 +909,59 @@ void qt_handle_xdnd_finished( TQWidget *, const XEvent * xe, bool passive ) void TQDragManager::timerEvent( TQTimerEvent* e ) { - if ( e->timerId() == heartbeat && qt_xdnd_source_sameanswer.isNull() ) - move( TQCursor::pos() ); + if ( e->timerId() == heartbeat ) { + if( need_modifiers_check ) { + Window root, child; + int root_x, root_y, win_x, win_y; + unsigned int tqmask; + XQueryPointer( qt_xdisplay(), qt_xrootwin( qt_xdnd_current_screen ), + &root, &child, &root_x, &root_y, &win_x, &win_y, &tqmask ); + if( updateMode( (ButtonState)qt_x11_translateButtonState( tqmask ))) + qt_xdnd_source_sameanswer = TQRect(); // force move + } + need_modifiers_check = TRUE; + if( qt_xdnd_source_sameanswer.isNull() ) + move( TQCursor::pos() ); + } +} + +static bool qt_xdnd_was_move = false; +static bool qt_xdnd_found = false; +// check whole incoming X queue for move events +// checking whole queue is done by always returning False in the predicate +// if there's another move event in the queue, and there's not a mouse button +// or keyboard or ClientMessage event before it, the current move event +// may be safely discarded +// this helps avoiding being overloaded by being flooded from many events +// from the XServer +static +Bool qt_xdnd_predicate( Display*, XEvent* ev, XPointer ) +{ + if( qt_xdnd_found ) + return False; + if( ev->type == MotionNotify ) + { + qt_xdnd_was_move = true; + qt_xdnd_found = true; + } + if( ev->type == ButtonPress || ev->type == ButtonRelease + || ev->type == XKeyPress || ev->type == XKeyRelease + || ev->type == ClientMessage ) + { + qt_xdnd_was_move = false; + qt_xdnd_found = true; + } + return False; +} + +static +bool qt_xdnd_another_movement() +{ + qt_xdnd_was_move = false; + qt_xdnd_found = false; + XEvent dummy; + XCheckIfEvent( qt_xdisplay(), &dummy, qt_xdnd_predicate, NULL ); + return qt_xdnd_was_move; } bool TQDragManager::eventFilter( TQObject * o, TQEvent * e) @@ -901,8 +986,11 @@ bool TQDragManager::eventFilter( TQObject * o, TQEvent * e) if ( e->type() == TQEvent::MouseMove ) { TQMouseEvent* me = (TQMouseEvent *)e; - updateMode(me->stateAfter()); - move( me->globalPos() ); + if( !qt_xdnd_another_movement()) { + updateMode(me->stateAfter()); + move( me->globalPos() ); + } + need_modifiers_check = FALSE; return TRUE; } else if ( e->type() == TQEvent::MouseButtonRelease ) { tqApp->removeEventFilter( this ); @@ -941,9 +1029,11 @@ bool TQDragManager::eventFilter( TQObject * o, TQEvent * e) beingCancelled = FALSE; tqApp->exit_loop(); } else { - updateMode(ke->stateAfter()); - qt_xdnd_source_sameanswer = TQRect(); // force move - move( TQCursor::pos() ); + if( updateMode(ke->stateAfter())) { + qt_xdnd_source_sameanswer = TQRect(); // force move + move( TQCursor::pos() ); + } + need_modifiers_check = FALSE; } return TRUE; // Eat all key events } @@ -970,10 +1060,10 @@ bool TQDragManager::eventFilter( TQObject * o, TQEvent * e) static TQt::ButtonState oldstate; -void TQDragManager::updateMode( TQt::ButtonState newstate ) +bool TQDragManager::updateMode( TQt::ButtonState newstate ) { if ( newstate == oldstate ) - return; + return false; const int both = ShiftButton|ControlButton; if ( (newstate & both) == both ) { global_requested_action = TQDropEvent::Link; @@ -997,6 +1087,7 @@ void TQDragManager::updateMode( TQt::ButtonState newstate ) } } oldstate = newstate; + return true; } @@ -1138,12 +1229,13 @@ void TQDragManager::move( const TQPoint & globalPos ) // recreate the pixmap on the new screen... delete qt_xdnd_deco; qt_xdnd_deco = new TQShapedPixmapWidget( screen ); + qt_xdnd_deco->x11SetWindowTransient( dragSource->tqtopLevelWidget()); if (!TQWidget::mouseGrabber()) { updatePixmap(); qt_xdnd_deco->grabMouse(); } } - updatePixmap(); + updatePixmap( globalPos ); if ( qt_xdnd_source_sameanswer.contains( globalPos ) && qt_xdnd_source_sameanswer.isValid() ) { @@ -1691,6 +1783,7 @@ bool TQDragManager::drag( TQDragObject * o, TQDragObject::DragMode mode ) dragSource = (TQWidget *)(object->tqparent()); + qt_xdnd_deco->x11SetWindowTransient( dragSource->tqtopLevelWidget()); tqApp->installEventFilter( this ); qt_xdnd_source_current_time = GET_QT_X_TIME(); XSetSelectionOwner( TQPaintDevice::x11AppDisplay(), qt_xdnd_selection, @@ -1703,6 +1796,7 @@ bool TQDragManager::drag( TQDragObject * o, TQDragObject::DragMode mode ) qt_xdnd_source_sameanswer = TQRect(); move(TQCursor::pos()); heartbeat = startTimer(200); + need_modifiers_check = FALSE; #ifndef TQT_NO_CURSOR tqApp->setOverrideCursor( Qt::ArrowCursor ); @@ -1736,7 +1830,7 @@ bool TQDragManager::drag( TQDragObject * o, TQDragObject::DragMode mode ) // qt_xdnd_source_object persists until we get an xdnd_finish message } -void TQDragManager::updatePixmap() +void TQDragManager::updatePixmap( const TQPoint& cursorPos ) { if ( qt_xdnd_deco ) { TQPixmap pm; @@ -1751,9 +1845,8 @@ void TQDragManager::updatePixmap() defaultPm = new TQPixmap(default_pm); pm = *defaultPm; } - qt_xdnd_deco->setPixmap(pm); - qt_xdnd_deco->move(TQCursor::pos()-pm_hot); - qt_xdnd_deco->tqrepaint(FALSE); + qt_xdnd_deco->setPixmap(pm, pm_hot); + qt_xdnd_deco->move(cursorPos-pm_hot); //if ( willDrop ) { qt_xdnd_deco->show(); //} else { @@ -1762,4 +1855,9 @@ void TQDragManager::updatePixmap() } } +void TQDragManager::updatePixmap() +{ + updatePixmap( TQCursor::pos()); +} + #endif // TQT_NO_DRAGANDDROP diff --git a/tqtinterface/qt4/src/kernel/tqdragobject.cpp b/tqtinterface/qt4/src/kernel/tqdragobject.cpp index 6e58f84..5a4d2fe 100644 --- a/tqtinterface/qt4/src/kernel/tqdragobject.cpp +++ b/tqtinterface/qt4/src/kernel/tqdragobject.cpp @@ -2468,6 +2468,16 @@ bool TQTextDrag::decode( const TQMimeSource* e, TQString& str, TQCString& subtyp { if(!e) return FALSE; + + // when subtype is not specified, try text/plain first, otherwise this may read + // things like text/x-moz-url even though better targets are available + if( subtype.isNull()) { + TQCString subtmp = "plain"; + if( decode( e, str, subtmp )) { + subtype = subtmp; + return true; + } + } if ( e->cacheType == TQMimeSource::Text ) { str = *e->cache.txt.str; diff --git a/tqtinterface/qt4/src/kernel/tqdragobject.h b/tqtinterface/qt4/src/kernel/tqdragobject.h index 3d55967..7133c0f 100644 --- a/tqtinterface/qt4/src/kernel/tqdragobject.h +++ b/tqtinterface/qt4/src/kernel/tqdragobject.h @@ -476,10 +476,11 @@ private: void move( const TQPoint & ); void drop(); void updatePixmap(); + void updatePixmap( const TQPoint& cursorPos ); private: TQDragObject * object; - void updateMode( TQt::ButtonState newstate ); + bool updateMode( TQt::ButtonState newstate ); void updateCursor(); #if defined(TQ_WS_X11) void createCursors(); diff --git a/tqtinterface/qt4/src/kernel/tqevent.cpp b/tqtinterface/qt4/src/kernel/tqevent.cpp index b34f38d..59a6ca7 100644 --- a/tqtinterface/qt4/src/kernel/tqevent.cpp +++ b/tqtinterface/qt4/src/kernel/tqevent.cpp @@ -874,6 +874,10 @@ TQWheelEvent::TQWheelEvent( const TQPoint &pos, int delta, int state, Orientatio the result of a known key (e.g. it may be the result of a compose sequence or a keyboard macro, or due to key event compression). + Applications should not use the TQt latin 1 keycodes between 128 + and 255, but should rather use the TQKeyEvent::text(). This is + mainly for compatibility. + \sa TQWidget::setKeyCompression() */ diff --git a/tqtinterface/qt4/src/kernel/tqfontdatabase.cpp b/tqtinterface/qt4/src/kernel/tqfontdatabase.cpp index f79c14b..e70be03 100644 --- a/tqtinterface/qt4/src/kernel/tqfontdatabase.cpp +++ b/tqtinterface/qt4/src/kernel/tqfontdatabase.cpp @@ -707,6 +707,10 @@ static TQtFontStyle *bestStyle(TQtFontFoundry *foundry, const TQtFontStyle::Key } FM_DEBUG( " best style has distance 0x%x", dist ); + if (!foundry->count) { + TQtFontStyle *temp = NULL; + return temp; + } return foundry->styles[best]; } @@ -980,20 +984,22 @@ TQFontDatabase::tqfindFont( TQFont::Script script, const TQFontPrivate *fp, #ifdef TQ_WS_X11 if (script == TQFont::Han) { - // modify script according to locale - static TQFont::Script defaultHan = TQFont::UnknownScript; - if (defaultHan == TQFont::UnknownScript) { - TQCString locale = setlocale(LC_ALL, NULL); - if (locale.tqcontains("ko")) - defaultHan = TQFont::Han_Korean; - else if (locale.tqcontains("zh_TW") || locale.tqcontains("zh_HK")) - defaultHan = TQFont::Han_TraditionalChinese; - else if (locale.tqcontains("zh")) - defaultHan = TQFont::Han_SimplifiedChinese; - else - defaultHan = TQFont::Han_Japanese; - } - script = defaultHan; + // modify script according to locale + static TQFont::Script defaultHan; + TQCString locale = setlocale(LC_ALL, NULL); + + if (locale.tqcontains("ko")) + defaultHan = TQFont::Han_Korean; + else if (locale.tqcontains("zh_TW") || locale.tqcontains("zh_HK")) + defaultHan = TQFont::Han_TraditionalChinese; + else if (locale.tqcontains("zh")) + defaultHan = TQFont::Han_SimplifiedChinese; + else if (locale.tqcontains("ja")) + defaultHan = TQFont::Han_Japanese; + else + defaultHan = TQFont::Han; // don't change + + script = defaultHan; } #endif diff --git a/tqtinterface/qt4/src/kernel/tqfontdatabase_x11.cpp b/tqtinterface/qt4/src/kernel/tqfontdatabase_x11.cpp index 8ea403f..97cb544 100644 --- a/tqtinterface/qt4/src/kernel/tqfontdatabase_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqfontdatabase_x11.cpp @@ -721,6 +721,9 @@ static void loadXlfds( const char *reqFamily, int encoding_id ) if ( fontFamily && fontFamily->xlfdLoaded ) return; +#ifdef TQT_XFT2 + if ( !qt_has_xft ) { +#endif // TQT_XFT2 int fontCount; // force the X server to give us XLFDs TQCString xlfd_pattern = "-*-"; @@ -822,8 +825,11 @@ static void loadXlfds( const char *reqFamily, int encoding_id ) } XFreeFontNames( fontList ); -} +#ifdef TQT_XFT2 + } +#endif // TQT_XFT2 +} #ifndef TQT_NO_XFTFREETYPE static int getXftWeight(int xftweight) diff --git a/tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp b/tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp index 0b45ec9..8d76e0b 100644 --- a/tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp @@ -2694,23 +2694,16 @@ bool TQOpenType::positionAndAdd(TQShaperItem *item, bool doLogClusters) // ###### fix the case where we have y advances. How do we handle this in Uniscribe????? if (positions[i].new_advance) { item->advances[i] = item->flags & TQTextEngine::RightToLeft - ? -tqRound((positions[i].x_advance >> 6)*scale) + ? -tqRound((positions[i].x_advance >> 6)*scale) : tqRound((positions[i].x_advance >> 6)*scale); } else { item->advances[i] += item->flags & TQTextEngine::RightToLeft - ? -tqRound((positions[i].x_advance >> 6)*scale) + ? -tqRound((positions[i].x_advance >> 6)*scale) : tqRound((positions[i].x_advance >> 6)*scale); } - int back = 0; - item->offsets[i].x = tqRound((positions[i].x_pos >> 6)*scale); - item->offsets[i].y = tqRound((positions[i].y_pos >> 6)*scale); - while (positions[i-back].back) { - back += positions[i - back].back; - item->offsets[i].x += tqRound((positions[i - back].x_pos >> 6)*scale); - item->offsets[i].y += tqRound((positions[i - back].y_pos >> 6)*scale); - } - item->offsets[i].y = -item->offsets[i].y; - back = positions[i].back; + item->offsets[i].x = tqRound((positions[i].x_pos >> 6)*scale); + item->offsets[i].y = -tqRound((positions[i].y_pos >> 6)*scale); + int back = positions[i].back; if (item->flags & TQTextEngine::RightToLeft) { while (back--) { item->offsets[i].x -= item->advances[i-back]; diff --git a/tqtinterface/qt4/src/kernel/tqinputcontext.cpp b/tqtinterface/qt4/src/kernel/tqinputcontext.cpp new file mode 100644 index 0000000..dfb38f7 --- /dev/null +++ b/tqtinterface/qt4/src/kernel/tqinputcontext.cpp @@ -0,0 +1,856 @@ +/**************************************************************************** +** $Id: qinputcontext.cpp,v 1.6 2004/06/22 06:47:30 daisuke Exp $ +** +** Implementation of TQInputContext class +** +** Copyright (C) 2000-2003 Trolltech AS. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses for Unix/X11 may use this file in accordance with the TQt Commercial +** License Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +//#define TQT_NO_IM_PREEDIT_RELOCATION + +#include "tqinputcontext.h" + +#ifndef TQT_NO_IM + +#include "tqplatformdefs.h" + +#include "tqapplication.h" +#include "tqwidget.h" +#include "tqpopupmenu.h" + +#include <stdlib.h> +#include <limits.h> + +class TQInputContextPrivate +{ +public: + TQInputContextPrivate() + : holderWidget( 0 ), composingWidget( 0 ), hasFocus( FALSE ), + isComposing( FALSE ) +#if !defined(TQT_NO_IM_PREEDIT_RELOCATION) + , preeditString( TQString() ), + cursorPosition( -1 ), selLength ( 0 ) +#endif + {} + + TQWidget *holderWidget; // widget to which TQInputContext instance belongs. + TQWidget *composingWidget; + bool hasFocus; + bool isComposing; + + void updateComposingState( const TQString &text, + int newCursorPosition, int newSelLength ) { +#if !defined(TQT_NO_IM_PREEDIT_RELOCATION) + preeditString = text; + cursorPosition = newCursorPosition; + selLength = newSelLength; +#endif + } + + void resetComposingState() { + isComposing = FALSE; +#if !defined(TQT_NO_IM_PREEDIT_RELOCATION) + preeditString = TQString(); + cursorPosition = -1; + selLength = 0; +#endif + } + +#if !defined(TQT_NO_IM_PREEDIT_RELOCATION) + TQString preeditString; + int cursorPosition; + int selLength; +#endif +}; + + +// UPDATED COMMENT RETQUIRED -- 2004-07-08 YamaKen +/*! + \class TQInputContext qinputcontext.h + \brief The TQInputContext class abstracts the input method dependent data and composing state. + + \ingroup i18n + + An input method is responsible to input complex text that cannot + be inputted via simple keymap. It converts a sequence of input + events (typically key events) into a text string through the input + method specific converting process. The class of the processes are + widely ranging from simple finite state machine to complex text + translator that pools a whole paragraph of a text with text + editing capability to perform grammar and semantic analysis. + + To abstract such different input method specific intermediate + information, TQt offers the TQInputContext as base class. The + concept is well known as 'input context' in the input method + domain. an input context is created for a text widget in response + to a demand. It is ensured that an input context is prepared for + an input method before input to a text widget. + + Multiple input contexts that is belonging to a single input method + may concurrently coexist. Suppose multi-window text editor. Each + text widget of window A and B holds different TQInputContext + instance which contains different state information such as + partially composed text. + + \section1 Groups of functions: + + \table + \header \i Context \i Functions + + \row \i Receiving information \i + x11FilterEvent(), + filterEvent(), + setMicroFocus(), + mouseHandler() + + \row \i Sending back composed text \i + sendIMEvent(), + + \row \i State change notification \i + setFocus(), + unsetFocus(), + reset() + + \row \i Context information \i + identifierName(), + language(), + font(), + isComposing(), + + \endtable + + + \section1 Sharing input context between text widgets + + Any input context can be shared between several text widgets to + reduce resource consumption. In ideal case, each text widgets + should be allocated dedicated input context. But some complex + input contexts require slightly heavy resource such as 100 + kilobytes of memory. It prevents quite many text widgets from + being used concurrently. + + To resolve such problem, we can share an input context. There is + one 'input context holder widget' per text widgets that shares + identical input context. In this model, the holder widget owns the + shared input context. Other text widgets access the input context + via TQApplication::locateICHolderWidget(). But the access + convention is transparently hidden into TQWidget, so developers are + not required to aware of it. + + What developer should know is only the mapping function + TQApplication::locateICHolderWidget(). It accepts a widget as + argument and returns its holder widget. Default implementation + returns the top-level widget of the widget as reasonable + assumption. But some applications should reimplement the function + to fit application specific usability. See + TQApplication::locateICHolderWidget() for further information. + + + \section1 Preedit preservation + + As described above, input contexts have wide variety of amount of + the state information in accordance with belonging input + method. It is ranging from 2-3 keystrokes of sequence in + deterministic input methods to hundreds of keystrokes with + semantic text refinement in complex input methods such as ordinary + Japanese input method. The difference requires the different reset + policies in losing input focus. + + The former simple input method case, users will prefer resetting + the context to back to the neutral state when something + happened. Suppose a web browsing. The user scroll the page by + scrollbar after he or she has typed a half of the valid key + sequence into a text widget. In the case, the input context should + be reset in losing focus when he or she has dragged the + scrollbar. He or she will be confused if the input context is + still preserved until focused back to the text widget because he + or she will restart typing with first key of the sequence as a + habitual operation. + + On the other hand, we should choose completely different policy + for the latter complex input method case. Suppose same situation + as above but he or she is using a complex input method. In the + case, he or she will be angry if the input context has been lost + when he or she has dragged the scrollbar because the input context + contained a valuably composed text made up by considerable input + cost. So we should not reset the input context in the case. And + the input context should be preserved until focused back to the + text widget. This behavior is named as 'preedit preservation'. + + The two policies can be switched by calling or not calling reset() + in unsetFocus(). Default implementation of unsetFocus() calls + reset() to fit the simple input methods. The implementation is + expressed as 'preedit preservation is disabled'. + + + \section1 Preedit relocation + + Although the most case of the preedit preservation problem for + complex input methods is resolved as described above, there is a + special case. Suppose the case that matches all of the following + conditions. + + \list + + \i a input focus has been moved from a text widget to another text + widget directly + + \i the input context is shared between the two text widgets + + \i preedit preservation is enabled for the input context + + \endlist + + In the case, there are the following two requirements that + contradicts each other. The input context sharing causes it. + + \list + + \i the input context has to be reset to prepare to input to the + newly focused text widget + + \i the input context has to be preserved until focused back to the + previous text widget + + \endlist + + A intrinsic feature named 'preedit relocation' is available to + compromise the requirements. If the feature is enabled for the + input context, it is simply moved to the new text widget with the + preedit string. The user continues the input on the new text + widget, or relocate it to another text widget. The preedit of + previous text widget is automatically cleared to back to the + neutral state of the widget. + + This strange behavior is just a compromise. As described in + previous section, complex input method user should not be exposed + to the risk losing the input context because it contains valuable + long text made up with considerable input cost. The user will + immediately focus back to the previous text widget to continue the + input in the correct text widget if the preedit relocation + occurred. The feature is mainly existing as safety. + + The feature properly works even if the focus is moved as + following. Input method developers are not required to be aware of + the relocation protocol since TQInputContext transparently handles + it. + + a text widget -> a non-text widget -> another text widget + + To enable the preedit relocation feature, the input context class + have to reimplement isPreeditRelocationEnabled() as returns TRUE. + The implementation requires that the preedit preservation is also + enabled since preedit relocation is a special case of the preedit + preservation. If the preedit relocation is disabled, the input + context is simply reset in the relocation case. + + + \section1 Input context instanciation + \section1 Input method switching + + \section1 Text widget implementor's guide + + Add following code fragment into createPopupMenu() to add input + method dependent submenus. + + \code + #ifndef TQT_NO_IM + TQInputContext *qic = getInputContext(); + if ( qic ) + qic->addMenusTo( popup ); + #endif + \endcode + + \sa TQInputContextPlugin, TQInputContextFactory, TQApplication::locateICHolderWidget(), TQApplication::defaultInputMethod() +*/ + + +/*! + Constructs an input context. + + holderWidget is set immediately after this constructor has been + returned on the X11 platform. +*/ +TQInputContext::TQInputContext( TQObject *tqparent ) + : TQObject( tqparent ) +{ + d = new TQInputContextPrivate; +} + + +/*! + Destroys the input context. +*/ +TQInputContext::~TQInputContext() +{ + delete d; +} + +#if defined(TQ_WS_X11) +/*! + \internal + Returns the owner of this input context. Ordinary input methods + should not call this function directly to keep platform + independence and flexible configuration possibility. + + The return value may differ from tqfocusWidget() if the input + context is shared between several text widgets. + + \sa setHolderWidget(), tqfocusWidget() +*/ +TQWidget *TQInputContext::holderWidget() const +{ + return d->holderWidget; +} + +/*! + \internal + Sets the owner of this input context. Ordinary input methods + must not call this function directly. + + \sa holderWidget() +*/ +void TQInputContext::setHolderWidget( TQWidget *w ) +{ + d->holderWidget = w; +} + +/*! + \internal + Returns the widget that has an input focus for this input + context. Ordinary input methods should not call this function + directly to keep platform independence and flexible configuration + possibility. + + The return value may differ from holderWidget() if the input + context is shared between several text widgets. + + \sa setFocusWidget(), holderWidget() +*/ +TQWidget *TQInputContext::tqfocusWidget() const +{ + return d->hasFocus ? d->composingWidget : 0; +} + + +/*! + \internal + Sets the widget that has an input focus for this input + context. Ordinary input methods must not call this function + directly. + + \sa tqfocusWidget() +*/ +void TQInputContext::setFocusWidget( TQWidget *w ) +{ + if ( w ) { + bool isFocusingBack = ( w == d->composingWidget ); + bool isPreeditRelocation = ( ! isFocusingBack && isComposing() && + d->composingWidget ); + // invoke sendIMEventInternal() rather than sendIMEvent() to + // avoid altering the composing state + if ( isPreeditRelocation == TRUE ) { + // clear preedit of previously focused text + // widget. preserved preedit may be exist even if + // isPreeditRelocationEnabled() == FALSE. + sendIMEventInternal( TQEvent::IMEnd ); + } + d->composingWidget = w; // changes recipient of TQIMEvent + if ( isPreeditRelocation == TRUE ) { +#if !defined(TQT_NO_IM_PREEDIT_RELOCATION) + if ( isPreeditRelocationEnabled() ) { + // copy preedit state to the widget that gaining focus + sendIMEventInternal( TQEvent::IMStart ); + sendIMEventInternal( TQEvent::IMCompose, d->preeditString, + d->cursorPosition, d->selLength ); + } else +#endif + { + // reset input context when the shared context has + // focused on another text widget + reset(); + } + } + } + d->hasFocus = w ? TRUE : FALSE; +} + + +/*! + \internal + This function is called from TQWidget to keep input state + consistency. Ordinary input method must not call this function + directly. +*/ +void TQInputContext::releaseComposingWidget( TQWidget *w ) +{ + if ( d->composingWidget == w ) { + d->composingWidget = 0; + d->hasFocus = FALSE; + } +} +#endif // TQ_WS_X11 + +/*! + \internal + This function can be reimplemented in a subclass as returning TRUE + if you want making your input method enable the preedit + relocation. See the description for preedit relocation of + TQInputContext. + + /sa TQInputContext +*/ +bool TQInputContext::isPreeditRelocationEnabled() +{ + return FALSE; +} + +/*! + This function indicates whether IMStart event had been sent to the + text widget. It is ensured that an input context can send IMCompose + or IMEnd event safely if this function returned TRUE. + + The state is automatically being tracked through sendIMEvent(). + + \sa sendIMEvent() +*/ +bool TQInputContext::isComposing() const +{ + return d->isComposing; +} + + +/*! + This function can be reimplemented in a subclass to filter input + events. + + Return TRUE if the \a event has been consumed. Otherwise, the + unfiltered \a event will be forwarded to widgets as ordinary + way. Although the input events have accept() and ignore() + methods, leave it untouched. + + \a event is currently restricted to TQKeyEvent. But some input + method related events such as TQWheelEvent or TQTabletEvent may be + added in future. + + The filtering opportunity is always given to the input context as + soon as possible. 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. + + Ordinary input methods require discrete key events to work + properly, so TQt's key compression is always disabled for any input + contexts. + + \sa TQKeyEvent, x11FilterEvent() +*/ +bool TQInputContext::filterEvent( const TQEvent *event ) +{ + return FALSE; +} + + +/*! + \fn void TQInputContext::deletionRequested() + + Emit this signal when a fatal error has been caused in the input + context. The input context will be deleted by the owner which is + usually the holder widget. +*/ + +/*! + \fn void TQInputContext::imEventGenerated( TQObject *receiver, TQIMEvent *e ) + + \internal + This signal is emitted when the user has sent a TQIMEvent through + sendIMEvent(). Ordinary input methods should not emit this signal + directly. + + \a receiver is a platform dependent destination of the \a e. + + \sa TQIMEvent, sendIMEvent(), sendIMEventInternal(), +*/ + +/*! + \internal + Sends a TQIMEvent to the client via imEventGenerated() + signal. Ordinary input method should not call this function + directly. + + \sa TQIMEvent, TQIMComposeEvent, sendIMEvent(), imEventGenerated() +*/ +void TQInputContext::sendIMEventInternal( TQEvent::Type type, + const TQString &text, + int cursorPosition, int selLength ) +{ + TQObject *receiver = 0; + TQIMEvent *event = 0; + +#if defined(TQ_WS_X11) + receiver = d->composingWidget; +#elif defined(TQ_WS_TQWS) + // just a placeholder +#endif + if ( ! receiver ) + return; + + if ( type == TQEvent::IMStart ) { + qDebug( "sending IMStart with %d chars to %p", + text.length(), receiver ); + event = new TQIMEvent( type, text, cursorPosition ); + } else if ( type == TQEvent::IMEnd ) { + qDebug( "sending IMEnd with %d chars to %p, text=%s", + text.length(), receiver, (const char*)text.local8Bit() ); + event = new TQIMEvent( type, text, cursorPosition ); + } else if ( type == TQEvent::IMCompose ) { + qDebug( "sending IMCompose to %p with %d chars, cpos=%d, sellen=%d, text=%s", + receiver, text.length(), cursorPosition, selLength, + (const char*)text.local8Bit() ); + event = new TQIMComposeEvent( type, text, cursorPosition, selLength ); + } + + if ( event ) + emit imEventGenerated( receiver, event ); +} + + +/*! + Call this function to send TQIMEvent to the text widget. This + function constructs a TQIMEvent based on the arguments and send it + to the appropriate widget. Ordinary input method should not + reimplement this function. + + \a type is either \c TQEvent::IMStart or \c TQEvent::IMCompose or \c + TQEvent::IMEnd. You have to send a \c TQEvent::IMStart to start + composing, then send several \c TQEvent::IMCompose to update the + preedit of the widget, and finalize the composition with sending + \c TQEvent::IMEnd. + + \c TQEvent::IMStart should always be sent without arguments as: + \code + sendIMEvent( TQEvent::IMStart ) + \endcode + + And \c TQEvent::IMCompose can be sent without cursor: + \code + sendIMEvent( TQEvent::IMCompose, TQString( "a text" ) ) + \endcode + + Or optionally with cursor with \a cursorPosition: + \code + sendIMEvent( TQEvent::IMCompose, TQString( "a text with cursor" ), 12 ) + \endcode + Note that \a cursorPosition also specifies microfocus position. + + Or optionally with selection text: + \code + sendIMEvent( TQEvent::IMCompose, TQString( "a text with selection" ), 12, 9 ) + \endcode + \a cursorPosition and \a selLength must be within the \a text. The + \a cursorPosition also specifies microfocus position in the case: + + \c TQEvent::IMEnd can be sent without arguments to terminate the + composition with null string: + \code + sendIMEvent( TQEvent::IMEnd ) + \endcode + + Or optionally accepts \a text to commit a string: + \code + sendIMEvent( TQEvent::IMEnd, TQString( "a text" ) ) + \endcode + + \sa TQIMEvent, TQIMComposeEvent, setMicroFocus() +*/ +void TQInputContext::sendIMEvent( TQEvent::Type type, const TQString &text, + int cursorPosition, int selLength ) +{ +#if defined(TQ_WS_X11) + if ( !tqfocusWidget() ) + return; +#endif + + if ( type == TQEvent::IMStart ) { + sendIMEventInternal( type, text, cursorPosition, selLength ); + d->isComposing = TRUE; + } else if ( type == TQEvent::IMEnd ) { + d->resetComposingState(); + sendIMEventInternal( type, text, cursorPosition, selLength ); + } else if ( type == TQEvent::IMCompose ) { + d->updateComposingState( text, cursorPosition, selLength ); + sendIMEventInternal( type, text, cursorPosition, selLength ); + } +} + + +/*! + This function can be reimplemented in a subclass to detect + that the input context has been focused on. + + The input context will receive input events through + x11FilterEvent() and filterEvent() after setFocus() until + unsetFocus() has been called. + + an input context is ensured that setFocus() is called exactly once + until unsetFocus() has been called even if preedit relocation has + occurred. This means that an input focus will survive between + several widgets that sharing the input context. + + On the X11 platform, tqfocusWidget is already set before this + function has been called. + + \sa unsetFocus() +*/ +void TQInputContext::setFocus() +{ +} + + +/*! + This function can be reimplemented in a subclass to detect + that the input context has lost the focus. + + an input context is ensured that unsetFocus() is not called during + preedit relocation. This means that an input focus will survive + between several widgets that sharing the input context. + + Default implementation that calls reset() is sufficient for simple + input methods. You can override this function to alter the + behavior. For example, most Japanese input contexts should not be + reset on losing focus. The context sometimes contains a whole + paragraph and has minutes of lifetime different to ephemeral one + in other languages. The piled input context should be survived + until focused again since Japanese user naturally expects so. + + On the X11 platform, tqfocusWidget is valid until this function has + been returned. + + \sa setFocus() +*/ +void TQInputContext::unsetFocus() +{ + reset(); +} + + +/*! + This function can be implemented in a subclass to handle + microfocus changes. + + 'microfocus' stands for the input method focus point in the + preedit (XIM "spot" point) for complex language input handling. It + can be used to place auxiliary GUI widgets such as candidate + selection window. + + \a x, \a y, \a w and \a h represents the position and size of the + cursor in the preedit string. \a f is the font on the location of + the cursor. +*/ +void TQInputContext::setMicroFocus( int x, int y, int w, int h, TQFont *f ) +{ +} + + +/*! + This function can be reimplemented in a subclass to handle mouse + presses/releases/doubleclicks/moves within the preedit text. You + can use the function to implement mouse-oriented user interface + such as text selection or popup menu for candidate selection. + + The parameter \a x is the offset within the string that was sent + with the IMCompose event. The alteration boundary of \a x is + ensured as character boundary of preedit string accurately. + + \a type is either \c TQEvent::MouseButtonPress or \c + TQEvent::MouseButtonRelease or \c TQEvent::MouseButtonDblClick or \c + TQEvent::MouseButtonMove. Refer \a button and \a state to determine + what operation has performed. + + The method interface is imported from + TQWSInputMethod::mouseHandler() of TQt/Embedded 2.3.7 and extended + for desktop system. + */ +void TQInputContext::mouseHandler( int x, TQEvent::Type type, + TQt::ButtonState button, + TQt::ButtonState state ) +{ + // Default behavior for simple ephemeral input contexts. Some + // complex input contexts should not be reset here. + if ( type == TQEvent::MouseButtonPress || + type == TQEvent::MouseButtonDblClick ) + reset(); +} + + +/*! + Returns the font of the current input widget + */ +TQFont TQInputContext::font() const +{ + if ( !tqfocusWidget() ) + return TQApplication::font(); //### absolutely last resort + + return tqfocusWidget()->font(); +} + + +/*! + This function can be reimplemented in a subclass to reset the + state of the input method. + + This function is called by several widgets to reset input + state. For example, a text widget call this function before + inserting a text to make widget ready to accept a text. + + Default implementation is sufficient for simple input method. You + can override this function to reset external input method engines + in complex input method. In the case, call TQInputContext::reset() + to ensure proper termination of inputting. + + You must not send any TQIMEvent except empty IMEnd event using + TQInputContext::reset() at reimplemented reset(). It will break + input state consistency. +*/ +void TQInputContext::reset() +{ + if ( isComposing() ) + sendIMEvent( TQEvent::IMEnd ); +} + + +/*! + This function must be implemented in any subclasses to return the + identifier name of the input method. + + Return value is the name to identify and specify input methods for + the input method switching mechanism and so on. The name has to be + consistent with TQInputContextPlugin::keys(). The name has to + consist of ASCII characters only. + + There are two different names with different responsibility in the + input method domain. This function returns one of them. Another + name is called 'display name' that stands for the name for + endusers appeared in a menu and so on. + + \sa TQInputContextPlugin::keys(), TQInputContextPlugin::displayName() +*/ +TQString TQInputContext::identifierName() +{ + return ""; +} + + +/*! + This function must be implemented in any subclasses to return a + language code (e.g. "zh_CN", "zh_TW", "zh_HK", "ja", "ko", ...) + of the input context. If the input context can handle multiple + languages, return the currently used one. The name has to be + consistent with TQInputContextPlugin::language(). + + This information will be used by language tagging feature in + TQIMEvent. It is required to distinguish unified han characters + correctly. It enables proper font and character code + handling. Suppose CJK-awared multilingual web browser + (that automatically modifies fonts in CJK-mixed text) and XML editor + (that automatically inserts lang attr). + + \sa TQInputContextPlugin::language() +*/ +TQString TQInputContext::language() +{ + return ""; +} + + +#if ([[[TQT_VERSION IS DEPRECATED]]]-0 >= 0x040000) +/*! + This is a preliminary interface for TQt4 + */ +TQList<TQAction *> TQInputContext::actions() +{ +} +#else +/*! + This function can be reimplemented in a subclass to provide input + method dependent popup menus. Return 0 if the menus are + unnecessary. + + Ownership of the object and tqchildren are transferred to the + caller, and the result must not be called + setAutoDelete(). TQInputContextMenu::title is used for label text + of the popup menu as submenu. + + \sa addMenusTo() +*/ +TQPtrList<TQInputContextMenu> *TQInputContext::menus() +{ + return 0; +} +#endif + +/*! + Appends input method dependent submenus into \a popup. A separator + is also inserted into \a popup if \a action is InsertSeparator. + + This is an utility function only for convenience in limited + situation. This function is used by input context owner such as + text widgets to add the submenus to its own context menu. If you + want to insert the submenus in more flexible way, use + TQInputContext::menus() manually. \a popup is not restricted to + context menu of a text widget. For example, the owner may be a + input method menu of TQtopia taskbar in TQt/Embedded platform. + + \sa menus(), TQInputContextMenu::Action +*/ +void TQInputContext::addMenusTo( TQPopupMenu *popup, TQInputContextMenu::Action action ) +{ + if ( ! popup ) + return; + + TQPtrList<TQInputContextMenu> *imMenus = menus(); + if ( imMenus ) { + if ( action == TQInputContextMenu::InsertSeparator ) + popup->insertSeparator(); + for ( TQPtrList<TQInputContextMenu>::Iterator it = imMenus->begin(); + it != imMenus->end(); + ++it ) { + TQInputContextMenu *imMenu = *it; + popup->insertItem( imMenu->title, imMenu->popup ); + } + imMenus->clear(); + delete imMenus; + } +} + +#endif //TQ_NO_IM diff --git a/tqtinterface/qt4/src/kernel/tqinputcontext.h b/tqtinterface/qt4/src/kernel/tqinputcontext.h new file mode 100644 index 0000000..9dbd9bf --- /dev/null +++ b/tqtinterface/qt4/src/kernel/tqinputcontext.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** $Id: qinputcontext.h,v 1.8 2004/06/22 06:47:30 daisuke Exp $ +** +** Definition of TQInputContext +** +** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses may use this file in accordance with the TQt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef TQINPUTCONTEXT_H +#define TQINPUTCONTEXT_H + +#ifndef TQT_NO_IM + +#ifndef TQT_H +#include "tqobject.h" +#include "tqglobal.h" +#include "tqevent.h" +#include "tqstring.h" +#if ([[[TQT_VERSION IS DEPRECATED]]]-0 >= 0x040000) +#include "tqlist.h" +#include "tqaction.h" +#else +#include "tqptrlist.h" +#endif +#endif + +class TQWidget; +class TQFont; +class TQPopupMenu; +class TQInputContextPrivate; + + +struct TQInputContextMenu { + enum Action { + NoSeparator, + InsertSeparator + }; +#if !([[[TQT_VERSION IS DEPRECATED]]]-0 >= 0x040000) + TQString title; + TQPopupMenu *popup; +#endif +}; + + +class TQInputContext : public TQObject +{ + TQ_OBJECT +public: + TQInputContext( TQObject *tqparent = 0 ); + virtual ~TQInputContext(); + + virtual TQString identifierName(); + virtual TQString language(); + +#if defined(TQ_WS_X11) + virtual bool x11FilterEvent( TQWidget *keywidget, XEvent *event ); +#endif // TQ_WS_X11 + virtual bool filterEvent( const TQEvent *event ); + virtual void reset(); + + virtual void setFocus(); + virtual void unsetFocus(); + virtual void setMicroFocus( int x, int y, int w, int h, TQFont *f = 0 ); + virtual void mouseHandler( int x, TQEvent::Type type, + TQt::ButtonState button, TQt::ButtonState state ); + virtual TQFont font() const; + virtual bool isComposing() const; + virtual bool isPreeditRelocationEnabled(); + +#if ([[[TQT_VERSION IS DEPRECATED]]]-0 >= 0x040000) + virtual TQList<TQAction *> actions(); + void addActionsTo( TQMenu *menu, TQInputContextMenu::Action action = TQInputContextMenu::InsertSeparator ); +#else + virtual TQPtrList<TQInputContextMenu> *menus(); + void addMenusTo( TQPopupMenu *popup, TQInputContextMenu::Action action = TQInputContextMenu::InsertSeparator ); +#endif + +#if defined(TQ_WS_X11) + // these functions are not recommended for ordinary use + virtual TQWidget *tqfocusWidget() const; + virtual TQWidget *holderWidget() const; + + // these functions must not be used by ordinary input method + virtual void setFocusWidget( TQWidget *w ); + virtual void setHolderWidget( TQWidget *w ); + virtual void releaseComposingWidget( TQWidget *w ); +#endif + +signals: + void deletionRequested(); + void imEventGenerated( TQObject *receiver, TQIMEvent *e ); + +protected: + virtual void sendIMEvent( TQEvent::Type type, + const TQString &text = TQString(), + int cursorPosition = -1, int selLength = 0 ); + +private: + void sendIMEventInternal( TQEvent::Type type, + const TQString &text = TQString(), + int cursorPosition = -1, int selLength = 0 ); + + TQInputContextPrivate *d; + + friend class TQWidget; + friend class TQInputContextFactory; + +private: // Disabled copy constructor and operator= + TQInputContext( const TQInputContext & ); + TQInputContext &operator=( const TQInputContext & ); + +}; + +#endif //TQ_NO_IM + +#endif // TQINPUTCONTEXT_H diff --git a/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp b/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp index 758b56d..e96c75c 100644 --- a/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp @@ -36,500 +36,34 @@ ** **********************************************************************/ +#include "tqinputcontext.h" + +#ifndef TQT_NO_IM + #include "tqplatformdefs.h" #include "tqapplication.h" #include "tqwidget.h" -#include "tqinputcontext_p.h" - -#include <stdlib.h> -#include <limits.h> +#include "tqt_x11_p.h" -bool qt_compose_emptied = FALSE; +/*! + This function may be overridden only if input method is depending + on X11 and you need raw XEvent. Otherwise, this function must not. -#if !defined(TQT_NO_XIM) + This function is designed to filter raw key events for XIM, but + other input methods may use this to implement some special + features such as distinguishing Shift_L and Shift_R. -#define XK_MISCELLANY -#define XK_LATIN1 -#include <X11/keysymdef.h> + Return TRUE if the \a event has been consumed. Otherwise, the + unfiltered \a event will be translated into TQEvent and forwarded + to filterEvent(). Filtering at both x11FilterEvent() and + filterEvent() in single input method is allowed. -// #define TQT_XIM_DEBUG + \a keywidget is a client widget into which a text is inputted. \a + event is inputted XEvent. -// from qapplication_x11.cpp -extern XIM qt_xim; -extern XIMStyle qt_xim_style; - -/* The cache here is needed, as X11 leaks a few kb for every - XFreeFontSet call, so we avoid creating and deletion of fontsets as - much as possible + \sa filterEvent() */ -static XFontSet fontsetCache[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -static int fontsetRefCount = 0; - -static const char * const fontsetnames[] = { - "-*-fixed-medium-r-*-*-16-*,-*-*-medium-r-*-*-16-*", - "-*-fixed-medium-i-*-*-16-*,-*-*-medium-i-*-*-16-*", - "-*-fixed-bold-r-*-*-16-*,-*-*-bold-r-*-*-16-*", - "-*-fixed-bold-i-*-*-16-*,-*-*-bold-i-*-*-16-*", - "-*-fixed-medium-r-*-*-24-*,-*-*-medium-r-*-*-24-*", - "-*-fixed-medium-i-*-*-24-*,-*-*-medium-i-*-*-24-*", - "-*-fixed-bold-r-*-*-24-*,-*-*-bold-r-*-*-24-*", - "-*-fixed-bold-i-*-*-24-*,-*-*-bold-i-*-*-24-*" -}; - -static XFontSet getFontSet( const TQFont &f ) -{ - int i = 0; - if (f.italic()) - i |= 1; - if (f.bold()) - i |= 2; - - if ( f.pointSize() > 20 ) - i += 4; - - if ( !fontsetCache[i] ) { - Display* dpy = TQPaintDevice::x11AppDisplay(); - int missCount; - char** missList; - fontsetCache[i] = XCreateFontSet(dpy, fontsetnames[i], &missList, &missCount, 0); - if(missCount > 0) - XFreeStringList(missList); - if ( !fontsetCache[i] ) { - fontsetCache[i] = XCreateFontSet(dpy, "-*-fixed-*-*-*-*-16-*", &missList, &missCount, 0); - if(missCount > 0) - XFreeStringList(missList); - if ( !fontsetCache[i] ) - fontsetCache[i] = (XFontSet)-1; - } - } - return (fontsetCache[i] == (XFontSet)-1) ? 0 : fontsetCache[i]; -} - - -#ifdef TQ_C_CALLBACKS -extern "C" { -#endif // TQ_C_CALLBACKS - - static int xic_start_callback(XIC, XPointer client_data, XPointer) { - TQInputContext *qic = (TQInputContext *) client_data; - if (! qic) { -#ifdef TQT_XIM_DEBUG - qDebug("compose start: no qic"); -#endif // TQT_XIM_DEBUG - - return 0; - } - - qic->composing = TRUE; - qic->text = TQString::null; - qic->tqfocusWidget = 0; - - if ( qic->selectedChars.size() < 128 ) - qic->selectedChars.resize( 128 ); - qic->selectedChars.fill( 0 ); - -#ifdef TQT_XIM_DEBUG - qDebug("compose start"); -#endif // TQT_XIM_DEBUG - - return 0; - } - - static int xic_draw_callback(XIC, XPointer client_data, XPointer call_data) { - TQInputContext *qic = (TQInputContext *) client_data; - if (! qic) { -#ifdef TQT_XIM_DEBUG - qDebug("compose event: invalid compose event %p", qic); -#endif // TQT_XIM_DEBUG - - return 0; - } - - bool send_imstart = FALSE; - if (tqApp->tqfocusWidget() != qic->tqfocusWidget && qic->text.isEmpty()) { - if (qic->tqfocusWidget) { -#ifdef TQT_XIM_DEBUG - qDebug( "sending IMEnd (empty) to %p", qic->tqfocusWidget ); -#endif // TQT_XIM_DEBUG - - TQIMEvent endevent(TQEvent::IMEnd, TQString::null, -1); - TQApplication::sendEvent(qic->tqfocusWidget, &endevent); - } - - qic->text = TQString::null; - qic->tqfocusWidget = tqApp->tqfocusWidget(); - qic->composing = FALSE; - - if ( qic->selectedChars.size() < 128 ) - qic->selectedChars.resize( 128 ); - qic->selectedChars.fill( 0 ); - - if (qic->tqfocusWidget) { - qic->composing = TRUE; - send_imstart = TRUE; - } - } - - if (! qic->composing || ! qic->tqfocusWidget) { -#ifdef TQT_XIM_DEBUG - qDebug("compose event: invalid compose event %d %p", - qic->composing, qic->tqfocusWidget); -#endif // TQT_XIM_DEBUG - - return 0; - } - - if ( send_imstart ) { -#ifdef TQT_XIM_DEBUG - qDebug( "sending IMStart to %p", qic->tqfocusWidget ); -#endif // TQT_XIM_DEBUG - - qt_compose_emptied = FALSE; - TQIMEvent startevent(TQEvent::IMStart, TQString::null, -1); - TQApplication::sendEvent(qic->tqfocusWidget, &startevent); - } - - XIMPreeditDrawCallbackStruct *drawstruct = - (XIMPreeditDrawCallbackStruct *) call_data; - XIMText *text = (XIMText *) drawstruct->text; - int cursor = drawstruct->caret, sellen = 0; - - if ( ! drawstruct->caret && ! drawstruct->chg_first && - ! drawstruct->chg_length && ! text ) { - // nothing to do - return 0; - } - - if (text) { - char *str = 0; - if (text->encoding_is_wchar) { - int l = wcstombs(NULL, text->string.wide_char, text->length); - if (l != -1) { - str = new char[l + 1]; - wcstombs(str, text->string.wide_char, l); - str[l] = 0; - } - } else - str = text->string.multi_byte; - - if (! str) - return 0; - - TQString s = TQString::fromLocal8Bit(str); - - if (text->encoding_is_wchar) - delete [] str; - - if (drawstruct->chg_length < 0) - qic->text.tqreplace(drawstruct->chg_first, UINT_MAX, s); - else - qic->text.tqreplace(drawstruct->chg_first, drawstruct->chg_length, s); - - if ( qic->selectedChars.size() < qic->text.length() ) { - // expand the selectedChars array if the compose string is longer - uint from = qic->selectedChars.size(); - qic->selectedChars.resize( qic->text.length() ); - for ( uint x = from; from < qic->selectedChars.size(); ++x ) - qic->selectedChars[x] = 0; - } - - uint x; - bool *p = qic->selectedChars.data() + drawstruct->chg_first; - // determine if the changed chars are selected based on text->feedback - for ( x = 0; x < s.length(); ++x ) - *p++ = ( text->feedback ? ( text->feedback[x] & XIMReverse ) : 0 ); - - // figure out where the selection starts, and how long it is - p = qic->selectedChars.data(); - bool started = FALSE; - for ( x = 0; x < TQMIN(qic->text.length(), qic->selectedChars.size()); ++x ) { - if ( started ) { - if ( *p ) ++sellen; - else break; - } else { - if ( *p ) { - cursor = x; - started = TRUE; - sellen = 1; - } - } - ++p; - } - } else { - if (drawstruct->chg_length == 0) - drawstruct->chg_length = -1; - - qic->text.remove(drawstruct->chg_first, drawstruct->chg_length); - qt_compose_emptied = qic->text.isEmpty(); - if ( qt_compose_emptied ) { -#ifdef TQT_XIM_DEBUG - qDebug( "compose emptied" ); -#endif // TQT_XIM_DEBUG - - // don't send an empty compose, since we will send an IMEnd with - // either the correct compose text (or null text if the user has - // cancelled the compose or deleted all chars). - return 0; - } - } - -#ifdef TQT_XIM_DEBUG - qDebug( "sending IMCompose to %p with %d chars", - qic->tqfocusWidget, qic->text.length() ); -#endif // TQT_XIM_DEBUG - - TQIMComposeEvent event( TQEvent::IMCompose, qic->text, cursor, sellen ); - TQApplication::sendEvent(qic->tqfocusWidget, &event); - return 0; - } - - static int xic_done_callback(XIC, XPointer client_data, XPointer) { - TQInputContext *qic = (TQInputContext *) client_data; - if (! qic) - return 0; - - if (qic->composing && qic->tqfocusWidget) { -#ifdef TQT_XIM_DEBUG - qDebug( "sending IMEnd (empty) to %p", qic->tqfocusWidget ); -#endif // TQT_XIM_DEBUG - - TQIMEvent event(TQEvent::IMEnd, TQString::null, -1); - TQApplication::sendEvent(qic->tqfocusWidget, &event); - } - - qic->composing = FALSE; - qic->tqfocusWidget = 0; - - if ( qic->selectedChars.size() < 128 ) - qic->selectedChars.resize( 128 ); - qic->selectedChars.fill( 0 ); - - return 0; - } - -#ifdef TQ_C_CALLBACKS -} -#endif // TQ_C_CALLBACKS - -#endif // !TQT_NO_XIM - - - -TQInputContext::TQInputContext(TQWidget *widget) - : ic(0), tqfocusWidget(0), composing(FALSE), fontset(0) -{ -#if !defined(TQT_NO_XIM) - fontsetRefCount++; - if (! qt_xim) { - qWarning("TQInputContext: no input method context available"); - return; - } - - if (! widget->isTopLevel()) { - qWarning("TQInputContext: cannot create input context for non-toplevel widgets"); - return; - } - - XPoint spot; - XRectangle rect; - XVaNestedList preedit_attr = 0; - XIMCallback startcallback, drawcallback, donecallback; - - font = widget->font(); - fontset = getFontSet( font ); - - if (qt_xim_style & XIMPreeditArea) { - rect.x = 0; - rect.y = 0; - rect.width = widget->width(); - rect.height = widget->height(); - - preedit_attr = XVaCreateNestedList(0, - XNArea, &rect, - XNFontSet, fontset, - (char *) 0); - } else if (qt_xim_style & XIMPreeditPosition) { - spot.x = 1; - spot.y = 1; - - preedit_attr = XVaCreateNestedList(0, - XNSpotLocation, &spot, - XNFontSet, fontset, - (char *) 0); - } else if (qt_xim_style & XIMPreeditCallbacks) { - startcallback.client_data = (XPointer) this; - startcallback.callback = (XIMProc) xic_start_callback; - drawcallback.client_data = (XPointer) this; - drawcallback.callback = (XIMProc)xic_draw_callback; - donecallback.client_data = (XPointer) this; - donecallback.callback = (XIMProc) xic_done_callback; - - preedit_attr = XVaCreateNestedList(0, - XNPreeditStartCallback, &startcallback, - XNPreeditDrawCallback, &drawcallback, - XNPreeditDoneCallback, &donecallback, - (char *) 0); - } - - if (preedit_attr) { - ic = XCreateIC(qt_xim, - XNInputStyle, qt_xim_style, - XNClientWindow, widget->winId(), - XNPreeditAttributes, preedit_attr, - (char *) 0); - XFree(preedit_attr); - } else - ic = XCreateIC(qt_xim, - XNInputStyle, qt_xim_style, - XNClientWindow, widget->winId(), - (char *) 0); - - if (! ic) - qFatal("Failed to create XIM input context!"); - - // when resetting the input context, preserve the input state - (void) XSetICValues((XIC) ic, XNResetState, XIMPreserveState, (char *) 0); -#endif // !TQT_NO_XIM -} - - -TQInputContext::~TQInputContext() -{ - -#if !defined(TQT_NO_XIM) - if (ic) - XDestroyIC((XIC) ic); - - if ( --fontsetRefCount == 0 ) { - Display *dpy = TQPaintDevice::x11AppDisplay(); - for ( int i = 0; i < 8; i++ ) { - if ( fontsetCache[i] && fontsetCache[i] != (XFontSet)-1 ) { - XFreeFontSet(dpy, fontsetCache[i]); - fontsetCache[i] = 0; - } - } - } - -#endif // !TQT_NO_XIM - - ic = 0; - tqfocusWidget = 0; - composing = FALSE; -} - - -void TQInputContext::reset() -{ -#if !defined(TQT_NO_XIM) - if (tqfocusWidget && composing && ! text.isNull()) { -#ifdef TQT_XIM_DEBUG - qDebug("TQInputContext::reset: composing - sending IMEnd (empty) to %p", - tqfocusWidget); -#endif // TQT_XIM_DEBUG - - TQIMEvent endevent(TQEvent::IMEnd, TQString::null, -1); - TQApplication::sendEvent(tqfocusWidget, &endevent); - tqfocusWidget = 0; - text = TQString::null; - if ( selectedChars.size() < 128 ) - selectedChars.resize( 128 ); - selectedChars.fill( 0 ); - - char *mb = XmbResetIC((XIC) ic); - if (mb) - XFree(mb); - } -#endif // !TQT_NO_XIM -} - - -void TQInputContext::setComposePosition(int x, int y) -{ -#if !defined(TQT_NO_XIM) - if (qt_xim && ic) { - XPoint point; - point.x = x; - point.y = y; - - XVaNestedList preedit_attr = - XVaCreateNestedList(0, - XNSpotLocation, &point, - - (char *) 0); - XSetICValues((XIC) ic, XNPreeditAttributes, preedit_attr, (char *) 0); - XFree(preedit_attr); - } -#endif // !TQT_NO_XIM -} - - -void TQInputContext::setComposeArea(int x, int y, int w, int h) -{ -#if !defined(TQT_NO_XIM) - if (qt_xim && ic) { - XRectangle rect; - rect.x = x; - rect.y = y; - rect.width = w; - rect.height = h; - - XVaNestedList preedit_attr = XVaCreateNestedList(0, - XNArea, &rect, - - (char *) 0); - XSetICValues((XIC) ic, XNPreeditAttributes, preedit_attr, (char *) 0); - XFree(preedit_attr); - } -#endif -} - - -int TQInputContext::lookupString(XKeyEvent *event, TQCString &chars, - KeySym *key, Status *status) const -{ - int count = 0; - -#if !defined(TQT_NO_XIM) - if (qt_xim && ic) { - count = XmbLookupString((XIC) ic, event, chars.data(), - chars.size(), key, status); - - if ((*status) == XBufferOverflow ) { - chars.resize(count + 1); - count = XmbLookupString((XIC) ic, event, chars.data(), - chars.size(), key, status); - } - } - -#endif // TQT_NO_XIM - - return count; -} - -void TQInputContext::setFocus() -{ -#if !defined(TQT_NO_XIM) - if (qt_xim && ic) - XSetICFocus((XIC) ic); -#endif // !TQT_NO_XIM -} - -void TQInputContext::setXFontSet(const TQFont &f) -{ -#if !defined(TQT_NO_XIM) - if (font == f) return; // nothing to do - font = f; - - XFontSet fs = getFontSet(font); - if (fontset == fs) return; // nothing to do - fontset = fs; - XVaNestedList preedit_attr = XVaCreateNestedList(0, XNFontSet, fontset, (char *) 0); - XSetICValues((XIC) ic, XNPreeditAttributes, preedit_attr, (char *) 0); - XFree(preedit_attr); -#else - TQ_UNUSED( f ); -#endif -} +#endif //TQ_NO_IM
\ No newline at end of file diff --git a/tqtinterface/qt4/src/kernel/tqnamespace.h b/tqtinterface/qt4/src/kernel/tqnamespace.h index b158936..d3919c9 100644 --- a/tqtinterface/qt4/src/kernel/tqnamespace.h +++ b/tqtinterface/qt4/src/kernel/tqnamespace.h @@ -512,7 +512,8 @@ typedef Qt::Orientation Orientation; #ifdef TQT_NO_COMPAT enum GUIStyle { WindowsStyle = 1, // ### TQt 4.0: either remove the obsolete enums or clean up compat vs. - MotifStyle = 4 // ### TQT_NO_COMPAT by reordering or combination into one enum. + MotifStyle = 4, // ### TQT_NO_COMPAT by reordering or combination into one enum. + GtkStyle = 6 // Gtk compability mode }; #else enum GUIStyle { @@ -520,7 +521,8 @@ typedef Qt::Orientation Orientation; WindowsStyle, Win3Style, // OBSOLETE PMStyle, // OBSOLETE - MotifStyle + MotifStyle, + GtkStyle = 6 // Gtk compability mode }; #endif @@ -631,6 +633,87 @@ typedef Qt::Orientation Orientation; Key_Help = (int)Qt::Key_Help, Key_Direction_L = (int)Qt::Key_Direction_L, Key_Direction_R = (int)Qt::Key_Direction_R, + + // International input method support (X keycode - 0xEE00, the + // definition follows TQt/Embedded 2.3.7) Only interesting if + // you are writing your own input method + + // International & multi-key character composition + Key_Multi_key = 0x1120, // Multi-key character compose + Key_Codeinput = 0x1137, + Key_SingleCandidate = 0x113c, + Key_MultipleCandidate = 0x113d, + Key_PreviousCandidate = 0x113e, + + // Misc Functions + Key_Mode_switch = 0x117e, // Character set switch + //Key_script_switch = 0x117e, // Alias for mode_switch + + // Japanese keyboard support + Key_Kanji = 0x1121, // Kanji, Kanji convert + Key_Muhenkan = 0x1122, // Cancel Conversion + //Key_Henkan_Mode = 0x1123, // Start/Stop Conversion + Key_Henkan = 0x1123, // Alias for Henkan_Mode + Key_Romaji = 0x1124, // to Romaji + Key_Hiragana = 0x1125, // to Hiragana + Key_Katakana = 0x1126, // to Katakana + Key_Hiragana_Katakana = 0x1127, // Hiragana/Katakana toggle + Key_Zenkaku = 0x1128, // to Zenkaku + Key_Hankaku = 0x1129, // to Hankaku + Key_Zenkaku_Hankaku = 0x112a, // Zenkaku/Hankaku toggle + Key_Touroku = 0x112b, // Add to Dictionary + Key_Massyo = 0x112c, // Delete from Dictionary + Key_Kana_Lock = 0x112d, // Kana Lock + Key_Kana_Shift = 0x112e, // Kana Shift + Key_Eisu_Shift = 0x112f, // Alphanumeric Shift + Key_Eisu_toggle = 0x1130, // Alphanumeric toggle + //Key_Kanji_Bangou = 0x1137, // Codeinput + //Key_Zen_Koho = 0x113d, // Multiple/All Candidate(s) + //Key_Mae_Koho = 0x113e, // Previous Candidate + + // Korean keyboard support + // + // In fact, many Korean users need only 2 keys, Key_Hangul and + // Key_Hangul_Hanja. But rest of the keys are good for future. + + Key_Hangul = 0x1131, // Hangul start/stop(toggle) + Key_Hangul_Start = 0x1132, // Hangul start + Key_Hangul_End = 0x1133, // Hangul end, English start + Key_Hangul_Hanja = 0x1134, // Start Hangul->Hanja Conversion + Key_Hangul_Jamo = 0x1135, // Hangul Jamo mode + Key_Hangul_Romaja = 0x1136, // Hangul Romaja mode + //Key_Hangul_Codeinput = 0x1137, // Hangul code input mode + Key_Hangul_Jeonja = 0x1138, // Jeonja mode + Key_Hangul_Banja = 0x1139, // Banja mode + Key_Hangul_PreHanja = 0x113a, // Pre Hanja conversion + Key_Hangul_PostHanja = 0x113b, // Post Hanja conversion + //Key_Hangul_SingleCandidate = 0x113c, // Single candidate + //Key_Hangul_MultipleCandidate = 0x113d, // Multiple candidate + //Key_Hangul_PreviousCandidate = 0x113e, // Previous candidate + Key_Hangul_Special = 0x113f, // Special symbols + //Key_Hangul_switch = 0x117e, // Alias for mode_switch + + // dead keys (X keycode - 0xED00 to avoid the conflict) + Key_Dead_Grave = 0x1250, + Key_Dead_Acute = 0x1251, + Key_Dead_Circumflex = 0x1252, + Key_Dead_Tilde = 0x1253, + Key_Dead_Macron = 0x1254, + Key_Dead_Breve = 0x1255, + Key_Dead_Abovedot = 0x1256, + Key_Dead_Diaeresis = 0x1257, + Key_Dead_Abovering = 0x1258, + Key_Dead_Doubleacute = 0x1259, + Key_Dead_Caron = 0x125a, + Key_Dead_Cedilla = 0x125b, + Key_Dead_Ogonek = 0x125c, + Key_Dead_Iota = 0x125d, + Key_Dead_Voiced_Sound = 0x125e, + Key_Dead_Semivoiced_Sound = 0x125f, + Key_Dead_Belowdot = 0x1260, + Key_Dead_Hook = 0x1261, + Key_Dead_Horn = 0x1262, + Key_Space = (int)Qt::Key_Space, // 7 bit printable ASCII Key_Any = Key_Space, Key_Exclam = (int)Qt::Key_Exclam, @@ -703,6 +786,11 @@ typedef Qt::Orientation Orientation; Key_AsciiTilde = (int)Qt::Key_AsciiTilde, // Latin 1 codes adapted from X: keysymdef.h,v 1.21 94/08/28 16:17:06 + // + // This is mainly for compatibility - applications and input + // methods should not use the TQt keycodes between 128 and 255, + // but should rather use the TQKeyEvent::text(). See + // TQETWidget::translateKeyEventInternal() for more details. Key_nobreakspace = (int)Qt::Key_nobreakspace, Key_exclamdown = (int)Qt::Key_exclamdown, diff --git a/tqtinterface/qt4/src/kernel/tqpaintdevice_x11.cpp b/tqtinterface/qt4/src/kernel/tqpaintdevice_x11.cpp index 2432607..fd4cc0b 100644 --- a/tqtinterface/qt4/src/kernel/tqpaintdevice_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqpaintdevice_x11.cpp @@ -1105,11 +1105,16 @@ static void create_dpis() TQ_CHECK_PTR( dpisX ); TQ_CHECK_PTR( dpisY ); for ( i = 0; i < screens; i++ ) { - dpisX[ i ] = (DisplayWidth(dpy,i) * 254 + DisplayWidthMM(dpy,i)*5) - - / (DisplayWidthMM(dpy,i)*10); - dpisY[ i ] = (DisplayHeight(dpy,i) * 254 + DisplayHeightMM(dpy,i)*5) - / (DisplayHeightMM(dpy,i)*10); + if (DisplayWidthMM(dpy,i) < 1) + dpisX[ i ] = 75; // default the dpi to 75. + else + dpisX[ i ] = (DisplayWidth(dpy,i) * 254 + DisplayWidthMM(dpy,i)*5) + / (DisplayWidthMM(dpy,i)*10); + if (DisplayHeightMM(dpy,i) < 1) + dpisY[ i ] = 75; // default the dpi to 75. + else + dpisY[ i ] = (DisplayHeight(dpy,i) * 254 + DisplayHeightMM(dpy,i)*5) + / (DisplayHeightMM(dpy,i)*10); } } diff --git a/tqtinterface/qt4/src/kernel/tqpixmap_x11.cpp b/tqtinterface/qt4/src/kernel/tqpixmap_x11.cpp index 974f23c..2a497e5 100644 --- a/tqtinterface/qt4/src/kernel/tqpixmap_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqpixmap_x11.cpp @@ -40,7 +40,19 @@ // NOT REVISED +#include "tqplatformdefs.h" + +#if defined(Q_OS_WIN32) && defined(TQT_MITSHM) +#undef TQT_MITSHM +#endif + +#ifdef TQT_MITSHM + +// Use the MIT Shared Memory extension for pixmap<->image conversions +#define TQT_MITSHM_CONVERSIONS + // Uncomment the next line to enable the MIT Shared Memory extension +// for TQPixmap::xForm() // // WARNING: This has some problems: // @@ -48,7 +60,7 @@ // 2. TQt does not handle the ShmCompletion message, so you will // get strange effects if you xForm() repeatedly. // -// #define TQT_MITSHM +// #define TQT_MITSHM_XFORM #if defined(TQ_OS_WIN32) && defined(TQT_MITSHM) #undef TQT_MITSHM @@ -131,7 +143,7 @@ inline static void qSafeXDestroyImage( XImage *x ) MIT Shared Memory Extension support: makes xForm noticeably (~20%) faster. *****************************************************************************/ -#if defined(TQT_MITSHM) +#if defined(TQT_MITSHM_XFORM) static bool xshminit = FALSE; static XShmSegmentInfo xshminfo; @@ -213,8 +225,100 @@ static bool qt_create_mitshm_buffer( const TQPaintDevice* dev, int w, int h ) // return FALSE; // } -#endif // TQT_MITSHM +#endif // TQT_MITSHM_XFORM + +#ifdef TQT_MITSHM_CONVERSIONS + +static bool qt_mitshm_error = false; +static int qt_mitshm_errorhandler( Display*, XErrorEvent* ) +{ + qt_mitshm_error = true; + return 0; +} + +static XImage* qt_XShmCreateImage( Display* dpy, Visual* visual, unsigned int depth, + int format, int /*offset*/, char* /*data*/, unsigned int width, unsigned int height, + int /*bitmap_pad*/, int /*bytes_per_line*/, XShmSegmentInfo* shminfo ) +{ + if( width * height * depth < 100*100*32 ) + return NULL; + static int shm_inited = -1; + if( shm_inited == -1 ) { + if( XShmQueryExtension( dpy )) + shm_inited = 1; + else + shm_inited = 0; + } + if( shm_inited == 0 ) + return NULL; + XImage* xi = XShmCreateImage( dpy, visual, depth, format, NULL, shminfo, width, + height ); + if( xi == NULL ) + return NULL; + shminfo->shmid = shmget( IPC_PRIVATE, xi->bytes_per_line * xi->height, + IPC_CREAT|0600); + if( shminfo->shmid < 0 ) { + XDestroyImage( xi ); + return NULL; + } + shminfo->readOnly = False; + shminfo->shmaddr = (char*)shmat( shminfo->shmid, 0, 0 ); + if( shminfo->shmaddr == (char*)-1 ) { + XDestroyImage( xi ); + shmctl( shminfo->shmid, IPC_RMID, 0 ); + return NULL; + } + xi->data = shminfo->shmaddr; +#ifndef TQT_MITSHM_RMID_IGNORES_REFCOUNT + // mark as deleted to automatically free the memory in case + // of a crash (but this doesn't work e.g. on Solaris) + shmctl( shminfo->shmid, IPC_RMID, 0 ); +#endif + if( shm_inited == 1 ) { // first time + XErrorHandler old_h = XSetErrorHandler( qt_mitshm_errorhandler ); + XShmAttach( dpy, shminfo ); + shm_inited = 2; + XSync( dpy, False ); + XSetErrorHandler( old_h ); + if( qt_mitshm_error ) { // oops ... perhaps we are remote? + shm_inited = 0; + XDestroyImage( xi ); + shmdt( shminfo->shmaddr ); +#ifdef TQT_MITSHM_RMID_IGNORES_REFCOUNT + shmctl( shminfo->shmid, IPC_RMID, 0 ); +#endif + return NULL; + } + } else + XShmAttach( dpy, shminfo ); + return xi; +} + +static void qt_XShmDestroyImage( XImage* xi, XShmSegmentInfo* shminfo ) +{ + XShmDetach( TQPaintDevice::x11AppDisplay(), shminfo ); + XDestroyImage( xi ); + shmdt( shminfo->shmaddr ); +#ifdef TQT_MITSHM_RMID_IGNORES_REFCOUNT + shmctl( shminfo->shmid, IPC_RMID, 0 ); +#endif +} +static XImage* qt_XShmGetImage( const TQPixmap* pix, int format, + XShmSegmentInfo* shminfo ) +{ + XImage* xi = qt_XShmCreateImage( pix->x11Display(), (Visual*)pix->x11Visual(), + pix->depth(), format, 0, 0, pix->width(), pix->height(), 32, 0, shminfo ); + if( xi == NULL ) + return NULL; + if( XShmGetImage( pix->x11Display(), pix->handle(), xi, 0, 0, AllPlanes ) == False ) { + qt_XShmDestroyImage( xi, shminfo ); + return NULL; + } + return xi; +} + +#endif // TQT_MITSHM_CONVERSIONS /***************************************************************************** Internal functions @@ -667,9 +771,20 @@ TQImage TQPixmap::convertToImage() const d = 32; // > 8 ==> 32 XImage *xi = (XImage *)data->ximage; // any cached ximage? - if ( !xi ) // fetch data from X server +#ifdef TQT_MITSHM_CONVERSIONS + bool mitshm_ximage = false; + XShmSegmentInfo shminfo; +#endif + if ( !xi ) { // fetch data from X server +#ifdef TQT_MITSHM_CONVERSIONS + xi = qt_XShmGetImage( this, mono ? XYPixmap : ZPixmap, &shminfo ); + if( xi ) { + mitshm_ximage = true; + } else +#endif xi = XGetImage( x11Display(), hd, 0, 0, w, h, AllPlanes, mono ? XYPixmap : ZPixmap ); + } TQ_CHECK_PTR( xi ); if (!xi) return image; // null image @@ -680,15 +795,31 @@ TQImage TQPixmap::convertToImage() const TQImage::LittleEndian : TQImage::BigEndian; } image.create( w, h, d, 0, bitOrder ); - if ( image.isNull() ) // could not create image + if ( image.isNull() ) { // could not create image +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_ximage ) + qt_XShmDestroyImage( xi, &shminfo ); + else +#endif + qSafeXDestroyImage( xi ); return image; + } const TQPixmap* msk = tqmask(); const TQPixmap *alf = data->alphapm; TQImage alpha; if (alf) { - XImage *axi = XGetImage(x11Display(), alf->hd, 0, 0, w, h, AllPlanes, ZPixmap); + XImage* axi; +#ifdef TQT_MITSHM_CONVERSIONS + bool mitshm_aximage = false; + XShmSegmentInfo ashminfo; + axi = qt_XShmGetImage( alf, ZPixmap, &ashminfo ); + if( axi ) { + mitshm_aximage = true; + } else +#endif + axi = XGetImage(x11Display(), alf->hd, 0, 0, w, h, AllPlanes, ZPixmap); if (axi) { image.setAlphaBuffer( TRUE ); @@ -702,6 +833,11 @@ TQImage TQPixmap::convertToImage() const src += axi->bytes_per_line; } +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_aximage ) + qt_XShmDestroyImage( axi, &ashminfo ); + else +#endif qSafeXDestroyImage( axi ); } } else if (msk) { @@ -844,6 +980,12 @@ TQImage TQPixmap::convertToImage() const xi->bits_per_pixel ); #endif image.reset(); +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_ximage ) + qt_XShmDestroyImage( xi, &shminfo ); + else +#endif + qSafeXDestroyImage( xi ); return image; } @@ -949,10 +1091,22 @@ TQImage TQPixmap::convertToImage() const delete [] carr; } if ( data->optim != BestOptim ) { // throw away image data +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_ximage ) + qt_XShmDestroyImage( xi, &shminfo ); + else +#endif qSafeXDestroyImage( xi ); ((TQPixmap*)this)->data->ximage = 0; - } else // keep ximage data + } else { // keep ximage data +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_ximage ) { // copy the XImage? + qt_XShmDestroyImage( xi, &shminfo ); + xi = 0; + } +#endif ((TQPixmap*)this)->data->ximage = xi; + } return image; } @@ -1125,6 +1279,11 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) bool trucol = (visual->c_class == TrueColor || visual->c_class == DirectColor); int nbytes = image.numBytes(); uchar *newbits= 0; + int newbits_size = 0; +#ifdef TQT_MITSHM_CONVERSIONS + bool mitshm_ximage = false; + XShmSegmentInfo shminfo; +#endif if ( trucol ) { // truecolor display TQRgb pix[256]; // pixel translation table @@ -1153,19 +1312,24 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) } } +#ifdef TQT_MITSHM_CONVERSIONS + xi = qt_XShmCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0, &shminfo ); + if( xi != NULL ) { + mitshm_ximage = true; + newbits = (uchar*)xi->data; + } + else +#endif xi = XCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0 ); - TQ_CHECK_PTR( xi ); if (!xi) return false; + if( newbits == NULL ) newbits = (uchar *)malloc( xi->bytes_per_line*h ); TQ_CHECK_PTR( newbits ); if ( !newbits ) // no memory return FALSE; int bppc = xi->bits_per_pixel; - if ( bppc > 8 && xi->byte_order == LSBFirst ) - bppc++; - bool contig_bits = n_bits(red_mask) == rbits && n_bits(green_mask) == gbits && n_bits(blue_mask) == bbits; @@ -1215,31 +1379,70 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) init=TRUE; } - for ( uint y=0; y<h; y++ ) { - uchar* src = image.scanLine( y ); - uchar* dst = newbits + xi->bytes_per_line*y; - TQRgb* p = (TQRgb *)src; + enum { BPP8, + BPP16_8_3_M3, BPP16_7_2_M3, BPP16_MSB, BPP16_LSB, + BPP24_MSB, BPP24_LSB, + BPP32_16_8_0, BPP32_MSB, BPP32_LSB + } mode = BPP8; -#define GET_RGB \ - int r = tqRed ( *p ); \ - int g = tqGreen( *p ); \ - int b = tqBlue ( *p++ ); \ - r = red_shift > 0 \ - ? r << red_shift : r >> -red_shift; \ - g = green_shift > 0 \ - ? g << green_shift : g >> -green_shift; \ - b = blue_shift > 0 \ - ? b << blue_shift : b >> -blue_shift; + if ( bppc > 8 && xi->byte_order == LSBFirst ) + bppc++; + + int wordsize; + bool bigendian; + qSysInfo( &wordsize, &bigendian ); + bool same_msb_lsb = ( xi->byte_order == MSBFirst ) == ( bigendian ); + + if( bppc == 8 ) // 8 bit + mode = BPP8; + else if( bppc == 16 || bppc == 17 ) { // 16 bit MSB/LSB + if( red_shift == 8 && green_shift == 3 && blue_shift == -3 + && !d8 && same_msb_lsb ) + mode = BPP16_8_3_M3; + else if( red_shift == 7 && green_shift == 2 && blue_shift == -3 + && !d8 && same_msb_lsb ) + mode = BPP16_7_2_M3; + else + mode = bppc == 17 ? BPP16_LSB : BPP16_MSB; + } else if( bppc == 24 || bppc == 25 ) { // 24 bit MSB/LSB + mode = bppc == 25 ? BPP24_LSB : BPP24_MSB; + } else if( bppc == 32 || bppc == 33 ) { // 32 bit MSB/LSB + if( red_shift == 16 && green_shift == 8 && blue_shift == 0 + && !d8 && same_msb_lsb ) + mode = BPP32_16_8_0; + else + mode = bppc == 33 ? BPP32_LSB : BPP32_MSB; + } else + qFatal("Logic error 3"); #define GET_PIXEL \ int pixel; \ if ( d8 ) pixel = pix[*src++]; \ else { \ - GET_RGB \ - pixel = (b & blue_mask)|(g & green_mask) | (r & red_mask) \ + int r = tqRed ( *p ); \ + int g = tqGreen( *p ); \ + int b = tqBlue ( *p++ ); \ + r = red_shift > 0 \ + ? r << red_shift : r >> -red_shift; \ + g = green_shift > 0 \ + ? g << green_shift : g >> -green_shift; \ + b = blue_shift > 0 \ + ? b << blue_shift : b >> -blue_shift; \ + pixel = (r & red_tqmask)|(g & green_tqmask) | (b & blue_tqmask) \ | ~(blue_mask | green_mask | red_mask); \ } +// optimized case - no d8 case, shift only once instead of twice, tqmask only once instead of twice, +// use direct values instead of variables, and use only one statement +// (*p >> 16), (*p >> 8 ) and (*p) are tqRed(),tqGreen() and tqBlue() without masking +// shifts have to be passed including the shift operator (e.g. '>>3'), because of the direction +#define GET_PIXEL_OPT(red_shift,green_shift,blue_shift,red_tqmask,green_tqmask,blue_tqmask) \ + int pixel = ((( *p >> 16 ) red_shift ) & red_tqmask ) \ + | ((( *p >> 8 ) green_shift ) & green_tqmask ) \ + | ((( *p ) blue_shift ) & blue_tqmask ); \ + ++p; + + #define GET_PIXEL_DITHER_TC \ int r = tqRed ( *p ); \ int g = tqGreen( *p ); \ @@ -1262,89 +1465,176 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) ? b << blue_shift : b >> -blue_shift; \ int pixel = (b & blue_mask)|(g & green_mask) | (r & red_mask); - if ( dither_tc ) { - uint x; - switch ( bppc ) { - case 16: // 16 bit MSB - for ( x=0; x<w; x++ ) { - GET_PIXEL_DITHER_TC - *dst++ = (pixel >> 8); - *dst++ = pixel; - } +// again, optimized case +// can't be optimized that much :( +#define GET_PIXEL_DITHER_TC_OPT(red_shift,green_shift,blue_shift,red_tqmask,green_tqmask,blue_tqmask, \ + rbits,gbits,bbits) \ + const int thres = D[x%16][y%16]; \ + int r = tqRed ( *p ); \ + if ( r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \ + > thres) \ + r += (1<<(8-rbits)); \ + int g = tqGreen( *p ); \ + if ( g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \ + > thres) \ + g += (1<<(8-gbits)); \ + int b = tqBlue ( *p++ ); \ + if ( b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \ + > thres) \ + b += (1<<(8-bbits)); \ + int pixel = (( r red_shift ) & red_tqmask ) \ + | (( g green_shift ) & green_tqmask ) \ + | (( b blue_shift ) & blue_tqmask ); + +#define CYCLE(body) \ + for ( uint y=0; y<h; y++ ) { \ + uchar* src = image.scanLine( y ); \ + uchar* dst = newbits + xi->bytes_per_line*y; \ + TQRgb* p = (TQRgb *)src; \ + body \ + } + + if ( dither_tc ) { + switch ( mode ) { + case BPP16_8_3_M3: + CYCLE( + TQ_INT16* dst16 = (TQ_INT16*)dst; + for ( uint x=0; x<w; x++ ) { + GET_PIXEL_DITHER_TC_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f,5,6,5) + *dst16++ = pixel; + } + ) break; - case 17: // 16 bit LSB - for ( x=0; x<w; x++ ) { - GET_PIXEL_DITHER_TC - *dst++ = pixel; - *dst++ = pixel >> 8; - } + case BPP16_7_2_M3: + CYCLE( + TQ_INT16* dst16 = (TQ_INT16*)dst; + for ( uint x=0; x<w; x++ ) { + GET_PIXEL_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f) + *dst16++ = pixel; + } + ) break; default: qFatal("Logic error"); } - } else { - uint x; - switch ( bppc ) { - case 8: // 8 bit - for ( x=0; x<w; x++ ) { - int pixel = pix[*src++]; - *dst++ = pixel; - } + } else { + switch ( mode ) { + case BPP8: // 8 bit + CYCLE( + Q_UNUSED(p); + for ( uint x=0; x<w; x++ ) { + int pixel = pix[*src++]; + *dst++ = pixel; + } + ) break; - case 16: // 16 bit MSB - for ( x=0; x<w; x++ ) { - GET_PIXEL - *dst++ = (pixel >> 8); - *dst++ = pixel; - } + case BPP16_8_3_M3: + CYCLE( + TQ_INT16* dst16 = (TQ_INT16*)dst; + for ( uint x=0; x<w; x++ ) { + GET_PIXEL_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f) + *dst16++ = pixel; + } + ) break; - case 17: // 16 bit LSB - for ( x=0; x<w; x++ ) { - GET_PIXEL - *dst++ = pixel; - *dst++ = pixel >> 8; - } + case BPP16_7_2_M3: + CYCLE( + TQ_INT16* dst16 = (TQ_INT16*)dst; + for ( uint x=0; x<w; x++ ) { + GET_PIXEL_DITHER_TC_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f,5,5,5) + *dst16++ = pixel; + } + ) break; - case 24: // 24 bit MSB - for ( x=0; x<w; x++ ) { - GET_PIXEL - *dst++ = pixel >> 16; - *dst++ = pixel >> 8; - *dst++ = pixel; - } + case BPP16_MSB: // 16 bit MSB + CYCLE( + for ( uint x=0; x<w; x++ ) { + GET_PIXEL_DITHER_TC + *dst++ = (pixel >> 8); + *dst++ = pixel; + } + ) break; - case 25: // 24 bit LSB - for ( x=0; x<w; x++ ) { - GET_PIXEL - *dst++ = pixel; - *dst++ = pixel >> 8; - *dst++ = pixel >> 16; - } + case BPP16_LSB: // 16 bit LSB + CYCLE( + for ( uint x=0; x<w; x++ ) { + GET_PIXEL_DITHER_TC + *dst++ = pixel; + *dst++ = pixel >> 8; + } + ) break; - case 32: // 32 bit MSB - for ( x=0; x<w; x++ ) { - GET_PIXEL - *dst++ = pixel >> 24; - *dst++ = pixel >> 16; - *dst++ = pixel >> 8; - *dst++ = pixel; - } + case BPP16_MSB: // 16 bit MSB + CYCLE( + for ( uint x=0; x<w; x++ ) { + GET_PIXEL + *dst++ = (pixel >> 8); + *dst++ = pixel; + } + ) + break; + case BPP16_LSB: // 16 bit LSB + CYCLE( + for ( uint x=0; x<w; x++ ) { + GET_PIXEL + *dst++ = pixel; + *dst++ = pixel >> 8; + } + ) + break; + case BPP24_MSB: // 24 bit MSB + CYCLE( + for ( uint x=0; x<w; x++ ) { + GET_PIXEL + *dst++ = pixel >> 16; + *dst++ = pixel >> 8; + *dst++ = pixel; + } + ) break; case 33: // 32 bit LSB - for ( x=0; x<w; x++ ) { - GET_PIXEL - *dst++ = pixel; - *dst++ = pixel >> 8; - *dst++ = pixel >> 16; - *dst++ = pixel >> 24; - } + case BPP24_LSB: // 24 bit LSB + CYCLE( + for ( uint x=0; x<w; x++ ) { + GET_PIXEL + *dst++ = pixel; + *dst++ = pixel >> 8; + *dst++ = pixel >> 16; + } + ) break; - default: - qFatal("Logic error 2"); - } - } - } - xi->data = (char *)newbits; + case BPP32_16_8_0: + CYCLE( + memcpy( dst, p, w * 4 ); + ) + break; + case BPP32_MSB: // 32 bit MSB + CYCLE( + for ( uint x=0; x<w; x++ ) { + GET_PIXEL + *dst++ = pixel >> 24; + *dst++ = pixel >> 16; + *dst++ = pixel >> 8; + *dst++ = pixel; + } + ) + break; + case BPP32_LSB: // 32 bit LSB + CYCLE( + for ( uint x=0; x<w; x++ ) { + GET_PIXEL + *dst++ = pixel; + *dst++ = pixel >> 8; + *dst++ = pixel >> 16; + *dst++ = pixel >> 24; + } + ) + break; + default: + qFatal("Logic error 2"); + } + } + xi->data = (char *)newbits; } if ( d == 8 && !trucol ) { // 8 bit pixmap @@ -1363,6 +1653,7 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) } newbits = (uchar *)malloc( nbytes ); // copy image into newbits + newbits_size = nbytes; TQ_CHECK_PTR( newbits ); if ( !newbits ) // no memory return FALSE; @@ -1479,12 +1770,19 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) } } - if ( !xi ) { // X image not created + if ( !xi ) { +#ifdef TQT_MITSHM_CONVERSIONS + xi = qt_XShmCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0, &shminfo ); + if( xi != NULL ) + mitshm_ximage = true; + else +#endif // X image not created xi = XCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0 ); if ( xi->bits_per_pixel == 16 ) { // convert 8 bpp ==> 16 bpp ushort *p2; int p2inc = xi->bytes_per_line/sizeof(ushort); ushort *newerbits = (ushort *)malloc( xi->bytes_per_line * h ); + newbits_size = xi->bytes_per_line * h; TQ_CHECK_PTR( newerbits ); if ( !newerbits ) // no memory return FALSE; @@ -1502,6 +1800,14 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) "(bpp=%d)", xi->bits_per_pixel ); #endif } +#ifdef TQT_MITSHM_CONVERSIONS + if( newbits_size > 0 && mitshm_ximage ) { // need to copy to shared memory + memcpy( xi->data, newbits, newbits_size ); + free( newbits ); + newbits = (uchar*)xi->data; + } + else +#endif xi->data = (char *)newbits; } @@ -1535,19 +1841,24 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) } +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_ximage ) + XShmPutImage( dpy, hd, qt_xget_readonly_gc( x11Screen(), FALSE ), + xi, 0, 0, 0, 0, w, h, False ); + else +#endif XPutImage( dpy, hd, qt_xget_readonly_gc( x11Screen(), FALSE ), xi, 0, 0, 0, 0, w, h ); - if ( data->optim != BestOptim ) { // throw away image - qSafeXDestroyImage( xi ); - data->ximage = 0; - } else { // keep ximage that we created - data->ximage = xi; - } data->w = w; data->h = h; data->d = dd; + XImage* axi = NULL; +#ifdef TQT_MITSHM_CONVERSIONS + bool mitshm_aximage = false; + XShmSegmentInfo ashminfo; +#endif if ( image.hasAlphaBuffer() ) { TQBitmap m; m = image.createAlphaMask( conversion_flags ); @@ -1583,38 +1894,90 @@ bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags ) data->alphapm->rendhd = (HANDLE) XftDrawCreateAlpha( x11Display(), data->alphapm->hd, 8 ); - XImage *axi = XCreateImage(x11Display(), (Visual *) x11Visual(), +#ifdef TQT_MITSHM_CONVERSIONS + axi = qt_XShmCreateImage( x11Display(), (Visual*)x11Visual(), + 8, ZPixmap, 0, 0, w, h, 8, 0, &ashminfo ); + if( axi != NULL ) + mitshm_aximage = true; + else +#endif + axi = XCreateImage(x11Display(), (Visual *) x11Visual(), 8, ZPixmap, 0, 0, w, h, 8, 0); if (axi) { + if( axi->data==NULL ) { // the data is deleted by qSafeXDestroyImage axi->data = (char *) malloc(h * axi->bytes_per_line); TQ_CHECK_PTR( axi->data ); + } char *aptr = axi->data; if (image.depth() == 32) { const int *iptr = (const int *) image.bits(); - int max = w * h; - while (max--) - *aptr++ = *iptr++ >> 24; // squirt + if( axi->bytes_per_line == (int)w ) { + int max = w * h; + while (max--) + *aptr++ = *iptr++ >> 24; // squirt + } else { + for (uint i = 0; i < h; ++i ) { + for (uint j = 0; j < w; ++j ) + *aptr++ = *iptr++ >> 24; // squirt + aptr += ( axi->bytes_per_line - w ); + } + } } else if (image.depth() == 8) { const TQRgb * const rgb = image.colorTable(); for (uint y = 0; y < h; ++y) { const uchar *iptr = image.scanLine(y); for (uint x = 0; x < w; ++x) *aptr++ = tqAlpha(rgb[*iptr++]); + aptr += ( axi->bytes_per_line - w ); } } GC gc = XCreateGC(x11Display(), data->alphapm->hd, 0, 0); + #ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_aximage ) + XShmPutImage( dpy, data->alphapm->hd, gc, axi, 0, 0, 0, 0, w, h, False ); + else +#endif XPutImage(dpy, data->alphapm->hd, gc, axi, 0, 0, 0, 0, w, h); XFreeGC(x11Display(), gc); - qSafeXDestroyImage(axi); } } #endif // TQT_NO_XFTFREETYPE } +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_ximage || mitshm_aximage ) + XSync( x11Display(), False ); // wait until processed +#endif + + if ( data->optim != BestOptim ) { // throw away image +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_ximage ) + qt_XShmDestroyImage( xi, &shminfo ); + else +#endif + qSafeXDestroyImage( xi ); + data->ximage = 0; + } else { // keep ximage that we created +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_ximage ) { // copy the XImage? + qt_XShmDestroyImage( xi, &shminfo ); + xi = 0; + } +#endif + data->ximage = xi; + } + if( axi ) { +#ifdef TQT_MITSHM_CONVERSIONS + if( mitshm_aximage ) + qt_XShmDestroyImage( axi, &ashminfo ); + else +#endif + qSafeXDestroyImage(axi); + } return TRUE; } @@ -1777,7 +2140,7 @@ TQPixmap TQPixmap::xForm( const TQWMatrix &matrix ) const return pm; } -#if defined(TQT_MITSHM) +#if defined(TQT_MITSHM_XFORM) static bool try_once = TRUE; if (try_once) { try_once = FALSE; @@ -1810,7 +2173,7 @@ TQPixmap TQPixmap::xForm( const TQWMatrix &matrix ) const dbpl = ((w*bpp+31)/32)*4; dbytes = dbpl*h; -#if defined(TQT_MITSHM) +#if defined(TQT_MITSHM_XFORM) if ( use_mitshm ) { dptr = (uchar *)xshmimg->data; uchar fillbyte = bpp == 8 ? white.pixel() : 0xff; @@ -1826,7 +2189,7 @@ TQPixmap TQPixmap::xForm( const TQWMatrix &matrix ) const memset( dptr, TQt::white.pixel( x11Screen() ), dbytes ); else memset( dptr, 0xff, dbytes ); -#if defined(TQT_MITSHM) +#if defined(TQT_MITSHM_XFORM) } #endif @@ -1857,7 +2220,7 @@ TQPixmap TQPixmap::xForm( const TQWMatrix &matrix ) const } else { xbpl = (w*bpp)/8; p_inc = dbpl - xbpl; -#if defined(TQT_MITSHM) +#if defined(TQT_MITSHM_XFORM) if ( use_mitshm ) p_inc = xshmimg->bytes_per_line - xbpl; #endif @@ -1894,7 +2257,7 @@ TQPixmap TQPixmap::xForm( const TQWMatrix &matrix ) const TQPixmap pm( w, h ); pm.data->uninit = FALSE; pm.x11SetScreen( x11Screen() ); -#if defined(TQT_MITSHM) +#if defined(TQT_MITSHM_XFORM) if ( use_mitshm ) { XCopyArea( dpy, xshmpm, pm.handle(), gc, 0, 0, w, h, 0, 0 ); } else { @@ -1903,7 +2266,7 @@ TQPixmap TQPixmap::xForm( const TQWMatrix &matrix ) const ZPixmap, 0, (char *)dptr, w, h, 32, 0 ); XPutImage( dpy, pm.handle(), gc, xi, 0, 0, 0, 0, w, h); qSafeXDestroyImage( xi ); -#if defined(TQT_MITSHM) +#if defined(TQT_MITSHM_XFORM) } #endif diff --git a/tqtinterface/qt4/src/kernel/tqrichtext.cpp b/tqtinterface/qt4/src/kernel/tqrichtext.cpp index 8b614d6..00484d6 100644 --- a/tqtinterface/qt4/src/kernel/tqrichtext.cpp +++ b/tqtinterface/qt4/src/kernel/tqrichtext.cpp @@ -9028,7 +9028,7 @@ void TQTextCursor::restoreState() pop(); } -bool TQTextCursor::place( const TQPoint &p, TQTextParagraph *s, bool link ) +bool TQTextCursor::place( const TQPoint &p, TQTextParagraph *s, bool link, bool loosePlacing, bool matchBetweenCharacters ) { TQPoint pos( p ); TQRect r; @@ -9046,7 +9046,7 @@ bool TQTextCursor::place( const TQPoint &p, TQTextParagraph *s, bool link ) str = s; if ( pos.y() >= r.y() && pos.y() <= r.y() + r.height() ) break; - if ( !s->next() ) { + if ( loosePlacing == TRUE && !s->next() ) { #ifdef TQ_WS_MACX pos.setX( s->rect().x() + s->rect().width() ); #endif @@ -9087,7 +9087,7 @@ bool TQTextCursor::place( const TQPoint &p, TQTextParagraph *s, bool link ) if ( pos.x() < x ) pos.setX( x + 1 ); int cw; - int curpos = s->length()-1; + int curpos = -1; int dist = 10000000; bool inCustom = FALSE; while ( i < nextLine ) { @@ -9109,14 +9109,21 @@ bool TQTextCursor::place( const TQPoint &p, TQTextParagraph *s, bool link ) cpos += cw; int d = cpos - pos.x(); bool dm = d < 0 ? !chr->rightToLeft : chr->rightToLeft; - if ( (TQABS( d ) < dist || (dist == d && dm == TRUE )) && para->string()->validCursorPosition( i ) ) { + if ( ( matchBetweenCharacters == TRUE && (TQABS( d ) < dist || (dist == d && dm == TRUE )) && para->string()->validCursorPosition( i ) ) || + ( matchBetweenCharacters == FALSE && ( d == 0 || dm == TRUE ) ) ) { dist = TQABS( d ); - if ( !link || pos.x() >= x + chr->x ) + if ( !link || ( pos.x() >= x + chr->x && ( loosePlacing == TRUE || pos.x() < cpos ) ) ) curpos = i; } } i++; } + if ( curpos == -1 ) { + if ( loosePlacing == TRUE ) + curpos = s->length()-1; + else + return FALSE; + } setIndex( curpos ); #ifndef TQT_NO_TEXTCUSTOMITEM @@ -13244,6 +13251,9 @@ void TQTextParagraph::drawString( TQPainter &painter, const TQString &str, int s tmpw = fullSelectionWidth - xleft; painter.fillRect( xleft, y, tmpw, h, color ); painter.drawText( xstart, y + baseLine, str, start, len, dir ); + // draw preedit's underline + if (selection == TQTextDocument::IMCompositionText) + painter.drawLine(xstart, y + baseLine + 1, xstart + w, y + baseLine + 1); if (selStart != start || selEnd != start + len || selWrap) painter.restore(); } diff --git a/tqtinterface/qt4/src/kernel/tqrichtext_p.h b/tqtinterface/qt4/src/kernel/tqrichtext_p.h index b9cbd98..edb8c76 100644 --- a/tqtinterface/qt4/src/kernel/tqrichtext_p.h +++ b/tqtinterface/qt4/src/kernel/tqrichtext_p.h @@ -2523,7 +2523,8 @@ public: int totalOffsetY() const; // total document offset bool place( const TQPoint &pos, TQTextParagraph *s ) { return place( pos, s, FALSE ); } - bool place( const TQPoint &pos, TQTextParagraph *s, bool link ); + bool place( const TQPoint &pos, TQTextParagraph *s, bool link ) { return place( pos, s, link, TRUE, TRUE ); } + bool place( const TQPoint &pos, TQTextParagraph *s, bool link, bool loosePlacing, bool matchBetweenCharacters ); void restoreState(); diff --git a/tqtinterface/qt4/src/kernel/tqt_x11_p.h b/tqtinterface/qt4/src/kernel/tqt_x11_p.h index e08531d..a33ce01 100644 --- a/tqtinterface/qt4/src/kernel/tqt_x11_p.h +++ b/tqtinterface/qt4/src/kernel/tqt_x11_p.h @@ -177,6 +177,11 @@ extern "C" { #endif // TQT_NO_XRENDER +#ifndef TQT_NO_XSYNC +# include <X11/extensions/sync.h> +#endif // TQT_NO_XSYNC + + #ifndef TQT_NO_XKB # include <X11/XKBlib.h> #endif // TQT_NO_XKB diff --git a/tqtinterface/qt4/src/kernel/tqwidget.cpp b/tqtinterface/qt4/src/kernel/tqwidget.cpp index 9e60bac..67d0e1b 100644 --- a/tqtinterface/qt4/src/kernel/tqwidget.cpp +++ b/tqtinterface/qt4/src/kernel/tqwidget.cpp @@ -5953,8 +5953,24 @@ void TQWidget::setFocus() if ( isActiveWindow() ) { TQWidget * prev = tqApp->focus_widget; if ( prev ) { - if ( prev != this ) + // This part is never executed when TQ_WS_X11? Preceding XFocusOut + // had already reset focus_widget when received XFocusIn + + // Don't reset input context explicitly here. Whether reset or not + // when focusing out is a responsibility of input methods. For + // example, Japanese input context should not be reset here. The + // context sometimes contains a whole paragraph and has minutes of + // lifetime different to ephemeral one in other languages. The + // input context should be survived until focused again. So we + // delegate the responsibility to input context via + // unfocusInputContext(). + if ( prev != this && prev->isInputMethodEnabled() ) { +#if 0 prev->resetInputContext(); +#else + prev->unfocusInputContext(); +#endif + } } #if defined(TQ_WS_WIN) else { @@ -5962,9 +5978,8 @@ void TQWidget::setFocus() } #endif tqApp->focus_widget = this; -#if defined(TQ_WS_X11) - focusInputContext(); -#endif + if( isInputMethodEnabled() ) + focusInputContext(); #if defined(TQ_WS_WIN) if ( !tqtopLevelWidget()->isPopup() ) @@ -6012,7 +6027,11 @@ void TQWidget::clearFocus() focusProxy()->clearFocus(); return; } else if ( hasFocus() ) { +#if !defined(TQ_WS_X11) resetInputContext(); +#else + unfocusInputContext(); +#endif TQWidget* w = tqApp->tqfocusWidget(); // clear active focus tqApp->focus_widget = 0; @@ -7338,7 +7357,13 @@ bool TQWidget::event( TQEvent *e ) break; case TQEvent::MouseButtonPress: + // Don't reset input context here. Whether reset or not is + // a responsibility of input method. reset() will be + // called by mouseHandler() of input method if necessary + // via mousePressEvent() of text widgets. +#if 0 resetInputContext(); +#endif mousePressEvent( (TQMouseEvent*)e ); if ( ! ((TQMouseEvent*)e)->isAccepted() ) return FALSE; diff --git a/tqtinterface/qt4/src/kernel/tqwidget.h b/tqtinterface/qt4/src/kernel/tqwidget.h index c027464..65b424e 100644 --- a/tqtinterface/qt4/src/kernel/tqwidget.h +++ b/tqtinterface/qt4/src/kernel/tqwidget.h @@ -64,6 +64,10 @@ #endif // TQFONTENGINE_P_H #endif // USE_QT4 +#if defined(TQ_WS_X11) && !defined(TQT_NO_IM) +class TQInputContext; +#endif + class TQLayout; #ifdef USE_QT4 @@ -980,7 +984,19 @@ public: CGContextRef macCGContext(bool clipped=TRUE) const; #endif #endif - +#if defined(TQ_WS_X11) + enum X11WindowType { + X11WindowTypeSelect, + X11WindowTypeCombo, + X11WindowTypeDND, + X11WindowTypeTooltip, + X11WindowTypeMenu, // torn-off + X11WindowTypeDropdown, + X11WindowTypePopup + }; + void x11SetWindowType( X11WindowType type = X11WindowTypeSelect ); + void x11SetWindowTransient( TQWidget* tqparent ); +#endif void setWindowOpacity(double level); double windowOpacity() const; @@ -1051,6 +1067,18 @@ protected: int metric( int ) const; +#if defined(TQ_WS_X11) +#if !defined(TQT_NO_IM_EXTENSIONS) + virtual TQWidget *icHolderWidget(); +#else + TQWidget *icHolderWidget(); +#endif + TQInputContext *getInputContext(); + void changeInputContext( const TQString & ); + void sendMouseEventToInputContext( int x, TQEvent::Type type, + TQt::ButtonState button, + TQt::ButtonState state ); +#endif void resetInputContext(); virtual void create( WId = 0, bool initializeWindow = TRUE, @@ -1082,14 +1110,25 @@ protected: private Q_SLOTS: void focusProxyDestroyed(); +#if defined(TQ_WS_X11) + void destroyInputContext(); +#endif private: void setFontSys( TQFont *f = 0 ); #if defined(TQ_WS_X11) void createInputContext(); - void destroyInputContext(); void focusInputContext(); + void unfocusInputContext(); void checkChildrenDnd(); + +#ifndef TQT_NO_XSYNC + void createSyncCounter(); + void destroySyncCounter(); + void incrementSyncCounter(); + void handleSyncRequest( void* ev ); +#endif + #elif defined(TQ_WS_MAC) uint own_id : 1, macDropEnabled : 1; EventHandlerRef window_event; @@ -1160,6 +1199,9 @@ private: #ifndef TQT_NO_LAYOUT TQLayout *lay_out; #endif +#if defined(TQ_WS_X11) && !defined(TQT_NO_IM) && !defined(TQT_NO_IM_EXTENSIONS) + TQInputContext *ic; // Input Context +#endif TQWExtra *extra; #if defined(TQ_WS_TQWS) TQRegion req_region; // Requested region @@ -1471,7 +1513,13 @@ struct TQ_EXPORT TQTLWExtra { uint dnd : 1; // DND properties installed uint uspos : 1; // User defined position uint ussize : 1; // User defined size - void *xic; // XIM Input Context +#if defined(TQT_NO_IM_EXTENSIONS) + void *xic; // Input Context +#endif +#ifndef TQT_NO_XSYNC + ulong syncCounter; + uint syncRequestValue[2]; +#endif #endif #if defined(TQ_WS_MAC) WindowGroupRef group; diff --git a/tqtinterface/qt4/src/kernel/tqwidget_x11.cpp b/tqtinterface/qt4/src/kernel/tqwidget_x11.cpp index f8c605a..c6e7abb 100644 --- a/tqtinterface/qt4/src/kernel/tqwidget_x11.cpp +++ b/tqtinterface/qt4/src/kernel/tqwidget_x11.cpp @@ -83,6 +83,11 @@ extern Atom qt_net_wm_window_type_menu; extern Atom qt_net_wm_window_type_utility; extern Atom qt_net_wm_window_type_splash; extern Atom qt_net_wm_window_type_override; +extern Atom qt_net_wm_window_type_dropdown_menu; +extern Atom qt_net_wm_window_type_popup_menu; +extern Atom qt_net_wm_window_type_combo; +extern Atom qt_net_wm_window_type_dnd; +extern Atom qt_net_wm_window_type_tooltip; extern Atom qt_net_wm_pid; extern Atom qt_net_wm_user_time; extern Atom qt_enlightenment_desktop; @@ -300,11 +305,9 @@ int qt_sip_count( TQWidget* ); bool qt_wstate_iconified( WId ); void qt_updated_rootinfo(); -#ifndef TQT_NO_XIM -#include "tqinputcontext_p.h" - -extern XIM qt_xim; -extern XIMStyle qt_xim_style; +#ifndef TQT_NO_IM +#include "tqinputcontext.h" +#include "tqinputcontextfactory.h" #endif // Paint event clipping magic @@ -322,6 +325,12 @@ extern bool qt_deferred_map_tqcontains(TQWidget *); static TQWidget *mouseGrb = 0; static TQWidget *keyboardGrb = 0; +#ifndef TQT_NO_XSYNC +extern Atom qt_net_wm_sync_request_counter; +extern Atom qt_net_wm_sync_request; +extern bool qt_use_xsync; +#endif + // defined in qfont_x11.cpp extern bool qt_has_xft; @@ -683,10 +692,6 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) x11Colormap() ); #endif // TQT_NO_XFTFREETYPE - // NET window types - long net_wintypes[7] = { 0, 0, 0, 0, 0, 0, 0 }; - int curr_wintype = 0; - // NET window states long net_winstates[6] = { 0, 0, 0, 0, 0, 0 }; int curr_winstate = 0; @@ -708,7 +713,6 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) if ( testWFlags(WStyle_Splash) ) { if (qt_net_supports(qt_net_wm_window_type_splash)) { clearWFlags( WX11BypassWM ); - net_wintypes[curr_wintype++] = qt_net_wm_window_type_splash; } else { setWFlags( WX11BypassWM | WStyle_Tool | WStyle_NoBorder ); } @@ -717,27 +721,22 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) mwmhints.decorations = 0L; mwmhints.flags |= (1L << 1); // MWM_HINTS_DECORATIONS - if ( testWFlags( WStyle_NoBorder ) ) { - // override netwm type - quick and easy for KDE noborder - net_wintypes[curr_wintype++] = qt_net_wm_window_type_override; - } else { - if ( testWFlags( WStyle_NormalBorder | WStyle_DialogBorder ) ) { - mwmhints.decorations |= (1L << 1); // MWM_DECOR_BORDER - mwmhints.decorations |= (1L << 2); // MWM_DECOR_RESIZEH - } + if ( testWFlags( WStyle_NormalBorder | WStyle_DialogBorder ) ) { + mwmhints.decorations |= (1L << 1); // MWM_DECOR_BORDER + mwmhints.decorations |= (1L << 2); // MWM_DECOR_RESIZEH + } - if ( testWFlags( WStyle_Title ) ) - mwmhints.decorations |= (1L << 3); // MWM_DECOR_TITLE + if ( testWFlags( WStyle_Title ) ) + mwmhints.decorations |= (1L << 3); // MWM_DECOR_TITLE - if ( testWFlags( WStyle_SysMenu ) ) - mwmhints.decorations |= (1L << 4); // MWM_DECOR_MENU + if ( testWFlags( WStyle_SysMenu ) ) + mwmhints.decorations |= (1L << 4); // MWM_DECOR_MENU - if ( testWFlags( WStyle_Minimize ) ) - mwmhints.decorations |= (1L << 5); // MWM_DECOR_MINIMIZE + if ( testWFlags( WStyle_Minimize ) ) + mwmhints.decorations |= (1L << 5); // MWM_DECOR_MINIMIZE - if ( testWFlags( WStyle_Maximize ) ) - mwmhints.decorations |= (1L << 6); // MWM_DECOR_MAXIMIZE - } + if ( testWFlags( WStyle_Maximize ) ) + mwmhints.decorations |= (1L << 6); // MWM_DECOR_MAXIMIZE if (testWFlags(WStyle_Tool)) { wsa.save_under = True; @@ -757,23 +756,6 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) } } - // ### need a better way to do this - if (inherits("TQPopupMenu")) { - // menu netwm type - net_wintypes[curr_wintype++] = qt_net_wm_window_type_menu; - } else if (inherits("TQToolBar")) { - // toolbar netwm type - net_wintypes[curr_wintype++] = qt_net_wm_window_type_toolbar; - } else if (testWFlags(WStyle_Customize) && testWFlags(WStyle_Tool)) { - // utility netwm type - net_wintypes[curr_wintype++] = qt_net_wm_window_type_utility; - } - - if (dialog) // dialog netwm type - net_wintypes[curr_wintype++] = qt_net_wm_window_type_dialog; - // normal netwm type - default - net_wintypes[curr_wintype++] = qt_net_wm_window_type_normal; - // stays on top if (testWFlags(WStyle_StaysOnTop)) { net_winstates[curr_winstate++] = qt_net_wm_state_above; @@ -808,6 +790,7 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) wsa.save_under = True; XChangeWindowAttributes( dpy, id, CWOverrideRedirect | CWSaveUnder, &wsa ); + x11SetWindowType(); } else if ( topLevel && !desktop ) { // top-level widget TQWidget *p = parentWidget(); // real tqparent if (p) @@ -851,11 +834,14 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) XResizeWindow( dpy, id, crect.width(), crect.height() ); XStoreName( dpy, id, tqAppName() ); - Atom protocols[4]; + Atom protocols[5]; int n = 0; protocols[n++] = qt_wm_delete_window; // support del window protocol protocols[n++] = qt_wm_take_focus; // support take focus window protocol protocols[n++] = qt_net_wm_ping; // support _NET_WM_PING protocol +#ifndef TQT_NO_XSYNC + protocols[n++] = qt_net_wm_sync_request;// support the _NET_WM_SYNC_REQUEST protocol +#endif if ( testWFlags( WStyle_ContextHelp ) ) protocols[n++] = qt_net_wm_context_help; XSetWMProtocols( dpy, id, protocols, n ); @@ -867,12 +853,7 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) else XDeleteProperty(dpy, id, qt_xa_motif_wm_hints); - // set _NET_WM_WINDOW_TYPE - if (curr_wintype > 0) - XChangeProperty(dpy, id, qt_net_wm_window_type, XA_ATOM, 32, PropModeReplace, - (unsigned char *) net_wintypes, curr_wintype); - else - XDeleteProperty(dpy, id, qt_net_wm_window_type); + x11SetWindowType(); // set _NET_WM_WINDOW_STATE if (curr_winstate > 0) @@ -886,6 +867,14 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) XChangeProperty(dpy, id, qt_net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &curr_pid, 1); +#ifndef TQT_NO_XSYNC + // set _NET_WM_SYNC_COUNTER + createSyncCounter(); + long counterVal = topData()->syncCounter; + XChangeProperty( dpy, id, qt_net_wm_sync_request_counter, XA_CARDINAL, 32, PropModeReplace, + (unsigned char*) &counterVal, 1); +#endif + // when we create a toplevel widget, the frame strut should be dirty fstrut_dirty = 1; @@ -923,6 +912,10 @@ void TQWidget::create( WId window, bool initializeWindow, bool destroyOldWindow) if ( destroyw ) qt_XDestroyWindow( this, dpy, destroyw ); + +#if !defined(TQT_NO_IM_EXTENSIONS) + ic = 0; +#endif } @@ -981,11 +974,24 @@ void TQWidget::destroy( bool destroyWindow, bool destroySubWindows ) if ( destroyWindow ) qt_XDestroyWindow( this, x11Display(), winid ); } +#ifndef TQT_NO_XSYNC + destroySyncCounter(); +#endif setWinId( 0 ); extern void qPRCleanup( TQWidget *widget ); // from qapplication_x11.cpp if ( testWState(WState_Reparented) ) qPRCleanup(this); + + if( this == icHolderWidget() ) { + destroyInputContext(); + } else { + // release previous focus information participating with + // preedit preservation of qic + TQInputContext *qic = getInputContext(); + if ( qic ) + qic->releaseComposingWidget( this ); + } } } @@ -1022,14 +1028,18 @@ void TQWidget::reparentSys( TQWidget *tqparent, WFlags f, const TQPoint &p, bool XReparentWindow( x11Display(), old_winid, RootWindow( x11Display(), x11Screen() ), 0, 0 ); - if ( isTopLevel() ) { - // input contexts are associated with toplevel widgets, so we need - // destroy the context here. if we are reparenting back to toplevel, - // then we will have another context created, otherwise we will - // use our new toplevel's context + if ( this == icHolderWidget() ) { + // input contexts are sometimes associated with toplevel widgets, so + // we need destroy the context here. if we are reparenting back to + // toplevel, then we may have another context created, otherwise we + // will use our new ic holder's context destroyInputContext(); } +#ifndef TQT_NO_XSYNC + destroySyncCounter(); +#endif + if ( isTopLevel() || !tqparent ) // we are toplevel, or reparenting to toplevel topData()->parentWinId = 0; @@ -1131,6 +1141,64 @@ void TQWidget::reparentSys( TQWidget *tqparent, WFlags f, const TQPoint &p, bool setMouseTracking(mouse_tracking); } +// Sets the EWMH (netwm) window type. Needed as a separate function +// because create() may be too soon in some cases. +void TQWidget::x11SetWindowType( X11WindowType type ) +{ + // NET window types + long net_wintypes[7] = { 0, 0, 0, 0, 0, 0, 0 }; + int curr_wintype = 0; + if( testWFlags(WType_Desktop)) + return; + if( type == X11WindowTypeSelect ) { + if ( testWFlags(WStyle_Splash)) { + if (qt_net_supports(qt_net_wm_window_type_splash)) { + net_wintypes[curr_wintype++] = qt_net_wm_window_type_splash; + } + } else if (inherits(TQTOOLBAR_OBJECT_NAME_STRING)) { + // toolbar netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_toolbar; + } else if (testWFlags(WStyle_Customize) && testWFlags(WStyle_Tool)) { + // utility netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_utility; + } else if (testWFlags(WType_Dialog)) { + // dialog netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_dialog; + } + } else if( type == X11WindowTypeCombo ) { + // combo netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_combo; + } else if( type == X11WindowTypeDND ) { + // dnd netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_dnd; + } else if( type == X11WindowTypeDropdown ) { + // dropdown netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_dropdown_menu; + } else if( type == X11WindowTypePopup ) { + // popup netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_popup_menu; + } else if( type == X11WindowTypeMenu ) { + // menu netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_menu; + } else if( type == X11WindowTypeTooltip ) { + // tooltip netwm type + net_wintypes[curr_wintype++] = qt_net_wm_window_type_tooltip; + } + + // normal netwm type - default + net_wintypes[curr_wintype++] = qt_net_wm_window_type_normal; + // set _NET_WM_WINDOW_TYPE + if (curr_wintype > 0) + XChangeProperty(x11Display(), winId(), qt_net_wm_window_type, XA_ATOM, 32, PropModeReplace, + (unsigned char *) net_wintypes, curr_wintype); + else + XDeleteProperty(x11Display(), winId(), qt_net_wm_window_type); +} + +void TQWidget::x11SetWindowTransient( TQWidget* tqparent ) +{ + XSetTransientForHint( x11Display(), winId(), tqparent->winId()); +} /*! Translates the widget coordinate \a pos to global screen @@ -1182,7 +1250,8 @@ TQPoint TQWidget::mapFromGlobal( const TQPoint &pos ) const language input systems. In the X11 version of TQt, if \a text is TRUE, this method sets the - XIM "spot" point for complex language input handling. + input method focus point in the preedit (XIM "spot" point) for + complex language input handling. The font \a f is a rendering hint to the currently active input method. If \a f is 0 the widget's font is used. @@ -1192,22 +1261,15 @@ TQPoint TQWidget::mapFromGlobal( const TQPoint &pos ) const void TQWidget::setMicroFocusHint(int x, int y, int width, int height, bool text, TQFont *f ) { -#ifndef TQT_NO_XIM +#ifndef TQT_NO_IM if ( text ) { - TQWidget* tlw = tqtopLevelWidget(); - TQTLWExtra *topdata = tlw->topData(); - // trigger input context creation if it hasn't happened already createInputContext(); - TQInputContext *qic = (TQInputContext *) topdata->xic; - - if ( qt_xim && qic ) { - TQPoint p( x, y ); - TQPoint p2 = mapTo( tqtopLevelWidget(), TQPoint( 0, 0 ) ); - p = mapTo( tqtopLevelWidget(), p); - qic->setXFontSet( f ? *f : fnt ); - qic->setComposePosition(p.x(), p.y() + height); - qic->setComposeArea(p2.x(), p2.y(), this->width(), this->height()); + + TQInputContext *qic = getInputContext(); + if(qic) { + TQPoint gp = mapToGlobal( TQPoint( x, y ) ); + qic->setMicroFocus(gp.x(), gp.y(), width, height, f); } } #endif @@ -2659,13 +2721,21 @@ void TQWidget::deleteSysExtra() void TQWidget::createTLSysExtra() { +#if defined(TQT_NO_IM_EXTENSIONS) // created lazily extra->topextra->xic = 0; +#endif +#ifndef TQT_NO_XSYNC + extra->topextra->syncCounter = 0; + extra->topextra->syncRequestValue[0] = 0; + extra->topextra->syncRequestValue[1] = 0; +#endif } void TQWidget::deleteTLSysExtra() { - destroyInputContext(); + // don't destroy input context here. it will be destroyed in + // TQWidget::destroy() destroyInputContext(); } /* @@ -2706,6 +2776,51 @@ void TQWidget::checkChildrenDnd() } } + +#ifndef TQT_NO_XSYNC +// create a window's XSyncCounter +void TQWidget::createSyncCounter() +{ + if( !qt_use_xsync || !isTopLevel() || topData()->syncCounter ) + return; + XSyncValue zero; + XSyncIntToValue( &zero, 0 ); + topData()->syncCounter = XSyncCreateCounter( x11Display(), zero ); +} + +// destroy a window's XSyncCounter +void TQWidget::destroySyncCounter() +{ + if( !qt_use_xsync || !extra || !extra->topextra + || !extra->topextra->syncCounter ) + return; + XSyncDestroyCounter( x11Display(), extra->topextra->syncCounter ); + extra->topextra->syncCounter = 0; +} + +// increment a window's XSyncCounter +void TQWidget::incrementSyncCounter() +{ + if( qt_use_xsync && topData()->syncCounter && + !(topData()->syncRequestValue[0] == 0 && + topData()->syncRequestValue[1] == 0) ) { + XSyncValue val; + XSyncIntsToValue( &val, topData()->syncRequestValue[ 0 ], topData()->syncRequestValue[ 1 ] ); + XSyncSetCounter( x11Display(), topData()->syncCounter, val ); + topData()->syncRequestValue[0] = topData()->syncRequestValue[1] = 0; + } +} + +// handle _NET_WM_SYNC_REQUEST +void TQWidget::handleSyncRequest( void* ev ) +{ + XEvent* xev = (XEvent*)ev; + topData()->syncRequestValue[ 0 ] = xev->xclient.data.l[ 2 ]; + topData()->syncRequestValue[ 1 ] = xev->xclient.data.l[ 3 ]; +} +#endif // TQT_NO_XSYNC + + /*! \property TQWidget::acceptDrops \brief whether drop events are enabled for this widget @@ -2897,76 +3012,256 @@ void TQWidget::updateFrameStrut() const } +/*! + This function returns the widget holding the TQInputContext + instance for this widget. The instance is used for text input to + this widget, switching input method, etc. + + By default, this function delegates the role of returning input + context holder widget to TQApplication::locateICHolderWidget(). + + This definition enables application developer to change the + mapping of widgets to TQInputContext instance simply by overriding + TQApplication::locateICHolderWidget(). + + \sa TQApplication::locateICHolderWidget() +*/ +TQWidget *TQWidget::icHolderWidget() +{ + return tqApp->locateICHolderWidget(this); +} + + +/*! + This function returns the TQInputContext instance for this widget. + This instance is used for text input to this widget, etc. + It is simply the accessor function. +*/ +TQInputContext *TQWidget::getInputContext() +{ + TQInputContext *qic = 0; + +// #if !defined(TQT_NO_IM_EXTENSIONS) + if ( isInputMethodEnabled() ) { +#if !defined(TQT_NO_IM_EXTENSIONS) + qic = icHolderWidget()->ic; +#else +// { + // icHolderWidget is always tqtopLevelWidget + TQTLWExtra *topdata = icHolderWidget()->topData(); + qic = (TQInputContext *)topdata->xic; +#endif + } + + return qic; +} + + +/*! + This function replaces the TQInputContext instance used for text + input to this widget. The \a identifierName is the identifier name + of newly choosed input method. +*/ +void TQWidget::changeInputContext( const TQString& identifierName ) +{ + TQWidget *icWidget = icHolderWidget(); +#if !defined(TQT_NO_IM_EXTENSIONS) + TQInputContext **qicp = &icWidget->ic; +#else + TQInputContext **qicp = (TQInputContext **)&icWidget->topData()->xic; +#endif + + if( *qicp ) + delete *qicp; + // an input context that has the identifierName is generated. + TQInputContext *qic = TQInputContextFactory::create( identifierName, icWidget ); + *qicp = qic; + if ( qic ) { + TQObject::connect( qic, TQT_SIGNAL(imEventGenerated(TQObject *,TQIMEvent *)), + tqApp, TQT_SLOT(postIMEvent(TQObject *,TQIMEvent *)) ); + TQObject::connect( qic, TQT_SIGNAL(deletionRequested()), + icWidget, TQT_SLOT(destroyInputContext()) ); + } +} + + +/*! + \internal + This is an internal function, you should never call this. + + This function is called to generate an input context + according to a configuration for default input method + + When TQT_NO_IM_EXTENSIONS is not set, input context is + generated only when isInputMethodEnabled() returns TRUE. +*/ void TQWidget::createInputContext() { - TQWidget *tlw = tqtopLevelWidget(); - TQTLWExtra *topdata = tlw->topData(); +// #if !defined(TQT_NO_IM_EXTENSIONS) + if( !isInputMethodEnabled() || TQApplication::closingDown() ) + return; +// #endif -#ifndef TQT_NO_XIM - if (qt_xim) { - if (! topdata->xic) { - TQInputContext *qic = new TQInputContext(tlw); - topdata->xic = (void *) qic; - } - } else -#endif // TQT_NO_XIM - { - // qDebug("TQWidget::createInputContext: no xim"); - topdata->xic = 0; - } + TQWidget *icWidget = icHolderWidget(); +#ifndef TQT_NO_IM +#if !defined(TQT_NO_IM_EXTENSIONS) + TQInputContext **qicp = &icWidget->ic; +#else + TQInputContext **qicp = (TQInputContext **)&icWidget->topData()->xic; +#endif + + if ( ! *qicp ) { + // an input context of the default input method is generated. + TQInputContext *qic = TQInputContextFactory::create( TQApplication::defaultInputMethod(), icWidget ); + + *qicp = qic; + if ( qic ) { + TQObject::connect( qic, TQT_SIGNAL(imEventGenerated(TQObject *,TQIMEvent *)), + tqApp, TQT_SLOT(postIMEvent(TQObject *,TQIMEvent *)) ); + TQObject::connect( qic, TQT_SIGNAL(deletionRequested()), + icWidget, TQT_SLOT(destroyInputContext()) ); + } + } +#endif // TQT_NO_IM } +/*! + \internal + + This slot is used to destroy the input context that belonging + to the widget itself, so icHolderWidget()->ic is not fetched. + + \sa TQInputContext::deletionRequested() +*/ void TQWidget::destroyInputContext() { -#ifndef TQT_NO_XIM - TQInputContext *qic = (TQInputContext *) extra->topextra->xic; - delete qic; -#endif // TQT_NO_XIM - extra->topextra->xic = 0; +#ifndef TQT_NO_IM +#if !defined(TQT_NO_IM_EXTENSIONS) + TQInputContext **qicp = ⁣ +#else + if ( ! extra || ! extra->topextra ) + return; + + TQInputContext **qicp = (TQInputContext **)&extra->topextra->xic; +#endif + + if( *qicp ) + delete *qicp; + + *qicp = 0; +#endif // TQT_NO_IM } /*! - This function is called when the user finishes input composition, - e.g. changes focus to another widget, moves the cursor, etc. + This function is called when text widgets need to be neutral state to + execute text operations properly. See qlineedit.cpp and qtextedit.cpp as + example. + + Ordinary reset that along with changing focus to another widget, + moving the cursor, etc, is implicitly handled via + unfocusInputContext() because whether reset or not when such + situation is a responsibility of input methods. So we delegate the + responsibility to the input context via unfocusInputContext(). See + 'Preedit preservation' section of the class description of + TQInputContext for further information. + + \sa TQInputContext, unfocusInputContext(), TQInputContext::unsetFocus() */ void TQWidget::resetInputContext() { -#ifndef TQT_NO_XIM - if ((qt_xim_style & XIMPreeditCallbacks) && hasFocus()) { - TQWidget *tlw = tqtopLevelWidget(); - TQTLWExtra *topdata = tlw->topData(); +#ifndef TQT_NO_IM + // trigger input context creation if it hasn't happened already + createInputContext(); + + TQInputContext *qic = getInputContext(); + if( qic ) + qic->reset(); +#endif // TQT_NO_IM +} + + +/*! + \internal + This is an internal function, you should never call this. + + This function is called to focus associated input context. The + code intends to eliminate duplicate focus for the context even if + the context is shared between widgets + + \sa TQInputContext::setFocus() + */ +void TQWidget::focusInputContext() +{ +#ifndef TQT_NO_IM + TQWidget* tlw = tqtopLevelWidget(); + if (!tlw->isPopup() || isInputMethodEnabled()) { // trigger input context creation if it hasn't happened already createInputContext(); - if (topdata->xic) { - TQInputContext *qic = (TQInputContext *) topdata->xic; - qic->reset(); + TQInputContext *qic = getInputContext(); + if ( qic ) { + if( qic->tqfocusWidget() != this ) { + qic->setFocusWidget( this ); + qic->setFocus(); + } } } -#endif // TQT_NO_XIM +#endif // TQT_NO_IM } -void TQWidget::focusInputContext() -{ -#ifndef TQT_NO_XIM - TQWidget *tlw = tqtopLevelWidget(); - if (!tlw->isPopup() || isInputMethodEnabled()) { - TQTLWExtra *topdata = tlw->topData(); +/*! + \internal + This is an internal function, you should never call this. - // trigger input context creation if it hasn't happened already - createInputContext(); + This function is called to remove focus from associated input + context. - if (topdata->xic) { - TQInputContext *qic = (TQInputContext *) topdata->xic; - qic->setFocus(); - } + \sa TQInputContext::unsetFocus() + */ +void TQWidget::unfocusInputContext() +{ +#ifndef TQT_NO_IM + // trigger input context creation if it hasn't happened already + createInputContext(); + + TQInputContext *qic = getInputContext(); + if ( qic ) { + // may be caused reset() in some input methods + qic->unsetFocus(); + qic->setFocusWidget( 0 ); } -#endif // TQT_NO_XIM +#endif // TQT_NO_IM } + + +/*! + This function is called to send mouse event to associated input + context by derived text widgets. A derived text widget must be + calculate \a x as character offset at the mouse cursor in the + preedit. + + \sa TQInputContext::mouseHandler() + */ +void TQWidget::sendMouseEventToInputContext( int x, TQEvent::Type type, + TQt::ButtonState button, + TQt::ButtonState state ) +{ +#ifndef TQT_NO_IM + // trigger input context creation if it hasn't happened already + createInputContext(); + + TQInputContext *qic = getInputContext(); + if ( qic ) { + // may be causing reset() in some input methods + qic->mouseHandler( x, type, button, state ); + } +#endif // TQT_NO_IM +} + void TQWidget::setWindowOpacity(double) { |