mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-23 12:36:51 +03:00
c105738fa3
This changes the LOG macro to be varadic removing the need for all callsites to have double bracketing and allows for future improvement on how we use the logging macros. The callsites were changed with coccinelle and the changes checked by hand. Compile tested for several frontends but not all. A formatting annotation has also been added which allows the compiler to check the parameters and types passed to the logging.
586 lines
16 KiB
C
586 lines
16 KiB
C
/*
|
|
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
|
|
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
|
|
*
|
|
* This file is part of NetSurf, http://www.netsurf-browser.org/
|
|
*
|
|
* NetSurf is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* NetSurf is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/** \file
|
|
* Generic tree handling (implementation).
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
#include "utils/log.h"
|
|
#include "utils/utf8.h"
|
|
#include "utils/utils.h"
|
|
#include "desktop/tree.h"
|
|
#include "desktop/plotters.h"
|
|
|
|
#include "gtk/compat.h"
|
|
#include "gtk/gui.h"
|
|
#include "gtk/plotters.h"
|
|
#include "gtk/treeview.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;
|
|
int last_x, last_y;
|
|
browser_mouse_state mouse_state;
|
|
struct tree *tree;
|
|
};
|
|
|
|
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);
|
|
}
|
|
|
|
struct tree *nsgtk_treeview_get_tree(struct nsgtk_treeview *tv)
|
|
{
|
|
return tv->tree;
|
|
}
|
|
|
|
static void nsgtk_tree_redraw_request(int x, int y, int width, int height, void *data)
|
|
{
|
|
struct nsgtk_treeview *tw = data;
|
|
|
|
gtk_widget_queue_draw_area(GTK_WIDGET(tw->drawing_area),
|
|
x, y, width, height);
|
|
}
|
|
|
|
|
|
/**
|
|
* Updates the tree owner following a tree resize
|
|
*
|
|
* \param tree the tree to update the owner of
|
|
* \param width The width to resize to.
|
|
* \param height The height to resize to.
|
|
* \param data The treeview resize.
|
|
*/
|
|
static void nsgtk_tree_resized(struct tree *tree, int width, int height, void *data)
|
|
{
|
|
struct nsgtk_treeview *tw = data;
|
|
|
|
gtk_widget_set_size_request(GTK_WIDGET(tw->drawing_area),
|
|
width, height);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Scrolls the tree to make an element visible
|
|
*
|
|
* \param y Y coordinate of the element
|
|
* \param height height of the element
|
|
* \param data user data assigned to the tree on tree creation
|
|
*/
|
|
static void nsgtk_tree_scroll_visible(int y, int height, void *data)
|
|
{
|
|
int y0, y1;
|
|
gdouble page;
|
|
struct nsgtk_treeview *tw = data;
|
|
GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(tw->scrolled);
|
|
|
|
assert(vadj);
|
|
|
|
g_object_get(vadj, "page-size", &page, NULL);
|
|
|
|
y0 = (int)(gtk_adjustment_get_value(vadj));
|
|
y1 = y0 + page;
|
|
|
|
if ((y >= y0) && (y + height <= y1))
|
|
return;
|
|
if (y + height > y1)
|
|
y0 = y0 + (y + height - y1);
|
|
if (y < y0)
|
|
y0 = y;
|
|
gtk_adjustment_set_value(vadj, y0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieves the dimensions of the window with the tree
|
|
*
|
|
* \param data user data assigned to the tree on tree creation
|
|
* \param width will be updated to window width if not NULL
|
|
* \param height will be updated to window height if not NULL
|
|
*/
|
|
static void nsgtk_tree_get_window_dimensions(int *width, int *height, void *data)
|
|
{
|
|
struct nsgtk_treeview *tw = data;
|
|
GtkAdjustment *vadj;
|
|
GtkAdjustment *hadj;
|
|
gdouble page;
|
|
|
|
if (width != NULL) {
|
|
hadj = gtk_scrolled_window_get_hadjustment(tw->scrolled);
|
|
g_object_get(hadj, "page-size", &page, NULL);
|
|
*width = page;
|
|
}
|
|
|
|
if (height != NULL) {
|
|
vadj = gtk_scrolled_window_get_vadjustment(tw->scrolled);
|
|
g_object_get(vadj, "page-size", &page, NULL);
|
|
*height = page;
|
|
}
|
|
}
|
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
static gboolean
|
|
nsgtk_tree_window_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
|
|
{
|
|
struct tree *tree = (struct tree *)data;
|
|
struct redraw_context ctx = {
|
|
.interactive = true,
|
|
.background_images = true,
|
|
.plot = &nsgtk_plotters
|
|
};
|
|
double x1;
|
|
double y1;
|
|
double x2;
|
|
double y2;
|
|
|
|
current_widget = widget;
|
|
current_cr = cr;
|
|
|
|
cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
|
|
|
|
tree_draw(tree, 0, 0, x1, y1, x2 - x1, y2 - y1, &ctx);
|
|
|
|
current_widget = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#else
|
|
|
|
/* signal handler functions for a tree window */
|
|
static gboolean
|
|
nsgtk_tree_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer g)
|
|
{
|
|
struct tree *tree = (struct tree *) g;
|
|
struct redraw_context ctx = {
|
|
.interactive = true,
|
|
.background_images = true,
|
|
.plot = &nsgtk_plotters
|
|
};
|
|
int x, y, width, height;
|
|
|
|
x = event->area.x;
|
|
y = event->area.y;
|
|
width = event->area.width;
|
|
height = event->area.height;
|
|
|
|
current_widget = widget;
|
|
current_cr = gdk_cairo_create(nsgtk_widget_get_window(widget));
|
|
|
|
tree_draw(tree, 0, 0, x, y, width, height, &ctx);
|
|
|
|
current_widget = NULL;
|
|
cairo_destroy(current_cr);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
void nsgtk_tree_window_hide(GtkWidget *widget, gpointer g)
|
|
{
|
|
}
|
|
|
|
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;
|
|
tw->mouse_pressed_x = event->x;
|
|
tw->mouse_pressed_y = event->y;
|
|
|
|
if (event->type == GDK_2BUTTON_PRESS)
|
|
tw->mouse_state = BROWSER_MOUSE_DOUBLE_CLICK;
|
|
|
|
switch (event->button) {
|
|
case 1: tw->mouse_state |= BROWSER_MOUSE_PRESS_1; break;
|
|
case 2: tw->mouse_state |= BROWSER_MOUSE_PRESS_2; break;
|
|
}
|
|
/* Handle the modifiers too */
|
|
if (event->state & GDK_SHIFT_MASK)
|
|
tw->mouse_state |= BROWSER_MOUSE_MOD_1;
|
|
if (event->state & GDK_CONTROL_MASK)
|
|
tw->mouse_state |= BROWSER_MOUSE_MOD_2;
|
|
if (event->state & GDK_MOD1_MASK)
|
|
tw->mouse_state |= BROWSER_MOUSE_MOD_3;
|
|
|
|
/* Record where we pressed, for use when determining whether to start
|
|
* a drag in motion notify events. */
|
|
tw->last_x = event->x;
|
|
tw->last_y = event->y;
|
|
|
|
tree_mouse_action(tree, tw->mouse_state, event->x, event->y);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
nsgtk_tree_window_button_release_event(GtkWidget *widget,
|
|
GdkEventButton *event, gpointer g)
|
|
{
|
|
bool shift = event->state & GDK_SHIFT_MASK;
|
|
bool ctrl = event->state & GDK_CONTROL_MASK;
|
|
bool alt = event->state & GDK_MOD1_MASK;
|
|
struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g;
|
|
struct tree *tree = tw->tree;
|
|
|
|
/* We consider only button 1 clicks as double clicks.
|
|
* If the mouse state is PRESS then we are waiting for a release to emit
|
|
* a click event, otherwise just reset the state to nothing*/
|
|
if (tw->mouse_state & BROWSER_MOUSE_DOUBLE_CLICK) {
|
|
|
|
if (tw->mouse_state & BROWSER_MOUSE_PRESS_1)
|
|
tw->mouse_state ^= BROWSER_MOUSE_PRESS_1 |
|
|
BROWSER_MOUSE_CLICK_1;
|
|
else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2)
|
|
tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 |
|
|
BROWSER_MOUSE_CLICK_2 |
|
|
BROWSER_MOUSE_DOUBLE_CLICK);
|
|
|
|
} else if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) {
|
|
tw->mouse_state ^= (BROWSER_MOUSE_PRESS_1 |
|
|
BROWSER_MOUSE_CLICK_1);
|
|
} else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2) {
|
|
tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 |
|
|
BROWSER_MOUSE_CLICK_2);
|
|
} else if (tw->mouse_state & BROWSER_MOUSE_HOLDING_1) {
|
|
tw->mouse_state ^= (BROWSER_MOUSE_HOLDING_1 |
|
|
BROWSER_MOUSE_DRAG_ON);
|
|
} else if (tw->mouse_state & BROWSER_MOUSE_HOLDING_2) {
|
|
tw->mouse_state ^= (BROWSER_MOUSE_HOLDING_2 |
|
|
BROWSER_MOUSE_DRAG_ON);
|
|
}
|
|
|
|
/* Handle modifiers being removed */
|
|
if (tw->mouse_state & BROWSER_MOUSE_MOD_1 && !shift)
|
|
tw->mouse_state ^= BROWSER_MOUSE_MOD_1;
|
|
if (tw->mouse_state & BROWSER_MOUSE_MOD_2 && !ctrl)
|
|
tw->mouse_state ^= BROWSER_MOUSE_MOD_2;
|
|
if (tw->mouse_state & BROWSER_MOUSE_MOD_3 && !alt)
|
|
tw->mouse_state ^= BROWSER_MOUSE_MOD_3;
|
|
|
|
|
|
if (tw->mouse_state &
|
|
~(BROWSER_MOUSE_MOD_1 |
|
|
BROWSER_MOUSE_MOD_2 |
|
|
BROWSER_MOUSE_MOD_3)) {
|
|
tree_mouse_action(tree, tw->mouse_state,
|
|
event->x, event->y);
|
|
} else {
|
|
tree_drag_end(tree, tw->mouse_state,
|
|
tw->mouse_pressed_x,
|
|
tw->mouse_pressed_y,
|
|
event->x, event->y);
|
|
}
|
|
|
|
tw->mouse_state = 0;
|
|
tw->mouse_pressed = false;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
nsgtk_tree_window_motion_notify_event(GtkWidget *widget,
|
|
GdkEventMotion *event, gpointer g)
|
|
{
|
|
bool shift = event->state & GDK_SHIFT_MASK;
|
|
bool ctrl = event->state & GDK_CONTROL_MASK;
|
|
bool alt = event->state & GDK_MOD1_MASK;
|
|
struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g;
|
|
struct tree *tree = tw->tree;
|
|
|
|
if (tw->mouse_pressed == false)
|
|
return TRUE;
|
|
|
|
if ((fabs(event->x - tw->last_x) < 5.0) &&
|
|
(fabs(event->y - tw->last_y) < 5.0)) {
|
|
/* Mouse hasn't moved far enough from press coordinate
|
|
* for this to be considered a drag.
|
|
*/
|
|
return FALSE;
|
|
} else {
|
|
/* This is a drag, ensure it's always treated as such,
|
|
* even if we drag back over the press location.
|
|
*/
|
|
tw->last_x = INT_MIN;
|
|
tw->last_y = INT_MIN;
|
|
}
|
|
|
|
if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) {
|
|
/* Start button 1 drag */
|
|
tree_mouse_action(tree, BROWSER_MOUSE_DRAG_1,
|
|
tw->mouse_pressed_x, tw->mouse_pressed_y);
|
|
/* Replace PRESS with HOLDING and declare drag in progress */
|
|
tw->mouse_state ^= (BROWSER_MOUSE_PRESS_1 |
|
|
BROWSER_MOUSE_HOLDING_1);
|
|
tw->mouse_state |= BROWSER_MOUSE_DRAG_ON;
|
|
return TRUE;
|
|
}
|
|
else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2){
|
|
/* Start button 2s drag */
|
|
tree_mouse_action(tree, BROWSER_MOUSE_DRAG_2,
|
|
tw->mouse_pressed_x, tw->mouse_pressed_y);
|
|
/* Replace PRESS with HOLDING and declare drag in progress */
|
|
tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 |
|
|
BROWSER_MOUSE_HOLDING_2);
|
|
tw->mouse_state |= BROWSER_MOUSE_DRAG_ON;
|
|
return TRUE;
|
|
}
|
|
|
|
/* Handle modifiers being removed */
|
|
if (tw->mouse_state & BROWSER_MOUSE_MOD_1 && !shift)
|
|
tw->mouse_state ^= BROWSER_MOUSE_MOD_1;
|
|
if (tw->mouse_state & BROWSER_MOUSE_MOD_2 && !ctrl)
|
|
tw->mouse_state ^= BROWSER_MOUSE_MOD_2;
|
|
if (tw->mouse_state & BROWSER_MOUSE_MOD_3 && !alt)
|
|
tw->mouse_state ^= BROWSER_MOUSE_MOD_3;
|
|
|
|
if (tw->mouse_state & (BROWSER_MOUSE_HOLDING_1 |
|
|
BROWSER_MOUSE_HOLDING_2))
|
|
tree_mouse_action(tree, tw->mouse_state, event->x,
|
|
event->y);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event,
|
|
gpointer g)
|
|
{
|
|
struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g;
|
|
struct tree *tree = tw->tree;
|
|
uint32_t nskey;
|
|
double value;
|
|
GtkAdjustment *vscroll;
|
|
GtkAdjustment *hscroll;
|
|
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)
|
|
return TRUE;
|
|
|
|
vscroll = gtk_scrolled_window_get_vadjustment(tw->scrolled);
|
|
hscroll = gtk_scrolled_window_get_hadjustment(tw->scrolled);
|
|
g_object_get(vscroll, "page-size", &vpage, NULL);
|
|
g_object_get(hscroll, "page-size", &hpage, NULL);
|
|
|
|
switch (event->keyval) {
|
|
case GDK_KEY(Home):
|
|
case GDK_KEY(KP_Home):
|
|
scroll = vscroll;
|
|
value = nsgtk_adjustment_get_lower(scroll);
|
|
break;
|
|
|
|
case GDK_KEY(End):
|
|
case GDK_KEY(KP_End):
|
|
scroll = vscroll;
|
|
value = nsgtk_adjustment_get_upper(scroll) - vpage;
|
|
if (value < nsgtk_adjustment_get_lower(scroll))
|
|
value = nsgtk_adjustment_get_lower(scroll);
|
|
break;
|
|
|
|
case GDK_KEY(Left):
|
|
case GDK_KEY(KP_Left):
|
|
scroll = hscroll;
|
|
value = gtk_adjustment_get_value(scroll) -
|
|
nsgtk_adjustment_get_step_increment(scroll);
|
|
if (value < nsgtk_adjustment_get_lower(scroll))
|
|
value = nsgtk_adjustment_get_lower(scroll);
|
|
break;
|
|
|
|
case GDK_KEY(Up):
|
|
case GDK_KEY(KP_Up):
|
|
scroll = vscroll;
|
|
value = gtk_adjustment_get_value(scroll) -
|
|
nsgtk_adjustment_get_step_increment(scroll);
|
|
if (value < nsgtk_adjustment_get_lower(scroll))
|
|
value = nsgtk_adjustment_get_lower(scroll);
|
|
break;
|
|
|
|
case GDK_KEY(Right):
|
|
case GDK_KEY(KP_Right):
|
|
scroll = hscroll;
|
|
value = gtk_adjustment_get_value(scroll) +
|
|
nsgtk_adjustment_get_step_increment(scroll);
|
|
if (value > nsgtk_adjustment_get_upper(scroll) - hpage)
|
|
value = nsgtk_adjustment_get_upper(scroll) - hpage;
|
|
break;
|
|
|
|
case GDK_KEY(Down):
|
|
case GDK_KEY(KP_Down):
|
|
scroll = vscroll;
|
|
value = gtk_adjustment_get_value(scroll) +
|
|
nsgtk_adjustment_get_step_increment(scroll);
|
|
if (value > nsgtk_adjustment_get_upper(scroll) - vpage)
|
|
value = nsgtk_adjustment_get_upper(scroll) - vpage;
|
|
break;
|
|
|
|
case GDK_KEY(Page_Up):
|
|
case GDK_KEY(KP_Page_Up):
|
|
scroll = vscroll;
|
|
value = gtk_adjustment_get_value(scroll) -
|
|
nsgtk_adjustment_get_page_increment(scroll);
|
|
|
|
if (value < nsgtk_adjustment_get_lower(scroll))
|
|
value = nsgtk_adjustment_get_lower(scroll);
|
|
|
|
break;
|
|
|
|
case GDK_KEY(Page_Down):
|
|
case GDK_KEY(KP_Page_Down):
|
|
scroll = vscroll;
|
|
value = gtk_adjustment_get_value(scroll) +
|
|
nsgtk_adjustment_get_page_increment(scroll);
|
|
|
|
if (value > nsgtk_adjustment_get_upper(scroll) - vpage)
|
|
value = nsgtk_adjustment_get_upper(scroll) - vpage;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (scroll != NULL)
|
|
gtk_adjustment_set_value(scroll, value);
|
|
|
|
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,
|
|
.scroll_visible = nsgtk_tree_scroll_visible,
|
|
.get_window_dimensions = nsgtk_tree_get_window_dimensions
|
|
};
|
|
|
|
struct nsgtk_treeview *nsgtk_treeview_create(unsigned int flags,
|
|
GtkWindow *window, GtkScrolledWindow *scrolled,
|
|
GtkDrawingArea *drawing_area)
|
|
{
|
|
struct nsgtk_treeview *tv;
|
|
|
|
assert(drawing_area != NULL);
|
|
|
|
tv = malloc(sizeof(struct nsgtk_treeview));
|
|
if (tv == NULL) {
|
|
LOG("malloc failed");
|
|
warn_user("NoMemory", 0);
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
|
|
nsgtk_widget_override_background_color(GTK_WIDGET(drawing_area),
|
|
GTK_STATE_NORMAL,
|
|
0, 0xffff, 0xffff, 0xffff);
|
|
|
|
nsgtk_connect_draw_event(GTK_WIDGET(drawing_area), G_CALLBACK(nsgtk_tree_window_draw_event), tv->tree);
|
|
|
|
#define CONNECT(obj, sig, callback, ptr) \
|
|
g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
|
|
CONNECT(drawing_area, "button-press-event",
|
|
nsgtk_tree_window_button_press_event,
|
|
tv);
|
|
CONNECT(drawing_area, "button-release-event",
|
|
nsgtk_tree_window_button_release_event,
|
|
tv);
|
|
CONNECT(drawing_area, "motion-notify-event",
|
|
nsgtk_tree_window_motion_notify_event,
|
|
tv);
|
|
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;
|
|
}
|