Advertisement
Guest User

myipaddress.c

a guest
Aug 30th, 2016
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.46 KB | None | 0 0
  1. #include <gtk/gtk.h>
  2. #include <gdk/gdkkeysyms.h>
  3. #include <stdlib.h>
  4. #include <math.h>
  5. #include "myipaddress.h"
  6.  
  7. #define MY_IP_ADDRESS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MY_IP_ADDRESS_TYPE, MyIPAddressPrivate))
  8.  
  9. typedef struct _MyIPAddressPrivate  MyIPAddressPrivate;
  10.  
  11. struct _MyIPAddressPrivate
  12. {
  13.   guint address[4];
  14. };
  15.  
  16. enum
  17. {
  18.   CHANGED_SIGNAL,
  19.   LAST_SIGNAL
  20. };
  21.  
  22. enum
  23. {
  24.   PROP_0,
  25.   PROP_IP1,
  26.   PROP_IP2,
  27.   PROP_IP3,
  28.   PROP_IP4
  29. };
  30.  
  31. static void my_ip_address_class_init (MyIPAddressClass*);
  32. static void my_ip_address_init (MyIPAddress*);
  33. static void my_ip_address_get_property (GObject*, guint, GValue*, GParamSpec*);
  34. static void my_ip_address_set_property (GObject*, guint,
  35.                                          const GValue*, GParamSpec*);
  36.  
  37. static void my_ip_address_render (MyIPAddress*);
  38. static void my_ip_address_move_cursor (GObject*, GParamSpec*);
  39. static gboolean my_ip_address_key_pressed (GtkEntry*, GdkEventKey*);
  40.  
  41. static guint my_ip_address_signals[LAST_SIGNAL] = { 0 };
  42.  
  43. /* Get a GType that corresponds to MyIPAddress. The first time this function is
  44.  * called (on object instantiation), the type is registered. */
  45. GType
  46. my_ip_address_get_type (void)
  47. {
  48.   static GType entry_type = 0;
  49.  
  50.   if (!entry_type)
  51.   {
  52.     static const GTypeInfo entry_info =
  53.     {
  54.       sizeof (MyIPAddressClass),
  55.       NULL,
  56.       NULL,
  57.       (GClassInitFunc) my_ip_address_class_init,
  58.       NULL,
  59.       NULL,
  60.       sizeof (MyIPAddress),
  61.       0,
  62.       (GInstanceInitFunc) my_ip_address_init,
  63.     };
  64.  
  65.     entry_type = g_type_register_static (GTK_TYPE_ENTRY, "MyIPAddress",
  66.                                          &entry_info, 0);
  67.   }
  68.  
  69.   return entry_type;
  70. }
  71.  
  72. /* Initialize the MyIPAddressClass class by overriding standard functions,
  73.  * registering a private class and setting up signals and properties. */
  74. static void
  75. my_ip_address_class_init (MyIPAddressClass *klass)
  76. {
  77.   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  78.  
  79.   /* Override the standard functions for setting and retrieving properties. */
  80.   gobject_class->set_property = my_ip_address_set_property;
  81.   gobject_class->get_property = my_ip_address_get_property;
  82.  
  83.   /* Add MyIPAddressPrivate as a private data class of MyIPAddressClass. */
  84.   g_type_class_add_private (klass, sizeof (MyIPAddressPrivate));
  85.  
  86.   /* Register the ip-changed signal, which will be emitted when the ip changes. */
  87.   my_ip_address_signals[CHANGED_SIGNAL] =
  88.          g_signal_new ("ip-changed", G_TYPE_FROM_CLASS (klass),
  89.                        G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
  90.                        G_STRUCT_OFFSET (MyIPAddressClass, ip_changed),
  91.                        NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
  92.  
  93.   /* Register four GObject properties, one for each ip address number. */
  94.   g_object_class_install_property (gobject_class, PROP_IP1,
  95.                  g_param_spec_int ("ip-number-1",
  96.                                    "IP Address Number 1",
  97.                                    "The first IP address number",
  98.                                    0, 255, 0,
  99.                                    G_PARAM_READWRITE));
  100.  
  101.   g_object_class_install_property (gobject_class, PROP_IP2,
  102.                  g_param_spec_int ("ip-number-2",
  103.                                    "IP Address Number 2",
  104.                                    "The second IP address number",
  105.                                    0, 255, 0,
  106.                                    G_PARAM_READWRITE));
  107.  
  108.   g_object_class_install_property (gobject_class, PROP_IP3,
  109.                  g_param_spec_int ("ip-number-3",
  110.                                    "IP Address Number 3",
  111.                                    "The third IP address number",
  112.                                    0, 255, 0,
  113.                                    G_PARAM_READWRITE));
  114.  
  115.   g_object_class_install_property (gobject_class, PROP_IP4,
  116.                  g_param_spec_int ("ip-number-4",
  117.                                    "IP Address Number 1",
  118.                                    "The fourth IP address number",
  119.                                    0, 255, 0,
  120.                                    G_PARAM_READWRITE));
  121. }
  122.  
  123. /* This function is called when the programmer gives a new value for a widget
  124.  * property with g_object_set(). */
  125. static void
  126. my_ip_address_set_property (GObject *object,
  127.                             guint prop_id,
  128.                             const GValue *value,
  129.                             GParamSpec *pspec)
  130. {
  131.   MyIPAddress *ipaddress = MY_IP_ADDRESS (object);
  132.   gint address[4] = { -1, -1, -1, -1 };
  133.  
  134.   switch (prop_id)
  135.   {
  136.     case PROP_IP1:
  137.       address[0] = g_value_get_int (value);
  138.       my_ip_address_set_address (ipaddress, address);
  139.       break;
  140.     case PROP_IP2:
  141.       address[1] = g_value_get_int (value);
  142.       my_ip_address_set_address (ipaddress, address);
  143.       break;
  144.     case PROP_IP3:
  145.       address[2] = g_value_get_int (value);
  146.       my_ip_address_set_address (ipaddress, address);
  147.       break;
  148.     case PROP_IP4:
  149.       address[3] = g_value_get_int (value);
  150.       my_ip_address_set_address (ipaddress, address);
  151.       break;
  152.     default:
  153.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  154.       break;
  155.   }
  156. }
  157.  
  158. /* This function is called when the programmer requests the value of a widget
  159.  * property with g_object_get(). */
  160. static void
  161. my_ip_address_get_property (GObject *object,
  162.                             guint prop_id,
  163.                             GValue *value,
  164.                             GParamSpec *pspec)
  165. {
  166.   MyIPAddress *ipaddress = MY_IP_ADDRESS (object);
  167.   MyIPAddressPrivate *priv = MY_IP_ADDRESS_GET_PRIVATE (ipaddress);
  168.  
  169.   switch (prop_id)
  170.   {
  171.     case PROP_IP1:
  172.       g_value_set_int (value, priv->address[0]);
  173.       break;
  174.     case PROP_IP2:
  175.       g_value_set_int (value, priv->address[1]);
  176.       break;
  177.     case PROP_IP3:
  178.       g_value_set_int (value, priv->address[2]);
  179.       break;
  180.     case PROP_IP4:
  181.       g_value_set_int (value, priv->address[3]);
  182.       break;
  183.     default:
  184.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  185.       break;
  186.   }
  187. }
  188.  
  189. /* Initialize the actual MyIPAddress widget. This function is used to setup
  190.  * the initial view of the widget and set necessary properties. */
  191. static void
  192. my_ip_address_init (MyIPAddress *ipaddress)
  193. {
  194.   MyIPAddressPrivate *priv = MY_IP_ADDRESS_GET_PRIVATE (ipaddress);
  195.   PangoFontDescription *fd;
  196.   guint i;
  197.  
  198.   for (i = 0; i < 4; i++)
  199.     priv->address[i] = 0;
  200.  
  201.   fd = pango_font_description_from_string ("Monospace");
  202.   gtk_widget_modify_font (GTK_WIDGET (ipaddress), fd);
  203.   my_ip_address_render (ipaddress);
  204.   pango_font_description_free (fd);
  205.  
  206.   /* The key-press-event signal will be used to filter out certain keys. We will
  207.    * also monitory the cursor-position property so it can be moved correctly. */
  208.   g_signal_connect (G_OBJECT (ipaddress), "key-press-event",
  209.                     G_CALLBACK (my_ip_address_key_pressed), NULL);
  210.   g_signal_connect (G_OBJECT (ipaddress), "notify::cursor-position",
  211.                     G_CALLBACK (my_ip_address_move_cursor), NULL);
  212. }
  213.  
  214. /* Create and return a new instance of the MyIPAddress widget. */
  215. GtkWidget*
  216. my_ip_address_new ()
  217. {
  218.   return GTK_WIDGET (g_object_new (my_ip_address_get_type (), NULL));
  219. }
  220.  
  221. /* Return a string that represents the currently displayed IP address. */
  222. gchar*
  223. my_ip_address_get_address (MyIPAddress *ipaddress)
  224. {
  225.   MyIPAddressPrivate *priv = MY_IP_ADDRESS_GET_PRIVATE (ipaddress);
  226.  
  227.   return g_strdup_printf ("%d.%d.%d.%d", priv->address[0], priv->address[1],
  228.                           priv->address[2], priv->address[3]);
  229. }
  230.  
  231. /* Set the content of the IP address. Ignore any values that are out of bounds
  232.  * so the programmer can provide a negative value for fields not to change. */
  233. void
  234. my_ip_address_set_address (MyIPAddress *ipaddress,
  235.                            gint address[4])
  236. {
  237.   MyIPAddressPrivate *priv = MY_IP_ADDRESS_GET_PRIVATE (ipaddress);
  238.   guint i;
  239.  
  240.   for (i = 0; i < 4; i++)
  241.   {
  242.     if (address[i] >= 0 && address[i] <= 255)
  243.     {
  244.       priv->address[i] = address[i];
  245.     }
  246.   }
  247.  
  248.   my_ip_address_render (ipaddress);
  249.   g_signal_emit_by_name ((gpointer) ipaddress, "ip-changed");
  250. }
  251.  
  252. /* Render the current content of the IP address in the GtkEntry widget. */
  253. static void
  254. my_ip_address_render (MyIPAddress *ipaddress)
  255. {
  256.   MyIPAddressPrivate *priv = MY_IP_ADDRESS_GET_PRIVATE (ipaddress);
  257.   GString *text;
  258.   guint i;
  259.  
  260.   /* Create a string that displays the IP address content, adding spaces if a
  261.    * number cannot fill three characters. */
  262.   text = g_string_new (NULL);
  263.   for (i = 0; i < 4; i++)
  264.   {
  265.     gchar *temp = g_strdup_printf ("%3i.", priv->address[i]);
  266.     text = g_string_append (text, temp);
  267.     g_free (temp);
  268.   }
  269.  
  270.   /* Remove the trailing decimal place and add the string to the GtkEntry. */
  271.   text = g_string_truncate (text, 15);
  272.   gtk_entry_set_text (GTK_ENTRY (ipaddress), text->str);
  273.   g_string_free (text, TRUE);
  274. }
  275.  
  276. /* Force the cursor to always be at the end of one of the four numbers. */
  277. static void
  278. my_ip_address_move_cursor (GObject *entry,
  279.                            GParamSpec *spec)
  280. {
  281.   gint cursor = gtk_editable_get_position (GTK_EDITABLE (entry));
  282.  
  283.   if (cursor <= 3)
  284.     gtk_editable_set_position (GTK_EDITABLE (entry), 3);
  285.   else if (cursor <= 7)
  286.     gtk_editable_set_position (GTK_EDITABLE (entry), 7);
  287.   else if (cursor <= 11)
  288.     gtk_editable_set_position (GTK_EDITABLE (entry), 11);
  289.   else
  290.     gtk_editable_set_position (GTK_EDITABLE (entry), 15);
  291.    
  292. }
  293.  
  294. /* Handle key presses of numbers, tabs, backspaces and returns. */
  295. static gboolean
  296. my_ip_address_key_pressed (GtkEntry *entry,
  297.                            GdkEventKey *event)
  298. {
  299.   MyIPAddressPrivate *priv = MY_IP_ADDRESS_GET_PRIVATE (entry);
  300.   guint k = event->keyval;
  301.   gint cursor, value;
  302.  
  303.   /* If the key is an integer, append the new number to the address. This is only
  304.    * done if the resulting number will be less than 255. */
  305.   if ((k >= GDK_0 && k <= GDK_9) || (k >= GDK_KP_0 && k <= GDK_KP_9))
  306.   {
  307.     cursor = floor (gtk_editable_get_position (GTK_EDITABLE (entry)) / 4);
  308.     value = g_ascii_digit_value (event->string[0]);
  309.    
  310.     if ((priv->address[cursor] == 25) && (value > 5))
  311.       return TRUE;
  312.    
  313.     if (priv->address[cursor] < 26)
  314.     {
  315.       priv->address[cursor] *= 10;
  316.       priv->address[cursor] += value;
  317.       my_ip_address_render (MY_IP_ADDRESS (entry));
  318.       gtk_editable_set_position (GTK_EDITABLE (entry), (4 * cursor) + 3);
  319.       g_signal_emit_by_name ((gpointer) entry, "ip-changed");
  320.     }
  321.   }
  322.   /* Move to the next number or wrap around to the first. */
  323.   else if (k == GDK_Tab)
  324.   {
  325.     cursor = (floor (gtk_editable_get_position (GTK_EDITABLE (entry)) / 4) + 1);
  326.     gtk_editable_set_position (GTK_EDITABLE (entry), (4 * (cursor % 4)) + 3);
  327.   }
  328.   /* Delete the last digit of the current number. This just divides the number by
  329.    * 10, relying on the fact that any remainder will be ignored. */
  330.   else if (k == GDK_BackSpace)
  331.   {
  332.     cursor = floor (gtk_editable_get_position (GTK_EDITABLE (entry)) / 4);
  333.     priv->address[cursor] /= 10;
  334.     my_ip_address_render (MY_IP_ADDRESS (entry));
  335.     gtk_editable_set_position (GTK_EDITABLE (entry), (4 * cursor) + 3);
  336.     g_signal_emit_by_name ((gpointer) entry, "ip-changed");
  337.   }
  338.   /* Activate the GtkEntry widget, which corresponds to the activate signal. */
  339.   else if ((k == GDK_Return) || (k == GDK_KP_Enter))
  340.     gtk_widget_activate (GTK_WIDGET (entry));
  341.  
  342.   return TRUE;
  343. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement