PageRenderTime 247ms CodeModel.GetById 181ms app.highlight 40ms RepoModel.GetById 20ms app.codeStats 0ms

/gtkterm-0.99.6/src/macros.c

#
C | 533 lines | 417 code | 90 blank | 26 comment | 38 complexity | 3a567735e6e398c790c4b58fccf4d10d MD5 | raw file
  1/***********************************************************************/
  2/* macros.c                                                            */
  3/* --------                                                            */
  4/*           GTKTerm Software                                          */
  5/*                      (c) Julien Schmitt                             */
  6/*                      julien@jls-info.com                            */
  7/*                                                                     */
  8/* ------------------------------------------------------------------- */
  9/*                                                                     */
 10/*   Purpose                                                           */
 11/*      Functions for the management of the macros                     */
 12/*                                                                     */
 13/*   ChangeLog                                                         */
 14/*      - 0.99.2 : Internationalization                                */
 15/*      - 0.99.0 : file creation by Julien                             */
 16/*                                                                     */
 17/***********************************************************************/
 18
 19#include <gtk/gtk.h>
 20#include <gdk/gdk.h>
 21#include <gdk/gdkkeysyms.h>
 22#include <stdlib.h>
 23#include <string.h>
 24#include <stdio.h>
 25
 26#include "gettext.h"
 27#include "widgets.h"
 28#include "macros.h"
 29
 30enum
 31  {
 32    COLUMN_SHORTCUT,
 33    COLUMN_ACTION,
 34    NUM_COLUMNS
 35  };
 36
 37macro_t *macros = NULL;
 38static GtkWidget *window = NULL;
 39
 40macro_t *get_shortcuts(gint *size)
 41{
 42  gint i = 0;
 43  
 44  if(macros != NULL)
 45    {
 46      while(macros[i].shortcut != NULL)
 47	i++;
 48    }
 49  *size = i;
 50  return macros;
 51}
 52
 53
 54static void shortcut_callback(gpointer *number)
 55{ 
 56  gchar *string;
 57  gchar *str;
 58  gint i, length;
 59  guchar a;
 60  guint val_read;
 61  
 62  string = macros[(long)number].action;
 63  length = strlen(string);
 64  
 65  for(i = 0; i < length; i++)
 66    {
 67      if(string[i] == '\\')
 68        {
 69	  if(g_unichar_isdigit((gunichar)string[i + 1]))
 70	    {
 71	      if((string[i + 1] == '0') && (string[i + 2] != 0))
 72		{
 73		  if(g_unichar_isxdigit((gunichar)string[i + 3]))
 74		    {
 75		      str = &string[i + 2];
 76		      i += 3;
 77		    }
 78		  else
 79		    {
 80		      str = &string[i + 1];
 81		      if(g_unichar_isxdigit((gunichar)string[i + 2]))
 82			i += 2;
 83		      else
 84			i++;
 85		    }
 86		}
 87	      else
 88		{
 89		  str = &string[i + 1];
 90		  if(g_unichar_isxdigit((gunichar)string[i + 2]))
 91		    i += 2;
 92		  else
 93		    i++;
 94		}
 95	      if(sscanf(str, "%02X", &val_read) == 1)
 96		a = (guchar)val_read;
 97	      else
 98		a = '\\';
 99	    }
100	  else
101	    {
102	      switch(string[i + 1])
103		{
104		case 'a':
105		  a = '\a';
106		  break;
107		case 'b':
108		  a = '\b';
109		  break;
110		case 't':
111		  a = '\t';
112		  break;
113		case 'n':
114		  a = '\n';
115		  break;
116		case 'v':
117		  a = '\v';
118		  break;
119		case 'f':
120		  a = '\f';
121		  break;
122		case 'r':
123		  a = '\r';
124		  break;
125		case '\\':
126		  a = '\\';
127		  break;
128		default:
129		  a = '\\';
130		  i--;
131		  break;
132		}
133	      i++;
134	    }
135	  send_serial(&a, 1);
136	}
137      else
138	{
139	  send_serial(&string[i], 1);
140	}
141    }
142
143  str = g_strdup_printf(_("Macro \"%s\" sent !"), macros[(long)number].shortcut);
144  Put_temp_message(str, 800);
145  g_free(str);
146}
147
148void create_shortcuts(macro_t *macro, gint size)
149{
150  macros = g_malloc((size + 1) * sizeof(macro_t));
151  if(macros != NULL)
152    {
153      memcpy(macros, macro, size * sizeof(macro_t));
154      macros[size].shortcut = NULL;
155      macros[size].action = NULL;
156    }
157  else
158    perror("malloc");
159}
160
161void add_shortcuts(void)
162{
163  long i = 0;
164  guint acc_key;
165  GdkModifierType mod;
166
167  if(macros == NULL)
168    return;
169
170  while(macros[i].shortcut != NULL)
171    {
172      macros[i].closure = g_cclosure_new_swap(G_CALLBACK(shortcut_callback), (gpointer)i, NULL);
173      gtk_accelerator_parse(macros[i].shortcut, &acc_key, &mod);
174      if(acc_key != 0)
175	gtk_accel_group_connect(shortcuts, acc_key, mod, GTK_ACCEL_MASK, macros[i].closure);
176      i++;
177    }
178}
179
180static void macros_destroy(void)
181{
182  gint i = 0;
183
184  if(macros == NULL)
185    return;
186
187  while(macros[i].shortcut != NULL)
188    {
189      g_free(macros[i].shortcut);
190      g_free(macros[i].action);
191      /*
192      g_closure_unref(macros[i].closure);
193      */
194      i++;
195    }
196  g_free(macros);
197  macros = NULL;
198}
199
200void remove_shortcuts(void)
201{
202  gint i = 0;
203
204  if(macros == NULL)
205    return;
206  
207  while(macros[i].shortcut != NULL)
208    {
209      gtk_accel_group_disconnect(shortcuts, macros[i].closure);
210      i++;
211    }
212
213  macros_destroy();
214}
215
216static GtkTreeModel *create_model(void)
217{
218  gint i = 0;
219  GtkListStore *store;
220  GtkTreeIter iter;
221
222  /* create list store */
223  store = gtk_list_store_new (NUM_COLUMNS,
224			      G_TYPE_STRING,
225			      G_TYPE_STRING,
226			      G_TYPE_BOOLEAN,
227			      G_TYPE_BOOLEAN);
228
229  /* add data to the list store */
230  if(macros != NULL)
231    {
232      while(1)
233	{
234	  if(macros[i].shortcut == NULL)
235	    break;
236	  gtk_list_store_append (store, &iter);
237	  gtk_list_store_set (store, &iter,
238			      COLUMN_SHORTCUT, macros[i].shortcut,
239			      COLUMN_ACTION, macros[i].action,
240			      -1);
241	  i++;
242	}
243    }
244
245  return GTK_TREE_MODEL(store);
246}
247
248static gboolean
249shortcut_edited (GtkCellRendererText *cell,
250		 const gchar         *path_string,
251		 const gchar         *new_text,
252		 gpointer             data)
253{
254  GtkTreeModel *model = (GtkTreeModel *)data;
255  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
256  GtkTreeIter iter;
257
258  gtk_tree_model_get_iter(model, &iter, path); 
259  
260  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_ACTION, new_text, -1);
261  gtk_tree_path_free (path);
262 
263  return TRUE;
264}
265
266static void
267add_columns (GtkTreeView *treeview)
268{
269  GtkCellRenderer *renderer;
270  GtkTreeViewColumn *column;
271  GtkTreeModel *model = gtk_tree_view_get_model (treeview);
272
273  renderer = gtk_cell_renderer_text_new ();
274  column = gtk_tree_view_column_new_with_attributes (_("Shortcut"),
275						     renderer,
276						     "text",
277						     COLUMN_SHORTCUT,
278						     NULL);
279  gtk_tree_view_column_set_sort_column_id (column, COLUMN_SHORTCUT);
280  gtk_tree_view_append_column (treeview, column);
281
282  renderer = gtk_cell_renderer_text_new ();
283  g_signal_connect (renderer, "edited", G_CALLBACK(shortcut_edited), model);
284  column = gtk_tree_view_column_new_with_attributes ("Action", renderer, "text", COLUMN_ACTION, NULL);
285  g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL);
286  gtk_tree_view_column_set_sort_column_id (column, COLUMN_ACTION);
287  gtk_tree_view_append_column (treeview, column);
288}
289
290static gint Add_shortcut(GtkWidget *button, gpointer pointer)
291{
292  GtkTreeIter iter;
293  GtkTreeModel *model = (GtkTreeModel *)pointer;
294  
295
296  gtk_list_store_append(GTK_LIST_STORE(model), &iter);
297
298  gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_SHORTCUT, "None", -1);
299
300  return FALSE;
301}
302
303static gboolean Delete_shortcut(GtkWidget *button, gpointer pointer)
304{
305  GtkTreeIter iter;
306  GtkTreeView *treeview = (GtkTreeView *)pointer;
307  GtkTreeModel *model = gtk_tree_view_get_model (treeview);
308  GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
309
310  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
311    {
312      gint i;
313      GtkTreePath *path;
314
315      path = gtk_tree_model_get_path(model, &iter);
316      i = gtk_tree_path_get_indices(path)[0];
317      gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
318
319      gtk_tree_path_free (path);
320    }
321
322  return FALSE;
323}
324
325static gboolean Save_shortcuts(GtkWidget *button, gpointer pointer)
326{
327  GtkTreeIter iter;
328  GtkTreeView *treeview = (GtkTreeView *)pointer;
329  GtkTreeModel *model = gtk_tree_view_get_model (treeview);
330  gint i = 0;
331
332  remove_shortcuts();
333
334  if(gtk_tree_model_get_iter_first(model, &iter))
335    {
336      do
337	{
338	  i++;
339	} while(gtk_tree_model_iter_next(model, &iter));
340
341      gtk_tree_model_get_iter_first(model, &iter);
342
343      macros = g_malloc((i + 1) * sizeof(macro_t));
344      i = 0;
345      if(macros != NULL)
346	{
347	  do
348	    {
349	      gtk_tree_model_get(model, &iter, COLUMN_SHORTCUT, &(macros[i].shortcut), \
350				 COLUMN_ACTION, &(macros[i].action), \
351				 -1);
352	      i++;
353	    } while(gtk_tree_model_iter_next(model, &iter));
354
355	  macros[i].shortcut = NULL;
356	  macros[i].action = NULL;
357	}
358    }
359
360  add_shortcuts();
361
362  return FALSE;
363}
364
365static gboolean key_pressed(GtkWidget *window, GdkEventKey *key, gpointer pointer)
366{
367  GtkTreeIter iter;
368  GtkTreeView *treeview = (GtkTreeView *)pointer;
369  GtkTreeModel *model = gtk_tree_view_get_model (treeview);
370  GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
371  gchar *str = NULL;
372
373  switch(key->keyval)
374    {
375    case GDK_Shift_L:
376    case GDK_Shift_R:
377    case GDK_Control_L:
378    case GDK_Control_R:
379    case GDK_Caps_Lock:
380    case GDK_Shift_Lock:
381    case GDK_Meta_L:
382    case GDK_Meta_R:
383    case GDK_Alt_L:
384    case GDK_Alt_R:
385    case GDK_Super_L:
386    case GDK_Super_R:
387    case GDK_Hyper_L:
388    case GDK_Hyper_R:
389    case GDK_Mode_switch:
390      return FALSE;
391    default:
392      break;
393    }
394
395  if(gtk_tree_selection_get_selected(selection, NULL, &iter))
396    {
397      gint i;
398      GtkTreePath *path;
399      
400      path = gtk_tree_model_get_path(model, &iter);
401      i = gtk_tree_path_get_indices(path)[0];
402      str = gtk_accelerator_name(key->keyval, key->state & ~GDK_MOD2_MASK);
403      gtk_list_store_set(GTK_LIST_STORE (model), &iter, COLUMN_SHORTCUT, str, -1);
404
405      gtk_tree_path_free(path);
406      g_free(str);
407
408      g_signal_handlers_disconnect_by_func(window, G_CALLBACK(key_pressed), pointer);
409    }
410  return FALSE;
411}
412
413
414static gboolean Capture_shortcut(GtkWidget *button, gpointer pointer)
415{
416  g_signal_connect_after(window, "key_press_event", G_CALLBACK(key_pressed), pointer);
417
418  return FALSE;
419}
420
421static gboolean Help_screen(GtkWidget *button, gpointer pointer)
422{
423  GtkWidget *Dialogue, *Label, *Bouton, *Frame;
424
425  Dialogue = gtk_dialog_new();
426  gtk_window_set_title(GTK_WINDOW(Dialogue), _("Help on macros"));
427  Bouton = gtk_button_new_from_stock (GTK_STOCK_OK);
428  gtk_signal_connect_object(GTK_OBJECT(Bouton), "clicked", (GtkSignalFunc)gtk_widget_destroy, GTK_OBJECT(Dialogue));
429  gtk_signal_connect(GTK_OBJECT(Dialogue), "destroy", (GtkSignalFunc)gtk_widget_destroy, NULL);
430  gtk_signal_connect(GTK_OBJECT(Dialogue), "delete_event", (GtkSignalFunc)gtk_widget_destroy, NULL);
431  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(Dialogue)->action_area), Bouton, TRUE, TRUE, 0);
432
433  Label = gtk_label_new(_("The \"action\" field of a macro is the data to be sent on the port. Text can be entered, but also special chars, like \\n, \\t, \\r, etc. You can also enter hexadecimal data preceded by a '\\'. The hexadecimal data should not begin with a letter (eg. use \\0FF and not \\FF)\nExamples :\n\t\"Hello\\n\" sends \"Hello\" followed by a Line Feed\n\t\"Hello\\0A\" does the same thing but the LF is entered in hexadecimal"));
434  gtk_label_set_line_wrap(GTK_LABEL (Label), TRUE);
435  gtk_label_set_selectable(GTK_LABEL(Label), TRUE);
436  gtk_misc_set_padding(GTK_MISC(Label), 10, 10);
437
438  Frame = gtk_frame_new(NULL);
439  gtk_container_set_border_width(GTK_CONTAINER(Frame), 5);
440  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(Dialogue)->vbox), Frame, FALSE, FALSE, 0);
441  gtk_container_add(GTK_CONTAINER(Frame), Label);
442
443  gtk_widget_show_all(Dialogue);
444
445  return FALSE;
446}
447
448
449gint Config_macros(GtkWidget *wid, guint param)
450{
451  GtkWidget *vbox, *hbox;
452  GtkWidget *sw;
453  GtkTreeModel *model;
454  GtkWidget *treeview;
455  GtkWidget *button;
456  GtkWidget *separator;
457
458  /* create window, etc */
459  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
460  gtk_window_set_title (GTK_WINDOW (window), _("Configure Macros"));
461  
462  g_signal_connect (window, "destroy",
463		    G_CALLBACK (gtk_widget_destroyed), &window);
464  gtk_container_set_border_width (GTK_CONTAINER (window), 8);
465
466  vbox = gtk_vbox_new (FALSE, 8);
467  gtk_container_add (GTK_CONTAINER (window), vbox);
468  
469  sw = gtk_scrolled_window_new (NULL, NULL);
470  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
471				       GTK_SHADOW_ETCHED_IN);
472  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
473				  GTK_POLICY_NEVER,
474				  GTK_POLICY_AUTOMATIC);
475  gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
476
477  /* create tree model */
478  model = create_model ();
479  
480  /* create tree view */
481  treeview = gtk_tree_view_new_with_model (model);
482  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
483  gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview),
484				   COLUMN_SHORTCUT);
485  
486  g_object_unref (model);
487  
488  gtk_container_add (GTK_CONTAINER (sw), treeview);
489  
490  /* add columns to the tree view */
491  add_columns (GTK_TREE_VIEW (treeview));
492
493  hbox = gtk_hbox_new (TRUE, 4);
494  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
495  
496  button = gtk_button_new_with_mnemonic (_("_Add"));
497  g_signal_connect(button, "clicked", G_CALLBACK(Add_shortcut), (gpointer)model);
498  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
499
500  button = gtk_button_new_with_mnemonic (_("_Delete"));
501  g_signal_connect(button, "clicked", G_CALLBACK(Delete_shortcut), (gpointer)treeview);
502  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
503  
504  button = gtk_button_new_with_mnemonic (_("_Capture Shortcut"));
505  g_signal_connect(button, "clicked", G_CALLBACK(Capture_shortcut), (gpointer)treeview);
506  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
507
508  separator = gtk_hseparator_new();
509  gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, TRUE, 0);
510
511  hbox = gtk_hbox_new (TRUE, 4);
512  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
513  
514  button = gtk_button_new_from_stock (GTK_STOCK_HELP);
515  g_signal_connect(button, "clicked", G_CALLBACK(Help_screen), NULL);
516  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
517
518  button = gtk_button_new_from_stock (GTK_STOCK_OK);
519  g_signal_connect(button, "clicked", G_CALLBACK(Save_shortcuts), (gpointer)treeview);
520  g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer)window);
521  gtk_box_pack_end (GTK_BOX (hbox), button, TRUE, TRUE, 0);
522
523  button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
524  g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer)window);
525  gtk_box_pack_end (GTK_BOX (hbox), button, TRUE, TRUE, 0);
526
527  gtk_window_set_default_size (GTK_WINDOW(window), 300, 400);
528  
529  gtk_widget_show_all(window);
530
531  return FALSE;
532}
533