From 5444ea50bb2b1b894d5b3c33676f9ef207fdcd1a Mon Sep 17 00:00:00 2001 From: Jan Arne Petersen Date: Wed, 30 Dec 2015 00:08:17 +0100 Subject: Fix text-input support for new API Update text input support to upstream text-input protocol v2 from wayland-protocols. Remove support for input-method protocol for now. Map text-input protocol on compositor side to the Qt input method API, this allows to use any qt platform input method on compositor side (especially qtvirtualkeyboard). Add support for qtvirtualkeyboard to pure-qml example. Implement all missing functions of the text-input protocol. Change-Id: I597451ff65454a63dff86026b6a8d1ffbe07ce02 Done-with: Zeno Endemann Reviewed-by: Giulio Camuffo --- src/3rdparty/protocol/input-method.xml | 273 ---------- src/3rdparty/protocol/text-input-unstable-v2.xml | 478 +++++++++++++++++ src/3rdparty/protocol/text.xml | 346 ------------ src/client/client.pro | 4 +- src/client/qwaylanddisplay.cpp | 10 +- src/client/qwaylanddisplay_p.h | 6 +- src/client/qwaylandinputcontext.cpp | 506 +++++++++++++----- src/client/qwaylandinputcontext_p.h | 77 ++- src/client/qwaylandinputdevice.cpp | 27 +- src/client/qwaylandinputdevice_p.h | 6 + src/compositor/compositor.pro | 4 +- src/compositor/compositor_api/compositor_api.pri | 5 +- .../compositor_api/qwaylandcompositor.cpp | 2 + src/compositor/compositor_api/qwaylandcompositor.h | 3 + src/compositor/compositor_api/qwaylandinput.cpp | 13 +- .../compositor_api/qwaylandinputmethodcontrol.cpp | 162 ++++++ .../compositor_api/qwaylandinputmethodcontrol.h | 84 +++ .../compositor_api/qwaylandinputmethodcontrol_p.h | 80 +++ .../compositor_api/qwaylandinputpanel.cpp | 83 --- src/compositor/compositor_api/qwaylandinputpanel.h | 78 --- .../compositor_api/qwaylandquickitem.cpp | 60 ++- src/compositor/compositor_api/qwaylandquickitem.h | 12 + src/compositor/compositor_api/qwaylandsurface.cpp | 20 +- src/compositor/compositor_api/qwaylandsurface.h | 5 +- src/compositor/compositor_api/qwaylandsurface_p.h | 7 +- src/compositor/extensions/extensions.pri | 21 +- src/compositor/extensions/qwaylandtextinput.cpp | 591 +++++++++++++++++++++ src/compositor/extensions/qwaylandtextinput.h | 86 +++ src/compositor/extensions/qwaylandtextinput_p.h | 135 +++++ .../extensions/qwaylandtextinputmanager.cpp | 98 ++++ .../extensions/qwaylandtextinputmanager.h | 64 +++ .../extensions/qwaylandtextinputmanager_p.h | 69 +++ src/compositor/extensions/qwlinputmethod.cpp | 152 ------ src/compositor/extensions/qwlinputmethod_p.h | 105 ---- .../extensions/qwlinputmethodcontext.cpp | 135 ----- .../extensions/qwlinputmethodcontext_p.h | 90 ---- src/compositor/extensions/qwlinputpanel.cpp | 130 ----- src/compositor/extensions/qwlinputpanel_p.h | 99 ---- src/compositor/extensions/qwlinputpanelsurface.cpp | 86 --- src/compositor/extensions/qwlinputpanelsurface_p.h | 95 ---- src/compositor/extensions/qwltextinput.cpp | 212 -------- src/compositor/extensions/qwltextinput_p.h | 106 ---- src/compositor/extensions/qwltextinputmanager.cpp | 64 --- src/compositor/extensions/qwltextinputmanager_p.h | 78 --- .../compositor/qwaylandquickcompositorplugin.cpp | 5 +- src/shared/qwaylandinputmethodeventbuilder.cpp | 286 ++++++++++ src/shared/qwaylandinputmethodeventbuilder.h | 87 +++ src/shared/qwaylandxkb.cpp | 55 ++ src/shared/qwaylandxkb.h | 7 + 49 files changed, 2876 insertions(+), 2331 deletions(-) delete mode 100644 src/3rdparty/protocol/input-method.xml create mode 100644 src/3rdparty/protocol/text-input-unstable-v2.xml delete mode 100644 src/3rdparty/protocol/text.xml create mode 100644 src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp create mode 100644 src/compositor/compositor_api/qwaylandinputmethodcontrol.h create mode 100644 src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h delete mode 100644 src/compositor/compositor_api/qwaylandinputpanel.cpp delete mode 100644 src/compositor/compositor_api/qwaylandinputpanel.h create mode 100644 src/compositor/extensions/qwaylandtextinput.cpp create mode 100644 src/compositor/extensions/qwaylandtextinput.h create mode 100644 src/compositor/extensions/qwaylandtextinput_p.h create mode 100644 src/compositor/extensions/qwaylandtextinputmanager.cpp create mode 100644 src/compositor/extensions/qwaylandtextinputmanager.h create mode 100644 src/compositor/extensions/qwaylandtextinputmanager_p.h delete mode 100644 src/compositor/extensions/qwlinputmethod.cpp delete mode 100644 src/compositor/extensions/qwlinputmethod_p.h delete mode 100644 src/compositor/extensions/qwlinputmethodcontext.cpp delete mode 100644 src/compositor/extensions/qwlinputmethodcontext_p.h delete mode 100644 src/compositor/extensions/qwlinputpanel.cpp delete mode 100644 src/compositor/extensions/qwlinputpanel_p.h delete mode 100644 src/compositor/extensions/qwlinputpanelsurface.cpp delete mode 100644 src/compositor/extensions/qwlinputpanelsurface_p.h delete mode 100644 src/compositor/extensions/qwltextinput.cpp delete mode 100644 src/compositor/extensions/qwltextinput_p.h delete mode 100644 src/compositor/extensions/qwltextinputmanager.cpp delete mode 100644 src/compositor/extensions/qwltextinputmanager_p.h create mode 100644 src/shared/qwaylandinputmethodeventbuilder.cpp create mode 100644 src/shared/qwaylandinputmethodeventbuilder.h (limited to 'src') diff --git a/src/3rdparty/protocol/input-method.xml b/src/3rdparty/protocol/input-method.xml deleted file mode 100644 index 70afdcb1d..000000000 --- a/src/3rdparty/protocol/input-method.xml +++ /dev/null @@ -1,273 +0,0 @@ - - - - Copyright © 2012, 2013 Intel Corporation - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - - Corresponds to a text model on input method side. An input method context - is created on text mode activation on the input method side. It allows to - receive information about the text model from the application via events. - Input method contexts do not keep state after deactivation and should be - destroyed after deactivation is handled. - - Text is generally UTF-8 encoded, indices and lengths are in bytes. - - Serials are used to synchronize the state between the text input and - an input method. New serials are sent by the text input in the - commit_state request and are used by the input method to indicate - the known text input state in events like preedit_string, commit_string, - and keysym. The text input can then ignore events from the input method - which are based on an outdated state (for example after a reset). - - - - - Send the commit string text for insertion to the application. - - The text to commit could be either just a single character after a key - press or the result of some composing (pre-edit). It could be also an - empty text when some text should be removed (see - delete_surrounding_text) or when the input cursor should be moved (see - cursor_position). - - Any previously set composing text will be removed. - - - - - - - Send the pre-edit string text to the application text input. - - The commit text can be used to replace the preedit text on reset (for - example on unfocus). - - Also previously sent preedit_style and preedit_cursor requests are - processed bt the text_input also. - - - - - - - - Sets styling information on composing text. The style is applied for - length in bytes from index relative to the beginning of - the composing text (as byte offset). Multiple styles can - be applied to a composing text. - - This request should be sent before sending preedit_string request. - - - - - - - - Sets the cursor position inside the composing text (as byte offset) - relative to the start of the composing text. - - When index is negative no cursor should be displayed. - - This request should be sent before sending preedit_string request. - - - - - - - - This request will be handled on text_input side as part of a directly - following commit_string request. - - - - - - - Sets the cursor and anchor to a new position. Index is the new cursor - position in bytess (when >= 0 relative to the end of inserted text - else relative to beginning of inserted text). Anchor is the new anchor - position in bytes (when >= 0 relative to the end of inserted text, else - relative to beginning of inserted text). When there should be no - selected text anchor should be the same as index. - - This request will be handled on text_input side as part of a directly - following commit_string request. - - - - - - - - - - Notify when a key event was sent. Key events should not be used for - normal text input operations, which should be done with commit_string, - delete_surrounfing_text, etc. The key event follows the wl_keyboard key - event convention. Sym is a XKB keysym, state a wl_keyboard key_state. - - - - - - - - - - Allows an input method to receive hardware keyboard input and process - key events to generate text events (with pre-edit) over the wire. This - allows input methods which compose multiple key events for inputting - text like it is done for CJK languages. - - - - - - Should be used when filtering key events with grab_keyboard. - - When the wl_keyboard::key event is not processed by the input - method itself and should be sent to the client instead, forward it - with this request. The arguments should be the ones from the - wl_keyboard::key event. - - For generating custom key events use the keysym request instead. - - - - - - - - - Should be used when filtering key events with grab_keyboard. - - When the wl_keyboard::modifiers event should be also send to the - client, forward it with this request. The arguments should be the ones - from the wl_keyboard::modifiers event. - - - - - - - - - - - - - - - - - - The plain surrounding text around the input position. Cursor is the - position in bytes within the surrounding text relative to the beginning - of the text. Anchor is the position in bytes of the selection anchor - within the surrounding text relative to the beginning of the text. If - there is no selected text anchor is the same as cursor. - - - - - - - - - - - - - - - - - - - - - - - - - - An input method object is responsible to compose text in response to - input from hardware or virtual keyboards. There is one input method - object per seat. On activate there is a new input method context object - created which allows the input method to communicate with the text model. - - - - A text model was activated. Creates an input method context object - which allows communication with the text model. - - - - - - The text model corresponding to the context argument was deactivated. - The input method context should be destroyed after deactivation is - handled. - - - - - - - - Only one client can bind this interface at a time. - - - - - - - - - - - - - - - - A keybaord surface is only shown, when a text model is active - - - - - - - - An overlay panel is shown near the input cursor above the application - window when a text model is active. - - - - diff --git a/src/3rdparty/protocol/text-input-unstable-v2.xml b/src/3rdparty/protocol/text-input-unstable-v2.xml new file mode 100644 index 000000000..bb366c921 --- /dev/null +++ b/src/3rdparty/protocol/text-input-unstable-v2.xml @@ -0,0 +1,478 @@ + + + + + Copyright © 2012, 2013 Intel Corporation + Copyright © 2015, 2016 Jan Arne Petersen + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + The zwp_text_input_v2 interface represents text input and input methods + associated with a seat. It provides enter/leave events to follow the + text input focus for a seat. + + Requests are used to enable/disable the text-input object and set + state information like surrounding and selected text or the content type. + The information about the entered text is sent to the text-input object + via the pre-edit and commit events. Using this interface removes the need + for applications to directly process hardware key events and compose text + out of them. + + Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices + have to always point to the first byte of an UTF-8 encoded code point. + Lengths are not allowed to contain just a part of an UTF-8 encoded code + point. + + State is sent by the state requests (set_surrounding_text, + set_content_type, set_cursor_rectangle and set_preferred_language) and + an update_state request. After an enter or an input_method_change event + all state information is invalidated and needs to be resent from the + client. A reset or entering a new widget on client side also + invalidates all current state information. + + + + + Destroy the wp_text_input object. Also disables all surfaces enabled + through this wp_text_input object + + + + + + Enable text input in a surface (usually when a text entry inside of it + has focus). + + This can be called before or after a surface gets text (or keyboard) + focus via the enter event. Text input to a surface is only active + when it has the current text (or keyboard) focus and is enabled. + + + + + + + Disable text input in a surface (typically when there is no focus on any + text entry inside the surface). + + + + + + + Requests input panels (virtual keyboard) to show. + + This should be used for example to show a virtual keyboard again + (with a tap) after it was closed by pressing on a close button on the + keyboard. + + + + + + Requests input panels (virtual keyboard) to hide. + + + + + + Sets the plain surrounding text around the input position. Text is + UTF-8 encoded. Cursor is the byte offset within the surrounding text. + Anchor is the byte offset of the selection anchor within the + surrounding text. If there is no selected text, anchor is the same as + cursor. + + Make sure to always send some text before and after the cursor + except when the cursor is at the beginning or end of text. + + When there was a configure_surrounding_text event take the + before_cursor and after_cursor arguments into account for picking how + much surrounding text to send. + + There is a maximum length of wayland messages so text can not be + longer than 4000 bytes. + + + + + + + + + Content hint is a bitmask to allow to modify the behavior of the text + input. + + + + + + + + + + + + + + + + + The content purpose allows to specify the primary purpose of a text + input. + + This allows an input method to show special purpose input panels with + extra characters or to disallow some characters. + + + + + + + + + + + + + + + + + + + Sets the content purpose and content hint. While the purpose is the + basic purpose of an input field, the hint flags allow to modify some + of the behavior. + + When no content type is explicitly set, a normal content purpose with + none hint should be assumed. + + + + + + + + Sets the cursor outline as a x, y, width, height rectangle in surface + local coordinates. + + Allows the compositor to put a window with word suggestions near the + cursor. + + + + + + + + + + Sets a specific language. This allows for example a virtual keyboard to + show a language specific layout. The "language" argument is a RFC-3066 + format language tag. + + It could be used for example in a word processor to indicate language of + currently edited document or in an instant message application which + tracks languages of contacts. + + + + + + + Defines the reason for sending an updated state. + + + + + + + + + + Allows to atomically send state updates from client. + + This request should follow after a batch of state updating requests + like set_surrounding_text, set_content_type, set_cursor_rectangle and + set_preferred_language. + + The flags field indicates why an updated state is sent to the input + method. + + Reset should be used by an editor widget after the text was changed + outside of the normal input method flow. + + For "change" it is enough to send the changed state, else the full + state should be send. + + Serial should be set to the serial from the last enter or + input_method_changed event. + + To make sure to not receive outdated input method events after a + reset or switching to a new widget wl_display_sync() should be used + after update_state in these cases. + + + + + + + + Notification that this seat's text-input focus is on a certain surface. + + When the seat has the keyboard capability the text-input focus follows + the keyboard focus. + + + + + + + + Notification that this seat's text-input focus is no longer on + a certain surface. + + The leave notification is sent before the enter notification + for the new focus. + + When the seat has the keyboard capabillity the text-input focus follows + the keyboard focus. + + + + + + + + + + + + + Notification that the visibility of the input panel (virtual keyboard) + changed. + + The rectangle x, y, width, height defines the area overlapped by the + input panel (virtual keyboard) on the surface having the text + focus in surface local coordinates. + + That can be used to make sure widgets are visible and not covered by + a virtual keyboard. + + + + + + + + + + + Notify when a new composing text (pre-edit) should be set around the + current cursor position. Any previously set composing text should + be removed. + + The commit text can be used to replace the composing text in some cases + (for example when losing focus). + + The text input should also handle all preedit_style and preedit_cursor + events occurring directly before preedit_string. + + + + + + + + + + + + + + + + + + + Sets styling information on composing text. The style is applied for + length bytes from index relative to the beginning of the composing + text (as byte offset). Multiple styles can be applied to a composing + text by sending multiple preedit_styling events. + + This event is handled as part of a following preedit_string event. + + + + + + + + + Sets the cursor position inside the composing text (as byte + offset) relative to the start of the composing text. When index is a + negative number no cursor is shown. + + When no preedit_cursor event is sent the cursor will be at the end of + the composing text by default. + + This event is handled as part of a following preedit_string event. + + + + + + + Notify when text should be inserted into the editor widget. The text to + commit could be either just a single character after a key press or the + result of some composing (pre-edit). It could be also an empty text + when some text should be removed (see delete_surrounding_text) or when + the input cursor should be moved (see cursor_position). + + Any previously set composing text should be removed. + + + + + + + Notify when the cursor or anchor position should be modified. + + This event should be handled as part of a following commit_string + event. + + The text between anchor and index should be selected. + + + + + + + + Notify when the text around the current cursor position should be + deleted. BeforeLength and afterLength is the length (in bytes) of text + before and after the current cursor position (excluding the selection) + to delete. + + This event should be handled as part of a following commit_string + or preedit_string event. + + + + + + + + Transfer an array of 0-terminated modifiers names. The position in + the array is the index of the modifier as used in the modifiers + bitmask in the keysym event. + + + + + + + Notify when a key event was sent. Key events should not be used + for normal text input operations, which should be done with + commit_string, delete_surrounding_text, etc. The key event follows + the wl_keyboard key event convention. Sym is a XKB keysym, state a + wl_keyboard key_state. Modifiers are a mask for effective modifiers + (where the modifier indices are set by the modifiers_map event) + + + + + + + + + + Sets the language of the input text. The "language" argument is a RFC-3066 + format language tag. + + + + + + + + + + + + + Sets the text direction of input text. + + It is mainly needed for showing input cursor on correct side of the + editor when there is no input yet done and making sure neutral + direction text is laid out properly. + + + + + + + Configure what amount of surrounding text is expected by the + input method. The surrounding text will be sent in the + set_surrounding_text request on the following state information updates. + + + + + + + + The input method changed on compositor side, which invalidates all + current state information. New state information should be sent from + the client via state requests (set_surrounding_text, + set_content_hint, ...) and update_state. + + + + + + + + + A factory for text-input objects. This object is a global singleton. + + + + + Destroy the wp_text_input_manager object. + + + + + + Creates a new text-input object for a given seat. + + + + + + diff --git a/src/3rdparty/protocol/text.xml b/src/3rdparty/protocol/text.xml deleted file mode 100644 index 1b5284dc3..000000000 --- a/src/3rdparty/protocol/text.xml +++ /dev/null @@ -1,346 +0,0 @@ - - - - - Copyright © 2012, 2013 Intel Corporation - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - - - - - An object used for text input. Adds support for text input and input - methods to applications. A text-input object is created from a - wl_text_input_manager and corresponds typically to a text entry in an - application. - Requests are used to activate/deactivate the text-input object and set - state information like surrounding and selected text or the content type. - The information about entered text is sent to the text-input object via - the pre-edit and commit events. Using this interface removes the need - for applications to directly process hardware key events and compose text - out of them. - - Text is generally UTF-8 encoded, indices and lengths are in bytes. - - Serials are used to synchronize the state between the text input and - an input method. New serials are sent by the text input in the - commit_state request and are used by the input method to indicate - the known text input state in events like preedit_string, commit_string, - and keysym. The text input can then ignore events from the input method - which are based on an outdated state (for example after a reset). - - - - Requests the text-input object to be activated (typically when the - text entry gets focus). - The seat argument is a wl_seat which maintains the focus for this - activation. The surface argument is a wl_surface assigned to the - text-input object and tracked for focus lost. The enter event - is emitted on successful activation. - - - - - - - Requests the text-input object to be deactivated (typically when the - text entry lost focus). The seat argument is a wl_seat which was used - for activation. - - - - - - Requests input panels (virtual keyboard) to show. - - - - - Requests input panels (virtual keyboard) to hide. - - - - - Should be called by an editor widget when the input state should be - reset, for example after the text was changed outside of the normal - input method flow. - - - - - Sets the plain surrounding text around the input position. Text is - UTF-8 encoded. Cursor is the byte offset within the - surrounding text. Anchor is the byte offset of the - selection anchor within the surrounding text. If there is no selected - text anchor is the same as cursor. - - - - - - - - Content hint is a bitmask to allow to modify the behavior of the text - input. - - - - - - - - - - - - - - - - - - The content purpose allows to specify the primary purpose of a text - input. - - This allows an input method to show special purpose input panels with - extra characters or to disallow some characters. - - - - - - - - - - - - - - - - - - Sets the content purpose and content hint. While the purpose is the - basic purpose of an input field, the hint flags allow to modify some - of the behavior. - - When no content type is explicitly set, a normal content purpose with - default hints (auto completion, auto correction, auto capitalization) - should be assumed. - - - - - - - - - - - - - Sets a specific language. This allows for example a virtual keyboard to - show a language specific layout. The "language" argument is a RFC-3066 - format language tag. - - It could be used for example in a word processor to indicate language of - currently edited document or in an instant message application which tracks - languages of contacts. - - - - - - - - - - - - - Notify the text-input object when it received focus. Typically in - response to an activate request. - - - - - - Notify the text-input object when it lost focus. Either in response - to a deactivate request or when the assigned surface lost focus or was - destroyed. - - - - - Transfer an array of 0-terminated modifiers names. The position in - the array is the index of the modifier as used in the modifiers - bitmask in the keysym event. - - - - - - Notify when the visibility state of the input panel changed. - - - - - - Notify when a new composing text (pre-edit) should be set around the - current cursor position. Any previously set composing text should - be removed. - - The commit text can be used to replace the preedit text on reset - (for example on unfocus). - - The text input should also handle all preedit_style and preedit_cursor - events occuring directly before preedit_string. - - - - - - - - - - - - - - - - - - Sets styling information on composing text. The style is applied for - length bytes from index relative to the beginning of the composing - text (as byte offset). Multiple styles can - be applied to a composing text by sending multiple preedit_styling - events. - - This event is handled as part of a following preedit_string event. - - - - - - - - Sets the cursor position inside the composing text (as byte - offset) relative to the start of the composing text. When index is a - negative number no cursor is shown. - - This event is handled as part of a following preedit_string event. - - - - - - Notify when text should be inserted into the editor widget. The text to - commit could be either just a single character after a key press or the - result of some composing (pre-edit). It could be also an empty text - when some text should be removed (see delete_surrounding_text) or when - the input cursor should be moved (see cursor_position). - - Any previously set composing text should be removed. - - - - - - - Notify when the cursor or anchor position should be modified. - - This event should be handled as part of a following commit_string - event. - - - - - - - Notify when the text around the current cursor position should be - deleted. - - Index is relative to the current cursor (in bytes). - Length is the length of deleted text (in bytes). - - This event should be handled as part of a following commit_string - event. - - - - - - - Notify when a key event was sent. Key events should not be used - for normal text input operations, which should be done with - commit_string, delete_surrounding_text, etc. The key event follows - the wl_keyboard key event convention. Sym is a XKB keysym, state a - wl_keyboard key_state. Modifiers are a mask for effective modifiers - (where the modifier indices are set by the modifiers_map event) - - - - - - - - - - Sets the language of the input text. The "language" argument is a RFC-3066 - format language tag. - - - - - - - - - - - - Sets the text direction of input text. - - It is mainly needed for showing input cursor on correct side of the - editor when there is no input yet done and making sure neutral - direction text is laid out properly. - - - - - - - - - A factory for text-input objects. This object is a global singleton. - - - - Creates a new text-input object. - - - - - diff --git a/src/client/client.pro b/src/client/client.pro index 1219ee345..61404eeb9 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -39,7 +39,7 @@ WAYLANDCLIENTSOURCES += \ ../extensions/touch-extension.xml \ ../extensions/qtkey-extension.xml \ ../extensions/windowmanager.xml \ - ../3rdparty/protocol/text.xml \ + ../3rdparty/protocol/text-input-unstable-v2.xml \ ../3rdparty/protocol/xdg-shell.xml \ SOURCES += qwaylandintegration.cpp \ @@ -66,6 +66,7 @@ SOURCES += qwaylandintegration.cpp \ qwaylandqtkey.cpp \ ../shared/qwaylandmimehelper.cpp \ ../shared/qwaylandxkb.cpp \ + ../shared/qwaylandinputmethodeventbuilder.cpp \ qwaylandabstractdecoration.cpp \ qwaylanddecorationfactory.cpp \ qwaylanddecorationplugin.cpp \ @@ -100,6 +101,7 @@ HEADERS += qwaylandintegration_p.h \ qwaylandqtkey_p.h \ ../shared/qwaylandmimehelper.h \ ../shared/qwaylandxkb.h \ + ../shared/qwaylandinputmethodeventbuilder.h \ qwaylandabstractdecoration_p.h \ qwaylanddecorationfactory_p.h \ qwaylanddecorationplugin_p.h \ diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 7244363cd..a18b9853f 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -50,6 +50,7 @@ #include "qwaylandxdgshell_p.h" #include "qwaylandxdgsurface_p.h" #include "qwaylandwlshellsurface_p.h" +#include "qwaylandinputcontext_p.h" #include "qwaylandwindowmanagerintegration_p.h" #include "qwaylandshellintegration_p.h" @@ -60,7 +61,7 @@ #include "qwaylandtouch_p.h" #include "qwaylandqtkey_p.h" -#include +#include #include #include @@ -281,8 +282,11 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin mTouchExtension.reset(new QWaylandTouchExtension(this, id)); } else if (interface == QStringLiteral("qt_key_extension")) { mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id)); - } else if (interface == QStringLiteral("wl_text_input_manager")) { - mTextInputManager.reset(new QtWayland::wl_text_input_manager(registry, id, 1)); + } else if (interface == QStringLiteral("zwp_text_input_manager_v2")) { + mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1)); + foreach (QWaylandInputDevice *inputDevice, mInputDevices) { + inputDevice->setTextInput(new QWaylandTextInput(this, mTextInputManager->get_text_input(inputDevice->wl_seat()))); + } } else if (interface == QStringLiteral("qt_hardware_integration")) { mHardwareIntegration.reset(new QWaylandHardwareIntegration(registry, id)); // make a roundtrip here since we need to receive the events sent by diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 82d87cb92..618e57c59 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -76,7 +76,7 @@ namespace QtWayland { class qt_shell; class qt_sub_surface_extension; class qt_surface_extension; - class wl_text_input_manager; + class zwp_text_input_manager_v2; class xdg_shell; } @@ -147,7 +147,7 @@ public: QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); } QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); } - QtWayland::wl_text_input_manager *textInputManager() const { return mTextInputManager.data(); } + QtWayland::zwp_text_input_manager_v2 *textInputManager() const { return mTextInputManager.data(); } QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); } struct RegistryGlobal { @@ -207,7 +207,7 @@ private: QScopedPointer mTouchExtension; QScopedPointer mQtKeyExtension; QScopedPointer mWindowManagerIntegration; - QScopedPointer mTextInputManager; + QScopedPointer mTextInputManager; QScopedPointer mHardwareIntegration; QSocketNotifier *mReadNotifier; int mFd; diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp index 00f6a4303..aeaf415d2 100644 --- a/src/client/qwaylandinputcontext.cpp +++ b/src/client/qwaylandinputcontext.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Klarälvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWaylandClient module of the Qt Toolkit. @@ -40,147 +40,358 @@ #include "qwaylandinputcontext_p.h" -#include -#include -#ifndef QT_NO_WAYLAND_XKB -#include -#endif +#include +#include +#include +#include +#include #include "qwaylanddisplay_p.h" #include "qwaylandinputdevice_p.h" +#include "qwaylandinputmethodeventbuilder.h" #include "qwaylandwindow_p.h" +#include "qwaylandxkb.h" QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(qLcQpaInputMethods, "qt.qpa.input.methods") + namespace QtWaylandClient { -static Qt::Key toQtKey(uint32_t sym) -{ -#ifndef QT_NO_WAYLAND_XKB - switch (static_cast(sym)) { - case XKB_KEY_BackSpace: - return Qt::Key_Backspace; - case XKB_KEY_Return: - return Qt::Key_Return; - case XKB_KEY_Left: - return Qt::Key_Left; - case XKB_KEY_Up: - return Qt::Key_Up; - case XKB_KEY_Right: - return Qt::Key_Right; - case XKB_KEY_Down: - return Qt::Key_Down; - default: - return Qt::Key_unknown; - } -#else - Q_UNUSED(sym) - return Qt::Key_unknown; -#endif +namespace { +const Qt::InputMethodQueries supportedQueries = Qt::ImEnabled | + Qt::ImSurroundingText | + Qt::ImCursorPosition | + Qt::ImAnchorPosition | + Qt::ImHints | + Qt::ImCursorRectangle | + Qt::ImPreferredLanguage; } -static QEvent::Type toQEventType(uint32_t state) +QWaylandTextInput::QWaylandTextInput(QWaylandDisplay *display, struct ::zwp_text_input_v2 *text_input) + : QtWayland::zwp_text_input_v2(text_input) + , m_display(display) + , m_builder() + , m_serial(0) + , m_surface(nullptr) + , m_preeditCommit() + , m_inputPanelVisible(false) + , m_keyboardRectangle() + , m_locale() + , m_inputDirection(Qt::LayoutDirectionAuto) + , m_resetCallback(nullptr) { - switch (static_cast(state)) { - default: - case WL_KEYBOARD_KEY_STATE_PRESSED: - return QEvent::KeyPress; - case WL_KEYBOARD_KEY_STATE_RELEASED: - return QEvent::KeyRelease; - } } -QWaylandTextInput::QWaylandTextInput(struct ::wl_text_input *text_input) - : QtWayland::wl_text_input(text_input) - , m_commit() - , m_serial(0) - , m_resetSerial(0) +QWaylandTextInput::~QWaylandTextInput() { + if (m_resetCallback) + wl_callback_destroy(m_resetCallback); } -QString QWaylandTextInput::commitString() const +void QWaylandTextInput::reset() { - return m_commit; + m_builder.reset(); + m_preeditCommit = QString(); + updateState(Qt::ImQueryAll, update_state_reset); } -void QWaylandTextInput::reset() +void QWaylandTextInput::commit() { - wl_text_input::reset(); - updateState(); - m_resetSerial = m_serial; + if (QObject *o = QGuiApplication::focusObject()) { + QInputMethodEvent event; + event.setCommitString(m_preeditCommit); + QCoreApplication::sendEvent(o, &event); + } + + reset(); } -void QWaylandTextInput::updateState() +const wl_callback_listener QWaylandTextInput::callbackListener = { + QWaylandTextInput::resetCallback +}; + +void QWaylandTextInput::resetCallback(void *data, wl_callback *, uint32_t) +{ + QWaylandTextInput *self = static_cast(data); + + if (self->m_resetCallback) { + wl_callback_destroy(self->m_resetCallback); + self->m_resetCallback = nullptr; + } +} + +void QWaylandTextInput::updateState(Qt::InputMethodQueries queries, uint32_t flags) { if (!QGuiApplication::focusObject()) return; - QInputMethodQueryEvent event(Qt::ImQueryAll); + if (!QGuiApplication::focusWindow() || !QGuiApplication::focusWindow()->handle()) + return; + + struct ::wl_surface *surface = static_cast(QGuiApplication::focusWindow()->handle())->object(); + if (!surface || (surface != m_surface)) + return; + + queries &= supportedQueries; + + // Surrounding text, cursor and anchor positions are transferred together + if ((queries & Qt::ImSurroundingText) || (queries & Qt::ImCursorPosition) || (queries & Qt::ImAnchorPosition)) + queries |= Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition; + + QInputMethodQueryEvent event(queries); QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); - const QString &text = event.value(Qt::ImSurroundingText).toString(); - const int cursor = event.value(Qt::ImCursorPosition).toInt(); - const int anchor = event.value(Qt::ImAnchorPosition).toInt(); + if ((queries & Qt::ImSurroundingText) || (queries & Qt::ImCursorPosition) || (queries & Qt::ImAnchorPosition)) { + QString text = event.value(Qt::ImSurroundingText).toString(); + int cursor = event.value(Qt::ImCursorPosition).toInt(); + int anchor = event.value(Qt::ImAnchorPosition).toInt(); + + // Make sure text is not too big + if (text.toUtf8().size() > 2048) { + int c = qAbs(cursor - anchor) <= 512 ? qMin(cursor, anchor) + qAbs(cursor - anchor) / 2: cursor; + + const int offset = c - qBound(0, c, 512 - qMin(text.size() - c, 256)); + text = text.mid(offset + c - 256, 512); + cursor -= offset; + anchor -= offset; + } + + set_surrounding_text(text, text.leftRef(cursor).toUtf8().size(), text.leftRef(anchor).toUtf8().size()); + } + + if (queries & Qt::ImHints) { + QWaylandInputMethodContentType contentType = QWaylandInputMethodContentType::convert(static_cast(event.value(Qt::ImHints).toInt())); + set_content_type(contentType.hint, contentType.purpose); + } + + if (queries & Qt::ImCursorRectangle) { + const QRect &cRect = event.value(Qt::ImCursorRectangle).toRect(); + const QRect &tRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect); + set_cursor_rectangle(tRect.x(), tRect.y(), tRect.width(), tRect.height()); + } + + if (queries & Qt::ImPreferredLanguage) { + const QString &language = event.value(Qt::ImPreferredLanguage).toString(); + set_preferred_language(language); + } + + update_state(m_serial, flags); + if (flags != update_state_change) { + if (m_resetCallback) + wl_callback_destroy(m_resetCallback); + m_resetCallback = wl_display_sync(m_display->wl_display()); + wl_callback_add_listener(m_resetCallback, &QWaylandTextInput::callbackListener, this); + } +} + +bool QWaylandTextInput::isInputPanelVisible() const +{ + return m_inputPanelVisible; +} + +QRectF QWaylandTextInput::keyboardRect() const +{ + return m_keyboardRectangle; +} + +QLocale QWaylandTextInput::locale() const +{ + return m_locale; +} + +Qt::LayoutDirection QWaylandTextInput::inputDirection() const +{ + return m_inputDirection; +} - set_surrounding_text(text, text.leftRef(cursor).toUtf8().size(), text.leftRef(anchor).toUtf8().size()); +void QWaylandTextInput::zwp_text_input_v2_enter(uint32_t serial, ::wl_surface *surface) +{ + m_serial = serial; + m_surface = surface; - commit_state(++m_serial); + updateState(Qt::ImQueryAll, update_state_enter); } -void QWaylandTextInput::text_input_preedit_string(uint32_t serial, const QString &text, const QString &commit) +void QWaylandTextInput::zwp_text_input_v2_leave(uint32_t serial, ::wl_surface *surface) { - Q_UNUSED(serial) + m_serial = serial; + + if (m_surface != surface) { + qCDebug(qLcQpaInputMethods()) << Q_FUNC_INFO << "Got leave event for surface" << surface << "focused surface" << m_surface; + } + + m_surface = nullptr; +} + +void QWaylandTextInput::zwp_text_input_v2_modifiers_map(wl_array *map) +{ + QList modifiersMap = QByteArray::fromRawData(static_cast(map->data), map->size).split('\0'); + + m_modifiersMap.clear(); + + Q_FOREACH (const QByteArray &modifier, modifiersMap) { + if (modifier == "Shift") + m_modifiersMap.append(Qt::ShiftModifier); + else if (modifier == "Control") + m_modifiersMap.append(Qt::ControlModifier); + else if (modifier == "Alt") + m_modifiersMap.append(Qt::AltModifier); + else if (modifier == "Mod1") + m_modifiersMap.append(Qt::AltModifier); + else if (modifier == "Mod4") + m_modifiersMap.append(Qt::MetaModifier); + else + m_modifiersMap.append(Qt::NoModifier); + } +} + +void QWaylandTextInput::zwp_text_input_v2_input_panel_state(uint32_t visible, int32_t x, int32_t y, int32_t width, int32_t height) +{ + const bool inputPanelVisible = (visible == input_panel_visibility_visible); + if (m_inputPanelVisible != inputPanelVisible) { + m_inputPanelVisible = inputPanelVisible; + QGuiApplicationPrivate::platformIntegration()->inputContext()->emitInputPanelVisibleChanged(); + } + const QRectF keyboardRectangle(x, y, width, height); + if (m_keyboardRectangle != keyboardRectangle) { + m_keyboardRectangle = keyboardRectangle; + QGuiApplicationPrivate::platformIntegration()->inputContext()->emitKeyboardRectChanged(); + } +} + +void QWaylandTextInput::zwp_text_input_v2_preedit_string(const QString &text, const QString &commit) +{ + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard preedit_string: reset not confirmed"; + m_builder.reset(); + return; + } + if (!QGuiApplication::focusObject()) return; - m_commit = commit; - QList attributes; - QInputMethodEvent event(text, attributes); + QInputMethodEvent event = m_builder.buildPreedit(text); + + m_builder.reset(); + m_preeditCommit = commit; + QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); } -void QWaylandTextInput::text_input_commit_string(uint32_t serial, const QString &text) +void QWaylandTextInput::zwp_text_input_v2_preedit_styling(uint32_t index, uint32_t length, uint32_t style) +{ + m_builder.addPreeditStyling(index, length, style); +} + +void QWaylandTextInput::zwp_text_input_v2_preedit_cursor(int32_t index) { - Q_UNUSED(serial); + m_builder.setPreeditCursor(index); +} + +void QWaylandTextInput::zwp_text_input_v2_commit_string(const QString &text) +{ + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard commit_string: reset not confirmed"; + m_builder.reset(); + return; + } + if (!QGuiApplication::focusObject()) return; - QInputMethodEvent event; - event.setCommitString(text); + QInputMethodEvent event = m_builder.buildCommit(text); + + m_builder.reset(); + QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); +} - m_commit = QString(); +void QWaylandTextInput::zwp_text_input_v2_cursor_position(int32_t index, int32_t anchor) +{ + m_builder.setCursorPosition(index, anchor); } -void QWaylandTextInput::text_input_enter(wl_surface *) +void QWaylandTextInput::zwp_text_input_v2_delete_surrounding_text(uint32_t before_length, uint32_t after_length) { - updateState(); - m_resetSerial = m_serial; + m_builder.setDeleteSurroundingText(before_length, after_length); } -void QWaylandTextInput::text_input_leave() +void QWaylandTextInput::zwp_text_input_v2_keysym(uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) { - if (!m_commit.isEmpty()) - text_input_commit_string(0, m_commit); + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard keysym: reset not confirmed"; + return; + } + + if (!QGuiApplication::focusWindow()) + return; + + Qt::KeyboardModifiers qtModifiers = modifiersToQtModifiers(modifiers); + + QEvent::Type type = QWaylandXkb::toQtEventType(state); + const QString &text = QWaylandXkb::textFromKeysym(sym, qtModifiers); + int qtkey = QWaylandXkb::keysymToQtKey(sym, qtModifiers, text); + + QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), + time, type, qtkey, qtModifiers, text); } -void QWaylandTextInput::text_input_keysym(uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) +void QWaylandTextInput::zwp_text_input_v2_language(const QString &language) { - Q_UNUSED(serial); - Q_UNUSED(time); - Q_UNUSED(modifiers); - if (!QGuiApplication::focusObject()) + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard language: reset not confirmed"; return; + } - // TODO: Convert modifiers to Qt::KeyboardModifiers. - QKeyEvent event(toQEventType(state), toQtKey(sym), Qt::NoModifier); - QCoreApplication::sendEvent(qGuiApp->focusWindow(), &event); + const QLocale locale(language); + if (m_locale != locale) { + m_locale = locale; + QGuiApplicationPrivate::platformIntegration()->inputContext()->emitLocaleChanged(); + } +} + +void QWaylandTextInput::zwp_text_input_v2_text_direction(uint32_t direction) +{ + if (m_resetCallback) { + qCDebug(qLcQpaInputMethods()) << "discard text_direction: reset not confirmed"; + return; + } + + const Qt::LayoutDirection inputDirection = (direction == text_direction_auto) ? Qt::LayoutDirectionAuto : + (direction == text_direction_ltr) ? Qt::LeftToRight : + (direction == text_direction_rtl) ? Qt::RightToLeft : Qt::LayoutDirectionAuto; + if (m_inputDirection != inputDirection) { + m_inputDirection = inputDirection; + QGuiApplicationPrivate::platformIntegration()->inputContext()->emitInputDirectionChanged(m_inputDirection); + } +} + +void QWaylandTextInput::zwp_text_input_v2_input_method_changed(uint32_t serial, uint32_t flags) +{ + Q_UNUSED(flags); + + m_serial = serial; + updateState(Qt::ImQueryAll, update_state_full); +} + +Qt::KeyboardModifiers QWaylandTextInput::modifiersToQtModifiers(uint32_t modifiers) +{ + Qt::KeyboardModifiers ret = Qt::NoModifier; + for (int i = 0; modifiers >>= 1; ++i) { + ret |= m_modifiersMap[i]; + } + return ret; } QWaylandInputContext::QWaylandInputContext(QWaylandDisplay *display) : QPlatformInputContext() , mDisplay(display) - , mTextInput() + , mCurrentWindow() +{ +} + +QWaylandInputContext::~QWaylandInputContext() { } @@ -191,96 +402,141 @@ bool QWaylandInputContext::isValid() const void QWaylandInputContext::reset() { - if (!ensureTextInput()) + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + QPlatformInputContext::reset(); + + if (!textInput()) return; - mTextInput->reset(); + textInput()->reset(); } void QWaylandInputContext::commit() { - if (!ensureTextInput()) - return; + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; - if (!QGuiApplication::focusObject()) + if (!textInput()) return; - QInputMethodEvent event; - event.setCommitString(mTextInput->commitString()); - QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); - - mTextInput->reset(); + textInput()->commit(); } void QWaylandInputContext::update(Qt::InputMethodQueries queries) { - Q_UNUSED(queries); - if (!ensureTextInput()) - return; - - mTextInput->updateState(); -} + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO << queries; -void QWaylandInputContext::invokeAction(QInputMethod::Action, int cursorPosition) -{ - if (!ensureTextInput()) + if (!QGuiApplication::focusObject() || !textInput()) return; - mTextInput->invoke_action(0, cursorPosition); // FIXME button, to UTF8 cursor position + if (mCurrentWindow && mCurrentWindow->handle() && !inputMethodAccepted()) { + struct ::wl_surface *surface = static_cast(mCurrentWindow->handle())->object(); + textInput()->disable(surface); + mCurrentWindow.clear(); + } else if (!mCurrentWindow && inputMethodAccepted()) { + QWindow *window = QGuiApplication::focusWindow(); + if (window && window->handle()) { + struct ::wl_surface *surface = static_cast(window->handle())->object(); + textInput()->enable(surface); + mCurrentWindow = window; + } + } + + textInput()->updateState(queries, QtWayland::zwp_text_input_v2::update_state_change); } void QWaylandInputContext::showInputPanel() { - if (!ensureTextInput()) + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) return; - mTextInput->show_input_panel(); + textInput()->show_input_panel(); } void QWaylandInputContext::hideInputPanel() { - if (!ensureTextInput()) + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) return; - mTextInput->hide_input_panel(); + textInput()->hide_input_panel(); } bool QWaylandInputContext::isInputPanelVisible() const { - return false; + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) + return QPlatformInputContext::isInputPanelVisible(); + + return textInput()->isInputPanelVisible(); } -void QWaylandInputContext::setFocusObject(QObject *object) +QRectF QWaylandInputContext::keyboardRect() const { - if (!ensureTextInput()) - return; + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; - if (!object) { - mTextInput->deactivate(mDisplay->defaultInputDevice()->wl_seat()); - return; - } + if (!textInput()) + return QPlatformInputContext::keyboardRect(); - QWindow *window = QGuiApplication::focusWindow(); - if (!window || !window->handle()) - return; + return textInput()->keyboardRect(); +} - struct ::wl_surface *surface = static_cast(window->handle())->object(); - mTextInput->activate(mDisplay->defaultInputDevice()->wl_seat(), surface); +QLocale QWaylandInputContext::locale() const +{ + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) + return QPlatformInputContext::locale(); + + return textInput()->locale(); } -bool QWaylandInputContext::ensureTextInput() +Qt::LayoutDirection QWaylandInputContext::inputDirection() const { - if (mTextInput) - return true; + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) + return QPlatformInputContext::inputDirection(); + + return textInput()->inputDirection(); +} + +void QWaylandInputContext::setFocusObject(QObject *) +{ + qCDebug(qLcQpaInputMethods) << Q_FUNC_INFO; + + if (!textInput()) + return; - if (!isValid()) - return false; + QWindow *window = QGuiApplication::focusWindow(); - mTextInput.reset(new QWaylandTextInput(mDisplay->textInputManager()->create_text_input())); - return true; + if (mCurrentWindow && mCurrentWindow->handle()) { + if (mCurrentWindow.data() != window || !inputMethodAccepted()) { + struct ::wl_surface *surface = static_cast(mCurrentWindow->handle())->object(); + textInput()->disable(surface); + mCurrentWindow.clear(); + } + } + + if (window && window->handle() && inputMethodAccepted()) { + if (mCurrentWindow.data() != window) { + struct ::wl_surface *surface = static_cast(window->handle())->object(); + textInput()->enable(surface); + mCurrentWindow = window; + } + textInput()->updateState(Qt::ImQueryAll, QtWayland::zwp_text_input_v2::update_state_enter); + } } +QWaylandTextInput *QWaylandInputContext::textInput() const +{ + return mDisplay->defaultInputDevice()->textInput(); } -QT_END_NAMESPACE +} +QT_END_NAMESPACE diff --git a/src/client/qwaylandinputcontext_p.h b/src/client/qwaylandinputcontext_p.h index cdabfcca4..0429dd14e 100644 --- a/src/client/qwaylandinputcontext_p.h +++ b/src/client/qwaylandinputcontext_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Klarälvdalens Datakonsult AB (KDAB). +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWaylandClient module of the Qt Toolkit. @@ -54,36 +54,75 @@ #include -#include +#include +#include +#include +#include + +#include +#include QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(qLcQpaInputMethods) + namespace QtWaylandClient { class QWaylandDisplay; -class QWaylandTextInput : public QtWayland::wl_text_input +class QWaylandTextInput : public QtWayland::zwp_text_input_v2 { public: - QWaylandTextInput(struct ::wl_text_input *text_input); - - QString commitString() const; + QWaylandTextInput(QWaylandDisplay *display, struct ::zwp_text_input_v2 *text_input); + ~QWaylandTextInput(); void reset(); - void updateState(); + void commit(); + void updateState(Qt::InputMethodQueries queries, uint32_t flags); + + bool isInputPanelVisible() const; + QRectF keyboardRect() const; + + QLocale locale() const; + Qt::LayoutDirection inputDirection() const; protected: - void text_input_preedit_string(uint32_t serial, const QString &text, const QString &commit) Q_DECL_OVERRIDE; - void text_input_commit_string(uint32_t serial, const QString &text) Q_DECL_OVERRIDE; - void text_input_enter(wl_surface *surface) Q_DECL_OVERRIDE; - void text_input_leave() Q_DECL_OVERRIDE; - void text_input_keysym(uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers); + void zwp_text_input_v2_enter(uint32_t serial, struct ::wl_surface *surface) Q_DECL_OVERRIDE; + void zwp_text_input_v2_leave(uint32_t serial, struct ::wl_surface *surface) Q_DECL_OVERRIDE; + void zwp_text_input_v2_modifiers_map(wl_array *map) Q_DECL_OVERRIDE; + void zwp_text_input_v2_input_panel_state(uint32_t state, int32_t x, int32_t y, int32_t width, int32_t height) Q_DECL_OVERRIDE; + void zwp_text_input_v2_preedit_string(const QString &text, const QString &commit) Q_DECL_OVERRIDE; + void zwp_text_input_v2_preedit_styling(uint32_t index, uint32_t length, uint32_t style) Q_DECL_OVERRIDE; + void zwp_text_input_v2_preedit_cursor(int32_t index) Q_DECL_OVERRIDE; + void zwp_text_input_v2_commit_string(const QString &text) Q_DECL_OVERRIDE; + void zwp_text_input_v2_cursor_position(int32_t index, int32_t anchor) Q_DECL_OVERRIDE; + void zwp_text_input_v2_delete_surrounding_text(uint32_t before_length, uint32_t after_length) Q_DECL_OVERRIDE; + void zwp_text_input_v2_keysym(uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) Q_DECL_OVERRIDE; + void zwp_text_input_v2_language(const QString &language) Q_DECL_OVERRIDE; + void zwp_text_input_v2_text_direction(uint32_t direction) Q_DECL_OVERRIDE; + void zwp_text_input_v2_input_method_changed(uint32_t serial, uint32_t flags) Q_DECL_OVERRIDE; private: - QString m_commit; + Qt::KeyboardModifiers modifiersToQtModifiers(uint32_t modifiers); + + QWaylandDisplay *m_display; + QWaylandInputMethodEventBuilder m_builder; + + QVector m_modifiersMap; uint32_t m_serial; - uint32_t m_resetSerial; + struct ::wl_surface *m_surface; + + QString m_preeditCommit; + + bool m_inputPanelVisible; + QRectF m_keyboardRectangle; + QLocale m_locale; + Qt::LayoutDirection m_inputDirection; + + struct ::wl_callback *m_resetCallback; + static const wl_callback_listener callbackListener; + static void resetCallback(void *data, struct wl_callback *wl_callback, uint32_t time); }; class QWaylandInputContext : public QPlatformInputContext @@ -91,25 +130,29 @@ class QWaylandInputContext : public QPlatformInputContext Q_OBJECT public: explicit QWaylandInputContext(QWaylandDisplay *display); + ~QWaylandInputContext(); bool isValid() const Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void commit() Q_DECL_OVERRIDE; void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE; - void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE; void showInputPanel() Q_DECL_OVERRIDE; void hideInputPanel() Q_DECL_OVERRIDE; bool isInputPanelVisible() const Q_DECL_OVERRIDE; + QRectF keyboardRect() const Q_DECL_OVERRIDE; + + QLocale locale() const Q_DECL_OVERRIDE; + Qt::LayoutDirection inputDirection() const Q_DECL_OVERRIDE; void setFocusObject(QObject *object) Q_DECL_OVERRIDE; private: - bool ensureTextInput(); + QWaylandTextInput *textInput() const; QWaylandDisplay *mDisplay; - QScopedPointer mTextInput; + QPointer mCurrentWindow; }; } diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 46c473e70..cf1c7ac44 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -50,6 +50,7 @@ #include "qwaylanddisplay_p.h" #include "qwaylandshmbackingstore_p.h" #include "../shared/qwaylandxkb.h" +#include "qwaylandinputcontext_p.h" #include #include @@ -185,6 +186,7 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, , mKeyboard(0) , mPointer(0) , mTouch(0) + , mTextInput(0) , mTime(0) , mSerial(0) , mTouchDevice(0) @@ -193,6 +195,9 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, mDataDevice = mQDisplay->dndSelectionHandler()->getDataDevice(this); } + if (mQDisplay->textInputManager()) { + mTextInput = new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())); + } } QWaylandInputDevice::~QWaylandInputDevice() @@ -277,6 +282,16 @@ QWaylandDataDevice *QWaylandInputDevice::dataDevice() const return mDataDevice; } +void QWaylandInputDevice::setTextInput(QWaylandTextInput *textInput) +{ + mTextInput = textInput; +} + +QWaylandTextInput *QWaylandInputDevice::textInput() const +{ + return mTextInput; +} + void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button) { if (mPointer) @@ -693,19 +708,9 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, Qt::KeyboardModifiers modifiers = mParent->modifiers(); - uint utf32 = xkb_keysym_to_utf32(sym); - if (utf32) - text = QString::fromUcs4(&utf32, 1); - + text = QWaylandXkb::textFromKeysym(sym, modifiers); qtkey = QWaylandXkb::keysymToQtKey(sym, modifiers, text); - - // Map control + letter to proper text - if (utf32 >= 'A' && utf32 <= '~' && (modifiers & Qt::ControlModifier)) { - utf32 &= ~0x60; - text = QString::fromUcs4(&utf32, 1); - } - sendKey(window->window(), time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); #else // Generic fallback for single hard keys: Assume 'key' is a Qt key code. diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 0da45c384..82b9d90c3 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -80,6 +80,7 @@ namespace QtWaylandClient { class QWaylandWindow; class QWaylandDisplay; class QWaylandDataDevice; +class QWaylandTextInput; class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice : public QObject @@ -108,6 +109,9 @@ public: void setDataDevice(QWaylandDataDevice *device); QWaylandDataDevice *dataDevice() const; + void setTextInput(QWaylandTextInput *textInput); + QWaylandTextInput *textInput() const; + void removeMouseButtonFromState(Qt::MouseButton button); QWaylandWindow *pointerFocus() const; @@ -138,6 +142,8 @@ private: Pointer *mPointer; Touch *mTouch; + QWaylandTextInput *mTextInput; + uint32_t mTime; uint32_t mSerial; diff --git a/src/compositor/compositor.pro b/src/compositor/compositor.pro index 67c735f98..37f670964 100644 --- a/src/compositor/compositor.pro +++ b/src/compositor/compositor.pro @@ -20,8 +20,8 @@ QMAKE_DOCS = $$PWD/doc/qtwaylandcompositor.qdocconf } INCLUDEPATH += ../shared -HEADERS += ../shared/qwaylandmimehelper.h -SOURCES += ../shared/qwaylandmimehelper.cpp +HEADERS += ../shared/qwaylandmimehelper.h ../shared/qwaylandinputmethodeventbuilder.h +SOURCES += ../shared/qwaylandmimehelper.cpp ../shared/qwaylandinputmethodeventbuilder.cpp include ($$PWD/global/global.pri) include ($$PWD/wayland_wrapper/wayland_wrapper.pri) diff --git a/src/compositor/compositor_api/compositor_api.pri b/src/compositor/compositor_api/compositor_api.pri index 1140efe34..1724ec965 100644 --- a/src/compositor/compositor_api/compositor_api.pri +++ b/src/compositor/compositor_api/compositor_api.pri @@ -14,7 +14,6 @@ HEADERS += \ compositor_api/qwaylandpointer_p.h \ compositor_api/qwaylandtouch.h \ compositor_api/qwaylandtouch_p.h \ - compositor_api/qwaylandinputpanel.h \ compositor_api/qwaylandoutput.h \ compositor_api/qwaylanddrag.h \ compositor_api/qwaylandbufferref.h \ @@ -24,6 +23,8 @@ HEADERS += \ compositor_api/qwaylandview_p.h \ compositor_api/qwaylandresource.h \ compositor_api/qwaylandsurfacegrabber.h \ + compositor_api/qwaylandinputmethodcontrol.h \ + compositor_api/qwaylandinputmethodcontrol_p.h SOURCES += \ compositor_api/qwaylandcompositor.cpp \ @@ -33,7 +34,6 @@ SOURCES += \ compositor_api/qwaylandkeyboard.cpp \ compositor_api/qwaylandpointer.cpp \ compositor_api/qwaylandtouch.cpp \ - compositor_api/qwaylandinputpanel.cpp \ compositor_api/qwaylandoutput.cpp \ compositor_api/qwaylanddrag.cpp \ compositor_api/qwaylandbufferref.cpp \ @@ -41,6 +41,7 @@ SOURCES += \ compositor_api/qwaylandview.cpp \ compositor_api/qwaylandresource.cpp \ compositor_api/qwaylandsurfacegrabber.cpp \ + compositor_api/qwaylandinputmethodcontrol.cpp QT += core-private diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 17b089dcf..9bc4f582b 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -85,6 +85,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(qLcCompositorInputMethods, "qt.compositor.input.methods") + namespace QtWayland { class WindowSystemEventHandler : public QWindowSystemEventHandler diff --git a/src/compositor/compositor_api/qwaylandcompositor.h b/src/compositor/compositor_api/qwaylandcompositor.h index a30786eb2..c03bcc5d1 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.h +++ b/src/compositor/compositor_api/qwaylandcompositor.h @@ -44,6 +44,7 @@ #include #include #include +#include struct wl_display; @@ -66,6 +67,8 @@ class QWaylandTouch; class QWaylandSurfaceGrabber; class QWaylandBufferRef; +Q_DECLARE_LOGGING_CATEGORY(qLcCompositorInputMethods) + class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandCompositor : public QWaylandObject { Q_OBJECT diff --git a/src/compositor/compositor_api/qwaylandinput.cpp b/src/compositor/compositor_api/qwaylandinput.cpp index ed1a9c786..ad6cb2369 100644 --- a/src/compositor/compositor_api/qwaylandinput.cpp +++ b/src/compositor/compositor_api/qwaylandinput.cpp @@ -38,17 +38,18 @@ #include "qwaylandinput_p.h" #include "qwaylandcompositor.h" +#include "qwaylandinputmethodcontrol.h" #include "qwaylandview.h" #include #include #include #include -#include #include #include #include #include "extensions/qwlqtkey_p.h" +#include "extensions/qwaylandtextinput.h" QT_BEGIN_NAMESPACE @@ -295,11 +296,21 @@ void QWaylandInputDevice::sendFullTouchEvent(QTouchEvent *event) void QWaylandInputDevice::sendFullKeyEvent(QKeyEvent *event) { Q_D(QWaylandInputDevice); + if (!keyboardFocus()) { qWarning("Cannot send key event, no keyboard focus, fix the compositor"); return; } + if (keyboardFocus()->inputMethodControl()->enabled() + && event->nativeScanCode() == 0) { + QWaylandTextInput *textInput = QWaylandTextInput::findIn(this); + if (textInput) { + textInput->sendKeyEvent(event); + return; + } + } + QtWayland::QtKeyExtensionGlobal *ext = QtWayland::QtKeyExtensionGlobal::findIn(d->compositor); if (ext && ext->postQtKeyEvent(event, keyboardFocus())) return; diff --git a/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp b/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp new file mode 100644 index 000000000..a82990f3d --- /dev/null +++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol.cpp @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandinputmethodcontrol.h" +#include "qwaylandinputmethodcontrol_p.h" + +#include "qwaylandcompositor.h" +#include "qwaylandinput.h" +#include "qwaylandsurface.h" +#include "qwaylandview.h" +#include "qwaylandtextinput.h" + +#include + +QWaylandInputMethodControl::QWaylandInputMethodControl(QWaylandSurface *surface) + : QObject(*new QWaylandInputMethodControlPrivate(surface), surface) +{ + connect(d_func()->compositor, &QWaylandCompositor::defaultInputDeviceChanged, + this, &QWaylandInputMethodControl::defaultInputDeviceChanged); + connect(d_func()->textInput(), &QWaylandTextInput::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled); + connect(d_func()->textInput(), &QWaylandTextInput::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled); +#ifndef QT_NO_IM + connect(d_func()->textInput(), &QWaylandTextInput::updateInputMethod, this, &QWaylandInputMethodControl::updateInputMethod); +#endif +} + +QVariant QWaylandInputMethodControl::inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const +{ + Q_D(const QWaylandInputMethodControl); + + QWaylandTextInput *textInput = d->textInput(); + + if (textInput && textInput->focus() == d->surface) { + return textInput->inputMethodQuery(query, argument); + } + + return QVariant(); +} + +void QWaylandInputMethodControl::inputMethodEvent(QInputMethodEvent *event) +{ + Q_D(QWaylandInputMethodControl); + + QWaylandTextInput *textInput = d->textInput(); + if (textInput) { + textInput->sendInputMethodEvent(event); + } else { + event->ignore(); + } +} + +bool QWaylandInputMethodControl::enabled() const +{ + Q_D(const QWaylandInputMethodControl); + + return d->enabled; +} + +void QWaylandInputMethodControl::setEnabled(bool enabled) +{ + Q_D(QWaylandInputMethodControl); + + if (d->enabled == enabled) + return; + + d->enabled = enabled; + emit enabledChanged(enabled); +#ifndef QT_NO_IM + emit updateInputMethod(Qt::ImQueryInput); +#endif +} + +void QWaylandInputMethodControl::surfaceEnabled(QWaylandSurface *surface) +{ + Q_D(QWaylandInputMethodControl); + + if (surface == d->surface) + setEnabled(true); +} + +void QWaylandInputMethodControl::surfaceDisabled(QWaylandSurface *surface) +{ + Q_D(QWaylandInputMethodControl); + + if (surface == d->surface) + setEnabled(false); +} + +void QWaylandInputMethodControl::setSurface(QWaylandSurface *surface) +{ + Q_D(QWaylandInputMethodControl); + + if (d->surface == surface) + return; + + d->surface = surface; + + QWaylandTextInput *textInput = d->textInput(); + setEnabled(textInput && textInput->isSurfaceEnabled(d->surface)); +} + +void QWaylandInputMethodControl::defaultInputDeviceChanged() +{ + Q_D(QWaylandInputMethodControl); + + disconnect(d->textInput(), 0, this, 0); + + d->inputDevice = d->compositor->defaultInputDevice(); + QWaylandTextInput *textInput = d->textInput(); + + connect(textInput, &QWaylandTextInput::surfaceEnabled, this, &QWaylandInputMethodControl::surfaceEnabled); + connect(textInput, &QWaylandTextInput::surfaceDisabled, this, &QWaylandInputMethodControl::surfaceDisabled); + + setEnabled(textInput && textInput->isSurfaceEnabled(d->surface)); +} + +QWaylandInputMethodControlPrivate::QWaylandInputMethodControlPrivate(QWaylandSurface *surface) + : QObjectPrivate() + , compositor(surface->compositor()) + , inputDevice(compositor->defaultInputDevice()) + , surface(surface) + , enabled(false) +{ +} + +QWaylandTextInput *QWaylandInputMethodControlPrivate::textInput() const +{ + return QWaylandTextInput::findIn(inputDevice); +} diff --git a/src/compositor/compositor_api/qwaylandinputmethodcontrol.h b/src/compositor/compositor_api/qwaylandinputmethodcontrol.h new file mode 100644 index 000000000..f71650294 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDINPUTMETHODCONTROL_H +#define QWAYLANDINPUTMETHODCONTROL_H + +#include + +QT_BEGIN_NAMESPACE + +class QWaylandCompositor; +class QWaylandInputMethodControlPrivate; +class QWaylandSurface; +class QInputMethodEvent; + +class QWaylandInputMethodControl : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandInputMethodControl) + Q_DISABLE_COPY(QWaylandInputMethodControl) + + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) +public: + explicit QWaylandInputMethodControl(QWaylandSurface *surface); + +#ifndef QT_NO_IM + QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const; +#endif + + void inputMethodEvent(QInputMethodEvent *event); + + bool enabled() const; + void setEnabled(bool enabled); + + void setSurface(QWaylandSurface *surface); + +Q_SIGNALS: + void enabledChanged(bool enabled); +#ifndef QT_NO_IM + void updateInputMethod(Qt::InputMethodQueries queries); +#endif + +private: + void defaultInputDeviceChanged(); + void surfaceEnabled(QWaylandSurface *surface); + void surfaceDisabled(QWaylandSurface *surface); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDINPUTMETHODCONTROL_H diff --git a/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h b/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h new file mode 100644 index 000000000..a687e5299 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDINPUTMETHODCONTROL_P_H +#define QWAYLANDINPUTMETHODCONTROL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QWaylandCompositor; +class QWaylandInputDevice; +class QWaylandSurface; +class QWaylandTextInput; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandInputMethodControlPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QWaylandInputMethodControl) + +public: + explicit QWaylandInputMethodControlPrivate(QWaylandSurface *surface); + + QWaylandTextInput *textInput() const; + + QWaylandCompositor *compositor; + QWaylandInputDevice *inputDevice; + QWaylandSurface *surface; + bool enabled; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDINPUTMETHODCONTROL_P_H diff --git a/src/compositor/compositor_api/qwaylandinputpanel.cpp b/src/compositor/compositor_api/qwaylandinputpanel.cpp deleted file mode 100644 index 6f774cd98..000000000 --- a/src/compositor/compositor_api/qwaylandinputpanel.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwaylandinputpanel.h" - -#include - -#include - -#include "qwlinputpanel_p.h" - -QT_BEGIN_NAMESPACE - -QWaylandInputPanel::QWaylandInputPanel(QWaylandCompositor *compositor) - : QWaylandExtensionTemplate(compositor, *new QWaylandInputPanelPrivate(compositor)) -{ -} - -QWaylandSurface *QWaylandInputPanel::focus() const -{ - Q_D(const QWaylandInputPanel); - - return d->focus(); -} - -bool QWaylandInputPanel::visible() const -{ - Q_D(const QWaylandInputPanel); - - return d->inputPanelVisible(); -} - -QRect QWaylandInputPanel::cursorRectangle() const -{ - Q_D(const QWaylandInputPanel); - - return d->cursorRectangle(); -} - -const struct wl_interface *QWaylandInputPanel::interface() -{ - return QWaylandInputPanelPrivate::interface(); -} - -QByteArray QWaylandInputPanel::interfaceName() -{ - return QWaylandInputPanelPrivate::interfaceName(); -} - -QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandinputpanel.h b/src/compositor/compositor_api/qwaylandinputpanel.h deleted file mode 100644 index d29743140..000000000 --- a/src/compositor/compositor_api/qwaylandinputpanel.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWAYLANDINPUTPANEL_H -#define QWAYLANDINPUTPANEL_H - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class QWaylandCompositor; -class QWaylandInputPanelPrivate; -class QWaylandSurface; - -class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandInputPanel : public QWaylandExtensionTemplate -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QWaylandInputPanel) - - Q_PROPERTY(QWaylandSurface* focus READ focus NOTIFY focusChanged) - Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged) - Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) - -public: - explicit QWaylandInputPanel(QWaylandCompositor *compositor); - - QWaylandSurface *focus() const; - bool visible() const; - QRect cursorRectangle() const; - - static const struct wl_interface *interface(); - static QByteArray interfaceName(); -Q_SIGNALS: - void focusChanged(); - void visibleChanged(); - void cursorRectangleChanged(); -}; - -QT_END_NAMESPACE - -#endif // QWAYLANDINPUTPANEL_H diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 8fd759bda..bee12b4a5 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -37,6 +37,8 @@ #include "qwaylandquickitem.h" #include "qwaylandquickitem_p.h" #include "qwaylandquicksurface.h" +#include "qwaylandinputmethodcontrol.h" +#include "qwaylandtextinput.h" #include #include #include @@ -54,6 +56,7 @@ #include #include + QT_BEGIN_NAMESPACE QMutex *QWaylandQuickItemPrivate::mutex = 0; @@ -459,6 +462,21 @@ void QWaylandQuickItem::mouseUngrabEvent() } } +#ifndef QT_NO_IM +/*! + * \internal + */ +void QWaylandQuickItem::inputMethodEvent(QInputMethodEvent *event) +{ + Q_D(QWaylandQuickItem); + if (d->shouldSendInputEvents()) { + d->oldSurface->inputMethodControl()->inputMethodEvent(event); + } else { + event->ignore(); + } +} +#endif + /*! * \internal */ @@ -480,6 +498,9 @@ void QWaylandQuickItem::handleSurfaceChanged() disconnect(d->oldSurface, &QWaylandSurface::sizeChanged, this, &QWaylandQuickItem::updateSize); disconnect(d->oldSurface, &QWaylandSurface::configure, this, &QWaylandQuickItem::updateBuffer); disconnect(d->oldSurface, &QWaylandSurface::redraw, this, &QQuickItem::update); +#ifndef QT_NO_IM + disconnect(d->oldSurface->inputMethodControl(), &QWaylandInputMethodControl::updateInputMethod, this, &QWaylandQuickItem::updateInputMethod); +#endif } if (QWaylandSurface *newSurface = d->view->surface()) { connect(newSurface, &QWaylandSurface::mappedChanged, this, &QWaylandQuickItem::surfaceMappedChanged); @@ -487,6 +508,9 @@ void QWaylandQuickItem::handleSurfaceChanged() connect(newSurface, &QWaylandSurface::sizeChanged, this, &QWaylandQuickItem::updateSize); connect(newSurface, &QWaylandSurface::configure, this, &QWaylandQuickItem::updateBuffer); connect(newSurface, &QWaylandSurface::redraw, this, &QQuickItem::update); +#ifndef QT_NO_IM + connect(newSurface->inputMethodControl(), &QWaylandInputMethodControl::updateInputMethod, this, &QWaylandQuickItem::updateInputMethod); +#endif if (d->sizeFollowsSurface) { setWidth(newSurface->size().width()); setHeight(newSurface->size().height()); @@ -502,6 +526,9 @@ void QWaylandQuickItem::handleSurfaceChanged() } surfaceChangedEvent(d->view->surface(), d->oldSurface); d->oldSurface = d->view->surface(); +#ifndef QT_NO_IM + updateInputMethod(Qt::ImQueryInput); +#endif } /*! @@ -510,7 +537,7 @@ void QWaylandQuickItem::handleSurfaceChanged() */ void QWaylandQuickItem::takeFocus(QWaylandInputDevice *device) { - setFocus(true); + forceActiveFocus(); if (!surface()) return; @@ -520,6 +547,9 @@ void QWaylandQuickItem::takeFocus(QWaylandInputDevice *device) target = compositor()->defaultInputDevice(); } target->setKeyboardFocus(surface()); + QWaylandTextInput *textInput = QWaylandTextInput::findIn(target); + if (textInput) + textInput->setFocus(surface()); } /*! @@ -632,6 +662,23 @@ void QWaylandQuickItem::setSizeFollowsSurface(bool sizeFollowsSurface) emit sizeFollowsSurfaceChanged(); } +#ifndef QT_NO_IM +QVariant QWaylandQuickItem::inputMethodQuery(Qt::InputMethodQuery query) const +{ + return inputMethodQuery(query, QVariant()); +} + +QVariant QWaylandQuickItem::inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const +{ + Q_D(const QWaylandQuickItem); + + if (query == Qt::ImEnabled) + return QVariant((flags() & ItemAcceptsInputMethod) != 0); + + return d->oldSurface->inputMethodControl()->inputMethodQuery(query, argument); +} +#endif + /*! \qmlproperty bool QtWayland::QWaylandSurfaceItem::paintEnabled @@ -698,6 +745,17 @@ void QWaylandQuickItem::beforeSync() } } +#ifndef QT_NO_IM +void QWaylandQuickItem::updateInputMethod(Qt::InputMethodQueries queries) +{ + Q_D(QWaylandQuickItem); + + setFlag(QQuickItem::ItemAcceptsInputMethod, + d->oldSurface ? d->oldSurface->inputMethodControl()->enabled() : false); + QQuickItem::updateInputMethod(queries | Qt::ImEnabled); +} +#endif + QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { Q_D(QWaylandQuickItem); diff --git a/src/compositor/compositor_api/qwaylandquickitem.h b/src/compositor/compositor_api/qwaylandquickitem.h index 81ea5213b..9dab65acf 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.h +++ b/src/compositor/compositor_api/qwaylandquickitem.h @@ -99,6 +99,11 @@ public: bool sizeFollowsSurface() const; void setSizeFollowsSurface(bool sizeFollowsSurface); +#ifndef QT_NO_IM + QVariant inputMethodQuery(Qt::InputMethodQuery query) const Q_DECL_OVERRIDE; + Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const; +#endif + protected: void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; @@ -114,6 +119,10 @@ protected: void touchEvent(QTouchEvent *event) Q_DECL_OVERRIDE; void mouseUngrabEvent() Q_DECL_OVERRIDE; +#ifndef QT_NO_IM + void inputMethodEvent(QInputMethodEvent *event) Q_DECL_OVERRIDE; +#endif + virtual void surfaceChangedEvent(QWaylandSurface *newSurface, QWaylandSurface *oldSurface); public Q_SLOTS: virtual void takeFocus(QWaylandInputDevice *device = 0); @@ -129,6 +138,9 @@ private Q_SLOTS: void updateBuffer(bool hasBuffer); void updateWindow(); void beforeSync(); +#ifndef QT_NO_IM + void updateInputMethod(Qt::InputMethodQueries queries); +#endif Q_SIGNALS: void surfaceChanged(); diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index 97e4b6a80..3a16ed27a 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -43,6 +43,7 @@ #include "wayland_wrapper/qwlregion_p.h" #include "extensions/qwlextendedsurface_p.h" +#include "qwaylandinputmethodcontrol_p.h" #include #include @@ -124,13 +125,13 @@ QWaylandSurfacePrivate::QWaylandSurfacePrivate() , client(Q_NULLPTR) , buffer(0) , role(0) - , inputPanelSurface(0) , inputRegion(infiniteRegion()) , isCursorSurface(false) , destroyed(false) , mapped(false) , isInitialized(false) , contentOrientation(Qt::PrimaryOrientation) + , inputMethodControl(Q_NULLPTR) , subsurface(0) { pending.buffer = 0; @@ -426,6 +427,7 @@ void QWaylandSurface::initialize(QWaylandCompositor *compositor, QWaylandClient d->client = client; d->init(client->client(), id, version); d->isInitialized = true; + d->inputMethodControl = new QWaylandInputMethodControl(this); #ifndef QT_NO_DEBUG QWaylandSurfacePrivate::removeUninitializedSurface(d); #endif @@ -587,16 +589,6 @@ void QWaylandSurface::sendFrameCallbacks() } } -/*! - * Returns true if the QWaylandSurface has an input panel surface. Otherwise returns false. - */ -bool QWaylandSurface::hasInputPanelSurface() const -{ - Q_D(const QWaylandSurface); - - return d->inputPanelSurface != 0; -} - /*! * Returns true if the QWaylandSurface's input region contains the point \a p. * Otherwise returns false. @@ -660,6 +652,12 @@ bool QWaylandSurface::isCursorSurface() const return d->isCursorSurface; } +QWaylandInputMethodControl *QWaylandSurface::inputMethodControl() const +{ + Q_D(const QWaylandSurface); + return d->inputMethodControl; +} + /*! * Updates the surface with the compositor's retained clipboard selection. While this * is done automatically when the surface receives keyboard focus, this function is diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h index a782e5bae..6abdbdef5 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -59,6 +59,7 @@ class QWaylandCompositor; class QWaylandBufferRef; class QWaylandView; class QWaylandSurfaceOp; +class QWaylandInputMethodControl; class QWaylandSurfaceRole { @@ -112,8 +113,6 @@ public: QWaylandCompositor *compositor() const; - bool hasInputPanelSurface() const; - bool inputRegionContains(const QPoint &p) const; Q_INVOKABLE void destroy(); @@ -133,6 +132,8 @@ public: void markAsCursorSurface(bool cursorSurface); bool isCursorSurface() const; + QWaylandInputMethodControl *inputMethodControl() const; + public Q_SLOTS: void updateSelection(); diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h index 635820931..d8b289c63 100644 --- a/src/compositor/compositor_api/qwaylandsurface_p.h +++ b/src/compositor/compositor_api/qwaylandsurface_p.h @@ -56,7 +56,6 @@ #include #include -#include #include #include @@ -78,6 +77,7 @@ class QWaylandCompositor; class QWaylandSurface; class QWaylandView; class QWaylandSurfaceInterface; +class QWaylandInputMethodControl; namespace QtWayland { class FrameCallback; @@ -105,8 +105,6 @@ public: void notifyViewsAboutDestruction(); - void setInputPanelSurface(QtWayland::InputPanelSurface *ips) { inputPanelSurface = ips; } - #ifndef QT_NO_DEBUG static void addUninitializedSurface(QWaylandSurfacePrivate *surface); static void removeUninitializedSurface(QWaylandSurfacePrivate *surface); @@ -161,8 +159,6 @@ public: //member variables QList pendingFrameCallbacks; QList frameCallbacks; - QtWayland::InputPanelSurface *inputPanelSurface; - QRegion inputRegion; QRegion opaqueRegion; @@ -175,6 +171,7 @@ public: //member variables bool isInitialized; Qt::ScreenOrientation contentOrientation; QWindow::Visibility visibility; + QWaylandInputMethodControl *inputMethodControl; class Subsurface : public QtWaylandServer::wl_subsurface { diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri index 03be3905e..1d34803f0 100644 --- a/src/compositor/extensions/extensions.pri +++ b/src/compositor/extensions/extensions.pri @@ -4,8 +4,7 @@ WAYLANDSERVERSOURCES += \ ../extensions/touch-extension.xml \ ../extensions/qtkey-extension.xml \ ../extensions/windowmanager.xml \ - ../3rdparty/protocol/input-method.xml \ - ../3rdparty/protocol/text.xml \ + ../3rdparty/protocol/text-input-unstable-v2.xml \ ../3rdparty/protocol/xdg-shell.xml \ HEADERS += \ @@ -14,14 +13,12 @@ HEADERS += \ extensions/qwlqtkey_p.h \ extensions/qwaylandwlshell.h \ extensions/qwaylandwlshell_p.h \ + extensions/qwaylandtextinput.h \ + extensions/qwaylandtextinput_p.h \ + extensions/qwaylandtextinputmanager.h \ + extensions/qwaylandtextinputmanager_p.h \ extensions/qwaylandwindowmanagerextension.h \ extensions/qwaylandwindowmanagerextension_p.h \ - extensions/qwltextinput_p.h \ - extensions/qwltextinputmanager_p.h \ - extensions/qwlinputpanel_p.h \ - extensions/qwlinputpanelsurface_p.h \ - extensions/qwlinputmethod_p.h \ - extensions/qwlinputmethodcontext_p.h \ extensions/qwaylandxdgshell.h \ extensions/qwaylandxdgshell_p.h \ @@ -30,13 +27,9 @@ SOURCES += \ extensions/qwlqttouch.cpp \ extensions/qwlqtkey.cpp \ extensions/qwaylandwlshell.cpp \ + extensions/qwaylandtextinput.cpp \ + extensions/qwaylandtextinputmanager.cpp \ extensions/qwaylandwindowmanagerextension.cpp \ - extensions/qwltextinput.cpp \ - extensions/qwltextinputmanager.cpp \ - extensions/qwlinputpanel.cpp \ - extensions/qwlinputpanelsurface.cpp \ - extensions/qwlinputmethod.cpp \ - extensions/qwlinputmethodcontext.cpp \ extensions/qwaylandxdgshell.cpp \ qtHaveModule(quick) { diff --git a/src/compositor/extensions/qwaylandtextinput.cpp b/src/compositor/extensions/qwaylandtextinput.cpp new file mode 100644 index 000000000..31166ddb2 --- /dev/null +++ b/src/compositor/extensions/qwaylandtextinput.cpp @@ -0,0 +1,591 @@ +/**************************************************************************** +** +** Copyright (C) 2013-2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandtextinput.h" +#include "qwaylandtextinput_p.h" + +#include +#include + +#include "qwaylandsurface.h" +#include "qwaylandview.h" +#include "qwaylandxkb.h" +#include "qwaylandinputmethodeventbuilder.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QWaylandTextInputClientState::QWaylandTextInputClientState() + : hints(0) + , cursorRectangle() + , surroundingText() + , cursorPosition(0) + , anchorPosition(0) + , preferredLanguage() + , changedState() +{ +} + +Qt::InputMethodQueries QWaylandTextInputClientState::updatedQueries(const QWaylandTextInputClientState &other) const +{ + Qt::InputMethodQueries queries; + + if (hints != other.hints) + queries |= Qt::ImHints; + if (cursorRectangle != other.cursorRectangle) + queries |= Qt::ImCursorRectangle; + if (surroundingText != other.surroundingText) + queries |= Qt::ImSurroundingText | Qt::ImCurrentSelection; + if (cursorPosition != other.cursorPosition) + queries |= Qt::ImCursorPosition | Qt::ImCurrentSelection; + if (anchorPosition != other.anchorPosition) + queries |= Qt::ImAnchorPosition | Qt::ImCurrentSelection; + if (preferredLanguage != other.preferredLanguage) + queries |= Qt::ImPreferredLanguage; + + return queries; +} + +Qt::InputMethodQueries QWaylandTextInputClientState::mergeChanged(const QWaylandTextInputClientState &other) { + Qt::InputMethodQueries queries; + + if ((other.changedState & Qt::ImHints) && hints != other.hints) { + hints = other.hints; + queries |= Qt::ImHints; + } + + if ((other.changedState & Qt::ImCursorRectangle) && cursorRectangle != other.cursorRectangle) { + cursorRectangle = other.cursorRectangle; + queries |= Qt::ImCursorRectangle; + } + + if ((other.changedState & Qt::ImSurroundingText) && surroundingText != other.surroundingText) { + surroundingText = other.surroundingText; + queries |= Qt::ImSurroundingText | Qt::ImCurrentSelection; + } + + if ((other.changedState & Qt::ImCursorPosition) && cursorPosition != other.cursorPosition) { + cursorPosition = other.cursorPosition; + queries |= Qt::ImCursorPosition | Qt::ImCurrentSelection; + } + + if ((other.changedState & Qt::ImAnchorPosition) && anchorPosition != other.anchorPosition) { + anchorPosition = other.anchorPosition; + queries |= Qt::ImAnchorPosition | Qt::ImCurrentSelection; + } + + if ((other.changedState & Qt::ImPreferredLanguage) && preferredLanguage != other.preferredLanguage) { + preferredLanguage = other.preferredLanguage; + queries |= Qt::ImPreferredLanguage; + } + + return queries; +} + +QWaylandTextInputPrivate::QWaylandTextInputPrivate(QWaylandCompositor *compositor) + : QWaylandExtensionTemplatePrivate() + , QtWaylandServer::zwp_text_input_v2() + , compositor(compositor) + , focus(nullptr) + , focusResource(nullptr) + , focusDestroyListener() + , inputPanelVisible(false) + , currentState(new QWaylandTextInputClientState) + , pendingState(new QWaylandTextInputClientState) + , serial(0) + , enabledSurfaces() +{ +} + +void QWaylandTextInputPrivate::sendInputMethodEvent(QInputMethodEvent *event) +{ + if (!focusResource || !focusResource->handle) + return; + + if (event->replacementLength() > 0 || event->replacementStart() != 0) { + if (event->replacementStart() <= 0 && (event->replacementLength() >= -event->replacementStart())) { + const int selectionStart = qMin(currentState->cursorPosition, currentState->anchorPosition); + const int selectionEnd = qMax(currentState->cursorPosition, currentState->anchorPosition); + const int before = currentState->surroundingText.midRef(selectionStart + event->replacementStart(), -event->replacementStart()).toUtf8().size(); + const int after = currentState->surroundingText.midRef(selectionEnd, event->replacementLength() + event->replacementStart()).toUtf8().size(); + send_delete_surrounding_text(focusResource->handle, before, after); + } else { + // TODO: Implement this case + qWarning() << "Not yet supported case of replacement. Start:" << event->replacementStart() << "length:" << event->replacementLength(); + } + } + foreach (const QInputMethodEvent::Attribute &attribute, event->attributes()) { + if (attribute.type == QInputMethodEvent::Selection) { + const int cursorAfterCommit = qMin(currentState->cursorPosition, currentState->anchorPosition) + event->replacementStart() + event->commitString().length(); + QString textAfterCommit = currentState->surroundingText; + textAfterCommit.remove(qMin(currentState->cursorPosition, currentState->anchorPosition), + qAbs(currentState->cursorPosition - currentState->anchorPosition)); + textAfterCommit.replace(qMin(currentState->cursorPosition, currentState->anchorPosition) + event->replacementStart(), + event->replacementLength(), event->commitString()); + + int cursor = textAfterCommit.midRef(qMin(attribute.start, cursorAfterCommit), qAbs(attribute.start - cursorAfterCommit)).toUtf8().size(); + int anchor = textAfterCommit.midRef(qMin(attribute.length, cursorAfterCommit), qAbs(attribute.length - cursorAfterCommit)).toUtf8().size(); + send_cursor_position(focusResource->handle, + attribute.start < cursorAfterCommit ? -cursor : cursor, + attribute.start < cursorAfterCommit ? -anchor : anchor); + } + } + send_commit_string(focusResource->handle, event->commitString()); + foreach (const QInputMethodEvent::Attribute &attribute, event->attributes()) { + if (attribute.type == QInputMethodEvent::Cursor) { + int index = event->preeditString().leftRef(attribute.start).toUtf8().size(); + send_preedit_cursor(focusResource->handle, index); + } else if (attribute.type == QInputMethodEvent::TextFormat) { + int start = currentState->surroundingText.leftRef(attribute.start).toUtf8().size(); + int end = currentState->surroundingText.leftRef(attribute.start + attribute.length).toUtf8().size(); + // TODO add support for different stylesQWaylandTextInput + send_preedit_styling(focusResource->handle, start, end - start, preedit_style_default); + } + } + send_preedit_string(focusResource->handle, event->preeditString(), event->preeditString()); +} + +void QWaylandTextInputPrivate::sendKeyEvent(QKeyEvent *event) +{ + if (!focusResource || !focusResource->handle) + return; + + // TODO add support for modifiers + + foreach (xkb_keysym_t keysym, QWaylandXkb::toKeysym(event)) { + send_keysym(focusResource->handle, event->timestamp(), keysym, + event->type() == QEvent::KeyPress ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED, + 0); + } +} + +void QWaylandTextInputPrivate::sendInputPanelState() +{ + if (!focusResource || !focusResource->handle) + return; + + QInputMethod *inputMethod = qApp->inputMethod(); + const QRectF& keyboardRect = inputMethod->keyboardRectangle(); + const QRectF& sceneInputRect = inputMethod->inputItemTransform().mapRect(inputMethod->inputItemRectangle()); + const QRectF& localRect = sceneInputRect.intersected(keyboardRect).translated(-sceneInputRect.topLeft()); + + send_input_panel_state(focusResource->handle, + inputMethod->isVisible() ? input_panel_visibility_visible : input_panel_visibility_hidden, + localRect.x(), localRect.y(), localRect.width(), localRect.height()); +} + +void QWaylandTextInputPrivate::sendTextDirection() +{ + if (!focusResource || !focusResource->handle) + return; + + const Qt::LayoutDirection direction = qApp->inputMethod()->inputDirection(); + send_text_direction(focusResource->handle, + (direction == Qt::LeftToRight) ? text_direction_ltr : + (direction == Qt::RightToLeft) ? text_direction_rtl : text_direction_auto); +} + +void QWaylandTextInputPrivate::sendLocale() +{ + if (!focusResource || !focusResource->handle) + return; + + const QLocale locale = qApp->inputMethod()->locale(); + send_language(focusResource->handle, locale.bcp47Name()); +} + +QVariant QWaylandTextInputPrivate::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const +{ + switch (property) { + case Qt::ImHints: + return QVariant(static_cast(currentState->hints)); + case Qt::ImCursorRectangle: + return currentState->cursorRectangle; + case Qt::ImFont: + // Not supported + return QVariant(); + case Qt::ImCursorPosition: + return currentState->cursorPosition; + case Qt::ImSurroundingText: + return currentState->surroundingText; + case Qt::ImCurrentSelection: + return currentState->surroundingText.mid(qMin(currentState->cursorPosition, currentState->anchorPosition), + qAbs(currentState->anchorPosition - currentState->cursorPosition)); + case Qt::ImMaximumTextLength: + // Not supported + return QVariant(); + case Qt::ImAnchorPosition: + return currentState->anchorPosition; + case Qt::ImAbsolutePosition: + // We assume the surrounding text is our whole document for now + return currentState->cursorPosition; + case Qt::ImTextAfterCursor: + if (argument.isValid()) + return currentState->surroundingText.mid(currentState->cursorPosition, argument.toInt()); + return currentState->surroundingText.mid(currentState->cursorPosition); + case Qt::ImTextBeforeCursor: + if (argument.isValid()) + return currentState->surroundingText.left(currentState->cursorPosition).right(argument.toInt()); + return currentState->surroundingText.left(currentState->cursorPosition); + case Qt::ImPreferredLanguage: + return currentState->preferredLanguage; + + default: + return QVariant(); + } +} + +void QWaylandTextInputPrivate::setFocus(QWaylandSurface *surface) +{ + Q_Q(QWaylandTextInput); + + if (focusResource && focus != surface) { + uint32_t serial = compositor->nextSerial(); + send_leave(focusResource->handle, serial, focus->resource()); + focusDestroyListener.reset(); + } + + Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0; + + if (resource && (focus != surface || focusResource != resource)) { + uint32_t serial = compositor->nextSerial(); + currentState.reset(new QWaylandTextInputClientState); + pendingState.reset(new QWaylandTextInputClientState); + send_enter(resource->handle, serial, surface->resource()); + focusResource = resource; + sendInputPanelState(); + sendLocale(); + sendTextDirection(); + focusDestroyListener.listenForDestruction(surface->resource()); + if (inputPanelVisible && q->isSurfaceEnabled(surface)) + qApp->inputMethod()->show(); + } + + focusResource = resource; + focus = surface; +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_bind_resource(Resource *resource) +{ + send_modifiers_map(resource->handle, QByteArray("")); +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_destroy_resource(Resource *resource) +{ + if (focusResource == resource) + focusResource = 0; +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_enable(Resource *resource, wl_resource *surface) +{ + Q_Q(QWaylandTextInput); + + QWaylandSurface *s = QWaylandSurface::fromResource(surface); + enabledSurfaces.insert(resource, s); + emit q->surfaceEnabled(s); +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_disable(QtWaylandServer::zwp_text_input_v2::Resource *resource, wl_resource *) +{ + Q_Q(QWaylandTextInput); + + QWaylandSurface *s = enabledSurfaces.take(resource); + emit q->surfaceDisabled(s); +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_show_input_panel(Resource *) +{ + inputPanelVisible = true; + + qApp->inputMethod()->show(); +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_hide_input_panel(Resource *) +{ + inputPanelVisible = false; + + qApp->inputMethod()->hide(); +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) +{ + if (resource != focusResource) + return; + + pendingState->cursorRectangle = QRect(x, y, width, height); + + pendingState->changedState |= Qt::ImCursorRectangle; +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_update_state(Resource *resource, uint32_t serial, uint32_t flags) +{ + Q_Q(QWaylandTextInput); + + qCDebug(qLcCompositorInputMethods) << "update_state" << serial << flags; + + if (resource != focusResource) + return; + + if (flags == update_state_reset || flags == update_state_enter) { + qCDebug(qLcCompositorInputMethods) << "QInputMethod::reset()"; + qApp->inputMethod()->reset(); + } + + this->serial = serial; + + Qt::InputMethodQueries queries; + if (flags == update_state_change) { + queries = currentState->mergeChanged(*pendingState.data()); + } else { + queries = pendingState->updatedQueries(*currentState.data()); + currentState.swap(pendingState); + } + + pendingState.reset(new QWaylandTextInputClientState); + + if (queries) { + qCDebug(qLcCompositorInputMethods) << "QInputMethod::update()" << queries; + + emit q->updateInputMethod(queries); + } +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose) +{ + if (resource != focusResource) + return; + + pendingState->hints = 0; + + if ((hint & content_hint_auto_completion) == 0 + && (hint & content_hint_auto_correction) == 0) + pendingState->hints |= Qt::ImhNoPredictiveText; + if ((hint & content_hint_auto_capitalization) == 0) + pendingState->hints |= Qt::ImhNoAutoUppercase; + if ((hint & content_hint_lowercase) != 0) + pendingState->hints |= Qt::ImhPreferLowercase; + if ((hint & content_hint_uppercase) != 0) + pendingState->hints |= Qt::ImhPreferUppercase; + if ((hint & content_hint_hidden_text) != 0) + pendingState->hints |= Qt::ImhHiddenText; + if ((hint & content_hint_sensitive_data) != 0) + pendingState->hints |= Qt::ImhSensitiveData; + if ((hint & content_hint_latin) != 0) + pendingState->hints |= Qt::ImhLatinOnly; + if ((hint & content_hint_multiline) != 0) + pendingState->hints |= Qt::ImhMultiLine; + + switch (purpose) { + case content_purpose_normal: + break; + case content_purpose_alpha: + pendingState->hints |= Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly; + break; + case content_purpose_digits: + pendingState->hints |= Qt::ImhDigitsOnly; + break; + case content_purpose_number: + pendingState->hints |= Qt::ImhFormattedNumbersOnly; + break; + case content_purpose_phone: + pendingState->hints |= Qt::ImhDialableCharactersOnly; + break; + case content_purpose_url: + pendingState->hints |= Qt::ImhUrlCharactersOnly; + break; + case content_purpose_email: + pendingState->hints |= Qt::ImhEmailCharactersOnly; + break; + case content_purpose_name: + case content_purpose_password: + break; + case content_purpose_date: + pendingState->hints |= Qt::ImhDate; + break; + case content_purpose_time: + pendingState->hints |= Qt::ImhTime; + break; + case content_purpose_datetime: + pendingState->hints |= Qt::ImhDate | Qt::ImhTime; + break; + case content_purpose_terminal: + default: + break; + } + + pendingState->changedState |= Qt::ImHints; +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_set_preferred_language(Resource *resource, const QString &language) +{ + if (resource != focusResource) + return; + + pendingState->preferredLanguage = language; + + pendingState->changedState |= Qt::ImPreferredLanguage; +} + +void QWaylandTextInputPrivate::zwp_text_input_v2_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor) +{ + if (resource != focusResource) + return; + + pendingState->surroundingText = text; + pendingState->cursorPosition = QWaylandInputMethodEventBuilder::indexFromWayland(text, cursor); + pendingState->anchorPosition = QWaylandInputMethodEventBuilder::indexFromWayland(text, anchor); + + pendingState->changedState |= Qt::ImSurroundingText | Qt::ImCursorPosition | Qt::ImAnchorPosition; +} + +QWaylandTextInput::QWaylandTextInput(QWaylandObject *container, QWaylandCompositor *compositor) + : QWaylandExtensionTemplate(container, *new QWaylandTextInputPrivate(compositor)) +{ + connect(&d_func()->focusDestroyListener, &QWaylandDestroyListener::fired, + this, &QWaylandTextInput::focusSurfaceDestroyed); + + connect(qApp->inputMethod(), &QInputMethod::visibleChanged, + this, &QWaylandTextInput::sendInputPanelState); + connect(qApp->inputMethod(), &QInputMethod::keyboardRectangleChanged, + this, &QWaylandTextInput::sendInputPanelState); + connect(qApp->inputMethod(), &QInputMethod::inputDirectionChanged, + this, &QWaylandTextInput::sendTextDirection); + connect(qApp->inputMethod(), &QInputMethod::localeChanged, + this, &QWaylandTextInput::sendLocale); +} + +QWaylandTextInput::~QWaylandTextInput() +{ +} + +void QWaylandTextInput::sendInputMethodEvent(QInputMethodEvent *event) +{ + Q_D(QWaylandTextInput); + + d->sendInputMethodEvent(event); +} + +void QWaylandTextInput::sendKeyEvent(QKeyEvent *event) +{ + Q_D(QWaylandTextInput); + + d->sendKeyEvent(event); +} + +void QWaylandTextInput::sendInputPanelState() +{ + Q_D(QWaylandTextInput); + + d->sendInputPanelState(); +} + +void QWaylandTextInput::sendTextDirection() +{ + Q_D(QWaylandTextInput); + + d->sendTextDirection(); +} + +void QWaylandTextInput::sendLocale() +{ + Q_D(QWaylandTextInput); + + d->sendLocale(); +} + +QVariant QWaylandTextInput::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const +{ + const Q_D(QWaylandTextInput); + + return d->inputMethodQuery(property, argument); +} + +QWaylandSurface *QWaylandTextInput::focus() const +{ + const Q_D(QWaylandTextInput); + + return d->focus; +} + +void QWaylandTextInput::setFocus(QWaylandSurface *surface) +{ + Q_D(QWaylandTextInput); + + d->setFocus(surface); +} + +void QWaylandTextInput::focusSurfaceDestroyed(void *) +{ + Q_D(QWaylandTextInput); + + d->focusDestroyListener.reset(); + + d->focus = nullptr; + d->focusResource = nullptr; +} + +bool QWaylandTextInput::isSurfaceEnabled(QWaylandSurface *surface) const +{ + const Q_D(QWaylandTextInput); + + return d->enabledSurfaces.values().contains(surface); +} + +void QWaylandTextInput::add(::wl_client *client, uint32_t id, int version) +{ + Q_D(QWaylandTextInput); + + d->add(client, id, version); +} + +const wl_interface *QWaylandTextInput::interface() +{ + return QWaylandTextInputPrivate::interface(); +} + +QByteArray QWaylandTextInput::interfaceName() +{ + return QWaylandTextInputPrivate::interfaceName(); +} + +QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwaylandtextinput.h b/src/compositor/extensions/qwaylandtextinput.h new file mode 100644 index 000000000..100384e76 --- /dev/null +++ b/src/compositor/extensions/qwaylandtextinput.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2013-2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDTEXTINPUT_H +#define QWAYLANDTEXTINPUT_H + +#include + +QT_BEGIN_NAMESPACE + +class QWaylandTextInputPrivate; + +class QInputMethodEvent; +class QKeyEvent; +class QWaylandSurface; + +class QWaylandTextInput : public QWaylandExtensionTemplate +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandTextInput) +public: + explicit QWaylandTextInput(QWaylandObject *container, QWaylandCompositor *compositor); + ~QWaylandTextInput(); + + void sendInputMethodEvent(QInputMethodEvent *event); + void sendKeyEvent(QKeyEvent *event); + + QVariant inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const; + + QWaylandSurface *focus() const; + void setFocus(QWaylandSurface *surface); + + bool isSurfaceEnabled(QWaylandSurface *surface) const; + + void add(::wl_client *client, uint32_t id, int version); + static const struct wl_interface *interface(); + static QByteArray interfaceName(); + +Q_SIGNALS: + void updateInputMethod(Qt::InputMethodQueries queries); + void surfaceEnabled(QWaylandSurface *surface); + void surfaceDisabled(QWaylandSurface *surface); + +private: + void focusSurfaceDestroyed(void *); + void sendInputPanelState(); + void sendTextDirection(); + void sendLocale(); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDTEXTINPUT_H diff --git a/src/compositor/extensions/qwaylandtextinput_p.h b/src/compositor/extensions/qwaylandtextinput_p.h new file mode 100644 index 000000000..79706a7e2 --- /dev/null +++ b/src/compositor/extensions/qwaylandtextinput_p.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDTEXTINPUT_P_H +#define QWAYLANDTEXTINPUT_P_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QInputMethodEvent; +class QKeyEvent; +class QWaylandCompositor; +class QWaylandView; + +class QWaylandTextInputClientState { +public: + QWaylandTextInputClientState(); + + Qt::InputMethodQueries updatedQueries(const QWaylandTextInputClientState &other) const; + Qt::InputMethodQueries mergeChanged(const QWaylandTextInputClientState &other); + + Qt::InputMethodHints hints; + QRect cursorRectangle; + QString surroundingText; + int cursorPosition; + int anchorPosition; + QString preferredLanguage; + + Qt::InputMethodQueries changedState; +}; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandTextInputPrivate : public QWaylandExtensionTemplatePrivate, public QtWaylandServer::zwp_text_input_v2 +{ + Q_DECLARE_PUBLIC(QWaylandTextInput) +public: + explicit QWaylandTextInputPrivate(QWaylandCompositor *compositor); + + void sendInputMethodEvent(QInputMethodEvent *event); + void sendKeyEvent(QKeyEvent *event); + void sendInputPanelState(); + void sendTextDirection(); + void sendLocale(); + + QVariant inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const; + + void setFocus(QWaylandSurface *surface); + + QWaylandCompositor *compositor; + + QWaylandSurface *focus; + Resource *focusResource; + QWaylandDestroyListener focusDestroyListener; + + bool inputPanelVisible; + + QScopedPointer currentState; + QScopedPointer pendingState; + + uint32_t serial; + + QHash enabledSurfaces; + +protected: + void zwp_text_input_v2_bind_resource(Resource *resource) Q_DECL_OVERRIDE; + void zwp_text_input_v2_destroy_resource(Resource *resource) Q_DECL_OVERRIDE; + + void zwp_text_input_v2_destroy(Resource *resource) Q_DECL_OVERRIDE; + void zwp_text_input_v2_enable(Resource *resource, wl_resource *surface) Q_DECL_OVERRIDE; + void zwp_text_input_v2_disable(Resource *resource, wl_resource *surface) Q_DECL_OVERRIDE; + void zwp_text_input_v2_show_input_panel(Resource *resource) Q_DECL_OVERRIDE; + void zwp_text_input_v2_hide_input_panel(Resource *resource) Q_DECL_OVERRIDE; + void zwp_text_input_v2_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor) Q_DECL_OVERRIDE; + void zwp_text_input_v2_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose) Q_DECL_OVERRIDE; + void zwp_text_input_v2_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) Q_DECL_OVERRIDE; + void zwp_text_input_v2_set_preferred_language(Resource *resource, const QString &language) Q_DECL_OVERRIDE; + void zwp_text_input_v2_update_state(Resource *resource, uint32_t serial, uint32_t flags) Q_DECL_OVERRIDE; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDTEXTINPUT_P_H diff --git a/src/compositor/extensions/qwaylandtextinputmanager.cpp b/src/compositor/extensions/qwaylandtextinputmanager.cpp new file mode 100644 index 000000000..62e8ac88c --- /dev/null +++ b/src/compositor/extensions/qwaylandtextinputmanager.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2013-2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandtextinputmanager.h" +#include "qwaylandtextinputmanager_p.h" + +#include +#include + +#include "qwaylandtextinput.h" + +QT_BEGIN_NAMESPACE + +QWaylandTextInputManagerPrivate::QWaylandTextInputManagerPrivate() + : QWaylandExtensionTemplatePrivate() + , QtWaylandServer::zwp_text_input_manager_v2() +{ +} + +void QWaylandTextInputManagerPrivate::zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seat) +{ + Q_Q(QWaylandTextInputManager); + QWaylandCompositor *compositor = static_cast(q->extensionContainer()); + QWaylandInputDevice *inputDevice = QWaylandInputDevice::fromSeatResource(seat); + QWaylandTextInput *textInput = QWaylandTextInput::findIn(inputDevice); + if (!textInput) { + textInput = new QWaylandTextInput(inputDevice, compositor); + } + textInput->add(resource->client(), id, wl_resource_get_version(resource->handle)); +} + +QWaylandTextInputManager::QWaylandTextInputManager() + : QWaylandExtensionTemplate(*new QWaylandTextInputManagerPrivate) +{ +} + +QWaylandTextInputManager::QWaylandTextInputManager(QWaylandCompositor *compositor) + : QWaylandExtensionTemplate(compositor, *new QWaylandTextInputManagerPrivate) +{ +} + +void QWaylandTextInputManager::initialize() +{ + Q_D(QWaylandTextInputManager); + + QWaylandExtensionTemplate::initialize(); + QWaylandCompositor *compositor = static_cast(extensionContainer()); + if (!compositor) { + qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandTextInputManager"; + return; + } + d->init(compositor->display(), 1); +} + +const wl_interface *QWaylandTextInputManager::interface() +{ + return QWaylandTextInputManagerPrivate::interface(); +} + +QByteArray QWaylandTextInputManager::interfaceName() +{ + return QWaylandTextInputManagerPrivate::interfaceName(); +} + +QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwaylandtextinputmanager.h b/src/compositor/extensions/qwaylandtextinputmanager.h new file mode 100644 index 000000000..6c250d58c --- /dev/null +++ b/src/compositor/extensions/qwaylandtextinputmanager.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDTEXTINPUTMANAGER_H +#define QWAYLANDTEXTINPUTMANAGER_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QWaylandTextInputManagerPrivate; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandTextInputManager : public QWaylandExtensionTemplate +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandTextInputManager) +public: + QWaylandTextInputManager(); + QWaylandTextInputManager(QWaylandCompositor *compositor); + + void initialize() Q_DECL_OVERRIDE; + + static const struct wl_interface *interface(); + static QByteArray interfaceName(); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDTEXTINPUTMANAGER_H diff --git a/src/compositor/extensions/qwaylandtextinputmanager_p.h b/src/compositor/extensions/qwaylandtextinputmanager_p.h new file mode 100644 index 000000000..8052301c9 --- /dev/null +++ b/src/compositor/extensions/qwaylandtextinputmanager_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2013-2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDTEXTINPUTMANAGER_P_H +#define QWAYLANDTEXTINPUTMANAGER_P_H + +#include + +#include + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandTextInputManagerPrivate : public QWaylandExtensionTemplatePrivate, public QtWaylandServer::zwp_text_input_manager_v2 +{ + Q_DECLARE_PUBLIC(QWaylandTextInputManager) +public: + QWaylandTextInputManagerPrivate(); + +protected: + void zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seat) Q_DECL_OVERRIDE; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDTEXTINPUTMANAGER_P_H diff --git a/src/compositor/extensions/qwlinputmethod.cpp b/src/compositor/extensions/qwlinputmethod.cpp deleted file mode 100644 index 6cf23bcb1..000000000 --- a/src/compositor/extensions/qwlinputmethod.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwlinputmethod_p.h" - -#include -#include -#include -#include "qwlinputmethodcontext_p.h" -#include "qwlinputpanel_p.h" -#include "qwltextinput_p.h" - -QT_BEGIN_NAMESPACE - -namespace QtWayland { - -InputMethod::InputMethod(QWaylandInputDevice *seat) - : QWaylandExtensionTemplate(seat) - , QtWaylandServer::wl_input_method(seat->compositor()->display(), 1) - , m_seat(seat) - , m_resource(0) - , m_textInput() - , m_context() -{ - connect(seat->keyboard(), &QWaylandKeyboard::focusChanged, this, &InputMethod::focusChanged); -} - -InputMethod::~InputMethod() -{ -} - -void InputMethod::activate(TextInput *textInput) -{ - if (!m_resource) { - qDebug("Cannot activate (no input method running)."); - return; - } - - if (m_textInput) { - Q_ASSERT(m_textInput != textInput); - m_textInput->deactivate(this); - } - m_textInput = textInput; - m_context = new InputMethodContext(m_resource->client(), textInput); - - send_activate(m_resource->handle, m_context->resource()->handle); - - QWaylandInputPanelPrivate *panel = QWaylandInputPanelPrivate::findIn(compositor()); - if (panel) { - panel->setFocus(textInput->focus()); - panel->setCursorRectangle(textInput->cursorRectangle()); - panel->setInputPanelVisible(textInput->inputPanelVisible()); - } -} - -void InputMethod::deactivate() -{ - if (!m_resource) { - qDebug("Cannot deactivate (no input method running)."); - return; - } - - send_deactivate(m_resource->handle, m_context->resource()->handle); - m_textInput = 0; - m_context = 0; - - QWaylandInputPanelPrivate *panel = QWaylandInputPanelPrivate::findIn(compositor()); - if (panel) { - panel->setFocus(0); - panel->setCursorRectangle(QRect()); - panel->setInputPanelVisible(false); - } -} - -void InputMethod::focusChanged(QWaylandSurface *surface) -{ - if (!m_textInput) - return; - - if (!surface || m_textInput->focus() != surface) { - m_textInput->deactivate(this); - } -} - -bool InputMethod::isBound() const -{ - return m_resource != 0; -} - -InputMethodContext *InputMethod::context() const -{ - return m_context; -} - -TextInput *InputMethod::textInput() const -{ - return m_textInput; -} - -void InputMethod::input_method_bind_resource(Resource *resource) -{ - if (m_resource) { - wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "interface object already bound"); - wl_resource_destroy(resource->handle); - return; - } - - m_resource = resource; -} - -void InputMethod::input_method_destroy_resource(Resource *resource) -{ - Q_ASSERT(resource == m_resource); - m_resource = 0; -} - -} // namespace QtWayland - -QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwlinputmethod_p.h b/src/compositor/extensions/qwlinputmethod_p.h deleted file mode 100644 index 69348df6c..000000000 --- a/src/compositor/extensions/qwlinputmethod_p.h +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTWAYLAND_QWLINPUTMETHOD_H -#define QTWAYLAND_QWLINPUTMETHOD_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QWaylandInputDevice; -class QWaylandCompositor; - -namespace QtWayland { - -class InputMethodContext; -class TextInput; - -class InputMethod : public QWaylandExtensionTemplate , public QtWaylandServer::wl_input_method -{ - Q_OBJECT -public: - explicit InputMethod(QWaylandInputDevice *seat); - ~InputMethod(); - - QWaylandCompositor *compositor() const { return m_seat->compositor(); } - - void activate(TextInput *textInput); - void deactivate(); - - bool isBound() const; - - InputMethodContext *context() const; - TextInput *textInput() const; - -protected: - void input_method_bind_resource(Resource *resource); - void input_method_destroy_resource(Resource *resource); - -private Q_SLOTS: - void focusChanged(QWaylandSurface *surface); - -private: - QWaylandInputDevice *m_seat; - Resource *m_resource; - TextInput *m_textInput; - InputMethodContext *m_context; -}; - -} // namespace QtWayland - -QT_END_NAMESPACE - -#endif // QTWAYLAND_QWLINPUTMETHOD_H diff --git a/src/compositor/extensions/qwlinputmethodcontext.cpp b/src/compositor/extensions/qwlinputmethodcontext.cpp deleted file mode 100644 index 6421d5e76..000000000 --- a/src/compositor/extensions/qwlinputmethodcontext.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwlinputmethodcontext_p.h" - -#include "qwltextinput_p.h" - -QT_BEGIN_NAMESPACE - -namespace QtWayland { - -InputMethodContext::InputMethodContext(wl_client *client, TextInput *textInput) - : QtWaylandServer::wl_input_method_context(client, 0, 1) - , m_textInput(textInput) -{ -} - -InputMethodContext::~InputMethodContext() -{ -} - -void InputMethodContext::input_method_context_destroy_resource(Resource *) -{ - delete this; -} - -void InputMethodContext::input_method_context_destroy(Resource *resource) -{ - wl_resource_destroy(resource->handle); -} - -void InputMethodContext::input_method_context_commit_string(Resource *, uint32_t serial, const QString &text) -{ - m_textInput->send_commit_string(serial, text); -} - -void InputMethodContext::input_method_context_cursor_position(Resource *, int32_t index, int32_t anchor) -{ - m_textInput->send_cursor_position(index, anchor); -} - -void InputMethodContext::input_method_context_delete_surrounding_text(Resource *, int32_t index, uint32_t length) -{ - m_textInput->send_delete_surrounding_text(index, length); -} - -void InputMethodContext::input_method_context_language(Resource *, uint32_t serial, const QString &language) -{ - m_textInput->send_language(serial, language); -} - -void InputMethodContext::input_method_context_keysym(Resource *, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) -{ - m_textInput->send_keysym(serial, time, sym, state, modifiers); -} - -void InputMethodContext::input_method_context_modifiers_map(Resource *, wl_array *map) -{ - QByteArray modifiersArray(static_cast(map->data), map->size); - m_textInput->send_modifiers_map(modifiersArray); -} - -void InputMethodContext::input_method_context_preedit_cursor(Resource *, int32_t index) -{ - m_textInput->send_preedit_cursor(index); -} - -void InputMethodContext::input_method_context_preedit_string(Resource *, uint32_t serial, const QString &text, const QString &commit) -{ - m_textInput->send_preedit_string(serial, text, commit); -} - -void InputMethodContext::input_method_context_preedit_styling(Resource *, uint32_t index, uint32_t length, uint32_t style) -{ - m_textInput->send_preedit_styling(index, length, style); -} - -void InputMethodContext::input_method_context_grab_keyboard(Resource *, uint32_t keyboard) -{ - Q_UNUSED(keyboard); -} - -void InputMethodContext::input_method_context_key(Resource *, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) -{ - Q_UNUSED(serial); - Q_UNUSED(time); - Q_UNUSED(key); - Q_UNUSED(state); -} - -void InputMethodContext::input_method_context_modifiers(Resource *, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) -{ - Q_UNUSED(serial); - Q_UNUSED(mods_depressed); - Q_UNUSED(mods_latched); - Q_UNUSED(mods_locked); - Q_UNUSED(group); -} - -} // namespace QtWayland - -QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwlinputmethodcontext_p.h b/src/compositor/extensions/qwlinputmethodcontext_p.h deleted file mode 100644 index febadc957..000000000 --- a/src/compositor/extensions/qwlinputmethodcontext_p.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTWAYLAND_QWLINPUTMETHODCONTEXT_P_H -#define QTWAYLAND_QWLINPUTMETHODCONTEXT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -namespace QtWayland { - -class TextInput; - -class InputMethodContext : public QtWaylandServer::wl_input_method_context -{ -public: - explicit InputMethodContext(struct ::wl_client *client, TextInput *textInput); - ~InputMethodContext(); - -protected: - void input_method_context_destroy_resource(Resource *resource) Q_DECL_OVERRIDE; - void input_method_context_destroy(Resource *resource) Q_DECL_OVERRIDE; - - void input_method_context_commit_string(Resource *resource, uint32_t serial, const QString &text) Q_DECL_OVERRIDE; - void input_method_context_cursor_position(Resource *resource, int32_t index, int32_t anchor) Q_DECL_OVERRIDE; - void input_method_context_delete_surrounding_text(Resource *resource, int32_t index, uint32_t length) Q_DECL_OVERRIDE; - void input_method_context_language(Resource *resource, uint32_t serial, const QString &language) Q_DECL_OVERRIDE; - void input_method_context_keysym(Resource *resource, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) Q_DECL_OVERRIDE; - void input_method_context_modifiers_map(Resource *resource, wl_array *map) Q_DECL_OVERRIDE; - void input_method_context_preedit_cursor(Resource *resource, int32_t index) Q_DECL_OVERRIDE; - void input_method_context_preedit_string(Resource *resource, uint32_t serial, const QString &text, const QString &commit) Q_DECL_OVERRIDE; - void input_method_context_preedit_styling(Resource *resource, uint32_t index, uint32_t length, uint32_t style) Q_DECL_OVERRIDE; - void input_method_context_grab_keyboard(Resource *resource, uint32_t keyboard) Q_DECL_OVERRIDE; - void input_method_context_key(Resource *resource, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) Q_DECL_OVERRIDE; - void input_method_context_modifiers(Resource *resource, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) Q_DECL_OVERRIDE; - -private: - TextInput *m_textInput; -}; - -} // namespace QtWayland - -QT_END_NAMESPACE - -#endif // QTWAYLAND_QWLINPUTMETHODCONTEXT_P_H diff --git a/src/compositor/extensions/qwlinputpanel.cpp b/src/compositor/extensions/qwlinputpanel.cpp deleted file mode 100644 index 8f41f0ca3..000000000 --- a/src/compositor/extensions/qwlinputpanel.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwlinputpanel_p.h" - -#include -#include - -#include "qwlinputmethod_p.h" -#include "qwlinputpanelsurface_p.h" -#include "qwltextinput_p.h" - -QT_BEGIN_NAMESPACE - -QWaylandInputPanelPrivate::QWaylandInputPanelPrivate(QWaylandCompositor *compositor) - : QWaylandExtensionTemplatePrivate() - , QtWaylandServer::wl_input_panel() - , m_compositor(compositor) - , m_focus() - , m_inputPanelVisible(false) - , m_cursorRectangle() -{ - init(compositor->display(), 1); -} - -QWaylandInputPanelPrivate::~QWaylandInputPanelPrivate() -{ -} - -QWaylandInputPanel *QWaylandInputPanelPrivate::waylandInputPanel() const -{ - QWaylandInputPanel *panel = const_cast(q_func()); - return panel; -} - -QWaylandSurface *QWaylandInputPanelPrivate::focus() const -{ - return m_focus; -} - -void QWaylandInputPanelPrivate::setFocus(QWaylandSurface *focus) -{ - Q_Q(QWaylandInputPanel); - if (m_focus == focus) - return; - - m_focus = focus; - - Q_EMIT q->focusChanged(); -} - -bool QWaylandInputPanelPrivate::inputPanelVisible() const -{ - return m_inputPanelVisible; -} - -void QWaylandInputPanelPrivate::setInputPanelVisible(bool inputPanelVisible) -{ - Q_Q(QWaylandInputPanel); - if (m_inputPanelVisible == inputPanelVisible) - return; - - m_inputPanelVisible = inputPanelVisible; - - q->visibleChanged(); -} - -QRect QWaylandInputPanelPrivate::cursorRectangle() const -{ - return m_cursorRectangle; -} - -void QWaylandInputPanelPrivate::setCursorRectangle(const QRect &cursorRectangle) -{ - Q_Q(QWaylandInputPanel); - if (m_cursorRectangle == cursorRectangle) - return; - - m_cursorRectangle = cursorRectangle; - - Q_EMIT q->cursorRectangleChanged(); -} - -QWaylandInputPanelPrivate *QWaylandInputPanelPrivate::findIn(QWaylandObject *container) -{ - QWaylandInputPanel *panel = QWaylandInputPanel::findIn(container); - if (!panel) - return Q_NULLPTR; - return panel->d_func(); -} - -void QWaylandInputPanelPrivate::input_panel_get_input_panel_surface(Resource *resource, uint32_t id, wl_resource *surface) -{ - new QtWayland::InputPanelSurface(resource->client(), id, QWaylandSurface::fromResource(surface)); -} - -QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwlinputpanel_p.h b/src/compositor/extensions/qwlinputpanel_p.h deleted file mode 100644 index 97720f050..000000000 --- a/src/compositor/extensions/qwlinputpanel_p.h +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTWAYLAND_QWLINPUTPANEL_P_H -#define QTWAYLAND_QWLINPUTPANEL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace QtWayland { -class TextInput; -} - - -class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandInputPanelPrivate : public QWaylandExtensionTemplatePrivate, public QtWaylandServer::wl_input_panel -{ - Q_DECLARE_PUBLIC(QWaylandInputPanel) -public: - QWaylandInputPanelPrivate(QWaylandCompositor *compositor); - ~QWaylandInputPanelPrivate(); - - QWaylandInputPanel *waylandInputPanel() const; - - QWaylandSurface *focus() const; - void setFocus(QWaylandSurface *focus); - - bool inputPanelVisible() const; - void setInputPanelVisible(bool inputPanelVisible); - - QRect cursorRectangle() const; - void setCursorRectangle(const QRect &cursorRectangle); - - static QWaylandInputPanelPrivate *findIn(QWaylandObject *container); -protected: - void input_panel_get_input_panel_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface) Q_DECL_OVERRIDE; - -private: - QWaylandCompositor *m_compositor; - - QWaylandSurface *m_focus; - bool m_inputPanelVisible; - QRect m_cursorRectangle; -}; - -QT_END_NAMESPACE - -#endif // QTWAYLAND_QWLINPUTPANEL_P_H diff --git a/src/compositor/extensions/qwlinputpanelsurface.cpp b/src/compositor/extensions/qwlinputpanelsurface.cpp deleted file mode 100644 index c54520aad..000000000 --- a/src/compositor/extensions/qwlinputpanelsurface.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Pier Luigi Fiorini -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwlinputpanelsurface_p.h" - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace QtWayland { - -InputPanelSurface::InputPanelSurface(wl_client *client, int id, QWaylandSurface *surface) - : QtWaylandServer::wl_input_panel_surface(client, id, 1) - , m_surface(surface) - , m_type(Invalid) - , m_output(0) - , m_position() -{ - QWaylandSurfacePrivate::get(surface)->setInputPanelSurface(this); -} - -InputPanelSurface::Type InputPanelSurface::type() const -{ - return m_type; -} - -QWaylandOutput *InputPanelSurface::output() const -{ - return m_output; -} - -QtWaylandServer::wl_input_panel_surface::position InputPanelSurface::position() const -{ - return m_position; -} - -void InputPanelSurface::input_panel_surface_set_overlay_panel(Resource *) -{ - m_type = OverlayPanel; -} - -void InputPanelSurface::input_panel_surface_set_toplevel(Resource *, wl_resource *output_resource, uint32_t position) -{ - m_type = Toplevel; - m_output = QWaylandOutput::fromResource(output_resource); - m_position = static_cast(position); -} - -QT_END_NAMESPACE - -} // namespace QtWayland diff --git a/src/compositor/extensions/qwlinputpanelsurface_p.h b/src/compositor/extensions/qwlinputpanelsurface_p.h deleted file mode 100644 index e11923bd0..000000000 --- a/src/compositor/extensions/qwlinputpanelsurface_p.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Pier Luigi Fiorini -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTWAYLAND_QWLINPUTPANELSURFACE_P_H -#define QTWAYLAND_QWLINPUTPANELSURFACE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include - -QT_BEGIN_NAMESPACE - -class QWaylandOutput; - -namespace QtWayland { - -class InputPanelSurface : public QtWaylandServer::wl_input_panel_surface -{ -public: - enum Type { - Invalid, - Toplevel, - OverlayPanel - }; - - InputPanelSurface(struct ::wl_client *client, int id, QWaylandSurface *surface); - - Type type() const; - - QWaylandOutput *output() const; - wl_input_panel_surface::position position() const; - -protected: - void input_panel_surface_set_overlay_panel(Resource *resource) Q_DECL_OVERRIDE; - void input_panel_surface_set_toplevel(Resource *resource, wl_resource *output_resource, uint32_t position) Q_DECL_OVERRIDE; - -private: - QWaylandSurface *m_surface; - - Type m_type; - - QWaylandOutput *m_output; - wl_input_panel_surface::position m_position; -}; - -} // namespace QtWayland - -QT_END_NAMESPACE - -#endif // QTWAYLAND_QWLINPUTPANELSURFACE_P_H diff --git a/src/compositor/extensions/qwltextinput.cpp b/src/compositor/extensions/qwltextinput.cpp deleted file mode 100644 index 7546ab6a0..000000000 --- a/src/compositor/extensions/qwltextinput.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwltextinput_p.h" - -#include "qwlinputmethod_p.h" -#include "qwlinputmethodcontext_p.h" -#include "qwlinputpanel_p.h" -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace QtWayland { - -TextInput::TextInput(QWaylandObject *container, QWaylandCompositor *compositor, struct ::wl_client *client, int id) - : QWaylandExtensionTemplate(container) - , wl_text_input(client, id, 1) - , m_compositor(compositor) - , m_focus() - , m_inputPanelVisible() - , m_cursorRectangle() -{ -} - -QWaylandSurface *TextInput::focus() const -{ - return m_focus; -} - -bool TextInput::inputPanelVisible() const -{ - return m_inputPanelVisible; -} - -QRect TextInput::cursorRectangle() const -{ - return m_cursorRectangle; -} - -void TextInput::deactivate(InputMethod *inputMethod) -{ - if (m_activeInputMethods.removeOne(inputMethod)) - inputMethod->deactivate(); - - if (m_activeInputMethods.isEmpty()) - send_leave(); -} - -void TextInput::text_input_destroy_resource(Resource *) -{ - Q_FOREACH (InputMethod *inputMethod, m_activeInputMethods) { - deactivate(inputMethod); - } - - delete this; -} - -void TextInput::text_input_activate(Resource *, wl_resource *seat, wl_resource *surface) -{ - QWaylandSurface *oldSurface = m_focus; - m_focus = QWaylandSurface::fromResource(surface); - - if (oldSurface != m_focus) - send_leave(); - - bool wasEmpty = m_activeInputMethods.isEmpty(); - - InputMethod *inputMethod = InputMethod::findIn(QWaylandInputDevice::fromSeatResource(seat)); - - if (inputMethod && !m_activeInputMethods.contains(inputMethod)) { - m_activeInputMethods.append(inputMethod); - inputMethod->activate(this); - } - - if (wasEmpty || oldSurface != m_focus) - send_enter(surface); -} - -void TextInput::text_input_deactivate(Resource *, wl_resource *seat) -{ - InputMethod *inputMethod = InputMethod::findIn(QWaylandInputDevice::fromSeatResource(seat)); - - if (inputMethod) - deactivate(inputMethod); -} - -static bool isInputMethodBound(InputMethod *inputMethod) -{ - return inputMethod->isBound(); -} - -void TextInput::text_input_show_input_panel(Resource *) -{ - m_inputPanelVisible = true; - - if (std::find_if(m_activeInputMethods.cbegin(), m_activeInputMethods.cend(), isInputMethodBound) != m_activeInputMethods.cend()){ - QWaylandInputPanelPrivate *panel = QWaylandInputPanelPrivate::findIn(m_compositor); - if (panel) - panel->setInputPanelVisible(true); - } -} - -void TextInput::text_input_hide_input_panel(Resource *) -{ - m_inputPanelVisible = false; - - if (std::find_if(m_activeInputMethods.cbegin(), m_activeInputMethods.cend(), isInputMethodBound) != m_activeInputMethods.cend()) { - QWaylandInputPanelPrivate *panel = QWaylandInputPanelPrivate::findIn(m_compositor); - if (panel) - panel->setInputPanelVisible(false); - } -} - -void TextInput::text_input_set_cursor_rectangle(Resource *, int32_t x, int32_t y, int32_t width, int32_t height) -{ - m_cursorRectangle = QRect(x, y, width, height); - - if (!m_activeInputMethods.isEmpty()) { - QWaylandInputPanelPrivate *panel = QWaylandInputPanelPrivate::findIn(m_compositor); - if (panel) - panel->setCursorRectangle(m_cursorRectangle); - } -} - -void TextInput::text_input_reset(Resource *) -{ - Q_FOREACH (InputMethod *inputMethod, m_activeInputMethods) { - if (inputMethod->context()) - inputMethod->context()->send_reset(); - } -} - -void TextInput::text_input_commit_state(Resource *, uint32_t serial) -{ - Q_FOREACH (InputMethod *inputMethod, m_activeInputMethods) { - if (inputMethod->context()) - inputMethod->context()->send_commit_state(serial); - } -} - -void TextInput::text_input_set_content_type(Resource *, uint32_t hint, uint32_t purpose) -{ - Q_FOREACH (InputMethod *inputMethod, m_activeInputMethods) { - if (inputMethod->context()) - inputMethod->context()->send_content_type(hint, purpose); - } -} - -void TextInput::text_input_set_preferred_language(Resource *, const QString &language) -{ - Q_FOREACH (InputMethod *inputMethod, m_activeInputMethods) { - if (inputMethod->context()) - inputMethod->context()->send_preferred_language(language); - } -} - -void TextInput::text_input_set_surrounding_text(Resource *, const QString &text, uint32_t cursor, uint32_t anchor) -{ - Q_FOREACH (InputMethod *inputMethod, m_activeInputMethods) { - if (inputMethod->context()) - inputMethod->context()->send_surrounding_text(text, cursor, anchor); - } -} - -void TextInput::text_input_invoke_action(Resource *, uint32_t button, uint32_t index) -{ - Q_FOREACH (InputMethod *inputMethod, m_activeInputMethods) { - if (inputMethod->context()) - inputMethod->context()->send_invoke_action(button, index); - } -} - -} // namespace QtWayland - -QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwltextinput_p.h b/src/compositor/extensions/qwltextinput_p.h deleted file mode 100644 index 02adc5cae..000000000 --- a/src/compositor/extensions/qwltextinput_p.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTWAYLAND_QWLTEXTINPUT_P_H -#define QTWAYLAND_QWLTEXTINPUT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QWaylandSurface; -class QWaylandCompositor; - -namespace QtWayland { - -class InputMethod; - -class TextInput : public QWaylandExtensionTemplate, public QtWaylandServer::wl_text_input -{ -public: - explicit TextInput(QWaylandObject *container, QWaylandCompositor *compositor, struct ::wl_client *client, int id); - - QWaylandSurface *focus() const; - - bool inputPanelVisible() const; - QRect cursorRectangle() const; - - void deactivate(InputMethod *inputMethod); - -protected: - void text_input_destroy_resource(Resource *resource) Q_DECL_OVERRIDE; - - void text_input_activate(Resource *resource, wl_resource *seat, wl_resource *surface) Q_DECL_OVERRIDE; - void text_input_deactivate(Resource *resource, wl_resource *seat) Q_DECL_OVERRIDE; - void text_input_show_input_panel(Resource *resource) Q_DECL_OVERRIDE; - void text_input_hide_input_panel(Resource *resource) Q_DECL_OVERRIDE; - void text_input_reset(Resource *resource) Q_DECL_OVERRIDE; - void text_input_commit_state(Resource *resource, uint32_t serial) Q_DECL_OVERRIDE; - void text_input_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose) Q_DECL_OVERRIDE; - void text_input_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) Q_DECL_OVERRIDE; - void text_input_set_preferred_language(Resource *resource, const QString &language) Q_DECL_OVERRIDE; - void text_input_set_surrounding_text(Resource *resource, const QString &text, uint32_t cursor, uint32_t anchor) Q_DECL_OVERRIDE; - void text_input_invoke_action(Resource *resource, uint32_t button, uint32_t index) Q_DECL_OVERRIDE; - -private: - QWaylandCompositor *m_compositor; - QList m_activeInputMethods; - QWaylandSurface *m_focus; - - bool m_inputPanelVisible; - QRect m_cursorRectangle; - -}; - -} // namespace QtWayland - -QT_END_NAMESPACE - -#endif // QTWAYLAND_QWLTEXTINPUT_P_H diff --git a/src/compositor/extensions/qwltextinputmanager.cpp b/src/compositor/extensions/qwltextinputmanager.cpp deleted file mode 100644 index 9c7dd72f4..000000000 --- a/src/compositor/extensions/qwltextinputmanager.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwltextinputmanager_p.h" - -#include -#include "qwltextinput_p.h" - -QT_BEGIN_NAMESPACE - -namespace QtWayland { - -TextInputManager::TextInputManager(QWaylandCompositor *compositor) - : QWaylandExtensionTemplate(compositor) - , QtWaylandServer::wl_text_input_manager(compositor->display(), 1) - , m_compositor(compositor) -{ -} - -TextInputManager::~TextInputManager() -{ -} - -void TextInputManager::text_input_manager_create_text_input(Resource *resource, uint32_t id) -{ - new TextInput(this, m_compositor, resource->client(), id); -} - -} // namespace QtWayland - -QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwltextinputmanager_p.h b/src/compositor/extensions/qwltextinputmanager_p.h deleted file mode 100644 index 0125bdcae..000000000 --- a/src/compositor/extensions/qwltextinputmanager_p.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTWAYLAND_QWLTEXTINPUTMANAGER_P_H -#define QTWAYLAND_QWLTEXTINPUTMANAGER_P_H - -#include -#include - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -QT_BEGIN_NAMESPACE - -class QWaylandCompositor; - -namespace QtWayland { - -class TextInputManager : public QWaylandExtensionTemplate, public QtWaylandServer::wl_text_input_manager -{ - Q_OBJECT -public: - TextInputManager(QWaylandCompositor *compositor); - ~TextInputManager(); - -protected: - void text_input_manager_create_text_input(Resource *resource, uint32_t id) Q_DECL_OVERRIDE; - -private: - QWaylandCompositor *m_compositor; -}; - -} // namespace QtWayland - -QT_END_NAMESPACE - -#endif // QTWAYLAND_QWLTEXTINPUTMANAGER_P_H diff --git a/src/imports/compositor/qwaylandquickcompositorplugin.cpp b/src/imports/compositor/qwaylandquickcompositorplugin.cpp index 7be257d37..1fa28123d 100644 --- a/src/imports/compositor/qwaylandquickcompositorplugin.cpp +++ b/src/imports/compositor/qwaylandquickcompositorplugin.cpp @@ -51,6 +51,7 @@ #include #include +#include #include #include "qwaylandmousetracker_p.h" @@ -61,6 +62,8 @@ Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandQuickCompositor) Q_COMPOSITOR_DECLARE_QUICK_DATA_CLASS(QWaylandWlShell) Q_COMPOSITOR_DECLARE_QUICK_DATA_CLASS(QWaylandWlShellSurface) +Q_COMPOSITOR_DECLARE_QUICK_DATA_CLASS(QWaylandTextInputManager) + class QmlUrlResolver { public: @@ -142,7 +145,7 @@ public: qmlRegisterType(uri, 1, 0, "WlShell"); qmlRegisterType(uri, 1, 0, "WlShellSurface"); qmlRegisterType(uri, 1, 0, "WlShellSurfaceItem"); - + qmlRegisterType(uri, 1, 0, "TextInputManager"); } }; //![class decl] diff --git a/src/shared/qwaylandinputmethodeventbuilder.cpp b/src/shared/qwaylandinputmethodeventbuilder.cpp new file mode 100644 index 000000000..eb527c15a --- /dev/null +++ b/src/shared/qwaylandinputmethodeventbuilder.cpp @@ -0,0 +1,286 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandinputmethodeventbuilder.h" + +#include +#include + +#ifdef QT_BUILD_WAYLANDCOMPOSITOR_LIB +#include +#else +#include +#endif + +QT_BEGIN_NAMESPACE + +QWaylandInputMethodEventBuilder::QWaylandInputMethodEventBuilder() + : m_anchor(0) + , m_cursor(0) + , m_deleteBefore(0) + , m_deleteAfter(0) + , m_preeditCursor(0) + , m_preeditStyles() +{ +} + +QWaylandInputMethodEventBuilder::~QWaylandInputMethodEventBuilder() +{ +} + +void QWaylandInputMethodEventBuilder::reset() +{ + m_anchor = 0; + m_cursor = 0; + m_deleteBefore = 0; + m_deleteAfter = 0; + m_preeditCursor = 0; + m_preeditStyles.clear(); +} + +void QWaylandInputMethodEventBuilder::setCursorPosition(int32_t index, int32_t anchor) +{ + m_cursor = index; + m_anchor = anchor; +} + +void QWaylandInputMethodEventBuilder::setDeleteSurroundingText(uint32_t beforeLength, uint32_t afterLength) +{ + m_deleteBefore = beforeLength; + m_deleteAfter = afterLength; +} + +void QWaylandInputMethodEventBuilder::addPreeditStyling(uint32_t index, uint32_t length, uint32_t style) +{ + QTextCharFormat format; + + switch (style) { + case 0: + case 1: + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format)); + break; + case 2: + case 3: + format.setFontWeight(QFont::Bold); + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format)); + break; + case 4: + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format)); + case 5: + format.setFontUnderline(true); + format.setUnderlineStyle(QTextCharFormat::WaveUnderline); + format.setUnderlineColor(QColor(Qt::red)); + m_preeditStyles.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, index, length, format)); + break; +// case QtWayland::wl_text_input::preedit_style_selection: +// case QtWayland::wl_text_input::preedit_style_none: + default: + break; + } +} + +void QWaylandInputMethodEventBuilder::setPreeditCursor(int32_t index) +{ + m_preeditCursor = index; +} + +QInputMethodEvent QWaylandInputMethodEventBuilder::buildCommit(const QString &text) +{ + QList attributes; + + const QPair replacement = replacementForDeleteSurrounding(); + + if (m_cursor != 0 || m_anchor != 0) { + QString surrounding = QInputMethod::queryFocusObject(Qt::ImSurroundingText, QVariant()).toString(); + const int cursor = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()).toInt(); + const int anchor = QInputMethod::queryFocusObject(Qt::ImAnchorPosition, QVariant()).toInt(); + const int absoluteCursor = QInputMethod::queryFocusObject(Qt::ImAbsolutePosition, QVariant()).toInt(); + + const int absoluteOffset = absoluteCursor - cursor; + + const int cursorAfterCommit = qMin(anchor, cursor) + replacement.first + text.length(); + surrounding.replace(qMin(anchor, cursor) + replacement.first, + qAbs(anchor - cursor) + replacement.second, text); + + attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, + indexFromWayland(surrounding, m_cursor, cursorAfterCommit) + absoluteOffset, + indexFromWayland(surrounding, m_anchor, cursorAfterCommit) + absoluteOffset, + QVariant())); + } + + QInputMethodEvent event(QString(), attributes); + event.setCommitString(text, replacement.first, replacement.second); + + return event; +} + +QInputMethodEvent QWaylandInputMethodEventBuilder::buildPreedit(const QString &text) +{ + QList attributes; + + if (m_preeditCursor < 0) { + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant())); + } else if (m_preeditCursor > 0) { + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant())); + } + + Q_FOREACH (const QInputMethodEvent::Attribute &attr, m_preeditStyles) { + int start = indexFromWayland(text, attr.start); + int length = indexFromWayland(text, attr.start + attr.length) - start; + attributes.append(QInputMethodEvent::Attribute(attr.type, start, length, attr.value)); + } + + QInputMethodEvent event(text, attributes); + + const QPair replacement = replacementForDeleteSurrounding(); + event.setCommitString(QString(), replacement.first, replacement.second); + + return event; +} + +QPair QWaylandInputMethodEventBuilder::replacementForDeleteSurrounding() +{ + if (m_deleteBefore == 0 && m_deleteAfter == 0) + return QPair(0, 0); + + const QString &surrounding = QInputMethod::queryFocusObject(Qt::ImSurroundingText, QVariant()).toString(); + const int cursor = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()).toInt(); + const int anchor = QInputMethod::queryFocusObject(Qt::ImAnchorPosition, QVariant()).toInt(); + + const int selectionStart = qMin(cursor, anchor); + const int selectionEnd = qMax(cursor, anchor); + + const int deleteBefore = selectionStart - indexFromWayland(surrounding, -m_deleteBefore, selectionStart); + const int deleteAfter = indexFromWayland(surrounding, m_deleteAfter, selectionEnd) - selectionEnd; + + return QPair(-deleteBefore, deleteBefore + deleteAfter); +} + +QWaylandInputMethodContentType QWaylandInputMethodContentType::convert(Qt::InputMethodHints hints) +{ + uint32_t hint = ZWP_TEXT_INPUT_V2_CONTENT_HINT_NONE; + uint32_t purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NORMAL; + + if (hints & Qt::ImhHiddenText) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_HIDDEN_TEXT; + } + if (hints & Qt::ImhSensitiveData) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_SENSITIVE_DATA; + } + if ((hints & Qt::ImhNoAutoUppercase) == 0) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CAPITALIZATION; + } + if (hints & Qt::ImhPreferNumbers) { + // Nothing yet + } + if (hints & Qt::ImhPreferUppercase) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE; + } + if (hints & Qt::ImhPreferLowercase) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE; + } + if ((hints & Qt::ImhNoPredictiveText) == 0) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_COMPLETION | ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CORRECTION; + } + + if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime) == 0) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATE; + } else if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime)) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATETIME; + } else if ((hints & Qt::ImhDate) == 0 && (hints & Qt::ImhTime)) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TIME; + } + + if (hints & Qt::ImhPreferLatin) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN; + } + + if (hints & Qt::ImhMultiLine) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_MULTILINE; + } + + if (hints & Qt::ImhDigitsOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DIGITS; + } + if (hints & Qt::ImhFormattedNumbersOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NUMBER; + } + if (hints & Qt::ImhUppercaseOnly) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE; + } + if (hints & Qt::ImhLowercaseOnly) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE; + } + if (hints & Qt::ImhDialableCharactersOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PHONE; + } + if (hints & Qt::ImhEmailCharactersOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_EMAIL; + } + if (hints & Qt::ImhUrlCharactersOnly) { + purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_URL; + } + if (hints & Qt::ImhLatinOnly) { + hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN; + } + return QWaylandInputMethodContentType{hint, purpose}; +} + +int QWaylandInputMethodEventBuilder::indexFromWayland(const QString &str, int utf8Index, int baseIndex) +{ + if (utf8Index == 0) + return baseIndex; + + if (utf8Index < 0) { + const QByteArray &utf8 = str.leftRef(baseIndex).toUtf8(); + return QString::fromUtf8(utf8.left(qMax(utf8.length() + utf8Index, 0))).length(); + } else { + const QByteArray &utf8 = str.midRef(baseIndex).toUtf8(); + return QString::fromUtf8(utf8.left(utf8Index)).length() + baseIndex; + } +} + +QT_END_NAMESPACE + diff --git a/src/shared/qwaylandinputmethodeventbuilder.h b/src/shared/qwaylandinputmethodeventbuilder.h new file mode 100644 index 000000000..188a6a94b --- /dev/null +++ b/src/shared/qwaylandinputmethodeventbuilder.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDINPUTMETHODEVENTBUILDER_H +#define QWAYLANDINPUTMETHODEVENTBUILDER_H + +#include + +QT_BEGIN_NAMESPACE + +class QWaylandInputMethodEventBuilder +{ +public: + QWaylandInputMethodEventBuilder(); + ~QWaylandInputMethodEventBuilder(); + + void reset(); + + void setCursorPosition(int32_t index, int32_t anchor); + void setDeleteSurroundingText(uint32_t beforeLength, uint32_t afterLength); + + void addPreeditStyling(uint32_t index, uint32_t length, uint32_t style); + void setPreeditCursor(int32_t index); + + QInputMethodEvent buildCommit(const QString &text); + QInputMethodEvent buildPreedit(const QString &text); + + static int indexFromWayland(const QString &str, int utf8Index, int baseIndex = 0); +private: + QPair replacementForDeleteSurrounding(); + + int32_t m_anchor; + int32_t m_cursor; + uint32_t m_deleteBefore; + uint32_t m_deleteAfter; + + int32_t m_preeditCursor; + QList m_preeditStyles; +}; + +struct QWaylandInputMethodContentType { + uint32_t hint; + uint32_t purpose; + + static QWaylandInputMethodContentType convert(Qt::InputMethodHints hints); +}; + + +QT_END_NAMESPACE + +#endif // QWAYLANDINPUTMETHODEVENTBUILDER_H diff --git a/src/shared/qwaylandxkb.cpp b/src/shared/qwaylandxkb.cpp index f5d0527de..32d24bd62 100644 --- a/src/shared/qwaylandxkb.cpp +++ b/src/shared/qwaylandxkb.cpp @@ -40,6 +40,7 @@ #include "qwaylandxkb.h" +#include #include #ifndef QT_NO_WAYLAND_XKB @@ -282,6 +283,16 @@ static int lookupKeysym(xkb_keysym_t key) return code; } +static xkb_keysym_t toKeysymFromTable(uint32_t key) +{ + for (int i = 0; KeyTbl[i]; i += 2) { + if (key == KeyTbl[i + 1]) + return KeyTbl[i]; + } + + return 0; +} + int QWaylandXkb::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text) { int code = 0; @@ -326,6 +337,50 @@ Qt::KeyboardModifiers QWaylandXkb::modifiers(struct xkb_state *state) return modifiers; } +QEvent::Type QWaylandXkb::toQtEventType(uint32_t state) +{ + return state != 0 ? QEvent::KeyPress : QEvent::KeyRelease; +} + +QString QWaylandXkb::textFromKeysym(uint32_t keysym, Qt::KeyboardModifiers modifiers) +{ + uint utf32 = xkb_keysym_to_utf32(keysym); + + // Map control + letter to proper text + if (utf32 >= 'A' && utf32 <= '~' && (modifiers & Qt::ControlModifier)) { + utf32 &= ~0x60; + return QString::fromUcs4(&utf32, 1); + } + + if (utf32) + return QString::fromUcs4(&utf32, 1); + + return QString(); +} + +QVector QWaylandXkb::toKeysym(QKeyEvent *event) +{ + QVector keysyms; + if (event->key() >= Qt::Key_F1 && event->key() <= Qt::Key_F35) { + keysyms.append(XKB_KEY_F1 + (event->key() - Qt::Key_F1)); + } else if (event->modifiers() & Qt::KeypadModifier) { + if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) + keysyms.append(XKB_KEY_KP_0 + (event->key() - Qt::Key_0)); + else + keysyms.append(toKeysymFromTable(event->key())); + } else if (!event->text().isEmpty()) { + // From libxkbcommon keysym-utf.c: + // "We allow to represent any UCS character in the range U-00000000 to + // U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff." + foreach (uint utf32, event->text().toUcs4()) { + keysyms.append(utf32 | 0x01000000); + } + } else { + keysyms.append(toKeysymFromTable(event->key())); + } + return keysyms; +} + QT_END_NAMESPACE #endif // QT_NO_WAYLAND_XKB diff --git a/src/shared/qwaylandxkb.h b/src/shared/qwaylandxkb.h index bfb38515f..9b5c935a5 100644 --- a/src/shared/qwaylandxkb.h +++ b/src/shared/qwaylandxkb.h @@ -44,15 +44,22 @@ #ifndef QT_NO_WAYLAND_XKB #include +#include #include QT_BEGIN_NAMESPACE +class QKeyEvent; + class QWaylandXkb { public: static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text); static Qt::KeyboardModifiers modifiers(struct xkb_state *state); + + static QEvent::Type toQtEventType(uint32_t state); + static QString textFromKeysym(uint32_t keysym, Qt::KeyboardModifiers modifiers); + static QVector toKeysym(QKeyEvent *event); }; QT_END_NAMESPACE -- cgit v1.2.3