Commit 86e2ac3d892cef514e7ab91eeecf8ab3656560d9

Authored by Perry Werneck
1 parent f1467582
Exists in master and in 1 other branch develop

Implementing the new smart paste feature.

src/include/clipboard.h
... ... @@ -89,12 +89,14 @@
89 89 G_GNUC_INTERNAL const char * v3270_update_selected_text(GtkWidget *widget, gboolean cut);
90 90 G_GNUC_INTERNAL GList * v3270_getColumns_from_selection(v3270 * terminal);
91 91  
92   -
93   - /// @brief Get formatted contents as single text.
  92 + /// @brief Get contents.
94 93 G_GNUC_INTERNAL gchar * v3270_get_copy_as_text(v3270 * terminal);
95 94 G_GNUC_INTERNAL gchar * v3270_get_copy_as_html(v3270 * terminal);
96 95 G_GNUC_INTERNAL gchar * v3270_get_copy_as_table(v3270 * terminal, const gchar *delimiter);
97 96 G_GNUC_INTERNAL gchar * v3270_get_copy_as_data_block(v3270 * terminal);
98 97  
  98 + /// @brief Set contents.
  99 + G_GNUC_INTERNAL gboolean v3270_set_from_data_block(v3270 * terminal, const struct SelectionHeader *selection);
  100 +
99 101 #endif // V3270_CLIPBOARD_H_INCLUDED
100 102  
... ...
src/include/terminal.h
... ... @@ -64,6 +64,9 @@ G_BEGIN_DECLS
64 64 // Cursors
65 65 GdkCursor * cursors[LIB3270_POINTER_COUNT];
66 66  
  67 + // Atoms
  68 + GdkAtom clipboard_formatted; ///< @brief Format for internal clipboard cut & paste.
  69 +
67 70 // Signals
68 71 void (*activate)(GtkWidget *widget);
69 72 void (*toggle_changed)(v3270 *widget,LIB3270_TOGGLE toggle_id,gboolean toggle_state,const gchar *toggle_name);
... ...
src/selection/copy.c
... ... @@ -53,14 +53,6 @@
53 53 terminal->selection.format = format;
54 54 do_copy(terminal,cut);
55 55  
56   -#ifdef DEBUG
57   - {
58   - // DEBUG DATA BLOCK
59   - g_free(v3270_get_copy_as_data_block(terminal));
60   - }
61   -
62   -#endif // DEBUG
63   -
64 56 v3270_update_system_clipboard(widget);
65 57  
66 58 }
... ...
src/selection/datablock.c
... ... @@ -71,7 +71,7 @@ static GList * getUnprotected(H3270 *hSession, const lib3270_selection *selectio
71 71  
72 72 struct SelectionFieldHeader * field = (struct SelectionFieldHeader *) g_malloc0(sizeof(struct SelectionFieldHeader) + length);
73 73  
74   - field->baddr = lib3270_translate_to_address(hSession,row + selection->bounds.row,start + selection->bounds.col);
  74 + field->baddr = lib3270_translate_to_address(hSession,row + selection->bounds.row + 1,start + selection->bounds.col + 1);
75 75 field->length = length;
76 76  
77 77 // Copy string
... ... @@ -125,6 +125,7 @@ gchar * v3270_get_copy_as_data_block(v3270 * terminal)
125 125 }
126 126  
127 127 // Setup block header
  128 + debug("Creating block at offset %u", header->length);
128 129 struct SelectionBlockHeader * blockheader = (struct SelectionBlockHeader *) (((unsigned char *) header) + header->length);
129 130 header->length += sizeof(* blockheader);
130 131  
... ... @@ -149,6 +150,7 @@ gchar * v3270_get_copy_as_data_block(v3270 * terminal)
149 150  
150 151 memcpy((ptr+header->length), value->data, length);
151 152 header->length += length;
  153 + blockheader->records++;
152 154  
153 155 }
154 156  
... ... @@ -158,3 +160,87 @@ gchar * v3270_get_copy_as_data_block(v3270 * terminal)
158 160  
159 161 return (gchar *) g_realloc((gpointer) header, header->length+1);
160 162 }
  163 +
  164 +gboolean v3270_set_from_data_block(v3270 * terminal, const struct SelectionHeader *selection)
  165 +{
  166 + const unsigned char * raw_data = (const unsigned char *) selection;
  167 + unsigned int raw_pos = sizeof(struct SelectionHeader);
  168 + unsigned int column;
  169 + unsigned int record;
  170 +
  171 + while(raw_pos < selection->length)
  172 + {
  173 + const struct SelectionBlockHeader * block = (const struct SelectionBlockHeader *) (raw_data + raw_pos);
  174 + debug("Processing block at offset %u with %u elements", raw_pos, block->records);
  175 +
  176 + raw_pos += sizeof(struct SelectionBlockHeader);
  177 + gboolean found = TRUE;
  178 +
  179 + for(record = 0; record < block->records; record++)
  180 + {
  181 + const struct SelectionFieldHeader * field = (struct SelectionFieldHeader *) (raw_data + raw_pos);
  182 +
  183 + debug("Analizing field at %u: addr=%u length=%u",
  184 + raw_pos,
  185 + field->baddr,
  186 + field->length
  187 + );
  188 +
  189 + raw_pos += (sizeof(struct SelectionFieldHeader) + field->length);
  190 + for(column = 0; column < field->length; column++)
  191 + {
  192 + if(lib3270_is_protected(terminal->host,field->baddr+column))
  193 + {
  194 + debug("Column %d is protected",column);
  195 + found = FALSE;
  196 + break;
  197 + }
  198 + }
  199 + }
  200 +
  201 + if(found && block->records)
  202 + {
  203 + // The current datablock is valid, paste it!
  204 + raw_data = (const unsigned char *) (block+1);
  205 + raw_pos = 0;
  206 +
  207 + debug("Found valid screen with %u elements", block->records);
  208 +
  209 + for(record = 0; record < block->records; record++)
  210 + {
  211 + const struct SelectionFieldHeader * field = (struct SelectionFieldHeader *) (raw_data + raw_pos);
  212 +
  213 + debug("Processing field at %u: addr=%u length=%u",
  214 + raw_pos,
  215 + field->baddr,
  216 + field->length
  217 + );
  218 +
  219 + raw_pos += (sizeof(struct SelectionFieldHeader) + field->length);
  220 +
  221 + debug(
  222 + "Pasting record %u baddr=%u length=%u",
  223 + record,
  224 + field->baddr,
  225 + (unsigned int) field->length
  226 + );
  227 +
  228 + if(lib3270_set_string_at_address(terminal->host, field->baddr,(const unsigned char *) (field+1), field->length) < 0)
  229 + {
  230 + debug("Can't set string baddr=%u length=%u errno=%d %s",
  231 + field->baddr,
  232 + field->length,
  233 + errno,
  234 + strerror(errno)
  235 + );
  236 + return FALSE;
  237 + }
  238 + }
  239 +
  240 + return TRUE;
  241 + }
  242 +
  243 + }
  244 +
  245 + return FALSE;
  246 +}
... ...
src/selection/linux/copy.c
... ... @@ -95,7 +95,7 @@ static void clipboard_get(G_GNUC_UNUSED GtkClipboard *clipboard, GtkSelectionDa
95 95 g_autofree gchar *data = v3270_get_copy_as_data_block(terminal);
96 96 gtk_selection_data_set(
97 97 selection,
98   - gdk_atom_intern_static_string("application/x-v3270-unprotected"),
  98 + GTK_V3270_GET_CLASS(obj)->clipboard_formatted,
99 99 8,
100 100 (guchar *) data,
101 101 ((struct SelectionHeader *) data)->length
... ...
src/selection/linux/paste.c
... ... @@ -36,30 +36,139 @@ static void text_received(G_GNUC_UNUSED GtkClipboard *clipboard, const gchar *t
36 36 v3270_input_text(widget,text,"UTF-8");
37 37 }
38 38  
39   -static gboolean has_target(const gchar *name, const GdkAtom *atoms, const gint n_atoms)
  39 +static gboolean has_target(const GdkAtom atom, const GdkAtom *atoms, const gint n_atoms)
40 40 {
41 41 gint ix;
42 42  
43 43 for(ix = 0; ix < n_atoms; ix++)
44 44 {
45   - if(!g_ascii_strcasecmp(name,gdk_atom_name(atoms[ix])))
  45 + if(atom == atoms[ix])
46 46 return TRUE;
47   -
48 47 }
49 48  
50 49 return FALSE;
51 50 }
52 51  
  52 +static void formatted_received(GtkClipboard *clipboard, GtkSelectionData *selection_data, GtkWidget *widget)
  53 +{
  54 + const struct SelectionHeader *selection = (const struct SelectionHeader *) gtk_selection_data_get_data(selection_data);
  55 +
  56 + v3270 * terminal = GTK_V3270(widget);
  57 +
  58 + debug(
  59 + "Received formatted data with %u bytes: Build=%u rows=%u cols=%u",
  60 + selection->length,
  61 + selection->build,
  62 + selection->rows,
  63 + selection->cols
  64 + );
  65 +
  66 + if(selection->cols != lib3270_get_width(terminal->host) || selection->rows != lib3270_get_height(terminal->host))
  67 + {
  68 + GtkWidget * dialog =
  69 + gtk_message_dialog_new(
  70 + GTK_WINDOW(gtk_widget_get_toplevel(widget)),
  71 + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
  72 + GTK_MESSAGE_INFO,
  73 + GTK_BUTTONS_NONE,
  74 + _("Not the same terminal type")
  75 + );
  76 +
  77 +
  78 + gtk_window_set_title(GTK_WINDOW(dialog),_("Can't paste"));
  79 +
  80 + gtk_dialog_add_buttons(
  81 + GTK_DIALOG (dialog),
  82 + _("_Cancel"), GTK_RESPONSE_CANCEL,
  83 + _("_Paste as text"), GTK_RESPONSE_APPLY,
  84 + NULL
  85 + );
  86 +
  87 + gtk_dialog_set_default_response(GTK_DIALOG (dialog),GTK_RESPONSE_APPLY);
  88 +
  89 + gint response = gtk_dialog_run(GTK_DIALOG(dialog));
  90 +
  91 + gtk_widget_destroy(dialog);
  92 +
  93 + if(response == GTK_RESPONSE_APPLY)
  94 + {
  95 + gtk_clipboard_request_text(
  96 + clipboard,
  97 + (GtkClipboardTextReceivedFunc) text_received,
  98 + (gpointer) widget
  99 + );
  100 + }
  101 +
  102 + return;
  103 +
  104 + }
  105 +
  106 + if(!v3270_set_from_data_block(terminal, selection))
  107 + {
  108 + GtkWidget * dialog =
  109 + gtk_message_dialog_new(
  110 + GTK_WINDOW(gtk_widget_get_toplevel(widget)),
  111 + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
  112 + GTK_MESSAGE_INFO,
  113 + GTK_BUTTONS_NONE,
  114 + _("Unable to paste formatted data")
  115 + );
  116 +
  117 +
  118 + gtk_window_set_title(GTK_WINDOW(dialog),_("Can't paste"));
  119 +
  120 + gtk_dialog_add_buttons(
  121 + GTK_DIALOG (dialog),
  122 + _("_Cancel"), GTK_RESPONSE_CANCEL,
  123 + _("_Paste as text"), GTK_RESPONSE_APPLY,
  124 + NULL
  125 + );
  126 +
  127 + gtk_dialog_set_default_response(GTK_DIALOG (dialog),GTK_RESPONSE_APPLY);
  128 +
  129 + gint response = gtk_dialog_run(GTK_DIALOG(dialog));
  130 +
  131 + gtk_widget_destroy(dialog);
  132 +
  133 + if(response == GTK_RESPONSE_APPLY)
  134 + {
  135 + gtk_clipboard_request_text(
  136 + clipboard,
  137 + (GtkClipboardTextReceivedFunc) text_received,
  138 + (gpointer) widget
  139 + );
  140 + }
  141 +
  142 + return;
  143 +
  144 +
  145 + }
  146 +
  147 +
  148 +}
  149 +
53 150 static void targets_received(GtkClipboard *clipboard, GdkAtom *atoms, gint n_atoms, GtkWidget *widget)
54 151 {
55   - if(has_target("application/x-" PACKAGE_NAME, atoms, n_atoms))
  152 + if(has_target(GTK_V3270_GET_CLASS(widget)->clipboard_formatted,atoms,n_atoms))
56 153 {
57   - debug("Clipboard as TN3270 \"%s\" data",PACKAGE_NAME);
  154 + debug("Clipboard as TN3270 \"%s\" data",gdk_atom_name(GTK_V3270_GET_CLASS(widget)->clipboard_formatted));
  155 +
  156 + gtk_clipboard_request_contents(
  157 + clipboard,
  158 + GTK_V3270_GET_CLASS(widget)->clipboard_formatted,
  159 + (GtkClipboardReceivedFunc) formatted_received,
  160 + (gpointer) widget
  161 + );
  162 +
58 163 return;
59 164 }
60 165  
61 166 // No special format available, request it as text.
62   - gtk_clipboard_request_text(clipboard, (GtkClipboardTextReceivedFunc) text_received, (gpointer) widget);
  167 + gtk_clipboard_request_text(
  168 + clipboard,
  169 + (GtkClipboardTextReceivedFunc) text_received,
  170 + (gpointer) widget
  171 + );
63 172  
64 173 }
65 174  
... ...
src/terminal/widget.c
... ... @@ -258,6 +258,9 @@ static void v3270_class_init(v3270Class *klass)
258 258 // Object methods
259 259 gobject_class->finalize = finalize;
260 260  
  261 + // Atoms
  262 + klass->clipboard_formatted = gdk_atom_intern_static_string("application/x-v3270-unprotected");
  263 +
261 264 // Widget methods
262 265 widget_class->realize = v3270_realize;
263 266 widget_class->size_allocate = v3270_size_allocate;
... ...