diff options
Diffstat (limited to 'src')
44 files changed, 2616 insertions, 2071 deletions
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 @@ -<?xml version="1.0" encoding="UTF-8"?> -<protocol name="input_method"> - <copyright> - 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. - </copyright> - - - <interface name="wl_input_method_context" version="1"> - <description summary="input method context"> - 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). - </description> - <request name="destroy" type="destructor"/> - <request name="commit_string"> - <description summary="commit string"> - 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. - </description> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="text" type="string"/> - </request> - <request name="preedit_string"> - <description summary="pre-edit string"> - 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. - </description> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="text" type="string"/> - <arg name="commit" type="string"/> - </request> - <request name="preedit_styling"> - <description summary="pre-edit styling"> - 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. - </description> - <arg name="index" type="uint"/> - <arg name="length" type="uint"/> - <arg name="style" type="uint"/> - </request> - <request name="preedit_cursor"> - <description summary="pre-edit cursor"> - 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. - </description> - <arg name="index" type="int"/> - </request> - <request name="delete_surrounding_text"> - <description summary="delete text"> - - - This request will be handled on text_input side as part of a directly - following commit_string request. - </description> - <arg name="index" type="int"/> - <arg name="length" type="uint"/> - </request> - <request name="cursor_position"> - <description summary="set cursor to a new position"> - 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. - </description> - <arg name="index" type="int"/> - <arg name="anchor" type="int"/> - </request> - <request name="modifiers_map"> - <arg name="map" type="array"/> - </request> - <request name="keysym"> - <description summary="keysym"> - 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. - </description> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="time" type="uint"/> - <arg name="sym" type="uint"/> - <arg name="state" type="uint"/> - <arg name="modifiers" type="uint"/> - </request> - <request name="grab_keyboard"> - <description summary="grab hardware keyboard"> - 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. - </description> - <arg name="keyboard" type="new_id" interface="wl_keyboard"/> - </request> - <request name="key"> - <description summary="forward key event"> - 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. - </description> - <arg name="serial" type="uint" summary="serial from wl_keyboard::key"/> - <arg name="time" type="uint" summary="time from wl_keyboard::key"/> - <arg name="key" type="uint" summary="key from wl_keyboard::key"/> - <arg name="state" type="uint" summary="state from wl_keyboard::key"/> - </request> - <request name="modifiers"> - <description summary="forward modifiers event"> - 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. - </description> - <arg name="serial" type="uint" summary="serial from wl_keyboard::modifiers"/> - <arg name="mods_depressed" type="uint" summary="mods_depressed from wl_keyboard::modifiers"/> - <arg name="mods_latched" type="uint" summary="mods_latched from wl_keyboard::modifiers"/> - <arg name="mods_locked" type="uint" summary="mods_locked from wl_keyboard::modifiers"/> - <arg name="group" type="uint" summary="group from wl_keyboard::modifiers"/> - </request> - <request name="language"> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="language" type="string"/> - </request> - <request name="text_direction"> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="direction" type="uint"/> - </request> - <event name="surrounding_text"> - <description summary="surrounding text 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. - </description> - <arg name="text" type="string"/> - <arg name="cursor" type="uint"/> - <arg name="anchor" type="uint"/> - </event> - <event name="reset"> - </event> - <event name="content_type"> - <arg name="hint" type="uint"/> - <arg name="purpose" type="uint"/> - </event> - <event name="invoke_action"> - <arg name="button" type="uint"/> - <arg name="index" type="uint"/> - </event> - <event name="commit_state"> - <arg name="serial" type="uint" summary="serial of text input state"/> - </event> - <event name="preferred_language"> - <arg name="language" type="string"/> - </event> - </interface> - - <interface name="wl_input_method" version="1"> - <description summary="input method"> - 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. - </description> - <event name="activate"> - <description summary="activate event"> - A text model was activated. Creates an input method context object - which allows communication with the text model. - </description> - <arg name="id" type="new_id" interface="wl_input_method_context"/> - </event> - <event name="deactivate"> - <description summary="activate event"> - The text model corresponding to the context argument was deactivated. - The input method context should be destroyed after deactivation is - handled. - </description> - <arg name="context" type="object" interface="wl_input_method_context"/> - </event> - </interface> - - <interface name="wl_input_panel" version="1"> - <description summary="interface for implementing keyboards"> - Only one client can bind this interface at a time. - </description> - - <request name="get_input_panel_surface"> - <arg name="id" type="new_id" interface="wl_input_panel_surface"/> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - </interface> - - <interface name="wl_input_panel_surface" version="1"> - <enum name="position"> - <entry name="center_bottom" value="0"/> - </enum> - - <request name="set_toplevel"> - <description summary="set the surface type as a keyboard"> - A keybaord surface is only shown, when a text model is active - </description> - <arg name="output" type="object" interface="wl_output"/> - <arg name="position" type="uint"/> - </request> - - <request name="set_overlay_panel"> - <description summary="set the surface type as an overlay panel"> - An overlay panel is shown near the input cursor above the application - window when a text model is active. - </description> - </request> - </interface> -</protocol> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<protocol name="text_input_unstable_v2"> + <copyright> + 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. + </copyright> + + <interface name="zwp_text_input_v2" version="1"> + <description summary="text input"> + 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. + </description> + + <request name="destroy" type="destructor"> + <description summary="Destroy the wp_text_input"> + Destroy the wp_text_input object. Also disables all surfaces enabled + through this wp_text_input object + </description> + </request> + + <request name="enable"> + <description summary="enable text input for surface"> + 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. + </description> + <arg name="surface" type="object" interface="wl_surface"/> + </request> + + <request name="disable"> + <description summary="disable text input for surface"> + Disable text input in a surface (typically when there is no focus on any + text entry inside the surface). + </description> + <arg name="surface" type="object" interface="wl_surface"/> + </request> + + <request name="show_input_panel"> + <description summary="show input panels"> + 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. + </description> + </request> + + <request name="hide_input_panel"> + <description summary="hide input panels"> + Requests input panels (virtual keyboard) to hide. + </description> + </request> + + <request name="set_surrounding_text"> + <description summary="sets the surrounding text"> + 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. + </description> + <arg name="text" type="string"/> + <arg name="cursor" type="int"/> + <arg name="anchor" type="int"/> + </request> + + <enum name="content_hint" bitfield="true"> + <description summary="content hint"> + Content hint is a bitmask to allow to modify the behavior of the text + input. + </description> + <entry name="none" value="0x0" summary="no special behaviour"/> + <entry name="auto_completion" value="0x1" summary="suggest word completions"/> + <entry name="auto_correction" value="0x2" summary="suggest word corrections"/> + <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/> + <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/> + <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/> + <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/> + <entry name="hidden_text" value="0x40" summary="characters should be hidden"/> + <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/> + <entry name="latin" value="0x100" summary="just latin characters should be entered"/> + <entry name="multiline" value="0x200" summary="the text input is multiline"/> + </enum> + + <enum name="content_purpose"> + <description summary="content purpose"> + 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. + </description> + <entry name="normal" value="0" summary="default input, allowing all characters"/> + <entry name="alpha" value="1" summary="allow only alphabetic characters"/> + <entry name="digits" value="2" summary="allow only digits"/> + <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/> + <entry name="phone" value="4" summary="input a phone number"/> + <entry name="url" value="5" summary="input an URL"/> + <entry name="email" value="6" summary="input an email address"/> + <entry name="name" value="7" summary="input a name of a person"/> + <entry name="password" value="8" summary="input a password (combine with password or sensitive_data hint)"/> + <entry name="date" value="9" summary="input a date"/> + <entry name="time" value="10" summary="input a time"/> + <entry name="datetime" value="11" summary="input a date and time"/> + <entry name="terminal" value="12" summary="input for a terminal"/> + </enum> + + <request name="set_content_type"> + <description summary="set content purpose and hint"> + 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. + </description> + <arg name="hint" type="uint" enum="content_hint"/> + <arg name="purpose" type="uint" enum="content_purpose"/> + </request> + + <request name="set_cursor_rectangle"> + <description summary="set cursor position"> + 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. + </description> + <arg name="x" type="int"/> + <arg name="y" type="int"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + </request> + + <request name="set_preferred_language"> + <description summary="sets preferred language"> + 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. + </description> + <arg name="language" type="string"/> + </request> + + <enum name="update_state"> + <description summary="update_state flags"> + Defines the reason for sending an updated state. + </description> + <entry name="change" value="0" summary="updated state because it changed"/> + <entry name="full" value="1" summary="full state after enter or input_method_changed event"/> + <entry name="reset" value="2" summary="full state after reset"/> + <entry name="enter" value="3" summary="full state after switching focus to a different widget on client side"/> + </enum> + + <request name="update_state"> + <description summary="update 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. + </description> + <arg name="serial" type="uint" summary="serial of the enter or input_method_changed event"/> + <arg name="reason" type="uint" enum="update_state"/> + </request> + + <event name="enter"> + <description summary="enter event"> + 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. + </description> + <arg name="serial" type="uint" summary="serial to be used by update_state"/> + <arg name="surface" type="object" interface="wl_surface"/> + </event> + + <event name="leave"> + <description summary="leave event"> + 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. + </description> + <arg name="serial" type="uint"/> + <arg name="surface" type="object" interface="wl_surface"/> + </event> + + <enum name="input_panel_visibility"> + <entry name="hidden" value="0" + summary="the input panel (virtual keyboard) is hidden"/> + <entry name="visible" value="1" + summary="the input panel (virtual keyboard) is visible"/> + </enum> + + <event name="input_panel_state"> + <description summary="state of the input panel"> + 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. + </description> + <arg name="state" type="uint" enum="input_panel_visibility"/> + <arg name="x" type="int"/> + <arg name="y" type="int"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + </event> + + <event name="preedit_string"> + <description summary="pre-edit"> + 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. + </description> + <arg name="text" type="string"/> + <arg name="commit" type="string"/> + </event> + + <enum name="preedit_style"> + <entry name="default" value="0" summary="default style for composing text"/> + <entry name="none" value="1" summary="composing text should be shown the same as non-composing text"/> + <entry name="active" value="2" summary="composing text might be bold"/> + <entry name="inactive" value="3" summary="composing text might be cursive"/> + <entry name="highlight" value="4" summary="composing text might have a different background color"/> + <entry name="underline" value="5" summary="composing text might be underlined"/> + <entry name="selection" value="6" summary="composing text should be shown the same as selected text"/> + <entry name="incorrect" value="7" summary="composing text might be underlined with a red wavy line"/> + </enum> + + <event name="preedit_styling"> + <description summary="pre-edit styling"> + 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. + </description> + <arg name="index" type="uint"/> + <arg name="length" type="uint"/> + <arg name="style" type="uint" enum="preedit_style"/> + </event> + + <event name="preedit_cursor"> + <description summary="pre-edit cursor"> + 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. + </description> + <arg name="index" type="int"/> + </event> + + <event name="commit_string"> + <description summary="commit"> + 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. + </description> + <arg name="text" type="string"/> + </event> + + <event name="cursor_position"> + <description summary="set cursor to new position"> + 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. + </description> + <arg name="index" type="int" summary="position of cursor"/> + <arg name="anchor" type="int" summary="position of selection anchor"/> + </event> + + <event name="delete_surrounding_text"> + <description summary="delete surrounding text"> + 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. + </description> + <arg name="before_length" type="uint" summary="length of text before current cursor positon"/> + <arg name="after_length" type="uint" summary="length of text after current cursor positon"/> + </event> + + <event name="modifiers_map"> + <description summary="modifiers map"> + 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. + </description> + <arg name="map" type="array"/> + </event> + + <event name="keysym"> + <description summary="keysym"> + 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) + </description> + <arg name="time" type="uint"/> + <arg name="sym" type="uint"/> + <arg name="state" type="uint"/> + <arg name="modifiers" type="uint"/> + </event> + + <event name="language"> + <description summary="language"> + Sets the language of the input text. The "language" argument is a RFC-3066 + format language tag. + </description> + <arg name="language" type="string"/> + </event> + + <enum name="text_direction"> + <entry name="auto" value="0" summary="automatic text direction based on text and language"/> + <entry name="ltr" value="1" summary="left-to-right"/> + <entry name="rtl" value="2" summary="right-to-left"/> + </enum> + + <event name="text_direction"> + <description summary="text direction"> + 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. + </description> + <arg name="direction" type="uint" enum="text_direction"/> + </event> + + <event name="configure_surrounding_text"> + <description summary="configure amount of surrounding text to be sent"> + 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. + </description> + <arg name="before_cursor" type="int"/> + <arg name="after_cursor" type="int"/> + </event> + + <event name="input_method_changed"> + <description summary="Notifies about a changed input method"> + 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. + </description> + <arg name="serial" type="uint" summary="serial to be used by update_state"/> + <arg name="flags" type="uint" summary="currently unused"/> + </event> + </interface> + + <interface name="zwp_text_input_manager_v2" version="1"> + <description summary="text input manager"> + A factory for text-input objects. This object is a global singleton. + </description> + + <request name="destroy" type="destructor"> + <description summary="Destroy the wp_text_input_manager"> + Destroy the wp_text_input_manager object. + </description> + </request> + + <request name="get_text_input"> + <description summary="create a new text input object"> + Creates a new text-input object for a given seat. + </description> + <arg name="id" type="new_id" interface="zwp_text_input_v2"/> + <arg name="seat" type="object" interface="wl_seat"/> + </request> + </interface> +</protocol> 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 @@ -<?xml version="1.0" encoding="UTF-8"?> -<protocol name="text"> - - <copyright> - 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. - </copyright> - - <interface name="wl_text_input" version="1"> - <description summary="text input"> - 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). - </description> - <request name="activate"> - <description summary="request activation"> - 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. - </description> - <arg name="seat" type="object" interface="wl_seat"/> - <arg name="surface" type="object" interface="wl_surface"/> - </request> - <request name="deactivate"> - <description summary="request deactivation"> - 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. - </description> - <arg name="seat" type="object" interface="wl_seat"/> - </request> - <request name="show_input_panel"> - <description summary="show input panels"> - Requests input panels (virtual keyboard) to show. - </description> - </request> - <request name="hide_input_panel"> - <description summary="hide input panels"> - Requests input panels (virtual keyboard) to hide. - </description> - </request> - <request name="reset"> - <description summary="reset"> - 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. - </description> - </request> - <request name="set_surrounding_text"> - <description summary="sets the surrounding text"> - 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. - </description> - <arg name="text" type="string"/> - <arg name="cursor" type="uint"/> - <arg name="anchor" type="uint"/> - </request> - <enum name="content_hint"> - <description summary="content hint"> - Content hint is a bitmask to allow to modify the behavior of the text - input. - </description> - <entry name="none" value="0x0" summary="no special behaviour"/> - <entry name="default" value="0x7" summary="auto completion, correction and capitalization"/> - <entry name="password" value="0xc0" summary="hidden and sensitive text"/> - <entry name="auto_completion" value="0x1" summary="suggest word completions"/> - <entry name="auto_correction" value="0x2" summary="suggest word corrections"/> - <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/> - <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/> - <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/> - <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/> - <entry name="hidden_text" value="0x40" summary="characters should be hidden"/> - <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/> - <entry name="latin" value="0x100" summary="just latin characters should be entered"/> - <entry name="multiline" value="0x200" summary="the text input is multiline"/> - </enum> - <enum name="content_purpose"> - <description summary="content purpose"> - 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. - </description> - <entry name="normal" value="0" summary="default input, allowing all characters"/> - <entry name="alpha" value="1" summary="allow only alphabetic characters"/> - <entry name="digits" value="2" summary="allow only digits"/> - <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/> - <entry name="phone" value="4" summary="input a phone number"/> - <entry name="url" value="5" summary="input an URL"/> - <entry name="email" value="6" summary="input an email address"/> - <entry name="name" value="7" summary="input a name of a person"/> - <entry name="password" value="8" summary="input a password (combine with password or sensitive_data hint)"/> - <entry name="date" value="9" summary="input a date"/> - <entry name="time" value="10" summary="input a time"/> - <entry name="datetime" value="11" summary="input a date and time"/> - <entry name="terminal" value="12" summary="input for a terminal"/> - </enum> - <request name="set_content_type"> - <description summary="set content purpose and hint"> - 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. - </description> - <arg name="hint" type="uint"/> - <arg name="purpose" type="uint"/> - </request> - <request name="set_cursor_rectangle"> - <arg name="x" type="int"/> - <arg name="y" type="int"/> - <arg name="width" type="int"/> - <arg name="height" type="int"/> - </request> - <request name="set_preferred_language"> - <description summary="sets preferred language"> - 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. - </description> - <arg name="language" type="string"/> - </request> - <request name="commit_state"> - <arg name="serial" type="uint" summary="used to identify the known state"/> - </request> - <request name="invoke_action"> - <arg name="button" type="uint"/> - <arg name="index" type="uint"/> - </request> - <event name="enter"> - <description summary="enter event"> - Notify the text-input object when it received focus. Typically in - response to an activate request. - </description> - <arg name="surface" type="object" interface="wl_surface"/> - </event> - <event name="leave"> - <description summary="leave event"> - 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. - </description> - </event> - <event name="modifiers_map"> - <description summary="modifiers map"> - 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. - </description> - <arg name="map" type="array"/> - </event> - <event name="input_panel_state"> - <description summary="state of the input panel"> - Notify when the visibility state of the input panel changed. - </description> - <arg name="state" type="uint"/> - </event> - <event name="preedit_string"> - <description summary="pre-edit"> - 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. - </description> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="text" type="string"/> - <arg name="commit" type="string"/> - </event> - <enum name="preedit_style"> - <entry name="default" value="0" summary="default style for composing text"/> - <entry name="none" value="1" summary="style should be the same as in non-composing text"/> - <entry name="active" value="2"/> - <entry name="inactive" value="3"/> - <entry name="highlight" value="4"/> - <entry name="underline" value="5"/> - <entry name="selection" value="6"/> - <entry name="incorrect" value="7"/> - </enum> - <event name="preedit_styling"> - <description summary="pre-edit styling"> - 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. - </description> - <arg name="index" type="uint"/> - <arg name="length" type="uint"/> - <arg name="style" type="uint"/> - </event> - <event name="preedit_cursor"> - <description summary="pre-edit cursor"> - 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. - </description> - <arg name="index" type="int"/> - </event> - <event name="commit_string"> - <description summary="commit"> - 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. - </description> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="text" type="string"/> - </event> - <event name="cursor_position"> - <description summary="set cursor to new position"> - Notify when the cursor or anchor position should be modified. - - This event should be handled as part of a following commit_string - event. - </description> - <arg name="index" type="int"/> - <arg name="anchor" type="int"/> - </event> - <event name="delete_surrounding_text"> - <description summary="delete surrounding text"> - 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. - </description> - <arg name="index" type="int"/> - <arg name="length" type="uint"/> - </event> - <event name="keysym"> - <description summary="keysym"> - 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) - </description> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="time" type="uint"/> - <arg name="sym" type="uint"/> - <arg name="state" type="uint"/> - <arg name="modifiers" type="uint"/> - </event> - <event name="language"> - <description summary="language"> - Sets the language of the input text. The "language" argument is a RFC-3066 - format language tag. - </description> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="language" type="string"/> - </event> - <enum name="text_direction"> - <entry name="auto" value="0" summary="automatic text direction based on text and language"/> - <entry name="ltr" value="1" summary="left-to-right"/> - <entry name="rtl" value="2" summary="right-to-left"/> - </enum> - <event name="text_direction"> - <description summary="text direction"> - 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. - </description> - <arg name="serial" type="uint" summary="serial of the latest known text input state"/> - <arg name="direction" type="uint"/> - </event> - </interface> - - <interface name="wl_text_input_manager" version="1"> - <description summary="text input manager"> - A factory for text-input objects. This object is a global singleton. - </description> - <request name="create_text_input"> - <description summary="create text input"> - Creates a new text-input object. - </description> - <arg name="id" type="new_id" interface="wl_text_input"/> - </request> - </interface> -</protocol> 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 <QtWaylandClient/private/qwayland-text.h> +#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h> #include <QtWaylandClient/private/qwayland-xdg-shell.h> #include <QtCore/QAbstractEventDispatcher> @@ -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<QWaylandTouchExtension> mTouchExtension; QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension; QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration; - QScopedPointer<QtWayland::wl_text_input_manager> mTextInputManager; + QScopedPointer<QtWayland::zwp_text_input_manager_v2> mTextInputManager; QScopedPointer<QWaylandHardwareIntegration> 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 <QGuiApplication> -#include <QWindow> -#ifndef QT_NO_WAYLAND_XKB -#include <xkbcommon/xkbcommon.h> -#endif +#include <QtGui/QGuiApplication> +#include <QtGui/QTextCharFormat> +#include <QtGui/QWindow> +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpa/qplatformintegration.h> #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<xkb_keysym_t>(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<wl_keyboard_key_state>(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<QWaylandTextInput*>(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<QWaylandWindow *>(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<Qt::InputMethodHints>(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<QByteArray> modifiersMap = QByteArray::fromRawData(static_cast<const char*>(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<QInputMethodEvent::Attribute> 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<QWaylandWindow *>(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<QWaylandWindow *>(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<QWaylandWindow *>(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<QWaylandWindow *>(mCurrentWindow->handle())->object(); + textInput()->disable(surface); + mCurrentWindow.clear(); + } + } + + if (window && window->handle() && inputMethodAccepted()) { + if (mCurrentWindow.data() != window) { + struct ::wl_surface *surface = static_cast<QWaylandWindow *>(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 <qpa/qplatforminputcontext.h> -#include <QtWaylandClient/private/qwayland-text.h> +#include <QLoggingCategory> +#include <QPointer> +#include <QRectF> +#include <QVector> + +#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h> +#include <qwaylandinputmethodeventbuilder.h> 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<Qt::KeyboardModifier> 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<QWaylandTextInput> mTextInput; + QPointer<QWindow> 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 <QtGui/private/qpixmap_raster_p.h> #include <QtGui/private/qguiapplication_p.h> @@ -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 <QObject> #include <QImage> #include <QRect> +#include <QLoggingCategory> 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 <QtWaylandCompositor/QWaylandDrag> #include <QtWaylandCompositor/QWaylandTouch> #include <QtWaylandCompositor/QWaylandPointer> #include <QtWaylandCompositor/QWaylandWlShellSurface> -#include <QtWaylandCompositor/private/qwlinputmethod_p.h> #include <QtWaylandCompositor/private/qwaylandinput_p.h> #include <QtWaylandCompositor/private/qwaylandcompositor_p.h> #include <QtWaylandCompositor/private/qwldatadevice_p.h> #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 <QtGui/QInputMethodEvent> + +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/qwaylandinputpanel.cpp b/src/compositor/compositor_api/qwaylandinputmethodcontrol.h index 6f774cd98..f71650294 100644 --- a/src/compositor/compositor_api/qwaylandinputpanel.cpp +++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** 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. @@ -34,50 +34,51 @@ ** ****************************************************************************/ -#include "qwaylandinputpanel.h" +#ifndef QWAYLANDINPUTMETHODCONTROL_H +#define QWAYLANDINPUTMETHODCONTROL_H -#include <QtWaylandCompositor/QWaylandCompositor> - -#include <private/qobject_p.h> - -#include "qwlinputpanel_p.h" +#include <QObject> QT_BEGIN_NAMESPACE -QWaylandInputPanel::QWaylandInputPanel(QWaylandCompositor *compositor) - : QWaylandExtensionTemplate(compositor, *new QWaylandInputPanelPrivate(compositor)) -{ -} +class QWaylandCompositor; +class QWaylandInputMethodControlPrivate; +class QWaylandSurface; +class QInputMethodEvent; -QWaylandSurface *QWaylandInputPanel::focus() const +class QWaylandInputMethodControl : public QObject { - Q_D(const QWaylandInputPanel); + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandInputMethodControl) + Q_DISABLE_COPY(QWaylandInputMethodControl) - return d->focus(); -} + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) +public: + explicit QWaylandInputMethodControl(QWaylandSurface *surface); -bool QWaylandInputPanel::visible() const -{ - Q_D(const QWaylandInputPanel); +#ifndef QT_NO_IM + QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const; +#endif - return d->inputPanelVisible(); -} + void inputMethodEvent(QInputMethodEvent *event); -QRect QWaylandInputPanel::cursorRectangle() const -{ - Q_D(const QWaylandInputPanel); + bool enabled() const; + void setEnabled(bool enabled); - return d->cursorRectangle(); -} + void setSurface(QWaylandSurface *surface); -const struct wl_interface *QWaylandInputPanel::interface() -{ - return QWaylandInputPanelPrivate::interface(); -} +Q_SIGNALS: + void enabledChanged(bool enabled); +#ifndef QT_NO_IM + void updateInputMethod(Qt::InputMethodQueries queries); +#endif -QByteArray QWaylandInputPanel::interfaceName() -{ - return QWaylandInputPanelPrivate::interfaceName(); -} +private: + void defaultInputDeviceChanged(); + void surfaceEnabled(QWaylandSurface *surface); + void surfaceDisabled(QWaylandSurface *surface); +}; QT_END_NAMESPACE + +#endif // QWAYLANDINPUTMETHODCONTROL_H diff --git a/src/compositor/compositor_api/qwaylandinputpanel.h b/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h index d29743140..a687e5299 100644 --- a/src/compositor/compositor_api/qwaylandinputpanel.h +++ b/src/compositor/compositor_api/qwaylandinputmethodcontrol_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** 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. @@ -34,45 +34,47 @@ ** ****************************************************************************/ -#ifndef QWAYLANDINPUTPANEL_H -#define QWAYLANDINPUTPANEL_H +#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 <QtWaylandCompositor/qwaylandexport.h> -#include <QtWaylandCompositor/qwaylandextension.h> +#include <QtWaylandCompositor/qwaylandinputmethodcontrol.h> -#include <QObject> -#include <QRect> +#include <QtCore/private/qobject_p.h> QT_BEGIN_NAMESPACE class QWaylandCompositor; -class QWaylandInputPanelPrivate; +class QWaylandInputDevice; class QWaylandSurface; +class QWaylandTextInput; -class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandInputPanel : public QWaylandExtensionTemplate<QWaylandInputPanel> +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandInputMethodControlPrivate : public QObjectPrivate { - 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) + Q_DECLARE_PUBLIC(QWaylandInputMethodControl) public: - explicit QWaylandInputPanel(QWaylandCompositor *compositor); + explicit QWaylandInputMethodControlPrivate(QWaylandSurface *surface); - QWaylandSurface *focus() const; - bool visible() const; - QRect cursorRectangle() const; + QWaylandTextInput *textInput() const; - static const struct wl_interface *interface(); - static QByteArray interfaceName(); -Q_SIGNALS: - void focusChanged(); - void visibleChanged(); - void cursorRectangleChanged(); + QWaylandCompositor *compositor; + QWaylandInputDevice *inputDevice; + QWaylandSurface *surface; + bool enabled; }; QT_END_NAMESPACE -#endif // QWAYLANDINPUTPANEL_H +#endif // QWAYLANDINPUTMETHODCONTROL_P_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 <QtWaylandCompositor/qwaylandcompositor.h> #include <QtWaylandCompositor/qwaylandinput.h> #include <QtWaylandCompositor/qwaylandbufferref.h> @@ -54,6 +56,7 @@ #include <wayland-server.h> #include <QThread> + 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 <QtWaylandCompositor/QWaylandCompositor> #include <QtWaylandCompositor/QWaylandClient> @@ -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 @@ -588,16 +590,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 <QtWaylandCompositor/qwaylandsurface.h> #include <QtWaylandCompositor/qwaylandbufferref.h> -#include <QtWaylandCompositor/private/qwlinputpanelsurface_p.h> #include <QtWaylandCompositor/private/qwlregion_p.h> #include <QtCore/QVector> @@ -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<QtWayland::FrameCallback *> pendingFrameCallbacks; QList<QtWayland::FrameCallback *> 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 <QtWaylandCompositor/QWaylandCompositor> +#include <QtWaylandCompositor/private/qwaylandinput_p.h> + +#include "qwaylandsurface.h" +#include "qwaylandview.h" +#include "qwaylandxkb.h" +#include "qwaylandinputmethodeventbuilder.h" + +#include <QGuiApplication> +#include <QInputMethodEvent> + +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<int>(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/qwlinputpanelsurface_p.h b/src/compositor/extensions/qwaylandtextinput.h index e11923bd0..100384e76 100644 --- a/src/compositor/extensions/qwlinputpanelsurface_p.h +++ b/src/compositor/extensions/qwaylandtextinput.h @@ -1,7 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** 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. @@ -35,61 +34,53 @@ ** ****************************************************************************/ -#ifndef QTWAYLAND_QWLINPUTPANELSURFACE_P_H -#define QTWAYLAND_QWLINPUTPANELSURFACE_P_H +#ifndef QWAYLANDTEXTINPUT_H +#define QWAYLANDTEXTINPUT_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 <QtWaylandCompositor/private/qwayland-server-input-method.h> - -#include <QWaylandSurface> +#include <QtWaylandCompositor/QWaylandExtension> QT_BEGIN_NAMESPACE -class QWaylandOutput; +class QWaylandTextInputPrivate; -namespace QtWayland { +class QInputMethodEvent; +class QKeyEvent; +class QWaylandSurface; -class InputPanelSurface : public QtWaylandServer::wl_input_panel_surface +class QWaylandTextInput : public QWaylandExtensionTemplate<QWaylandTextInput> { + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandTextInput) public: - enum Type { - Invalid, - Toplevel, - OverlayPanel - }; + explicit QWaylandTextInput(QWaylandObject *container, QWaylandCompositor *compositor); + ~QWaylandTextInput(); - InputPanelSurface(struct ::wl_client *client, int id, QWaylandSurface *surface); + void sendInputMethodEvent(QInputMethodEvent *event); + void sendKeyEvent(QKeyEvent *event); - Type type() const; + QVariant inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const; - QWaylandOutput *output() const; - wl_input_panel_surface::position position() const; + QWaylandSurface *focus() const; + void setFocus(QWaylandSurface *surface); -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; + bool isSurfaceEnabled(QWaylandSurface *surface) const; -private: - QWaylandSurface *m_surface; + void add(::wl_client *client, uint32_t id, int version); + static const struct wl_interface *interface(); + static QByteArray interfaceName(); - Type m_type; +Q_SIGNALS: + void updateInputMethod(Qt::InputMethodQueries queries); + void surfaceEnabled(QWaylandSurface *surface); + void surfaceDisabled(QWaylandSurface *surface); - QWaylandOutput *m_output; - wl_input_panel_surface::position m_position; +private: + void focusSurfaceDestroyed(void *); + void sendInputPanelState(); + void sendTextDirection(); + void sendLocale(); }; -} // namespace QtWayland - QT_END_NAMESPACE -#endif // QTWAYLAND_QWLINPUTPANELSURFACE_P_H +#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 <QtWaylandCompositor/private/qwaylandextension_p.h> +#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v2.h> +#include <QtWaylandCompositor/QWaylandDestroyListener> + +#include <QtCore/QObject> +#include <QtCore/QMap> +#include <QtCore/QRect> +#include <QtCore/QVector> +#include <QtGui/QInputMethod> +#include <QtWaylandCompositor/QWaylandSurface> + +// +// 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<QWaylandTextInputClientState> currentState; + QScopedPointer<QWaylandTextInputClientState> pendingState; + + uint32_t serial; + + QHash<Resource *, QWaylandSurface*> 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 <QtWaylandCompositor/QWaylandCompositor> +#include <QtWaylandCompositor/QWaylandInputDevice> + +#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<QWaylandCompositor *>(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<QWaylandTextInputManager>(*new QWaylandTextInputManagerPrivate) +{ +} + +QWaylandTextInputManager::QWaylandTextInputManager(QWaylandCompositor *compositor) + : QWaylandExtensionTemplate<QWaylandTextInputManager>(compositor, *new QWaylandTextInputManagerPrivate) +{ +} + +void QWaylandTextInputManager::initialize() +{ + Q_D(QWaylandTextInputManager); + + QWaylandExtensionTemplate::initialize(); + QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(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/qwltextinputmanager.cpp b/src/compositor/extensions/qwaylandtextinputmanager.h index 9c7dd72f4..6c250d58c 100644 --- a/src/compositor/extensions/qwltextinputmanager.cpp +++ b/src/compositor/extensions/qwaylandtextinputmanager.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** 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. @@ -34,31 +34,31 @@ ** ****************************************************************************/ -#include "qwltextinputmanager_p.h" +#ifndef QWAYLANDTEXTINPUTMANAGER_H +#define QWAYLANDTEXTINPUTMANAGER_H -#include <QtWaylandCompositor/QWaylandCompositor> -#include "qwltextinput_p.h" +#include <QtWaylandCompositor/QWaylandExtension> + +#include <QtCore/QSize> QT_BEGIN_NAMESPACE -namespace QtWayland { +class QWaylandTextInputManagerPrivate; -TextInputManager::TextInputManager(QWaylandCompositor *compositor) - : QWaylandExtensionTemplate(compositor) - , QtWaylandServer::wl_text_input_manager(compositor->display(), 1) - , m_compositor(compositor) +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandTextInputManager : public QWaylandExtensionTemplate<QWaylandTextInputManager> { -} + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandTextInputManager) +public: + QWaylandTextInputManager(); + QWaylandTextInputManager(QWaylandCompositor *compositor); -TextInputManager::~TextInputManager() -{ -} + void initialize() Q_DECL_OVERRIDE; -void TextInputManager::text_input_manager_create_text_input(Resource *resource, uint32_t id) -{ - new TextInput(this, m_compositor, resource->client(), id); -} - -} // namespace QtWayland + static const struct wl_interface *interface(); + static QByteArray interfaceName(); +}; QT_END_NAMESPACE + +#endif // QWAYLANDTEXTINPUTMANAGER_H diff --git a/src/compositor/extensions/qwltextinputmanager_p.h b/src/compositor/extensions/qwaylandtextinputmanager_p.h index 0125bdcae..8052301c9 100644 --- a/src/compositor/extensions/qwltextinputmanager_p.h +++ b/src/compositor/extensions/qwaylandtextinputmanager_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** 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. @@ -34,11 +34,12 @@ ** ****************************************************************************/ -#ifndef QTWAYLAND_QWLTEXTINPUTMANAGER_P_H -#define QTWAYLAND_QWLTEXTINPUTMANAGER_P_H +#ifndef QWAYLANDTEXTINPUTMANAGER_P_H +#define QWAYLANDTEXTINPUTMANAGER_P_H -#include <QtWaylandCompositor/QWaylandExtension> -#include <QtWaylandCompositor/private/qwayland-server-text.h> +#include <QtWaylandCompositor/private/qwaylandextension_p.h> + +#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v2.h> // // W A R N I N G @@ -53,26 +54,16 @@ QT_BEGIN_NAMESPACE -class QWaylandCompositor; - -namespace QtWayland { - -class TextInputManager : public QWaylandExtensionTemplate<TextInputManager>, public QtWaylandServer::wl_text_input_manager +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandTextInputManagerPrivate : public QWaylandExtensionTemplatePrivate, public QtWaylandServer::zwp_text_input_manager_v2 { - Q_OBJECT + Q_DECLARE_PUBLIC(QWaylandTextInputManager) public: - TextInputManager(QWaylandCompositor *compositor); - ~TextInputManager(); + QWaylandTextInputManagerPrivate(); protected: - void text_input_manager_create_text_input(Resource *resource, uint32_t id) Q_DECL_OVERRIDE; - -private: - QWaylandCompositor *m_compositor; + void zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seat) Q_DECL_OVERRIDE; }; -} // namespace QtWayland - QT_END_NAMESPACE -#endif // QTWAYLAND_QWLTEXTINPUTMANAGER_P_H +#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 <QtWaylandCompositor/QWaylandCompositor> -#include <QtWaylandCompositor/QWaylandKeyboard> -#include <QtWaylandCompositor/QWaylandInputDevice> -#include "qwlinputmethodcontext_p.h" -#include "qwlinputpanel_p.h" -#include "qwltextinput_p.h" - -QT_BEGIN_NAMESPACE - -namespace QtWayland { - -InputMethod::InputMethod(QWaylandInputDevice *seat) - : QWaylandExtensionTemplate<InputMethod>(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 <QtWaylandCompositor/private/qwayland-server-input-method.h> -#include <QtWaylandCompositor/QWaylandExtension> -#include <QtWaylandCompositor/QWaylandInputDevice> - -#include <QObject> -#include <QScopedPointer> - -#include <QtWaylandCompositor/QWaylandSurface> - -QT_BEGIN_NAMESPACE - -class QWaylandInputDevice; -class QWaylandCompositor; - -namespace QtWayland { - -class InputMethodContext; -class TextInput; - -class InputMethod : public QWaylandExtensionTemplate<InputMethod> , 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<char *>(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 <QtWaylandCompositor/private/qwayland-server-input-method.h> - -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 <QtWaylandCompositor/qwaylandinputpanel.h> -#include <QtWaylandCompositor/QWaylandCompositor> - -#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<QWaylandInputPanel *>(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 <QtWaylandCompositor/qwaylandexport.h> -#include <QtWaylandCompositor/qwaylandinputpanel.h> - -#include <QtWaylandCompositor/private/qwaylandextension_p.h> -#include <QtWaylandCompositor/private/qwayland-server-input-method.h> - -#include <QRect> -#include <QScopedPointer> - -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 <pierluigi.fiorini@gmail.com> -** 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 <QtWaylandCompositor/private/qwaylandsurface_p.h> -#include <QtWaylandCompositor/QWaylandOutput> - -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<wl_input_panel_surface::position>(position); -} - -QT_END_NAMESPACE - -} // namespace QtWayland 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 <QtWaylandCompositor/QWaylandInputPanel> -#include <QtWaylandCompositor/QWaylandCompositor> -#include <QtWaylandCompositor/private/qwaylandinput_p.h> - -#include <algorithm> - -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 <QtWaylandCompositor/QWaylandExtension> -#include <QtWaylandCompositor/private/qwayland-server-text.h> - -#include <QRect> - -QT_BEGIN_NAMESPACE - -class QWaylandSurface; -class QWaylandCompositor; - -namespace QtWayland { - -class InputMethod; - -class TextInput : public QWaylandExtensionTemplate<TextInput>, 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<InputMethod*> 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/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 <QtWaylandCompositor/QWaylandResource> #include <QtWaylandCompositor/QWaylandWlShell> +#include <QtWaylandCompositor/QWaylandTextInputManager> #include <QtWaylandCompositor/qwaylandexport.h> #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<QWaylandWlShellQuickData>(uri, 1, 0, "WlShell"); qmlRegisterType<QWaylandWlShellSurfaceQuickData>(uri, 1, 0, "WlShellSurface"); qmlRegisterType<QWaylandQuickWlShellSurfaceItem>(uri, 1, 0, "WlShellSurfaceItem"); - + qmlRegisterType<QWaylandTextInputManagerQuickData>(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 <QInputMethod> +#include <QTextCharFormat> + +#ifdef QT_BUILD_WAYLANDCOMPOSITOR_LIB +#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v2.h> +#else +#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h> +#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<QInputMethodEvent::Attribute> attributes; + + const QPair<int, int> 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<QInputMethodEvent::Attribute> 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<int, int> replacement = replacementForDeleteSurrounding(); + event.setCommitString(QString(), replacement.first, replacement.second); + + return event; +} + +QPair<int, int> QWaylandInputMethodEventBuilder::replacementForDeleteSurrounding() +{ + if (m_deleteBefore == 0 && m_deleteAfter == 0) + return QPair<int, int>(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<int, int>(-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 <QInputMethodEvent> + +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<int, int> replacementForDeleteSurrounding(); + + int32_t m_anchor; + int32_t m_cursor; + uint32_t m_deleteBefore; + uint32_t m_deleteAfter; + + int32_t m_preeditCursor; + QList<QInputMethodEvent::Attribute> 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 <QKeyEvent> #include <QString> #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<xkb_keysym_t> QWaylandXkb::toKeysym(QKeyEvent *event) +{ + QVector<xkb_keysym_t> 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 <Qt> +#include <QEvent> #include <xkbcommon/xkbcommon.h> 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<xkb_keysym_t> toKeysym(QKeyEvent *event); }; QT_END_NAMESPACE |