http://qs321.pair.com?node_id=361795
Category: Win32 Stuff
Author/Contact Info Chady
Description:

Win32 Multiple Clipboards was implemented in a really silly way. I don't know how I missed the obvious. Here's a different implementation that eats a lot less memory, and doesn't use threads and sharing etc...

In fact, what I missed last time was the timer. And since there's no readable documentation for Win32::GUI I came across this by a combination of poking thourgh GUI.pm and luck. It worked out pretty well, and now I'm actually using this.

You will probably need Win32::GUI cause it's not with default ActiveState's installation, otherwise, this should work right out of the box.

Screenshot

Comments and suggestions please.

#!perl 

# copyright (c) Chady Kassouf 2004
# This program is free software, it is distributed under 
# the sames terms as Perl itself.

use strict;

use Win32::Clipboard;
use Win32::GUI;

my $empty = '--empty--';        # the empty string
# my $image = '[BITMAP]';
my $DEBUG = 1;                # set to 1 for debugging info.

my @boxes;                # holds the radiobuttons
my $CLIP;                # tied to the clipboard
my @board;                # holds the clipboard entries.


push @board, ['', $empty] for 0 .. 4;
tie $CLIP, 'Win32::Clipboard';

# GUI creation.

my $main = Win32::GUI::Window->new(
    -name    =>    'main',
    -text    =>    'Win32 Multiple Clipboards II',
    -width    =>    200,
    -height    =>    150
);

my $icon = Win32::GUI::Icon->new('Note.ico');
my $tray = $main->AddNotifyIcon(
    -name    =>    'tray',
    -icon    =>    $icon,
    -tip    =>    'Win32 Multiple Clipboards II'
);


# I found this handled nicely, 
# this isn't a busy loop, so no high CPU usage here
my $timer = $main->AddTimer('timer', 100);


foreach (0 .. 4) {
    $boxes[$_] = $main->AddRadioButton(
        -name => "board$_",
                -text => $board[$_]->[1],
                -pos  => [ 10, 10 + 20 * $_ ],
    );
    $boxes[$_]->{-width} = 150;
}

$main->Show();
set_clip(1);
Win32::GUI::Dialog();

#####

sub timer_Timer {

    my $label;
    my $data;
    
    if (tied($CLIP)->IsBitmap()) {
        # I tried to handle bitmap data, but it 
        # gets ruined while copied back and forth;
        # when set back, the data become text data.
        debug('Bitmap data, skipping');
        return;
        # $label = $image;
        # $data = tied($CLIP)->GetBitmap();
    } else {
        $label = $CLIP;
        $label =~ s/^(.{20})(.*)$/$1... /;
        $data = $CLIP;
    }

    return if $data eq $board[0]->[0];
    debug ('Got new clipboard.');

    unshift @board, [$data, $label];
    pop @board if @board == 4;

}

sub redraw {
    for (0..4) {
        $boxes[$_]->Checked(0);
        $boxes[$_]->{-text} = $board[$_]->[1];
    }
}

sub set_clip {
    my $which = shift;
    redraw();

    if ($which) {
        $which--;
        if ($board[$which]->[1] eq $empty) {
            debug('empty slot.');
        } else {
            debug('Setting clip to: ', $board[$which]->[1]);
            $CLIP = $board[$which]->[0];
        }
        $main->Disable();
        $main->Hide();
    }
}


# everything I tried doesn't work here.
sub board0_Click {set_clip(1);1;}
sub board1_Click {set_clip(2);1;}
sub board2_Click {set_clip(3);1;}
sub board3_Click {set_clip(4);1;}
sub board4_Click {set_clip(5);1;}


sub tray_Click {
    
    # move the window near the task bar
    my $desk = Win32::GUI::GetDesktopWindow();
    my $dw = Win32::GUI::Width($desk);
    my $dh = Win32::GUI::Height($desk);
    my $x = $dw - $main->Width();
    # the taskbar is 27 pixels on Xp (no Luna)
    my $y = $dh - $main->Height() - 27;
    $main->Move($x, $y);
    
    redraw();
    
    $main->Enable();
    $main->Show();
    1;
}

sub main_Minimize {

    $main->Disable();
    $main->Hide();
    1;
}

sub main_Terminate {
    -1;
}

sub debug {
    print @_, "\n" if $DEBUG;
}