From b4195d4101a3ebc1bd27bd1b36220f386bbf0672 Mon Sep 17 00:00:00 2001 From: perry.werneck@gmail.com Date: Thu, 3 May 2012 11:29:18 +0000 Subject: [PATCH] Renomeando diretorio de fontes da aplicacao para facilitar empacotamento --- accessible.c | 865 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ accessible.h | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ draw.c | 397 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ genmarshal | 11 +++++++++++ iocallback.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ keyboard.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ locked.xbm | 14 ++++++++++++++ mouse.c | 263 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ oia.c | 1032 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ private.h | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ selection.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sources.mak | 2 ++ unlocked.xbm | 14 ++++++++++++++ v3270.h | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ widget.c | 1221 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 5384 insertions(+), 0 deletions(-) create mode 100644 accessible.c create mode 100644 accessible.h create mode 100644 draw.c create mode 100644 genmarshal create mode 100644 iocallback.c create mode 100644 keyboard.c create mode 100644 locked.xbm create mode 100644 mouse.c create mode 100644 oia.c create mode 100644 private.h create mode 100644 selection.c create mode 100644 sources.mak create mode 100644 unlocked.xbm create mode 100644 v3270.h create mode 100644 widget.c diff --git a/accessible.c b/accessible.c new file mode 100644 index 0000000..2dd99e0 --- /dev/null +++ b/accessible.c @@ -0,0 +1,865 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como accessible.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + + #include + + #define ENABLE_NLS + #define GETTEXT_PACKAGE PACKAGE_NAME + + #include + #include + #include + + #include + #include + #include "v3270.h" + #include "private.h" + #include "accessible.h" + +// References: +// +// http://git.gnome.org/browse/gtk+/tree/gtk/a11y/gtkwidgetaccessible.c +// http://git.gnome.org/browse/gtk+/tree/gtk/a11y/gtkentryaccessible.c +// + + +/*--[ Prototipes ]-----------------------------------------------------------------------------------*/ + +static void atk_component_interface_init (AtkComponentIface *iface); +static void atk_action_interface_init (AtkActionIface *iface); +static void v3270_accessible_class_init (v3270AccessibleClass *klass); +static void v3270_accessible_init (v3270Accessible *widget); + +static void atk_text_interface_init (AtkTextIface *iface); + +/*--[ Widget definition ]----------------------------------------------------------------------------*/ + +G_DEFINE_TYPE_WITH_CODE (v3270Accessible, v3270_accessible, GTK_TYPE_ACCESSIBLE, + G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init) + G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init) + G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init) + ) + +// G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, atk_editable_text_interface_init) + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + +static const gchar * v3270_accessible_get_description (AtkObject *accessible) +{ + GtkWidget *widget = gtk_accessible_get_widget(GTK_ACCESSIBLE (accessible)); + + if (widget == NULL) + return NULL; + + return _( "3270 screen" ); +} + +static void v3270_accessible_focus_event(AtkObject *obj, gboolean focus_in) +{ + AtkObject *focus_obj = g_object_get_data (G_OBJECT (obj), "gail-focus-object"); + + if(focus_obj == NULL) + focus_obj = obj; + + atk_object_notify_state_change(focus_obj, ATK_STATE_FOCUSED, focus_in); +} + +static AtkAttributeSet * v3270_accessible_get_attributes (AtkObject *obj) +{ + AtkAttributeSet * attributes; + AtkAttribute * toolkit = g_new(AtkAttribute, 1); + + toolkit->name = g_strdup("toolkit"); + toolkit->value = g_strdup("gtk"); + + attributes = g_slist_append (NULL, toolkit); + + return attributes; +} + +static void v3270_accessible_initialize (AtkObject *obj, gpointer data) +{ + obj->role = ATK_ROLE_TEXT; +} + +static void v3270_accessible_class_init(v3270AccessibleClass *klass) +{ + AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + + class->get_description = v3270_accessible_get_description; + class->focus_event = v3270_accessible_focus_event; + class->get_attributes = v3270_accessible_get_attributes; + class->initialize = v3270_accessible_initialize; + +/* + klass->notify_gtk = gtk_widget_accessible_notify_gtk; + + class->get_parent = gtk_widget_accessible_get_parent; + class->ref_relation_set = gtk_widget_accessible_ref_relation_set; + class->ref_state_set = gtk_widget_accessible_ref_state_set; + class->get_index_in_parent = gtk_widget_accessible_get_index_in_parent; +*/ +} + +static gint v3270_accessible_get_n_actions(AtkAction *action) +{ + return 1; +} + +static const gchar* v3270_accessible_action_get_name (AtkAction *action, gint i) +{ + if (i != 0) + return NULL; + + return "activate"; +} + +static gboolean v3270_accessible_do_action(AtkAction *action, gint i) +{ + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action)); + + if(widget == NULL) + return FALSE; + + if(!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget)) + return FALSE; + + if (i != 0) + return FALSE; + + gtk_widget_activate(widget); + + return TRUE; +} + +static void atk_action_interface_init(AtkActionIface *iface) +{ + iface->get_name = v3270_accessible_action_get_name; + iface->get_n_actions = v3270_accessible_get_n_actions; + iface->do_action = v3270_accessible_do_action; + +/* + iface->get_keybinding = gtk_entry_accessible_get_keybinding; +*/ +} + +static gunichar v3270_accessible_get_character_at_offset(AtkText *atk_text, gint offset) +{ + GtkWidget * widget = gtk_accessible_get_widget(GTK_ACCESSIBLE (atk_text)); + + if(widget == NULL) + { + H3270 * host = v3270_get_session(widget); + gchar * text = lib3270_get_text(host,offset,1); + + if(text) + { + gunichar unichar; + gsize bytes_written; + GError * error = NULL; + gchar * utfstring = g_convert_with_fallback( text, + -1, + "UTF-8", + lib3270_get_charset(host), + " ", + NULL, + &bytes_written, + &error ); + + if(error) + { + g_warning("%s failed: %s",__FUNCTION__,error->message); + g_error_free(error); + } + unichar = *utfstring; + + g_free(utfstring); + + return unichar; + } + + } + + return '\0'; +} + +static gint v3270_accessible_get_caret_offset(AtkText *text) +{ + GtkWidget *widget = gtk_accessible_get_widget(GTK_ACCESSIBLE(text)); + + if (widget == NULL) + return 0; + + return lib3270_get_cursor_address(GTK_V3270(widget)->host); +} + +static gint v3270_accessible_get_character_count(AtkText *text) +{ + int rows,cols; + GtkWidget *widget = gtk_accessible_get_widget(GTK_ACCESSIBLE(text)); + + if(!widget) + return 0; + + return lib3270_get_length(GTK_V3270(widget)->host); +} + +static gint v3270_accessible_get_offset_at_point(AtkText *atk_text, gint x, gint y, AtkCoordType coords) +{ + gint x_window, + y_window, + x_widget, + y_widget; + GdkWindow * window; + GtkWidget * widget = gtk_accessible_get_widget(GTK_ACCESSIBLE(atk_text)); + + if(!widget) + return -1; + + window = gtk_widget_get_window(widget); + gdk_window_get_origin(window, &x_widget, &y_widget); + + switch(coords) + { + case ATK_XY_SCREEN: + x -= x_widget; + y -= y_widget; + break; + + case ATK_XY_WINDOW: + window = gdk_window_get_toplevel(window); + gdk_window_get_origin (window, &x_window, &y_window); + x = x - x_widget + x_window; + y = y - y_widget + y_window; + break; + + default: + return -1; + + } + + return v3270_get_offset_at_point(GTK_V3270(widget),x,y); +} + +/* +text : an AtkText +offset : The offset of the text character for which bounding information is required. +x : Pointer for the x cordinate of the bounding box +y : Pointer for the y cordinate of the bounding box +width : Pointer for the width of the bounding box +height : Pointer for the height of the bounding box +coords : specify whether coordinates are relative to the screen or widget window +*/ + +static void v3270_accessible_get_character_extents( AtkText *text, + gint offset, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coords ) +{ + v3270 * widget = (v3270 *) gtk_accessible_get_widget(GTK_ACCESSIBLE (text)); + int rows, cols; + GdkWindow * window; + + if (widget == NULL) + return; + + lib3270_get_screen_size(widget->host,&rows,&cols); + + // Get screen position + window = gtk_widget_get_window(GTK_WIDGET(widget)); + gdk_window_get_origin(window, x, y); + + // Get screen position + *x += widget->metrics.left + ((offset%cols) * widget->metrics.width); + *y += widget->metrics.top + ((offset/cols) * widget->metrics.spacing); + *width = widget->metrics.width; + *height = widget->metrics.spacing; + + if(coords == ATK_XY_WINDOW) + { + // Correct position based on toplevel + gint x_window, y_window; + + window = gdk_window_get_toplevel(window); + gdk_window_get_origin(window, &x_window, &y_window); + *x -= x_window; + *y -= y_window; + } + +// trace("%s: offset=%d x=%d y=%d %s",__FUNCTION__,offset,*x,*y,coords == ATK_XY_WINDOW ? "ATK_XY_WINDOW" : ""); + +} + +static gchar * v3270_accessible_get_text_at_offset(AtkText *atk_text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) +{ + GtkWidget * widget = gtk_accessible_get_widget(GTK_ACCESSIBLE (atk_text)); + H3270 * host; + char * text; + int rows,cols,pos; + + if(!widget) + return NULL; + + host = GTK_V3270(widget)->host; + lib3270_get_screen_size(host,&rows,&cols); + + switch(boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: // Boundary is the boundary between characters + // (including non-printing characters) + + text = lib3270_get_text(host,offset,1); + break; + + case ATK_TEXT_BOUNDARY_WORD_START: // Boundary is the start (i.e. first character) of a word. + return g_strdup("ATK_TEXT_BOUNDARY_WORD_START"); + break; + + case ATK_TEXT_BOUNDARY_WORD_END: // Boundary is the end (i.e. last character) of a word. + return g_strdup("ATK_TEXT_BOUNDARY_WORD_END"); + break; + + case ATK_TEXT_BOUNDARY_SENTENCE_START: // Boundary is the first character in a sentence. + return g_strdup("ATK_TEXT_BOUNDARY_SENTENCE_START"); + break; + + case ATK_TEXT_BOUNDARY_SENTENCE_END: // Boundary is the last (terminal) character in + // a sentence; in languages which use "sentence stop" punctuation such as English, the boundary is thus the '.', '?', or + // similar terminal punctuation character. + return g_strdup("ATK_TEXT_BOUNDARY_SENTENCE_END"); + break; + + + case ATK_TEXT_BOUNDARY_LINE_START: // Boundary is the initial character of the content or a character immediately following a newline, + // linefeed, or return character. + pos = (offset/cols)*cols; + if(pos == offset) + offset++; + text = lib3270_get_text(host,pos,(offset-pos)); + break; + + + case ATK_TEXT_BOUNDARY_LINE_END: // Boundary is the linefeed, or return character. + return g_strdup("ATK_TEXT_BOUNDARY_LINE_END"); + break; + + } + + if(text) + { + gsize bytes_written; + GError * error = NULL; + gchar * utfchar = g_convert_with_fallback( text, + -1, + "UTF-8", + lib3270_get_charset(host), + " ", + NULL, + &bytes_written, + &error ); + + if(error) + { + g_warning("%s failed: %s",__FUNCTION__,error->message); + g_error_free(error); + } + + free(text); + return utfchar; + } + + return NULL; +} + +static gchar * v3270_accessible_get_text(AtkText *atk_text, gint start_pos, gint end_pos) +{ + GtkWidget * widget = gtk_accessible_get_widget(GTK_ACCESSIBLE (atk_text)); + char * text; + H3270 * host; + gchar * utftext = NULL; + + if(widget == NULL) + return NULL; + + host = v3270_get_session(widget); + if(!host) + return NULL; + + if(!lib3270_connected(host)) + return g_strdup( "" ); + + text = lib3270_get_text(host,start_pos,end_pos < start_pos ? -1 : (end_pos - start_pos)); + + if(text) + { + gsize bytes_written; + GError * error = NULL; + + utftext = g_convert_with_fallback(text,-1,"UTF-8",lib3270_get_charset(host)," ",NULL,&bytes_written, &error); + + if(error) + { + g_warning("%s failed: %s",__FUNCTION__,error->message); + g_error_free(error); + } + + free(text); + +// trace("%s:\n%s\n",__FUNCTION__,utftext); + + } + + return utftext; +} + +static gboolean v3270_set_caret_offset(AtkText *text, gint offset) +{ + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + if (widget == NULL) + return FALSE; + + trace("%s - offset=%d",__FUNCTION__,offset); + + lib3270_set_cursor_address(GTK_V3270(widget)->host,offset); + + return TRUE; +} + +static gboolean v3270_accessible_remove_selection(AtkText *text, gint selection_num) +{ + GtkWidget * widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + + if (widget == NULL || selection_num != 0) + return FALSE; + + v3270_unselect(widget); + + return TRUE; +} + +static gint v3270_accessible_get_n_selections (AtkText *text) +{ + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + + if(!widget) + return 0; + +// trace("%s: n_selections=%d",__FUNCTION__,v3270_get_selection_bounds(widget, NULL, NULL) ? 1 : 0); + + return v3270_get_selection_bounds(widget, NULL, NULL) ? 1 : 0; +} + +static gchar * v3270_accessible_get_selection(AtkText *atk_text, gint selection_num, gint *start_pos, gint *end_pos) +{ + GtkWidget *widget = gtk_accessible_get_widget(GTK_ACCESSIBLE (atk_text)); + +// trace("%s: selection_num=%d",__FUNCTION__,selection_num); + if (widget == NULL ||selection_num != 0) + return NULL; + + if(v3270_get_selection_bounds(widget, start_pos, end_pos)) + { +// trace("%s: TRUE",__FUNCTION__); + return v3270_get_region(widget, *start_pos, *end_pos, FALSE); + } + +// trace("%s: FALSE",__FUNCTION__); + return NULL; +} + +static gboolean v3270_accessible_add_selection(AtkText *text, gint start_pos, gint end_pos) +{ + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + + if (widget == NULL) + return FALSE; + + if(!v3270_get_selection_bounds(widget,NULL,NULL)) + { + v3270_select_region(widget, start_pos, end_pos); + return TRUE; + } + + return FALSE; +} + +static gboolean v3270_accessible_set_selection(AtkText *text, gint selection_num, gint start_pos, gint end_pos) +{ + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + gint start, end; + + if(widget == NULL || selection_num != 0) + return FALSE; + + if(!v3270_get_selection_bounds(widget,NULL,NULL)) + { + v3270_select_region(widget, start_pos, end_pos); + return TRUE; + } + + return FALSE; +} + +static AtkAttributeSet *add_attribute(AtkAttributeSet * attributes, AtkTextAttribute attr, const gchar *value) +{ + AtkAttribute *at = g_new(AtkAttribute, 1); + + at->name = g_strdup (atk_text_attribute_get_name (attr)); + at->value = g_strdup (value); + + return g_slist_prepend (attributes, at); +} + +static AtkAttributeSet * v3270_accessible_get_default_attributes (AtkText *text) +{ + GtkWidget * widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + AtkAttributeSet * attributes = NULL; + + if(!widget) + return NULL; + + trace("%s is incomplete ***********************",__FUNCTION__); + + // http://developer.gnome.org/atk/stable/AtkText.html#AtkTextAttribute + + // The direction of the text, if set. Values are "none", "ltr" or "rtl" + attributes = add_attribute(attributes, ATK_TEXT_ATTR_DIRECTION,atk_text_attribute_get_value(ATK_TEXT_ATTR_DIRECTION,gtk_widget_get_direction(widget))); + + return attributes; +} + +/** + * Creates an AtkAttributeSet which consists of the attributes explicitly + * set at the position offset in the text. start_offset and end_offset are set + * to the start and end of the range around offset where the attributes are invariant. + * Note that end_offset is the offset of the first character after the range. + * See the enum AtkTextAttribute for types of text attributes that can be returned. + * Note that other attributes may also be returned. + * + * @param text an AtkText + * @param offset the offset at which to get the attributes, -1 means the offset of the character to be inserted at the caret location. + * @param start_offset the address to put the start offset of the range + * @param end_offset the address to put the end offset of the range + * + * @return an AtkAttributeSet which contains the attributes explicitly set at offset. + */ +static AtkAttributeSet * v3270_accessible_get_run_attributes(AtkText *text, gint offset, gint * start_offset, gint * end_offset) +{ + GtkWidget * widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text)); + H3270 * host; + AtkAttributeSet * attributes = NULL; + int start, end; + + trace("%s is incomplete ***********************",__FUNCTION__); + + g_return_val_if_fail((widget && GTK_IS_V3270(widget)),NULL); + + host = v3270_get_session(widget); + + if(offset == -1) + offset = lib3270_get_cursor_address(host); + + if(!lib3270_get_field_bounds(host,offset,&start,&end)) + { + *start_offset = start; + *end_offset = end; + } + + // http://developer.gnome.org/atk/stable/AtkText.html#AtkTextAttribute + + // The direction of the text, if set. Values are "none", "ltr" or "rtl" + attributes = add_attribute(attributes, ATK_TEXT_ATTR_DIRECTION,atk_text_attribute_get_value(ATK_TEXT_ATTR_DIRECTION,gtk_widget_get_direction(widget))); + + // ATK_TEXT_ATTR_LEFT_MARGIN + // The pixel width of the left margin + + // ATK_TEXT_ATTR_RIGHT_MARGIN + // The pixel width of the right margin + + // ATK_TEXT_ATTR_INVISIBLE + // Either "true" or "false" indicating whether text is visible or not + + // Either "true" or "false" indicating whether text is editable or not + attributes = add_attribute( attributes, + ATK_TEXT_ATTR_EDITABLE, + lib3270_is_protected(host,offset) ? "false" : "true" ); + + // The background color. The value is an RGB value of the format "u,u,u" + // ATK_TEXT_ATTR_BG_COLOR + + // The foreground color. The value is an RGB value of the format "u,u,u" + // ATK_TEXT_ATTR_FG_COLOR + + // The font family name + attributes = add_attribute( attributes, + ATK_TEXT_ATTR_FAMILY_NAME, + GTK_V3270(widget)->font_family ); + + return attributes; +} + +/* +static gchar * v3270_accessible_get_text_after_offset(AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) +{ + // http://developer.gnome.org/atk/stable/AtkText.html#atk-text-get-text-after-offset + trace("WARNING: %s is incomplete",__FUNCTION__); + +} +*/ + +/* +static gchar * v3270_accessible_get_text_before_offset(AtkText *text,gint offset,AtkTextBoundary boundary_type,gint *start_offset,gint *end_offset) +{ + // http://developer.gnome.org/atk/stable/AtkText.html#atk-text-get-text-before-offset + trace("WARNING: %s is incomplete",__FUNCTION__); + +} +*/ + +static void atk_text_interface_init(AtkTextIface *iface) +{ + iface->get_text = v3270_accessible_get_text; + iface->get_character_at_offset = v3270_accessible_get_character_at_offset; + + iface->get_text_at_offset = v3270_accessible_get_text_at_offset; + + iface->get_character_count = v3270_accessible_get_character_count; + iface->get_caret_offset = v3270_accessible_get_caret_offset; + iface->set_caret_offset = v3270_set_caret_offset; + + iface->get_character_extents = v3270_accessible_get_character_extents; + iface->get_offset_at_point = v3270_accessible_get_offset_at_point; + + iface->get_n_selections = v3270_accessible_get_n_selections; + iface->add_selection = v3270_accessible_add_selection; + iface->remove_selection = v3270_accessible_remove_selection; + iface->set_selection = v3270_accessible_set_selection; + iface->get_selection = v3270_accessible_get_selection; + iface->get_run_attributes = v3270_accessible_get_run_attributes; + iface->get_default_attributes = v3270_accessible_get_default_attributes; +// iface->get_text_after_offset = v3270_accessible_get_text_after_offset; +// iface->get_text_before_offset = v3270_accessible_get_text_before_offset; + +} + +static void v3270_accessible_init(v3270Accessible *widget) +{ + AtkObject *obj = ATK_OBJECT(widget); + obj->role = ATK_ROLE_TEXT; +} + +void v3270_accessible_get_extents(AtkComponent *component, gint *x, gint *y,gint *width,gint *height, AtkCoordType coord_type) +{ + GtkWidget *widget = gtk_accessible_get_widget(GTK_ACCESSIBLE (component)); + GdkWindow *window; + gint x_window, y_window; + GtkAllocation allocation; + + if (widget == NULL) + return; + + gtk_widget_get_allocation (widget, &allocation); + *width = allocation.width; + *height = allocation.height; + + if(gtk_widget_get_parent(widget)) + { + *x = allocation.x; + *y = allocation.y; + window = gtk_widget_get_parent_window (widget); + } + else + { + *x = 0; + *y = 0; + window = gtk_widget_get_window (widget); + } + + gdk_window_get_origin(window, &x_window, &y_window); + *x += x_window; + *y += y_window; + + if (coord_type == ATK_XY_WINDOW) + { + gint x_toplevel, y_toplevel; + + window = gdk_window_get_toplevel (gtk_widget_get_window (widget)); + gdk_window_get_origin (window, &x_toplevel, &y_toplevel); + + *x -= x_toplevel; + *y -= y_toplevel; + } +} + +static void v3270_accessible_get_size(AtkComponent *component,gint *width, gint *height) +{ + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component)); + + if (widget == NULL) + return; + + *width = gtk_widget_get_allocated_width (widget); + *height = gtk_widget_get_allocated_height (widget); +} + +static gboolean v3270_accessible_grab_focus(AtkComponent *component) +{ + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component)); + GtkWidget *toplevel; + + if (!widget) + return FALSE; + + gtk_widget_grab_focus (widget); + + toplevel = gtk_widget_get_toplevel (widget); + if (gtk_widget_is_toplevel (toplevel)) + { + #ifdef GDK_WINDOWING_X11 + gtk_window_present_with_time (GTK_WINDOW (toplevel),gdk_x11_get_server_time(gtk_widget_get_window(widget))); + #else + gtk_window_present (GTK_WINDOW (toplevel)); + #endif + } + + return TRUE; +} + +static AtkLayer v3270_accessible_get_layer (AtkComponent *component) +{ + return ATK_LAYER_WIDGET; +} + +static gboolean v3270_accessible_set_size(AtkComponent *component, gint width, gint height) +{ + GtkWidget *widget = gtk_accessible_get_widget(GTK_ACCESSIBLE (component)); + + if (widget == NULL) + return FALSE; + + gtk_widget_set_size_request(widget, width, height); + return TRUE; +} + +static void atk_component_interface_init(AtkComponentIface *iface) +{ + iface->get_extents = v3270_accessible_get_extents; + iface->get_size = v3270_accessible_get_size; + iface->grab_focus = v3270_accessible_grab_focus; + iface->get_layer = v3270_accessible_get_layer; + iface->set_size = v3270_accessible_set_size; +} + +void v3270_acessible_set_state(GtkAccessible *obj, LIB3270_MESSAGE id) +{ + #ifdef DEBUG + #define STATE_MESSAGE(x,c) { #x, x, c } + #else + #define STATE_MESSAGE(x,c) { x, c } + #endif + + static const struct _state + { + #ifdef DEBUG + const gchar * dbg; + #endif + AtkStateType atkstate; + V3270_STATE flag; + } table[] = + { + STATE_MESSAGE(ATK_STATE_BUSY, V3270_STATE_BUSY ), + STATE_MESSAGE(ATK_STATE_EDITABLE, V3270_STATE_EDITABLE ), + STATE_MESSAGE(ATK_STATE_ENABLED, V3270_STATE_ENABLED ), + STATE_MESSAGE(ATK_STATE_INVALID_ENTRY, V3270_STATE_INVALID_ENTRY ), + }; + + V3270_STATE state = GTK_V3270_ACCESSIBLE(obj)->state; + V3270_STATE bits; + int f; + + switch(id) + { + case LIB3270_MESSAGE_NONE: + state = V3270_STATE_EDITABLE|V3270_STATE_ENABLED; + break; + + case LIB3270_MESSAGE_SYSWAIT: + case LIB3270_MESSAGE_TWAIT: + case LIB3270_MESSAGE_RESOLVING: + case LIB3270_MESSAGE_CONNECTING: + state = V3270_STATE_BUSY; + break; + + case LIB3270_MESSAGE_CONNECTED: + case LIB3270_MESSAGE_AWAITING_FIRST: + state = V3270_STATE_ENABLED; + break; + + case LIB3270_MESSAGE_DISCONNECTED: + state = 0; + break; + + case LIB3270_MESSAGE_MINUS: + case LIB3270_MESSAGE_INHIBIT: + case LIB3270_MESSAGE_X: + break; + + case LIB3270_MESSAGE_PROTECTED: + case LIB3270_MESSAGE_NUMERIC: + case LIB3270_MESSAGE_OVERFLOW: + case LIB3270_MESSAGE_KYBDLOCK: + state = V3270_STATE_INVALID_ENTRY|V3270_STATE_EDITABLE|V3270_STATE_ENABLED; + break; + + } + + if(state == GTK_V3270_ACCESSIBLE(obj)->state) + return; + + bits = GTK_V3270_ACCESSIBLE(obj)->state ^ state; + + trace("State change from %04x to %04x (bits=%04x)", + GTK_V3270_ACCESSIBLE(obj)->state, + state, bits ); + + for(f=0;fstate = state; +} + diff --git a/accessible.h b/accessible.h new file mode 100644 index 0000000..380ce73 --- /dev/null +++ b/accessible.h @@ -0,0 +1,73 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como accessible.h e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_V3270_ACCESSIBLE (v3270_accessible_get_type ()) +#define GTK_V3270_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_V3270_ACCESSIBLE, v3270Accessible)) +#define GTK_V3270_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_V3270_ACCESSIBLE, v3270AccessibleClass)) +#define GTK_IS_V3270_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_V3270_ACCESSIBLE)) +#define GTK_IS_V3270_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_V3270_ACCESSIBLE)) +#define GTK_V3270_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_V3270_ACCESSIBLE, v3270AccessibleClass)) + +typedef struct _v3270Accessible v3270Accessible; +typedef struct _v3270AccessibleClass v3270AccessibleClass; + +typedef enum _v3270_state +{ + V3270_STATE_NONE = 0x0000, + V3270_STATE_EDITABLE = 0x0001, + V3270_STATE_BUSY = 0x0002, + V3270_STATE_ENABLED = 0x0004, + V3270_STATE_INVALID_ENTRY = 0x0008, + +} V3270_STATE; + +struct _v3270Accessible +{ + GtkAccessible parent; + V3270_STATE state; + +// AtkLayer layer; +}; + +struct _v3270AccessibleClass +{ + GtkAccessibleClass parent_class; + + +}; + +GType v3270_accessible_get_type(void); + +void v3270_acessible_set_state(GtkAccessible *obj, LIB3270_MESSAGE id); + +G_END_DECLS diff --git a/draw.c b/draw.c new file mode 100644 index 0000000..c8a309c --- /dev/null +++ b/draw.c @@ -0,0 +1,397 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como draw.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + + #include + #include + #include + #include + #include "v3270.h" + #include "private.h" + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + +gboolean v3270_draw(GtkWidget * widget, cairo_t * cr) +{ + v3270 * terminal = GTK_V3270(widget); + + cairo_set_source_surface(cr,terminal->surface,0,0); + cairo_paint(cr); + + if(lib3270_get_toggle(terminal->host,LIB3270_TOGGLE_CROSSHAIR) && (terminal->cursor.show&2)) + { + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + + gdk_cairo_set_source_color(cr,terminal->color+V3270_COLOR_CROSS_HAIR); + + cairo_rectangle(cr, 0,terminal->cursor.rect.y+terminal->metrics.height,allocation.width,1); + cairo_fill(cr); + + cairo_rectangle(cr, terminal->cursor.rect.x,0,1,terminal->oia_rect->y-3); + cairo_fill(cr); + } + + if(terminal->cursor.show == 3) + { + cairo_set_source_surface(cr,terminal->cursor.surface,terminal->cursor.rect.x,terminal->cursor.rect.y); + + if(lib3270_get_toggle(terminal->host,LIB3270_TOGGLE_INSERT)) + { + cairo_rectangle(cr, terminal->cursor.rect.x, + terminal->cursor.rect.y, + terminal->cursor.rect.width, + terminal->cursor.rect.height ); + } + else + { + cairo_rectangle(cr, terminal->cursor.rect.x, + terminal->cursor.rect.y+terminal->metrics.height, + terminal->cursor.rect.width, + terminal->metrics.descent ); + } + + cairo_fill(cr); + } + + return FALSE; +} + +#if( !GTK_CHECK_VERSION(3,0,0)) +gboolean v3270_expose(GtkWidget *widget, GdkEventExpose *event) +{ + cairo_t *cr = gdk_cairo_create(widget->window); + v3270_draw(widget,cr); + cairo_destroy(cr); + return FALSE; +} +#endif // GTk3 + + +static void get_element_colors(unsigned short attr, GdkColor **fg, GdkColor **bg, GdkColor *color) +{ + if(attr & LIB3270_ATTR_SELECTED) + { + *fg = color+V3270_COLOR_SELECTED_FG; + *bg = color+V3270_COLOR_SELECTED_BG; + } + else + { + *bg = color+((attr & 0x00F0) >> 4); + + if(attr & LIB3270_ATTR_FIELD) + *fg = color+(attr & 0x0003)+V3270_COLOR_FIELD; + else + *fg = color+(attr & 0x000F); + } +} + +void v3270_draw_element(cairo_t *cr, unsigned char chr, unsigned short attr, H3270 *session, guint height, GdkRectangle *rect, GdkColor *color) +{ + GdkColor *fg; + GdkColor *bg; + + get_element_colors(attr,&fg,&bg,color); + v3270_draw_char(cr,chr,attr,session,height,rect,fg,bg); +} + +void v3270_draw_char(cairo_t *cr, unsigned char chr, unsigned short attr, H3270 *session, guint height, GdkRectangle *rect, GdkColor *fg, GdkColor *bg) +{ + // Clear element area + gdk_cairo_set_source_color(cr,bg); + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + + // Set foreground color + gdk_cairo_set_source_color(cr,fg); + + // Draw char + if(attr & LIB3270_ATTR_CG) + { + switch(chr) + { + case 0xd3: // CG 0xab, plus + cairo_move_to(cr,rect->x+(rect->width/2),rect->y); + cairo_rel_line_to(cr,0,rect->height); + cairo_move_to(cr,rect->x,rect->y+(rect->height/2)); + cairo_rel_line_to(cr,rect->width,0); + break; + + case 0xa2: // CG 0x92, horizontal line + cairo_move_to(cr,rect->x,rect->y+(rect->height/2)); + cairo_rel_line_to(cr,rect->width,0); + break; + + case 0x85: // CG 0x184, vertical line + cairo_move_to(cr,rect->x+(rect->width/2),rect->y); + cairo_rel_line_to(cr,0,rect->height); + break; + + case 0xd4: // CG 0xac, LR corner + cairo_move_to(cr,rect->x, rect->y+(rect->height/2)); + cairo_rel_line_to(cr,rect->width/2,0); + cairo_rel_line_to(cr,0,-(rect->height/2)); + break; + + case 0xd5: // CG 0xad, UR corner + cairo_move_to(cr,rect->x, rect->y+(rect->height/2)); + cairo_rel_line_to(cr,rect->width/2,0); + cairo_rel_line_to(cr,0,rect->height/2); + break; + + case 0xc5: // CG 0xa4, UL corner + cairo_move_to(cr,rect->x+rect->width,rect->y+(rect->height/2)); + cairo_rel_line_to(cr,-(rect->width/2),0); + cairo_rel_line_to(cr,0,(rect->height/2)); + break; + + case 0xc4: // CG 0xa3, LL corner + cairo_move_to(cr,rect->x+rect->width,rect->y+(rect->height/2)); + cairo_rel_line_to(cr,-(rect->width/2),0); + cairo_rel_line_to(cr,0,-(rect->height/2)); + break; + + case 0xc6: // CG 0xa5, left tee + cairo_move_to(cr,rect->x+(rect->width/2),rect->y+(rect->height/2)); + cairo_rel_line_to(cr,rect->width/2,0); + cairo_move_to(cr,rect->x+(rect->width/2),rect->y); + cairo_rel_line_to(cr,0,rect->height); + break; + + case 0xd6: // CG 0xae, right tee + cairo_move_to(cr,rect->x+(rect->width/2),rect->y+(rect->height/2)); + cairo_rel_line_to(cr,-(rect->width/2),0); + cairo_move_to(cr,rect->x+(rect->width/2),rect->y); + cairo_rel_line_to(cr,0,rect->height); + break; + + case 0xc7: // CG 0xa6, bottom tee + cairo_move_to(cr,rect->x+(rect->width/2),rect->y+(rect->height/2)); + cairo_rel_line_to(cr,0,-(rect->height/2)); + cairo_move_to(cr,rect->x,rect->y+(rect->height/2)); + cairo_rel_line_to(cr,rect->width,0); + break; + + case 0xd7: // CG 0xaf, top tee + cairo_move_to(cr,rect->x+(rect->width/2),rect->y+(rect->height/2)); + cairo_rel_line_to(cr,0,rect->height/2); + cairo_move_to(cr,rect->x,rect->y+(rect->height/2)); + cairo_rel_line_to(cr,rect->width,0); + break; + + case 0x8c: // CG 0xf7, less or equal "≤" + cairo_move_to(cr,rect->x,rect->y+height); + cairo_show_text(cr, "≤"); + break; + + case 0xae: // CG 0xd9, greater or equal "≥" + cairo_move_to(cr,rect->x,rect->y+height); + cairo_show_text(cr, "≥"); + break; + + case 0xbe: // CG 0x3e, not equal "≠" + cairo_move_to(cr,rect->x,rect->y+height); + cairo_show_text(cr, "≠"); + break; + + case 0xad: // "[" + cairo_move_to(cr,rect->x,rect->y+height); + cairo_show_text(cr, "["); + break; + + case 0xbd: // "]" + cairo_move_to(cr,rect->x,rect->y+height); + cairo_show_text(cr, "]"); + break; + + default: + cairo_rectangle(cr, rect->x+1, rect->y+1, rect->width-2, rect->height-2); + } + } + else if(chr) + { + gchar *utf = g_convert((char *) &chr, 1, "UTF-8", lib3270_get_charset(session), NULL, NULL, NULL); + + if(utf) + { + cairo_move_to(cr,rect->x,rect->y+height); + cairo_show_text(cr, utf); + g_free(utf); + } + } + cairo_stroke(cr); +} + +void v3270_reload(GtkWidget *widget) +{ + v3270 * terminal = GTK_V3270(widget); + +#if GTK_CHECK_VERSION(3,0,0) + gint width = gtk_widget_get_allocated_width(widget); + gint height = gtk_widget_get_allocated_height(widget); +#else + gint width = terminal->width; + gint height = terminal->height; +#endif + + GdkRectangle rect; + int addr, cursor, r, rows, cols; + + cairo_t * cr; + + if(!gtk_widget_get_realized(widget)) + return; + + // Create new terminal image + if(terminal->surface) + cairo_surface_destroy(terminal->surface); + + terminal->surface = (cairo_surface_t *) gdk_window_create_similar_surface(gtk_widget_get_window(widget),CAIRO_CONTENT_COLOR,width,height); + + // Update the created image + cr = cairo_create(terminal->surface); + v3270_update_font_metrics(terminal, cr, width, height); + + gdk_cairo_set_source_color(cr,terminal->color+V3270_COLOR_BACKGROUND); + cairo_rectangle(cr, 0, 0, width, height); + cairo_fill(cr); + cairo_stroke(cr); + + // Draw terminal contents + lib3270_get_screen_size(terminal->host,&rows,&cols); + + memset(&rect,0,sizeof(rect)); + rect.y = terminal->metrics.top; + rect.width = terminal->metrics.width; + rect.height = terminal->metrics.spacing; + addr = 0; + cursor = lib3270_get_cursor_address(terminal->host); + + for(r = 0; r < rows; r++) + { + int c; + + rect.x = terminal->metrics.left; + + for(c=0;c < cols;c++) + { + unsigned char chr = 0; + unsigned short attr; + + lib3270_get_contents(terminal->host,addr,addr,&chr,&attr); + + if(addr == cursor) + v3270_update_cursor_rect(terminal,&rect,chr,attr); + + v3270_draw_element(cr,chr,attr,terminal->host,terminal->metrics.height,&rect,terminal->color); + + addr++; + rect.x += rect.width; + } + + rect.y += terminal->metrics.spacing; + + } + + v3270_draw_oia(cr, terminal->host, rect.y, cols, &terminal->metrics, terminal->color,terminal->oia_rect); + + cairo_destroy(cr); + +} + +void v3270_update_char(H3270 *session, int addr, unsigned char chr, unsigned short attr, unsigned char cursor) +{ + v3270 * terminal = GTK_V3270(session->widget); + cairo_t * cr; + GdkRectangle rect; + int rows,cols; + + if(!gtk_widget_get_realized(GTK_WIDGET(terminal))) + return; + + if(!terminal->surface) + { + v3270_reload(GTK_WIDGET(terminal)); + gtk_widget_queue_draw(GTK_WIDGET(terminal)); + return; + } + + lib3270_get_screen_size(terminal->host,&rows,&cols); + + memset(&rect,0,sizeof(rect)); + rect.x = terminal->metrics.left + ((addr % cols) * terminal->metrics.width); + rect.y = terminal->metrics.top + ((addr / cols) * terminal->metrics.spacing); + rect.width = terminal->metrics.width; + rect.height = terminal->metrics.spacing; + +// trace("%s: c=%c attr=%04x addr=%d pos=%d,%d x=%d y=%d w=%d h=%d",__FUNCTION__,chr,(int) attr,addr,(addr / cols),(addr % cols),rect.x,rect.y,rect.width,rect.height); + + cr = cairo_create(terminal->surface); + cairo_set_scaled_font(cr,terminal->font_scaled); + v3270_draw_element(cr, chr, attr, terminal->host, terminal->metrics.height, &rect,terminal->color); + cairo_destroy(cr); + + if(cursor) + v3270_update_cursor_rect(terminal,&rect,chr,attr); + + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),rect.x,rect.y,rect.width,rect.height); + +} + +void v3270_update_cursor_surface(v3270 *widget,unsigned char chr,unsigned short attr) +{ + if(widget->cursor.surface) + { + GdkRectangle rect = widget->cursor.rect; + cairo_t * cr = cairo_create(widget->cursor.surface); + GdkColor * fg; + GdkColor * bg; + + get_element_colors(attr,&fg,&bg,widget->color); + + cairo_set_scaled_font(cr,widget->font_scaled); + + rect.x = 0; + rect.y = 0; + v3270_draw_char(cr,chr,attr,widget->host,widget->metrics.height,&rect,bg,fg); + + cairo_destroy(cr); + } + + +} + +void v3270_update_cursor_rect(v3270 *widget, GdkRectangle *rect, unsigned char chr, unsigned short attr) +{ + widget->cursor.chr = chr; + widget->cursor.rect = *rect; + widget->cursor.attr = attr; + widget->cursor.rect.height = widget->metrics.height + widget->metrics.descent; + v3270_update_cursor_surface(widget,chr,attr); +} + diff --git a/genmarshal b/genmarshal new file mode 100644 index 0000000..d615b87 --- /dev/null +++ b/genmarshal @@ -0,0 +1,11 @@ +VOID:VOID +VOID:VOID,ENUM,BOOL,POINTER +VOID:VOID,ENUM +VOID:VOID,POINTER +VOID:POINTER +VOID:VOID,POINTER,POINTER +VOID:VOID,UINT,POINTER +BOOL:VOID,UINT,ENUM +VOID:VOID,BOOL +BOOL:VOID,BOOL,BOOL,POINTER +VOID:VOID,UINT,UINT diff --git a/iocallback.c b/iocallback.c new file mode 100644 index 0000000..ab42921 --- /dev/null +++ b/iocallback.c @@ -0,0 +1,349 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como iocallback.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * licinio@bb.com.br (Licínio Luis Branco) + * kraucer@bb.com.br (Kraucer Fernandes Mazuco) + * + */ + +#if defined(_WIN32) /*[*/ + #include +#elif defined(__APPLE__) + #include + #include +#else + #include + #include +#endif /*]*/ + +#include +#include +#include "../globals.h" + +#ifdef HAVE_MALLOC_H + #include +#endif + +static int static_CallAndWait(int(*callback)(H3270 *session, void *), H3270 *session, void *parm); +static unsigned long static_AddInput(int source, H3270 *session, void (*fn)(H3270 *session)); +static void static_RemoveSource(unsigned long id); + +#if !defined(_WIN32) /*[*/ +static unsigned long static_AddOutput(int source, H3270 *session, void (*fn)(H3270 *session)); +#endif + +static unsigned long static_AddExcept(int source, H3270 *session, void (*fn)(H3270 *session)); +static unsigned long static_AddTimeOut(unsigned long interval_ms, H3270 *session, void (*proc)(H3270 *session)); +static void static_RemoveTimeOut(unsigned long timer); +static int static_Sleep(int seconds); +static int static_RunPendingEvents(int wait); + +static gboolean IO_prepare(GSource *source, gint *timeout); +static gboolean IO_check(GSource *source); +static gboolean IO_dispatch(GSource *source, GSourceFunc callback, gpointer user_data); +static void IO_finalize(GSource *source); /* Can be NULL */ +static gboolean IO_closure(gpointer data); + +/*---[ Structs ]-------------------------------------------------------------------------------------------*/ + + typedef struct _IO_Source + { + GSource gsrc; + GPollFD poll; + int source; + void (*fn)(H3270 *session); + H3270 *session; + } IO_Source; + + typedef struct _timer + { + unsigned char remove; + void (*fn)(H3270 *session); + H3270 *session; + } TIMER; + + static GSourceFuncs IOSources = + { + IO_prepare, + IO_check, + IO_dispatch, + IO_finalize, + IO_closure, + NULL + }; + +/*---[ Implement ]-----------------------------------------------------------------------------------------*/ + +static unsigned long AddSource(int source, H3270 *session, gushort events, void (*fn)(H3270 *session)) +{ + IO_Source *src = (IO_Source *) g_source_new(&IOSources,sizeof(IO_Source)); + + src->source = source; + src->fn = fn; + src->poll.fd = source; + src->poll.events = events; + + g_source_attach((GSource *) src,NULL); + g_source_add_poll((GSource *) src,&src->poll); + + return (unsigned long) src; +} + +static unsigned long static_AddInput(int source, H3270 *session, void (*fn)(H3270 *session)) +{ + return AddSource(source,session,G_IO_IN|G_IO_HUP|G_IO_ERR,fn); +} + +static void static_RemoveSource(unsigned long id) +{ + if(id) + g_source_destroy((GSource *) id); +} + +#if !defined(_WIN32) /*[*/ +static unsigned long static_AddOutput(int source, H3270 *session, void (*fn)(H3270 *session)) +{ + return AddSource(source,session,G_IO_OUT|G_IO_HUP|G_IO_ERR,fn); +} +#endif /*]*/ + +static unsigned long static_AddExcept(int source, H3270 *session, void (*fn)(H3270 *session)) +{ +#if defined(_WIN32) /*[*/ + return 0; +#else + return AddSource(source,session,G_IO_HUP|G_IO_ERR,fn); +#endif +} + +static gboolean do_timer(TIMER *t) +{ + if(!t->remove) + t->fn(t->session); + return FALSE; +} + +static unsigned long static_AddTimeOut(unsigned long interval, H3270 *session, void (*proc)(H3270 *session)) +{ + TIMER *t = g_malloc(sizeof(TIMER)); + + t->remove = 0; + t->fn = proc; + t->session = session; + + g_timeout_add_full(G_PRIORITY_DEFAULT, (guint) interval, (GSourceFunc) do_timer, t, g_free); + + return (unsigned long) t; +} + +static void static_RemoveTimeOut(unsigned long timer) +{ + // FIXME (perry#2#): It this really necessary? The timeout is removed as soon as it ticks. + ((TIMER *) timer)->remove++; +} + +static gboolean IO_prepare(GSource *source, gint *timeout) +{ + /* + * Called before all the file descriptors are polled. + * If the source can determine that it is ready here + * (without waiting for the results of the poll() call) + * it should return TRUE. + * + * It can also return a timeout_ value which should be the maximum + * timeout (in milliseconds) which should be passed to the poll() call. + * The actual timeout used will be -1 if all sources returned -1, + * or it will be the minimum of all the timeout_ values + * returned which were >= 0. + * + */ + return 0; +} + +static gboolean IO_check(GSource *source) +{ + /* + * Called after all the file descriptors are polled. + * The source should return TRUE if it is ready to be dispatched. + * Note that some time may have passed since the previous prepare + * function was called, so the source should be checked again here. + * + */ +#if defined(_WIN32) /*[*/ + + if(WaitForSingleObject((HANDLE) ((IO_Source *) source)->source,0) == WAIT_OBJECT_0) + return TRUE; + +#else /*][*/ + + struct pollfd fds; + + memset(&fds,0,sizeof(fds)); + + fds.fd = ((IO_Source *) source)->poll.fd; + fds.events = ((IO_Source *) source)->poll.events; + + if(poll(&fds,1,0) > 0) + return TRUE; + +#endif /*]*/ + + return FALSE; +} + +static gboolean IO_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) +{ + /* + * Called to dispatch the event source, + * after it has returned TRUE in either its prepare or its check function. + * The dispatch function is passed in a callback function and data. + * The callback function may be NULL if the source was never connected + * to a callback using g_source_set_callback(). The dispatch function + * should call the callback function with user_data and whatever additional + * parameters are needed for this type of event source. + */ + ((IO_Source *) source)->fn(((IO_Source *) source)->session); + return TRUE; +} + +static void IO_finalize(GSource *source) +{ + +} + +static gboolean IO_closure(gpointer data) +{ + return 0; +} + +struct bgParameter +{ + gboolean running; + H3270 *session; + int rc; + int(*callback)(H3270 *session, void *); + void *parm; + +}; + +gpointer BgCall(struct bgParameter *p) +{ + trace("%s starts",__FUNCTION__); + p->rc = p->callback(p->session, p->parm); + p->running = FALSE; + trace("%s ends",__FUNCTION__); + return 0; +} + +static int static_CallAndWait(int(*callback)(H3270 *session, void *), H3270 *session, void *parm) +{ + struct bgParameter p = { TRUE, session, -1, callback, parm }; + GThread *thread; + + trace("Starting auxiliary thread for callback %p",callback); + + p.running = TRUE; + thread = g_thread_create( (GThreadFunc) BgCall, &p, 0, NULL); + + if(!thread) + { + g_error("Can't start background thread"); + return -1; + } + + while(p.running) + gtk_main_iteration(); + + return p.rc; +} + +static int static_Sleep(int seconds) +{ + time_t end = time(0) + seconds; + + while(time(0) < end) + gtk_main_iteration(); + + return 0; +} + +static int static_RunPendingEvents(int wait) +{ + int rc = 0; + while(gtk_events_pending()) + { + rc = 1; + gtk_main_iteration(); + } + + if(wait) + gtk_main_iteration(); + + return rc; +} + +static void beep(H3270 *session) +{ + gdk_beep(); +} + +void v3270_register_io_handlers(v3270Class *cls) +{ + static const struct lib3270_callbacks hdl = + { + sizeof(struct lib3270_callbacks), + + static_AddTimeOut, + static_RemoveTimeOut, + + static_AddInput, + static_RemoveSource, + + static_AddExcept, + +#if !defined(_WIN32) + static_AddOutput, +#endif + +#ifdef G_THREADS_ENABLED + static_CallAndWait, +#else + NULL, +#endif + + static_Sleep, + static_RunPendingEvents, + beep + + }; + + if(lib3270_register_handlers(&hdl)) + { + g_error("%s",_( "Can't set lib3270 I/O handlers" ) ); + } + + trace("%s: I/O handlers OK",__FUNCTION__); +} diff --git a/keyboard.c b/keyboard.c new file mode 100644 index 0000000..6fe3087 --- /dev/null +++ b/keyboard.c @@ -0,0 +1,241 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como keyboard.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * licinio@bb.com.br (Licínio Luis Branco) + * kraucer@bb.com.br (Kraucer Fernandes Mazuco) + * macmiranda@bb.com.br (Marco Aurélio Caldas Miranda) + * + */ + + #include + #include + #include + #include + #include + #include + + #include "v3270.h" + #include "private.h" + +#if GTK_CHECK_VERSION(3,0,0) + #include +#else + #include +#endif + +#ifndef GDK_ALT_MASK + #define GDK_ALT_MASK GDK_MOD1_MASK +#endif + +#ifndef GDK_NUMLOCK_MASK + #define GDK_NUMLOCK_MASK GDK_MOD2_MASK +#endif + + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + + #define keyval_is_alt() (event->keyval == GDK_Alt_L || event->keyval == GDK_Meta_L || event->keyval == GDK_ISO_Level3_Shift) + + static void update_keyboard_state(v3270 *terminal, GdkEventKey *event, gboolean status) + { + if(event->keyval == GDK_Shift_R || event->keyval == GDK_Shift_L) + { + if(status) + terminal->keyflags |= KEY_FLAG_SHIFT; + else + terminal->keyflags &= ~KEY_FLAG_SHIFT; + v3270_draw_shift_status(terminal); + } + + if(keyval_is_alt()) + { + if(status) + terminal->keyflags |= KEY_FLAG_ALT; + else + terminal->keyflags &= ~KEY_FLAG_ALT; + v3270_draw_alt_status(terminal); + } + + } + + static gboolean check_keypress(v3270 *widget, GdkEventKey *event) + { + static const struct _keycode + { + guint keyval; + GdkModifierType state; + int (*exec)(H3270 *session); + } keycode[] = + { + { GDK_Left, 0, lib3270_cursor_left }, + { GDK_Up, 0, lib3270_cursor_up }, + { GDK_Right, 0, lib3270_cursor_right }, + { GDK_Down, 0, lib3270_cursor_down }, + { GDK_Tab, 0, lib3270_tab }, + { GDK_ISO_Left_Tab, GDK_SHIFT_MASK, lib3270_backtab }, + { GDK_KP_Left, 0, lib3270_cursor_left }, + { GDK_KP_Up, 0, lib3270_cursor_up }, + { GDK_KP_Right, 0, lib3270_cursor_right }, + { GDK_KP_Down, 0, lib3270_cursor_down }, + + { GDK_KP_Add, GDK_NUMLOCK_MASK, NULL }, + { GDK_KP_Subtract, GDK_NUMLOCK_MASK, NULL }, + + { GDK_3270_PrintScreen, 0, NULL }, + { GDK_Sys_Req, 0, lib3270_sysreq }, + + { GDK_Print, GDK_CONTROL_MASK, NULL }, + { GDK_Print, GDK_SHIFT_MASK, lib3270_sysreq }, + { GDK_Control_R, 0, NULL }, + { GDK_Control_L, 0, NULL }, + +#ifdef WIN32 + { GDK_Pause, 0, NULL }, +#endif + }; + + int f; + int state = event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK); + gboolean handled = FALSE; + +#ifdef WIN32 + // FIXME (perry#1#): Find a better way! + if( event->keyval == 0xffffff && event->hardware_keycode == 0x0013) + event->keyval = GDK_Pause; + + // Windows sets in left/right control + else if(state & GDK_CONTROL_MASK && (event->keyval == GDK_Control_R || event->keyval == GDK_Control_L)) + state &= ~GDK_CONTROL_MASK; +#endif + + g_signal_emit(GTK_WIDGET(widget), v3270_widget_signal[SIGNAL_KEYPRESS], 0, event->keyval, state, &handled); + if(handled) + return TRUE; + + if(event->keyval >= GDK_F1 && event->keyval <= GDK_F12 && !(state & (GDK_CONTROL_MASK|GDK_ALT_MASK))) + { + int pfcode = (event->keyval - GDK_F1) + ((state & GDK_SHIFT_MASK) ? 13 : 1); + if(pfcode > 0 && pfcode < 25) + { + lib3270_pfkey(widget->host,pfcode); + return TRUE; + } + } + + for(f=0; f < G_N_ELEMENTS(keycode);f++) + { + if(keycode[f].keyval == event->keyval && state == keycode[f].state) + { + if(keycode[f].exec) + { + keycode[f].exec(widget->host); + return TRUE; + } + } + } + + return FALSE; + } + + gboolean v3270_key_press_event(GtkWidget *widget, GdkEventKey *event) + { + v3270 * terminal = GTK_V3270(widget); + + update_keyboard_state(terminal,event,TRUE); + + if(gtk_im_context_filter_keypress(terminal->input_method,event)) + return TRUE; + + if(check_keypress(terminal,event)) + { + gtk_im_context_reset(terminal->input_method); + return TRUE; + } + + return FALSE; + + } + + gboolean v3270_key_release_event(GtkWidget *widget, GdkEventKey *event) + { + v3270 * terminal = GTK_V3270(widget); + + update_keyboard_state(terminal,event,FALSE); + + if(gtk_im_context_filter_keypress(terminal->input_method,event)) + return TRUE; + + return FALSE; + + } + + void v3270_tab(GtkWidget *widget) + { + g_return_if_fail(GTK_IS_V3270(widget)); + lib3270_tab(GTK_V3270(widget)->host); + } + + void v3270_backtab(GtkWidget *widget) + { + g_return_if_fail(GTK_IS_V3270(widget)); + lib3270_backtab(GTK_V3270(widget)->host); + } + + void v3270_set_string(GtkWidget *widget, const gchar *str) + { + H3270 *host; + gchar *utf; + + g_return_if_fail(GTK_IS_V3270(widget)); + + host = GTK_V3270(widget)->host; + + utf = g_convert((char *) str, -1, lib3270_get_charset(host), "UTF-8", NULL, NULL, NULL); + + if(utf) + { + lib3270_set_string(host, (const unsigned char *) utf); + g_free(utf); + } + + } + + void v3270_key_commit(GtkIMContext *imcontext, gchar *str, v3270 *widget) + { + gchar *utf = g_convert((char *) str, -1, lib3270_get_charset(widget->host), "UTF-8", NULL, NULL, NULL); + + if(utf) + { + lib3270_set_string(GTK_V3270(widget)->host, (const unsigned char *) utf); + g_free(utf); + } + else + { + lib3270_ring_bell(widget->host); + } + } + + diff --git a/locked.xbm b/locked.xbm new file mode 100644 index 0000000..039a355 --- /dev/null +++ b/locked.xbm @@ -0,0 +1,14 @@ +#define locked_width 32 +#define locked_height 32 +static unsigned char locked_bits[] = { + 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x07, 0xe0, 0x00, + 0x80, 0x03, 0xc0, 0x01, 0xc0, 0xf1, 0x8f, 0x03, 0xc0, 0xf8, 0x1f, 0x03, + 0xc0, 0x1c, 0x38, 0x03, 0xc0, 0x0c, 0x30, 0x03, 0xc0, 0x0c, 0x30, 0x03, + 0xc0, 0x0c, 0x30, 0x03, 0xc0, 0x0c, 0x30, 0x03, 0xc0, 0x0c, 0x30, 0x03, + 0xc0, 0x0c, 0x30, 0x03, 0xc0, 0x0c, 0x30, 0x03, 0xf0, 0xff, 0xff, 0x0f, + 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0xcc, 0xcc, 0x0c, 0xf0, 0xcc, 0xcc, 0x0c, + 0x30, 0x33, 0x33, 0x0f, 0x30, 0x33, 0x33, 0x0f, 0xf0, 0xcc, 0xcc, 0x0c, + 0xf0, 0xcc, 0xcc, 0x0c, 0x30, 0x33, 0x33, 0x0f, 0x30, 0x33, 0x33, 0x0f, + 0xf0, 0xcc, 0xcc, 0x0c, 0xf0, 0xcc, 0xcc, 0x0c, 0x30, 0x33, 0x33, 0x0f, + 0x30, 0x33, 0x33, 0x0f, 0xf0, 0xcc, 0xcc, 0x0c, 0xf0, 0xcc, 0xcc, 0x0c, + 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x0f }; diff --git a/mouse.c b/mouse.c new file mode 100644 index 0000000..1318739 --- /dev/null +++ b/mouse.c @@ -0,0 +1,263 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como mouse.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + + #include + #include + #include + #include "v3270.h" + #include "private.h" + #include + #include + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + +gint v3270_get_offset_at_point(v3270 *widget, gint x, gint y) +{ + GdkPoint point; + int r,c; + + if(x > 0 && y > 0) + { + point.x = ((x-widget->metrics.left)/widget->metrics.width); + point.y = ((y-widget->metrics.top)/widget->metrics.spacing); + + lib3270_get_screen_size(widget->host,&r,&c); + + if(point.x >= 0 && point.y >= 0 && point.x < c && point.y < r) + return (point.y * c) + point.x; + } + + return -1; +} + +static void single_click(v3270 *widget, int baddr) +{ + switch(lib3270_get_selection_flags(widget->host,baddr)) + { + case 0x00: + // Unselected area, move cursor and remove selection + lib3270_set_cursor_address(widget->host,baddr); + lib3270_unselect(widget->host); + widget->selecting = 1; + break; + + + default: + // Move selected area + trace("%s: default action",__FUNCTION__); + widget->selection_addr = baddr; + widget->moving = 1; + } + + +} + +static void button_1_press(GtkWidget *widget, GdkEventType type, int baddr) +{ + switch(type) + { + case GDK_BUTTON_PRESS: // Single click - set mode + single_click(GTK_V3270(widget),baddr); + break; + + case GDK_2BUTTON_PRESS: // Double click - Select word + if(lib3270_select_word_at(GTK_V3270(widget)->host,baddr)); + lib3270_ring_bell(GTK_V3270(widget)->host); + break; + + case GDK_3BUTTON_PRESS: // Triple clock - Select field + if(lib3270_select_field_at(GTK_V3270(widget)->host,baddr)) + lib3270_ring_bell(GTK_V3270(widget)->host); + break; + +#ifdef DEBUG + default: + trace("Unexpected button 1 type %d",type); +#endif + } +} + +void v3270_emit_popup(v3270 *widget, int baddr, GdkEventButton *event) +{ + unsigned char chr = 0; + unsigned short attr; + gboolean handled = FALSE; + + lib3270_get_contents(widget->host,baddr,baddr,&chr,&attr); + + g_signal_emit(GTK_WIDGET(widget), v3270_widget_signal[SIGNAL_POPUP], 0, + (attr & LIB3270_ATTR_SELECTED) ? TRUE : FALSE, + lib3270_connected(widget->host) ? TRUE : FALSE, + event, + &handled); + + if(handled) + return; + + gdk_beep(); +} + +gboolean v3270_button_press_event(GtkWidget *widget, GdkEventButton *event) +{ + int baddr = v3270_get_offset_at_point(GTK_V3270(widget),event->x,event->y); + + if(baddr < 0) + return FALSE; + +// trace("%s button=%d type=%d",__FUNCTION__,event->button,event->type); + + switch(event->button) + { + case 1: // Left button + button_1_press(widget,event->type,baddr); + break; + + case 3: // Right button + if(event->type == GDK_BUTTON_PRESS) + v3270_emit_popup(GTK_V3270(widget),baddr,event); + break; + + default: + trace("%s button=%d type=%d",__FUNCTION__,event->button,event->type); + } + + return FALSE; +} + +gboolean v3270_button_release_event(GtkWidget *widget, GdkEventButton*event) +{ + switch(event->button) + { + case 1: + GTK_V3270(widget)->selecting = 0; + GTK_V3270(widget)->moving = 0; + GTK_V3270(widget)->resizing = 0; + break; + + default: + trace("%s button=%d type=%d",__FUNCTION__,event->button,event->type); + } + + + return FALSE; +} + + +static void update_mouse_pointer(GtkWidget *widget, int baddr) +{ + v3270 *terminal = GTK_V3270(widget); + + if(baddr >= 0 && terminal->pointer_id == LIB3270_CURSOR_EDITABLE) + { + int id = terminal->pointer; + + switch(lib3270_get_selection_flags(terminal->host,baddr) & 0x8f) + { + case 0x80: + id = V3270_CURSOR_MOVE_SELECTION; + break; + + case 0x82: + id = V3270_CURSOR_SELECTION_TOP; + break; + + case 0x86: + id = V3270_CURSOR_SELECTION_TOP_RIGHT; + break; + + case 0x84: + id = V3270_CURSOR_SELECTION_RIGHT; + break; + + case 0x81: + id = V3270_CURSOR_SELECTION_LEFT; + break; + + case 0x89: + id = V3270_CURSOR_SELECTION_BOTTOM_LEFT; + break; + + case 0x88: + id = V3270_CURSOR_SELECTION_BOTTOM; + break; + + case 0x8c: + id = V3270_CURSOR_SELECTION_BOTTOM_RIGHT; + break; + + case 0x83: + id = V3270_CURSOR_SELECTION_TOP_LEFT; + break; + + default: + id = lib3270_is_protected(terminal->host,baddr) ? V3270_CURSOR_PROTECTED : V3270_CURSOR_UNPROTECTED; + + } + + gdk_window_set_cursor(gtk_widget_get_window(widget),v3270_cursor[id]); + } + +} + +void v3270_update_mouse_pointer(GtkWidget *widget) +{ + gint x, y; + +#if GTK_CHECK_VERSION(3,4,0) + #warning Implement gdk_window_get_device_position +#endif // GTK(3,4,0) + + gtk_widget_get_pointer(widget,&x,&y); + update_mouse_pointer(widget,v3270_get_offset_at_point(GTK_V3270(widget),x,y)); +} + +gboolean v3270_motion_notify_event(GtkWidget *widget, GdkEventMotion *event) +{ + v3270 * terminal = GTK_V3270(widget); + int baddr = v3270_get_offset_at_point(terminal,event->x,event->y); + + if(baddr >= 0) + { + if(terminal->selecting) // Select region + { + lib3270_select_to(terminal->host,baddr); + } + if(terminal->moving) // Move selected area + { + terminal->selection_addr = lib3270_drag_selection(terminal->host,terminal->pointer,terminal->selection_addr,baddr); + } + else + { + terminal->pointer = lib3270_get_selection_flags(terminal->host,baddr); + update_mouse_pointer(widget,baddr); + } + } + + return FALSE; +} diff --git a/oia.c b/oia.c new file mode 100644 index 0000000..9435051 --- /dev/null +++ b/oia.c @@ -0,0 +1,1032 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como oia.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + + #include + #include + #include + #include + #include + #include + + #ifdef HAVE_LIBM + #include + #endif // HAVE_LIBM + + #include "v3270.h" + #include "private.h" + +/*--[ Prototipes ]-----------------------------------------------------------------------------------*/ + +static void draw_cursor_position(cairo_t *cr, GdkRectangle *rect, struct v3270_metrics *metrics, int row, int col); + +/*--[ Statics ]--------------------------------------------------------------------------------------*/ + + #include "locked.xbm" + #include "unlocked.xbm" + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + +static void short2string(char *ptr, unsigned short vlr, size_t sz) +{ + int f; + + for(f=sz-1;f>=0;f--) + { + ptr[f] = '0'+(vlr%10); + vlr /= 10; + } +} + + +#ifdef HAVE_LIBM +static gint draw_spinner(cairo_t *cr, GdkRectangle *r, GdkColor *color, gint step) +{ + static const guint num_steps = 10; + + gdouble dx = r->width/2; + gdouble dy = r->height/2; + gdouble radius = MIN (r->width / 2, r->height / 2); + gdouble half = num_steps / 2; + gint i; + + cairo_save(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + + cairo_rectangle(cr, r->x, r->y, r->width, r->height); + cairo_clip(cr); + cairo_translate(cr, r->x, r->y); + + step++; + step %= num_steps; + + for (i = 0; i < num_steps; i++) + { + gint inset = 0.7 * radius; + + /* transparency is a function of time and intial value */ + gdouble t = (gdouble) ((i + num_steps - step) % num_steps) / num_steps; + + cairo_save(cr); + + cairo_set_source_rgba (cr, + color[V3270_COLOR_OIA_SPINNER].red / 65535., + color[V3270_COLOR_OIA_SPINNER].green / 65535., + color[V3270_COLOR_OIA_SPINNER].blue / 65535., + t); + + cairo_set_line_width (cr, 2.0); + cairo_move_to (cr, + dx + (radius - inset) * cos (i * G_PI / half), + dy + (radius - inset) * sin (i * G_PI / half)); + cairo_line_to (cr, + dx + radius * cos (i * G_PI / half), + dy + radius * sin (i * G_PI / half)); + cairo_stroke (cr); + + cairo_restore (cr); + } + + cairo_restore(cr); + + return step; +} +#endif // HAVE_LIBM + +static void setup_cursor_position(GdkRectangle *rect, struct v3270_metrics *metrics, cairo_t *cr, H3270 *host, int cols, GdkColor *color) +{ + rect->width = metrics->width * 8; + rect->x -= rect->width; + + if(lib3270_get_toggle(host,LIB3270_TOGGLE_CURSOR_POS)) + { + int addr = lib3270_get_cursor_address(host); + draw_cursor_position(cr,rect,metrics,addr/cols,addr%cols); + } +} + +static void setup_timer_position(GdkRectangle *rect, struct v3270_metrics *metrics, cairo_t *cr, H3270 *host, int cols, GdkColor *color) +{ + char buffer[7]; + cairo_text_extents_t extents; + + short2string(buffer,0,2); + buffer[2] = ':'; + short2string(buffer+3,0,2); + buffer[5] = 0; + + cairo_text_extents(cr,buffer,&extents); + rect->width = ((int) extents.width + 2); + rect->x -= rect->width; +} + +static void setup_spinner_position(GdkRectangle *rect, struct v3270_metrics *metrics, cairo_t *cr, H3270 *host, int cols, GdkColor *color) +{ + rect->width = rect->height; + rect->x -= rect->width; +// draw_spinner(cr,rect,color,0); +} + +static void setup_luname_position(GdkRectangle *rect, struct v3270_metrics *metrics, cairo_t *cr, H3270 *host, int cols, GdkColor *color) +{ + const char *luname = lib3270_get_luname(host); + + rect->width *= 16; + rect->x -= rect->width; + + cairo_save(cr); + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_clip(cr); + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); +#else + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_BACKGROUND); +#endif + + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + + if(luname) + { + cairo_move_to(cr,rect->x,rect->y+metrics->height); + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_LUNAME); + cairo_show_text(cr,luname); + cairo_stroke(cr); + } + + cairo_restore(cr); + +} + +static void setup_single_char_right(GdkRectangle *rect, struct v3270_metrics *metrics, cairo_t *cr, H3270 *host, int cols, GdkColor *color) +{ + rect->x -= rect->width; + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); +#endif + +} + +static void setup_insert_position(GdkRectangle *rect, struct v3270_metrics *metrics, cairo_t *cr, H3270 *host, int cols, GdkColor *color) +{ + if(rect->width > rect->height) + { + rect->width = rect->height; + } + else if(rect->height > rect->width) + { + rect->y += (rect->height - rect->width)/2; + rect->height = rect->width; + } + + rect->x -= rect->width; + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); +#endif + +} + + + +static void setup_double_char_position(GdkRectangle *rect, struct v3270_metrics *metrics, cairo_t *cr, H3270 *host, int cols, GdkColor *color) +{ + rect->width <<= 1; + rect->x -= rect->width; + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); +#endif + +} + +static void draw_undera(cairo_t *cr, H3270 *host, struct v3270_metrics *metrics, GdkColor *color, GdkRectangle *rect) +{ +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); +#else + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_BACKGROUND); +#endif + + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + + if(lib3270_get_undera(host)) + { + const gchar *chr = lib3270_in_e(host) ? "B" : "A"; + cairo_text_extents_t extents; + int x,y; + + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_BACKGROUND); + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_FOREGROUND); + + cairo_text_extents(cr,chr,&extents); + + x = rect->x + ((rect->width/2) - ((extents.width+extents.x_bearing)/2)); + y = rect->y + extents.height+((rect->height/2) - (extents.height/2)); + + cairo_move_to(cr,x,y); + cairo_show_text(cr,chr); + + cairo_move_to(cr,x+extents.x_bearing,y+2); + cairo_rel_line_to(cr,extents.width,0); + + cairo_stroke(cr); + + } + +} + +void v3270_draw_connection(cairo_t *cr, H3270 *host, struct v3270_metrics *metrics, GdkColor *color, GdkRectangle *rect) +{ + cairo_text_extents_t extents; + gchar *str = "?"; + + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_FOREGROUND); + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_stroke(cr); + + if(lib3270_get_oia_box_solid(host)) + { + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + return; + } + + if(lib3270_in_ansi(host)) + *str = 'N'; + else if(lib3270_in_sscp(host)) + *str = 'S'; + + cairo_text_extents(cr,str,&extents); + cairo_move_to(cr,rect->x+((rect->width/2)-(extents.width/2)),rect->y+extents.height+( (rect->height/2) - (extents.height/2))); + cairo_show_text(cr,str); + +} + +void v3270_draw_ssl_status(cairo_t *cr, H3270 *host, struct v3270_metrics *metrics, GdkColor *color, GdkRectangle *rect) +{ + cairo_surface_t * icon; + double sz = rect->width < rect->height ? rect->width : rect->height; + int idx = lib3270_get_ssl_state(host) ? 1 : 0; + + static const struct + { + unsigned short width; + unsigned short height; + unsigned char * bits; + } bitmap[] = + { + { unlocked_width, unlocked_height, unlocked_bits }, + { locked_width, locked_height, locked_bits }, + }; + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); +#else + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_BACKGROUND); +#endif + + cairo_translate(cr, rect->x, rect->y); + + cairo_rectangle(cr, 0, 0, rect->width, rect->height); + cairo_fill(cr); + + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_FOREGROUND); + + icon = cairo_image_surface_create_for_data( (unsigned char *) bitmap[idx].bits, + CAIRO_FORMAT_A1, + bitmap[idx].width,bitmap[idx].height, + cairo_format_stride_for_width(CAIRO_FORMAT_A1,locked_width)); + + cairo_scale(cr, sz / ((double) bitmap[idx].width), + sz / ((double) bitmap[idx].height)); + + cairo_mask_surface(cr,icon,(rect->width-sz)/2,(rect->height-sz)/2); + + cairo_surface_destroy(icon); + +} + +static void draw_status_message(cairo_t *cr, LIB3270_MESSAGE id, struct v3270_metrics *metrics, GdkColor *color, GdkRectangle *rect) +{ + #ifdef DEBUG + #define OIA_MESSAGE(x,c,y) { #x, c, y } + #else + #define OIA_MESSAGE(x,c,y) { c, y } + #endif + + static const struct _message + { + #ifdef DEBUG + const gchar * dbg; + #endif + enum V3270_COLOR + color; + const gchar * msg; + } message[] = + { + OIA_MESSAGE( LIB3270_MESSAGE_NONE, + V3270_COLOR_OIA_STATUS_OK, + NULL ), + + OIA_MESSAGE( LIB3270_MESSAGE_SYSWAIT, + V3270_COLOR_OIA_STATUS_OK, + N_( "X System" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_TWAIT, + V3270_COLOR_OIA_STATUS_OK, + N_( "X Wait" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_CONNECTED, + V3270_COLOR_OIA_STATUS_OK, + NULL ), + + OIA_MESSAGE( LIB3270_MESSAGE_DISCONNECTED, + V3270_COLOR_OIA_STATUS_INVALID, + N_( "X Not Connected" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_AWAITING_FIRST, + V3270_COLOR_OIA_STATUS_OK, + N_( "X" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_MINUS, + V3270_COLOR_OIA_STATUS_OK, + N_( "X -f" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_PROTECTED, + V3270_COLOR_OIA_STATUS_INVALID, + N_( "X Protected" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_NUMERIC, + V3270_COLOR_OIA_STATUS_INVALID, + N_( "X Numeric" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_OVERFLOW, + V3270_COLOR_OIA_STATUS_INVALID, + N_( "X Overflow" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_INHIBIT, + V3270_COLOR_OIA_STATUS_INVALID, + N_( "X Inhibit" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_KYBDLOCK, + V3270_COLOR_OIA_STATUS_INVALID, + N_( "X") ), + + OIA_MESSAGE( LIB3270_MESSAGE_X, + V3270_COLOR_OIA_STATUS_INVALID, + N_( "X" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_RESOLVING, + V3270_COLOR_OIA_STATUS_WARNING, + N_( "X Resolving" ) ), + + OIA_MESSAGE( LIB3270_MESSAGE_CONNECTING, + V3270_COLOR_OIA_STATUS_WARNING, + N_( "X Connecting" ) ), + + + }; + + const gchar *msg = message[0].msg; + +// trace("%s: id=%d",__FUNCTION__,id); + + if(id >= 0 && id < G_N_ELEMENTS(message)) + { + msg = message[id].msg; +#ifdef DEBUG + if(!msg) + msg = message[id].dbg; +#endif // DEBUG + } + + if(msg) + { + gdk_cairo_set_source_color(cr,color+message[id].color); + cairo_move_to(cr,rect->x,rect->y+metrics->height); + cairo_show_text(cr,gettext(msg)); + } + +} + +static void draw_insert(cairo_t *cr, H3270 *host, GdkColor *color, GdkRectangle *rect) +{ + if(lib3270_get_toggle(host,LIB3270_TOGGLE_INSERT)) + { + double y = rect->y+(rect->height-2); + + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_clip(cr); + + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_FOREGROUND); + + cairo_move_to(cr,rect->x,y); + cairo_rel_line_to(cr,rect->width/2,-(rect->height/1.7)); + cairo_line_to(cr,rect->x+rect->width,y); + cairo_stroke(cr); + } + +} + +void v3270_draw_oia(cairo_t *cr, H3270 *host, int row, int cols, struct v3270_metrics *metrics, GdkColor *color, GdkRectangle *rect) +{ + static const struct _right_fields + { + V3270_OIA_FIELD id; + void (*draw)(GdkRectangle *rect, struct v3270_metrics *metrics, cairo_t *cr, H3270 *host, int cols, GdkColor *color); + } right[] = + { + { V3270_OIA_CURSOR_POSITION, setup_cursor_position }, + { V3270_OIA_TIMER, setup_timer_position }, + { V3270_OIA_SPINNER, setup_spinner_position }, + { V3270_OIA_LUNAME, setup_luname_position }, +#ifdef X3270_PRINTER + { V3270_OIA_PRINTER, setup_single_char_right }, +#endif // X3270_PRINTER + { V3270_OIA_SCRIPT, setup_single_char_right }, + { V3270_OIA_INSERT, setup_insert_position }, + { V3270_OIA_TYPEAHEAD, setup_single_char_right }, + { V3270_OIA_SHIFT, setup_double_char_position }, +// { V3270_OIA_CAPS, setup_single_char_right }, + { V3270_OIA_ALT, setup_single_char_right }, + { V3270_OIA_SSL, setup_double_char_position }, + }; + + int f; + int rCol = metrics->left+(cols*metrics->width); + int lCol = metrics->left+1; + + row += OIA_TOP_MARGIN; + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_SEPARATOR); + cairo_rectangle(cr, metrics->left, row, cols*metrics->width, 1); + cairo_fill(cr); + + row += 2; + + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_BACKGROUND); + cairo_rectangle(cr, metrics->left, row, cols*metrics->width, metrics->spacing); + cairo_fill(cr); + + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_FOREGROUND); + + for(f=0;fx = rCol; + r->y = row; + r->width = metrics->width; + r->height = metrics->spacing; + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_FOREGROUND); + right[f].draw(r,metrics,cr,host,cols,color); + rCol = r->x - (metrics->width/3); + } + + gdk_cairo_set_source_color(cr,color+V3270_COLOR_OIA_FOREGROUND); + + const gchar *str = "4"; + cairo_text_extents_t extents; + + cairo_text_extents(cr,str,&extents); + cairo_move_to(cr,lCol+(((metrics->width+2)/2)-(extents.width/2)),row+extents.height+( (metrics->spacing/2) - (extents.height/2))); + cairo_show_text(cr,str); + + cairo_stroke(cr); + cairo_rectangle(cr, lCol, row, metrics->width+2, metrics->spacing); + cairo_stroke(cr); + + lCol += (metrics->width+5); + + // Undera indicator + rect[V3270_OIA_UNDERA].x = lCol; + rect[V3270_OIA_UNDERA].y = row; + rect[V3270_OIA_UNDERA].width = metrics->width+3; + rect[V3270_OIA_UNDERA].height = metrics->spacing; + draw_undera(cr,host,metrics,color,rect+V3270_OIA_UNDERA); + + lCol += (3 + rect[V3270_OIA_UNDERA].width); + + // Connection indicator + rect[V3270_OIA_CONNECTION].x = lCol; + rect[V3270_OIA_CONNECTION].y = row; + rect[V3270_OIA_CONNECTION].width = metrics->width+3; + rect[V3270_OIA_CONNECTION].height = metrics->spacing; + v3270_draw_connection(cr,host,metrics,color,rect+V3270_OIA_CONNECTION); + + lCol += (4 + rect[V3270_OIA_CONNECTION].width); + + memset(rect+V3270_OIA_MESSAGE,0,sizeof(GdkRectangle)); + + if(lCol < rCol) + { + GdkRectangle *r = rect+V3270_OIA_MESSAGE; + r->x = lCol; + r->y = row; + r->width = rCol - lCol; + r->height = metrics->spacing; + draw_status_message(cr,lib3270_get_program_message(host),metrics,color,r); + } + + cairo_save(cr); + v3270_draw_ssl_status(cr,host,metrics,color,rect+V3270_OIA_SSL); + cairo_restore(cr); + + cairo_save(cr); + draw_insert(cr,host,color,rect+V3270_OIA_INSERT); + cairo_restore(cr); +} + +/** + * Begin update of a specific OIA field. + * + * @param terminal 3270 terminal widget. + * @param r Rectangle to receive updated region. + * @param id Field id. + * + * @return cairo object for drawing. + * + */ +static cairo_t * set_update_region(v3270 * terminal, GdkRectangle **r, V3270_OIA_FIELD id) +{ + GdkRectangle * rect = terminal->oia_rect + id; + cairo_t * cr = cairo_create(terminal->surface); + + cairo_set_scaled_font(cr,terminal->font_scaled); + + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_clip(cr); + + *r = rect; + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); +#else + gdk_cairo_set_source_color(cr,terminal->color+V3270_COLOR_OIA_BACKGROUND); +#endif + + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + + gdk_cairo_set_source_color(cr,terminal->color+V3270_COLOR_OIA_FOREGROUND); + + return cr; +} + +void v3270_update_luname(GtkWidget *widget,const gchar *name) +{ + cairo_t * cr; + GdkRectangle * rect; + v3270 * terminal = GTK_V3270(widget); + + if(!terminal->surface) + return; + +// trace("%s",__FUNCTION__); + + cr = set_update_region(terminal,&rect,V3270_OIA_LUNAME); + + if(name) + { + cairo_move_to(cr,rect->x,rect->y+terminal->metrics.height); + gdk_cairo_set_source_color(cr,terminal->color+V3270_COLOR_OIA_LUNAME); + cairo_show_text(cr,name); + cairo_stroke(cr); + } + + cairo_destroy(cr); + + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),rect->x,rect->y,rect->width,rect->height); +} + +void v3270_update_message(v3270 *widget, LIB3270_MESSAGE id) +{ + cairo_t * cr; + GdkRectangle * rect; + + if(!widget->surface) + return; + + cr = set_update_region(widget,&rect,V3270_OIA_MESSAGE); + + draw_status_message(cr,id,&widget->metrics,widget->color,rect); + + cairo_destroy(cr); + + gtk_widget_queue_draw_area(GTK_WIDGET(widget),rect->x,rect->y,rect->width,rect->height); + + if(widget->accessible) + v3270_acessible_set_state(widget->accessible,id); +} + +static void draw_cursor_position(cairo_t *cr, GdkRectangle *rect, struct v3270_metrics *metrics, int row, int col) +{ + cairo_text_extents_t extents; + char buffer[10]; + + short2string(buffer,row+1,3); + buffer[3] = '/'; + short2string(buffer+4,col+1,3); + buffer[7] = 0; + + cairo_text_extents(cr,buffer,&extents); + + cairo_move_to(cr,(rect->x+rect->width)-(extents.width+2),rect->y+metrics->height); + cairo_show_text(cr, buffer); + cairo_stroke(cr); +} + +void v3270_update_cursor(H3270 *session, unsigned short row, unsigned short col, unsigned char c, unsigned short attr) +{ + v3270 * terminal = GTK_V3270(session->widget); + GdkRectangle saved; + + if(!terminal->surface) + return; + + // Update cursor rectangle + saved = terminal->cursor.rect; + + terminal->cursor.rect.x = terminal->metrics.left + (col * terminal->cursor.rect.width); + terminal->cursor.rect.y = terminal->metrics.top + (row * terminal->metrics.spacing); + terminal->cursor.rect.width = terminal->metrics.width; + terminal->cursor.rect.height = terminal->metrics.height+terminal->metrics.descent; + terminal->cursor.show |= 1; + + gtk_widget_queue_draw_area( GTK_WIDGET(terminal), saved.x, + saved.y, + saved.width, + saved.height); + + + v3270_update_cursor_surface(terminal,c,attr); + + gtk_widget_queue_draw_area( GTK_WIDGET(terminal), + terminal->cursor.rect.x,terminal->cursor.rect.y, + terminal->cursor.rect.width,terminal->cursor.rect.height); + + if(lib3270_get_toggle(session,LIB3270_TOGGLE_CROSSHAIR)) + { + GtkAllocation allocation; + gtk_widget_get_allocation(GTK_WIDGET(terminal), &allocation); + + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),0,saved.y+terminal->metrics.height,allocation.width,1); + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),saved.x,0,1,terminal->oia_rect->y-3); + + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),0,terminal->cursor.rect.y+terminal->metrics.height,allocation.width,1); + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),terminal->cursor.rect.x,0,1,terminal->oia_rect->y-3); + } + + if(lib3270_get_toggle(session,LIB3270_TOGGLE_CURSOR_POS)) + { + // Update OIA + GdkRectangle * rect; + cairo_t * cr; + + cr = set_update_region(terminal,&rect,V3270_OIA_CURSOR_POSITION); + + draw_cursor_position(cr,rect,&terminal->metrics,row,col); + + cairo_destroy(cr); + + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),rect->x,rect->y,rect->width,rect->height); + } + + if(terminal->accessible) + g_signal_emit_by_name(ATK_TEXT(terminal->accessible),"text-caret-moved",lib3270_get_cursor_address(session)); + +} + +struct timer_info +{ + time_t start; + time_t last; +#ifdef HAVE_LIBM + gint step; +#endif // HAVE_LIBM + v3270 * terminal; +}; + +static void release_timer(struct timer_info *info) +{ +// trace("Timer %p stops",info); + info->terminal->timer = NULL; + + if(info->terminal->surface) + { + // Erase timer info + static const int id[] = { V3270_OIA_TIMER, +#ifdef HAVE_LIBM + V3270_OIA_SPINNER +#endif // HAVE_LIBM + }; + int f; + + cairo_t *cr = cairo_create(info->terminal->surface); + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); +#else + gdk_cairo_set_source_color(cr,info->terminal->color+V3270_COLOR_OIA_BACKGROUND); +#endif + + for(f=0;fterminal->oia_rect + id[f]; + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + gtk_widget_queue_draw_area(GTK_WIDGET(info->terminal),rect->x,rect->y,rect->width,rect->height); + } + cairo_destroy(cr); + } + + g_free(info); +} + +void v3270_draw_shift_status(v3270 *terminal) +{ + GdkRectangle *r; + cairo_t *cr; + + if(!terminal->surface) + return; + + cr = set_update_region(terminal,&r,V3270_OIA_SHIFT); + cairo_translate(cr, r->x, r->y+1); + + trace("%s: %s",__FUNCTION__,(terminal->keyflags & KEY_FLAG_SHIFT) ? "Yes" : "No"); + + if(r->width > 2 && r->height > 7 && (terminal->keyflags & KEY_FLAG_SHIFT)) + { + int b,x,y,w,h,l; + int height = r->height-6; + + if(height > r->width) + { + w = r->width; + h = w*1.5; + } + else // width > height + { + h = height; + w = h/1.5; + } + + // Set image position + x = (r->width - w)/2; + y = (height - h)/2; + l = (w/3); + b = y+(w/1.5); + + cairo_move_to(cr,x+(w/2),y); + cairo_line_to(cr,x+w,b); + cairo_line_to(cr,(x+w)-l,b); + cairo_line_to(cr,(x+w)-l,y+h); + cairo_line_to(cr,x+l,y+h); + cairo_line_to(cr,x+l,b); + cairo_line_to(cr,x,b); + cairo_close_path(cr); + + cairo_stroke(cr); + + } + + cairo_destroy(cr); + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),r->x,r->y,r->width,r->height); + +} + +static void update_text_field(v3270 *terminal, gboolean flag, V3270_OIA_FIELD id, const gchar *text) +{ + GdkRectangle *r; + cairo_t *cr; + + if(!terminal->surface) + return; + + cr = set_update_region(terminal,&r,id); + cairo_translate(cr, r->x, r->y); + + if(flag) + { + cairo_move_to(cr,0,terminal->metrics.height); + cairo_show_text(cr, text); + cairo_stroke(cr); + } + + cairo_destroy(cr); + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),r->x,r->y,r->width,r->height); +} + +void v3270_draw_alt_status(v3270 *terminal) +{ + update_text_field(terminal,terminal->keyflags & KEY_FLAG_ALT,V3270_OIA_ALT,"A"); +} + +void v3270_draw_ins_status(v3270 *terminal) +{ + GdkRectangle *r; + cairo_t *cr; + + if(!terminal->surface) + return; + + cr = set_update_region(terminal,&r,V3270_OIA_INSERT); + + draw_insert(cr,terminal->host,terminal->color,r); + + cairo_destroy(cr); + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),r->x,r->y,r->width,r->height); + +} + +static gboolean update_timer(struct timer_info *info) +{ + cairo_t * cr; + time_t now = time(0); + GdkRectangle * rect; + + if(!info->terminal->surface) + return TRUE; + + cr = cairo_create(info->terminal->surface); + + if(now != info->last) + { + time_t seconds = now - info->start; + char buffer[7]; + + rect = info->terminal->oia_rect + V3270_OIA_TIMER; + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); +#else + gdk_cairo_set_source_color(cr,info->terminal->color+V3270_COLOR_OIA_BACKGROUND); +#endif + + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + + gdk_cairo_set_source_color(cr,info->terminal->color+V3270_COLOR_OIA_FOREGROUND); + + short2string(buffer,seconds/60,2); + buffer[2] = ':'; + short2string(buffer+3,seconds%60,2); + buffer[5] = 0; + + cairo_set_scaled_font(cr,info->terminal->font_scaled); + cairo_move_to(cr,rect->x,rect->y+info->terminal->metrics.height); + cairo_show_text(cr, buffer); + cairo_stroke(cr); + + info->last = now; + gtk_widget_queue_draw_area(GTK_WIDGET(info->terminal),rect->x,rect->y,rect->width,rect->height); + } + +#ifdef HAVE_LIBM + rect = info->terminal->oia_rect + V3270_OIA_SPINNER; + +#ifdef DEBUG + cairo_set_source_rgb(cr,0.1,0.1,0.1); +#else + gdk_cairo_set_source_color(cr,info->terminal->color+V3270_COLOR_OIA_BACKGROUND); +#endif + cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height); + cairo_fill(cr); + + gdk_cairo_set_source_color(cr,info->terminal->color+V3270_COLOR_OIA_FOREGROUND); + + info->step = draw_spinner(cr, rect, info->terminal->color, info->step); + gtk_widget_queue_draw_area(GTK_WIDGET(info->terminal),rect->x,rect->y,rect->width,rect->height); +#endif // HAVE_LIBM + + cairo_destroy(cr); + + return TRUE; +} + +void v3270_start_timer(GtkWidget *widget) +{ + struct timer_info *info; + v3270 *terminal = GTK_V3270(widget); + + if(terminal->timer) + { + g_source_ref(terminal->timer); + return; + } + + info = g_new0(struct timer_info,1); + info->terminal = terminal; + info->start = time(0); + + terminal->timer = g_timeout_source_new(100); + g_source_set_callback(terminal->timer,(GSourceFunc) update_timer, info, (GDestroyNotify) release_timer); + + g_source_attach(terminal->timer, NULL); + g_source_unref(terminal->timer); + + trace("Timer %p starts",info); +} + +void v3270_stop_timer(GtkWidget *widget) +{ + v3270 *terminal = GTK_V3270(widget); + + if(!terminal->timer) + return; + +// trace("Timer=%p",terminal->timer); + if(terminal->timer->ref_count < 2) + g_source_destroy(terminal->timer); + + if(terminal->timer) + g_source_unref(terminal->timer); + +} + +void v3270_update_oia(H3270 *session, LIB3270_FLAG id, unsigned char on) +{ + cairo_t *cr; + GdkRectangle *r; + + v3270 *terminal = GTK_V3270(session->widget); + + if(!terminal->surface) + return; + + switch(id) + { + case LIB3270_FLAG_BOXSOLID: + cr = set_update_region(terminal,&r,V3270_OIA_CONNECTION); + v3270_draw_connection(cr,terminal->host,&terminal->metrics,terminal->color,r); + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),r->x,r->y,r->width,r->height); + cairo_destroy(cr); + break; + + case LIB3270_FLAG_UNDERA: + cr = set_update_region(terminal,&r,V3270_OIA_UNDERA); + draw_undera(cr,terminal->host,&terminal->metrics,terminal->color,r); + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),r->x,r->y,r->width,r->height); + cairo_destroy(cr); + break; + + case LIB3270_FLAG_SECURE: + cr = set_update_region(terminal,&r,V3270_OIA_SSL); + v3270_draw_ssl_status(cr,terminal->host,&terminal->metrics,terminal->color,r); + gtk_widget_queue_draw_area(GTK_WIDGET(terminal),r->x,r->y,r->width,r->height); + cairo_destroy(cr); + break; + + case LIB3270_FLAG_TYPEAHEAD: + update_text_field(terminal,on,V3270_OIA_TYPEAHEAD,"T"); + break; + +#if defined(LIB3270_FLAG_PRINTER) && defined(X3270_PRINTER) + case LIB3270_FLAG_PRINTER: + update_text_field(terminal,on,V3270_OIA_PRINTER,"P"); + break; +#endif // LIB3270_FLAG_PRINTER + + default: + return; + } +} diff --git a/private.h b/private.h new file mode 100644 index 0000000..49024ff --- /dev/null +++ b/private.h @@ -0,0 +1,236 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como private.h e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * licinio@bb.com.br (Licínio Luis Branco) + * kraucer@bb.com.br (Kraucer Fernandes Mazuco) + * + */ + +#include + +#define ENABLE_NLS +#define GETTEXT_PACKAGE PACKAGE_NAME + +#include +#include + +#ifndef V3270_H_INCLUDED + #include "v3270.h" +#endif + +G_BEGIN_DECLS + + + struct _v3270Class + { + GtkWidgetClass parent_class; + + /* Signals */ + void (*activate)(GtkWidget *widget); + void (*toggle_changed)(v3270 *widget,LIB3270_TOGGLE toggle_id,gboolean toggle_state,const gchar *toggle_name); + void (*message_changed)(v3270 *widget, LIB3270_MESSAGE id); + void (*luname_changed)(GtkWidget *widget,const gchar *luname); + gboolean (*keypress)(GtkWidget *widget,guint keyval,GdkModifierType state); + + }; + +/*--[ Defines]---------------------------------------------------------------------------------------*/ + + #define OIA_TOP_MARGIN 2 + + #define KEY_FLAG_SHIFT 0x0001 + #define KEY_FLAG_ALT 0x0002 + + enum + { + SIGNAL_TOGGLE_CHANGED, + SIGNAL_MESSAGE_CHANGED, + SIGNAL_LUNAME_CHANGED, + SIGNAL_KEYPRESS, + SIGNAL_CONNECTED, + SIGNAL_DISCONNECTED, + SIGNAL_UPDATE_CONFIG, + SIGNAL_MODEL_CHANGED, + SIGNAL_SELECTING, + SIGNAL_POPUP, + SIGNAL_PASTENEXT, + SIGNAL_CLIPBOARD, + SIGNAL_CHANGED, + + LAST_SIGNAL + }; + +/*--[ Globals ]--------------------------------------------------------------------------------------*/ + + #define V3270_CURSOR_UNPROTECTED LIB3270_CURSOR_EDITABLE + #define V3270_CURSOR_WAITING LIB3270_CURSOR_WAITING + #define V3270_CURSOR_LOCKED LIB3270_CURSOR_LOCKED + + #define V3270_CURSOR_PROTECTED LIB3270_CURSOR_USER + #define V3270_CURSOR_MOVE_SELECTION LIB3270_CURSOR_USER+1 + #define V3270_CURSOR_SELECTION_TOP_LEFT LIB3270_CURSOR_USER+2 + #define V3270_CURSOR_SELECTION_TOP_RIGHT LIB3270_CURSOR_USER+3 + #define V3270_CURSOR_SELECTION_TOP LIB3270_CURSOR_USER+4 + #define V3270_CURSOR_SELECTION_BOTTOM_LEFT LIB3270_CURSOR_USER+5 + #define V3270_CURSOR_SELECTION_BOTTOM_RIGHT LIB3270_CURSOR_USER+6 + #define V3270_CURSOR_SELECTION_BOTTOM LIB3270_CURSOR_USER+7 + #define V3270_CURSOR_SELECTION_LEFT LIB3270_CURSOR_USER+8 + #define V3270_CURSOR_SELECTION_RIGHT LIB3270_CURSOR_USER+9 + + #define V3270_CURSOR_COUNT LIB3270_CURSOR_USER+10 + + + struct v3270_metrics + { + guint width; + guint height; + guint ascent; + guint descent; + + guint spacing; + + guint left; + guint top; + }; + +/*--[ Widget data ]----------------------------------------------------------------------------------*/ + + struct _v3270 + { + GtkWidget parent; + + // flags + int selecting : 1; /**< Selecting region */ + int moving : 1; /**< Moving selected region */ + int resizing : 1; /**< Resizing selected region */ + int table : 1; /**< Copy mode is table */ + +#if GTK_CHECK_VERSION(3,0,0) + +#else + gint width; + gint height; +#endif // GTK_CHECK_VERSION(3,0,0) + + GSource * timer; + GtkIMContext * input_method; + unsigned short keyflags; + gchar * clipboard; /**< Clipboard contents (text only) */ + + LIB3270_CURSOR pointer_id; + unsigned char pointer; /** Mouse pointer ID */ + int selection_addr; /** Selection addr */ + + // Font info + gchar * font_family; + cairo_font_weight_t font_weight; + cairo_scaled_font_t * font_scaled; + cairo_surface_t * surface; + + struct v3270_metrics metrics; + + gint minimum_width; + gint minimum_height; + + // Colors + GdkColor color[V3270_COLOR_COUNT]; /**< Terminal widget colors */ + + // Regions + GdkRectangle oia_rect[V3270_OIA_FIELD_COUNT]; + + struct + { + unsigned char show; /**< Cursor flag */ + unsigned char chr; /**< Char at cursor position */ + unsigned short attr; /**< Attribute at cursor position */ + GdkRectangle rect; /**< Cursor rectangle */ + GSource * timer; /**< Cursor blinking timer */ + cairo_surface_t * surface; /**< Cursor image */ + } cursor; + + // Acessibility + GtkAccessible * accessible; + + // lib3270 stuff + H3270 * host; /**< Related 3270 session */ + + }; + +/*--[ Globals ]--------------------------------------------------------------------------------------*/ + + G_GNUC_INTERNAL guint v3270_widget_signal[LAST_SIGNAL]; + G_GNUC_INTERNAL GdkCursor * v3270_cursor[V3270_CURSOR_COUNT]; + +/*--[ Prototipes ]-----------------------------------------------------------------------------------*/ + +const GtkWidgetClass * v3270_get_parent_class(void); + +gboolean v3270_draw(GtkWidget * widget, cairo_t * cr); +void v3270_draw_oia(cairo_t *cr, H3270 *host, int row, int cols, struct v3270_metrics *metrics, GdkColor *color, GdkRectangle *rect); +void v3270_update_mouse_pointer(GtkWidget *widget); + +#if ! GTK_CHECK_VERSION(3,0,0) + gboolean v3270_expose(GtkWidget * widget, GdkEventExpose *event); +#endif // GTK 3 + +void v3270_draw_shift_status(v3270 *terminal); +void v3270_draw_alt_status(v3270 *terminal); +void v3270_draw_ins_status(v3270 *terminal); + +void v3270_update_cursor_surface(v3270 *widget,unsigned char chr,unsigned short attr); + +void v3270_register_io_handlers(v3270Class *cls); + +void v3270_draw_char(cairo_t *cr, unsigned char chr, unsigned short attr, H3270 *session, guint height, GdkRectangle *rect, GdkColor *fg, GdkColor *bg); + +void v3270_start_timer(GtkWidget *terminal); +void v3270_stop_timer(GtkWidget *terminal); + +void v3270_draw_connection(cairo_t *cr, H3270 *host, struct v3270_metrics *metrics, GdkColor *color, GdkRectangle *rect); +void v3270_draw_ssl_status(cairo_t *cr, H3270 *host, struct v3270_metrics *metrics, GdkColor *color, GdkRectangle *rect); + +void v3270_update_char(H3270 *session, int addr, unsigned char chr, unsigned short attr, unsigned char cursor); + +void v3270_update_font_metrics(v3270 *terminal, cairo_t *cr, int width, int height); + +void v3270_update_cursor_rect(v3270 *widget, GdkRectangle *rect, unsigned char chr, unsigned short attr); + +void v3270_update_luname(GtkWidget *widget,const gchar *name); +void v3270_update_message(v3270 *widget, LIB3270_MESSAGE id); +void v3270_update_cursor(H3270 *session, unsigned short row, unsigned short col, unsigned char c, unsigned short attr); +void v3270_update_oia(H3270 *session, LIB3270_FLAG id, unsigned char on); + +// Keyboard & Mouse +gboolean v3270_key_press_event(GtkWidget *widget, GdkEventKey *event); +gboolean v3270_key_release_event(GtkWidget *widget, GdkEventKey *event); +void v3270_key_commit(GtkIMContext *imcontext, gchar *str, v3270 *widget); +gboolean v3270_button_press_event(GtkWidget *widget, GdkEventButton *event); +gboolean v3270_button_release_event(GtkWidget *widget, GdkEventButton*event); +gboolean v3270_motion_notify_event(GtkWidget *widget, GdkEventMotion *event); +void v3270_emit_popup(v3270 *widget, int baddr, GdkEventButton *event); +gint v3270_get_offset_at_point(v3270 *widget, gint x, gint y); + +G_END_DECLS diff --git a/selection.c b/selection.c new file mode 100644 index 0000000..b73f211 --- /dev/null +++ b/selection.c @@ -0,0 +1,476 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como clipboard.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + + #include + #include + #include + #include "v3270.h" + #include "private.h" + #include + +/*--[ Globals ]--------------------------------------------------------------------------------------*/ + + enum + { + CLIPBOARD_TYPE_TEXT, + }; + + static const GtkTargetEntry targets[] = + { + { "COMPOUND_TEXT", 0, CLIPBOARD_TYPE_TEXT }, + { "UTF8_STRING", 0, CLIPBOARD_TYPE_TEXT }, + }; + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + +static void clipboard_clear(GtkClipboard *clipboard, GObject *obj) +{ + trace("%s widget=%p",__FUNCTION__,obj); + +} + +static void clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection, guint target, GObject *obj) +{ + v3270 * widget = GTK_V3270(obj); + + trace("%s: widget=%p target=\"%s\"",__FUNCTION__,obj,targets[target].target); + + switch(target) + { + case CLIPBOARD_TYPE_TEXT: + if(!widget->clipboard) + lib3270_ring_bell(widget->host); + else + gtk_selection_data_set_text(selection,widget->clipboard,-1); + break; + + default: + g_warning("Unexpected clipboard type %d\n",target); + } +} + +gchar * v3270_get_text(GtkWidget *widget, int offset, int len) +{ + v3270 * terminal; + gchar * text; + char * str; + + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + + terminal = GTK_V3270(widget); + + str = lib3270_get_text(terminal->host, offset, len); + + if(!str) + return NULL; + + text = g_convert(str, -1, "UTF-8", lib3270_get_charset(terminal->host), NULL, NULL, NULL); + + free(str); + return text; +} + +/** + * Get lib3270 selection as a g_malloc buffer. + * + * @param widget Widget containing the desired section. + * + * @return NULL if error, otherwise the selected buffer contents (release with g_free). + * + */ +static gchar * v3270_get_selected(v3270 *widget) +{ + gchar *text = lib3270_get_selected(widget->host); + if(text) + { + gchar *str = g_strdup(text); + free(text); + return str; + } + return NULL; +} + +const gchar * v3270_get_selected_text(GtkWidget *widget) +{ + v3270 *terminal; + gchar *text; + + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + + terminal = GTK_V3270(widget); + + if(terminal->clipboard) + { + g_free(terminal->clipboard); + terminal->clipboard = NULL; + } + + text = v3270_get_selected(terminal); + + if(!text) + { + g_signal_emit(widget,v3270_widget_signal[SIGNAL_CLIPBOARD], 0, FALSE); + lib3270_ring_bell(terminal->host); + return NULL; + } + + if(terminal->table) + { + // Convert text to table + gchar **ln = g_strsplit(text,"\n",-1); + int width = lib3270_get_width(terminal->host); + gboolean cols[width]; + int l; + GString * buffer; + + memset(cols,0,sizeof(gboolean)*width); + + // Find column delimiters + for(l=0;ln[l];l++) + { + int c; + gchar * ptr = ln[l]; + GString * buffer; + + for(c=0;cclipboard = g_convert(text, -1, "UTF-8", lib3270_get_charset(terminal->host), NULL, NULL, NULL); + + g_free(text); + + + return terminal->clipboard; +} + +const gchar * v3270_get_copy(GtkWidget *widget) +{ + v3270 *terminal; + + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + + terminal = GTK_V3270(widget); + + return terminal->clipboard; +} + +const gchar * v3270_copy_append(GtkWidget *widget) +{ + v3270 * terminal; + char * str; + gchar * text; + gchar * clip; + + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + + terminal = GTK_V3270(widget); + + if(!terminal->clipboard) + return v3270_get_selected_text(widget); + + str = lib3270_get_selected(terminal->host); + + if(!str) + return terminal->clipboard; + + text = g_convert(str, -1, "UTF-8", lib3270_get_charset(terminal->host), NULL, NULL, NULL); + + free(str); + + clip = g_strconcat(terminal->clipboard,"\n",text,NULL); + + g_free(text); + g_free(terminal->clipboard); + + terminal->clipboard = clip; + + gtk_clipboard_set_text(gtk_widget_get_clipboard(widget,GDK_SELECTION_CLIPBOARD),terminal->clipboard,-1); + + g_signal_emit(widget,v3270_widget_signal[SIGNAL_CLIPBOARD], 0, TRUE); + + return terminal->clipboard; +} + +const gchar * v3270_copy(GtkWidget *widget, V3270_SELECT_FORMAT mode) +{ + const gchar * text; + GtkClipboard * clipboard = gtk_widget_get_clipboard(widget,GDK_SELECTION_CLIPBOARD); + + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + + GTK_V3270(widget)->table = (mode == V3270_SELECT_TABLE ? 1 : 0); + + text = v3270_get_selected_text(widget); + + if(text) + { + if(gtk_clipboard_set_with_owner( clipboard, + targets, + G_N_ELEMENTS(targets), + (GtkClipboardGetFunc) clipboard_get, + (GtkClipboardClearFunc) clipboard_clear, + G_OBJECT(widget) + )) + { + gtk_clipboard_set_can_store(clipboard,targets,1); + } + + g_signal_emit(widget,v3270_widget_signal[SIGNAL_CLIPBOARD], 0, TRUE); + } + + return text; + +} + +void v3270_paste_string(GtkWidget *widget, const gchar *text, const gchar *encoding) +{ + gchar * buffer = NULL; + H3270 * session = v3270_get_session(widget); + const gchar * charset = lib3270_get_charset(session); + gboolean next; + + if(!text) + return; + else if(g_strcasecmp(encoding,charset)) + buffer = g_convert(text, -1, charset, encoding, NULL, NULL, NULL); + else + buffer = g_strdup(text); + + if(!buffer) + { + /* Conversion failed, update special chars and try again */ + int f; + + static const struct _xlat + { + const gchar *from; + const gchar *to; + } xlat[] = + { + { "–", "-" }, + { "→", "->" }, + { "←", "<-" }, + { "©", "(c)" }, + { "↔", "<->" }, + { "™", "(TM)" }, + { "®", "(R)" }, + { "“", "\"" }, + { "”", "\"" }, + { "…", "..." }, + { "•", "*" }, + { "․", "." }, + { "·", "*" }, + + }; + + gchar *string = g_strdup(text); + + // FIXME (perry#1#): Is there any better way for a "sed" here? + for(f=0;fmessage, ln[f]); + + gtk_dialog_run(GTK_DIALOG (dialog)); + gtk_widget_destroy(dialog); + + break; + } + else + { + g_free(str); + } + + } + g_strfreev(ln); + + } + + g_free(string); + } + + if(buffer) + { + /* Remove TABS */ + gchar *ptr; + + for(ptr = buffer;*ptr;ptr++) + { + if(*ptr == '\t') + *ptr = ' '; + } + } + else + { + g_signal_emit(widget,v3270_widget_signal[SIGNAL_PASTENEXT], 0, FALSE); + return; + } + + next = lib3270_paste(session,(unsigned char *) buffer) ? TRUE : FALSE; + + trace("Pastenext is %s",next ? "On" : "Off"); + + g_free(buffer); + + g_signal_emit(widget,v3270_widget_signal[SIGNAL_PASTENEXT], 0, next); + +} + +static void text_received(GtkClipboard *clipboard, const gchar *text, GtkWidget *widget) +{ + v3270_paste_string(widget,text,"UTF-8"); +} + +void v3270_paste(GtkWidget *widget) +{ + gtk_clipboard_request_text(gtk_widget_get_clipboard(widget,GDK_SELECTION_CLIPBOARD),(GtkClipboardTextReceivedFunc) text_received,(gpointer) widget); +} + +void v3270_unselect(GtkWidget *widget) +{ + lib3270_unselect(v3270_get_session(widget)); +} + +gboolean v3270_get_selection_bounds(GtkWidget *widget, gint *start, gint *end) +{ + g_return_val_if_fail(GTK_IS_V3270(widget),FALSE); + return lib3270_get_selection_bounds(GTK_V3270(widget)->host,start,end) == 0 ? FALSE : TRUE; +} + +gchar * v3270_get_region(GtkWidget *widget, gint start_pos, gint end_pos, gboolean all) +{ + char * str; + gchar * utftext; + + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + + str = lib3270_get_region(GTK_V3270(widget)->host,start_pos,end_pos,all); + if(!str) + return NULL; + + utftext = g_convert(str, -1, "UTF-8", lib3270_get_charset(GTK_V3270(widget)->host), NULL, NULL, NULL); + + free(str); + + return utftext; +} + + void v3270_select_region(GtkWidget *widget, gint start, gint end) + { + g_return_if_fail(GTK_IS_V3270(widget)); + lib3270_select_region(GTK_V3270(widget)->host,start,end); + } + + diff --git a/sources.mak b/sources.mak new file mode 100644 index 0000000..f564843 --- /dev/null +++ b/sources.mak @@ -0,0 +1,2 @@ +V3270_SRC=marshal.c widget.c oia.c iocallback.c keyboard.c draw.c mouse.c selection.c accessible.c + diff --git a/unlocked.xbm b/unlocked.xbm new file mode 100644 index 0000000..6dcf3ee --- /dev/null +++ b/unlocked.xbm @@ -0,0 +1,14 @@ +#define unlocked_width 32 +#define unlocked_height 32 +static unsigned char unlocked_bits[] = { + 0x00, 0x00, 0xff, 0x0f, 0x00, 0x80, 0xff, 0x1f, 0x00, 0xc0, 0x01, 0x38, + 0x00, 0xe0, 0x00, 0x70, 0x00, 0x70, 0xfc, 0xe3, 0x00, 0x30, 0xfe, 0xc7, + 0x00, 0x30, 0x07, 0xce, 0x00, 0x30, 0x03, 0xcc, 0x00, 0x30, 0x03, 0xcc, + 0x00, 0x30, 0x03, 0xcc, 0x00, 0x30, 0x03, 0xcc, 0x00, 0x30, 0x03, 0xcc, + 0x00, 0x30, 0x03, 0xfc, 0x00, 0x30, 0x03, 0xfc, 0xff, 0xff, 0x3f, 0x00, + 0xff, 0xff, 0x3f, 0x00, 0x33, 0x33, 0x33, 0x00, 0x33, 0x33, 0x33, 0x00, + 0xcf, 0xcc, 0x3c, 0x00, 0xcf, 0xcc, 0x3c, 0x00, 0x33, 0x33, 0x33, 0x00, + 0x33, 0x33, 0x33, 0x00, 0xcf, 0xcc, 0x3c, 0x00, 0xcf, 0xcc, 0x3c, 0x00, + 0x33, 0x33, 0x33, 0x00, 0x33, 0x33, 0x33, 0x00, 0xcf, 0xcc, 0x3c, 0x00, + 0xcf, 0xcc, 0x3c, 0x00, 0x33, 0x33, 0x33, 0x00, 0x33, 0x33, 0x33, 0x00, + 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x3f, 0x00 }; diff --git a/v3270.h b/v3270.h new file mode 100644 index 0000000..fb39726 --- /dev/null +++ b/v3270.h @@ -0,0 +1,190 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como v3270.h e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * licinio@bb.com.br (Licínio Luis Branco) + * kraucer@bb.com.br (Kraucer Fernandes Mazuco) + * + */ + +#ifndef V3270_H_INCLUDED + + #include + #include + + #define V3270_H_INCLUDED 1 + + G_BEGIN_DECLS + + #define GTK_TYPE_V3270 (v3270_get_type ()) + #define GTK_V3270(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_V3270, v3270)) + #define GTK_V3270_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_V3270, v3270Class)) + #define GTK_IS_V3270(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_V3270)) + #define GTK_IS_V3270_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_V3270)) + #define GTK_V3270_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_V3270, v3270Class)) + + + typedef struct _v3270 v3270; + typedef struct _v3270Class v3270Class; + + enum V3270_COLOR + { + V3270_COLOR_BACKGROUND, + V3270_COLOR_BLUE, + V3270_COLOR_RED, + V3270_COLOR_PINK, + V3270_COLOR_GREEN, + V3270_COLOR_TURQUOISE, + V3270_COLOR_YELLOW, + V3270_COLOR_WHITE, + V3270_COLOR_BLACK, + V3270_COLOR_DARK_BLUE, + V3270_COLOR_ORANGE, + V3270_COLOR_PURPLE, + V3270_COLOR_DARK_GREEN, + V3270_COLOR_DARK_TURQUOISE, + V3270_COLOR_MUSTARD, + V3270_COLOR_GRAY, + + V3270_COLOR_FIELD, + V3270_COLOR_FIELD_INTENSIFIED, + V3270_COLOR_FIELD_PROTECTED, + V3270_COLOR_FIELD_PROTECTED_INTENSIFIED, + + V3270_COLOR_SELECTED_BG, + V3270_COLOR_SELECTED_FG, + + V3270_COLOR_CROSS_HAIR, + + // Oia Colors (Must be the last block) + V3270_COLOR_OIA_BACKGROUND, + V3270_COLOR_OIA_FOREGROUND, + V3270_COLOR_OIA_SEPARATOR, + V3270_COLOR_OIA_STATUS_OK, + V3270_COLOR_OIA_STATUS_INVALID, + + V3270_COLOR_COUNT + }; + + #define V3270_COLOR_OIA_STATUS_WARNING V3270_COLOR_OIA_STATUS_OK + + typedef enum _v3270_oia_field + { + V3270_OIA_UNDERA, /**< "A" underlined */ + V3270_OIA_CONNECTION, /**< solid box if connected, "?" in a box if not */ + V3270_OIA_MESSAGE, /**< message area */ + V3270_OIA_SSL, /**< SSL Status */ + /**< Meta indication ("M" or blank) */ + V3270_OIA_ALT, /**< Alt indication ("A" or blank) */ + /**< Compose indication ("C" or blank) */ + /**< Compose first character */ + V3270_OIA_SHIFT, /**< Shift Status */ + V3270_OIA_TYPEAHEAD, /**< Typeahead indication ("T" or blank) */ + V3270_OIA_INSERT, /**< Insert mode indication (Special symbol/"I" or blank) */ + V3270_OIA_SCRIPT, /**< Script indication ("S" or blank) */ + V3270_OIA_LUNAME, /**< LU Name */ + V3270_OIA_SPINNER, /**< command timing spinner */ + V3270_OIA_TIMER, /**< command timing (mmm:ss, or blank) */ + V3270_OIA_CURSOR_POSITION, /**< cursor position (rrr/ccc or blank) */ + +// V3270_OIA_CAPS, /**< Caps indication ("A" or blank) */ + +#ifdef X3270_PRINTER + V3270_OIA_PRINTER, /**< Printer indication ("P" or blank) */ +#endif // X3270_PRINTER + + V3270_OIA_FIELD_COUNT + + } V3270_OIA_FIELD; + + + #define V3270_COLOR_OIA_SPINNER V3270_COLOR_OIA_FOREGROUND + #define V3270_COLOR_OIA_LUNAME V3270_COLOR_OIA_FOREGROUND + #define V3270_COLOR_OIA_INSERT V3270_COLOR_OIA_FOREGROUND + + #ifndef v3270char + #define v3270char void + #endif // v3270_char + + GtkWidget * v3270_new(void); + GType v3270_get_type(void); + + void v3270_reload(GtkWidget * widget); + + void v3270_set_font_family(GtkWidget *widget, const gchar *name); + const gchar * v3270_get_font_family(GtkWidget *widget); + + H3270 * v3270_get_session(GtkWidget *widget); + + int v3270_connect(GtkWidget *widget, const gchar *host); + void v3270_disconnect(GtkWidget *widget); + + // Clipboard + typedef enum _v3270_select_format + { + V3270_SELECT_TEXT, + V3270_SELECT_TABLE, + + V3270_SELECT_MAX + } V3270_SELECT_FORMAT; + + const gchar * v3270_copy(GtkWidget *widget, V3270_SELECT_FORMAT mode); + const gchar * v3270_copy_append(GtkWidget *widget); + + const gchar * v3270_get_selected_text(GtkWidget *widget); + const gchar * v3270_get_copy(GtkWidget *widget); + gchar * v3270_get_text(GtkWidget *widget,int offset, int len); + gchar * v3270_get_region(GtkWidget *widget, gint start_pos, gint end_pos, gboolean all); + + void v3270_set_string(GtkWidget *widget, const gchar *str); + void v3270_tab(GtkWidget *widget); + void v3270_backtab(GtkWidget *widget); + + // Cut & Paste + gboolean v3270_get_selection_bounds(GtkWidget *widget, gint *start, gint *end); + void v3270_unselect(GtkWidget *widget); + void v3270_paste(GtkWidget *widget); + void v3270_paste_string(GtkWidget *widget, const gchar *text, const gchar *encoding); + void v3270_select_region(GtkWidget *widget, gint start, gint end); + + // Colors + void v3270_set_colors(GtkWidget *widget, const gchar *); + void v3270_set_color_table(GdkColor *table, const gchar *colors); + const GdkColor * v3270_get_color_table(GtkWidget *widget); + void v3270_set_mono_color_table(GdkColor *table, const gchar *fg, const gchar *bg); + void v3270_draw_element(cairo_t *cr, unsigned char chr, unsigned short attr, H3270 *session, guint height, GdkRectangle *rect, GdkColor *color); + void v3270_set_color(GtkWidget *widget, enum V3270_COLOR id, GdkColor *color); + GdkColor * v3270_get_color(GtkWidget *widget, enum V3270_COLOR id); + + // Misc + GtkIMContext * v3270_get_im_context(GtkWidget *widget); + gboolean v3270_get_toggle(GtkWidget *widget, LIB3270_TOGGLE ix); + + void v3270_set_host(GtkWidget *widget, const gchar *uri); + + +G_END_DECLS + +#endif // V3270_H_INCLUDED diff --git a/widget.c b/widget.c new file mode 100644 index 0000000..81878a0 --- /dev/null +++ b/widget.c @@ -0,0 +1,1221 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA, 02111-1307, USA + * + * Este programa está nomeado como widget.c e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + + #include + #include + #include + #include + #include + #include + #include + #include "v3270.h" + #include "private.h" + #include "accessible.h" + #include "marshal.h" + + #define WIDTH_IN_PIXELS(terminal,x) (x * cols) + #define HEIGHT_IN_PIXELS(terminal,x) (x * (rows+1)) + + #define CONTENTS_WIDTH(terminal) (cols * terminal->metrics.width) + #define CONTENTS_HEIGHT(terminal) (((rows+1) * terminal->metrics.spacing)+OIA_TOP_MARGIN+2) + +/*--[ Widget definition ]----------------------------------------------------------------------------*/ + + G_DEFINE_TYPE(v3270, v3270, GTK_TYPE_WIDGET); + +/*--[ Globals ]--------------------------------------------------------------------------------------*/ + + guint v3270_widget_signal[LAST_SIGNAL] = { 0 }; + GdkCursor * v3270_cursor[V3270_CURSOR_COUNT] = { 0 }; + +/*--[ Prototipes ]-----------------------------------------------------------------------------------*/ + + // http://git.gnome.org/browse/gtk+/tree/gtk/gtkdrawingarea.c?h=gtk-3-0 + +static void v3270_realize ( GtkWidget * widget) ; +static void v3270_size_allocate ( GtkWidget * widget, + GtkAllocation * allocation ); +static void v3270_send_configure ( v3270 * terminal ); +static AtkObject * v3270_get_accessible ( GtkWidget * widget ); + +// Signals +static void v3270_activate (GtkWidget *widget); + +gboolean v3270_focus_in_event(GtkWidget *widget, GdkEventFocus *event); +gboolean v3270_focus_out_event(GtkWidget *widget, GdkEventFocus *event); + +#if GTK_CHECK_VERSION(3,0,0) + +static void v3270_destroy (GtkWidget * object); + +#else + +static void v3270_destroy (GtkObject * object); + +#endif // gtk3 + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + +static void v3270_cursor_draw(v3270 *widget) +{ + int pos = lib3270_get_cursor_address(widget->host); + unsigned char c; + unsigned short attr; + + lib3270_get_contents(widget->host,pos,pos,&c,&attr); + v3270_update_cursor_surface(widget,c,attr); + gtk_widget_queue_draw_area( GTK_WIDGET(widget), + widget->cursor.rect.x,widget->cursor.rect.y, + widget->cursor.rect.width,widget->cursor.rect.height); + +} + +static void v3270_toggle_changed(v3270 *widget,LIB3270_TOGGLE toggle_id, gboolean toggle_state,const gchar *toggle_name) +{ + trace("%s: toggle %d (%s)=%s",__FUNCTION__,toggle_id,toggle_name,toggle_state ? "Yes" : "No"); + + switch(toggle_id) + { + case LIB3270_TOGGLE_CURSOR_POS: + case LIB3270_TOGGLE_CROSSHAIR: + v3270_reload(GTK_WIDGET(widget)); + gtk_widget_queue_draw(GTK_WIDGET(widget)); + break; + + case LIB3270_TOGGLE_CURSOR_BLINK: + widget->cursor.show |= 1; + break; + + case LIB3270_TOGGLE_INSERT: + v3270_draw_ins_status(widget); + v3270_cursor_draw(widget); + break; + + case LIB3270_TOGGLE_BOLD: + v3270_reload(GTK_WIDGET(widget)); + gtk_widget_queue_draw(GTK_WIDGET(widget)); + break; + + default: + return; + + } + +} + +static void loghandler(H3270 *session, const char *module, int rc, const char *fmt, va_list args) +{ + g_logv(module,rc ? G_LOG_LEVEL_WARNING : G_LOG_LEVEL_MESSAGE, fmt, args); +} + +static gboolean v3270_popup_menu(GtkWidget * widget) +{ + GdkEventButton event; + + memset(&event,0,sizeof(event)); + + event.time = gtk_get_current_event_time(); + event.button = 3; + event.type = GDK_BUTTON_PRESS; + + v3270_emit_popup( GTK_V3270(widget), + lib3270_get_cursor_address(GTK_V3270(widget)->host), + &event ); + + return TRUE; +} + +#if GTK_CHECK_VERSION(3,0,0) + +static GtkSizeRequestMode get_request_mode(GtkWidget *widget) +{ + int rows, cols; + + trace("%s",__FUNCTION__); + + lib3270_get_screen_size(GTK_V3270(widget)->host,&rows,&cols); + + return rows > cols ? GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT : GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; + +} + +void get_preferred_height(GtkWidget *widget, gint *minimum_height, gint *natural_height) +{ + int height = GTK_V3270(widget)->minimum_height; + + if(minimum_height) + *minimum_height = height ? height : 10; + + if(natural_height) + *natural_height = 400; + +} + +void get_preferred_width(GtkWidget *widget, gint *minimum_width, gint *natural_width) +{ + int width = GTK_V3270(widget)->minimum_width; + + if(minimum_width) + *minimum_width = width ? width : 10; + + if(natural_width) + *natural_width = 600; +} + +/* +void get_preferred_height_for_width(GtkWidget *widget, gint width, gint *minimum_height, gint *natural_height) +{ + trace("%s",__FUNCTION__); + + if(minimum_height) + *minimum_height = 10; + + if(natural_height) + *natural_height = 10; +} + +static void get_preferred_width_for_height(GtkWidget *widget,gint height, gint *minimum_width, gint *natural_width) +{ + trace("%s",__FUNCTION__); + + if(minimum_width) + *minimum_width = 10; + + if(natural_width) + *natural_width = 10; + +} +*/ + +#endif // GTK(3,0,0) + +static void v3270_class_init(v3270Class *klass) +{ + GObjectClass * gobject_class = G_OBJECT_CLASS(klass); + GtkWidgetClass * widget_class = GTK_WIDGET_CLASS(klass); + + lib3270_set_log_handler(loghandler); + + widget_class->realize = v3270_realize; + widget_class->size_allocate = v3270_size_allocate; + widget_class->key_press_event = v3270_key_press_event; + widget_class->key_release_event = v3270_key_release_event; + widget_class->focus_in_event = v3270_focus_in_event; + widget_class->focus_out_event = v3270_focus_out_event; + widget_class->button_press_event = v3270_button_press_event; + widget_class->button_release_event = v3270_button_release_event; + widget_class->motion_notify_event = v3270_motion_notify_event; + widget_class->popup_menu = v3270_popup_menu; + + /* Accessibility support */ + widget_class->get_accessible = v3270_get_accessible; + + klass->activate = v3270_activate; + klass->toggle_changed = v3270_toggle_changed; + klass->message_changed = v3270_update_message; + klass->luname_changed = v3270_update_luname; + +#if GTK_CHECK_VERSION(3,0,0) + + widget_class->get_preferred_height = get_preferred_height; + widget_class->get_preferred_width = get_preferred_width; +// widget_class->get_preferred_width_for_height = get_preferred_width_for_height; +// widget_class->get_preferred_height_for_width = get_preferred_height_for_width; + + widget_class->destroy = v3270_destroy; + widget_class->draw = v3270_draw; + +#else + + { + GtkObjectClass *object_class = (GtkObjectClass*) klass; + + object_class->destroy = v3270_destroy; + } + + widget_class->expose_event = v3270_expose; + + +#endif // GTK3 + + v3270_register_io_handlers(klass); + + // Cursors + { +#ifdef WIN32 + static const gchar * cr[V3270_CURSOR_COUNT] = + { + "ibeam", // V3270_CURSOR_UNPROTECTED + "wait", // V3270_CURSOR_WAITING + "arrow", // V3270_CURSOR_LOCKED + "arrow", // V3270_CURSOR_PROTECTED + "hand", // V3270_CURSOR_MOVE_SELECTION + "sizenwse", // V3270_CURSOR_SELECTION_TOP_LEFT + "sizenesw", // V3270_CURSOR_SELECTION_TOP_RIGHT + "sizens", // V3270_CURSOR_SELECTION_TOP + "sizenesw", // V3270_CURSOR_SELECTION_BOTTOM_LEFT + "sizenwse", // V3270_CURSOR_SELECTION_BOTTOM_RIGHT + "sizens", // V3270_CURSOR_SELECTION_BOTTOM + "sizewe", // V3270_CURSOR_SELECTION_LEFT + "sizewe", // V3270_CURSOR_SELECTION_RIGHT + }; +#else + static const int cr[V3270_CURSOR_COUNT] = + { + GDK_XTERM, // V3270_CURSOR_UNPROTECTED + GDK_WATCH, // V3270_CURSOR_WAITING + GDK_X_CURSOR, // V3270_CURSOR_LOCKED + GDK_ARROW, // V3270_CURSOR_PROTECTED + GDK_HAND1, // V3270_CURSOR_MOVE_SELECTION + GDK_TOP_LEFT_CORNER, // V3270_CURSOR_SELECTION_TOP_LEFT + GDK_TOP_RIGHT_CORNER, // V3270_CURSOR_SELECTION_TOP_RIGHT + GDK_TOP_SIDE, // V3270_CURSOR_SELECTION_TOP + GDK_BOTTOM_LEFT_CORNER, // V3270_CURSOR_SELECTION_BOTTOM_LEFT + GDK_BOTTOM_RIGHT_CORNER, // V3270_CURSOR_SELECTION_BOTTOM_RIGHT + GDK_BOTTOM_SIDE, // V3270_CURSOR_SELECTION_BOTTOM + GDK_LEFT_SIDE, // V3270_CURSOR_SELECTION_LEFT + GDK_RIGHT_SIDE, // V3270_CURSOR_SELECTION_RIGHT + }; +#endif // WIN32 + + int f; + + for(f=0;factivate_signal = + g_signal_new( "activate", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (v3270Class, activate), + NULL, NULL, + pw3270_VOID__VOID, + G_TYPE_NONE, 0); + + v3270_widget_signal[SIGNAL_TOGGLE_CHANGED] = + g_signal_new( "toggle_changed", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (v3270Class, toggle_changed), + NULL, NULL, + pw3270_VOID__VOID_ENUM_BOOL_POINTER, + G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_BOOLEAN, G_TYPE_STRING); + + v3270_widget_signal[SIGNAL_MESSAGE_CHANGED] = + g_signal_new( "message_changed", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (v3270Class, message_changed), + NULL, NULL, + pw3270_VOID__VOID_ENUM, + G_TYPE_NONE, 1, G_TYPE_UINT); + + v3270_widget_signal[SIGNAL_LUNAME_CHANGED] = + g_signal_new( "luname_changed", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (v3270Class, luname_changed), + NULL, NULL, + pw3270_VOID__VOID_POINTER, + G_TYPE_NONE, 1, G_TYPE_STRING); + + v3270_widget_signal[SIGNAL_KEYPRESS] = + g_signal_new( "keypress", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (v3270Class, keypress), + NULL, NULL, + pw3270_BOOL__VOID_UINT_ENUM, + G_TYPE_BOOLEAN, 2, G_TYPE_UINT, G_TYPE_UINT); + + v3270_widget_signal[SIGNAL_CONNECTED] = + g_signal_new( "connected", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + pw3270_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_STRING); + + v3270_widget_signal[SIGNAL_DISCONNECTED] = + g_signal_new( "disconnected", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + pw3270_VOID__VOID, + G_TYPE_NONE, 0); + + v3270_widget_signal[SIGNAL_UPDATE_CONFIG] = + g_signal_new( "update_config", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + pw3270_VOID__VOID_POINTER_POINTER, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + + v3270_widget_signal[SIGNAL_MODEL_CHANGED] = + g_signal_new( "model_changed", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + pw3270_VOID__VOID_UINT_POINTER, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); + + v3270_widget_signal[SIGNAL_SELECTING] = + g_signal_new( "selecting", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + pw3270_VOID__VOID_BOOL, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + v3270_widget_signal[SIGNAL_POPUP] = + g_signal_new( "popup", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + pw3270_BOOL__VOID_BOOL_BOOL_POINTER, + G_TYPE_BOOLEAN, 3, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER); + + v3270_widget_signal[SIGNAL_PASTENEXT] = + g_signal_new( "pastenext", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + pw3270_VOID__VOID_BOOL, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + v3270_widget_signal[SIGNAL_CLIPBOARD] = + g_signal_new( "has_text", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + pw3270_VOID__VOID_BOOL, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + v3270_widget_signal[SIGNAL_CHANGED] = + g_signal_new( "changed", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + pw3270_VOID__VOID_UINT_UINT, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + +} + +void v3270_update_font_metrics(v3270 *terminal, cairo_t *cr, int width, int height) +{ + // update font metrics + static const int font_size[] = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 40, 48, 56, 64, 72, 0 }; + int f, rows, cols, hFont; + int size = font_size[0]; + + cairo_font_extents_t extents; + + lib3270_get_screen_size(terminal->host,&rows,&cols); + + terminal->font_weight = lib3270_get_toggle(terminal->host,LIB3270_TOGGLE_BOLD) ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL; + + cairo_select_font_face(cr, terminal->font_family, CAIRO_FONT_SLANT_NORMAL,terminal->font_weight); + + for(f=0;font_size[f];f++) + { + cairo_set_font_size(cr,font_size[f]); + cairo_font_extents(cr,&extents); + + if(f == 0) + { + terminal->minimum_width = (cols * extents.max_x_advance); + terminal->minimum_height = ((rows+1) * (extents.height + extents.descent)) + (OIA_TOP_MARGIN+2); + } + + if( HEIGHT_IN_PIXELS(terminal,(extents.height+extents.descent)) < height && WIDTH_IN_PIXELS(terminal,extents.max_x_advance) < width ) + size = font_size[f]; + } + + cairo_set_font_size(cr,size); + +#if !GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_size_request(GTK_WIDGET(terminal),terminal->minimum_width,terminal->minimum_height); +#endif // !GTK(3,0,0) + +/* + double sx, sy; + cairo_matrix_t font_matrix; + + cairo_set_font_size(cr,10); + cairo_font_extents(cr,&extents); + + trace("font - extents.height=%f extents.width=%f",extents.height,extents.max_x_advance); + + sx = ((double) width) / (((double) terminal->cols) * extents.max_x_advance); + sy = ((double) height) / (((double) terminal->rows) * extents.height); + + trace("sy=%f sx=%f ",sy,sx); + + cairo_get_font_matrix(cr,&font_matrix); + cairo_matrix_scale(&font_matrix, sx, sy); + cairo_set_font_matrix(cr,&font_matrix); +*/ + + /* Save scaled font for use on next drawings */ + if(terminal->font_scaled) + cairo_scaled_font_destroy(terminal->font_scaled); + + terminal->font_scaled = cairo_get_scaled_font(cr); + cairo_scaled_font_reference(terminal->font_scaled); + + cairo_scaled_font_extents(terminal->font_scaled,&extents); + + terminal->metrics.width = (int) extents.max_x_advance; + terminal->metrics.height = (int) extents.height; + terminal->metrics.ascent = (int) extents.ascent; + terminal->metrics.descent = (int) extents.descent; + + hFont = terminal->metrics.height + terminal->metrics.descent; + + // Create new cursor surface + if(terminal->cursor.surface) + cairo_surface_destroy(terminal->cursor.surface); + + terminal->cursor.surface = gdk_window_create_similar_surface(gtk_widget_get_window(GTK_WIDGET(terminal)),CAIRO_CONTENT_COLOR,terminal->metrics.width,hFont); + + // Center image + size = CONTENTS_WIDTH(terminal); + terminal->metrics.left = (width >> 1) - ((size) >> 1); + + terminal->metrics.spacing = height / (rows+2); + if(terminal->metrics.spacing < hFont) + terminal->metrics.spacing = hFont; + + size = CONTENTS_HEIGHT(terminal); + + terminal->metrics.top = (height >> 1) - (size >> 1); + +} + +static void set_timer(H3270 *session, unsigned char on) +{ + GtkWidget *widget = GTK_WIDGET(session->widget); + + if(on) + v3270_start_timer(widget); + else + v3270_stop_timer(widget); + +} + +static void update_toggle(H3270 *session, LIB3270_TOGGLE ix, unsigned char value, LIB3270_TOGGLE_TYPE reason, const char *name) +{ + g_signal_emit(GTK_WIDGET(session->widget), v3270_widget_signal[SIGNAL_TOGGLE_CHANGED], 0, (guint) ix, (gboolean) (value != 0), (gchar *) name); +} + +static void update_message(H3270 *session, LIB3270_MESSAGE id) +{ + g_signal_emit(GTK_WIDGET(session->widget), v3270_widget_signal[SIGNAL_MESSAGE_CHANGED], 0, (gint) id); +} + +static void update_luname(H3270 *session, const char *name) +{ + g_signal_emit(GTK_WIDGET(session->widget), v3270_widget_signal[SIGNAL_LUNAME_CHANGED], 0, (gchar *) name); +} + +static void select_cursor(H3270 *session, LIB3270_CURSOR id) +{ + GtkWidget *widget = GTK_WIDGET(session->widget); + + if(gtk_widget_get_realized(widget) && gtk_widget_get_has_window(widget)) + { + GTK_V3270(widget)->pointer_id = id; + v3270_update_mouse_pointer(widget); + } +} + +static void ctlr_done(H3270 *session) +{ + GtkWidget *widget = GTK_WIDGET(session->widget); + + if(gtk_widget_get_realized(widget) && gtk_widget_get_has_window(widget)) + { + v3270_update_mouse_pointer(widget); + } + +} + +static void update_connect(H3270 *session, unsigned char connected) +{ + v3270 *widget = GTK_V3270(session->widget); + + if(connected) + { + widget->cursor.show |= 2; + g_signal_emit(GTK_WIDGET(widget), v3270_widget_signal[SIGNAL_CONNECTED], 0, session->full_current_host); + } + else + { + widget->cursor.show &= ~2; + g_signal_emit(GTK_WIDGET(widget), v3270_widget_signal[SIGNAL_DISCONNECTED], 0); + } + + gtk_widget_queue_draw(GTK_WIDGET(widget)); +} + +static void update_screen_size(H3270 *session,unsigned short rows, unsigned short cols) +{ +// trace("Widget %p changes to %dx%d",session->widget,cols,rows); + v3270_reload(GTK_WIDGET(session->widget)); + gtk_widget_queue_draw(GTK_WIDGET(session->widget)); +} + +static void update_model(H3270 *session, const char *name, int model, int rows, int cols) +{ + g_signal_emit(GTK_WIDGET(session->widget),v3270_widget_signal[SIGNAL_MODEL_CHANGED], 0, (guint) model, name); +} + +static void changed(H3270 *session, int offset, int len) +{ + GtkWidget * widget = session->widget; + GtkAccessible * obj = GTK_V3270(widget)->accessible; + + trace("%s: offset=%d len=%d",__FUNCTION__,offset,len) + + if(obj) + { + // Get new text, notify atk + gsize bytes_written = 0; + char * text = lib3270_get_text(session,offset,len); + + if(text) + { + GError * error = NULL; + gchar * utfchar = g_convert_with_fallback( text, + -1, + "UTF-8", + lib3270_get_charset(session), + " ", + NULL, + &bytes_written, + &error ); + + free(text); + + if(error) + { + g_warning("%s failed: %s",__FUNCTION__,error->message); + g_error_free(error); + } + + if(utfchar) + { + g_signal_emit_by_name(obj, "text-insert", offset, bytes_written, utfchar); + g_free(utfchar); + } + + } + } + + g_signal_emit(GTK_WIDGET(widget),v3270_widget_signal[SIGNAL_CHANGED], 0, (guint) offset, (guint) len); + +} + +static void set_selection(H3270 *session, unsigned char status) +{ + GtkWidget * widget = GTK_WIDGET(session->widget); + g_signal_emit(widget,v3270_widget_signal[SIGNAL_SELECTING], 0, status ? TRUE : FALSE); +} + +static void update_selection(H3270 *session, int start, int end) +{ + // Selected region changed + GtkWidget * widget = GTK_WIDGET(session->widget); + GtkAccessible * atk_obj = GTK_V3270(widget)->accessible; + + if(atk_obj) + g_signal_emit_by_name(atk_obj,"text-selection-changed"); + +} + +static void v3270_init(v3270 *widget) +{ + trace("%s",__FUNCTION__); + widget->host = lib3270_session_new(""); + + if(widget->host->sz != sizeof(H3270)) + { + g_error( _( "Unexpected signature in H3270 object, possible version mismatch in lib3270") ); + return; + } + + widget->host->widget = widget; + + widget->host->update = v3270_update_char; + widget->host->changed = changed; + widget->host->set_timer = set_timer; + + widget->host->set_selection = set_selection; + widget->host->update_selection = update_selection; + + widget->host->update_luname = update_luname; + widget->host->configure = update_screen_size; + widget->host->update_status = update_message; + widget->host->update_cursor = v3270_update_cursor; + widget->host->update_toggle = update_toggle; + widget->host->update_oia = v3270_update_oia; + widget->host->cursor = select_cursor; + widget->host->update_connect = update_connect; + widget->host->update_model = update_model; + widget->host->changed = changed; + widget->host->ctlr_done = ctlr_done; + + + // Setup input method + widget->input_method = gtk_im_multicontext_new(); + g_signal_connect(G_OBJECT(widget->input_method),"commit",G_CALLBACK(v3270_key_commit),widget); + + gtk_widget_set_can_default(GTK_WIDGET(widget),TRUE); + gtk_widget_set_can_focus(GTK_WIDGET(widget),TRUE); + + // Setup events + gtk_widget_add_events(GTK_WIDGET(widget),GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_MOTION_MASK|GDK_BUTTON_RELEASE_MASK|GDK_POINTER_MOTION_MASK|GDK_ENTER_NOTIFY_MASK); + +} + +GtkWidget * v3270_new(void) +{ + return g_object_new(GTK_TYPE_V3270, NULL); +} + +#if GTK_CHECK_VERSION(3,0,0) +static void v3270_destroy(GtkWidget *widget) +#else +static void v3270_destroy(GtkObject *widget) +#endif +{ + v3270 * terminal = GTK_V3270(widget); + + trace("%s %p",__FUNCTION__,widget); + + if(terminal->accessible) + { + gtk_accessible_set_widget(terminal->accessible, NULL); + g_object_unref(terminal->accessible); + terminal->accessible = NULL; + } + + if(terminal->host) + { + lib3270_session_free(terminal->host); + terminal->host = NULL; + } + + if(terminal->font_family) + { + g_free(terminal->font_family); + terminal->font_family = 0; + } + + if(terminal->font_scaled) + { + cairo_scaled_font_destroy(terminal->font_scaled); + terminal->font_scaled = NULL; + } + + if(terminal->surface) + { + cairo_surface_destroy(terminal->surface); + terminal->surface = NULL; + } + + if(terminal->cursor.surface) + { + cairo_surface_destroy(terminal->cursor.surface); + terminal->cursor.surface = NULL; + } + + if(terminal->timer) + { + g_source_destroy(terminal->timer); + while(terminal->timer) + g_source_unref(terminal->timer); + } + + if(terminal->cursor.timer) + { + g_source_destroy(terminal->cursor.timer); + while(terminal->cursor.timer) + g_source_unref(terminal->cursor.timer); + } + + if(terminal->input_method) + { + g_object_unref(terminal->input_method); + terminal->input_method = NULL; + } + + if(terminal->clipboard) + { + g_free(terminal->clipboard); + terminal->clipboard = NULL; + } + +#if GTK_CHECK_VERSION(3,0,0) + GTK_WIDGET_CLASS(v3270_parent_class)->destroy(widget); +#else + GTK_OBJECT_CLASS(v3270_parent_class)->destroy(widget); +#endif // GTK3 + +} + +static gboolean timer_tick(v3270 *widget) +{ + if(lib3270_get_toggle(widget->host,LIB3270_TOGGLE_CURSOR_BLINK)) + { + widget->cursor.show ^= 1; + gtk_widget_queue_draw_area(GTK_WIDGET(widget), widget->cursor.rect.x, + widget->cursor.rect.y, + widget->cursor.rect.width, + widget->cursor.rect.height ); + } + + return TRUE; +} + +static void release_timer(v3270 *widget) +{ + widget->cursor.timer = NULL; +} + +static void v3270_realize(GtkWidget * widget) +{ + if(!gtk_widget_get_has_window(widget)) + { + GTK_WIDGET_CLASS(v3270_parent_class)->realize(widget); + } + else + { + GtkAllocation allocation; + GdkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + + + gtk_widget_set_realized (widget, TRUE); + + gtk_widget_get_allocation (widget, &allocation); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; + + window = gdk_window_new(gtk_widget_get_parent_window (widget),&attributes, attributes_mask); + gdk_window_set_user_data (window, widget); + gtk_widget_set_window(widget, window); + + gtk_im_context_set_client_window(GTK_V3270(widget)->input_method,window); + + } + +#if !GTK_CHECK_VERSION(3,0,0) + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +#endif // !GTK3 + + v3270_reload(widget); + + v3270_send_configure(GTK_V3270(widget)); + + if(!GTK_V3270(widget)->cursor.timer) + { + // Setup cursor blink timer + v3270 *terminal = GTK_V3270(widget); + + terminal->cursor.timer = g_timeout_source_new(500); + g_source_set_callback(terminal->cursor.timer,(GSourceFunc) timer_tick, widget, (GDestroyNotify) release_timer); + + g_source_attach(terminal->cursor.timer, NULL); + g_source_unref(terminal->cursor.timer); + } + +} + +static void v3270_size_allocate(GtkWidget * widget, GtkAllocation * allocation) +{ + g_return_if_fail(GTK_IS_V3270(widget)); + g_return_if_fail(allocation != NULL); + +// trace("Widget size changes to %dx%d",allocation->width,allocation->height); + + gtk_widget_set_allocation(widget, allocation); + +#if !GTK_CHECK_VERSION(3,0,0) + { + v3270 *terminal = GTK_V3270(widget); + + terminal->width = allocation->width; + terminal->height = allocation->height; + } +#endif + + if(gtk_widget_get_realized(widget)) + { + if(gtk_widget_get_has_window(widget)) + gdk_window_move_resize(gtk_widget_get_window (widget),allocation->x, allocation->y,allocation->width, allocation->height); + + v3270_reload(widget); + v3270_send_configure(GTK_V3270(widget)); + } +} + +static void v3270_send_configure(v3270 * terminal) +{ + GtkAllocation allocation; + GtkWidget *widget; + GdkEvent *event = gdk_event_new(GDK_CONFIGURE); + + widget = GTK_WIDGET(terminal); + + gtk_widget_get_allocation(widget, &allocation); + + event->configure.window = g_object_ref(gtk_widget_get_window(widget)); + event->configure.send_event = TRUE; + event->configure.x = allocation.x; + event->configure.y = allocation.y; + event->configure.width = allocation.width; + event->configure.height = allocation.height; + +#if( !GTK_CHECK_VERSION(3,0,0)) + terminal->width = allocation.width; + terminal->height = allocation.height; +#endif + + gtk_widget_event(widget, event); + gdk_event_free(event); +} + +void v3270_set_colors(GtkWidget *widget, const gchar *colors) +{ + g_return_if_fail(GTK_IS_V3270(widget)); + + if(!colors) + { + colors = "#000000," // V3270_COLOR_BACKGROUND + "#7890F0," // V3270_COLOR_BLUE + "#FF0000," // V3270_COLOR_RED + "#FF00FF," // V3270_COLOR_PINK + "#00FF00," // V3270_COLOR_GREEN + "#00FFFF," // V3270_COLOR_TURQUOISE + "#FFFF00," // V3270_COLOR_YELLOW + "#FFFFFF," // V3270_COLOR_WHITE + "#000000," // V3270_COLOR_BLACK + "#000080," // V3270_COLOR_DARK_BLUE + "#FFA200," // V3270_COLOR_ORANGE + "#800080," // V3270_COLOR_PURPLE + "#008000," // V3270_COLOR_DARK_GREEN + "#008080," // V3270_COLOR_DARK_TURQUOISE + "#A0A000," // V3270_COLOR_MUSTARD + "#C0C0C0," // V3270_COLOR_GRAY + + "#00FF00," // V3270_COLOR_FIELD_DEFAULT + "#FF0000," // V3270_COLOR_FIELD_INTENSIFIED + "#00FFFF," // V3270_COLOR_FIELD_PROTECTED + "#FFFFFF," // V3270_COLOR_FIELD_PROTECTED_INTENSIFIED + + "#404040," // V3270_COLOR_SELECTED_BG + "#FFFFFF," // V3270_COLOR_SELECTED_FG, + + "#00FF00," // V3270_COLOR_CROSS_HAIR + + "#000000," // V3270_COLOR_OIA_BACKGROUND + "#00FF00," // V3270_COLOR_OIA + "#7890F0," // V3270_COLOR_OIA_SEPARATOR + "#FFFFFF," // V3270_COLOR_OIA_STATUS_OK + "#FF0000"; // V3270_COLOR_OIA_STATUS_INVALID + + } + + v3270_set_color_table(GTK_V3270(widget)->color,colors); + g_signal_emit(widget,v3270_widget_signal[SIGNAL_UPDATE_CONFIG], 0, "colors", colors); + v3270_reload(widget); + +} + +void v3270_set_color(GtkWidget *widget, enum V3270_COLOR id, GdkColor *color) +{ + g_return_if_fail(GTK_IS_V3270(widget)); + + GTK_V3270(widget)->color[id] = *color; + +#if !GTK_CHECK_VERSION(3,0,0) + gdk_colormap_alloc_color(gtk_widget_get_default_colormap(),color,TRUE,TRUE); +#endif // !GTK(3,0,0) + +} +GdkColor * v3270_get_color(GtkWidget *widget, enum V3270_COLOR id) +{ + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + return GTK_V3270(widget)->color+id; +} + +const GdkColor * v3270_get_color_table(GtkWidget *widget) +{ + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + return GTK_V3270(widget)->color; +} + +void v3270_set_mono_color_table(GdkColor *clr, const gchar *fg, const gchar *bg) +{ + int f; + + gdk_color_parse(bg,clr); + gdk_color_parse(fg,clr+1); + + for(f=2;ffont_family) + { + if(!g_strcasecmp(terminal->font_family,name)) + return; + g_free(terminal->font_family); + terminal->font_family = NULL; + } + + if(!name) + { + // TODO (perry#3#): Get default font family from currrent style + name = "courier new"; + } + + terminal->font_family = g_strdup(name); + terminal->font_weight = lib3270_get_toggle(terminal->host,LIB3270_TOGGLE_BOLD) ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL; + + trace("%s: %s (%p)",__FUNCTION__,terminal->font_family,terminal->font_family); + + g_signal_emit(widget,v3270_widget_signal[SIGNAL_UPDATE_CONFIG], 0, "font-family", name); + + v3270_reload(widget); + gtk_widget_queue_draw(widget); + + +} + +const gchar * v3270_get_font_family(GtkWidget *widget) +{ + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + return GTK_V3270(widget)->font_family; +} + +void v3270_disconnect(GtkWidget *widget) +{ + g_return_if_fail(GTK_IS_V3270(widget)); + lib3270_disconnect(GTK_V3270(widget)->host); +} + +H3270 * v3270_get_session(GtkWidget *widget) +{ + g_return_val_if_fail(GTK_IS_V3270(widget),NULL); + + return GTK_V3270(widget)->host; +} + +int v3270_connect(GtkWidget *widget, const gchar *host) +{ + v3270 * terminal; + int rc = -1; + + trace("%s widget=%p host=%p",__FUNCTION__,widget,host); + + g_return_val_if_fail(GTK_IS_V3270(widget),EINVAL); + + terminal = GTK_V3270(widget); + + rc = lib3270_connect(terminal->host,host,0); + + trace("%s exits with rc=%d (%s)",__FUNCTION__,rc,strerror(rc)); + + return rc; +} + +static gboolean notify_focus(GtkWidget *widget, GdkEventFocus *event) +{ + GtkAccessible *obj = GTK_V3270(widget)->accessible; + + if(obj) + g_signal_emit_by_name (obj, "focus-event", event->in); + + return FALSE; +} +gboolean v3270_focus_in_event(GtkWidget *widget, GdkEventFocus *event) +{ + v3270 * terminal = GTK_V3270(widget); + + gtk_im_context_focus_in(terminal->input_method); + + return notify_focus(widget,event); +} + +gboolean v3270_focus_out_event(GtkWidget *widget, GdkEventFocus *event) +{ + v3270 * terminal = GTK_V3270(widget); + + gtk_im_context_focus_out(terminal->input_method); + + return notify_focus(widget,event); +} + +static void v3270_activate(GtkWidget *widget) +{ + v3270 * terminal = GTK_V3270(widget); + + trace("%s: %p",__FUNCTION__,terminal); + + if(lib3270_connected(terminal->host)) + lib3270_enter(terminal->host); + else if(lib3270_get_host(terminal->host)) + v3270_connect(widget,NULL); + else + g_warning("Terminal widget %p activated without connection or valid hostname",terminal); +} + +const GtkWidgetClass * v3270_get_parent_class(void) +{ + return GTK_WIDGET_CLASS(v3270_parent_class); +} + +static AtkObject * v3270_get_accessible(GtkWidget * widget) +{ + v3270 * terminal = GTK_V3270(widget); + +// trace("%s acc=%p",__FUNCTION__,terminal->accessible); + + if(!terminal->accessible) + { + terminal->accessible = g_object_new(GTK_TYPE_V3270_ACCESSIBLE,NULL); + atk_object_initialize(ATK_OBJECT(terminal->accessible), widget); + gtk_accessible_set_widget(GTK_ACCESSIBLE(terminal->accessible),widget); + g_object_ref(terminal->accessible); + } + + return ATK_OBJECT(terminal->accessible); +} + +GtkIMContext * v3270_get_im_context(GtkWidget *widget) +{ + return GTK_V3270(widget)->input_method; +} + +gboolean v3270_get_toggle(GtkWidget *widget, LIB3270_TOGGLE ix) +{ + g_return_val_if_fail(GTK_IS_V3270(widget),FALSE); + + if(ix < LIB3270_TOGGLE_COUNT) + return lib3270_get_toggle(GTK_V3270(widget)->host,ix) ? TRUE : FALSE; + + return FALSE; +} + +void v3270_set_host(GtkWidget *widget, const gchar *uri) +{ + g_return_if_fail(GTK_IS_V3270(widget)); + g_return_if_fail(uri != NULL); + lib3270_set_host(GTK_V3270(widget)->host,uri); +} -- libgit2 0.21.2