#+TITLE: GTK-3 custom signals example
#+DATE: 2014-09-11 12:00:00 UTC
#+DESCRIPTION: Simple example on how to setup, connect to and trigger signals.
#+FILETAGS: GTK-3:python:widgets:signals
#+CATEGORY: python
#+SLUG: 16-gtk3-custom-signals-example
#+THUMBNAIL: ../../../images/gtk/tut16-signals.png
#+BEGIN_COMMENT
.. title: GTK-3 custom signals example
.. slug: 16-gtk3-custom-signals-example
.. date: 2014-09-11 12:00:00 UTC
.. tags: GTK-3, python, widgets, signals
.. category: python
.. description: Simple example on how to setup, connect to and trigger signals.
.. type: text
#+END_COMMENT


#+CAPTION: Opengl touch events
[[../../../images/gtk/tut16-signals.png]]


In this program we create 4 custom signals, the first to are connected to and triggered on launch, the latter two are triggered when you click the buttons.
        
We can create new signals using GObject.signal_new, we can then connect the new signal and callback as we normally would using widget .connect methods as normal. 
To trigger our custom event we use the .emit() method, this method also aalows us to fake events, for example we might want to fake the user clicking a button.


[[http://bazaar.launchpad.net/~oly/python-examples/trunk/files/head:/python-examples/gtk3/][Gtk signals]]


View python code
#+BEGIN_SRC python :tangle 16-gtk3-custom-signals-example.py
#!/usr/bin/python
from gi.repository import Gtk
from gi.repository import GObject

class application_gui:
    """Tutorial 02 buttons"""

    def __init__(self):
        #load in our glade interface
        xml = Gtk.Builder()
        xml.add_from_file('tut16-signals.glade')

        #grab our widget using get_object this is the name of the widget from glade, window1 is the default name
        self.window = xml.get_object('window1')
        self.text = xml.get_object('entry1')

        GObject.signal_new('custom-signal1', self.window, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
        GObject.signal_new('custom-signal2', self.window, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))

        self.window.connect('custom-signal1', self.custom_signal1_method)
        self.window.connect('custom-signal2', self.custom_signal2_method)

        #emit the custom signals on launch.
        self.window.emit('custom-signal1', 'hello from signal1')
        self.window.emit('custom-signal2', None)

        self.buttons = {}
        self.buttons['but1'] = xml.get_object('button1')
        self.buttons['but2'] = xml.get_object('button2')
        self.buttons['but3'] = xml.get_object('togglebutton1')
        self.buttons['but4'] = xml.get_object('togglebutton2')

        GObject.signal_new('custom-signal3', self.buttons['but1'], GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
        GObject.signal_new('custom-signal4', self.buttons['but2'], GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))

        self.buttons['but1'].connect('clicked', self.button_events)
        self.buttons['but1'].connect('custom-signal3', self.custom_signal3_method)
        self.buttons['but2'].connect('clicked', self.button_events)
        self.buttons['but2'].connect('custom-signal4', self.custom_signal4_method)
        self.buttons['but3'].connect('clicked', self.button_events)
        self.buttons['but4'].connect('clicked', self.button_events)

        #fake the user clicking one of our buttons
        self.buttons['but1'].emit('clicked')

        #connect to events, in this instance just quit our application
        self.window.connect('delete_event', Gtk.main_quit)
        self.window.connect('destroy', lambda quit: Gtk.main_quit())

        #show the window else there is nothing to see :)
        self.window.show()

    def custom_signal1_method(self, *args):
        print('custom_signal1 emitted')
        print(args)

    def custom_signal2_method(self, *args):
        print('custom_signal2 emitted')
        print(args)

    def custom_signal3_method(self, *args):
        print('custom_signal3 emitted')
        print(args)

    def custom_signal4_method(self, *args):
        print('custom_signal4 emitted')
        print(args)

    def button_events(self, widget):
        widget.emit('custom-signal3', ('1', '2', '3'))
        toggle_value = ''
        if widget.get_name() == 'GtkToggleButton':
            toggle_value = str(widget.get_active())
        self.text.set_text(widget.get_name() + ' ' +widget.get_label()+ ' ' + toggle_value)

application = application_gui()
Gtk.main()
#+END_SRC

View glade XML
#+BEGIN_SRC xml :tangle tut16-signals.glade
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <child>
      <object class="GtkBox" id="box1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkGrid" id="grid1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkButton" id="button1">
                <property name="label" translatable="yes">Button One Standard Button</property>
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">0</property>
                <property name="width">1</property>
                <property name="height">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkToggleButton" id="togglebutton1">
                <property name="label" translatable="yes">Button Three Toggle Button</property>
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="top_attach">0</property>
                <property name="width">1</property>
                <property name="height">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkToggleButton" id="togglebutton2">
                <property name="label" translatable="yes">Button Four Toggle Button</property>
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="top_attach">1</property>
                <property name="width">1</property>
                <property name="height">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="button2">
                <property name="label" translatable="yes">Button Two Standard Button</property>
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">1</property>
                <property name="width">1</property>
                <property name="height">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkEntry" id="entry1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="invisible_char">•</property>
            <property name="input_purpose">alpha</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
#+END_SRC
