{"id":1535,"date":"2013-08-26T12:22:44","date_gmt":"2013-08-26T19:22:44","guid":{"rendered":"https:\/\/dylanmc.ca\/\/-\/?p=1535"},"modified":"2021-12-01T11:25:51","modified_gmt":"2021-12-01T19:25:51","slug":"gnome-break-timer-week-10","status":"publish","type":"post","link":"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/","title":{"rendered":"GNOME Break Timer: Week 10"},"content":{"rendered":"\n<p>Earlier, when I mentioned that I was going to work on polish, I was thinking of a rather unfortunate line in my original roadmap that honestly just said &#8220;polish.&#8221; I started this chunk of my GSoC project with a new list of things I have been putting off for said polish phase, and it turned out to be quite substantial. I have several cool new things this week.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>First, I added a simple, custom container widget that allocates space for all of it children &#8211; whether or not they are visible &#8211; and distributes that space among the visible children. This way, our Break Schedule dialog is always the same shape, even though its contents change. This is sort of like using a GtkStack with the homogeneous property set to true. Once I wrapped my head around size requests and allocations and requisitions, it was really easy to implement. I&#8217;m not sure if it&#8217;s <em>correct<\/em>, strictly speaking, but it works for me.<\/p>\n\n\n\n<p><video src=\"https:\/\/s1.dylanmccall.com\/gnome-break-timer\/screenshots\/gsoc-week10-screencast.webm\" controls=\"controls\" width=\"700\" height=\"436\"><br><\/video><\/p>\n\n\n\n<pre class=\"wp-block-preformatted prettyprint\">class FixedSizeGrid : Gtk.Grid {\n\tpublic FixedSizeGrid() {\n\t\tObject();\n\t}\n\n\tpublic override void adjust_size_request (Gtk.Orientation orientation, ref int minimum_size, ref int natural_size) {\n\t\tforeach (Gtk.Widget widget in this.get_hidden_children()) {\n\t\t\tint widget_allocated_size = 0;\n\n\t\t\tif (orientation == Gtk.Orientation.VERTICAL &amp;&amp; this.orientation == Gtk.Orientation.VERTICAL) {\n\t\t\t\twidget_allocated_size = widget.get_allocated_height();\n\t\t\t} else if (orientation == Gtk.Orientation.HORIZONTAL &amp;&amp; this.orientation == Gtk.Orientation.HORIZONTAL) {\n\t\t\t\twidget_allocated_size = widget.get_allocated_width();\n\t\t\t}\n\n\t\t\tminimum_size += widget_allocated_size;\n\t\t\tnatural_size += widget_allocated_size;\n\n\t\t\twidget.adjust_size_request(orientation, ref minimum_size, ref natural_size);\n\t\t}\n\n\t\tbase.adjust_size_request(orientation, ref minimum_size, ref natural_size);\n\t}\n\n\tprivate List get_hidden_children() {\n\t\tvar hidden_children = new List();\n\t\tforeach (Gtk.Widget widget in this.get_children()) {\n\t\t\tif (! widget.is_visible()) hidden_children.append(widget);\n\t\t}\n\t\treturn hidden_children;\n\t}\n}<\/pre>\n\n\n\n<p>The big thing I worked on over the last two weeks was making the break timer service remember its state between sessions. Break Timer will remember if you need to take a break after you log out or restart the computer, and in the future it will be able to keep track of interesting statistics very easily. This also makes it much, much harder to &#8220;cheat,&#8221; by accident or intentionally, because it will always pick up where it left off.<\/p>\n\n\n\n<p>I decided to store the program&#8217;s state in the user&#8217;s cache folder using a json file, since we can work with json-glib quite nicely from Vala code. That happens when the process is (cleanly) interrupted or when gnome-session says it&#8217;s time to stop. (Thanks to Guilhem Bonnefille on gnome-devel-list for pointing me in the right direction about gnome-session). When the application starts, it reads that cache file and updates all its timers and counters accordingly. The way I implemented this leaves the door wide open for keeping breaks in sync <em>between<\/em> systems, over the network, which would be really cool.<\/p>\n\n\n\n<p>I ran some finicky problems working on this; I guess I don&#8217;t usually have to work with quite as many moving parts. I was very glad that several years of people extolling the virtues of test-driven development (most recently <a href=\"http:\/\/www.cs.sfu.ca\/~cameron\/\">David Cameron&#8217;s<\/a> awesome Quality Assurance course at SFU) finally rubbed off on me: as soon as I wrote a test case for the problem I was working on, it all got way easier. And I got a (slightly clunky) test case for free! I must remember to do more of that.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Earlier, when I mentioned that I was going to work on polish, I was thinking of a rather unfortunate line in my original roadmap that honestly just said &#8220;polish.&#8221; I started this chunk of my GSoC project with a new list of things I have been putting off for said polish phase, and it turned out to be quite substantial. I have several cool new things this week&hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[55],"tags":[],"class_list":["post-1535","post","type-post","status-publish","format-standard","hentry","category-gsoc-2013"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>GNOME Break Timer: Week 10 - Dylan McCall<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"GNOME Break Timer: Week 10 - Dylan McCall\" \/>\n<meta property=\"og:description\" content=\"Earlier, when I mentioned that I was going to work on polish, I was thinking of a rather unfortunate line in my original roadmap that honestly just said &#8220;polish.&#8221; I started this chunk of my GSoC project with a new list of things I have been putting off for said polish phase, and it turned out to be quite substantial. I have several cool new things this week&hellip;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/\" \/>\n<meta property=\"og:site_name\" content=\"Dylan McCall\" \/>\n<meta property=\"article:published_time\" content=\"2013-08-26T19:22:44+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-12-01T19:25:51+00:00\" \/>\n<meta name=\"author\" content=\"Dylan McCall\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dylan McCall\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/\"},\"author\":{\"name\":\"Dylan McCall\",\"@id\":\"https:\/\/dylanmc.ca\/\/-\/#\/schema\/person\/c244419a779c5414c768bc53ac5fb2d5\"},\"headline\":\"GNOME Break Timer: Week 10\",\"datePublished\":\"2013-08-26T19:22:44+00:00\",\"dateModified\":\"2021-12-01T19:25:51+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/\"},\"wordCount\":443,\"articleSection\":[\"GSoC 2013\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/\",\"url\":\"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/\",\"name\":\"GNOME Break Timer: Week 10 - Dylan McCall\",\"isPartOf\":{\"@id\":\"https:\/\/dylanmc.ca\/\/-\/#website\"},\"datePublished\":\"2013-08-26T19:22:44+00:00\",\"dateModified\":\"2021-12-01T19:25:51+00:00\",\"author\":{\"@id\":\"https:\/\/dylanmc.ca\/\/-\/#\/schema\/person\/c244419a779c5414c768bc53ac5fb2d5\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/\"]}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/dylanmc.ca\/\/-\/#website\",\"url\":\"https:\/\/dylanmc.ca\/\/-\/\",\"name\":\"Dylan McCall\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/dylanmc.ca\/\/-\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/dylanmc.ca\/\/-\/#\/schema\/person\/c244419a779c5414c768bc53ac5fb2d5\",\"name\":\"Dylan McCall\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/dylanmc.ca\/\/-\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/c94ab3a7e6a884542205e0408711cd54bb1fd5f4e90e7a5f621a54656a18a037?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/c94ab3a7e6a884542205e0408711cd54bb1fd5f4e90e7a5f621a54656a18a037?s=96&d=mm&r=g\",\"caption\":\"Dylan McCall\"},\"description\":\"Software developer, tea drinker, GNOME contributor. Occasionally a raving fanatic.\",\"sameAs\":[\"https:\/\/dylanmc.ca\/\/-\"],\"url\":\"https:\/\/dylanmc.ca\/\/-\/blog\/author\/dylan\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"GNOME Break Timer: Week 10 - Dylan McCall","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/","og_locale":"en_US","og_type":"article","og_title":"GNOME Break Timer: Week 10 - Dylan McCall","og_description":"Earlier, when I mentioned that I was going to work on polish, I was thinking of a rather unfortunate line in my original roadmap that honestly just said &#8220;polish.&#8221; I started this chunk of my GSoC project with a new list of things I have been putting off for said polish phase, and it turned out to be quite substantial. I have several cool new things this week&hellip;","og_url":"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/","og_site_name":"Dylan McCall","article_published_time":"2013-08-26T19:22:44+00:00","article_modified_time":"2021-12-01T19:25:51+00:00","author":"Dylan McCall","twitter_misc":{"Written by":"Dylan McCall","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/#article","isPartOf":{"@id":"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/"},"author":{"name":"Dylan McCall","@id":"https:\/\/dylanmc.ca\/\/-\/#\/schema\/person\/c244419a779c5414c768bc53ac5fb2d5"},"headline":"GNOME Break Timer: Week 10","datePublished":"2013-08-26T19:22:44+00:00","dateModified":"2021-12-01T19:25:51+00:00","mainEntityOfPage":{"@id":"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/"},"wordCount":443,"articleSection":["GSoC 2013"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/","url":"https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/","name":"GNOME Break Timer: Week 10 - Dylan McCall","isPartOf":{"@id":"https:\/\/dylanmc.ca\/\/-\/#website"},"datePublished":"2013-08-26T19:22:44+00:00","dateModified":"2021-12-01T19:25:51+00:00","author":{"@id":"https:\/\/dylanmc.ca\/\/-\/#\/schema\/person\/c244419a779c5414c768bc53ac5fb2d5"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/dylanmc.ca\/\/-\/blog\/2013\/08\/26\/gnome-break-timer-week-10\/"]}]},{"@type":"WebSite","@id":"https:\/\/dylanmc.ca\/\/-\/#website","url":"https:\/\/dylanmc.ca\/\/-\/","name":"Dylan McCall","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/dylanmc.ca\/\/-\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/dylanmc.ca\/\/-\/#\/schema\/person\/c244419a779c5414c768bc53ac5fb2d5","name":"Dylan McCall","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/dylanmc.ca\/\/-\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/c94ab3a7e6a884542205e0408711cd54bb1fd5f4e90e7a5f621a54656a18a037?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c94ab3a7e6a884542205e0408711cd54bb1fd5f4e90e7a5f621a54656a18a037?s=96&d=mm&r=g","caption":"Dylan McCall"},"description":"Software developer, tea drinker, GNOME contributor. Occasionally a raving fanatic.","sameAs":["https:\/\/dylanmc.ca\/\/-"],"url":"https:\/\/dylanmc.ca\/\/-\/blog\/author\/dylan\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pcXOQX-oL","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/posts\/1535","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/comments?post=1535"}],"version-history":[{"count":13,"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/posts\/1535\/revisions"}],"predecessor-version":[{"id":11006,"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/posts\/1535\/revisions\/11006"}],"wp:attachment":[{"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/media?parent=1535"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/categories?post=1535"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dylanmc.ca\/\/-\/wp-json\/wp\/v2\/tags?post=1535"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}