<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Igor Montagner</title>
    <description>The latest articles on DEV Community by Igor Montagner (@igordsm).</description>
    <link>https://dev.to/igordsm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F536906%2F35ec808f-9a72-458e-880c-67fcbbd25ddf.jpeg</url>
      <title>DEV Community: Igor Montagner</title>
      <link>https://dev.to/igordsm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/igordsm"/>
    <language>en</language>
    <item>
      <title>Vala reactive programming: part 3</title>
      <dc:creator>Igor Montagner</dc:creator>
      <pubDate>Sun, 02 Jan 2022 21:01:34 +0000</pubDate>
      <link>https://dev.to/igordsm/vala-reactive-programming-part-3-11h3</link>
      <guid>https://dev.to/igordsm/vala-reactive-programming-part-3-11h3</guid>
      <description>&lt;p&gt;The last article showed how we could create a Window with two different forms with clear separation between application logic and GUI code. Most of our work consisted of binding properties and using signals to send information out of components. Although this seems to work well with our little example, our application didn't have any global state. One could argue that global state is a code smell (and a lot of people do), but the fact is that lot's of applications use it to some degree. &lt;/p&gt;

&lt;p&gt;One of the problems of global state is that it increases &lt;strong&gt;coupling&lt;/strong&gt;. Essentially, &lt;strong&gt;coupling&lt;/strong&gt; represents the amount of interdependency between two or more modules. Frequently, in situations with large &lt;strong&gt;coupling&lt;/strong&gt; a change in one module snowballs into lots changes in the related modules as well. This is why &lt;strong&gt;coupling&lt;/strong&gt; is seen as bad: there's the possibility of a butterfly effect in which a small change in one module produces a large change overall. &lt;/p&gt;

&lt;p&gt;We could simply add properties to our &lt;code&gt;Application&lt;/code&gt; class pass them along to our components. This could be done either through bindings, via constructor parameters or by referencing the parent component using &lt;code&gt;(Application) this.parent.property_name&lt;/code&gt;. All these options are fine, in the sense that they work but might cause &lt;strong&gt;coupling&lt;/strong&gt; problems. &lt;/p&gt;

&lt;p&gt;The first two may require passing a reference to or binding &lt;code&gt;Application&lt;/code&gt; to basically every class you write. Not only this is annoying but it also makes testing harder. We might need to mock &lt;code&gt;Application&lt;/code&gt; for basically every class we test, since we are introducing a hard dependency on &lt;code&gt;Application&lt;/code&gt; existing even in functions where it's not used.&lt;/p&gt;

&lt;p&gt;We could circunvent this by using &lt;code&gt;parent&lt;/code&gt; references. However, we can easily get to a point where code like this is written: &lt;code&gt;parent.parent.property_name = ...&lt;/code&gt;. Not only this type creates highly coupled components, it's also very brittle. A component might break because of a change in the hierarchy of an apparently unrelated set of components. It might also be a nightmare to test, since we might need to reconstruct whole hierarchies of objects&lt;/p&gt;

&lt;h4&gt;
  
  
  It's possible to avoid this problems by being extra careful. The issue here is that it's easy to shoot yourself in the foot when using these approaches. So we'll try something different.
&lt;/h4&gt;

&lt;p&gt;In this post we'll explore using a &lt;em&gt;Singleton&lt;/em&gt; to store shared data and logic. A &lt;em&gt;Singleton&lt;/em&gt; is a class that only has one instance which is shared. Although *Singleton*s look like classes with all &lt;code&gt;static&lt;/code&gt; properties and methods, some key differences exist:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;*Singleton*s can implement interfaces&lt;/li&gt;
&lt;li&gt;*Singleton*s can lazy load resources &lt;/li&gt;
&lt;li&gt;A &lt;em&gt;Singleton&lt;/em&gt; instance can be passed a argument to other functions or methods&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Building a singleton in Vala is easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SingletonExample&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;SingletonExample&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// TODO: initialize all resources here&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;SingletonExample&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;SingletonExample&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SingletonExample&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// shared data is created using public properties&lt;/span&gt;

    &lt;span class="c1"&gt;// shared logic is created using public methods &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using it is even easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;SingletonExample&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt; &lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;method_here&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;SingletonExample&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt; &lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;property_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XXX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make no mistake, if we need shared data we are going to have to deal with &lt;em&gt;coupling&lt;/em&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  By using a &lt;em&gt;Singleton&lt;/em&gt; &lt;strong&gt;all components depend on the &lt;em&gt;Singleton&lt;/em&gt; **, which helps us to **avoid components depending on other components&lt;/strong&gt;.
&lt;/h4&gt;

&lt;p&gt;The advantage of using a &lt;em&gt;Singleton&lt;/em&gt; is that it concentrates the dependencies into a single class. Instead of using &lt;code&gt;parent&lt;/code&gt; or passing references deep into our component hierarchies, we can access &lt;code&gt;SingletonExample.getInstance ()&lt;/code&gt; anywhere in our code. We can also bind to &lt;code&gt;SingletonExample&lt;/code&gt;'s properties and connect to signals it emits. Thus, our reactive components can now react to local as well as global state changes. &lt;/p&gt;

&lt;p&gt;Some situations where using *Singleton*s may bring advantages include&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;sharing a list of opened folders/files in a text editor&lt;/li&gt;
&lt;li&gt;saving/retrieving user settings from dot files and making them available to the rest of the application&lt;/li&gt;
&lt;li&gt;storing a list media folders in a music/videos application&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Global state should be minimized and good design helps both decreasing &lt;em&gt;coupling&lt;/em&gt; and creating testable and quality code. However, sometimes using shared state leads to simpler design and less code. If this is the case, you might want to consider using Singleton in your next project. &lt;/p&gt;

</description>
      <category>vala</category>
      <category>glib</category>
    </item>
    <item>
      <title>Vala reactive programming: part 2</title>
      <dc:creator>Igor Montagner</dc:creator>
      <pubDate>Fri, 24 Dec 2021 14:18:53 +0000</pubDate>
      <link>https://dev.to/igordsm/vala-reactive-programming-part-2-4pb4</link>
      <guid>https://dev.to/igordsm/vala-reactive-programming-part-2-4pb4</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/igordsm/vala-reactive-programming-2pf4"&gt;last article&lt;/a&gt; we explored how to use properties and bindings to create reactive style programming in Vala. All UI code was written in &lt;code&gt;construct&lt;/code&gt; and all logic was represented by setting properties. UI was synchronized with the Widget state by binding properties to child widgets. Although the separation of concerns was nice, the example was too simple. There was only one component (the &lt;code&gt;LoginForm&lt;/code&gt;) and no information was neither (i) sent to other components; or (ii) received from other components. In this article we'll create a second form that receives the validated user from &lt;code&gt;LoginForm&lt;/code&gt; to a second form.&lt;/p&gt;

&lt;p&gt;All the example code for this article is available at the &lt;em&gt;part2&lt;/em&gt; folder in &lt;a href="https://github.com/igordsm/reactive-gtk-vala"&gt;this github repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mseppfVg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yvfhliueo869zk1j2lj5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mseppfVg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yvfhliueo869zk1j2lj5.gif" alt="Screen recording of final code" width="314" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our component architecture will be based on the following principle:&lt;/p&gt;

&lt;h4&gt;
  
  
  If two components share a parent, then it's the parent's resposability to connect them into a meaningful flow for the application
&lt;/h4&gt;

&lt;p&gt;Let's use this principle to extend the example from the &lt;a href="https://dev.to/igordsm/vala-reactive-programming-2pf4"&gt;last article&lt;/a&gt; and add a &lt;code&gt;UserInfoForm&lt;/code&gt; after a succesful sign in. We'll start from the &lt;em&gt;part2/v0.vala&lt;/em&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with events inside a component
&lt;/h2&gt;

&lt;p&gt;Events are a place where UI and logic code seems hard to separate. It's quite natural, for instance, to create a &lt;code&gt;login_btn_click&lt;/code&gt; event handler that uses both GUI calls to get information from the UI and properties. Fortunately, Vala also provides us with a very nice way of separating this: &lt;code&gt;lambda&lt;/code&gt; functions as event handlers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;do_login&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// check database and validate login here&lt;/span&gt;
    &lt;span class="c1"&gt;// GUI calls are forbidden here, only properties and other methods can be used&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ....&lt;/span&gt;

    &lt;span class="n"&gt;login_btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clicked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt; &lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// extract all info from the UI using GUI calls&lt;/span&gt;
        &lt;span class="nf"&gt;do_login&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt; 
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;lambda&lt;/code&gt; event handler we can extract all info from the UI using GUI calls and then pass this information along to a method. Since we can use bindings to link information between properties and GUI elements, the amount of code inside the &lt;code&gt;lambda&lt;/code&gt; event handler can be quite small. In fact, it might only treat the event information and pass it on to a method that uses it. Another interesting point is that &lt;code&gt;lambda&lt;/code&gt; can &lt;em&gt;ignore&lt;/em&gt; arguments and their types, so if we don't use the &lt;code&gt;GEvent&lt;/code&gt; that the handler is supposed to receive we can just ignore it in our declaration.&lt;/p&gt;

&lt;p&gt;This has two advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;do_login&lt;/code&gt; does not receive &lt;code&gt;Gtk.Event&lt;/code&gt; (or similar), which means it can be called from anywhere in the code, not only in response to an user generated event.&lt;/li&gt;
&lt;li&gt;Event handlers often receive different arguments depending on which event they handle. The &lt;code&gt;lambda&lt;/code&gt;handler is used to treat this arguments, so &lt;code&gt;do_login&lt;/code&gt; is not tied to a single type of event. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Sending information out
&lt;/h2&gt;

&lt;p&gt;For sending information out of our components we can use &lt;em&gt;signals&lt;/em&gt;. For instance, upon succesful login our &lt;code&gt;LoginForm&lt;/code&gt; could emit a &lt;code&gt;login_succesful&lt;/code&gt; signal that sends a &lt;code&gt;User&lt;/code&gt; instance with the currently logged in user info. Now it's up to the parent of &lt;code&gt;LoginForm&lt;/code&gt; to receive the signal and connect it to the next part of the application flow.&lt;/p&gt;

&lt;p&gt;First we modify &lt;code&gt;LoginForm&lt;/code&gt;. For now our &lt;code&gt;User&lt;/code&gt; class only contains the &lt;code&gt;username&lt;/code&gt; property. Also, &lt;code&gt;username&lt;/code&gt; is can only be assigned when creating an &lt;code&gt;User&lt;/code&gt; instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;construct&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Object&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginForm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;login_succesful&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ....&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;do_login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;login_succesful&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we receive this information in our &lt;code&gt;Application&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;activate&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;win&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ApplicationWindow&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;login_form&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LoginForm&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;login_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login_succesful&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s\n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="n"&gt;win&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login_form&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;win&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete code is shown in &lt;em&gt;part2/v1.vala&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intermission: &lt;code&gt;Application&lt;/code&gt; mixes UI and logic
&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;Application&lt;/code&gt; class is not following the principles outline in the &lt;a href="//2021-12-06.md"&gt;last article&lt;/a&gt;. Let's fix that while we add a new &lt;code&gt;Gtk.Stack&lt;/code&gt; to hold our new &lt;code&gt;HelloForm&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloForm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;expand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;valign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CENTER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;halign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CENTER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Label&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello (username goes here)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;attach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of creating widgets inside &lt;code&gt;Application&lt;/code&gt; we introduce a &lt;code&gt;ApplicationWidget&lt;/code&gt;, a class with the sole purpose of creating the workflow of data between our components. Our first version is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationWidget&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;login_form&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LoginForm&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;add_named&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login_form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"login_form"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hello_form&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HelloForm&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;add_named&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hello_form"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;visible_child_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"login_form"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete code is shown in &lt;em&gt;part2/v2.vala&lt;/em&gt;. Our application works exactly the same as before, but now UI is separated from the rest of the app in &lt;code&gt;Application&lt;/code&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receiving information from other components
&lt;/h2&gt;

&lt;p&gt;For receiving information from the "outside" worlds we have two options: regular instance methods or public properties. The advantage of using instance methods is that they can be directly connected to other components' signals. However, we must take care of only updating properties inside it so we don't mix UI and logic. We can also use public properties to receive data from the "outside world".&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use methods if something besides updating the UI is necessary (i.e. pulling information from the database or the web) &lt;/li&gt;
&lt;li&gt;Use properties otherwise &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We add a &lt;code&gt;user&lt;/code&gt; property to &lt;code&gt;HelloForm&lt;/code&gt; so it can receive the currently logged in user. We then connect the components in our &lt;code&gt;ApplicationWidget&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloForm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationWidget&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;

        &lt;span class="n"&gt;login_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login_succesful&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;hello_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;visible_child_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello_form"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final part of this is to connect a change in &lt;code&gt;HelloForm.user&lt;/code&gt; with the UI. A first could be creating a binding between &lt;code&gt;user.username&lt;/code&gt; to the label text. This won't work, as we are not changing the &lt;code&gt;username&lt;/code&gt; property of &lt;code&gt;user&lt;/code&gt;, we are overwritting the whole user object. Our binding must reflect that and listen to changes on the entire &lt;code&gt;user&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Up until this point we only used bindings with the same source and target type. GObject also allows &lt;em&gt;transformation&lt;/em&gt; bindings, in which we bind properties with different types and provide a function to &lt;em&gt;transform&lt;/em&gt; on type into the other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloForm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;

        &lt;span class="nf"&gt;bind_property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEFAULT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;srcval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;targetval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;srcval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_object&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;targetval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, %s!"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;printf&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Transformation functions receive &lt;a href="https://valadoc.org/gobject-2.0/GLib.Value.html"&gt;GLib.Value&lt;/a&gt;, so we need to convert to the type of objects we need. Now our &lt;code&gt;HelloForm&lt;/code&gt; reacts to a change in the application state in a complex way. And this concludes our experimentation with "reactive" &lt;em&gt;Vala&lt;/em&gt; and &lt;em&gt;GTK+&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I personally like this style of code much more than what I usually read in desktop GUI applications. What do you think? &lt;/p&gt;




&lt;p&gt;If you liked this post consider &lt;a href="https://www.buymeacoffee.com/igordsm"&gt;buying me a coffe&lt;/a&gt; and/or following me on twitter at &lt;a href="https://twitter.com/igor_montagner"&gt;@igor_montagner&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vala</category>
      <category>gtk</category>
      <category>linux</category>
    </item>
    <item>
      <title>Vala reactive programming</title>
      <dc:creator>Igor Montagner</dc:creator>
      <pubDate>Mon, 06 Dec 2021 20:03:52 +0000</pubDate>
      <link>https://dev.to/igordsm/vala-reactive-programming-2pf4</link>
      <guid>https://dev.to/igordsm/vala-reactive-programming-2pf4</guid>
      <description>&lt;p&gt;I've been doing some web programming using &lt;a href="https://preactjs.com/" rel="noopener noreferrer"&gt;preact&lt;/a&gt; these last weeks and one of the things that impressed the most was the way logic and UI are split in code. When doing functional components this is specially explicit. Your function returns whatever should be displayed by the component and receives a &lt;code&gt;props&lt;/code&gt; object containing all the information the components need to render. A component rerenders when some of its &lt;code&gt;props&lt;/code&gt; are changed, either because an external component made changes or in response to an event. &lt;/p&gt;

&lt;p&gt;IMHO, this really helps to organize code and separate concerns. All the logic is written in terms of the components' properties. The GUI is updated in response to changes in the properties in order to synchronize the component state with what is shown on screen. &lt;/p&gt;

&lt;p&gt;We can also achieve this in Vala using &lt;code&gt;properties&lt;/code&gt; and &lt;code&gt;bindings&lt;/code&gt; from GLib. In this article we will produce a login screen that validates the username and password fields. All code is available at &lt;a href="https://github.com/igordsm/reactive-gtk-vala" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91jxzwas4pgnjtzb9jtk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91jxzwas4pgnjtzb9jtk.gif" alt="GUI form that validates input"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: The repo contains many iterations of the code presented in this article. A comment containing the name of the original file is shown at the top of each code listing.  &lt;/p&gt;

&lt;p&gt;Let's start with the basic code to build the form above. This is just standard GTK code: all the ui elements are created in the &lt;code&gt;construct&lt;/code&gt; method. The original file (&lt;em&gt;v1/main.vala&lt;/em&gt;) also contains a &lt;code&gt;Gtk.Application&lt;/code&gt; subclass that handles initialization and showing our form. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vala tip&lt;/strong&gt;: the &lt;code&gt;construct&lt;/code&gt; block runs during an object's creation and after named constructors are called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// excerpt from v1.vala&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginForm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ......&lt;/span&gt;

    &lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;width_request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;margin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;column_homogeneous&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;expand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;valign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CENTER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;halign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CENTER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;username_field&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Entry&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;hexpand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;margin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;password_field&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Entry&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;hexpand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;margin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;validation_warning&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Label&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;wrap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;height_request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;login_btn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_label&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Login"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;expand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;halign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Align&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;END&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nf"&gt;attach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Label&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Username"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;attach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username_field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;attach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password_field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;attach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Label&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Password"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;attach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;validation_warning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;attach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login_btn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nf"&gt;show_all&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no interactivity in this form yet. In fact, it already starts in an inconsistent state: the &lt;code&gt;Login&lt;/code&gt; button is enabled even though block fields are empty. We could fix this simply by setting &lt;code&gt;sensitive=false&lt;/code&gt; in &lt;code&gt;login_btn&lt;/code&gt; initialization, but we won't. Instead we will create a property called &lt;code&gt;is_valid&lt;/code&gt; and &lt;strong&gt;bind&lt;/strong&gt; its value to &lt;code&gt;login_btn.sensitive&lt;/code&gt;. Every time one of the values change the other is instantly updated. Bindings can also be created with many values as long as a cicle is not introduced. &lt;/p&gt;

&lt;p&gt;Let's use this now in our program: first we create a property &lt;code&gt;is_valid&lt;/code&gt; and then we use &lt;a href="https://valadoc.org/gobject-2.0/GLib.Object.bind_property.html" rel="noopener noreferrer"&gt;bind_property&lt;/a&gt; to &lt;strong&gt;bind&lt;/strong&gt; its value to &lt;code&gt;login_btn.sensitive&lt;/code&gt;. Our &lt;a href="https://valadoc.org/gobject-2.0/GLib.BindingFlags.html" rel="noopener noreferrer"&gt;binding flags&lt;/a&gt; indicate that the binding is &lt;em&gt;bidirectional&lt;/em&gt; and that the value is &lt;em&gt;synchronized when the binding is created&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// excerpt from v2.vala&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginForm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;is_valid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// GUI creation code&lt;/span&gt;

        &lt;span class="nf"&gt;bind_property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"is_valid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;login_btn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sensitive"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BIDIRECTIONAL&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SYNC_CREATE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the login button is disabled when the app starts and will remain so until we set &lt;code&gt;is_valid=true&lt;/code&gt;. Unfortunately this never happens, so let's add a property &lt;code&gt;username&lt;/code&gt; and bind it to &lt;code&gt;username_field.text&lt;/code&gt;. When &lt;code&gt;username&lt;/code&gt; is set we check if its length is larger than 0 and set &lt;code&gt;is_valid&lt;/code&gt; accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// excerpt from v3.vala&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginForm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;is_valid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;is_valid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;is_valid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}}&lt;/span&gt;

    &lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// GUI creation code&lt;/span&gt;

        &lt;span class="nf"&gt;bind_property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"is_valid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;login_btn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sensitive"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BIDIRECTIONAL&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SYNC_CREATE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;bind_property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username_field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BIDIRECTIONAL&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SYNC_CREATE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the app and test the new validation: the login button should be disable when the app starts and respond to &lt;code&gt;is_valid&lt;/code&gt;. IMHO, the impressive part of this code is that all GUI code is on &lt;code&gt;construct&lt;/code&gt; and our logic is written only in terms of properties. When we update the Widget's properties the UI will update in response, so our application state is always consistent.&lt;/p&gt;

&lt;p&gt;Now the final step is to set &lt;code&gt;validation_error&lt;/code&gt; to a meaningful message. We can do this with another property binding. To make code more readble we also refactor all our validation code into a function &lt;code&gt;void validate_form ()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// excerpt from v4.vala&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginForm&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;validation_error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;validate_form&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//....&lt;/span&gt;

    &lt;span class="n"&gt;construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ....&lt;/span&gt;

        &lt;span class="nf"&gt;bind_property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validation_error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_warning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEFAULT&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SYNC_CREATE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validate_form&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_username&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;is_valid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;validation_error&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Empty username"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;is_valid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;validation_error&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it for the &lt;code&gt;username&lt;/code&gt; field. We can do exactly the same for the &lt;code&gt;password&lt;/code&gt; field and arrive at the final code available at &lt;code&gt;final.vala&lt;/code&gt; in the &lt;a href="https://github.com/igordsm/reactive-gtk-vala" rel="noopener noreferrer"&gt;example repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another interesting project is &lt;a href="https://gitlab.gnome.org/jwestman/blueprint-compiler" rel="noopener noreferrer"&gt;Blueprint compiler&lt;/a&gt;, which creates a sort of DSL for &lt;em&gt;Gtk&lt;/em&gt; components. So, what do you think about this style of &lt;em&gt;Gtk&lt;/em&gt; programming? Join the conversation in the comments ;) &lt;/p&gt;

</description>
      <category>vala</category>
      <category>gtk</category>
      <category>linux</category>
    </item>
    <item>
      <title>One PR a month: February and March</title>
      <dc:creator>Igor Montagner</dc:creator>
      <pubDate>Sun, 28 Mar 2021 15:23:12 +0000</pubDate>
      <link>https://dev.to/igordsm/one-pr-a-month-february-and-march-mp7</link>
      <guid>https://dev.to/igordsm/one-pr-a-month-february-and-march-mp7</guid>
      <description>&lt;p&gt;Since I did not publish a report in February, I am doing a joint February + March post using a couple PRs I recently sent. &lt;/p&gt;

&lt;p&gt;One of the things I like about &lt;a href="https://elementary.io"&gt;elementary&lt;/a&gt; is the care taken with UX. For instance, for less experienced users pasting random commands in the terminal is a sensitive operation, specially if these commands involve administrative privileges. For this reason, elementary's &lt;a href="https://github.com/elementary/terminal"&gt;terminal&lt;/a&gt; app shows a warning when the user pastes commands involving &lt;code&gt;sudo&lt;/code&gt; or with newlines. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P0kRUroC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dx80pf3o5g4exss995sl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P0kRUroC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dx80pf3o5g4exss995sl.png" alt="Paste Protection dialog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two issues were raised with this dialog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;That &lt;em&gt;details&lt;/em&gt; field did not exist (&lt;a href="https://github.com/elementary/terminal/issues/562"&gt;issue #562&lt;/a&gt;), so it was hard for the used to check the if the command being pasted was really dangerous&lt;/li&gt;
&lt;li&gt;Pressing &lt;em&gt;Escape&lt;/em&gt; would paste the text anyway (&lt;a href="https://github.com/elementary/terminal/issues/293"&gt;issue #293&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although both seem like very simple issues, everything is done taking into account these small details. This contributes to the polished feeling &lt;em&gt;elementary&lt;/em&gt; has.&lt;/p&gt;

&lt;p&gt;Fixing the first was really simple: the paste protection dialog inherits from &lt;a href="https://valadoc.org/granite/Granite.MessageDialog.html"&gt;&lt;code&gt;Granite.MessageDialog&lt;/code&gt;&lt;/a&gt;. This class has a method &lt;a href="https://valadoc.org/granite/Granite.MessageDialog.show_error_details.html"&gt;&lt;code&gt;show_error_details&lt;/code&gt;&lt;/a&gt; that creates the small collapsible text box. I just needed to call it with the appopriate text and call it a day: &lt;a href="https://github.com/elementary/terminal/pull/563"&gt;PR #563&lt;/a&gt;. It was almost instantly approved. &lt;/p&gt;

&lt;p&gt;The second issue was also simple: the dialog returns &lt;code&gt;1&lt;/code&gt; if the "Paste Anyway" button is pressed and &lt;code&gt;0&lt;/code&gt; if the "Don't paste" button is pressed. The code that checked if pasting should be cancelled was akin to &lt;code&gt;if (response == 0)&lt;/code&gt;. I'm not sure what pressing &lt;code&gt;Escape&lt;/code&gt; returns, but I'm pretty sure that text should only be pasted if &lt;code&gt;response == 1&lt;/code&gt;. So I changed the condition and now pasting works. This was done in &lt;a href="https://github.com/elementary/terminal/pull/569"&gt;PR #569&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An important point of both PRs is that they are &lt;strong&gt;very simple&lt;/strong&gt;. I used these to emphasize the contributing does not require superior ultra coding skills, just some pacience and a little effort. There are many issues that are easy and up for grabs not only in &lt;em&gt;elementary&lt;/em&gt; but also in many other projects. &lt;/p&gt;

&lt;p&gt;If you decide to take this challenge as well leave a comment. Or if you need help finding easy issues in elementary ;) Or anything , really.&lt;/p&gt;

</description>
      <category>vala</category>
      <category>elementaryos</category>
      <category>opensource</category>
    </item>
    <item>
      <title>One Pull Request per month: January</title>
      <dc:creator>Igor Montagner</dc:creator>
      <pubDate>Sun, 31 Jan 2021 00:52:39 +0000</pubDate>
      <link>https://dev.to/igordsm/one-pull-request-per-month-january-6ch</link>
      <guid>https://dev.to/igordsm/one-pull-request-per-month-january-6ch</guid>
      <description>&lt;p&gt;This year I'll be doing a challenge: submit at least one Pull Request to a FLOSS project. January's PR is a fix to &lt;a href="https://github.com/elementary/camera/issues/148"&gt;No audio is recorded with videos #148 &lt;/a&gt;, a bug in Elementary OS 6's "rewrite" of the Camera app. The backend was changed to pure GStreamer and this introduced some regressions. However, it also allows for better device detection and possibly more control over video and audio settings. Hopefully this new version will solve many of the "Camera does not work on XXX" issues.&lt;/p&gt;

&lt;p&gt;Having worked on Camera in the past (see my contributions in &lt;a href="https://dev.to/igordsm/my-year-in-review-contributions-to-elementary-os-3amd"&gt;my previous post&lt;/a&gt;), I decided to tackle a new issue: no sound was being recorded on the app. After some investigation I realized that this was expected: the app never requested sound to be recorded!&lt;/p&gt;

&lt;p&gt;GStreamer works with data processing pipelines with three basic elements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;sources&lt;/em&gt;, such as webcams, microphones or files, forward data from an external source to the pipeline&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;sinks&lt;/em&gt;, such as files or user interface elements, receive data from the pipeline and either save it or display it.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;elements&lt;/em&gt; receive data from the pipeline, transform it and forward this result to other elements or a sink.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thus, data flow from one or more &lt;em&gt;sources&lt;/em&gt;, passes thru many elements that transform it and finally reaches a &lt;em&gt;sink&lt;/em&gt; where it is stored or shown to the user. The following pipeline was being used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"v4l2src device=%s name=v4l2src !"
"video/x-raw, width=640, height=480, framerate=30/1 ! " +
"videoflip method=horizontal-flip name=hflip ! " +
"videobalance name=balance ! " +
"tee name=tee ! " +
"queue leaky=downstream max-size-buffers=10 ! " +
"videoconvert ! " +
"videoscale ! " +
"gtksink name=gtksink"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We only have a single source, &lt;em&gt;v4l2src&lt;/em&gt;, which corresponds to a Video for Linux 2 device (usually webcams or other external USB cameras). Data is passed thru many elements using a "!" character until reaching a &lt;code&gt;gtksink&lt;/code&gt; that shows the video preview. To record videos a new branch was connected to the &lt;em&gt;tee&lt;/em&gt; element that included a video encoder and a &lt;code&gt;filesink&lt;/code&gt; that finally stored the video to a file. Thus, the current pipeline only has a single source that produces video frames.&lt;/p&gt;

&lt;p&gt;To record audio we need a &lt;em&gt;source&lt;/em&gt; that produces audio. This can be done by adding an &lt;em&gt;alsasrc&lt;/em&gt; element that produces audio using the ALSA sound system. Gstreamer offers a very neat way of testing pipelines: the &lt;code&gt;gst-launch-1.0&lt;/code&gt; app.&lt;br&gt;
The following sequence of elements obtains data from the microphone using ALSA, encodes it using the &lt;a href="https://en.wikipedia.org/wiki/Vorbis"&gt;Vorbis codec&lt;/a&gt; and packages it into a &lt;a href="https://en.wikipedia.org/wiki/Ogg"&gt;Ogg container&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gst-launch-1.0 -e alsasrc ! audioconvert ! vorbisenc ! oggmux !  filesink location="aa.ogg"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we still can't produce a file with both audio &lt;strong&gt;and&lt;/strong&gt; video! Both pipelines produce only one or the other. That's where the &lt;code&gt;oggmux&lt;/code&gt; element comes into play: its role is to combine audio and video streams into a stream. Thus, to record audio as well we only need to add the elements above to the existing pipeline and link them to the existing &lt;code&gt;oggmux&lt;/code&gt; element. The code below does the job and is the basis of my January PR: &lt;a href="https://github.com/elementary/camera/pull/153/files#diff-3ec2685630fa1c16df439bb8af4419875a2bb293d8568ab1a226e8ebf122fccfR307"&gt; Add audio recording elements to record_bin. #153 &lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vala"&gt;&lt;code&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;alsasrc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElementFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"alsasrc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alsasrc&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;missing_messages&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;Gst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PbUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;missing_element_installer_detail_new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"alsasrc"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;audio_queue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElementFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"queue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;audio_convert&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElementFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"audioconvert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_convert&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;missing_messages&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;Gst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PbUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;missing_element_installer_detail_new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"audioconvert"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;audio_vorbis&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElementFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"vorbisenc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_vorbis&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;missing_messages&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;Gst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PbUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;missing_element_installer_detail_new&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"vorbisenc"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="n"&gt;record_bin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_many&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alsasrc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audio_queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audio_convert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audio_vorbis&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;alsasrc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;link_many&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audio_convert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audio_vorbis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;muxer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is rather self explanatory and is basically a Vala version of the command line pipeline I showed earlier. And... that's it. I'm now waiting for the maintainers to review it and begin the improvements so it eventually gets merged. Now I only have 11 PRs left for 2021. Let's keep them coming!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>elementaryos</category>
      <category>vala</category>
    </item>
    <item>
      <title>Treat Pull Requests are conversations, not code donations</title>
      <dc:creator>Igor Montagner</dc:creator>
      <pubDate>Mon, 25 Jan 2021 14:00:54 +0000</pubDate>
      <link>https://dev.to/igordsm/treat-pull-requests-are-conversations-not-code-donations-2hni</link>
      <guid>https://dev.to/igordsm/treat-pull-requests-are-conversations-not-code-donations-2hni</guid>
      <description>&lt;p&gt;Developers create and contribute to Free and Open Source Software for various reasons and it seems more and more people are interested in doing it. There are many articles that sound like &lt;em&gt;Start contributing to open source in X steps&lt;/em&gt; and &lt;em&gt;Hacktoberfest&lt;/em&gt;-like events that aim to increase engagement in FLOSS. It's not that most of these articles offer bad advice and some are actually pretty good. However, they miss a key element that I experienced time and time again when contributing to &lt;a href="http://elementary.io"&gt;Elementary OS&lt;/a&gt;: &lt;strong&gt;sending a &lt;em&gt;Pull Request&lt;/em&gt; is the starting line, not the finish&lt;/strong&gt;. No matter how many magical features you implement, no project is going to accept your code if it's a mess and/or does not follow the projects design/code guidelines. For maintainers, code donation does not help: either a contribution is fit for merging or it isn't. Since fixing other people's code is hard, maintainers prefer to ignore contributors that are not open to getting their code up to the projects' standards. &lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/igordsm/my-year-in-review-contributions-to-elementary-os-3amd"&gt;previous article&lt;/a&gt; I comment on many &lt;em&gt;PRs&lt;/em&gt; I proposed in 2020. The only ones were accepted without modifications were simple bug fixes that were very local and did not significantly impact the apps. Every other &lt;em&gt;PR&lt;/em&gt; started (sometimes long) discussions about how to improve the proposed changes, including many design changes and even discussions if the feature should be implemented at all. &lt;/p&gt;

&lt;p&gt;To illustrate this I'll comment the process for getting &lt;a href="https://github.com/elementary/camera/pull/138"&gt;Add option to mirror the webcam image #138&lt;/a&gt; accepted. My first try looked like the GIF below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--asFfAL7Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/221446/93685926-45660980-fa89-11ea-9451-19ff9ae70078.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--asFfAL7Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/221446/93685926-45660980-fa89-11ea-9451-19ff9ae70078.gif" alt="First try for #138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many design issues were raised and I created a second version:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lGN6JaPI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/221446/97380069-0788ac00-18a5-11eb-933c-9be9c562b262.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lGN6JaPI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://user-images.githubusercontent.com/221446/97380069-0788ac00-18a5-11eb-933c-9be9c562b262.gif" alt="Second attempt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I received some curious feedback on this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sq-QUVyn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p9lmteedv2kejwi7x5r4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sq-QUVyn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p9lmteedv2kejwi7x5r4.png" alt="ModeButton or ModelButton"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After some misunderstandings I was finally able to produce an acceptable version. Notice that now there are sliders in the menu! They were introduced after my first attempt and I needed to add my option to the menu without breaking these new modifications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gSUEbjH9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/221446/98941954-09b95000-24cc-11eb-8b85-d8939dda3ed7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gSUEbjH9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/221446/98941954-09b95000-24cc-11eb-8b85-d8939dda3ed7.png" alt="Final screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This conversation highlights a very reasonable principle: unless you are already invested in a project and know it very well, your first &lt;em&gt;PRs&lt;/em&gt; are probably not good enough to be accepted without modifications. And that's OK and expected. So instead of thinking that you are helping a project or donating/giving code to a project, it makes more sense to understand that &lt;strong&gt;proposing a &lt;em&gt;Pull Request&lt;/em&gt; is equivalent to starting a conversation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;conversation&lt;/em&gt; metaphor is interesting because it emphasizes that it takes two (or more) people to get a &lt;em&gt;PR&lt;/em&gt; accepted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;maintainers help newcomers and external contributors to adapt their changes so they are up to the project's standards;&lt;/li&gt;
&lt;li&gt;contributors continue to engage and improve their proposals until they are finally merged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any part disengages then the changes won't be merged and part of that effort might be wasted. Since &lt;em&gt;PRs&lt;/em&gt; are public this might still be used by some future &lt;em&gt;PR&lt;/em&gt; and eventually get accepted, but the odds are not favourable.&lt;/p&gt;

&lt;p&gt;One of the good points about viewing &lt;em&gt;PRs&lt;/em&gt; as conversations is that it is acceptable, maybe even natural, to reach out if it becomes stale. Sending messages like "Let me know if any changes are needed" or pinging people after addressing their feedback are good ways to keep the conversation alive. Just don't abuse it: maintainers are usually overworked, so sending too many messages actually makes things worse. Be polite, open to improvements and do you best to help them help you become an even better developer. &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>elementaryos</category>
    </item>
    <item>
      <title>My year in review: contributions to Elementary OS</title>
      <dc:creator>Igor Montagner</dc:creator>
      <pubDate>Fri, 18 Dec 2020 14:19:29 +0000</pubDate>
      <link>https://dev.to/igordsm/my-year-in-review-contributions-to-elementary-os-3amd</link>
      <guid>https://dev.to/igordsm/my-year-in-review-contributions-to-elementary-os-3amd</guid>
      <description>&lt;p&gt;This year I decided to take my open source contributions to the next level and focus my attention on a single project: &lt;a href="https://elementary.io" rel="noopener noreferrer"&gt;Elementary Linux&lt;/a&gt;. I choose this project for three simple reasons: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I use it for both work and personal use;&lt;/li&gt;
&lt;li&gt;It has a strong focus on design. I suck at design, so contributing with elementary might help me to learn a thing or two about it; &lt;/li&gt;
&lt;li&gt;It focuses on providing nice defaults. I have wasted too many hours customizing KDE and other WMs, but with elementary everything works well out of the box. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Camera
&lt;/h2&gt;

&lt;p&gt;The Camera app is migrating toward using GStreamer directly and a lot of things are changing right now. My first contributions were aimed at better camera detection: there are many reports of non-working cameras and PRs &lt;a href="https://github.com/elementary/camera/pull/127" rel="noopener noreferrer"&gt;#127 - Setting v4l device now works correctly&lt;/a&gt; and &lt;a href="https://github.com/elementary/camera/pull/128" rel="noopener noreferrer"&gt;#128 - &lt;br&gt;
Use gst.DeviceMonitor to list video sources&lt;/a&gt; include better detection by using GStreamer to enumerate available cameras. &lt;/p&gt;

&lt;p&gt;Another area of improvement was to allow simple image adjustments in the app. Mirroring was added in &lt;a href="https://github.com/elementary/camera/pull/138" rel="noopener noreferrer"&gt;#138&lt;/a&gt; and brightness and contrast in &lt;a href="https://github.com/elementary/camera/pull/139" rel="noopener noreferrer"&gt;#139&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;IMHO, my largest contributions was actually &lt;a href="https://github.com/elementary/camera/pull/134" rel="noopener noreferrer"&gt;#134 - Add option to switch cameras&lt;/a&gt;. I frequently use two cameras for classes and this not being able to select which to use was quite a limitation. After some back and forth regarding design issues it was finally merged!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzyp50alavtvbe52x813s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzyp50alavtvbe52x813s.gif" alt="Camera switching in elementary"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am still waiting for feedback in &lt;a href="https://github.com/elementary/camera/pull/142" rel="noopener noreferrer"&gt;#142 - Send notification when recording has finished&lt;/a&gt;, but it looks promising as well. &lt;/p&gt;

&lt;h2&gt;
  
  
  Code editor
&lt;/h2&gt;

&lt;p&gt;A first simple contribution was to &lt;a href="https://github.com/elementary/code/pull/888" rel="noopener noreferrer"&gt;enable changing tabs using &lt;code&gt;Ctrl&lt;/code&gt;+&lt;code&gt;Tab&lt;/code&gt;&lt;/a&gt;. This scratched an itch that was bothering me for a long time: I've lost count of how many times I tried to use the shortcut with Code... and now I don't need to count anymore. The PR was accepted and is already shipping in the pre-release images for Elementary 6! &lt;/p&gt;

&lt;p&gt;A second item on my wishlist was better markdown support. I like using Code to edit markdown. Somehow I'm more focused when using it for writing that VSCode, which is my goto editor for code. And issue &lt;a href="https://github.com/elementary/code/issues/850" rel="noopener noreferrer"&gt;#850&lt;/a&gt; was a good start. It proposed the inclusion of shortcuts for common formatting such as bold, italics and links. Many other editors use these for accelerating markdown editing and this is now possible since &lt;a href="https://github.com/elementary/code/pull/890" rel="noopener noreferrer"&gt;PR #890&lt;/a&gt; was accepted! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fezjj8py8iei18b5vattg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fezjj8py8iei18b5vattg.gif" alt="Markdown actions in Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I even sent a &lt;a href="https://github.com/elementary/code/pull/894" rel="noopener noreferrer"&gt;second PR&lt;/a&gt; building a "list mode" of sorts and opened an &lt;a href="https://github.com/elementary/code/issues/916" rel="noopener noreferrer"&gt;issue requesting other shortcuts&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7erwsb9rbuoq2purevue.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7erwsb9rbuoq2purevue.gif" alt="list edit mode in code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This year has been great for me. I've learned a lot about Vala, GTK and design by contributing to &lt;em&gt;elementary&lt;/em&gt;. I have even contributed to fix issues that are actually going to be useful for me, which is an even bigger plus. The only downside is that &lt;em&gt;elementary&lt;/em&gt; is not a large project with lots of people reviewing code, so sometimes PRs take weeks to finally get merged. Anyways, let's hope that next year brings more learning and merge Pull Requests 🎉️ &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>elementaryos</category>
      <category>vala</category>
    </item>
  </channel>
</rss>
