 Today, I'm going to be creating a GTK application using Haskell. I had an idea earlier this afternoon of a very simple application that I could build. Start to finish on camera on this one video and guide you step by step on exactly what to do. And this is going to be a very simple application that you can follow along with me and you can build it with me. And you actually don't even need to know any Haskell for the particular application I'm going to build today. It's going to be rather simple, so you don't really need to know Haskell. You're not going to need to know about, you know, creating recursive functions. You're not going to need to know what a monad is or anything deep like that. You know, today we're just going to keep it very basic, very simple. But after today, I think you'll have a better understanding of what GTK is, how GTK works and some of the Haskell bindings for GTK. One thing to note is that on a previous video about Haskell and GTK that I did, I used UI.GTK, that particular set of libraries, that particular set of bindings for GTK. But there's a more modern Haskell GTK library out there called GI.GTK. The particular package, if it's in your repositories and your Linux distros repositories will typically be Haskell-GI. For those of you on Arch Linux or Arch-based Linux distros like I am, you can't actually install Haskell-GI from the Arch repositories because it's packaged in the AUR and the AUR package for Haskell-GI will not compile correctly. I've tried it. I've tried it for many weeks, many months that package has been broken, which is really the reason on my previous video I used a different set of GTK bindings, a different library. But Haskell-GI is really the one that most of the Haskell community recommends that you use. So what we're going to do today is we're going to install Stack. Stack is kind of like a Haskell package manager. It's really not a package manager, but it's a way of managing applications that you're working on. You can think of Stack. What it does is within a project within Stack you can specify in a config file all the various libraries that are dependencies for the program you're working on. And Stack will pull down those libraries, it will install them for you, it pulls them down from a Haskell repository of software called Stackage. And then you don't really have to worry about your Linux distributions repositories and whether it has some of these Haskell libraries or not or whether they compile correctly or not because Stack will just take care of all of this for us and it's just a really nice way to work. So the very first thing you need to do, of course, is make sure you have Stack installed on your system. And there are various ways to install Stack, but the recommended way is to go to Haskellstack.org and on this website, how to install Stack, there is a curl command. So just run that command in a terminal and it will install Stack for you. And of course, you can read some of the documentation on exactly how to use Stack, but I'm going to talk you through it. So before we're getting started, I should tell you the program we're going to build today. So I've been thinking, what is the simplest program I could use for an example, especially a very first GTK application, and I have this logout program installed on my system called OB logout or open box logout, right? It's typically used for open box, but it can be used for other standalone window managers. It's a very simple little application. This little window with these seven buttons here, and you can see Cancel just closes the application, but you then have buttons for logout, restart, shutdown, suspend, hibernate, and lock. You can think of it as kind of like a session manager. And this is rather easy. When I launched this earlier today and I took a look at it, I was like, you know what? I could recreate that using Haskell and GTK probably in like 30 minutes. And you know, I actually did this earlier this afternoon just to see if that was the case. And yeah, it took me about an hour to recreate this in Haskell. And you know, most of that time was really spent creating some images. So what we're going to do is we are going to exactly recreate OB logout or close enough using Haskell dash GI. So let me quit out of OB logout and let's open a terminal. So to get started, if you already have stack installed, the first thing we want to do is we want to set up a new project. Now I'm going to CD into this directory here called source in this source directory. This is where I have various Haskell projects that I work on. And the very first thing you want to do is you want to run stack new and then the name of the program. I'm going to name my logout program bye bye, because essentially when you're logging out or shutting down, you're telling the computer bye bye, right? Let's go ahead and create that. Now when you run stack new name of project, you may get some errors because we should have set up a stack config file. You can see, you can see that in your home directory, you have a hidden directory called dot stack. And in that directory, you have config dot YAML. That's your stack config file. And in that config file, you have various variables that you should set. For example, your name, your email, the category of your software, copyright, your GitHub username. I don't actually have a GitHub username. So some of the stuff I can't set. But whatever you don't have set, it's going to complain, hey, we couldn't set these values. And because it's going to write these values and some other config files that it's going to generate, but it's no big deal. Even if these aren't set, the stack new name of project command, it's still set up your new project. It's just letting you know that it couldn't set these particular parameters. Now that we've created our new project, let's cd into the new project. So I'm going to cd into this new directory that was created called bye-bye. Because that was what stack created for us when we did the new project. By doing ls, you will see there are three directories and then several files that were created. The three directories are app, source and test. And then you have various files. So you have a change law. You have the license. You have package.yaml, which is very important. We're going to play with that. If I open this, I can open this really quickly here in Vim. You will see what this is. This is what really makes this interesting is you can specify dependencies. Right now the only dependency is base, just the Haskell base libraries. But we're going to need some other stuff here as well. As a matter of fact, I could go ahead and add a few things I know we're going to need. So I'm going to go ahead and I'm going to add these three packages right here. We're going to add gi-gtk. I'm going to add gi-gtk-hs and Haskell-gi-base. So those are a lot of the GTK libraries, the binding libraries that we're going to need, of course, to create our GTK application. We're probably going to have to come back to this file and add some other stuff later. But let's go ahead and write and quit that right now. And if we wanted to actually run this application, this new application that we created using stack, it's already a fully functional application. The first thing you want to do is run a stack setup. Stack setup is probably going to take you a while if this is the very first stack project you created because it's going to install GHC, the Haskell compiler. And that installation is going to take some time. Now because I work with Haskell a lot, I've already got GHC installed. I've used stack before, so I didn't have to go through that. Two other commands you need to be familiar with are stack build, which just compiles your application, assuming it compiles correctly. And in this case, the application compiles correctly. It tells us that it created an executable for this application. In this case, it's the name of project-exe. So in my case, bye-bye-exe. Now if you wanted to run this, you don't actually have to go find the location of that particular binary. You can just do stack run from inside the project. And it will run the bye-bye-exe, which all it does by default is it prints out to standard output sumfunk. Because that's the standard template is there's a library that prints out the word sumfunk and our main.hs, all it does is prints that. So let me open up Emacs because I'm going to use Emacs for this and I'm going to navigate to my source directory slash bye-bye. I'm going to hit enter. Let me zoom in. And of course, this is the directory structure I mentioned. We have app, source, test. We're not going to do anything with test. And really, we're not going to do anything with source. Source is where any kind of functions and libraries you create yourself that will be called from within the main, you would put these here. And there's already a file here lib.hs. If I hit enter and zoom in, you can see all it does is prints to standard output the word sumfunk. Now let me go up a directory. I'm going to go into the app directory and main.hs. And what does main.hs have by default? It just runs sumfunk, right? That particular function that was defined in lib.hs. Now I actually won't be using that lib.hs file for anything. So let's just get rid of that particular import. We won't need it. And obviously I'm not going to want the main block to equal sumfunk because we're no longer calling upon that particular function. So we're going to do something different for main. We are going to do main equals do hit enter. And we're going to do gtk.init space nothing. So this initializes this gtk application that we're creating. And then we're going to write a whole bunch of stuff. We're going to create a whole bunch of widgets. And then at the very end, we want to do gtk.main, which starts the main loop. So that is essentially what a gtk application written in Haskell should look like. You have gtk.init. And then at the very end, gtk.main, which starts the main loop, and of course everything in the main loop, is going to be all the widgets that we're going to define. Now the first thing we want to do is we need to import some libraries. We know we're going to need the Haskell GI gtk libraries. So I'm going to import those as qualified. You often have to import certain libraries in Haskell as qualified because there's so many Haskell libraries out there that people have created. And some of those libraries have function names that are the exact same name as a function in another library that you might import. So it's very important in all the tutorials for gi.gtk, they are almost always imported as qualified. And they typically qualify it as gtk. Now what this means is every time I use a function that is part of gi.gtk, I need to pre-pin that function with gtk. For example, init, that particular function there is part of gi.gtk, but I need to specify gtk.init because I imported it as qualified. I hope that makes sense. So how do you get all of the various functions and widgets and everything that are part of gi.gtk? Well, here's how I do it. Because I'm used to viewing Haskell documentation. I just do a quick Google search. I type Haskell gi.gtk and then name of whatever it is I'm looking for. In this case, I typed Haskell gi.gtk button. The very first result is this particular library here, gi.gtk.objects.button. This is how you create buttons using the Haskell gi.gtk library. And it gives us the various functions that are part of this library. It tells you the parameters that each function takes and what the result of that is, what it returns. And this is essentially the same as for anything else that you look up as far as Haskell documentation. You get a page just like this hosted over on hackage.haskell.org. And honestly, I find the Haskell documentation very easy to wrap my head around because it's laid out in a very user-friendly way. Now, I'm not going to spend a lot of time digging through Hackage here on video. I'm going to let you do that now that you know the site. Just do a quick Google search. Just search for Haskell gi.gtk. And then name of whatever function or widget or whatever it is you're looking up. And I promise you Google is going to take you to the proper page. Now, let me get back into our file here. The first thing we need to do before doing anything else is actually creating a window because right now this GTK application does nothing because we haven't defined any kind of widgets at all. And of course, the top-level widget needs to be the window itself. I'm going to name the window simply win. You can name it whatever. You can give it any kind of name, but this will be the only window for this application. So I'm going to keep it short and sweet. So win and then I'm going to do a left-pointing arrow, right? So that's a less than sign dash. And we're going to do this GTK.window new and new is capital N. So Haskell functions always begin with lowercase letters. And this is very important when you start creating your own functions. Never create a Haskell function with a capital letter. It won't work. The Haskell compiler will complain. But if you have a function name that is two or three words combined, such as my new function, you would do lowercase my, y. And then on each word, you would capitalize the first letter of each word, very similar to what was done here with this window new function. And then this particular function here, it takes an argument. We need to tell it what kind of window we're creating. And again, you can look this up in the documentation, but I'm just going to tell you what I'm going to do. I'm going to do GTK.capital window type top level. Let me make this full screen so you can see that. Some other things I'm going to do. I'm going to do a GTK set container border width. And we're going to set the container border width for widget win. You have to specify the widget that we're setting this for. And then I'm going to do a border width of 10. So our window should have a padding of 10 around it, right? So things aren't butted up against the edge of the window. Then I'm going to do GTK.set window title. I put a space here by accident. So GTK.set window title. And what widget are we setting a window title for? Well, we're setting that for win. So the same pattern, right? It's very easy. You quickly get the pattern of these things. And then this is going to take a string. A string in Haskell needs to be wrapped in double quotes. And I'm going to set the window title as buy, buy the name of our application. For sake of time here, I'm just going to paste a few more window settings here. I think these are pretty self-explanatory. I'm going to set window resizable to false, meaning I don't want the window really to resize. And then when I set window default width and window default height, I'm going to make it 750 by 225. And then I'm going to set the window position to GTK.window position center. I want it centered in the middle of the screen the way, you know, OB logout, right? And I'm basically trying to get this to be like OB logout. Well, now I'm in a tiling window manager and a floating window manager. It would actually appear, you know, centered and be somewhere around this size. And that's what I'm trying to recreate here. And finally GTK.window set decorated. We're going to set that to false. We don't want window decorations, not for something like this. Window decorations would be having a title bar and a close button and a minimize button and all of that. Now that's great for normal application windows, but for things like dialogue boxes, toolboxes, and in this case, this logout box, we don't need window decorations. That's just a useless cruft added to the window that doesn't need to be there. So now that I've created a window, we could actually try to launch this application. But one thing you always want to do, one of the very first things when you're creating a GTK application is you need to specify what the program should do when you close the window. Because if you just close the window, there could still be a process running in the background that you don't know about just sucking up all of your RAM. So you always need to specify what to do when your window is destroyed. So in this case, what I'm going to do is let me get into insert mode. I'm going to do gtk.onWidgetDestroy and then specify what widget we're talking about, in this case, window. So onWidgetDestroy for when, I want you to run this function here gtk.main quit. So I want the program to completely quit when the window is destroyed. And finally, we need to specify exactly what we want to do when we launch the application. When we very first launch the application, what we want to do is we want to do a pound sign or a hashtag here. So hashtag show all space when. So when the program launches, what should it do at the very beginning? It should just show us the window, the window we created. Now let me write that and now let me get out a full screen here because I'm going to go back to the terminal here. And I'm going to run. Let me clear the screen so you can see here. I'm going to run stack run. I'm going to zoom out a little bit here in the terminal because I think you guys are not going to really need to see any of the text here. All I have that all I have that terminal open for is simply to run stack run every time I'm done here. So let's run that. And it did not compile correctly. And I'm going to look here at the errors here. Just looking here at the errors, it did not like GTK window type top level. Now the good thing is the Haskell compiler is pretty smart. So it didn't like GTK window type top level, but it tells us perhaps you meant one of these two libraries and one of them is GTK window type top level, but without a capital L. It's just a lower case L. See I thought top and level were both capitalized, but a level actually is not. So all I need to do is get back into the document here and let me just change that capital L to a lower case L and write that. And then let me go back to the terminal and I'm going to do stack run. So now I'm getting an error about show all win, that very last line that we put here. And the reason is these kinds of labels here that begin with the hash symbol, the pound sign, those are what are known as overloaded. And what I need to do, we're going to use overloaded labels and overloaded strings. Those are just naturally part of the gi.gtk library. So really before we started, I should have went ahead and added this. So above the imports, I need to add these two lines. We need to add language and then overloaded labels and then language overloaded strings because we're going to have several of these various labels here that begin with the pound sign. So let me write that and then go back to the terminal and run stack run. And it is still complaining here. And it's complaining about data gi base dot signals. And again, the Haskell compiler, it gives me a clue here, data.gi.base. Well, if I go back in my imports, I never imported data.gi.base. So let's import it and see if that solves a problem. So now, one more time, stack run. And I'm looking at this, you know, and I always keep all of my mistakes on camera because I like to see you guys, I like for you guys to see how I figure out errors and solve problems. It's this line because Emacs is smart enough to also tell us it doesn't like hashtag show all and win. Which win, we've already defined that widget. I don't know why it's saying that this variable is not in scope because we defined it. It's right here. So something very wrong is happening here. So just looking at this, I see the problem. All right, so I'm glad I did this on camera, right? So the two lines here for overloaded labels and overloaded strings, they needed to be at the top. They needed to be above module mainware and all of the imports. Let me write that. And now, what do you want to bet that stack runs? It actually works this time. And it compiled correctly and there is our window. Now, we don't have anything to actually close the window here. In my tiling window manager, I have a key binding that will close the window. And we told the applet exactly what to do when the window was destroyed, quit the program. So there shouldn't be any kind of weird, like hidden processes that are still running. Now, the next thing I think we should do for creating our logout program, let me launch OB logout again. I'm going to create the same seven options here in my logout menu. So I need seven images because they were using images for the buttons. I'm going to do the same thing. So let's create some images. So let me create some space here and I'm going to do IMG1, image one. And then once again, the left pointing arrow. And then we're going to do gtk.image new from file. And then what we're going to do is a dollar sign. I'm going to do home, which is my home directory, plus plus. And then the path to where I have these images on my system, which I'm going to have them in the directory that I'm currently in, which is in my case, nc slash get lab dash repose slash source slash bye bye slash. And then the name of the images, the very first one was the cancel button. So I'm going to create a cancel dot ping. I've already created the ping images off camera. Now for those of you new to Haskell, the dollar sign here is the same as basically wrapping all of this in parentheses because I have to wrap this in parentheses to concatenate the home variable to this string. But a simpler way to do that is just putting a dollar sign. The dollar sign means there's an opening parentheses here and tack a closing parentheses at the end of the line. That's all that means. Now the home variable we haven't actually defined. So let's go ahead and define home. So I'm going to do home. And then once again, the left pointing arrow. And we're going to use this particular Haskell function called get home directory. Now get home directory is part of a Haskell library called system dot directory. So what we want to do is we want to go to imports. And I'm going to paste this here import system dot directory. And let me write that. And let's go ahead and see if this compiles. Now we haven't actually added the image to the window. I just want to see if just assigning the variables actually works. So let's run stack run. And it's good when you make simple changes to see if things compile. Don't make massive changes and then see if your program compiles because then it's not obvious the mistake you made because, you know, right now I've only added three new lines to the file. So it's really easy for me to figure out what the error is. And the Haskell compiler is complaining about import system dot directory. The reason it's complaining about that is because there's something we need to do. We need to add the system dot directory library to our package dot yaml. Remember that that was in part of the files that were created when we ran stack new name of project. So what I'm going to do is I'm going to go up a directory and go into package dot yaml. You guys remember this file. Remember at the very beginning where we went to the dependencies and we added gi dash gtk and Haskell dash gi dash base, et cetera. Well now what we want to do is add directory. That is the actual program name for the system dot directory libraries. It's simply called directory. So let me write that. And then let me go back to this here. And I haven't really made any changes to the main dot HS. I think all I need to do is just run stack run. And what stack is going to do is it's going to install system dot directory for us. And then of course it's going to run the program. So now it compiles correctly and it runs correctly. So let me make this full screen once again. So now we've got this image here and then once again for sake of time, and we're going to have seven images. So I'm just going to do a copy and paste job. We're going to have images for cancel, log out, reboot, shutdown, suspend, hibernate, and lock. Now exactly how should we add the images to our program? Well, let me do oblog out one more time to see what they did. And it looks like what oblog out is doing is they're using a grid. Right? So a grid and in the top row, they have the images. And in the second row of the grid, they have labels for the images, you know, cancel, log out, restart. That's exactly what I'm going to do. So we need to create a GTK grid. So I'm going to create a grid. I'm just going to call it grid because it will be the only grid for this application. No reason to give it some long and complicated names. So I'm just going to assign this variable as grid. And of course that needs to be GTK dot grid new. And then I'm going to paste these lines here while I'm at it. I just want to assign some other various settings to the grid. So what I'm going to do is I'm going to make the column spacing 10 pixels. Now the column spacing, of course, is going to be the spacing horizontally. And then I'm going to set the row spacing also to 10 pixels. That way, everything has a little bit of padding around it inside the grid. And finally, I'm going to do grid set column homogenous. I'm going to set that to true, meaning I want all the columns and rows and every I want all the cells in the grid to actually be the same size. Otherwise, when you put bigger text in one grid and smaller text, and they'll be different sizes, I don't want that. I want everything to have this homogenous spacing. So we created our window. We've created a grid. We've defined our images. And now there needs to be labels for each image as well. So to create labels using Haskell's gi.gtk library, you name a label. I'm just going to name them very simply. So I'm going to do label one for the very first label. And then once again, the left pointing arrow. This time we're going to do GTK dot label new. And I'm going to do nothing. I'm going to set it to nothing. Now, typically this takes a string. You know, you would actually give it a label like cancel. You know, that's the name of the button. But I don't just want plain cancel. I want actually this to be bolded text. And the way to do this using gi.gtk is to initially set the label to nothing. And then after that, do GTK dot label set markup for which widget label one. And then the string with the markup. And the markup, I'm going to use the bold tag. Standard B for bold for HTML. So I'm going to do B for bold cancel. And then the ending bold tag. So that is that label. And then I'm just going to create six more for logout reboot shutdown, suspend, hibernate, and lock. So let me just do a paste here. And you can see how that works. So now we have seven images, seven labels. Now let me launch OB logout one more time because these images here are not, they're images, but they're images set within a button. Because you see when I hover over them, you get some coloring around them, like a border around them. That's because there's actually a button here. And inside the button, the image was placed. So we actually need to create seven buttons for these seven images to go in. Then we need to create actions for each of the seven buttons. So actions would be when I click the button, what does it do? So let's get out of that. And let's go ahead and create a button. Create a button using gi.gtk. You give it a name. I'm going to, again, once again, very simply name these. I'm going to call button one, button one. I'm going to do gtk.button new. And new needs to be capitalized. And then what I want to do is I want to do gtk.button set relief. And then I'm setting that for button one. And what set relief is doing, it sets the relief, meaning the border and how the button is decorated. I don't actually want any decoration for the button. I don't even want the button to appear, because I'm going to put this image in the button. But really, all I want it to be is an image. I don't want anything else to this button. So I'm going to set this to gtk.relief, if I can spell, style none. So we created a button. We gave it a relief style of none, meaning there's really nothing to this button. So let's add something to the button. So gtk.button set image. And we're setting this, of course, for button one. And then I'm going to do the dollar sign, because again, this is the same as doing parentheses. I would have to do parentheses for the next part here, which is just image one. So we're setting the image inside the button. What are we setting it to? We're setting it to image one. That variable that we set earlier, if I scroll back up, image one is the location to that ping file there. Next, I want to make sure that the buttons don't expand vertically and horizontally and all of that, because it's going to look really weird. So I'm going to do a gtk.widget set h expand for horizontal expand. And then button one is the widget we're setting, and we're setting that to false. So I don't want a horizontal expansion. I don't want the button to resize, whatever the button size ends up. When I put the image in it, that's the size of the button. And finally, we need to create some kind of action for this button, because right now we've got the button. We put an image in it, but what happens when I press the button? Well, you need to do the following here. You need to do on button one, and then hashtag clicked, then dollar sign do. So this will be a do block. A do block is needed when you're going to run multiple commands as part of a function here being defined. So I'm going to do put string line. This is essentially printing to standard output. And I'm going to print user chose cancel, just letting me know in standard output that I pressed cancel, the cancel button. And then I also want you to run the following function here, gtk.widget destroy. What widget am I destroying? I'm destroying when the window just closed the entire program. Now let's actually stop for a minute, because we've done a lot here. I'm going to write that and let's see if this actually compiles. I just want to see if it compiles correctly. It's still going to be an empty window. Yeah, still an empty window, because even though we created those widgets, we haven't actually placed them inside the window just yet. So let's go ahead and actually start adding stuff to the window so we can see the buttons and images and everything. See if the stuff actually works. So I'm going to go back down here to where I added the grid. We need to add the grid to the window. So the very first thing we need to do, we create the window. Then we add the grid to the window. And then we need to add the buttons to the grid. Then we need to add the images to the buttons. You see how that works? There's a certain pattern here. So I'm going to do hash symbol add, and I'm going to add to the window the grid. Now the grid is empty, so we still won't see anything just yet. So now we need to add to the grid. The way to add to the grid is you do hashtag attach, and then we're attaching to the grid button one. I'm going to add button one. Let me create some spacing there. And then I need to give it four numeric values here. The very first two are kind of like x, y coordinates. In this case, it's going to be zero and zero. So what we're going to do is we're going to place button one in row zero because in programming, you always start counting at zero, not one, right? So we're going to place button one in row zero, column zero, and then how many rows and columns should button one take up? It should take up exactly one row and one column. And then when we defined button one, we already added the image to button one. So let's write and run stack run, and see if it compiles, and see if we actually see a button now. All right, so we see a button, and if I click it, it quits, but you notice the image did not load because I haven't actually put those images in that directory just yet. Let me actually open my file manager. And I created these images earlier today, so give me just a second to navigate to where I had these images saved earlier. And these were just standard icons that I found on my system as part of an icon pack that I kind of repurposed for purposes of this video. Some of them I edited slightly in GIMP, so I'm just going to paste these. I probably should put these in their own directory actually. What I probably should do is create a new directory here. I'm going to call it IMG for image. And let me actually paste those seven ping files into that. And then that way I'm not cluttering up essentially the root directory of this project. Now we get rid of those. All right, so now let me go back to where I defined the location of those images. And what I want to do, a good thing, is evil mode here inside Emacs, or if you were using Vim, this works here. I'm just going to get into visual block mode and I'm going to do a change. And I'm going to change all of those lines to slash IMG slash and hit escape. And I just changed the path to where all of those are. Now let me write and get back into the terminal. Let's run a stack run. And there is the cancel icon. I click it. It does a main quit, right? Or it does a widget destroy on window. So now let me get back into the file. So we have the image loading. Now we never did add label one under image one. So we wanted label one, which says cancel to be under that image. So how we do that is once again, go to the attachments for the grid. Actually, I'm just going to YY to copy and then P to paste. I'm going to attach to grid. And we're going to attach label one. Let me space this so everything is nice and even makes it easier to read. Label one needs to be in the zero column position again. But this time we're going to make it row one. So one row lower than button one. So just under it. And again, it's going to take up one column and one row. That's right. And then go back to the terminal run stack run. Now see if now we have an image and a label we do and the label is bolded because we added that. So now we just need to add the other six images and labels. So let me go back to button one. So what we need to do is we need to create buttons two through seven. And basically we just should copy this, copy it six more times, and then just adjust the settings to what they need to be. But I've already done this off camera. I'm just going to do a paste here. So we create a new button. Once again, relief style is none. We add image two to the empty button two. And this time what this is is the logout. So when we click button two, what I want you to do is print the standard output. User chose logout and the command to logout. There's not really a good command to kill Xmonad. I'm going to do kill all and then the Xmonad binaries. Actually Xmonad-X86 underscore 64-Linux. If you wanted a more nuclear option, you know, I could use this here, which is call command, which is a way to run system commands using Haskell. And I'm going to run pkill-u and then the name of my user. So kill all the processes that my user started, which would include Xmonad. So it's just going to kill everything and kick us back out to my login manager. Now you notice call command has this red squiggly line under it in Emacs, meaning that is not in scope. That particular command, that function, is because call command is part of a library we have not actually imported. That is part of a system process. So let me go back to the imports and add system dot process to the imports. Also, we never defined the user variable that I was using. If I scroll back down. See, we're going to run pkill-u and then plus plus user. That variable, well, what is user? Well, let me go back to where I defined home. That particular variable, we're going to do user. User is going to be get effective user name. So this is a Haskell function that gets your user's username. Now this particular function, you see, it's in red because that's part of a library that, again, we have not actually imported. And I know this one is part of system dot posix dot user. So let me go to imports and I'm going to import system dot posix dot user. Let me write and you see the red line goes away. So this variable is fine here. And if I go back down to the button where we were doing the call command, you see, there's no error there anymore. There's no error on user. So all of this should compile. So let me go to the terminal and do a stack run just to verify it compiles correctly. And it does not. It's complaining about importing system dot process and system dot posix dot user. You guys by now probably know why that is, is we can't just import libraries in our main.hs. We have to do it a second time with the stack package.yaml file. So let me go back into the package.hs. Back into the package.yaml file. We need to add a couple more programs here. So system dot process, that particular package is simply called process. And then system dot posix dot user is part of the unix package. Let me write that and then get back into the main.hs. Write that and then do a stack run. And this may take a second because it's going to install the process package. And it's also going to install the unix package. And then it runs the application and yeah, everything is working. Now we added the buttons, all seven buttons and their actions and everything, but they're still not part of the grid. That's really the last thing we need to do. So what we need to do is do an attach to grid button two, and then attach grid label two, and then do the same thing for button three, label three, button four, label four, etc. Once again, to speed up the video a little bit, I'm just going to do a paste here. And you can see button one, label one, button two, label two, etc. And you see button one, label one are at column zero that position. And then right next to them in column one would be button two, label two. And then next to those in column two would be button three, label three, etc. If I did this correctly, let me write, and if I do stack run, we should actually see seven buttons and seven labels now. And there you go. We have seven buttons, seven labels, and did they actually work? I know the cancel button works on video here. I really can't show you the rest of them, because I don't want to reboot the machine or shut down or anything, because it's going to kill my recording. It's going to kill all the Emacs buffers I have open and everything. I will show you the very last one, lock. Now what I did, let me close the program before I start hitting the buttons. What are the actions? Well, the very last one runs call command S lock. That is a Sucluses lock program. So you'd have to have S lock installed on your system for this to work. But what it will do, let me do a stack run, is when I click that it'll run S lock. Now S lock just turns the screen black until I start typing my password. If I type my password correctly, the screen turns blue. And when I hit enter, boom, I'm back in my machine. Suspend, does a suspend, hibernate when hibernate, of course. And yeah, you guys know the rest of the commands. That was really very simple. I'll show you the command system CTL. So system D commands for suspend and hibernate. I did a shutdown dash H now for shutdown. A simple reboot for reboot because on ArchBase systems, most system D distros, you just simply need the word reboot to reboot. And of course, cancel is a widget destroy window, meaning just kill the window. So that was a rather simple little program, right? And let's compare it to OB logout, right? This particular program, right? How quick was that for us to recreate that? Well, let me, once again, just for comparison, run our little program bye-bye, right? And all the buttons work. I will verify. I actually checked it off camera because I did create this before starting the video. It took me under an hour off camera from start to finish to create this little GTK application using Haskell. And this stuff isn't hard. I'm going to actually push this application to my GitLab. I'll put a link in the description where you guys can actually find the source code for this for those of you that want to check it out. Obviously, you want to check it out. This is your first GTK application. So you guys can maybe use it as a study guide or for those of you that just think it's a neat application. Maybe you want to push some commits to it. I may actually use this application, even though I was really using it as an example. I might actually keep this program around. I may actually package it up, create a binary for it. Maybe even put it as part of DTOS in the future. Now, obviously, this was a very basic application to create. You didn't really need to know any Haskell. To create this application, especially with me, just giving you some of the libraries and function names and things like that. Once you get into more complicated things, where the buttons and widgets and sliders and everything actually have to perform more complicated actions, then you actually have to start writing your own Haskell functions, which is a deeper topic. But we're going to get into that, I think, at some point. If you guys want to see more Haskell, more GTK, let me know down in the comments. Before I go, I need to thank a few special people, though. I need to thank Devin, Dustin, Gabe, James, Max, Matt, Michael, Mitchell. I almost messed that up. Paul, Scott, Wes, Helen, Armour, Dragon, Chuck, Commander. Okay, I did mess it up. Commander, Angry, Dio, Kai, Dylan, George, Lee, Lennox, Ninja, Marsha, Mike, Erion, Alexander, Peace, Origin, Madore, Polytech, Realiteats for Los Merid, Prophet, Steven, Willy, these guys. They're my has tiered patrons over on Patreon without these guys. This episode about creating this logout program using Haskell and GTK, it wouldn't have been possible. The show is also brought to you by each and every one of these. Fine ladies and gentlemen, all these names you're seeing on the screen right now. These are all my supporters over on Patreon because I don't have any corporate sponsors. Corporate sponsors wouldn't sponsor this stuff. I depend on you guys. If you want to see more videos about Lennox and Brain open source software, subscribe to DistroTube over on Patreon. Peace. Maybe I should create some GTK games for DTOS.