Merge lp:~unity-team/unity/unity.text-entry-im into lp:unity

Proposed by Brandon Schaefer
Status: Merged
Approved by: Tim Penhey
Approved revision: no longer in the source branch.
Merged at revision: 2011
Proposed branch: lp:~unity-team/unity/unity.text-entry-im
Merge into: lp:unity
Diff against target: 377 lines (+27/-251)
3 files modified
plugins/unityshell/src/DashController.cpp (+2/-0)
plugins/unityshell/src/IMTextEntry.cpp (+24/-221)
plugins/unityshell/src/IMTextEntry.h (+1/-30)
To merge this branch: bzr merge lp:~unity-team/unity/unity.text-entry-im
Reviewer Review Type Date Requested Status
Marco Trevisan (Treviño) Needs Fixing
Tim Penhey (community) Approve
Jay Taoko (community) Approve
Thomi Richards (community) Approve
Review via email: mp+94305@code.launchpad.net

Commit message

IMTextEntry now only handles copy/cut and pasting, everything else is in nux::TextEntry

To post a comment you must log in.
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

I've had a look through this, and it looks good to me.

review: Approve
Revision history for this message
Jay Taoko (jaytaoko) wrote :

Approved!

review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/333/console reported an error when processing this lp:~unity-team/unity/unity.text-entry-im branch.
Not merging it.

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

-- checking for modules 'compiz;nux-2.0>=2.0.0;libbamf3;dee-1.0;gio-2.0;gio-unix-2.0;dbusmenu-glib-0.4;x11;libstartup-notification-1.0;gthread-2.0;indicator3-0.4;atk;unity-misc>=0.4.0;gconf-2.0;libutouch-geis;gtk+-3.0>=3.1;sigc++-2.0;json-glib-1.0;libnotify;gnome-desktop-3.0;gdu;ibus-1.0;unity>=4.99.0'
-- package 'ibus-1.0' not found

Hmm I thought "libibus-1.0-dev" had been added to unity

Revision history for this message
Tim Penhey (thumper) wrote :

Changes look good, lets try it.

review: Approve
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :
review: Needs Fixing
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Sorry, I must have missed that while deleting everything! Here is the fix again:
https://code.launchpad.net/~brandontschaefer/unity/unity.fix-middle-paste-reg/+merge/94441

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/unityshell/src/DashController.cpp'
--- plugins/unityshell/src/DashController.cpp 2012-02-15 10:54:48 +0000
+++ plugins/unityshell/src/DashController.cpp 2012-02-23 10:16:31 +0000
@@ -278,6 +278,8 @@
278 window_->EnableInputWindow(false, "Dash", true, false);278 window_->EnableInputWindow(false, "Dash", true, false);
279 visible_ = false;279 visible_ = false;
280280
281 nux::GetWindowCompositor().SetKeyFocusArea(NULL,nux::KEY_NAV_NONE);
282
281 if (restore)283 if (restore)
282 PluginAdapter::Default ()->restoreInputFocus ();284 PluginAdapter::Default ()->restoreInputFocus ();
283285
284286
=== modified file 'plugins/unityshell/src/IMTextEntry.cpp'
--- plugins/unityshell/src/IMTextEntry.cpp 2012-02-23 08:55:35 +0000
+++ plugins/unityshell/src/IMTextEntry.cpp 2012-02-23 10:16:31 +0000
@@ -21,7 +21,6 @@
2121
22#include "IMTextEntry.h"22#include "IMTextEntry.h"
2323
24#include <boost/lexical_cast.hpp>
25#include <NuxCore/Logger.h>24#include <NuxCore/Logger.h>
26#include <UnityCore/GLibWrapper.h>25#include <UnityCore/GLibWrapper.h>
2726
@@ -36,127 +35,20 @@
36NUX_IMPLEMENT_OBJECT_TYPE(IMTextEntry);35NUX_IMPLEMENT_OBJECT_TYPE(IMTextEntry);
3736
38IMTextEntry::IMTextEntry()37IMTextEntry::IMTextEntry()
39 : TextEntry("", "", 80085)38 : TextEntry("", NUX_TRACKER_LOCATION)
40 , preedit_string("")39{
41 , im_enabled(false)
42 , im_active(false)
43 , focused_(false)
44{
45 g_setenv("IBUS_ENABLE_SYNC_MODE", "1", TRUE);
46 CheckIMEnabled();
47 im_enabled ? SetupMultiIM() : SetupSimpleIM();
48
49 key_nav_focus_change.connect([&](nux::Area* area, bool focus, nux::KeyNavDirection dir)
50 {
51 focus ? OnFocusIn() : OnFocusOut();
52 });
53 mouse_up.connect(sigc::mem_fun(this, &IMTextEntry::OnMouseButtonUp));
54}
55
56void IMTextEntry::CheckIMEnabled()
57{
58 const char* module = g_getenv("GTK_IM_MODULE");
59 if (module &&
60 g_strcmp0(module, "") &&
61 g_strcmp0(module, "gtk-im-context-simple"))
62 im_enabled = true;
63
64 LOG_DEBUG(logger) << "Input method support is "
65 << (im_enabled ? "enabled" : "disabled");
66}
67
68void IMTextEntry::SetupSimpleIM()
69{
70 im_context_ = gtk_im_context_simple_new();
71
72 sig_manager_.Add(new Signal<void, GtkIMContext*, char*>(im_context_, "commit", sigc::mem_fun(this, &IMTextEntry::OnCommit)));
73 sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-changed", sigc::mem_fun(this, &IMTextEntry::OnPreeditChanged)));
74 sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-start", sigc::mem_fun(this, &IMTextEntry::OnPreeditStart)));
75 sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-end", sigc::mem_fun(this, &IMTextEntry::OnPreeditEnd)));
76}
77
78void IMTextEntry::SetupMultiIM()
79{
80 im_context_ = gtk_im_multicontext_new();
81
82 sig_manager_.Add(new Signal<void, GtkIMContext*, char*>(im_context_, "commit", sigc::mem_fun(this, &IMTextEntry::OnCommit)));
83 sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-changed", sigc::mem_fun(this, &IMTextEntry::OnPreeditChanged)));
84 sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-start", sigc::mem_fun(this, &IMTextEntry::OnPreeditStart)));
85 sig_manager_.Add(new Signal<void, GtkIMContext*>(im_context_, "preedit-end", sigc::mem_fun(this, &IMTextEntry::OnPreeditEnd)));
86}40}
8741
88bool IMTextEntry::InspectKeyEvent(unsigned int event_type,42bool IMTextEntry::InspectKeyEvent(unsigned int event_type,
89 unsigned int keysym,43 unsigned int keysym,
90 const char* character)44 const char* character)
91{45{
92 bool propagate_event = !(TryHandleEvent(event_type, keysym, character));46 bool need_to_filter_event = TryHandleSpecial(event_type, keysym, character);
9347
94 LOG_DEBUG(logger) << "Input method "48 if (need_to_filter_event)
95 << (im_enabled ? gtk_im_multicontext_get_context_id(glib::object_cast<GtkIMMulticontext>(im_context_)) : "simple")49 need_to_filter_event = TextEntry::InspectKeyEvent(event_type, keysym, character);
96 << " "50
97 << (propagate_event ? "did not handle " : "handled ") 51 return need_to_filter_event;
98 << "event ("
99 << (event_type == NUX_KEYDOWN ? "press" : "release")
100 << ") ";
101
102 if (propagate_event)
103 propagate_event = !TryHandleSpecial(event_type, keysym, character);
104
105 if (propagate_event)
106 {
107 text_input_mode_ = event_type == NUX_KEYDOWN;
108 propagate_event = TextEntry::InspectKeyEvent(event_type, keysym, character);
109 text_input_mode_ = false;
110
111 UpdateCursorLocation();
112 }
113 return propagate_event;
114}
115
116bool IMTextEntry::TryHandleEvent(unsigned int eventType,
117 unsigned int keysym,
118 const char* character)
119{
120 nux::Event event = nux::GetWindowThread()->GetGraphicsDisplay().GetCurrentEvent();
121
122 CheckValidClientWindow(event.x11_window);
123
124 GdkEventKey ev;
125 KeyEventToGdkEventKey(event, ev);
126
127 return gtk_im_context_filter_keypress(im_context_, &ev);
128}
129
130inline void IMTextEntry::CheckValidClientWindow(Window window)
131{
132 if (!client_window_)
133 {
134 client_window_ = gdk_x11_window_foreign_new_for_display(gdk_display_get_default(), window);
135 gtk_im_context_set_client_window(im_context_, client_window_);
136
137 if (focused_)
138 {
139 gtk_im_context_focus_in(im_context_);
140 }
141 }
142}
143
144void IMTextEntry::KeyEventToGdkEventKey(Event& event, GdkEventKey& gdk_event)
145{
146 gdk_event.type = event.type == nux::NUX_KEYDOWN ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
147 gdk_event.window = client_window_;
148 gdk_event.send_event = FALSE;
149 gdk_event.time = event.x11_timestamp;
150 gdk_event.state = event.x11_key_state;
151 gdk_event.keyval = event.x11_keysym;
152
153 gchar* txt = const_cast<gchar*>(event.GetText());
154 gdk_event.length = strlen(txt);
155 gdk_event.string = txt;
156
157 gdk_event.hardware_keycode = event.x11_keycode;
158 gdk_event.group = 0;
159 gdk_event.is_modifier = 0;
160}52}
16153
162bool IMTextEntry::TryHandleSpecial(unsigned int eventType, unsigned int keysym, const char* character)54bool IMTextEntry::TryHandleSpecial(unsigned int eventType, unsigned int keysym, const char* character)
@@ -166,13 +58,14 @@
166 bool shift = (event.GetKeyState() & NUX_STATE_SHIFT);58 bool shift = (event.GetKeyState() & NUX_STATE_SHIFT);
167 bool ctrl = (event.GetKeyState() & NUX_STATE_CTRL);59 bool ctrl = (event.GetKeyState() & NUX_STATE_CTRL);
16860
61 /* If there is preedit, handle the event else where, but we
62 want to be able to copy/paste while ibus is active */
63 if (!preedit_.empty())
64 return true;
65
169 if (eventType != NUX_KEYDOWN)66 if (eventType != NUX_KEYDOWN)
170 return false;67 return false;
17168
172 /* If IM is active, de-activate Copy & Paste */
173 if (im_active)
174 return true;
175
176 if (((keyval == NUX_VK_x) && ctrl && !shift) ||69 if (((keyval == NUX_VK_x) && ctrl && !shift) ||
177 ((keyval == NUX_VK_DELETE) && shift && !ctrl))70 ((keyval == NUX_VK_DELETE) && shift && !ctrl))
178 {71 {
@@ -194,15 +87,16 @@
194 }87 }
195 else88 else
196 {89 {
197 return false;90 return true;
198 }91 }
199 return true;92 return false;
200}93}
20194
202void IMTextEntry::Cut()95void IMTextEntry::Cut()
203{96{
204 Copy();97 Copy();
205 DeleteSelection();98 DeleteSelection();
99 QueueRefresh (true, true);
206}100}
207101
208void IMTextEntry::Copy()102void IMTextEntry::Copy()
@@ -221,122 +115,31 @@
221 GdkAtom origin = primary ? GDK_SELECTION_PRIMARY : GDK_SELECTION_CLIPBOARD;115 GdkAtom origin = primary ? GDK_SELECTION_PRIMARY : GDK_SELECTION_CLIPBOARD;
222 glib::Object<GtkClipboard> clip(gtk_clipboard_get_for_display(gdk_display_get_default(),116 glib::Object<GtkClipboard> clip(gtk_clipboard_get_for_display(gdk_display_get_default(),
223 origin));117 origin));
118
224 auto callback = [](GtkClipboard* clip, const char* text, gpointer user_data)119 auto callback = [](GtkClipboard* clip, const char* text, gpointer user_data)
225 {120 {
226 IMTextEntry* self = static_cast<IMTextEntry*>(user_data);121 IMTextEntry* self = static_cast<IMTextEntry*>(user_data);
227 if (text)122 if (text)
228 self->InsertTextAt(self->cursor_, std::string(text));123 self->InsertText(std::string(text));
229 };124 };
230125
231 gtk_clipboard_request_text(clip, callback, this);126 gtk_clipboard_request_text(clip, callback, this);
232}127}
233128
234void IMTextEntry::InsertTextAt(unsigned int position, std::string const& text)129void IMTextEntry::InsertText(std::string const& text)
235{130{
236 DeleteSelection();131 DeleteSelection();
237132
238 if (!text.empty())133 if (!text.empty())
239 {134 {
240 std::string new_text(GetText());135 std::string new_text(GetText());
241 new_text.insert(position, text);136 new_text.insert(cursor_, text);
242137
243 int cursor = position;138 int cursor = cursor_;
244 SetText(new_text.c_str());139 SetText(new_text.c_str());
245 SetCursor(cursor + text.length());140 SetCursor(cursor + text.length());
246 UpdateCursorLocation();141 QueueRefresh (true, true);
247 }
248}
249
250void IMTextEntry::OnCommit(GtkIMContext* context, char* str)
251{
252 LOG_DEBUG(logger) << "Commit: " << str;
253 DeleteSelection();
254
255 if (str)
256 {
257 InsertTextAt(cursor_, std::string(str));
258 }
259}
260
261void IMTextEntry::OnPreeditChanged(GtkIMContext* context)
262{
263 glib::String preedit;
264 int cursor_pos = -1;
265
266 gtk_im_context_get_preedit_string(context, &preedit, &preedit_attrs_, &cursor_pos);
267
268 LOG_DEBUG(logger) << "Preedit changed: " << preedit;
269
270 preedit_ = preedit.Str();
271
272 if (!preedit.Str().empty()) {
273 preedit_cursor_ = preedit.Str().length();
274 QueueRefresh(true, true);
275 text_changed.emit(this);142 text_changed.emit(this);
276 UpdateCursorLocation();143 }
277 }144}
278}
279
280void IMTextEntry::OnPreeditStart(GtkIMContext* context)
281{
282 im_active = true;
283
284 LOG_DEBUG(logger) << "Preedit start";
285}
286
287void IMTextEntry::OnPreeditEnd(GtkIMContext* context)
288{
289 im_active = false;
290 ResetPreedit();
291 gtk_im_context_reset(im_context_);
292
293 QueueRefresh(true, true);
294 text_changed.emit(this);
295
296 LOG_DEBUG(logger) << "Preedit ended";
297}
298
299void IMTextEntry::OnFocusIn()
300{
301 focused_ = true;
302 gtk_im_context_focus_in(im_context_);
303 gtk_im_context_reset(im_context_);
304 UpdateCursorLocation();
305}
306
307void IMTextEntry::OnFocusOut()
308{
309 focused_ = false;
310 gtk_im_context_focus_out(im_context_);
311}
312
313void IMTextEntry::UpdateCursorLocation()
314{
315 nux::Rect strong, weak;
316 GetCursorRects(&strong, &weak);
317 nux::Geometry geo = GetGeometry();
318
319 GdkRectangle area = { strong.x + geo.x, strong.y + geo.y, strong.width, strong.height };
320 gtk_im_context_set_cursor_location(im_context_, &area);
321}
322
323void IMTextEntry::OnMouseButtonUp(int x, int y, unsigned long bflags, unsigned long kflags)
324{
325 int button = nux::GetEventButton(bflags);
326
327 if (im_enabled && button == 3)
328 {
329 GtkWidget* menu = gtk_menu_new();
330 gtk_im_multicontext_append_menuitems(glib::object_cast<GtkIMMulticontext>(im_context_),
331 GTK_MENU_SHELL(menu));
332 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, GDK_CURRENT_TIME);
333 }
334 else if (button == 2)
335 {
336 SetCursor(XYToTextIndex(x, y));
337 UpdateCursorLocation();
338 Paste(true);
339 }
340}
341
342}145}
343146
=== modified file 'plugins/unityshell/src/IMTextEntry.h'
--- plugins/unityshell/src/IMTextEntry.h 2012-02-13 09:49:45 +0000
+++ plugins/unityshell/src/IMTextEntry.h 2012-02-23 10:16:31 +0000
@@ -40,42 +40,13 @@
40public:40public:
41 IMTextEntry();41 IMTextEntry();
4242
43 nux::Property<std::string> preedit_string;
44 nux::Property<bool> im_enabled;
45 nux::Property<bool> im_active;
46
47private:43private:
48 void CheckIMEnabled();
49 void SetupSimpleIM();
50 void SetupMultiIM();
51
52 bool InspectKeyEvent(unsigned int eventType, unsigned int keysym, const char* character);44 bool InspectKeyEvent(unsigned int eventType, unsigned int keysym, const char* character);
53 bool TryHandleEvent(unsigned int eventType, unsigned int keysym, const char* character);
54 void KeyEventToGdkEventKey(Event& event, GdkEventKey& gdk_event);
55 inline void CheckValidClientWindow(Window window);
56 bool TryHandleSpecial(unsigned int eventType, unsigned int keysym, const char* character);45 bool TryHandleSpecial(unsigned int eventType, unsigned int keysym, const char* character);
57 void InsertTextAt(unsigned int position, std::string const& text);46 void InsertText(std::string const& text);
58 void Cut();47 void Cut();
59 void Copy();48 void Copy();
60 void Paste(bool primary = false);49 void Paste(bool primary = false);
61
62 void OnCommit(GtkIMContext* context, char* str);
63 void OnPreeditChanged(GtkIMContext* context);
64 void OnPreeditStart(GtkIMContext* context);
65 void OnPreeditEnd(GtkIMContext* context);
66
67 void OnFocusIn();
68 void OnFocusOut();
69
70 void UpdateCursorLocation();
71
72 void OnMouseButtonUp(int x, int y, unsigned long bflags, unsigned long kflags);
73
74 private:
75 glib::SignalManager sig_manager_;
76 glib::Object<GtkIMContext> im_context_;
77 glib::Object<GdkWindow> client_window_;
78 bool focused_;
79};50};
8051
81}52}