4 Hugues Ross - Blog: Awesomewm
Hugues Ross
Showing posts with label Awesomewm. Show all posts
Showing posts with label Awesomewm. Show all posts

7/16/17

Getting Organized - 6 - Tick Tock

Hello again, dear readers. Once again, it's time to make my life a little more productive. In my previous post, I grappled with my computer a little bit in order to bring my to-do list up every morning. This month, I'm going to work on my time management a little.

When I mentioned that I wanted a timer back in May, I said that I wanted "I'd like something that fits with everything else". I'm not entirely sure how many purely hypothetical beers I drank before writing that thought, but looking back it sounds more like the mutterings of the local town loony than anything important. I assure you, however, that this strange little collection of words will make sense if you read the following two paragraphs. So, y'know, you can just skip them if you're up for a challenge.

So, if you've been reading these posts religiously then you'll know that I use Awesome to manage my desktop. This gives me lots of control and customization options, but also makes using "traditional" desktop apps cumbersome at times. In this case, a quick Google search will find you endless pages of linux timer apps, coming in exactly two flavors:
  1. Pretty (useless) dialog windows that take up half your screen with fancy Large Text
  2. Icons in your system tray
Option 1 is unappealing in general, but also breaks with my window-management preferences. I could let one of these apps ignore Awesome's tiling rules, but then it would also block me from interacting with whatever's underneath it. Oh, and it's definitely not getting its own special desktop, so that's out. Option 2 would work nicely...if I had a system tray. I could add one and watch it fill with useless incongruous icons, or I could not do that and sleep well at night. But, there's another solution. Let's take a look at my bar for a moment:
Pretty much all of those nice little UI bits are custom. So, I can make my own "Option 2" that fits with the visual style of my desktop and does exactly what I want.

If you're still following along with my little scheme to make a timer but you're not sure it's quick or feasible, then I have some good news: It's done. I secretly went and did it this morning. Normally, I write and code together, but I just wasn't in the mood for 6 AM blogging. What was in the mood for was Runescape (???), and I didn't want to miss any deadlines in the process. I suppose you could say I was motivated by laziness, but I'm not about to complain!

The Implementation

The result of my mad morning keyboard mashing was just under 100 lines of Lua code. Most of that is UI boilerplate, but there's about 40 lines of actual logic in there that might interest someone, so let's give that a look:
   52 local timer = gears.timer {
   53     timeout   = 1,
   54     autostart = false,
   55     callback  = function()
   56         seconds_left = seconds_left - 1
   57         if seconds_left == 0 then
   58             awful.spawn({"mplayer", "/home/df458/assets/se/Notify01.wav"});
   59 
   60             local message = string.format("Your timer of %02d:%02d has ended", math.floor(seconds_total/3600), math.floor(seconds_total%3600/60))
   61             if seconds_total < 3600 then
   62                 message = string.format("Your timer of %02d:%02d has ended", math.floor(seconds_total/60), seconds_total%60)
   63             end
   64             naughty.notify {
   65                 title = "Time's up!",
   66                 text = message,
   67                 timeout = 300
   68             }
   69         elseif seconds_left < 0 then
   70             widget:set_visible(false)
   71             timer:stop()
   72         end
   73         progress:set_value(1 - (seconds_left / seconds_total))
   74         if seconds_left < 3600 then
   75             label:set_markup(string.format("%02d:%02d", math.floor(seconds_left/60), seconds_left%60))
   76         else
   77             label:set_markup(string.format("%02d:%02d", math.floor(seconds_left/3600), math.floor(seconds_left%3600/60)))
   78         end
   79     end
   80 }
   81 
   82 function activate_timer(seconds)
   83     seconds_left = seconds
   84     seconds_total = seconds
   85     widget:set_visible(true)
   86     progress:set_value(0)
   87     if seconds_left < 3600 then
   88         label:set_markup(string.format("%02d:%02d", math.floor(seconds_left/60), seconds_left%60))
   89     else
   90         label:set_markup(string.format("%02d:%02d", math.floor(seconds_left/3600), math.floor(seconds_left%3600/60)))
   91     end
   92     timer:start()
   93 end
As you can see, this little code block could probably use some cleaning. With that said, it works pretty well and demonstrates just how easy it is to make a timer. All I really do is set two numbers to how many seconds I want to wait, then subtract one from the 1st number every second. The second number isn't even necessary at all, but I use it to add a progress indicator. Beyond that, the rest is just making a nice text representation that switches between hour:minute to minute:second as necessary. When the timer's running, my little info are looks like this:
It's simple, sure, but it works quite well! Next time, I'll be wrapping up this series with some final touches to task management.

6/11/17

Getting Organized - 5 - Some Awesome Work

When we last left off on my quest for good time management, I decided to share my pizza recipe instead of being productive. Clearly, I'm making good progress. Now then, it's time to do some actual programming.

Awesome!

No, that's not your cries of joy. Awesome is the Window Manager that I use on all of my machines nowadays. In addition to laying out my windows in a pleasing fashion, it also exposes a powerful lua API for customizing and scripting, well, everything. This includes the UI, allowing for some very in-depth customizations!

Last time, I made a list of tasks to complete:
  1. Automatically opening my wiki every morning
  2. A simple timer that fits with my workflow
  3. A way to create tasks remotely while at work
Today, I'm going to finish off the first task. Furthermore, Awesome is going to help me with that.

Hello, Wiki!

Originally, I said that opening my wiki in the morning would be "super-easy to do". I lied! I lied to everyone, even myself! And what a lie it was.

An Unexpected Snag

The easiest way for me to make programs start on launch is to add them to my xinitrc file. In this case, I actually can't do that. Because the terminal that I run vim in won't have its settings ready before my xinitrc finishes running. That means that if I use my xinitrc to bring up my wiki, the colors and fonts will be wrong and it'll have a horrifying scrollbar that looks like it crawled out of Windows 3.1.

Obviously, I don't want that. Awesome gives me the ability to run applications, so I can have it launch my wiki. Perfect, right? Wrong! To help debug scripts and configuration, Awesome provides a mechanism to restart it without closing anything. This is also great! However, this means that every time I restart Awesome it'll also open the wiki again. So, we have a conundrum.

The Solution

The second problem can be solved, but it'll take a few small additions. The goal here is to have Awesome run certain programs on startup, but only if it isn't restarting. To do that, I need to store some information across runs.

Conveniently, Awesome has an event that runs when it exits. Even better, that event tells you whether the exit is part of a restart or not! So, I simply write a value to a file based on whether Awesome is restarting or not. Then, Awesome can read the value when it starts and use it to make decisions. The result looks like this:
awesome.connect_signal("exit", function(restart)
    local lastrun = io.open("~/.config/awesome/lastrun", "w")
    if lastrun ~= nil then
        if restart then
            lastrun:write(0)
        else
            lastrun:write(1)
        end
        lastrun:close()
    end
end)

...

local lastrun = io.open("~/.config/awesome/lastrun", "r")
if lastrun ~= nil then
    local was_quit = lastrun:read("*n")
    if was_quit == 1 then
        for i,e in pairs(autostart_once) do
            awful.spawn(e)
        end
    end
    lastrun:close()
else
    for i,e in pairs(autostart_once) do
        awful.spawn(e)
    end
end

for i,e in pairs(autostart_each) do
    awful.spawn(e)
end

As you can see, it's actually pretty simple. Anything that I add to the autostart_once list will only start if Awesome shut down properly last time it ran. On the other hand, anything in the autostart_each list will run every time Awesome runs. This makes for a convenient solution that I can use as much as I want going forward.

So, that was a semi-complicated solution to a relatively simple problem. Come back next time for some tougher-but-more-straightforward scripting.