Eugeni's blog

One blog to rule them all. Kinda.

Browsing the topic Linux-Planet

So, after a take on Metacity , I just went ahead and implemented the same quick workspace switching feature for KDE (namely, kwin) – with great help from Nicolas Lécureuil (a.k.a. Neoclust) of course!

Basically, it works essentially like the same feature in xfwm4 – when you switch to a different workspace via a keyboard shortcut, and press the same shortcut again while on this workspace, it will bring you back to the previous one. So you can press ctrl-f2 to switch to from workspace 1 workspace 2, and when you press ctrl-f2 again kwin will recognize that you want switch back, to whatever workspace you were before, and will do it. An extremely handy quirk which I cannot live without anymore :) .

I have to assume that I have never ever coded anything for KDE until yesterday, but it turned out to be extremely simple. KDE has its flaws, its infrastructure with billions of libraries and processes everywhere is hard to understand, but I actually was surprised on how easy it was.

So, without further words, the patch for kdebase4-workspace which adds this functionality follows (sorry for the formatting, but kde has some very long lines of code..):

diff -p -up kdebase-workspace-4.5.65svn1165394/kwin/kcmkwin/kwindesktop/main.cpp.switchback kdebase-workspace-4.5.65svn1165394/kwin/kcmkwin/kwindesktop/main.cpp
--- kdebase-workspace-4.5.65svn1165394/kwin/kcmkwin/kwindesktop/main.cpp.switchback 2010-09-01 09:10:02.000000000 -0300
+++ kdebase-workspace-4.5.65svn1165394/kwin/kcmkwin/kwindesktop/main.cpp    2010-09-01 09:21:13.000000000 -0300
@@ -184,6 +184,7 @@ void KWinDesktopConfig::init()
     connect( m_ui->popupHideSpinBox, SIGNAL(valueChanged(int)), SLOT(changed()));
     connect( m_ui->desktopLayoutIndicatorCheckBox, SIGNAL(stateChanged(int)), SLOT(changed()));
     connect( m_ui->wrapAroundBox, SIGNAL(stateChanged(int)), SLOT(changed()));
+    connect( m_ui->switchBackBox, SIGNAL(stateChanged(int)), SLOT(changed()));
     connect( m_editor, SIGNAL(keyChange()), SLOT(changed()));
     connect( m_ui->allShortcutsCheckBox, SIGNAL(stateChanged(int)), SLOT(slotShowAllShortcuts()));
     connect( m_ui->effectComboBox, SIGNAL(currentIndexChanged(int)), SLOT(changed()));
@@ -252,6 +253,8 @@ void KWinDesktopConfig::defaults()

     m_ui->wrapAroundBox->setChecked( true );

+    m_ui->switchBackBox->setChecked( false );
+
     m_editor->allDefault();

     emit changed(true);
@@ -285,6 +288,9 @@ void KWinDesktopConfig::load()
     KConfigGroup windowConfig( m_config, "Windows" );
     m_ui->wrapAroundBox->setChecked( windowConfig.readEntry<bool>( "RollOverDesktops", true ) );

+    // Quick switching back to previous desktop
+    m_ui->switchBackBox->setChecked( windowConfig.readEntry<bool>( "SwitchBackDesktops", false ) );
+
     // Effect for desktop switching
     // Set current option to "none" if no plugin is activated.
     KConfigGroup effectconfig( m_config, "Plugins" );
@@ -341,6 +347,9 @@ void KWinDesktopConfig::save()
     // Wrap Around on screen edge
     KConfigGroup windowConfig( m_config, "Windows" );
     windowConfig.writeEntry( "RollOverDesktops", m_ui->wrapAroundBox->isChecked() );
+    //
+    // Quickly back to previous desktop
+    windowConfig.writeEntry( "SwitchBackDesktops", m_ui->switchBackBox->isChecked() );

     // Effect desktop switching
     KConfigGroup effectconfig( m_config, "Plugins" );
diff -p -up kdebase-workspace-4.5.65svn1165394/kwin/kcmkwin/kwindesktop/main.ui.switchback kdebase-workspace-4.5.65svn1165394/kwin/kcmkwin/kwindesktop/main.ui
--- kdebase-workspace-4.5.65svn1165394/kwin/kcmkwin/kwindesktop/main.ui.switchback  2010-09-01 09:09:59.000000000 -0300
+++ kdebase-workspace-4.5.65svn1165394/kwin/kcmkwin/kwindesktop/main.ui 2010-09-01 09:59:02.000000000 -0300
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>572</width>
-    <height>310</height>
+    <height>334</height>
    </rect>
   </property>
   <layout class="QHBoxLayout" name="horizontalLayout">
@@ -141,6 +141,16 @@
          </property>
         </widget>
        </item>
+       <item>
+        <widget class="QCheckBox" name="switchBackBox">
+         <property name="whatsThis">
+          <string>Enable this option if you want to remember and recall previous desktop when switching via keyboard shortcuts. E.g., if you switched to desktop 2 by pressing its shortcut, pressing it again while on desktop 2 will bring you back to the previous desktop.</string>
+         </property>
+         <property name="text">
+          <string>Remember and recall previous desktop when switching via keyboard shortcuts</string>
+         </property>
+        </widget>
+       </item>
        <item>
         <widget class="QGroupBox" name="groupBox_3">
          <property name="title">
diff -p -up kdebase-workspace-4.5.65svn1165394/kwin/kwin.kcfg.switchback kdebase-workspace-4.5.65svn1165394/kwin/kwin.kcfg
--- kdebase-workspace-4.5.65svn1165394/kwin/kwin.kcfg.switchback    2010-09-01 09:10:56.000000000 -0300
+++ kdebase-workspace-4.5.65svn1165394/kwin/kwin.kcfg   2010-09-01 09:16:20.000000000 -0300
@@ -41,6 +41,7 @@
   <entry key="ShadeHover" type="Bool" />
   <entry key="GeometryTip" type="Bool" />
   <entry key="RollOverDesktops" type="Bool" />
+  <entry key="SwitchBackDesktops" type="Bool" />
   <entry key="FocusStealingPreventionLevel" type="Int" />
   <entry key="Placement" type="String" />
   <entry key="AutoRaise" type="Bool" />
diff -p -up kdebase-workspace-4.5.65svn1165394/kwin/options.cpp.switchback kdebase-workspace-4.5.65svn1165394/kwin/options.cpp
--- kdebase-workspace-4.5.65svn1165394/kwin/options.cpp.switchback  2010-09-01 09:12:09.000000000 -0300
+++ kdebase-workspace-4.5.65svn1165394/kwin/options.cpp 2010-09-01 09:26:40.000000000 -0300
@@ -87,6 +87,8 @@ unsigned long Options::updateSettings()

     rollOverDesktops = config.readEntry("RollOverDesktops", true);

+    switchBackDesktops = config.readEntry("SwitchBackDesktops", false);
+
     legacyFullscreenSupport = config.readEntry( "LegacyFullscreenSupport", false );

 //    focusStealingPreventionLevel = config.readEntry( "FocusStealingPreventionLevel", 2 );
diff -p -up kdebase-workspace-4.5.65svn1165394/kwin/options.h.switchback kdebase-workspace-4.5.65svn1165394/kwin/options.h
--- kdebase-workspace-4.5.65svn1165394/kwin/options.h.switchback    2010-09-01 09:12:07.000000000 -0300
+++ kdebase-workspace-4.5.65svn1165394/kwin/options.h   2010-09-01 09:22:14.000000000 -0300
@@ -215,6 +215,11 @@ class Options : public KDecorationOption
          */
         bool rollOverDesktops;

+        /**
+         * whether or not quick switching back to previous desktop is allowed via keyboard shortcuts
+         */
+        bool switchBackDesktops;
+
         // 0 - 4 , see Workspace::allowClientActivation()
         int focusStealingPreventionLevel;

diff -p -up kdebase-workspace-4.5.65svn1165394/kwin/workspace.cpp.switchback kdebase-workspace-4.5.65svn1165394/kwin/workspace.cpp
--- kdebase-workspace-4.5.65svn1165394/kwin/workspace.cpp.switchback    2010-05-20 08:42:10.000000000 -0300
+++ kdebase-workspace-4.5.65svn1165394/kwin/workspace.cpp   2010-09-01 10:10:02.000000000 -0300
@@ -95,6 +95,7 @@ Workspace::Workspace( bool restore )
     , desktopGridSize_( 1, 2 ) // Default to two rows
     , desktopGrid_( new int[2] )
     , currentDesktop_( 0 )
+    , prevDesktop_( 0 )
     , desktopLayoutDynamicity_( false )
     , tilingEnabled_( false )
     // Unsorted
@@ -1403,6 +1404,15 @@ bool Workspace::setCurrentDesktop( int n
     StackingUpdatesBlocker blocker( this );

     int old_desktop = currentDesktop();
+
+    // Eugeni: are we trying to switch back to previous desktop?
+    if (options->switchBackDesktops && (old_desktop == new_desktop ) && (prevDesktop() > 0) )
+        {
+        // go back to previous desktop
+        new_desktop = prevDesktop();
+        kDebug(1212) << "Switching back to " << new_desktop;
+        }
+
     if (new_desktop != currentDesktop() )
         {
         ++block_showing_desktop;
@@ -1413,6 +1423,7 @@ bool Workspace::setCurrentDesktop( int n
         ObscuringWindows obs_wins;

         currentDesktop_ = new_desktop; // Change the desktop (so that Client::updateVisibility() works)
+        prevDesktop_ = old_desktop;

         for( ClientList::ConstIterator it = stacking_order.constBegin();
             it != stacking_order.constEnd();
diff -p -up kdebase-workspace-4.5.65svn1165394/kwin/workspace.h.switchback kdebase-workspace-4.5.65svn1165394/kwin/workspace.h
--- kdebase-workspace-4.5.65svn1165394/kwin/workspace.h.switchback  2010-08-11 07:08:13.000000000 -0300
+++ kdebase-workspace-4.5.65svn1165394/kwin/workspace.h 2010-08-31 23:34:01.000000000 -0300
@@ -245,6 +245,10 @@ class Workspace : public QObject, public
          */
         int currentDesktop() const;
         /**
+         * @returns The ID of the previous desktop.
+         */
+        int prevDesktop() const;
+        /**
          * Set the current desktop to @a current.
          * @returns True on success, false otherwise.
          */
@@ -314,6 +318,7 @@ class Workspace : public QObject, public
         QSize desktopGridSize_;
         int* desktopGrid_;
         int currentDesktop_;
+        int prevDesktop_;
         QString activity_;
         bool desktopLayoutDynamicity_;

@@ -1142,6 +1147,11 @@ inline int Workspace::currentDesktop() c
     return currentDesktop_;
     }

+inline int Workspace::prevDesktop() const
+    {
+    return prevDesktop_;
+    }
+
 inline int Workspace::desktopAtCoords( QPoint coords ) const
     {
     return desktopGrid_[coords.y() * desktopGridSize_.width() + coords.x()];

Every time I try to switch to a different desktop environment/window manager, there is just one simple feature which always make me go back to xfce – the possibility to quickly switch back to previous virtual desktop. A simple but extremely addictive feature, which only xfwm4 was offering…

…until yesterday! I became tired on metacity not offering this feature, so I just went ahead and implemented it overnight (learning a lot about gnome development during the process).

So, if anyone out there was missing this feature – feel free to grab this patch and apply it to the metacity source. Basically, it will add one new gconf entry (switch_to_previous_workspace), and will make metacity remember the last workspace. So you can press ctrl-f2 to switch to from workspace 1 workspace 2, and when you press ctrl-f2 again metacity will recognize that you want switch back, to whatever workspace you were before, and will do it.

Once again, this is the beauty of the open source. If there is something you need, but nobody implemented it, you always have the possibility of just doing it yourself. At least, sometimes :) .

diff -p -up metacity-2.30.1/src/core/prefs.c.switch metacity-2.30.1/src/core/prefs.c
--- metacity-2.30.1/src/core/prefs.c.switch 2010-03-30 11:35:40.000000000 -0300
+++ metacity-2.30.1/src/core/prefs.c    2010-05-06 17:47:14.000000000 -0300
@@ -97,6 +97,7 @@ static char *cursor_theme = NULL;
 static int   cursor_size = 24;
 static gboolean compositing_manager = FALSE;
 static gboolean resize_with_right_button = FALSE;
+static gboolean switch_to_previous_workspace = TRUE;
 static gboolean force_fullscreen = TRUE;

 static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
@@ -412,6 +413,11 @@ static MetaBoolPreference preferences_bo
       &resize_with_right_button,
       FALSE,
     },
+    { "/apps/metacity/general/switch_to_previous_workspace",
+      META_PREF_SWITCH_TO_PREVIOUS_WORKSPACE,
+      &switch_to_previous_workspace,
+      FALSE,
+    },
     { NULL, 0, NULL, FALSE },
   };

@@ -1757,6 +1763,9 @@ meta_preference_to_string (MetaPreferenc

     case META_PREF_FORCE_FULLSCREEN:
       return "FORCE_FULLSCREEN";
+
+    case META_PREF_SWITCH_TO_PREVIOUS_WORKSPACE:
+      return "SWITCH_TO_PREVIOUS_WORKSPACE";
     }

   return "(unknown)";
@@ -2719,6 +2728,12 @@ meta_prefs_get_mouse_button_menu (void)
   return resize_with_right_button ? 2: 3;
 }

+guint
+meta_prefs_switch_to_previous_workspace (void)
+{
+  return switch_to_previous_workspace;
+}
+
 gboolean
 meta_prefs_get_force_fullscreen (void)
 {
diff -p -up metacity-2.30.1/src/core/screen-private.h.switch metacity-2.30.1/src/core/screen-private.h
--- metacity-2.30.1/src/core/screen-private.h.switch    2010-01-14 22:31:32.000000000 -0200
+++ metacity-2.30.1/src/core/screen-private.h   2010-05-06 17:47:14.000000000 -0300
@@ -80,7 +80,7 @@ struct _MetaScreen
   MetaUI *ui;
   MetaTabPopup *tab_popup;

-  MetaWorkspace *active_workspace;
+  MetaWorkspace *active_workspace, *last_workspace;

   /* This window holds the focus when we don't want to focus
    * any actual clients
diff -p -up metacity-2.30.1/src/core/workspace.c.switch metacity-2.30.1/src/core/workspace.c
--- metacity-2.30.1/src/core/workspace.c.switch 2010-01-14 22:31:32.000000000 -0200
+++ metacity-2.30.1/src/core/workspace.c    2010-05-06 18:00:39.000000000 -0300
@@ -377,7 +377,31 @@ meta_workspace_activate_with_focus (Meta
                 meta_workspace_index (workspace));

   if (workspace->screen->active_workspace == workspace)
-    return;
+  {
+      meta_verbose("Switching to same workspace detected, going back to previous one!!\n");
+      if (meta_prefs_switch_to_previous_workspace()) {
+          if (workspace->screen->last_workspace) {
+              meta_verbose("Going to desktop %d\n", meta_workspace_index(workspace));
+              meta_workspace_activate_with_focus(workspace->screen->last_workspace,
+                      NULL, timestamp);
+              return;
+          } else {
+              meta_verbose("No old workspace..\n");
+              return;
+          }
+      } else {
+          meta_verbose("Last workspace switching disabled..\n");
+          return;
+      }
+  }
+  else
+  {
+      if (workspace->screen->active_workspace)
+          meta_verbose("Updating last workspace.. current: %d, new: %d\n",
+                  meta_workspace_index(workspace->screen->active_workspace),
+                  meta_workspace_index(workspace));
+      workspace->screen->last_workspace = workspace->screen->active_workspace;
+  }

   if (workspace->screen->active_workspace)
     workspace_switch_sound(workspace->screen->active_workspace, workspace);
diff -p -up metacity-2.30.1/src/include/prefs.h.switch metacity-2.30.1/src/include/prefs.h
--- metacity-2.30.1/src/include/prefs.h.switch  2010-01-14 22:31:32.000000000 -0200
+++ metacity-2.30.1/src/include/prefs.h 2010-05-06 17:47:14.000000000 -0300
@@ -60,7 +60,8 @@ typedef enum
   META_PREF_CURSOR_SIZE,
   META_PREF_COMPOSITING_MANAGER,
   META_PREF_RESIZE_WITH_RIGHT_BUTTON,
-  META_PREF_FORCE_FULLSCREEN
+  META_PREF_FORCE_FULLSCREEN,
+  META_PREF_SWITCH_TO_PREVIOUS_WORKSPACE
 } MetaPreference;

 typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
diff -p -up metacity-2.30.1/src/metacity.schemas.in.in.switch metacity-2.30.1/src/metacity.schemas.in.in
--- metacity-2.30.1/src/metacity.schemas.in.in.switch   2010-05-06 17:47:14.000000000 -0300
+++ metacity-2.30.1/src/metacity.schemas.in.in  2010-05-06 18:01:16.000000000 -0300
@@ -4,6 +4,24 @@
     <!-- General preferences -->        

     <schema>
+      <key>/schemas/apps/metacity/general/switch_to_previous_workspace</key>
+      <applyto>/apps/metacity/general/switch_to_previous_workspace</applyto>
+      <owner>metacity</owner>
+      <type>bool</type>
+      <default>false</default>
+      <locale name="C">
+         <short>Remember and recall previous workspace when switching via keyboard shortcuts</short>
+         <long>
+           Set this to true to allow to switch to previous workspace when
+           using the current workspace keybinding. For example, if you switched
+           from workspace 2 to workspace 1 by pressing keyboard shortcut for
+           workspace 1, pressing the same shortcut again while on workspace 1
+           will switch to workspace 2.
+         </long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/metacity/general/mouse_button_modifier</key>
       <applyto>/apps/metacity/general/mouse_button_modifier</applyto>
       <owner>metacity</owner>
diff -p -up metacity-2.30.1/src/metacity.schemas.in.switch metacity-2.30.1/src/metacity.schemas.in
--- metacity-2.30.1/src/metacity.schemas.in.switch  2010-04-06 07:10:38.000000000 -0300
+++ metacity-2.30.1/src/metacity.schemas.in 2010-05-06 18:01:06.000000000 -0300
@@ -4,6 +4,24 @@
     <!-- General preferences -->        

     <schema>
+      <key>/schemas/apps/metacity/general/switch_to_previous_workspace</key>
+      <applyto>/apps/metacity/general/switch_to_previous_workspace</applyto>
+      <owner>metacity</owner>
+      <type>bool</type>
+      <default>false</default>
+      <locale name="C">
+         <short>Remember and recall previous workspace when switching via keyboard shortcuts</short>
+         <long>
+           Set this to true to allow to switch to previous workspace when
+           using the current workspace keybinding. For example, if you switched
+           from workspace 2 to workspace 1 by pressing keyboard shortcut for
+           workspace 1, pressing the same shortcut again while on workspace 1
+           will switch to workspace 2.
+         </long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/metacity/general/mouse_button_modifier</key>
       <applyto>/apps/metacity/general/mouse_button_modifier</applyto>
       <owner>metacity</owner>
@@ -247,7 +265,7 @@
       <applyto>/apps/metacity/general/theme</applyto>
       <owner>metacity</owner>
       <type>string</type>
-      <default>Clearlooks</default>
+      <default>Ia Ora Steel</default>
       <locale name="C">
          <short>Current theme</short>
          <long>

I just noticed this days that, according to smartctl, the hard disk on my notebook has reached 365 days on Power_On_Hours variable. As the notebook itself has almost 2 years of age (I bought it in March of 2008), it is almost a double birthday-combo :) .

However, at this age, it is obvious that the hard disk of the notebook was not prepared to endure such challenges nicely. Both of its speed (5400 RPMs), durability, capacity, and so on were targeted on a more light use.

On the other hand, the system has 3GB of RAM, which is more than enough for most of my tasks. So after some thinking, I’ve been using some small script to automatically improve the system performance by offloading the most I/O-consuming stuff to RAM for the past few months.

How does it works? Simple. I have a small script which grabs content of a disk directory which I expect to receive heavy use (for example, /usr/lib/firefox, or the rpm BUILD/ directories which receive lots of I/O when building packages, and so on), and converts them into a RAM disk. This way, when anything inside such directory is accessed, it requires absolutely no hard disk I/O, the seek times are non-existent as well, and the throughput is incredible.

For example, if I build mozilla-thunderbird by using real hard disk BUILD directory, it takes almost 2 hours to build. If I use ramdisk for just the BUILD directory, the time required for such task drops down to about 30 minutes. The firefox startup time (both cold and hot – e.g., the first execution and consecutive ones) have the same time of about 1 second; and so on.

So, without further words, this is the script I am using:

#!/bin/bash
#
# This script remounts a directory in tmpfs (ramdisk) to speed it up
#

DIR=$1
SIZE=$2

if [ ! "$UID" = "0" ]; then
    # this script must run by root. Let's try sudo'ing to root..
    exec sudo $0 $*
fi

if [ ! -d $DIR ]; then
    echo "Usage: $0 <full path to a directory>"
    exit 1
fi

if [ "a$SIZE" = "a" ]; then
    OPTIONS=""
else
    OPTIONS="-o size=$SIZE"
fi

# first, copy everything somewhere to reuse it later
TMP=`mktemp`
tar cpf $TMP $DIR

# remount dir as ramdisk
mount -t tmpfs $OPTIONS $DIR $DIR

# unpack everything back
(cd / && tar xpf $TMP)
rm -f $TMP

To use it, just save it under a name like toram and use it on the directory you want to move to ramdisk. The second optional parameter is the size of the ramdisk to use – as by default tmpfs mounts itself with 50% of available ram, sometimes you may want to use more or less memory.

Just some examples on how to use it:

# toram `pwd`/BUILD (will remount current BUILD directory in RAM)
# toram /usr/lib/firefox-3.6 (will remount firefox directory in ram)

I hope this could be useful to someone :) .

A few weeks ago I finally realized my old wish: I bought a real camera for me: a Nikon D40 – which is, according to many, many people, is the best DSLR out there. At least for non-professionals.

With just a few pictures it was already possible to note the difference – I could not ever EVER got close to those pictures with all my previous cameras (like Nokia N95 and Sony CyberShot W90):

Sunset at Angra dos Reis A flower and a tiny bee Rancho Panorama A beautiful flower

However, after a few days with my new camera, I found out that it came with some dust on its sensor. Not much, but clearly visible on pictures with uniform colors (like sky or white wall). For example, it is possible to see the dust spot on the left half of the following picture – if you zoom in, you’ll clearly see that there is some dark spot covering part of a cloud and appearing in the sky:

A lonely tree among clouds A lonely tree 3

One could say ‘Ahh, but that is just a small tiny spot.. nobody will notice it’. But… I do notice it, and I don’t like it. So I started looking for solutions for this issue.

In first place, I tried cleaning the sensor using a air blower (without luck). The dust spot moved a bit with the air flow (a few microns) and landed to its new place (permanently, I afraid). The next step was to ask the official Nikon support in Brazil, which is located in São Paulo city, about 250km from where I live. Their answer was is that the sensor cleaning should cost around R$ 100 (about 60 US$) + shipping. Quite expensive in my opinion.

So the next step was to start thinking like a computer geek. The photo is digital, so it is nothing more than a bunch of bits :) . So there SHOULD be some software or at least algorithm suitable for cleaning this all. After a quick research, I found that there is the Nikon Capture NX software which removes the dust pretty well. However, it is

  • commercial
  • expensive
  • orders you to take photos in RAW only. I like RAW, but… the memory card is not infinite.

So another option was to clean the dust in gimp. Manually… and it is needless to say that this approach is.. well.. boring, time-consuming and pretty much futile.

However, when all the hope was, apparently, lost, the Great Google Gods sent me a wonderful link to the Resynthesizer plugin – which is AMAZINGLY EFFICIENT in solving the dust issues.

So, dear readers, without other words, I’ll show you the few needed steps to fix the dust on your photos:

  1. Install resynthesizer plugin. On Mandriva systems, you can cheat and run a magic urpmi gimp2-resynthesizer command which will do the trick. On other systems, go to the resynthesizer web site, download, compile and install the plugin. it is trivial, so I won’t go into additional details here.

  2. Grab your dust-damaged image and open it in gimp. As you can see, there is a horrible dust on the left part of the otherwise-blue sky:

Gimp with the dust-cleaning victim

  1. Select a region around the dust to remove:

Selecting the dust to remove

  1. Press CTRL-X to remove the selected area:

Removing the dust

  1. Now, select a bit larger region around the white spot:

Selecting some space around the dust spot

  1. Go to Filters->Map->Resynthesize and run the Resynthesize filter:

The Resynthesizer plugin in all its glory

  1. Wait, wait, and…:

Magic!

  1. That’s it!:

A perfect clear sky!

Of course, it all could be done manually in gimp. However, the Resynthesizer plugin just makes it easier and better.

So what is the result? A bit more magic + some Hugin hacking and…:

Panoramic view of Ilha Bela/SP, Brazil

Yes, that’s right. Every image on panorama had a dust spot, which I cleared up with Resynthesizer. So next time you encounter some dust on your photo, remember that there is a GREAT open-source plugin for gimp out there to help!

Enjoy, and have a Happy New Year! :)

Working on Mandriva network tools, I looked on one of the most essential ones the network monitor (net_monitor). It was introduced a couple of releases before, and was mostly doing its job. However, it has a number of flaws and lack of features that motivated us to look closer at it.

Our old friend net_monitor, present in your favorite Mandriva distro!

Our old friend net_monitor, present in your favorite Mandriva distro!

The net_monitor currently used in all Mandriva versions is written in perl, is using internal drakx-net api (and is, therefore, only usable on Mandriva), and also have some issues such as memory leaks and non-usual interface. After a few thoughts and discussions we came to conclusion that it would be more adequate to project and rewrite it from scratch, turning it more modular, expansible and focused on common use cases.

Initially, I thought on using perl to write it, so it would still be part of drakx-net suite. However, after thinking on the code and the way it should work I felt that my brain was going to melt down :) (perl is a nice language, but it is certainly not that compatible with me). So I ended up with python, which is my language of choice (together with C). Also, I’ve received many comments saying that the net_monitor is no more relevant, as every desktop environment provides its own network monitoring tool, and it should be dropped from drakx-net. By combining those issues, we came to decision that it would be more proper to separate net_monitor into a different package – this way, it won’t depend on any drakx-net internal functionalities, and user could uninstall it if required and use his own network monitoring tool if he wants to. And, at the same time, users would still have a cute little network monitoring application on their machines.

So, as a picture says more than a thousand words, I guess I’ll just add some pictures here than additional KBs of text :) (EDIT: please note that the look and features of net_monitor have changed significantly in Mandriva since this post):

net_monitor monitoring a wireless connection

net_monitor monitoring a wireless connection

net_monitor monitoring a connection for which network accounting was not enabled

net_monitor monitoring a connection for which network accounting was not enabled

net_monitor displaying some statistics about your network usage (provided by vnstat)

net_monitor displaying some statistics about your network usage (provided by vnstat)

looking at daily traffic statistics on my notebook for the past month

looking at daily traffic statistics on my notebook for the past month

...and hourly statistics...

...and hourly statistics...

...and finding our when I killed my bandwidth..

...and finding our when I killed my bandwidth..

Surely, this is just an early and preliminary version, with many missing features and such. If you want to give it a try, just install net_monitor package, and it will create /usr/bin/net_monitor executable for you. It won’t conflict with existent net_monitor from drakx-net which is installed in /usr/sbin, so both of them may coexist on your system. If you look at /usr/share/doc/net_monitor/TODO, you’ll see some of the ideas that I intend to add to it, but the idea is to keep it simple and not transform it into an emacs of network monitoring :) . And, of course, feel free to add your comments and suggestions (and bug reports) here!

P.S.: Just to prevent comments like ‘you should focus on fixing bugs instead of wasting time writing new things’. Net_monitor is present in Mandriva for years now, and if you look at bugzilla list it has a number of bugs and issues. So I am not creating a new app – I am bringing back from the land of the dead an old one :) .

P.P.S.: Answering in advance to another question – yes, it would work on any Linux distro which has python and pygtk. You’ll just have to add some tricks into your network startup scripts to enable vnstat integration, but it will work just fine even without that.

One of non-trivial tricks involved in web site scalability is the optimization of all image files. One of the sites I am helping to take care of has a front page with more than 350KB in .jpeg images. And, obviously, it takes lots of time to load and, considering the number of accesses, the bandwidth is huge. Usually, those images can be optimized in photo editor, or saved with higher compression or lower quality, but sometimes there is not much else you can do. Or you think so.

One quick trick to improve this situation is by converting some images to png with ImageMagick and running pngcrush on them. A simple script can be used to do so:

    #!/bin/bash
    totalsize=0
    for file in *jpg; do
            # file.jpg becomes file.png
            newfile=${file/jpg/png}
            # convert to png
            convert $file 1.png
            # compact with pngcrush
            pngcrush -brute 1.png $newfile > /dev/null
            # calculate old and new sizes
            newsize=$(wc -c < $newfile)
            oldsize=$(wc -c < $file)
            if [ $newsize -lt $oldsize ]; then
                    echo "$file: reduced from $oldsize to $newsize bytes"
                    # remove old jpg file
                    rm -f $file
                    # replace all references to old file everywhere
                    sed -i -e "s/$file/$newfile/g" *
                    totalsize=$[$totalsize + $oldsize - $newsize]
            else
                    # old file is smaller, remove new file
                    rm -f $newfile
            fi
    done
    echo "total reduction: $totalsize"
    # remove temporary file
    rm -f 1.png

By running it on the website in question, it managed to shrink the front page by about 200KB of image data. Considering 10000 daily accesses, it would save about 2GB of network traffic per day.

Following yoho’s post, I thought it would be a good idea to join the Linux Planet project. My blog (well.. at least its technical part) is quite in line of the project’s goals: it is in English, it is technical, its content is all written by me, and it has the most reliable information out there about few opensource projects (for example, msec and netprofile :) ).

So, why not? From now on, this blog will land on Linux-Planet too! :)