Adding support for Linux' POSIX capabilities - Alex
authorterminatorX <>
Sat, 16 Aug 2003 19:15:14 +0000 (19:15 +0000)
committerterminatorX <>
Sat, 16 Aug 2003 19:15:14 +0000 (19:15 +0000)
18 files changed:
AUTHORS
ChangeLog
INSTALL
README.PERFORMANCE
TODO
configure.in
doc/terminatorX-manual/C/terminatorX-manual.xml
src/Makefile.am
src/main.cc
src/tX_capabilities.cc [new file with mode: 0644]
src/tX_capabilities.h [new file with mode: 0644]
src/tX_dialog.cc
src/tX_engine.cc
src/tX_engine.h
src/tX_glade_interface.cc
src/tX_global.c
src/tX_global.h
terminatorX.glade

diff --git a/AUTHORS b/AUTHORS
index 9b4c18e78c70e79ccae4a36df19a73d37bc6dd4d..134522e91820e920c9c4f2ef3629004fe1f65e3b 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -5,12 +5,12 @@ Author:                       Alexander K
 Contributors:
 licmak.awk:            Christian <eleet@altern.org>
 tX_wavfunc.c-patch:    "Andrew C. Bul+hac?k" <acb@zikzak.net>
-MK II icon:            Michael Kahl <m.kahl@student.hu-berlin.de>
+(removed) MK II icon:  Michael Kahl <m.kahl@student.hu-berlin.de>
 new startup switches:  Josh Steiner <joschi@eds.org>
 misc fixes and enhancements:
                        Adrian Reber <adrian@lisas.de>
-Ogg Vorbis support:    Matthew Evans <activesx@hotmail.com>
-MIDI interface:  Arthur Peters <amp@singingwizard.org>
+piped Ogg support:     Matthew Evans <activesx@hotmail.com>
+MIDI interface:                Arthur Peters <amp@singingwizard.org>
 
 The lowpass filter is based on a description:
 reso_lop.txt:          Paul Kellett <paul.kellett@maxim.abel.co.uk>
index 084986faf8ca69a34677583cd7a3f8b636fa6ef1..0f287051ff5c5931be964bbc74c5e7d75dfc7633 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,10 +4,20 @@ This is not a GNU-style ChangeLog but you sort of get the idea what was
 changed.
 
 [v3.81]
+- when compiled with rt-scheduling suppport terminatorX will now display the 
+  resulting scheduling policy in the about dialog.
+- if terminatorX was setup to use realtime priority for the audio engine thread
+  but you dont want it - disable realtime scheduling in the Preferences dialog.
+- if you don't want to confirm program termination every time you can now
+  disable "Ask for Quit confirmation" in the Preferences.
+- added support for Linux' POSIX capabilities. This allows a suid-root installed
+  terminatorX binary to drop root privileges much earlier than with the old
+  approach (so it should be more secure). Requires the libcap library.
 - obligatory documentation updates - clicking on the sub-sections should now 
   work.
-- removed gtk+ 1.2 cruft - terminatorX now compiles and gtk+ 2.2 and
-  *_DISABLE_DEPRECATED macros enabled.
+- removed gtk+ 1.2 cruft - terminatorX now compiles with gtk+ 2.2 and
+  *_DISABLE_DEPRECATED macros enabled. To verfiy that you can run 
+  configure with --disable-deprecated.
 - terminatorX now has a JACK backend. Currently it works like this: on startup
   tX will connect to the JACK daemon - if the daemon is not available on 
   startup JACK output is not available. When the audio engine is turned off,
@@ -20,7 +30,7 @@ changed.
   the Preferences - if terminatorX crashes right after hitting the "Power On"
   button it might be necessary to activate this for your ALSA setup. This
   probably results in a tiny memory leak - but on leak vs core you might decide
-  for leak.
+  for leak. Note: I even enabled the leak by default now.
 - fixed a bug that caused turntable 1 to get the focus on entering Mouse Grab
   mode even when it's audio panel was minimized.
 - MIDI mappings can now have "borders", meaning that the incoming MIDI signals
@@ -37,9 +47,11 @@ changed.
   the use of SCHED_FIFO unnecessary. 
 - running suid root was reported exploitable by Andrew Griffiths
   <andrewg@felinemenace.org> - the described environment variable based exploit 
-  was fixed - however there are possibly other ways to exploit it. Therefor 
-  running suid root has been explicitly disabled by default - configure with 
-  --enable-suidroot if you really, really want it. You have been warned.
+  was fixed - however there are possibly other ways to exploit it. So the 
+  old method of running suid root has been disabled by default. On Linux 
+  systems you really should use the capabilities based approach (see above).
+  If really want to use the old suid-root solution run configure with 
+  --enable-suidroot.
 - often, you record events and mess things up - in this case I'd often prefer 
   dropping the complete take instead of recording a bad perfomance - which is 
   why you now can activate "Confirm Recorded Events" from the "Sequencer" menu.
diff --git a/INSTALL b/INSTALL
index 272958910a6605e371e4f50381b487b0015a9e05..c7ac4465db8ac7c2264c424b1c606646801e0b75 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -93,17 +93,22 @@ Step 1: Configure terminatorX.
                Other options:
                -------------
                
+               --enable-capabilities
+               
+               Allows running terminatorX suid-root to gain realtime scheduling
+               (see README.PERFORMANCE).
+               
+               --enable-suidroot
+               
+               Allows running terminatorX suid-root to gain realtime scheduling
+               (see README.PERFORMANCE) - if your Linux system has capabilities
+               you should prefer that method.
+               
                --with-docdir
                
                If you intend to package terminatorX this flag will allow terminatorX
                to find the XML documentation in order to display it online.
                
-               --disable-gtk2
-               
-               If you've got gtk+ V2 installed but you want terminatorX to use
-               the old gtk+ V1.2 for some reason, use this switch to disable
-               gtk+ V2 code.
-               
                --disable-libxml2
                
                If you've got libxml V2 installed but you want terminatorX to 
index d727dc1619c029f6c82d5e8918b83f11cd2c5e2a..5e67904a04b8d3f7b4aafc0d69ed32d13f19dea9 100644 (file)
@@ -11,23 +11,33 @@ In Detail:
 1. Don't use pixmapped nor other "fat" gtk+-themes.
 ---------------------------------------------------
 
-The sequencer brings a lot of additional GUI activity. Now the "selfmade"
-widgets perform pretty good (no matter what theme you use) but for example
-scale widgets are extremly slow with pixmap-themes. The problem is that the
-gtk-pixmap engine has to stretch the images and stretching images is a very
-CPU-intensive task. So it's best to not use those themes at all.
-
-Now just recently I installed terminatorX on PIII 500 and wondered why it
-performed like running on a 486 machine. Now I found that those new fancy
-gtk+-themes that bring their own code to draw the widgets eat performance
-like mad, too. This even hurts the performance of tX' very own widgets and
-therefore hurts playback performance quite a lot. So you shouldn't use these 
-kind of themes, neither.
+terminatorX involves quite some GUI activity, so it's desirable that drawing
+happens fast. Some gtk+ engines can slow down drawing signifcantly
 
 2. Install suid root
 --------------------
 
-Update: This is now considered dangerous and not recommended.
+Note: Installing a program suid-root is always potentially dangerous. However
+a program needs special privileges to acquire realtime scheduling (which 
+improves playback quality signifcantly). Since release 3.81 terminatorX provides
+two methods of running suid root:
+
+- Linux' POSIX capabilities: when capabilities support is available at
+  compile time (requires libcap) terminatorX can make use of Linux' POSIX
+  capabilities. The binary has to be installed suid root but the program
+  will drop root privileges right on startup - after aquiring the CAP_SYS_NICE
+  capability.
+  
+- The "old" suid-root way: terminatorX starts the engine thread with root
+  privileges (and realtime scheduling). Then both threads drop root privileges.
+  Unfortunately the standard Linux 2.4 pthreads implementation has an extra
+  "manager" thread that keeps running as root. So it might be possible to gain
+  root privileges somehow. This has been shown before - the detected holes 
+  have been close, but I'm confident that others do exist.
+
+As the 2nd approach is more dangerous you have to explictly enable it at
+compile time (run configure with --enable-suidroot). However both methods might
+be exploitable somehow - so your not getting any garanties either way.
 
 3. Compile an optimized binary
 ------------------------------
@@ -46,7 +56,8 @@ in the options dialog.
 5. Optimize your kernel
 -----------------------
 
-2.5 Kernels have much lower latency than older Kernels - if you want to work 
-with a stable Kernel however I recommend patching the 2.4 Series with Kolivas
-ck patches. They improve terminatorX performace signifcally - if you dont 
-forget to renice your X to '0' (see Kolivas' FAQ).
+2.6 Kernels have much lower latency than older Kernels - if you want to work 
+with a stable Kernel however I recommend patching the 2.4 Series with Con 
+Kolivas' "ck" patches. They improve terminatorX performace signifcantly - if you
+dont forget to renice your X to '0' (see Con Kolivas' FAQ at 
+http://members.optusnet.com.au/ckolivas/kernel/).
diff --git a/TODO b/TODO
index 75f972247f54a95bee1835bd8535a1b29ba6aca5..c619f90aa6253fee2b9c7eb4dd0b81668b2ad425 100644 (file)
--- a/TODO
+++ b/TODO
@@ -8,8 +8,6 @@ High priority milestones:
 
 I'd like to have this in 4.0:
 
-- Write a JACK audio backend.
-
 - Support stereo LADSPA plugins somehow.
 
 Low priority milestones:
@@ -24,22 +22,4 @@ This might come after 4.0:
     
 - Support other languages.
 
---- Ok, the following points are already implemented:
-
-- Rewrite the audio device layer, so that terminatorX operates at a fix block
-  size - this will allow correct playback of sequencer events even if played
-  back on a different soundcard then recorded.
-
-- Support ALSA drivers and allow usage of multiple audio devices at the same 
-  time.
-  
-- Switch the terminatorX set file format to XML so that sets recorded on one
-  platform can be loaded on other platforms, too.
-  
-- Move the "main buttons" on the top right to a menu bar in order to get the
-  GUI even more flexible.
-
-- Provide a MIDI interface to terminatorX.
-
-- Use libaudiofile, libvorbis, etc. for file loading to get rid of "piped
-  loading" and accelerate loading of ogg and mp3 files this way.
+- Support multiple audio devices in parallel maybe?
index 95650cb26510736389113da1cfbcb9576ff6c71d..ffaa594893df2a97b7836b77ece91f2920f48b3c 100644 (file)
@@ -3,28 +3,29 @@ AC_INIT(src/tX_global.h)
 AM_INIT_AUTOMAKE(terminatorX, 3.81)
 AM_CONFIG_HEADER(config.h)
 
-dnl AC_ARG_ENABLE(closedev, [  --enable-closedev       close audio device if not in use. [default=yes] ])
-AC_ARG_ENABLE(sox,                     [  --enable-sox            use sox as input converter. (default=auto) ])
-AC_ARG_ENABLE(mpg123,          [  --enable-mpg123         use mpg123 as input converter. (default=auto) ])
-AC_ARG_ENABLE(ogg123,          [  --enable-ogg123         use ogg123 as input converter. (default=auto) ])
-AC_ARG_ENABLE(scheduler,       [  --enable-scheduler      enable rt-scheduling (default=no) ])
-AC_ARG_ENABLE(debug,           [  --enable-debug          enable debug output. (default=no) ])
-dnl AC_ARG_ENABLE(benchmark,[  --enable-benchmark      creates a non-functional test version (default=no) ])
-AC_ARG_ENABLE(wav,          [  --enable-wav            enables the builtin wav-loader (default=yes) ])
-AC_ARG_ENABLE(xsetpointer,  [  --enable-xsetpointer    enables executing of xsetpointer (default=auto) ])
-AC_ARG_ENABLE(alsa,         [  --enable-alsa           use ALSA for sound output (default=auto) ])
-AC_ARG_ENABLE(jack,         [  --enable-jack           use JACK for sound output (default=auto) ])
-AC_ARG_ENABLE(oss,          [  --enable-oss            use OSS for sound output (default=auto) ])
-dnl AC_ARG_ENABLE(dga2,     [  --enable-dga2           use DGA2 instead of DGA1. (experimental) (default=no) ])
-AC_ARG_ENABLE(libxml2,     [  --disable-libxml2       use libxml even if verion 2 detected (default=auto) ])
-AC_ARG_ENABLE(mad,                     [  --disable-mad           disable mad for mp3 support (default=auto) ])
+AC_ARG_ENABLE(sox,             [  --enable-sox            use sox as input converter. (default=auto) ])
+AC_ARG_ENABLE(mpg123,          [  --enable-mpg123         use mpg123 as input converter. (default=auto) ])
+AC_ARG_ENABLE(ogg123,          [  --enable-ogg123         use ogg123 as input converter. (default=auto) ])
+AC_ARG_ENABLE(scheduler,       [  --enable-scheduler      enable rt-scheduling (default=auto) ])
+AC_ARG_ENABLE(debug,           [  --enable-debug          enable debug output. (default=no) ])
+dnl AC_ARG_ENABLE(benchmark    [  --enable-benchmark      creates a non-functional test version (default=no) ])
+AC_ARG_ENABLE(wav,             [  --enable-wav            enables the built-in wav-loader (default=yes) ])
+AC_ARG_ENABLE(xsetpointer,     [  --enable-xsetpointer    enables executing of xsetpointer (default=auto) ])
+AC_ARG_ENABLE(alsa,            [  --enable-alsa           use ALSA for sound output (default=auto) ])
+AC_ARG_ENABLE(jack,            [  --enable-jack           use JACK for sound output (default=auto) ])
+AC_ARG_ENABLE(oss,             [  --enable-oss            use OSS for sound output (default=auto) ])
+dnl AC_ARG_ENABLE(dga2,                [  --enable-dga2           use DGA2 instead of DGA1. (experimental) (default=no) ])
+AC_ARG_ENABLE(libxml2,         [  --disable-libxml2       use libxml even if verion 2 detected (default=auto) ])
+AC_ARG_ENABLE(mad,             [  --disable-mad           disable mad for mp3 support (default=auto) ])
 AC_ARG_ENABLE(vorbis,          [  --disable-vorbis        disable libvorbis support (default=auto) ])
 AC_ARG_ENABLE(audiofile,       [  --disable-audiofile     disable audiofile support (default=auto) ])
 AC_ARG_ENABLE(legacy,          [  --enable-legacy         enable support for old terminatorX files (default=no) ])
 AC_ARG_ENABLE(alsamidi,                [  --disable-alsamidi      disable support  ALSA MIDI in (default=auto) ])
-AC_ARG_ENABLE(lrdf,                    [  --disable-lrdf          disable support for liblrdf (default=auto) ])
-AC_ARG_ENABLE(suidroot,                [  --enable-suidroot       enable suid-root exec - dangerous (default=no) ])
-AC_ARG_WITH(docdir,                    [  --with-docdir=/some/dir the final location the docs will be installed to. ])
+AC_ARG_ENABLE(lrdf,            [  --disable-lrdf          disable support for liblrdf (default=auto) ])
+AC_ARG_ENABLE(suidroot,                [  --enable-suidroot       enable old suid-root exec method (default=no) ])
+AC_ARG_ENABLE(capabilities,    [  --enable-capabilities   an alternative suid-root method (default=auto) ])
+AC_ARG_ENABLE(deprecated,      [  --disable-deprecated    compile without deprecated G*-headers (default=no) ])
+AC_ARG_WITH(docdir,            [  --with-docdir=/some/dir the final location the docs will be installed to. ])
 
 dnl Checks for programs.
 AC_PROG_AWK
@@ -50,6 +51,7 @@ OPTION_ALSAMIDI="no"
 OPTION_LEGACY="no"
 OPTION_LRDF="no"
 OPTION_SUIDROOT="no"
+OPTION_CAP="no"
 
 dnl Checks for libraries.
 AC_CHECK_LIB(m, floor,, AC_MSG_ERROR([** math-lib not installed or broken **]))
@@ -384,7 +386,7 @@ if test "$enable_3dnow" = "yes"; then
        AC_DEFINE_UNQUOTED([USE_3DNOW], 1, [Do not define this])
 fi 
 
-if test "$enable_scheduler" = "yes"; then
+if test "$enable_scheduler" != "no"; then
        OPTION_SCHEDULER="yes";
        AC_DEFINE_UNQUOTED([USE_SCHEDULER], 1, [Define this to compile with rt scheduling support])
 fi
@@ -402,6 +404,38 @@ if test "$enable_suidroot" = yes; then
        AC_DEFINE_UNQUOTED([ALLOW_SUID_ROOT], 1, [Define this only if you know what you're doing.])
 fi
 
+if test "$enable_capabilities" != "no"; then
+       AC_CHECK_HEADERS(sys/capability.h,capheader=yes,capheader=no)
+       AC_CHECK_HEADERS(sys/prctl.h,prctlheader=yes,prctlheader=no)
+       
+       if test "$capheader" = "yes"; then
+               if test "$prctlheader" = "yes"; then
+                       AC_CHECK_LIB(cap,cap_get_proc,caplib=yes,caplib=no)
+                       if test "$caplib" = "yes"; then
+                               LIBS="$LIBS -lcap"
+                               AC_DEFINE_UNQUOTED([USE_CAPABILITIES], 1, [Define to use capabilities])
+                               OPTION_CAP="yes"
+                       fi
+               fi
+       fi
+fi
+
+if test "$enable_capabilities" = "yes"; then
+       if test "$OPTION_CAP" != "yes"; then
+               AC_MSG_ERROR([** This system doesn't support capabilities. **])
+       fi
+fi
+
+
+
+if test "$enable_deprecated" = "no"; then
+       DEPRECATED_FLAGS="-DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED"
+else 
+    DEPRECATED_FLAGS=""
+fi
+
+AC_SUBST(DEPRECATED_FLAGS)
+
 AC_MSG_CHECKING(for necessary scratching skillz)
 AC_MSG_RESULT(yes)
 
@@ -615,15 +649,11 @@ option_info;
 option=lrdf; option_val=$OPTION_LRDF; option_url=http://plugin.org.uk/releases/lrdf/
 option_info;
 
-if test "$OPTION_SUIDROOT" = "yes"; then
-       option="suid-root exec \(dangerous\)"; option_val=$OPTION_SUIDROOT;
-       option_info;
-fi
-
 echo "legacy files support: $OPTION_LEGACY"
 echo "builtin-wav support: $OPTION_WAV"
 echo "enhanced scheduling support: $OPTION_SCHEDULER"
-echo "suid-root support: $OPTION_SUIDROOT"
+echo "old suid-root support: $OPTION_SUIDROOT"
+echo "capabilities support: $OPTION_CAP"
 echo "GNOME support: $OPTION_GNOME"
 echo
 echo You can now run \'make\' to compile terminatorX
index f3c92fc96566242ff5dba32d0d826b43b2281edb..52ae70c1747681175af201d462ce65101d2bcb07 100644 (file)
                   for loading misc other audio files.</para>
                 </listitem>
 
+                <listitem>
+                  <para><ulink url="???">libcap</ulink> for capabilties
+                  support.</para>
+                </listitem>
+
                 <listitem>
                   <para><ulink
                   url="http://www-ti.informatik.uni-tuebingen.de/~hippm/mpg123.html">mpg123</ulink>
       <sect3 id="SEQUENCERMENU">
         <title><emphasis>Sequencer</emphasis> Menu</title>
 
-        <para>The <emphasis>Sequencer</emphasis> (see the <xref
-        linkend="SEQUENCER" /> section for general information on the
-        sequencer) menu features these functions:</para>
+        <para>The <emphasis>Sequencer</emphasis> (see <xref
+        linkend="SEQUENCER" /> for general information on the sequencer) menu
+        features these functions:</para>
 
         <itemizedlist>
           <listitem>
           <listitem>
             <para><emphasis>Visit terminatorX.cx</emphasis></para>
 
-            <para>Will try to spawn a browser process to load the URL
-            &#34;http://terminatorX.cx&#34; - for easy update checking or just
-            unecessary bloat.</para>
+            <para>Will try to spawn a browser process to load the URL <ulink
+            url="http://terminatorX.cx">http://terminatorX.cx</ulink> - for
+            easy update checking or just unecessary bloat.</para>
           </listitem>
         </itemizedlist>
       </sect3>
         <listitem>
           <para><emphasis>Sequencer Play / Record / Stop</emphasis></para>
 
-          <para>Please read the <xref linkend="SEQUENCER" /> section to find
-          out more about the sequencer.</para>
+          <para>Please read <xref linkend="SEQUENCER" /> to find out more
+          about the sequencer.</para>
         </listitem>
 
         <listitem>
             <para>This button is available only if terminatorX was built with
             ALSA MIDI support and the sequencer input port was created
             successfully on startup. For more information on terminatorX&#39;
-            MIDI interface see <xref linkend="MIDI" /> section.</para>
+            MIDI interface see <xref linkend="MIDI" />.</para>
           </listitem>
         </itemizedlist>
       </sect3>
         parameter&#39;s MIDI mapping.</para></listitem><listitem><para><emphasis>Reset
         Lower MIDI Bound</emphasis></para><para>If a lower MIDI bound was set
         for this parameter it can be removed by selecting this menu entry.</para></listitem><listitem><para><emphasis>Delete
-        Sequencer Events</emphasis></para><para>Just like the <xref
-        linkend="SEQUENCERMENU" /> this entry allows you to delete events
-        recorded for this specific parameter.</para></listitem></itemizedlist></para>
+        Sequencer Events</emphasis></para><para>Just like the Sequencer menu
+        (see <xref linkend="SEQUENCERMENU" />) this entry allows you to delete
+        events recorded for this specific parameter.</para></listitem></itemizedlist></para>
       </sect3>
 
       <sect3>
             <para>Note that due to the wide parameter ranges some LADSPA
             plugins have they sometimes might be hard to control with the knob
             widget. In these cases you might want to use the text field to
-            enter values. For more details on Plugins see <xref
+            enter values. For more details on plugins see <xref
             linkend="LADSPAPLUGINS" />.</para>
           </listitem>
         </itemizedlist>
       move the sequencer-scale to that position, press <emphasis>Record,</emphasis>
       set the parameter and press <emphasis>Stop</emphasis> again.</para>
 
-      <para>To selectively delete events from the sequencer use see <xref
+      <para>To selectively delete events from the sequencer see <xref
       linkend="SEQUENCERMENU" /> and <xref linkend="PARAMETERMENU" />.</para>
     </sect2>
 
       <para>There are two ways to map MIDI events to a parameter:<itemizedlist><listitem><para>Via
       the <emphasis>Configure MIDI Bindings</emphasis> dialog as described
       below</para></listitem><listitem><para>Via the the a parameter&#39;s
-      menu (see <xref linkend="PARAMETERMENU" />) </para></listitem></itemizedlist></para>
+      menu (see <xref linkend="PARAMETERMENU" />)</para></listitem></itemizedlist></para>
 
       <para>Once the connection is set up terminatorX receives MIDI events
       through the input port. To configure what MIDI events will have which
       startup. By default the two output ports of terminatorX will be
       connected to physical ports if available. You can then re-wire the ports
       whatever way you want. They will not be deactivated - when
-      terminatorX&#39; audio engine is turned off , the audio backend emits
+      terminatorX&#39; audio engine is turned off, the audio backend emits
       continuous silence.</para>
     </sect2>
   </sect1>
       cause the parameter widgets to update less often.</para>
     </sect2>
 
-    <sect2>
+    <sect2 id="colors">
       <title><emphasis>Audio Colors</emphasis> and <emphasis>VU Colors</emphasis>
       Tab</title>
 
index c37d95e01ddd8577635da51b11e54cdb43fa6e54..bf37835e8102dc5ca9a1e156d3ef348d904d7d7c 100644 (file)
@@ -2,7 +2,7 @@ LIBS=@X_LIBS@ @GTK_LIBS@ @LIBS@
 
 SUBDIRS = gui_icons smallknob
 
-EXTRA_CFLAGS=-D_REENTRANT -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED
+EXTRA_CFLAGS=-D_REENTRANT @DEPRECATED_FLAGS@
 AM_CFLAGS=@CFLAGS@ @GTK_CFLAGS@ $(EXTRA_CFLAGS)
 AM_CXXFLAGS=@CFLAGS@ @GTK_CFLAGS@  $(EXTRA_CFLAGS)
 
@@ -37,4 +37,5 @@ terminatorX_SOURCES = tX_endian.c tX_dialog.cc tX_widget.c wav_write.c \
                        tX_midiin.h tX_midiin.cc tX_glade_interface.cc \
                        tX_glade_interface.h tX_glade_callbacks.cc \
                        tX_glade_callbacks.h tX_glade_support.cc \
-                       tX_glade_support.h tX_ladspa_class.h tX_ladspa_class.cc
+                       tX_glade_support.h tX_ladspa_class.h tX_ladspa_class.cc \
+                       tX_capabilities.h tX_capabilities.cc
index 039fb6fffefc887fe591d0a3886cde1663392158..db92f11e9342ebc450a4c39a8dd4f019dc6c9198 100644 (file)
@@ -62,6 +62,7 @@
 #include "tX_ladspa.h"
 #include "tX_ladspa_class.h"
 #include "tX_engine.h"
+#include "tX_capabilities.h"
 
 #ifdef CREATE_BENCHMARK 
 #include "tX_vtt.h"
@@ -76,7 +77,7 @@ void jack_check()
                tx_note("Couldn't connect to JACK server - JACK output not available.\n\nIf you want to use JACK, ensure the JACK daemon is running before you start terminatorX.", true);
        }
 }
-#endif                 
+#endif // USE_JACK
 
 int idle()
 {
@@ -111,31 +112,18 @@ usage: terminatorX [options]n\
   -s, --std-out                 Use stdout for sound output\n\
   --device=[output device]      Use alternate device for sound output\n\
 \n");
-/*
-  -n, --no-gui                 Run terminatorX with no GUI\n\
-  -m, --midi-in [file]         Use [file] for midi input\n\
-  -o, --midi-out [file]                Use [file] for midi input\n\
-  -s, --std-out                        Use stdout for sound output\n\
-\n");
-*/
 }
 
-
 int parse_args(int *argc, char **argv)
 {
        // pass over argv once to see if we need to load an alternate_rc file
-       for (int i = 1 ; i != *argc ; ++i )
-       {
-               if ((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) 
-               {
-                       if (argv[i+1] )
-                       {       
+       for (int i = 1 ; i != *argc ; ++i ) {
+               if ((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) {
+                       if (argv[i+1] ) {       
                                ++i;
                                fprintf(stderr, "tX: Loading alternate rc file %s\n", argv[i]);
                                globals.alternate_rc = argv[i];
-                       }
-                       else
-                       {
+                       } else {
                                show_help();    
                                exit(1);
                        }
@@ -153,41 +141,28 @@ int parse_args(int *argc, char **argv)
        globals.startup_set = 0;
                
        // then pass over again, this time setting passed values
-       for (int i = 1 ; i < *argc ; ++i )
-       {
-               if ((strcmp(argv[i], "-f") == 0) || (strcmp(argv[i], "--file") == 0))
-               {
+       for (int i = 1 ; i < *argc ; ++i ) {
+               if ((strcmp(argv[i], "-f") == 0) || (strcmp(argv[i], "--file") == 0)) {
                        ++i;
                        globals.startup_set = argv[i];
-               }       
-               else if (((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) && (argv[i+1]))
-               {
+               } else if (((strcmp(argv[i], "-r") == 0) || (strcmp(argv[i], "--rc-file") == 0)) && (argv[i+1])) {
                        ++i;
                        globals.alternate_rc = argv[i];
-               }
-               else if ((strcmp(argv[i], "-d") == 0) || (strcmp(argv[i], "--dont-save") == 0))
-               {
+               } else if ((strcmp(argv[i], "-d") == 0) || (strcmp(argv[i], "--dont-save") == 0)) {
                        fprintf(stderr, "tX: Do not save settings on exit\n");
                        globals.store_globals = 0;
 
-               }
-               else if ((strcmp(argv[i], "-s") == 0) || (strcmp(argv[i], "--std-out") == 0))
-               {
+               } else if ((strcmp(argv[i], "-s") == 0) || (strcmp(argv[i], "--std-out") == 0)) {
                        globals.use_stdout_cmdline = 1;
                        globals.use_stdout = 1;
-               }
-               else if ((strncmp(argv[i], "--device",8) == 0))
-               {
+               } else if ((strncmp(argv[i], "--device",8) == 0)) {
                        if (strlen(argv[i]+9)<=PATH_MAX)
                                strcpy(globals.oss_device,argv[i]+9);
-                       else
-                       {
+                       else {
                                show_help();
-                                exit(1);
+                               exit(1);
                        }
-               }
-               else
-               {
+               } else {
                        show_help();
                        exit(1);
                }
@@ -201,7 +176,7 @@ void checkenv(const char *name) {
        
        value=getenv(name);
        if (value) {
-               length=strlen(value);
+               length=strnlen(value, PATH_MAX+1);
                
                if (length>=PATH_MAX) {
                        tX_error("Your \"%s\" environment variable seems malicious (%i chars).", name, length);
@@ -216,6 +191,28 @@ int main(int argc, char **argv)
        fprintf(stderr, "%s - Copyright (C) 1999-2003 by Alexander König\n", VERSIONSTRING);
        fprintf(stderr, "terminatorX comes with ABSOLUTELY NO WARRANTY - for details read the license.\n");
 
+#ifdef USE_CAPABILITIES        
+       if (!geteuid()) {
+               if (prctl(PR_SET_KEEPCAPS, 1, -1, -1, -1)) {
+                       tX_error("failed to keep capabilites.");
+               }
+               set_nice_capability(CAP_PERMITTED);
+       }
+       
+       if ((!geteuid()) && (getuid() != geteuid())) {
+               tX_debug("main() - capabilites set, dropping root privileges.");
+               
+               int result=setuid(getuid());
+               
+               if (result) {
+                       tX_error("main() Panic: can't drop root privileges.");
+                       exit(2);
+               }
+       }
+       
+       set_nice_capability(CAP_EFFECTIVE);     
+#endif
+       
        checkenv("HOME");
        checkenv("XLOCALEDIR"); 
        
@@ -235,15 +232,18 @@ int main(int argc, char **argv)
                idle_tag=gtk_idle_add((GtkFunction)idle, NULL);
        }
        
-       LADSPA_Class :: init();
-       LADSPA_Plugin :: init();
+       LADSPA_Class::init();
+       LADSPA_Plugin::init();
 #ifdef USE_JACK        
-       tX_jack_client :: init();
+       tX_jack_client::init();
 #endif 
        
        create_mastergui(globals.width, globals.height);
                
        if (!globals.show_nag) {
+#ifdef USE_JACK
+               jack_check();
+#endif
                display_mastergui();
        }
                
@@ -264,10 +264,10 @@ int main(int argc, char **argv)
        if (tX_jack_client::get_instance()) {
                delete tX_jack_client::get_instance();
        }
-#endif 
+#endif // USE_JACK
        
        fprintf(stderr, "Have a nice life.\n");
-#else
+#else // CREATE_BENCHMARK
        gtk_widget_hide(main_window);
        while (gtk_events_pending()) gtk_main_iteration(); gdk_flush(); 
        gdk_flush();
@@ -298,6 +298,6 @@ int main(int argc, char **argv)
        
        ratio=((double) BENCH_CYCLES)/res;
        printf ("Rendered %i blocks in %f secons,\n=> %f blocks per second.\n\n", (long) BENCH_CYCLES, res, ratio);
-#endif
+#endif // CREATE_BENCHMARK
        return (0);
 }
diff --git a/src/tX_capabilities.cc b/src/tX_capabilities.cc
new file mode 100644 (file)
index 0000000..5642ccc
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999-2003  Alexander König
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    File: tX_capabilities.cc
+    Description: Aquire CAP_SYS_NICE through Linux' capabilities.
+*/    
+
+#include "tX_capabilities.h"
+#include "tX_global.h"
+#include <errno.h>
+#include <string.h>
+
+#ifdef USE_CAPABILITIES
+
+bool have_nice_capability()
+{
+       cap_t caps;
+       cap_flag_value_t cap;
+       pid_t pid;
+
+       caps=cap_get_proc();
+       
+       if (!caps) {
+               tX_error("have_nice_capability(): failed to get caps: %s.", strerror(errno));
+               return false;
+       }
+
+       cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &cap);
+       
+       if (cap==CAP_CLEAR) {
+               return false;
+       }
+       
+       return true;
+}
+
+void set_nice_capability(cap_flag_t cap_flag) {
+       cap_t caps;
+       const unsigned caps_size = 1;
+       cap_value_t cap_list[] = { CAP_SYS_NICE };
+       
+       caps=cap_get_proc();
+       
+       if (!caps) {
+               tX_error("set_capabilities(): failed to get caps: %s.", strerror(errno));
+               return;
+       }
+       
+       cap_set_flag(caps, cap_flag, caps_size, cap_list , CAP_SET);
+       
+       if (cap_set_proc(caps))  {
+               tX_error("set_capabilities(): failed to set caps: %s.", strerror(errno));
+       }
+}
+
+#endif // USE_CAPABILITIES
diff --git a/src/tX_capabilities.h b/src/tX_capabilities.h
new file mode 100644 (file)
index 0000000..281de14
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    terminatorX - realtime audio scratching software
+    Copyright (C) 1999-2003  Alexander König
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    File: tX_capabilities.h
+    Description: Aquire CAP_SYS_NICE through Linux' capabilities.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_CAPABILITIES
+#include <sys/prctl.h>
+
+#undef _POSIX_SOURCE
+#include <sys/capability.h>
+
+extern bool have_nice_capability();
+extern void set_nice_capability(cap_flag_t cap_flag);
+
+#endif // USE_CAPABILITIES
index db32c2113c8e52c7b0e9417cfb8ad42b5346a0ff..f6d9f01c3f62be24820a9320e08b63ec418cac63 100644 (file)
 #include "version.h"
 #include "tX_vtt.h"
 #include <dirent.h>
+#include "tX_engine.h"
+
+#ifdef USE_SCHEDULER
+#include <sched.h>
+#endif
 
 #ifdef USE_JACK
 extern void jack_check();
@@ -72,6 +77,7 @@ void apply_options(GtkWidget *dialog) {
        } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "jack_driver")))) {
                globals.audiodevice_type=JACK;
        }
+       globals.use_realtime=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "use_realtime")));
        
        /* Audio: OSS */
        strcpy(globals.oss_device, gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(lookup_widget(dialog, "oss_audio_device"))->entry)));
@@ -343,6 +349,8 @@ void init_tx_options(GtkWidget *dialog) {
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "oss_driver")), 1);
                        break;
        }
+
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "use_realtime")), globals.use_realtime);
        
 #ifndef USE_OSS
        gtk_widget_set_sensitive(lookup_widget(dialog, "oss_driver"), 0);
@@ -614,6 +622,35 @@ void show_about(int nag)
                gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
                add_about_wid_fix(label);
                
+#ifdef         USE_SCHEDULER
+               int prio=sched_getscheduler(tX_engine::get_instance()->get_pid());
+               char prio_str[32]="";
+               
+               switch (prio) {
+                       case SCHED_OTHER:
+                               strcpy(prio_str, "SCHED_OTHER");
+                               break;
+                       
+                       case SCHED_RR:
+                               strcpy(prio_str, "SCHED_RR");
+                               break;
+                       
+                       case SCHED_FIFO:
+                               strcpy(prio_str, "SCHED_FIFO");
+                               break;
+                       
+                       default:
+                               sprintf(prio_str, "UNKOWN (%i)", prio);
+               }
+               
+               sprintf(buffer, "Audio engine scheduling policy: %s.\n(Note: SCHED_FIFO equals realtime scheduling.)", prio_str);
+
+               label=gtk_label_new(buffer);
+
+               gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
+               add_about_wid_fix(label);
+#endif
+
                sep=gtk_hseparator_new();
                add_about_wid_fix(sep);
 
@@ -640,7 +677,7 @@ void show_about(int nag)
                gtk_text_buffer_insert_with_tags_by_name(tbuffer, &iter, license, -1, "courier", NULL);
                gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 5);
                gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 5);
-               gtk_widget_set_size_request(GTK_WIDGET(text), 700, 220);
+               gtk_widget_set_size_request(GTK_WIDGET(text), 640, 200);
                gtk_widget_show(text);          
                
                gtk_box_pack_start(GTK_BOX(hbox), scroll, WID_DYN);
index 05707cd16957eeffe537b9fe68f9dc55a5daa446..440da02052fc93a45a5318a55e42c569d3fbb726 100644 (file)
@@ -50,6 +50,8 @@
 #include <config.h>
 #include "tX_sequencer.h"
 #include <errno.h>
+#include <sched.h>
+#include "tX_capabilities.h"
 
 #include <sys/time.h>
 #include <sys/resource.h>
@@ -133,6 +135,11 @@ void *engine_thread_entry(void *engine_void) {
        /* Dropping root privileges for the engine thread - if running suid. */
        
        if ((!geteuid()) && (getuid() != geteuid())) {
+#ifdef USE_CAPABILITIES
+               tX_error("engine_thread_entry(): using capabilities but still suid root?");
+               tX_error("engine_thread_entry(): Please report this.");
+               exit(-1);
+#endif
                
 #ifndef ALLOW_SUID_ROOT
                tX_error("This binary doesn't support running suid-root.");
@@ -148,7 +155,32 @@ void *engine_thread_entry(void *engine_void) {
                        exit(2);
                }
        }
+
+       pid_t pid=getpid();
+       tX_engine::get_instance()->set_pid(pid);
+
+#ifdef USE_SCHEDULER
+#ifdef USE_CAPABILITIES
+       if (have_nice_capability()) {
+               if (globals.use_realtime) {
+                       struct sched_param parm;
+       
+                       sched_getparam(pid, &parm);
+                       parm.sched_priority=sched_get_priority_max(SCHED_FIFO);
+                       if (sched_setscheduler(pid, SCHED_FIFO, &parm)) {
+                               tX_error("engine_thread_entry(): failed to set realtime priority.");
+                       }
+               }
+       } else {
+               tX_warning("engine_thread_entry(): can't set SCHED_FIFO -> lacking capabilities.");
+       }
+#endif //USE_CAPABILITIES
        
+       if (sched_getscheduler(pid)!=SCHED_FIFO) {
+               tX_warning("engine_thread_entry() - engine has no realtime priority scheduling.");
+       }
+#endif //USE_SCHEDULER
+               
 #ifdef USE_JACK
        /* Create the client now, so the user has something to connect to. */
        tX_jack_client::get_instance();
@@ -167,10 +199,11 @@ tX_engine :: tX_engine() {
        pthread_mutex_init(&start, NULL);
        pthread_mutex_lock(&start);
        thread_terminate=false;
+       pid=0;
        
        /* Creating the actual engine thread.. */
 #ifdef USE_SCHEDULER   
-       if (!geteuid()) {
+       if (!geteuid() && globals.use_realtime) {
                pthread_attr_t pattr;
                struct sched_param sparm;
                
@@ -189,8 +222,7 @@ tX_engine :: tX_engine() {
                
                result=pthread_create(&thread, &pattr, engine_thread_entry, (void *) this);
        } else {
-               tX_debug("tX_engine() - Lacking root privileges - no realtime scheduling.");
-#endif         
+#endif // USE_SCHEDULER
                result=pthread_create(&thread, NULL, engine_thread_entry, (void *) this);
 #ifdef USE_SCHEDULER           
        }
index bf8c3e13cb52fb117b7b6b6f2feedb7cd993e2ba..281acf96fafbe9ba421fdaa792021539598e58ee 100644 (file)
@@ -28,6 +28,7 @@
 #include "tX_mouse.h"
 #include "tX_audiodevice.h"
 #include "tX_midiin.h"
+#include <sys/types.h>
 
 #define ENG_ERR 4
 
@@ -81,6 +82,15 @@ class tX_engine {
        tX_midiin *get_midi() { return midi; }
 #endif 
 
+#ifdef USE_SCHEDULER
+       private:
+       pid_t pid;
+       
+       public:
+       pid_t get_pid() { return pid; }
+       void set_pid(pid_t value) { pid=value; }
+#endif
+       
        static tX_engine *get_instance();
        tX_engine();
        ~tX_engine();
index 00a71b7f83c9f2b9292ea7aafabba643aa164173..8a62ce54b2e8b7daf0fcdb9497c6c5d7815a3c0f 100644 (file)
@@ -151,6 +151,8 @@ create_tx_options (void)
   GSList *oss_driver_group = NULL;
   GtkWidget *alsa_driver;
   GtkWidget *jack_driver;
+  GtkWidget *label58;
+  GtkWidget *use_realtime;
   GtkWidget *label1;
   GtkWidget *table5;
   GtkWidget *label21;
@@ -270,7 +272,7 @@ create_tx_options (void)
   gtk_widget_show (notebook1);
   gtk_box_pack_start (GTK_BOX (dialog_vbox3), notebook1, TRUE, TRUE, 0);
 
-  table4 = gtk_table_new (1, 2, FALSE);
+  table4 = gtk_table_new (2, 2, FALSE);
   gtk_widget_show (table4);
   gtk_container_add (GTK_CONTAINER (notebook1), table4);
   gtk_container_set_border_width (GTK_CONTAINER (table4), 4);
@@ -312,6 +314,20 @@ create_tx_options (void)
   gtk_radio_button_set_group (GTK_RADIO_BUTTON (jack_driver), oss_driver_group);
   oss_driver_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (jack_driver));
 
+  label58 = gtk_label_new ("Use realtime scheduling\nwhere available:");
+  gtk_widget_show (label58);
+  gtk_table_attach (GTK_TABLE (table4), label58, 0, 1, 1, 2,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+  gtk_label_set_justify (GTK_LABEL (label58), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_alignment (GTK_MISC (label58), 0, 0.5);
+
+  use_realtime = gtk_check_button_new_with_mnemonic ("Enabled");
+  gtk_widget_show (use_realtime);
+  gtk_table_attach (GTK_TABLE (table4), use_realtime, 1, 2, 1, 2,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+
   label1 = gtk_label_new ("Audio");
   gtk_widget_show (label1);
   gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook1), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook1), 0), label1);
@@ -1062,6 +1078,8 @@ create_tx_options (void)
   GLADE_HOOKUP_OBJECT (tx_options, oss_driver, "oss_driver");
   GLADE_HOOKUP_OBJECT (tx_options, alsa_driver, "alsa_driver");
   GLADE_HOOKUP_OBJECT (tx_options, jack_driver, "jack_driver");
+  GLADE_HOOKUP_OBJECT (tx_options, label58, "label58");
+  GLADE_HOOKUP_OBJECT (tx_options, use_realtime, "use_realtime");
   GLADE_HOOKUP_OBJECT (tx_options, label1, "label1");
   GLADE_HOOKUP_OBJECT (tx_options, table5, "table5");
   GLADE_HOOKUP_OBJECT (tx_options, label21, "label21");
index 477f749e69f286aa5225e38bd303ba7a2609b234..42daf288be7bd3c0f13867defc758f25980e6525 100644 (file)
@@ -156,6 +156,7 @@ void set_global_defaults() {
        strcpy(globals.vu_meter_normal, "#00FF00");     
        globals.vu_meter_border_intensity=0.7;
        globals.quit_confirm=1;
+       globals.use_realtime=1;
 }
 
 int load_globals_xml() {
@@ -253,6 +254,7 @@ int load_globals_xml() {
                        restore_float("vu_meter_border_intensity", globals.vu_meter_border_intensity);
 
                        restore_int("quit_confirm", globals.quit_confirm);
+                       restore_int("use_realtime", globals.use_realtime);
 
 #ifdef USE_ALSA_MIDI_IN
                        if (!elementFound && (xmlStrcmp(cur->name, (xmlChar *) "midi_connections")==0)) {
@@ -369,6 +371,7 @@ void store_globals() {
                store_float("vu_meter_border_intensity", globals.vu_meter_border_intensity);
 
                store_int("quit_confirm", globals.quit_confirm);
+               store_int("use_realtime", globals.use_realtime);
                
 #ifdef USE_ALSA_MIDI_IN
                tX_midiin_store_connections(rc, indent);
index c701aa2c5218a8d9c2d213e8b546b1ca96cd6bae..f6aec1bbefde1b0b260f9a9525e0004d02cd9574 100644 (file)
@@ -162,6 +162,7 @@ typedef struct {
        double vu_meter_border_intensity;
        
        int quit_confirm;
+       int use_realtime;
 } tx_global;
 
 extern tx_global globals;
index b4d2722b8e2729136f417932696f7116d7af1b8a..309fa32f03fa55db0e2cd296d090063793139626 100644 (file)
            <widget class="GtkTable" id="table4">
              <property name="border_width">4</property>
              <property name="visible">True</property>
-             <property name="n_rows">1</property>
+             <property name="n_rows">2</property>
              <property name="n_columns">2</property>
              <property name="homogeneous">False</property>
              <property name="row_spacing">2</property>
                  <property name="y_options">fill</property>
                </packing>
              </child>
+
+             <child>
+               <widget class="GtkLabel" id="label58">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Use realtime scheduling
+where available:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="left_attach">0</property>
+                 <property name="right_attach">1</property>
+                 <property name="top_attach">1</property>
+                 <property name="bottom_attach">2</property>
+                 <property name="x_options">fill</property>
+                 <property name="y_options"></property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkCheckButton" id="use_realtime">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="label" translatable="yes">Enabled</property>
+                 <property name="use_underline">True</property>
+                 <property name="relief">GTK_RELIEF_NORMAL</property>
+                 <property name="active">False</property>
+                 <property name="inconsistent">False</property>
+                 <property name="draw_indicator">True</property>
+               </widget>
+               <packing>
+                 <property name="left_attach">1</property>
+                 <property name="right_attach">2</property>
+                 <property name="top_attach">1</property>
+                 <property name="bottom_attach">2</property>
+                 <property name="x_options">fill</property>
+                 <property name="y_options"></property>
+               </packing>
+             </child>
            </widget>
            <packing>
              <property name="tab_expand">False</property>