[gnome-sound-recorder/wip/cdavis/gtk4] general: Initial port to GTK4




commit fc01a41cb1052cdd1423f5090047cf7cab769947
Author: Christopher Davis <brainblasted disroot org>
Date:   Thu Dec 3 03:43:34 2020 -0800

    general: Initial port to GTK4
    
    Requires some work on events and icons.

 data/ui/help-overlay.ui      |  13 --
 data/ui/recorder.ui          | 132 +++---------
 data/ui/row.ui               | 492 +++++++++++++++----------------------------
 data/ui/window.ui            | 228 ++++++--------------
 meson.build                  |   4 +-
 org.gnome.SoundRecorder.json |   4 +-
 src/application.js           |  39 ++--
 src/main.js                  |   6 +-
 src/recorderWidget.js        |  10 +-
 src/recordingsListBox.js     |   6 +-
 src/row.js                   |  26 ++-
 src/waveform.js              |  57 ++---
 src/window.js                |   5 +-
 13 files changed, 348 insertions(+), 674 deletions(-)
---
diff --git a/data/ui/help-overlay.ui b/data/ui/help-overlay.ui
index c75a762..efd4592 100644
--- a/data/ui/help-overlay.ui
+++ b/data/ui/help-overlay.ui
@@ -5,13 +5,11 @@
     <property name="modal">1</property>
     <child>
       <object class="GtkShortcutsSection">
-        <property name="visible">1</property>
         <property name="section-name">shortcuts</property>
         <property name="max-height">10</property>
         <child>
 
           <object class="GtkShortcutsGroup">
-            <property name="visible">1</property>
             <property name="title" translatable="yes" context="shortcut window">General</property>
             <child>
               <object class="GtkShortcutsShortcut">
@@ -22,14 +20,12 @@
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">S</property>
                 <property name="title" translatable="yes" context="shortcut window">Stop Recording</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">space</property>
                 <property name="title" translatable="yes" context="shortcut window">Play / Pause / 
Resume</property>
               </object>
@@ -37,28 +33,24 @@
 
              <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">Delete</property>
                 <property name="title" translatable="yes" context="shortcut window">Delete</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">F10</property>
                 <property name="title" translatable="yes" context="shortcut window">Open menu</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">&lt;ctrl&gt;question</property>
                 <property name="title" translatable="yes" context="shortcut window">Keyboard 
shortcuts</property>
               </object>
             </child>
             <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">&lt;ctrl&gt;Q</property>
                 <property name="title" translatable="yes" context="shortcut window">Quit</property>
               </object>
@@ -67,32 +59,27 @@
         </child>
         <child>
           <object class="GtkShortcutsGroup">
-            <property name="visible">1</property>
             <property name="title" translatable="yes" context="shortcut window">Recording</property>
              <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">B</property>
                 <property name="title" translatable="yes" context="shortcut window">Seek Backward</property>
               </object>
             </child>
              <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">N</property>
                 <property name="title" translatable="yes" context="shortcut window">Seek Forward</property>
               </object>
             </child>
              <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">F2</property>
                 <property name="title" translatable="yes" context="shortcut window">Rename</property>
               </object>
             </child>
              <child>
               <object class="GtkShortcutsShortcut">
-                <property name="visible">1</property>
                 <property name="accelerator">&lt;ctrl&gt;s</property>
                 <property name="title" translatable="yes" context="shortcut window">Export</property>
               </object>
diff --git a/data/ui/recorder.ui b/data/ui/recorder.ui
index 0c36559..81a802a 100644
--- a/data/ui/recorder.ui
+++ b/data/ui/recorder.ui
@@ -3,31 +3,22 @@
 <interface>
   <requires lib="gtk+" version="3.22"/>
   <requires lib="libhandy" version="1.0"/>
-  <template class="Gjs_RecorderWidget" parent="GtkBin">
-    <property name="visible">True</property>
-    <property name="can_focus">False</property>
+  <template class="Gjs_RecorderWidget" parent="GtkBox">
     <child>
-      <object class="HdyWindowHandle">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
+      <object class="GtkWindowHandle">
+        <property name="hexpand">True</property>
         <child>
           <object class="GtkBox">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
             <property name="margin_top">24</property>
             <property name="margin_bottom">24</property>
             <property name="orientation">vertical</property>
             <child>
               <object class="GtkBox" id="recorderBox">
                 <property name="height_request">230</property>
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="valign">center</property>
                 <property name="orientation">vertical</property>
                 <child>
                   <object class="GtkLabel" id="recorderTime">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="margin_top">18</property>
                     <property name="use_markup">True</property>
                     <attributes>
@@ -38,92 +29,57 @@
                       <class name="recorder-time-label"/>
                     </style>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="pack_type">end</property>
-                    <property name="position">0</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
             </child>
             <child>
               <object class="GtkBox">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="halign">center</property>
                 <property name="valign">center</property>
                 <property name="margin_top">8</property>
                 <property name="spacing">18</property>
                 <child>
                   <object class="GtkStack" id="playbackStack">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <child>
-                      <object class="GtkButton" id="resumeBtn">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <property name="tooltip_text" translatable="yes">Resume Recording</property>
-                        <property name="halign">center</property>
-                        <property name="valign">center</property>
-                        <property name="action_name">recorder.resume</property>
-                        <child>
-                          <object class="GtkImage">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
+                      <object class="GtkStackPage">
+                        <property name="name">recorder-start</property>
+                        <property name="child">
+                          <object class="GtkButton" id="resumeBtn">
+                            <property name="receives_default">True</property>
+                            <property name="tooltip_text" translatable="yes">Resume Recording</property>
+                            <property name="halign">center</property>
+                            <property name="valign">center</property>
+                            <property name="action_name">recorder.resume</property>
                             <property name="icon_name">media-playback-start-symbolic</property>
+                            <style>
+                              <class name="rounded-button"/>
+                            </style>
                           </object>
-                        </child>
-                        <style>
-                          <class name="rounded-button"/>
-                        </style>
+                        </property>
                       </object>
-                      <packing>
-                        <property name="name">recorder-start</property>
-                      </packing>
                     </child>
                     <child>
-                      <object class="GtkButton" id="pauseBtn">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <property name="tooltip_text" translatable="yes">Pause Recording</property>
-                        <property name="halign">center</property>
-                        <property name="valign">center</property>
-                        <property name="action_name">recorder.pause</property>
-                        <child>
-                          <object class="GtkImage">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
+                      <object class="GtkStackPage">
+                        <property name="name">recorder-pause</property>
+                        <property name="child">
+                          <object class="GtkButton" id="pauseBtn">
+                            <property name="receives_default">True</property>
+                            <property name="tooltip_text" translatable="yes">Pause Recording</property>
+                            <property name="halign">center</property>
+                            <property name="valign">center</property>
+                            <property name="action_name">recorder.pause</property>
                             <property name="icon_name">media-playback-pause-symbolic</property>
+                            <style>
+                              <class name="rounded-button"/>
+                            </style>
                           </object>
-                        </child>
-                        <style>
-                          <class name="rounded-button"/>
-                        </style>
+                        </property>
                       </object>
-                      <packing>
-                        <property name="name">recorder-pause</property>
-                        <property name="position">1</property>
-                      </packing>
                     </child>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkButton">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="tooltip_text" translatable="yes">Stop Recording</property>
                     <property name="halign">center</property>
@@ -131,10 +87,8 @@
                     <property name="action_name">recorder.stop</property>
                     <child>
                       <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="icon_name">media-playback-stop-symbolic</property>
-                        <property name="icon_size">3</property>
+                        <property name="pixel_size">24</property>
                       </object>
                     </child>
                     <style>
@@ -143,45 +97,21 @@
                       <class name="large"/>
                     </style>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkButton">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="tooltip_text" translatable="yes">Delete Recording</property>
                     <property name="halign">center</property>
                     <property name="valign">center</property>
                     <property name="action_name">recorder.cancel</property>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="icon_name">user-trash-symbolic</property>
-                      </object>
-                    </child>
+                    <property name="icon_name">user-trash-symbolic</property>
                     <style>
                       <class name="rounded-button"/>
                     </style>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">2</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="pack_type">end</property>
-                <property name="position">1</property>
-              </packing>
             </child>
           </object>
         </child>
diff --git a/data/ui/row.ui b/data/ui/row.ui
index 6fdcb41..317b8c1 100644
--- a/data/ui/row.ui
+++ b/data/ui/row.ui
@@ -4,431 +4,287 @@
   <requires lib="gtk+" version="3.20"/>
   <requires lib="libhandy" version="0.0"/>
   <template class="Gjs_Row" parent="GtkListBoxRow">
-    <property name="visible">True</property>
-    <property name="can_focus">True</property>
     <property name="selectable">False</property>
     <child>
       <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
         <property name="margin_top">12</property>
         <property name="margin_bottom">12</property>
         <property name="orientation">vertical</property>
         <child>
           <object class="GtkStack" id="mainStack">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
             <child>
-              <object class="GtkBox">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="valign">center</property>
-                <property name="margin_start">12</property>
-                <property name="margin_end">12</property>
-                <property name="hexpand">True</property>
-                <child>
-                  <object class="GtkLabel" id="duration">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="halign">end</property>
-                    <property name="use_markup">True</property>
-                    <attributes>
-                      <attribute name="font-features" value="tnum=1"/>
-                    </attributes>
-                  </object>
-                  <packing>
-                    <property name="pack_type">end</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
+              <object class="GtkStackPage">
+                <property name="name">display</property>
+                <property name="child">
                   <object class="GtkBox">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="orientation">vertical</property>
+                    <property name="valign">center</property>
+                    <property name="margin_start">12</property>
+                    <property name="margin_end">12</property>
+                    <property name="hexpand">True</property>
                     <child>
-                      <object class="GtkLabel" id="name">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="ellipsize">end</property>
-                        <property name="single_line_mode">True</property>
-                        <property name="xalign">0</property>
-                        <style>
-                          <class name="title"/>
-                        </style>
+                      <object class="GtkBox">
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkLabel" id="name">
+                            <property name="ellipsize">end</property>
+                            <property name="single_line_mode">True</property>
+                            <property name="xalign">0</property>
+                            <style>
+                              <class name="title"/>
+                            </style>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="date">
+                            <property name="margin_top">4</property>
+                            <property name="xalign">0</property>
+                            <style>
+                              <class name="subtitle"/>
+                            </style>
+                          </object>
+                        </child>
                       </object>
-                      <packing>
-                        <property name="position">0</property>
-                      </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel" id="date">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="margin_top">4</property>
-                        <property name="xalign">0</property>
-                        <style>
-                          <class name="subtitle"/>
-                        </style>
+                      <object class="GtkLabel" id="duration">
+                        <property name="hexpand">True</property>
+                        <property name="halign">end</property>
+                        <property name="use_markup">True</property>
+                        <attributes>
+                          <attribute name="font-features" value="tnum=1"/>
+                        </attributes>
                       </object>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
                     </child>
                   </object>
-                  <packing>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
+                </property>
               </object>
-              <packing>
-                <property name="name">display</property>
-              </packing>
             </child>
             <child>
-              <object class="GtkEntry" id="entry">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="margin_start">12</property>
-                <property name="margin_end">12</property>
-                <property name="activates_default">True</property>
-              </object>
-              <packing>
+              <object class="GtkStackPage">
                 <property name="name">edit</property>
-                <property name="position">1</property>
-              </packing>
+                <property name="child">
+                  <object class="GtkEntry" id="entry">
+                    <property name="margin_start">12</property>
+                    <property name="margin_end">12</property>
+                    <property name="activates_default">True</property>
+                  </object>
+                </property>
+              </object>
             </child>
           </object>
-          <packing>
-            <property name="position">0</property>
-          </packing>
         </child>
         <child>
           <object class="GtkRevealer" id="revealer">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
             <property name="transition_duration">250</property>
             <property name="transition_type">GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN</property>
             <child>
               <object class="GtkBox">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="orientation">vertical</property>
                 <child>
                   <object class="GtkStack" id="waveformStack">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="transition_type">crossfade</property>
                     <child>
-                      <object class="GtkSpinner">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="active">True</property>
-                      </object>
-                      <packing>
+                      <object class="GtkStackPage">
                         <property name="name">loading</property>
-                      </packing>
+                        <property name="child">
+                          <object class="GtkSpinner">
+                            <property name="spinning">True</property>
+                          </object>
+                        </property>
+                      </object>
                     </child>
                   </object>
-                  <packing>
-                    <property name="position">0</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkBox">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="margin_start">12</property>
                     <property name="margin_end">12</property>
                     <property name="margin_top">18</property>
                     <child>
-                      <object class="GtkStack" id="rightStack">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
+                      <object class="GtkBox" id="deleteBtnBox">
                         <child>
-                          <object class="HdySqueezer">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="homogeneous">True</property>
+                          <object class="GtkButton">
+                            <property name="valign">center</property>
+                            <property name="halign">center</property>
+                            <property name="action_name">recording.delete</property>
+                            <property name="receives_default">True</property>
+                            <property name="tooltip_text" translatable="yes">Delete</property>
+                            <property name="icon_name">user-trash-symbolic</property>
+                            <style>
+                              <class name="rounded-button"/>
+                            </style>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkBox" id="playbackControls">
+                        <property name="hexpand">True</property>
+                        <property name="halign">end</property>
+                        <property name="spacing">18</property>
+                        <child>
+                          <object class="GtkButton">
+                            <property name="valign">center</property>
+                            <property name="halign">center</property>
+                            <property name="action_name">recording.seek-backward</property>
+                            <property name="receives_default">True</property>
+                            <property name="tooltip_text" translatable="yes">Seek 10s Backward</property>
+                            <property name="icon_name">skip-back-symbolic</property>
+                            <style>
+                              <class name="rounded-button"/>
+                            </style>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkStack" id="playbackStack">
                             <child>
-                              <object class="GtkBox">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="spacing">8</property>
-                                <child>
-                                  <object class="GtkButton">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
+                              <object class="GtkStackPage">
+                                <property name="name">play</property>
+                                <property name="child">
+                                  <object class="GtkButton" id="playBtn">
                                     <property name="valign">center</property>
                                     <property name="halign">center</property>
                                     <property name="receives_default">True</property>
-                                    <property name="tooltip_text" translatable="yes">Export</property>
-                                    <property name="action_name">recording.export</property>
+                                    <property name="action_name">recording.play</property>
+                                    <property name="tooltip_text" translatable="yes">Play</property>
                                     <child>
                                       <object class="GtkImage">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">False</property>
-                                        <property name="icon_name">document-save-symbolic</property>
+                                        <property name="icon_name">media-playback-start-symbolic</property>
+                                        <property name="pixel_size">24</property>
                                       </object>
                                     </child>
                                     <style>
                                       <class name="rounded-button"/>
+                                      <class name="large"/>
                                     </style>
                                   </object>
-                                  <packing>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkButton">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
+                                </property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkStackPage">
+                                <property name="name">pause</property>
+                                <property name="child">
+                                  <object class="GtkButton" id="pauseBtn">
                                     <property name="valign">center</property>
                                     <property name="halign">center</property>
+                                    <property name="action_name">recording.pause</property>
                                     <property name="receives_default">True</property>
-                                    <property name="tooltip_text" translatable="yes">Rename</property>
-                                    <property name="action_name">recording.rename</property>
+                                    <property name="tooltip_text" translatable="yes">Pause</property>
                                     <child>
                                       <object class="GtkImage">
-                                        <property name="visible">True</property>
-                                        <property name="can_focus">False</property>
-                                        <property name="icon_name">document-edit-symbolic</property>
+                                        <property name="icon_name">media-playback-pause-symbolic</property>
+                                        <property name="pixel_size">24</property>
                                       </object>
                                     </child>
                                     <style>
                                       <class name="rounded-button"/>
+                                      <class name="large"/>
                                     </style>
                                   </object>
-                                  <packing>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                              </object>
-                            </child>
-                            <child>
-                              <object class="GtkMenuButton">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
-                                <property name="menu_model">optionMenu</property>
-                                <property name="halign">end</property>
-                                <property name="valign">center</property>
-                                <child>
-                                  <object class="GtkImage">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="icon_name">view-more-symbolic</property>
-                                  </object>
-                                </child>
-                                <style>
-                                  <class name="rounded-button"/>
-                                </style>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="name">options</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="saveBtn">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="can_default">True</property>
-                            <property name="valign">center</property>
-                            <property name="halign">end</property>
-                            <property name="receives_default">False</property>
-                            <property name="tooltip_text" translatable="yes">Save</property>
-                            <property name="action_name">recording.save</property>
-                            <child>
-                              <object class="GtkImage">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">emblem-ok-symbolic</property>
+                                </property>
                               </object>
                             </child>
-                            <style>
-                              <class name="rounded-button"/>
-                              <class name="suggested-action"/>
-                            </style>
                           </object>
-                          <packing>
-                            <property name="name">save</property>
-                            <property name="position">1</property>
-                          </packing>
                         </child>
-                      </object>
-                      <packing>
-                        <property name="pack_type">end</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkBox" id="deleteBtnBox">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <child>
                           <object class="GtkButton">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
                             <property name="valign">center</property>
                             <property name="halign">center</property>
-                            <property name="action_name">recording.delete</property>
+                            <property name="action_name">recording.seek-forward</property>
                             <property name="receives_default">True</property>
-                            <property name="tooltip_text" translatable="yes">Delete</property>
-                            <child>
-                              <object class="GtkImage">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">user-trash-symbolic</property>
-                              </object>
-                            </child>
+                            <property name="tooltip_text" translatable="yes">Seek 10s Forward</property>
+                            <property name="icon_name">skip-forward-symbolic</property>
                             <style>
                               <class name="rounded-button"/>
                             </style>
                           </object>
-                          <packing>
-                            <property name="position">0</property>
-                          </packing>
                         </child>
                       </object>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
                     </child>
                     <child>
-                      <object class="GtkBox" id="playbackControls">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">center</property>
-                        <property name="spacing">18</property>
-                        <child>
-                          <object class="GtkButton">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="valign">center</property>
-                            <property name="halign">center</property>
-                            <property name="action_name">recording.seek-backward</property>
-                            <property name="receives_default">True</property>
-                            <property name="tooltip_text" translatable="yes">Seek 10s Backward</property>
-                            <child>
-                              <object class="GtkImage">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">skip-back-symbolic</property>
-                              </object>
-                            </child>
-                            <style>
-                              <class name="rounded-button"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
+                      <object class="GtkStack" id="rightStack">
+                        <property name="hexpand">True</property>
+                        <property name="halign">end</property>
                         <child>
-                          <object class="GtkStack" id="playbackStack">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <child>
-                              <object class="GtkButton" id="playBtn">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="valign">center</property>
-                                <property name="halign">center</property>
-                                <property name="receives_default">True</property>
-                                <property name="action_name">recording.play</property>
-                                <property name="tooltip_text" translatable="yes">Play</property>
+                          <object class="GtkStackPage">
+                            <property name="name">options</property>
+                            <property name="child">
+                              <object class="HdySqueezer">
+                                <property name="homogeneous">True</property>
                                 <child>
-                                  <object class="GtkImage">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="icon_name">media-playback-start-symbolic</property>
-                                    <property name="icon_size">3</property>
+                                  <object class="GtkBox">
+                                    <property name="spacing">8</property>
+                                    <child>
+                                      <object class="GtkButton">
+                                        <property name="valign">center</property>
+                                        <property name="halign">center</property>
+                                        <property name="receives_default">True</property>
+                                        <property name="tooltip_text" translatable="yes">Export</property>
+                                        <property name="action_name">recording.export</property>
+                                        <property name="icon_name">document-save-symbolic</property>
+                                        <style>
+                                          <class name="rounded-button"/>
+                                        </style>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkButton">
+                                        <property name="valign">center</property>
+                                        <property name="halign">center</property>
+                                        <property name="receives_default">True</property>
+                                        <property name="tooltip_text" translatable="yes">Rename</property>
+                                        <property name="action_name">recording.rename</property>
+                                        <property name="icon_name">document-edit-symbolic</property>
+                                        <style>
+                                          <class name="rounded-button"/>
+                                        </style>
+                                      </object>
+                                    </child>
                                   </object>
                                 </child>
-                                <style>
-                                  <class name="rounded-button"/>
-                                  <class name="large"/>
-                                </style>
-                              </object>
-                              <packing>
-                                <property name="name">play</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkButton" id="pauseBtn">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="valign">center</property>
-                                <property name="halign">center</property>
-                                <property name="action_name">recording.pause</property>
-                                <property name="receives_default">True</property>
-                                <property name="tooltip_text" translatable="yes">Pause</property>
                                 <child>
-                                  <object class="GtkImage">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="icon_name">media-playback-pause-symbolic</property>
-                                    <property name="icon_size">3</property>
+                                  <object class="GtkMenuButton">
+                                    <property name="receives_default">True</property>
+                                    <property name="menu_model">optionMenu</property>
+                                    <property name="halign">end</property>
+                                    <property name="valign">center</property>
+                                    <property name="icon_name">view-more-symbolic</property>
+                                    <style>
+                                      <class name="rounded-button"/>
+                                    </style>
                                   </object>
                                 </child>
-                                <style>
-                                  <class name="rounded-button"/>
-                                  <class name="large"/>
-                                </style>
                               </object>
-                              <packing>
-                                <property name="name">pause</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
+                            </property>
                           </object>
-                          <packing>
-                            <property name="position">1</property>
-                          </packing>
                         </child>
                         <child>
-                          <object class="GtkButton">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="valign">center</property>
-                            <property name="halign">center</property>
-                            <property name="action_name">recording.seek-forward</property>
-                            <property name="receives_default">True</property>
-                            <property name="tooltip_text" translatable="yes">Seek 10s Forward</property>
-                            <child>
-                              <object class="GtkImage">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="icon_name">skip-forward-symbolic</property>
+                          <object class="GtkStackPage">
+                            <property name="name">save</property>
+                            <property name="child">
+                              <object class="GtkButton" id="saveBtn">
+                                <property name="valign">center</property>
+                                <property name="halign">end</property>
+                                <property name="receives_default">False</property>
+                                <property name="tooltip_text" translatable="yes">Save</property>
+                                <property name="action_name">recording.save</property>
+                                <property name="icon_name">emblem-ok-symbolic</property>
+                                <style>
+                                  <class name="rounded-button"/>
+                                  <class name="suggested-action"/>
+                                </style>
                               </object>
-                            </child>
-                            <style>
-                              <class name="rounded-button"/>
-                            </style>
+                            </property>
                           </object>
-                          <packing>
-                            <property name="position">2</property>
-                          </packing>
                         </child>
                       </object>
-                      <packing>
-                        <property name="expand">True</property>
-                        <property name="position">3</property>
-                      </packing>
                     </child>
                   </object>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
               </object>
             </child>
           </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
         </child>
       </object>
     </child>
diff --git a/data/ui/window.ui b/data/ui/window.ui
index 53bcdef..b870e0a 100644
--- a/data/ui/window.ui
+++ b/data/ui/window.ui
@@ -6,64 +6,39 @@
   <template class="Gjs_Window" parent="HdyApplicationWindow">
     <property name="width_request">350</property>
     <property name="height_request">480</property>
-    <property name="can_focus">False</property>
     <property name="hexpand">True</property>
     <property name="vexpand">True</property>
     <property name="default_width">780</property>
     <property name="default_height">480</property>
+    <property name="title" translatable="yes">Sound Recorder</property>
     <child>
       <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
         <child>
           <object class="GtkRevealer" id="headerRevealer">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
             <property name="reveal_child">True</property>
             <child>
               <object class="HdyHeaderBar">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="title" translatable="yes">Sound Recorder</property>
-                <property name="show_close_button">True</property>
+                <property name="show_title_buttons">True</property>
                 <child>
                   <object class="GtkButton">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
                     <property name="receives_default">False</property>
                     <property name="halign">center</property>
                     <property name="valign">center</property>
                     <property name="action_name">recorder.start</property>
                     <child>
                       <object class="GtkBox">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="spacing">4</property>
                         <child>
                           <object class="GtkImage">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
                             <property name="icon_name">media-record-symbolic</property>
                           </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
                         </child>
                         <child>
                           <object class="GtkLabel">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
                             <property name="margin_end">4</property>
                             <property name="label" translatable="yes">Record</property>
                           </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
-                          </packing>
                         </child>
                       </object>
                     </child>
@@ -72,28 +47,15 @@
                     </style>
                   </object>
                 </child>
-                <child>
+                <child type="end">
                   <object class="GtkMenuButton">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
                     <property name="receives_default">False</property>
-                    <property name="action_name">win.open-primary-menu</property>
                     <property name="menu_model">primaryMenu</property>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="icon_name">open-menu-symbolic</property>
-                      </object>
-                    </child>
+                    <property name="icon_name">open-menu-symbolic</property>
                     <style>
                       <class name="image-button"/>
                     </style>
                   </object>
-                  <packing>
-                    <property name="pack_type">end</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
                 <style>
                   <class name="titlebar"/>
@@ -101,172 +63,107 @@
               </object>
             </child>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
         </child>
         <child>
           <object class="GtkOverlay">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
             <child>
               <object class="GtkStack" id="mainStack">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="hexpand">True</property>
                 <property name="vexpand">True</property>
                 <child>
-                  <object class="GtkBox">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="halign">center</property>
-                    <property name="valign">center</property>
-                    <property name="orientation">vertical</property>
-                    <child>
-                      <object class="GtkImage" id="emptyIcon">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
+                  <object class="GtkStackPage">
+                    <property name="name">empty</property>
+                    <property name="child">
+                      <object class="GtkBox">
                         <property name="halign">center</property>
                         <property name="valign">center</property>
-                        <property name="pixel_size">96</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="margin_top">8</property>
-                        <property name="label" translatable="yes">Add Recordings</property>
-                        <style>
-                          <class name="dim-label"/>
-                          <class name="title-1"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="margin_top">4</property>
-                        <property name="label" translatable="yes">Use the &lt;b&gt;Record&lt;/b&gt; button 
to make sound recordings</property>
-                        <property name="use_markup">True</property>
-                        <property name="justify">center</property>
-                        <property name="wrap">True</property>
-                        <property name="max_width_chars">50</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkImage" id="emptyIcon">
+                            <property name="halign">center</property>
+                            <property name="valign">center</property>
+                            <property name="pixel_size">96</property>
+                            <style>
+                              <class name="dim-label"/>
+                            </style>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel">
+                            <property name="margin_top">8</property>
+                            <property name="label" translatable="yes">Add Recordings</property>
+                            <style>
+                              <class name="dim-label"/>
+                              <class name="title-1"/>
+                            </style>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel">
+                            <property name="margin_top">4</property>
+                            <property name="label" translatable="yes">Use the &lt;b&gt;Record&lt;/b&gt; 
button to make sound recordings</property>
+                            <property name="use_markup">True</property>
+                            <property name="justify">center</property>
+                            <property name="wrap">True</property>
+                            <property name="max_width_chars">50</property>
+                            <style>
+                              <class name="dim-label"/>
+                            </style>
+                          </object>
+                        </child>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
-                      </packing>
-                    </child>
+                    </property>
                   </object>
-                  <packing>
-                    <property name="name">empty</property>
-                  </packing>
                 </child>
                 <child>
-                  <object class="GtkScrolledWindow">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="hexpand">True</property>
-                    <property name="vexpand">True</property>
-                    <property name="hscrollbar_policy">never</property>
-                    <child>
-                      <object class="HdyClamp" id="column">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="maximum_size">650</property>
+                  <object class="GtkStackPage">
+                    <property name="name">recordings</property>
+                    <property name="child">
+                      <object class="GtkScrolledWindow">
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="hscrollbar_policy">never</property>
+                        <child>
+                          <object class="HdyClamp" id="column">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="maximum_size">650</property>
+                          </object>
+                        </child>
                       </object>
-                    </child>
+                    </property>
                   </object>
-                  <packing>
-                    <property name="name">recordings</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="index">-1</property>
-              </packing>
             </child>
             <child type="overlay">
               <object class="GtkRevealer" id="notificationRevealer">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="halign">center</property>
                 <property name="valign">start</property>
                 <child>
                   <object class="GtkBox">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <child>
                       <object class="GtkLabel" id="notificationMessage">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="wrap">True</property>
                         <property name="ellipsize">end</property>
                         <property name="xalign">0</property>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkButton" id="notificationUndoBtn">
                         <property name="label" translatable="yes">Undo</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
                         <property name="receives_default">True</property>
                         <property name="margin_start">12</property>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkButton" id="notificationCloseBtn">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
                         <property name="receives_default">True</property>
                         <property name="tooltip_text" translatable="yes">Close</property>
                         <property name="margin_start">8</property>
-                        <property name="relief">none</property>
-                        <child>
-                          <object class="GtkImage">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="icon_name">window-close-symbolic</property>
-                          </object>
-                        </child>
+                        <property name="has_frame">False</property>
+                        <property name="icon_name">window-close-symbolic</property>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
-                      </packing>
                     </child>
                     <style>
                       <class name="app-notification"/>
@@ -276,11 +173,6 @@
               </object>
             </child>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
         </child>
       </object>
     </child>
diff --git a/meson.build b/meson.build
index fbe0d58..15a2296 100644
--- a/meson.build
+++ b/meson.build
@@ -37,9 +37,9 @@ gjs_console = gjs_dep.get_pkgconfig_variable('gjs_console')
 # Lets check whether the dependencies exist
 dependency('gio-2.0', version: '>= 2.43.4')
 dependency('glib-2.0', version: '>= 2.39.3')
-dependency('gtk+-3.0', version: '>= 3.13.2')
+dependency('gtk4', version: '>= 3.99.3')
 dependency('gstreamer-player-1.0', version: '>= 1.12')
-dependency('libhandy-1', version: '>= 0.80.0')
+dependency('libhandy-4', version: '>= 1.0.0')
 dependency('gobject-introspection-1.0', version: '>= 1.31.6')
 
 gnome = import('gnome')
diff --git a/org.gnome.SoundRecorder.json b/org.gnome.SoundRecorder.json
index ea0c04a..4315535 100644
--- a/org.gnome.SoundRecorder.json
+++ b/org.gnome.SoundRecorder.json
@@ -31,8 +31,8 @@
             "sources" : [
                 {
                     "type" : "git",
-                    "url" : "https://gitlab.gnome.org/GNOME/libhandy.git";,
-                    "tag" : "1.0.0"
+                    "url" : "https://gitlab.gnome.org/exalm/libhandy.git";,
+                    "branch" : "gtk4"
                 }
             ]
         },
diff --git a/src/application.js b/src/application.js
index d9ab61a..9e07093 100644
--- a/src/application.js
+++ b/src/application.js
@@ -66,21 +66,22 @@ var Application = GObject.registerClass(class Application extends Gtk.Applicatio
         });
         this.add_action(quitAction);
 
-        this.add_accelerator('<Primary>q', 'app.quit', null);
-        this.add_accelerator('F10', 'win.open-primary-menu', null);
-        this.add_accelerator('<Primary>question', 'win.show-help-overlay', null);
-        this.add_accelerator('<Primary>r', 'recorder.start', null);
-        this.add_accelerator('space', 'recorder.pause', null);
-        this.add_accelerator('space', 'recorder.resume', null);
-        this.add_accelerator('Delete', 'recorder.cancel', null);
-        this.add_accelerator('s', 'recorder.stop', null);
-        this.add_accelerator('space', 'recording.play', null);
-        this.add_accelerator('space', 'recording.pause', null);
-        this.add_accelerator('b', 'recording.seek-backward', null);
-        this.add_accelerator('n', 'recording.seek-forward', null);
-        this.add_accelerator('F2', 'recording.rename', null);
-        this.add_accelerator('Delete', 'recording.delete', null);
-        this.add_accelerator('<Primary>s', 'recording.export', null);
+        this.set_accels_for_action('app.quit', ['<Primary>q']);
+        this.set_accels_for_action('win.open-primary-menu', ['F10']);
+        this.set_accels_for_action('win.show-help-overlay', ['<Primary>question']);
+        this.set_accels_for_action('recorder.start', ['<Primary>r']);
+        this.set_accels_for_action('recorder.pause', ['space']);
+        this.set_accels_for_action('recorder.resume', ['space']);
+        this.set_accels_for_action('recorder.cancel', ['Delete']);
+        this.set_accels_for_action('recorder.stop', ['s']);
+        /* TODO: Fix recording.* keybindings */
+        this.set_accels_for_action('recording.play', ['space']);
+        this.set_accels_for_action('recording.pause', ['space']);
+        this.set_accels_for_action('recording.seek-backward', ['b']);
+        this.set_accels_for_action('recording.seek-forward', ['n']);
+        this.set_accels_for_action('recording.rename', ['F2']);
+        this.set_accels_for_action('recording.delete', ['Delete']);
+        this.set_accels_for_action('recording.export', ['<Primary>s']);
     }
 
     vfunc_startup() {
@@ -90,11 +91,11 @@ var Application = GObject.registerClass(class Application extends Gtk.Applicatio
 
         let provider = new Gtk.CssProvider();
         provider.load_from_resource('/org/gnome/SoundRecorder/application.css');
-        Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
+        Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(),
             provider,
             Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
 
-        Gtk.IconTheme.get_default().add_resource_path('/org/gnome/SoundRecorder/icons/');
+        this.set_resource_base_path('/org/gnome/SoundRecorder/');
         Handy.init();
         Gst.init(null);
 
@@ -138,11 +139,7 @@ var Application = GObject.registerClass(class Application extends Gtk.Applicatio
             wrap_license: true,
             modal: true,
             transient_for: this.window,
-            use_header_bar: true,
         });
         aboutDialog.show();
-        aboutDialog.connect('response', () => {
-            aboutDialog.close();
-        });
     }
 });
diff --git a/src/main.js b/src/main.js
index 3b42332..7e1c3c4 100644
--- a/src/main.js
+++ b/src/main.js
@@ -29,16 +29,16 @@
 pkg.initGettext();
 pkg.initFormat();
 pkg.require({
-    'Gdk': '3.0',
+    'Gdk': '4.0',
     'GdkPixbuf': '2.0',
     'GLib': '2.0',
     'GObject': '2.0',
-    'Gtk': '3.0',
+    'Gtk': '4.0',
     'Gst': '1.0',
     'GstAudio': '1.0',
     'GstPlayer': '1.0',
     'GstPbutils': '1.0',
-    'Handy': '1',
+    'Handy': '4',
 });
 
 const { Application } = imports.application;
diff --git a/src/recorderWidget.js b/src/recorderWidget.js
index 2ba4d0d..a8470e2 100644
--- a/src/recorderWidget.js
+++ b/src/recorderWidget.js
@@ -22,7 +22,7 @@ var RecorderWidget = GObject.registerClass({
         'started': {},
         'stopped': { param_types: [GObject.TYPE_OBJECT] },
     },
-}, class RecorderWidget extends Gtk.Bin {
+}, class RecorderWidget extends Gtk.Box {
     _init(recorder) {
         super._init({});
         this.recorder = recorder;
@@ -31,7 +31,7 @@ var RecorderWidget = GObject.registerClass({
             vexpand: true,
             valign: Gtk.Align.FILL,
         }, WaveType.RECORDER);
-        this._recorderBox.add(this.waveform);
+        this._recorderBox.prepend(this.waveform);
 
         this.recorder.bind_property('current-peak', this.waveform, 'peak', GObject.BindingFlags.SYNC_CREATE 
| GObject.BindingFlags.DEFAULT);
         this.recorder.connect('notify::duration', _recorder => {
@@ -120,12 +120,6 @@ var RecorderWidget = GObject.registerClass({
             dialog.close();
         });
 
-        dialog.connect('key-press-event', (_, event) => {
-            const key = event.get_keyval()[1];
-            if (key === Gdk.KEY_Escape)
-                dialog.response(Gtk.ResponseType.NO);
-        });
-
         dialog.show();
     }
 
diff --git a/src/recordingsListBox.js b/src/recordingsListBox.js
index 879703c..df20af3 100644
--- a/src/recordingsListBox.js
+++ b/src/recordingsListBox.js
@@ -37,7 +37,7 @@ var RecordingsListBox = new GObject.registerClass({
         this.bind_model(model, recording => {
             let row = new Row(recording);
 
-            row.waveform.connect('button-press-event', _ => {
+            row.waveform.connect('gesture-pressed', _ => {
                 if (!this.activePlayingRow || this.activePlayingRow !== row) {
 
                     if (this.activePlayingRow)
@@ -99,10 +99,12 @@ var RecordingsListBox = new GObject.registerClass({
             return row;
         });
 
+        this.connect('row-activated', this.rowActivated.bind(this));
+
         this.show();
     }
 
-    vfunc_row_activated(row) {
+    rowActivated(list, row) {
         if (row.editMode && row.expanded || this.activeRow && this.activeRow.editMode && 
this.activeRow.expanded)
             return;
 
diff --git a/src/row.js b/src/row.js
index 154c0ef..0cd011f 100644
--- a/src/row.js
+++ b/src/row.js
@@ -81,16 +81,16 @@ var Row = GObject.registerClass({
         });
         this.actionGroup.add_action(exportAction);
 
-        let saveRenameAction = new Gio.SimpleAction({ name: 'save', enabled: false });
-        saveRenameAction.connect('activate', this.onRenameRecording.bind(this));
-        this.actionGroup.add_action(saveRenameAction);
+        this.saveRenameAction = new Gio.SimpleAction({ name: 'save', enabled: false });
+        this.saveRenameAction.connect('activate', this.onRenameRecording.bind(this));
+        this.actionGroup.add_action(this.saveRenameAction);
 
         this.renameAction = new Gio.SimpleAction({ name: 'rename', enabled: true });
         this.renameAction.connect('activate', action => {
             this.editMode = true;
             action.enabled = false;
         });
-        this.renameAction.bind_property('enabled', saveRenameAction, 'enabled', 
GObject.BindingFlags.INVERT_BOOLEAN);
+        this.renameAction.bind_property('enabled', this.saveRenameAction, 'enabled', 
GObject.BindingFlags.INVERT_BOOLEAN);
         this.actionGroup.add_action(this.renameAction);
 
         let pauseAction = new Gio.SimpleAction({ name: 'pause', enabled: false });
@@ -127,16 +127,24 @@ var Row = GObject.registerClass({
 
         this.insert_action_group('recording', this.actionGroup);
 
-        this.waveform.connect('button-press-event', _ => {
+        this.waveform.connect('gesture-pressed', _ => {
             pauseAction.activate(null);
         });
 
-        this._entry.connect('key-press-event', (_, event) => {
-            const key = event.get_keyval()[1];
+        this.keyController = Gtk.EventControllerKey.new();
+        this.keyController.connect('key-pressed', (controller, key, _code, _state) => {
             this._entry.get_style_context().remove_class('error');
 
-            if (key === Gdk.KEY_Escape)
+            if (key === Gdk.KEY_Escape) {
                 this.editMode = false;
+            } else {
+                controller.forward(this._entry);
+            }
+        });
+        this._entry.add_controller(this.keyController);
+
+        this._entry.connect('activate', _ => {
+            this.saveRenameAction.activate(null);
         });
 
         this._recording.connect('peaks-updated', _recording => {
@@ -180,7 +188,7 @@ var Row = GObject.registerClass({
             if (!this.expanded)
                 this.activate();
             this._entry.grab_focus();
-            this._saveBtn.grab_default();
+            /* TODO: this._saveBtn.grab_default(); */
             this._rightStack.visible_child_name = 'save';
         } else {
             this._rightStack.visible_child_name = 'options';
diff --git a/src/waveform.js b/src/waveform.js
index 9908896..f8570df 100644
--- a/src/waveform.js
+++ b/src/waveform.js
@@ -49,6 +49,7 @@ var WaveForm = GObject.registerClass({
     },
     Signals: {
         'position-changed': {  param_types: [GObject.TYPE_FLOAT]  },
+        'gesture-pressed': {},
     },
 }, class WaveForm extends Gtk.DrawingArea {
     _init(params, type) {
@@ -58,47 +59,53 @@ var WaveForm = GObject.registerClass({
         this.waveType = type;
         super._init(params);
 
-        if (this.waveType === WaveType.PLAYER) {
-            this.add_events(Gdk.EventMask.BUTTON_PRESS_MASK |
-                Gdk.EventMask.BUTTON_RELEASE_MASK |
-                Gdk.EventMask.BUTTON1_MOTION_MASK);
-        }
-
         this.rightColor = (IsDark ? [80, 80, 80] : [192, 191, 188]).map(x => x / 255);
         this.leftColor = (IsDark ? [192, 191, 188] : [46, 52, 54]).map(x => x / 255);
         this.dividerColor = (this.waveType === WaveType.PLAYER ? [28, 113, 216] : [255, 0, 0]).map(x => x / 
255);
 
+        // TODO: Figure out how to mesh these gestures with the row-activated cb and
+        // new event handling
+        if (this.waveType === WaveType.PLAYER) {
+            this.clickGesture = Gtk.GestureClick.new();
+            this.clickGesture.connect('pressed', this.gesturePressed.bind(this));
+            this.clickGesture.connect('released', this.gestureReleased.bind(this));
+            this.add_controller(this.clickGesture);
+
+            this.motionGesture = Gtk.EventControllerMotion.new();
+            this.motionGesture.connect('motion', this.onMotion.bind(this));
+        }
+
+        this.set_draw_func(this.drawFunc);
+
         this.show();
     }
 
-    vfunc_button_press_event(event) {
-        this._startX = event.x;
-        return true;
+    gesturePressed(n_press, x, y) {
+        this._startX = x;
+        this.emit('gesture-pressed');
     }
 
-    vfunc_motion_notify_event(event) {
-        this._position = this._clamped(event.x - this._startX + this._lastX);
+    onMotion(x, y) {
+        this._position = this._clamped(x - this._startX + this._lastX);
         this.queue_draw();
-        return true;
     }
 
-    vfunc_button_release_event(_) {
+    gestureReleased(n_press, x, y) {
         this._lastX = this._position;
         this.emit('position-changed', this.position);
-        return true;
     }
 
-    vfunc_draw(ctx) {
-        const maxHeight = this.get_allocated_height();
+    drawFunc(da, ctx, width, height) {
+        const maxHeight = da.get_allocated_height();
         const vertiCenter = maxHeight / 2;
-        const horizCenter = this.get_allocated_width() / 2;
+        const horizCenter = da.get_allocated_width() / 2;
 
-        let pointer = horizCenter + this._position;
+        let pointer = horizCenter + da._position;
 
         ctx.setLineCap(Cairo.LineCap.ROUND);
         ctx.setLineWidth(2);
 
-        ctx.setSourceRGB(...this.dividerColor);
+        ctx.setSourceRGB(...da.dividerColor);
 
         ctx.moveTo(horizCenter, vertiCenter - maxHeight);
         ctx.lineTo(horizCenter, vertiCenter + maxHeight);
@@ -106,21 +113,21 @@ var WaveForm = GObject.registerClass({
 
         ctx.setLineWidth(1);
 
-        this._peaks.forEach(peak => {
-            if (this.waveType === WaveType.PLAYER) {
+        da._peaks.forEach(peak => {
+            if (da.waveType === WaveType.PLAYER) {
                 if (pointer > horizCenter)
-                    ctx.setSourceRGB(...this.rightColor);
+                    ctx.setSourceRGB(...da.rightColor);
                 else
-                    ctx.setSourceRGB(...this.leftColor);
+                    ctx.setSourceRGB(...da.leftColor);
             } else {
-                ctx.setSourceRGB(...this.leftColor);
+                ctx.setSourceRGB(...da.leftColor);
             }
 
             ctx.moveTo(pointer, vertiCenter + peak * maxHeight);
             ctx.lineTo(pointer, vertiCenter - peak * maxHeight);
             ctx.stroke();
 
-            if (this.waveType === WaveType.PLAYER)
+            if (da.waveType === WaveType.PLAYER)
                 pointer += GUTTER;
             else
                 pointer -= GUTTER;
diff --git a/src/window.js b/src/window.js
index ff92f2e..4749846 100644
--- a/src/window.js
+++ b/src/window.js
@@ -93,7 +93,7 @@ var Window = GObject.registerClass({
             }
             this._notificationUndoBtn.disconnect(this.cancelSignalId);
         });
-        this._column.add(this._recordingListBox);
+        this._column.set_child(this._recordingListBox);
 
         this.recorderWidget.connect('started', this.onRecorderStarted.bind(this));
         this.recorderWidget.connect('canceled', this.onRecorderCanceled.bind(this));
@@ -103,7 +103,7 @@ var Window = GObject.registerClass({
         this.show();
     }
 
-    vfunc_delete_event() {
+    vfunc_close_request() {
         this._recordingList.cancellable.cancel();
         if (this.itemsSignalId)
             this._recordingList.disconnect(this.itemsSignalId);
@@ -115,6 +115,7 @@ var Window = GObject.registerClass({
         }
 
         this.recorder.stop();
+        this.application.quit();
     }
 
     onRecorderStarted() {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]