Skip to content
Merged
9 changes: 9 additions & 0 deletions CodenameOne/src/com/codename1/ui/TextInputClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@
/// All offsets exchanged with the platform are UTF-16 character indices. All callbacks are delivered on
/// the EDT.
public interface TextInputClient {
/// Optional contract for clients that can restore a canceled composition, including rich text
/// attributes and undo state. Ports may restore text and selection for older clients; rich editors
/// should implement this contract to restore their complete pre-composition state.
interface CompositionCancellation {
/// Restores the text, selection and attributes from before composition without recording an
/// undo entry. Does nothing when no composition is active.
void cancelComposing();
}

/// Key command: move / extend to the left.
int KEY_LEFT = 1;
/// Key command: move / extend to the right.
Expand Down
25 changes: 24 additions & 1 deletion CodenameOne/src/com/codename1/ui/editor/EditorView.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
/// This class provides the shared editing behavior. Feature layers (syntax highlighting, the gutter,
/// styled rich text) subclass it and override `#paintContent(Graphics, int, int, int, int)` and the
/// document/measurement hooks.
public class EditorView extends Component implements TextInputClient, com.codename1.ui.TextInputGeometry.Provider {
public class EditorView extends Component implements TextInputClient, TextInputClient.CompositionCancellation, com.codename1.ui.TextInputGeometry.Provider {
private EditorHost host;
private final boolean codeMode;
private EditorDocument doc = new EditorDocument();
Expand All @@ -60,6 +60,8 @@ public class EditorView extends Component implements TextInputClient, com.codena
// pre-composition snapshot so the finalized composition forms a single undo unit
private String composingBaseRemoved;
private Object composingBeforeState;
private int composingBeforeCaret;
private int composingBeforeAnchor;
private boolean editable = true;

private int scrollY;
Expand Down Expand Up @@ -1900,6 +1902,8 @@ public void setComposingText(String text, int relativeCaret) {
// commitText / finishComposing; intermediate compose updates are never recorded
composingBaseRemoved = doc.substring(start, end);
composingBeforeState = captureDocumentState();
composingBeforeCaret = caret;
composingBeforeAnchor = anchor;
}
String removed = doc.substring(start, end);
doc.delete(start, end);
Expand All @@ -1924,6 +1928,25 @@ public void setComposingText(String text, int relativeCaret) {
}
}

@Override
public void cancelComposing() {
if (composingStart < 0) {
return;
}
Object before = composingBeforeState;
int oldCaret = composingBeforeCaret;
int oldAnchor = composingBeforeAnchor;
replaceRange(composingStart, composingEnd,
composingBaseRemoved == null ? "" : composingBaseRemoved, false);
restoreDocumentState(before);
caret = doc.clamp(oldCaret);
anchor = oldAnchor < 0 ? -1 : doc.clamp(oldAnchor);
invalidateLayout();
scrollCaretVisible();
pushInputState();
repaint();
}

@Override
public void finishComposing() {
if (composingStart >= 0) {
Expand Down
10 changes: 10 additions & 0 deletions Ports/LinuxPort/nativeSources/cn1_linux_desktopwindow.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ CN1Graphics* cn1LinuxDesktopGraphics(int slot) {
return &w->g;
}

GtkWidget* cn1LinuxDesktopDrawingArea(int slot) {
CN1LinuxWindow* w = slotAt(slot);
return w == 0 ? 0 : w->drawingArea;
}

GtkWidget* cn1LinuxDesktopWidget(int slot) {
CN1LinuxWindow* w = slotAt(slot);
return w == 0 ? 0 : w->window;
Expand Down Expand Up @@ -432,6 +437,9 @@ static gboolean cn1DesktopOnKey(GtkWidget* widget, GdkEventKey* e, gpointer data
return FALSE;
}
}
if (cn1LinuxTextInputFilter((int) (w - cn1DesktopWindows), e)) {
return TRUE;
}
/* Same mapping the main window uses: GDK encodes many Unicode keyvals
* differently from their code point, so a raw keyval gives the wrong key code
* for anything outside ASCII. Navigation keys have no Unicode mapping and fall
Expand Down Expand Up @@ -730,6 +738,8 @@ static void cn1DesktopCreateOnMain(void* arg) {

gtk_container_add(GTK_CONTAINER(w->overlay), w->drawingArea);
gtk_overlay_add_overlay(GTK_OVERLAY(w->overlay), w->fixed);
/* Empty peer-layer space must reach the canvas, as in the main window. */
gtk_overlay_set_overlay_pass_through(GTK_OVERLAY(w->overlay), w->fixed, TRUE);
gtk_container_add(GTK_CONTAINER(w->window), w->overlay);

gtk_widget_add_events(w->drawingArea,
Expand Down
3 changes: 2 additions & 1 deletion Ports/LinuxPort/nativeSources/cn1_linux_edit.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ JAVA_OBJECT com_codename1_impl_linux_LinuxNative_editGetText___long_R_java_lang_
return JAVA_NULL;
}
pthread_mutex_lock(&e->lock);
result = newStringFromCString(threadStateData, e->text ? e->text : "");
result = newStringFromUtf8Len(threadStateData, e->text ? e->text : "",
e->text ? (int) strlen(e->text) : 0);
pthread_mutex_unlock(&e->lock);
return result;
}
Expand Down
3 changes: 3 additions & 0 deletions Ports/LinuxPort/nativeSources/cn1_linux_gfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ void cn1LinuxOverlayRemove(int slot, GtkWidget* w);

/* The top-level GtkWindow (NULL in headless mode). */
GtkWidget* cn1LinuxWindowWidget(void);
GtkWidget* cn1LinuxTextCanvas(int slot);
GtkWidget* cn1LinuxDesktopDrawingArea(int slot);
gboolean cn1LinuxTextInputFilter(int slot, GdkEventKey* event);

/* Additional desktop windows (cn1_linux_desktopwindow.c). A secondary window
* carries its own GtkWindow, drawing area, peer overlay and cairo back buffer;
Expand Down
2 changes: 1 addition & 1 deletion Ports/LinuxPort/nativeSources/cn1_linux_services.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ JAVA_OBJECT com_codename1_impl_linux_LinuxNative_clipboardGetText___R_java_lang_
JAVA_OBJECT result;
r.text = NULL;
cn1LinuxRunOnMainAndWait(cn1ClipGetTextOnMain, &r);
result = r.text ? newStringFromCString(threadStateData, r.text) : JAVA_NULL;
result = r.text ? newStringFromUtf8Len(threadStateData, r.text, (int) strlen(r.text)) : JAVA_NULL;
if (r.text) {
g_free(r.text);
}
Expand Down
Loading
Loading