mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-22 12:12:35 +03:00
GTK: add some support for input methods.
We do not currently support pre-edit texts, or retrieving/modifying text surrounding the caret. This does, at least, finally allow the use of dead keys during text input, but probably is insufficient for useful input of CJKV &c.
This commit is contained in:
parent
c47a497bca
commit
b928095652
@ -35,12 +35,14 @@
|
||||
#include "gtk/plotters.h"
|
||||
#include "gtk/treeview.h"
|
||||
#include "utils/log.h"
|
||||
#include "utils/utf8.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
struct nsgtk_treeview {
|
||||
GtkWindow *window;
|
||||
GtkScrolledWindow *scrolled;
|
||||
GtkDrawingArea *drawing_area;
|
||||
GtkIMContext *input_method;
|
||||
bool mouse_pressed;
|
||||
int mouse_pressed_x;
|
||||
int mouse_pressed_y;
|
||||
@ -52,6 +54,7 @@ struct nsgtk_treeview {
|
||||
void nsgtk_treeview_destroy(struct nsgtk_treeview *tv)
|
||||
{
|
||||
tree_delete(tv->tree);
|
||||
g_object_unref(tv->input_method);
|
||||
gtk_widget_destroy(GTK_WIDGET(tv->window));
|
||||
free(tv);
|
||||
}
|
||||
@ -206,12 +209,14 @@ void nsgtk_tree_window_hide(GtkWidget *widget, gpointer g)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean nsgtk_tree_window_button_press_event(GtkWidget *widget,
|
||||
static gboolean
|
||||
nsgtk_tree_window_button_press_event(GtkWidget *widget,
|
||||
GdkEventButton *event, gpointer g)
|
||||
{
|
||||
struct nsgtk_treeview *tw = g;
|
||||
struct tree *tree = tw->tree;
|
||||
|
||||
gtk_im_context_reset(tw->input_method);
|
||||
gtk_widget_grab_focus(GTK_WIDGET(tw->drawing_area));
|
||||
|
||||
tw->mouse_pressed = true;
|
||||
@ -243,7 +248,8 @@ gboolean nsgtk_tree_window_button_press_event(GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean nsgtk_tree_window_button_release_event(GtkWidget *widget,
|
||||
static gboolean
|
||||
nsgtk_tree_window_button_release_event(GtkWidget *widget,
|
||||
GdkEventButton *event, gpointer g)
|
||||
{
|
||||
bool shift = event->state & GDK_SHIFT_MASK;
|
||||
@ -307,7 +313,8 @@ gboolean nsgtk_tree_window_button_release_event(GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean nsgtk_tree_window_motion_notify_event(GtkWidget *widget,
|
||||
static gboolean
|
||||
nsgtk_tree_window_motion_notify_event(GtkWidget *widget,
|
||||
GdkEventMotion *event, gpointer g)
|
||||
{
|
||||
bool shift = event->state & GDK_SHIFT_MASK;
|
||||
@ -369,7 +376,8 @@ gboolean nsgtk_tree_window_motion_notify_event(GtkWidget *widget,
|
||||
}
|
||||
|
||||
|
||||
gboolean nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event,
|
||||
static gboolean
|
||||
nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer g)
|
||||
{
|
||||
struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g;
|
||||
@ -381,6 +389,9 @@ gboolean nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event,
|
||||
GtkAdjustment *scroll = NULL;
|
||||
gdouble hpage, vpage;
|
||||
|
||||
if (gtk_im_context_filter_keypress(tw->input_method, event))
|
||||
return TRUE;
|
||||
|
||||
nskey = gtk_gui_gdkkey_to_nskey(event);
|
||||
|
||||
if (tree_keypress(tree, nskey) == true)
|
||||
@ -473,6 +484,32 @@ gboolean nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
nsgtk_tree_window_keyrelease_event(GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer g)
|
||||
{
|
||||
struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g;
|
||||
|
||||
return gtk_im_context_filter_keypress(tw->input_method, event);
|
||||
}
|
||||
|
||||
static void
|
||||
nsgtk_tree_window_input_method_commit(GtkIMContext *ctx,
|
||||
const gchar *str, gpointer data)
|
||||
{
|
||||
struct nsgtk_treeview *tw = (struct nsgtk_treeview *) data;
|
||||
size_t len = strlen(str), offset = 0;
|
||||
|
||||
while (offset < len) {
|
||||
uint32_t nskey = utf8_to_ucs4(str + offset, len - offset);
|
||||
|
||||
tree_keypress(tw->tree, nskey);
|
||||
|
||||
offset = utf8_next(str, len, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const struct treeview_table nsgtk_tree_callbacks = {
|
||||
.redraw_request = nsgtk_tree_redraw_request,
|
||||
.resized = nsgtk_tree_resized,
|
||||
@ -498,6 +535,7 @@ struct nsgtk_treeview *nsgtk_treeview_create(unsigned int flags,
|
||||
tv->window = window;
|
||||
tv->scrolled = scrolled;
|
||||
tv->drawing_area = drawing_area;
|
||||
tv->input_method = gtk_im_multicontext_new();
|
||||
tv->tree = tree_create(flags, &nsgtk_tree_callbacks, tv);
|
||||
tv->mouse_state = 0;
|
||||
tv->mouse_pressed = false;
|
||||
@ -510,17 +548,31 @@ struct nsgtk_treeview *nsgtk_treeview_create(unsigned int flags,
|
||||
|
||||
#define CONNECT(obj, sig, callback, ptr) \
|
||||
g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
|
||||
CONNECT(drawing_area, "button_press_event",
|
||||
CONNECT(drawing_area, "button-press-event",
|
||||
nsgtk_tree_window_button_press_event,
|
||||
tv);
|
||||
CONNECT(drawing_area, "button_release_event",
|
||||
CONNECT(drawing_area, "button-release-event",
|
||||
nsgtk_tree_window_button_release_event,
|
||||
tv);
|
||||
CONNECT(drawing_area, "motion_notify_event",
|
||||
CONNECT(drawing_area, "motion-notify-event",
|
||||
nsgtk_tree_window_motion_notify_event,
|
||||
tv);
|
||||
CONNECT(drawing_area, "key_press_event",
|
||||
CONNECT(drawing_area, "key-press-event",
|
||||
nsgtk_tree_window_keypress_event,
|
||||
tv);
|
||||
CONNECT(drawing_area, "key-release-event",
|
||||
nsgtk_tree_window_keyrelease_event,
|
||||
tv);
|
||||
|
||||
|
||||
/* input method */
|
||||
gtk_im_context_set_client_window(tv->input_method,
|
||||
nsgtk_widget_get_window(GTK_WIDGET(tv->window)));
|
||||
gtk_im_context_set_use_preedit(tv->input_method, FALSE);
|
||||
/* input method signals */
|
||||
CONNECT(tv->input_method, "commit",
|
||||
nsgtk_tree_window_input_method_commit,
|
||||
tv);
|
||||
|
||||
return tv;
|
||||
}
|
||||
|
@ -33,16 +33,6 @@ void nsgtk_treeview_destroy(struct nsgtk_treeview *tv);
|
||||
|
||||
struct tree *nsgtk_treeview_get_tree(struct nsgtk_treeview *tv);
|
||||
|
||||
gboolean nsgtk_tree_window_expose_event(GtkWidget *, GdkEventExpose *,
|
||||
gpointer g);
|
||||
void nsgtk_tree_window_hide(GtkWidget *widget, gpointer g);
|
||||
gboolean nsgtk_tree_window_button_press_event(GtkWidget *widget,
|
||||
GdkEventButton *event, gpointer g);
|
||||
gboolean nsgtk_tree_window_button_release_event(GtkWidget *widget,
|
||||
GdkEventButton *event, gpointer g);
|
||||
gboolean nsgtk_tree_window_motion_notify_event(GtkWidget *widget,
|
||||
GdkEventMotion *event, gpointer g);
|
||||
gboolean nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event,
|
||||
gpointer g);
|
||||
|
||||
#endif /*__NSGTK_TREEVIEW_H__*/
|
||||
|
50
gtk/window.c
50
gtk/window.c
@ -27,6 +27,7 @@
|
||||
#include <gdk-pixbuf/gdk-pixdata.h>
|
||||
|
||||
#include "utils/log.h"
|
||||
#include "utils/utf8.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/nsoption.h"
|
||||
#include "content/hlcache.h"
|
||||
@ -105,6 +106,9 @@ struct gui_window {
|
||||
/** The icon this window should have */
|
||||
GdkPixbuf *icon;
|
||||
|
||||
/** The input method to use with this window */
|
||||
GtkIMContext *input_method;
|
||||
|
||||
/** list for cleanup */
|
||||
struct gui_window *next, *prev;
|
||||
};
|
||||
@ -315,6 +319,7 @@ static gboolean nsgtk_window_button_press_event(GtkWidget *widget,
|
||||
{
|
||||
struct gui_window *g = data;
|
||||
|
||||
gtk_im_context_reset(g->input_method);
|
||||
gtk_widget_grab_focus(GTK_WIDGET(g->layout));
|
||||
gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window(
|
||||
g->scaffold)->window));
|
||||
@ -490,7 +495,12 @@ static gboolean nsgtk_window_keypress_event(GtkWidget *widget,
|
||||
GdkEventKey *event, gpointer data)
|
||||
{
|
||||
struct gui_window *g = data;
|
||||
uint32_t nskey = gtk_gui_gdkkey_to_nskey(event);
|
||||
uint32_t nskey;
|
||||
|
||||
if (gtk_im_context_filter_keypress(g->input_method, event))
|
||||
return TRUE;
|
||||
|
||||
nskey = gtk_gui_gdkkey_to_nskey(event);
|
||||
|
||||
if (browser_window_key_press(g->bw, nskey))
|
||||
return TRUE;
|
||||
@ -598,6 +608,31 @@ static gboolean nsgtk_window_keypress_event(GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean nsgtk_window_keyrelease_event(GtkWidget *widget,
|
||||
GdkEventKey *event, gpointer data)
|
||||
{
|
||||
struct gui_window *g = data;
|
||||
|
||||
return gtk_im_context_filter_keypress(g->input_method, event);
|
||||
}
|
||||
|
||||
|
||||
static void nsgtk_window_input_method_commit(GtkIMContext *ctx,
|
||||
const gchar *str, gpointer data)
|
||||
{
|
||||
struct gui_window *g = data;
|
||||
size_t len = strlen(str), offset = 0;
|
||||
|
||||
while (offset < len) {
|
||||
uint32_t nskey = utf8_to_ucs4(str + offset, len - offset);
|
||||
|
||||
browser_window_key_press(g->bw, nskey);
|
||||
|
||||
offset = utf8_next(str, len, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean nsgtk_window_size_allocate_event(GtkWidget *widget,
|
||||
GtkAllocation *allocation, gpointer data)
|
||||
{
|
||||
@ -658,6 +693,8 @@ static void window_destroy(GtkWidget *widget, gpointer data)
|
||||
struct gui_window *gw = data;
|
||||
|
||||
browser_window_destroy(gw->bw);
|
||||
|
||||
g_object_unref(gw->input_method);
|
||||
}
|
||||
|
||||
/* Core interface documented in desktop/gui.h to create a gui_window */
|
||||
@ -720,6 +757,7 @@ gui_window_create(struct browser_window *bw,
|
||||
g->layout = GTK_LAYOUT(gtk_builder_get_object(xml, "layout"));
|
||||
g->status_bar = GTK_LABEL(gtk_builder_get_object(xml, "status_bar"));
|
||||
g->paned = GTK_PANED(gtk_builder_get_object(xml, "hpaned1"));
|
||||
g->input_method = gtk_im_multicontext_new();
|
||||
|
||||
|
||||
/* add new gui window to global list (push_top) */
|
||||
@ -763,6 +801,8 @@ gui_window_create(struct browser_window *bw,
|
||||
nsgtk_window_button_release_event, g);
|
||||
CONNECT(g->layout, "key-press-event",
|
||||
nsgtk_window_keypress_event, g);
|
||||
CONNECT(g->layout, "key-release-event",
|
||||
nsgtk_window_keyrelease_event, g);
|
||||
CONNECT(g->layout, "size-allocate",
|
||||
nsgtk_window_size_allocate_event, g);
|
||||
CONNECT(g->layout, "scroll-event",
|
||||
@ -779,6 +819,14 @@ gui_window_create(struct browser_window *bw,
|
||||
CONNECT(g->container, "destroy",
|
||||
window_destroy, g);
|
||||
|
||||
/* input method */
|
||||
gtk_im_context_set_client_window(g->input_method,
|
||||
nsgtk_layout_get_bin_window(g->layout));
|
||||
gtk_im_context_set_use_preedit(g->input_method, FALSE);
|
||||
/* input method signals */
|
||||
CONNECT(g->input_method, "commit",
|
||||
nsgtk_window_input_method_commit, g);
|
||||
|
||||
/* add the tab container to the scaffold notebook */
|
||||
switch (temp_open_background) {
|
||||
case -1:
|
||||
|
Loading…
Reference in New Issue
Block a user