Feed Notifier has a new home!

January 22, 2010

My Feed Notifier application has out-grown my blog.  Today I registered feed-notifier.com to host the app now that version 2.0 is nearing completion.  Check it out!

http://www.feednotifier.com/

Feed Notifier 2.0 – Configuring Pop-ups

January 21, 2010

I’ve cleaned up some code, changed the tab appearance of the options dialog, and have added controls for configuring the pop-ups.  Here’s how we’re looking now…

Feed Notifier 2.0

Feed Notifier 2.0

Feed Notifier 2.0 – Configuring Feeds

January 19, 2010

I’ve started the settings dialog for Feed Notifier 2.0.  It will have three tabs:

  • Feeds – Add, edit, remove feeds from the notifier.
  • Pop-ups – Configure appearance and behavior of the notification pop-ups.
  • Options – Configure miscellaneous application settings.

So far I’ve got the Feeds tab implemented.  I wrote the code in a hurry, so it needs some cleaning up.  But here it is…

Feed Notifier 2.0 - Feed Configuration

Feed Notifier 2.0 - Feed Configuration

Feed Notifier 2.0 – Adding New Feeds

January 18, 2010

Work on version 2.0 of the Feed Notifier is coming along smoothly.  Now I’d like to show off the new dialogs for adding feeds to the notifier.  It’s now been broken up into a 2-step process.

Add Feed: Step 1

Add Feed: Step 1

Add Feed: Step 2

Add Feed: Step 2

Things worth noting:

  • The app checks the feed to make sure it’s valid in Step 1.  If it’s valid, you move on to Step 2.
  • The app automatically puts in the title and link from the feed, but you can change them to whatever you want, to customize how it will appear in the pop-ups.
  • The polling interval units can be chosen: minutes, hours or days.  Polling interval can be as low as 1 minute.
  • So, it’s still really quick to add a feed but you get more customization options.

Sneak Peek: Feed Notifier 2.0

January 16, 2010

My Feed Notifier application has been a relative success.  It’s the only app I’ve created that continues to get hundreds of downloads every month, just by people finding it on my blog from search engines.  I’ve also received dozens of feature requests and have some ideas of my own.  So, I’ve been wanting to create version 2 of this simple but useful application and I’ve finally started just that.  For starters, the system tray pop-ups are getting a revamped look and feel, including user-selectable themes.  Here’s a sneak peek at my work in progress…

Feed Notifier 2.0 - Sneak Peek

Feed Notifier 2.0 - Sneak Peek

Some things to note about the new pop-up design:

  • The pop-ups are actually rendered using the Internet Explorer ActiveX plugin, meaning it will be easy to support and add new user-configurable themes.
  • The age of the post is now shown, as well as the author. (“21 days ago by George Sakkis”)
  • You can navigate through the items with the controls on the bottom.
  • The favicon for the feed will be shown in the top-left corner, if available.
  • The pop-up can be closed at any time with the icon on the top-right.
  • The play/pause controls enable/disable automatic stepping through the items.

I’m writing most of the code from scratch, so it may take some time before this release is available.  I’ll keep you posted.

Google Homepage Fade-In

December 6, 2009

Dumbest UI decision ever.

For those who haven’t noticed, the Google homepage (not iGoogle and not the Firefox start page, etc. but the real actual homepage at google.com) does a fade-in effect, showing only the logo, search bar and search buttons until the user moves the mouse, revealing everything else that used to always be visible upon page load.

Before Fade

Before Fade

After Fade

After Fade

Supposedly they did this to create less clutter and be more minimalistic, since most people visiting the page are just going to type in their search and hit enter.  Supposedly they also did tons of internal testing and randomized public testing.  Well, I think it’s retarded and annoying and a user experience failure.

  • The page was already more than acceptably minimalistic and uncluttered. If it ain’t broke, don’t fix it.
  • If users are just going to type and hit enter, they presumably are already pretty familiar with Google’s homepage and aren’t going to get confused by what else is on the screen. Targeting the wrong audience.
  • If users are looking for something else on that page (I click the top-left links all the time), they first have to jiggle the mouse around and wait for the dumb fade-in to complete. Degradation of user experience.
  • If I click “Home” in Firefox (which takes me to the Google homepage) and quickly move my mouse into the page area, the fade-in won’t even happen unless I keep moving my mouse for about a second. Poor implementation.
  • I can’t scan the page to see what is available to me until I move the mouse.  A new user might not even see what else is on the page.  I should be able to look for what I want and then move the mouse to it. Hidden content, degradation of user experience.
  • It can’t be disabled without using third-party browser extensions.  If it could I probably wouldn’t even be writing this.
  • It looks like Google is trying to make the page look stylish or something.  No one cares, we just want our primary navigation links to be available immediately.

The bottom line is that this change adds no benefit and is more likely to degrade the user experience.

Reminds me of this Onion video, except this time it’s Google and not Apple:

Apple Introduces Revolutionary New Laptop With No Keyboard

See also:

http://googleblog.blogspot.com/2009/12/now-you-see-it-now-you-dont.html

Drawing on the Windows desktop using Python and wxPython.

December 4, 2009

My co-worker showed me a neat little app that showed snowflakes falling on the Windows desktop.  The snow would pile up on windows, and the snow didn’t draw on top of other windows, only the desktop wallpaper.

I wondered how I could accomplish this using wxPython.  wx has a ScreenDC, but this draws on the entire screen, over windows and all.  I wanted to draw under windows but over the desktop.

The solution I came up with isn’t cross platform, but it works.  The idea is to use ctypes to invoke some win32 API’s to find the appropriate window to draw on.  The next important thing is knowing about the function wxWindow::AssociateHandle.  You can associate a window with any system-wide HWND and the wxWindow will start acting upon that window instead.

On windows, the control we want to draw on can be found with Spy++ and it’s hierarchy is:

  • Progman
  • SHELLDLL_DefView
  • SysListView32

SysListView32 is the control that shows all the desktop icons.  To get a handle to this control, we use the win32 functions GetDesktopWindow and FindWindowEx.

The following function finds a window from the specified name hierarchy.

def find_window(parent, names):
    if not names:
        return parent
    name = unicode(names[0])
    child = 0
    while True:
        child = ctypes.windll.user32.FindWindowExW(parent, child, name, 0)
        if not child:
            return 0
        result = find_window(child, names[1:])
        if result:
            return result

We use it like this:

desktop = ctypes.windll.user32.GetDesktopWindow()
handle = 0
handle = handle or find_window(desktop, ['Progman', 'SHELLDLL_DefView', 'SysListView32'])
handle = handle or find_window(desktop, ['WorkerW', 'SHELLDLL_DefView', 'SysListView32'])

On Windows 7 (and maybe Vista too), Progman is replaced by WorkerW, so we have to try both hierarchies and use the first match we find.

Then we just create a dummy window and associate it with the handle we found with find_window.

self.AssociateHandle(handle)

After that, a WindowDC can be used to draw on the desktop wallpaper.  The usual flicker-reducing techniques can’t really be used as we aren’t getting paint events.  Instead, what I did was invalidate small regions of the desktop with RefreshRect, followed by Update and then finally drawing the next frame.  Like this:

dc = wx.WindowDC(self)
for flake in self.flakes:
    self.RefreshRect(flake.rect)
    self.Update()
    flake.update()
    flake.draw(dc)
dc.Destroy()

I called my snowflake implementation wxSnow, and you can get it here:

http://www.michaelfogleman.com/wxsnow-snow-falling-on-your-windows-desktop/

Jayda & Pretzel

October 18, 2009

Testing embedding videos on my blog. This was taken with my new camera, which is awesome!  Be sure to watch the HD version!

Jayda & Pretzel from Michael Fogleman on Vimeo.

Python Short URL Generator

September 30, 2009

I wrote a Python module for generating Tiny URL- and bit.ly-like URLs. I see people in the programming community asking how to do this all the time. Some of the suggestions on how to implement it are dumb. Here’s my approach. I posted it as a recipe here: http://code.activestate.com/recipes/576918/

A bit-shuffling approach is used to avoid generating consecutive, predictable URLs. However, the algorithm is deterministic and will guarantee that no collisions will occur.

The URL alphabet is fully customizable and may contain any number of characters. By default, digits, upper- and lower-case letters are used, with some removed to avoid confusion between characters like o, O and 0. The default alphabet is shuffled and has a prime number of characters to further improve the results of the algorithm.

The block size specifies how many bits will be shuffled. The lower BLOCK_SIZE bits are reversed. Any bits higher than BLOCK_SIZE will remain as is. BLOCK_SIZE of 0 will leave all bits unaffected and the algorithm will simply be converting your integer to a different base.

The intended use is that incrementing, consecutive integers will be used as keys to generate the short URLs. For example, when creating a new URL, the unique integer ID assigned by a database could be used to generate the URL by using this module. Or a simple counter may be used. As long as the same integer is not used twice, the same short URL will not be generated twice.

The module supports both encoding and decoding of URLs. The min_length parameter allows you to pad the URL if you want it to be a specific length.

Sample Usage:
>>> import short_url
>>> url = short_url.encode_url(12)
>>> print url
LhKA
>>> key = short_url.decode_url(url)
>>> print key
12

Use the functions in the top-level of the module to use the default encoder. Otherwise, you may create your own UrlEncoder object and use its encode_url and decode_url methods.

Here’s the code!

DEFAULT_ALPHABET = 'JedR8LNFY2j6MrhkBSADUyfP5amuH9xQCX4VqbgpsGtnW7vc3TwKE'
DEFAULT_BLOCK_SIZE = 22
 
class UrlEncoder(object):
    def __init__(self, alphabet=DEFAULT_ALPHABET, block_size=DEFAULT_BLOCK_SIZE):
        self.alphabet = alphabet
        self.block_size = block_size
        self.mask = (1 << block_size) - 1
        self.mapping = range(block_size)
        self.mapping.reverse()
    def encode_url(self, n, min_length=0):
        return self.enbase(self.encode(n), min_length)
    def decode_url(self, n):
        return self.decode(self.debase(n))
    def encode(self, n):
        return (n & ~self.mask) | self._encode(n & self.mask)
    def _encode(self, n):
        result = 0
        for i, b in enumerate(self.mapping):
            if n & (1 << i):
                result |= (1 << b)
        return result
    def decode(self, n):
        return (n & ~self.mask) | self._decode(n & self.mask)
    def _decode(self, n):
        result = 0
        for i, b in enumerate(self.mapping):
            if n & (1 << b):
                result |= (1 << i)
        return result
    def enbase(self, x, min_length=0):
        result = self._enbase(x)
        padding = self.alphabet[0] * (min_length - len(result))
        return '%s%s' % (padding, result)
    def _enbase(self, x):
        n = len(self.alphabet)
        if x < n:
            return self.alphabet[x]
        return enbase(x/n) + self.alphabet[x%n]
    def debase(self, x):
        n = len(self.alphabet)
        result = 0
        for i, c in enumerate(reversed(x)):
            result += self.alphabet.index(c) * (n**i)
        return result
 
DEFAULT_ENCODER = UrlEncoder()
 
def encode(n):
    return DEFAULT_ENCODER.encode(n)
 
def decode(n):
    return DEFAULT_ENCODER.decode(n)
 
def enbase(n, min_length=0):
    return DEFAULT_ENCODER.enbase(n, min_length)
 
def debase(n):
    return DEFAULT_ENCODER.debase(n)
 
def encode_url(n, min_length=0):
    return DEFAULT_ENCODER.encode_url(n, min_length)
 
def decode_url(n):
    return DEFAULT_ENCODER.decode_url(n)
 
if __name__ == '__main__':
    for a in range(0, 200000, 37):
        b = encode(a)
        c = enbase(b)
        d = debase(c)
        e = decode(d)
        assert a == e
        assert b == d
        c = (' ' * (7 - len(c))) + c
        print '%6d %12d %s %12d %6d' % (a, b, c, d, e)

Feed Notifier Update: “Dismiss All” Feature and Shutdown Crash Fix

March 5, 2009

I’ve updated the Feed Notifier application with one new feature and one bug fix.  A “Dismiss All” feature allows you to clear the popup queue so that the popups will stop until more new ones come in.  I also finally tracked down the cause of a bug that caused the app to crash on shutdown/logout.  Yay.  The new installer has been uploaded.

Download the Feed Notifier installer for Windows.

 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org