widget: Move IM context to Widget

parent 9f9b31f8
......@@ -3334,8 +3334,7 @@ Terminal::pty_channel_eof()
void
Terminal::im_reset()
{
if (widget_realized() && m_im_context)
gtk_im_context_reset(m_im_context);
m_real_widget->im_reset();
m_im_preedit.clear();
m_im_preedit.shrink_to_fit();
......@@ -4339,15 +4338,6 @@ Terminal::reply(vte::parser::Sequence const& seq,
send(seq, builder);
}
/* Send text from the input method to the child. */
static void
vte_terminal_im_commit_cb(GtkIMContext *im_context,
char const* text,
vte::terminal::Terminal* that)
{
that->im_commit(text);
}
void
Terminal::im_commit(char const* text)
{
......@@ -4361,70 +4351,27 @@ Terminal::im_commit(char const* text)
}
}
/* We've started pre-editing. */
static void
vte_terminal_im_preedit_start_cb(GtkIMContext *im_context,
vte::terminal::Terminal* that)
{
that->im_preedit_start();
}
void
Terminal::im_preedit_start()
{
_vte_debug_print(VTE_DEBUG_EVENTS,
"Input method pre-edit started.\n");
m_im_preedit_active = true;
}
/* We've stopped pre-editing. */
static void
vte_terminal_im_preedit_end_cb(GtkIMContext *im_context,
vte::terminal::Terminal* that)
{
that->im_preedit_end();
}
void
Terminal::im_preedit_end()
{
_vte_debug_print(VTE_DEBUG_EVENTS,
"Input method pre-edit ended.\n");
m_im_preedit_active = false;
}
/* The pre-edit string changed. */
static void
vte_terminal_im_preedit_changed_cb(GtkIMContext *im_context,
vte::terminal::Terminal* that)
Terminal::im_preedit_set_active(bool active) noexcept
{
that->im_preedit_changed();
m_im_preedit_active = active;
}
void
Terminal::im_preedit_changed()
Terminal::im_preedit_changed(char const* str,
int cursorpos,
PangoAttrList* attrs) noexcept
{
gchar *str;
PangoAttrList *attrs;
gint cursorpos;
gtk_im_context_get_preedit_string(m_im_context, &str, &attrs, &cursorpos);
_vte_debug_print(VTE_DEBUG_EVENTS,
"Input method pre-edit changed (%s,%d).\n",
str, cursorpos);
/* Queue the area where the current preedit string is being displayed
* for repainting. */
invalidate_cursor_once();
m_im_preedit = str;
g_free(str);
if (m_im_preedit_attrs != NULL) {
if (m_im_preedit_attrs != nullptr) {
pango_attr_list_unref(m_im_preedit_attrs);
}
m_im_preedit_attrs = attrs;
m_im_preedit_cursor = cursorpos;
/* Invalidate again with the new cursor position */
......@@ -4434,39 +4381,18 @@ Terminal::im_preedit_changed()
im_update_cursor();
}
static gboolean
vte_terminal_im_retrieve_surrounding_cb(GtkIMContext *im_context,
vte::terminal::Terminal* that)
{
return that->im_retrieve_surrounding();
}
bool
Terminal::im_retrieve_surrounding()
{
/* FIXME: implement this! Bug #726191 */
_vte_debug_print(VTE_DEBUG_EVENTS,
"Input method retrieve-surrounding.\n");
return false;
}
static gboolean
vte_terminal_im_delete_surrounding_cb(GtkIMContext *im_context,
int offset,
int n_chars,
vte::terminal::Terminal* that)
{
return that->im_delete_surrounding(offset, n_chars);
}
bool
Terminal::im_delete_surrounding(int offset,
int n_chars)
int n_chars)
{
/* FIXME: implement this! Bug #726191 */
_vte_debug_print(VTE_DEBUG_EVENTS,
"Input method delete-surrounding offset %d n-chars %d.\n",
offset, n_chars);
return false;
}
......@@ -4482,7 +4408,7 @@ Terminal::im_update_cursor()
rect.width = m_cell_width; // FIXMEchpe: if columns > 1 ?
rect.y = row_to_pixel(m_screen->cursor.row) + m_padding.top;
rect.height = m_cell_height;
gtk_im_context_set_cursor_location(m_im_context, &rect);
m_real_widget->im_set_cursor_location(&rect);
}
void
......@@ -4765,7 +4691,7 @@ Terminal::widget_key_press(GdkEventKey *event)
/* Let the input method at this one first. */
if (!steal && m_input_enabled) {
if (m_im_context && gtk_im_context_filter_keypress(m_im_context, event)) {
if (m_real_widget->im_filter_keypress(event)) {
_vte_debug_print(VTE_DEBUG_EVENTS,
"Keypress taken by IM.\n");
return true;
......@@ -5059,8 +4985,7 @@ Terminal::widget_key_release(GdkEventKey *event)
read_modifiers((GdkEvent*)event);
if (m_input_enabled &&
m_im_context &&
gtk_im_context_filter_keypress(m_im_context, event))
m_real_widget->im_filter_keypress(event))
return true;
return false;
......@@ -7374,7 +7299,7 @@ Terminal::widget_focus_in(GdkEventFocus *event)
check_cursor_blink();
gtk_im_context_focus_in(m_im_context);
m_real_widget->im_focus_in();
invalidate_cursor_once();
maybe_feed_focus_event(true);
}
......@@ -7403,7 +7328,7 @@ Terminal::widget_focus_out(GdkEventFocus *event)
invalidate_all();
}
gtk_im_context_focus_out(m_im_context);
m_real_widget->im_focus_out();
invalidate_cursor_once();
m_mouse_pressed_buttons = 0;
......@@ -8312,24 +8237,11 @@ Terminal::widget_size_allocate(GtkAllocation *allocation)
void
Terminal::widget_unrealize()
{
_vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_unrealize()\n");
/* Deallocate the cursors. */
m_mouse_cursor_over_widget = FALSE;
match_hilite_clear();
/* Shut down input methods. */
if (m_im_context != nullptr) {
g_signal_handlers_disconnect_matched(m_im_context, G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
this);
im_reset();
gtk_im_context_set_client_window(m_im_context,
NULL);
g_object_unref(m_im_context);
m_im_context = nullptr;
}
m_im_preedit_active = FALSE;
m_im_preedit.clear();
m_im_preedit.shrink_to_fit();
......@@ -8577,8 +8489,6 @@ Terminal::~Terminal()
void
Terminal::widget_realize()
{
_vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_realize()\n");
m_mouse_cursor_over_widget = FALSE; /* We'll receive an enter_notify_event if the window appears under the cursor. */
/* Create rendering data if this is a re-realise */
......@@ -8586,32 +8496,7 @@ Terminal::widget_realize()
m_draw = _vte_draw_new();
}
// FIXMEchpe this shouldn't ever be true:
if (m_im_context != nullptr) {
g_signal_handlers_disconnect_matched(m_im_context, G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
this);
im_reset();
gtk_im_context_set_client_window(m_im_context, nullptr);
g_object_unref(m_im_context);
m_im_context = nullptr;
}
m_im_preedit_active = FALSE;
m_im_context = gtk_im_multicontext_new();
gtk_im_context_set_client_window(m_im_context, m_real_widget->event_window());
g_signal_connect(m_im_context, "commit",
G_CALLBACK(vte_terminal_im_commit_cb), this);
g_signal_connect(m_im_context, "preedit-start",
G_CALLBACK(vte_terminal_im_preedit_start_cb), this);
g_signal_connect(m_im_context, "preedit-changed",
G_CALLBACK(vte_terminal_im_preedit_changed_cb), this);
g_signal_connect(m_im_context, "preedit-end",
G_CALLBACK(vte_terminal_im_preedit_end_cb), this);
g_signal_connect(m_im_context, "retrieve-surrounding",
G_CALLBACK(vte_terminal_im_retrieve_surrounding_cb), this);
g_signal_connect(m_im_context, "delete-surrounding",
G_CALLBACK(vte_terminal_im_delete_surrounding_cb), this);
gtk_im_context_set_use_preedit(m_im_context, TRUE);
/* Clear modifiers. */
m_modifiers = 0;
......@@ -11385,13 +11270,13 @@ Terminal::set_input_enabled (bool enabled)
if (enabled) {
if (gtk_widget_has_focus(m_widget))
gtk_im_context_focus_in(m_im_context);
m_real_widget->im_focus_in();
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_READ_ONLY);
} else {
im_reset();
if (gtk_widget_has_focus(m_widget))
gtk_im_context_focus_out(m_im_context);
m_real_widget->im_focus_out();
disconnect_pty_write();
_vte_byte_array_clear(m_outgoing);
......
......@@ -319,6 +319,8 @@ vte_terminal_draw(GtkWidget *widget,
static void
vte_terminal_realize(GtkWidget *widget)
{
_vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_realize()\n");
GTK_WIDGET_CLASS(vte_terminal_parent_class)->realize(widget);
VteTerminal *terminal= VTE_TERMINAL(widget);
......@@ -328,6 +330,8 @@ vte_terminal_realize(GtkWidget *widget)
static void
vte_terminal_unrealize(GtkWidget *widget)
{
_vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_unrealize()\n");
VteTerminal *terminal = VTE_TERMINAL (widget);
WIDGET(terminal)->unrealize();
......
......@@ -565,8 +565,7 @@ public:
gboolean m_mouse_cursor_autohidden; /* whether the autohiding logic wants to hide it; even if autohiding is disabled via API */
/* Input method support. */
GtkIMContext *m_im_context;
gboolean m_im_preedit_active;
bool m_im_preedit_active;
std::string m_im_preedit;
PangoAttrList *m_im_preedit_attrs;
int m_im_preedit_cursor;
......@@ -853,9 +852,10 @@ public:
int status);
void im_commit(char const* text);
void im_preedit_start();
void im_preedit_end();
void im_preedit_changed();
void im_preedit_set_active(bool active) noexcept;
void im_preedit_changed(char const* str,
int cursorpos,
PangoAttrList* attrs) noexcept;
bool im_retrieve_surrounding();
bool im_delete_surrounding(int offset,
int n_chars);
......
......@@ -21,13 +21,67 @@
#include "widget.hh"
#include <new>
#include <string>
#include "debug.h"
using namespace std::literals;
namespace vte {
namespace platform {
static void
im_commit_cb(GtkIMContext* im_context,
char const* text,
Widget* that)
{
that->terminal()->im_commit(text);
}
static void
im_preedit_start_cb(GtkIMContext* im_context,
Widget* that)
{
_vte_debug_print(VTE_DEBUG_EVENTS, "Input method pre-edit started.\n");
that->terminal()->im_preedit_set_active(true);
}
static void
im_preedit_end_cb(GtkIMContext* im_context,
Widget* that)
{
_vte_debug_print(VTE_DEBUG_EVENTS, "Input method pre-edit ended.\n");
that->terminal()->im_preedit_set_active(false);
}
static void
im_preedit_changed_cb(GtkIMContext* im_context,
Widget* that)
{
that->im_preedit_changed();
}
static gboolean
im_retrieve_surrounding_cb(GtkIMContext* im_context,
Widget* that)
{
_vte_debug_print(VTE_DEBUG_EVENTS, "Input method retrieve-surrounding.\n");
return that->terminal()->im_retrieve_surrounding();
}
static gboolean
im_delete_surrounding_cb(GtkIMContext* im_context,
int offset,
int n_chars,
Widget* that)
{
_vte_debug_print(VTE_DEBUG_EVENTS,
"Input method delete-surrounding offset %d n-chars %d.\n",
offset, n_chars);
return that->terminal()->im_delete_surrounding(offset, n_chars);
}
Widget::Widget(VteTerminal* t) noexcept :
m_widget{&t->widget}
{
......@@ -50,8 +104,49 @@ Widget::create_cursor(GdkCursorType cursor_type) const noexcept
return gdk_cursor_new_for_display(gtk_widget_get_display(m_widget), cursor_type);
}
bool
Widget::im_filter_keypress(GdkEventKey* event) noexcept
{
// FIXMEchpe this can only be called when realized, so the m_im_context check is redundant
return m_im_context &&
gtk_im_context_filter_keypress(m_im_context.get(), event);
}
void
Widget::im_focus_in() noexcept
{
gtk_im_context_focus_in(m_im_context.get());
}
void
Widget::map()
Widget::im_focus_out() noexcept
{
gtk_im_context_focus_out(m_im_context.get());
}
void
Widget::im_preedit_changed() noexcept
{
char* str;
PangoAttrList* attrs;
int cursorpos;
gtk_im_context_get_preedit_string(m_im_context.get(), &str, &attrs, &cursorpos);
_vte_debug_print(VTE_DEBUG_EVENTS, "Input method pre-edit changed (%s,%d).\n",
str, cursorpos);
m_terminal->im_preedit_changed(str, cursorpos, attrs);
g_free(str);
}
void
Widget::im_set_cursor_location(cairo_rectangle_int_t const* rect) noexcept
{
gtk_im_context_set_cursor_location(m_im_context.get(), rect);
}
void
Widget::map() noexcept
{
if (m_event_window)
gdk_window_show_unraised(m_event_window);
......@@ -107,6 +202,23 @@ Widget::realize() noexcept
&attributes, attributes_mask);
gtk_widget_register_window(m_widget, m_event_window);
assert(!m_im_context);
m_im_context = gtk_im_multicontext_new();
gtk_im_context_set_client_window(m_im_context.get(), m_event_window);
g_signal_connect(m_im_context.get(), "commit",
G_CALLBACK(im_commit_cb), this);
g_signal_connect(m_im_context.get(), "preedit-start",
G_CALLBACK(im_preedit_start_cb), this);
g_signal_connect(m_im_context.get(), "preedit-changed",
G_CALLBACK(im_preedit_changed_cb), this);
g_signal_connect(m_im_context.get(), "preedit-end",
G_CALLBACK(im_preedit_end_cb), this);
g_signal_connect(m_im_context.get(), "retrieve-surrounding",
G_CALLBACK(im_retrieve_surrounding_cb), this);
g_signal_connect(m_im_context.get(), "delete-surrounding",
G_CALLBACK(im_delete_surrounding_cb), this);
gtk_im_context_set_use_preedit(m_im_context.get(), true);
m_terminal->widget_realize();
}
......@@ -151,6 +263,17 @@ Widget::unrealize() noexcept
m_mousing_cursor.reset();
m_hyperlink_cursor.reset();
/* Shut down input methods. */
assert(m_im_context);
g_signal_handlers_disconnect_matched(m_im_context.get(),
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
this);
m_terminal->im_preedit_changed("", 0, nullptr);
gtk_im_context_set_client_window(m_im_context.get(), nullptr);
m_im_context.reset();
/* Destroy input window */
gtk_widget_unregister_window(m_widget, m_event_window);
gdk_window_destroy(m_event_window);
m_event_window = nullptr;
......
......@@ -116,6 +116,22 @@ protected:
gdk_window_set_cursor(m_event_window, cursor);
}
bool im_filter_keypress(GdkEventKey* event) noexcept;
void im_focus_in() noexcept;
void im_focus_out() noexcept;
void im_reset() noexcept
{
if (m_im_context)
gtk_im_context_reset(m_im_context.get());
}
void im_set_cursor_location(cairo_rectangle_int_t const* rect) noexcept;
public: // FIXMEchpe
void im_preedit_changed() noexcept;
private:
GtkWidget* m_widget;
......@@ -129,6 +145,9 @@ private:
vte::glib::RefPtr<GdkCursor> m_invisible_cursor;
vte::glib::RefPtr<GdkCursor> m_mousing_cursor;
vte::glib::RefPtr<GdkCursor> m_hyperlink_cursor;
/* Input method */
vte::glib::RefPtr<GtkIMContext> m_im_context;
};
} // namespace platform
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment