package adesklets;

=for html <div class="Content">

=head1 NAME

adesklets.pm -- Perl bindings to the adesklets interpreter

=head1 COPYRIGHT

Copyright (C) 2006, Lucas Brutschy <lbrutschy@users.sourceforge.net>

Released under the GPL, version 2.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be
given in the documentation and software packages that this Software was
used.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

=head1 SYNOPSIS

 # Simple desklet: draw red lines following the mouse
 use adesklets;
 adesklets::open_streams();

 # These are just normal adesklet commands
 adesklets::window_resize(100,100);
 adesklets::window_reset(adesklets::WINDOW_UNMANAGED);
 adesklets::window_set_transparency(1);
 adesklets::context_set_color(255,255,255,64);
 adesklets::image_fill_rectangle(5,5,90,90);
 adesklets::window_show();

 adesklets::event_loop(ButtonPress=>\&onbutton); # supply a hash of callbacks
 adesklets::close_streams();

 sub onbutton
 {
    my($x,$y) = @_;
    adesklets::context_set_color(255,0,0,255);
    adesklets::image_fill_rectangle($x,$y,3,3);    
 }

=head1 DESCRIPTION

=head2 Functions

 time_gate: Set a time gate
 help: Display short help about a command
 ping: Ping the interpreter
 pause: Freeze the interpreter for debugging
 version: Get interpreter version
 get_id: Get current applet identificator
 history: List/save commands history
 set: Set or unset a textual variable
 unset_all: Unset all defined textual variables
 echo: Echo a string
 start_recording: Start recording a macro
 stop_recording: Stop recording the macro
 play_get_abort_on_events: Get replays interuptable status
 play_set_abort_on_events: Set replays to be interuptable
 play: Play a given macro
 context_get_dither: Get context dither
 context_get_anti_alias: Get context anti alias
 context_get_blend: Get context blending
 context_get_operation: Get context operation
 context_get_cliprect: Get clipping rectange
 context_get_image: Get context image
 context_get_font: Get context font
 context_get_color_range: Get context color range
 context_get_color_modifier: Get context color modifier
 context_get_filter: Get context filter
 context_get_color: Get context color
 context_get_angle: Get context angle
 context_get_direction: Get context direction
 context_set_dither: Set context dither
 context_set_anti_alias: Set context anti-alias
 context_set_blend: Set context blending
 context_set_operation: Set context operation
 context_set_cliprect: Set context clipping rectangle
 context_set_image: Set context image
 context_set_font: Set context font
 context_set_color_range: Set context color range
 context_set_color_modifier: Set context color modifier
 context_set_filter: Set context filter
 context_set_color: Set context RGBA color
 context_set_angle: Set context angle
 context_set_direction: Set context direction
 add_color_to_color_range: Add a color to a color range
 blend_image_onto_image: Blend images together
 blend_image_onto_image_at_angle: Blend images together
 blend_image_onto_image_skewed: Blend images together
 apply_filter: Apply a dynamic filter
 get_text_size: Get size of text
 get_text_advance: Get advance of text
 text_draw: Draw a text string
 modify_color_modifier_gamma: Modify gamma correction
 modify_color_modifier_brightness: Modify brightness
 modify_color_modifier_contrast: Modify contrast
 get_color_modifier_tables: Get tables for a color modifier
 set_color_modifier_tables: Set tables for a color modifier
 get_color_modifier_value: Get a value for a color modifier
 set_color_modifier_value: Set a value for a color modifier
 apply_color_modifier: Apply a color modifier
 apply_color_modifier_to_rectangle: Apply a color modifier
 load_image_without_cache: Load an image from disk bypassing the cache
 load_image: Load an image from disk
 save_image: Save an image to disk
 create_image: Create an image
 create_image_using_data: Create an image from data
 clone_image: Create a copy of an image
 free_image: Free an image
 load_font: Load a font
 free_font: Free a font
 list_fonts: List all fonts
 list_font_path: List all fonts path
 add_path_to_font_path: Add a font path
 remove_path_from_font_path: Remove a font path
 create_color_range: Create a color range
 free_color_range: Free a color range
 create_filter: Create a filter
 free_filter: Free a filter
 create_color_modifier: Create a color modifier
 free_color_modifier: Free a color modifier
 polygon_new: Create a polygon
 polygon_free: Free a polygon
 polygon_add_point: Add point to a polygon
 images_reset_all: Free all images and refresh foreground
 images_info: Get information on all images
 fonts_reset_all: Free all fonts
 fonts_info: Get information on all fonts
 color_ranges_reset_all: Free all color ranges
 color_ranges_info: Get information on all color ranges
 color_modifiers_reset_all: Free all color modifiers
 color_modifiers_info: Get information on all color modifiers
 filters_reset_all: Free all filters
 filters_info: Get information on all filters
 polygons_reset_all: Free all polygons
 polygons_info: Get information on all polygons
 image_has_alpha: Get alpha channel setting of an image
 image_get_width: Get width of an image
 image_get_height: Get height of an image
 image_get_filename: Get filename of an image
 image_get_data: Get the data of an image
 image_query_pixel: Query a pixel value
 image_set_has_alpha: Set alpha channel of an image
 image_set_changes_on_disk: Set image load time behavior
 image_set_format: Set image format
 image_filter_recurse: 
 image_draw_line: Draw a line
 image_draw_rectangle: Draw a rectangle
 image_fill_rectangle: Draw a filled rectangle
 image_fill_color_range_rectangle: Draw a gradian filled rectange
 image_draw_ellipse: Draw an ellipse
 image_fill_ellipse: Fill an ellipse
 image_copy_alpha_to_image: Transfert alpha channel
 image_copy_alpha_rectangle_to_image: Transfert alpha channel
 image_draw_polygon: Draw a polygon onto image
 image_fill_polygon: Fill a polygon onto image
 image_flip_horizontal: Flip an image horizontally
 image_flip_vertical: Flip an image vertically
 image_flip_diagonal: Flip an image diagonally
 image_orientate: Orientate an image
 image_blur: Blur an image
 image_sharpen: Sharpen an image
 filter_set: Set filter
 filter_set_red: Set filter red channel
 filter_set_green: Set filter grean channel
 filter_set_blue: Set filter blue channel
 filter_set_alpha: Set filter alpha channel
 filter_constants: Set filter constants
 filter_divisors: Set filter divisors
 menu_fire: Fire a given menu
 menu_reset_all: Reset all menus to initial state
 menu_add_menu: Add a new menu
 menu_add_submenu: Add a submenu to current menu
 menu_add_item: Add an item to current menu
 menu_add_separator: Add a separator to current menu
 menu_end_submenu: End a submenu construction
 events_info: Get all caught events
 events_get_echo: Get events echo status
 events_get_send_sigusr1: Get sending of SIGUSR1 to parent on event
 window_reset: Reset the window
 window_show: Map the window on the screen
 window_hide: Unmap the window from the screen
 window_resize: Resize the window
 window_get_transparency: Get automatic transparency
 window_get_background_grab: Get automatic grab
 window_get_background_image: Get background image
 window_get_managed_status: Get managed status
 window_set_transparency: Set automatic transparency
 window_set_background_grab: Set automatic grab
 window_set_background_image: Set background image
 screen_get_width: Get screen width
 screen_get_height: Get screen height
 screen_get_depth: Get screen depth
 get_charset: Get input charset
 set_charset: Set input charset
 charset_status: Get charset capabilities
 x_status: Status of connection to X Window server
 quit: Quit the program

=head2 Constants

 TEXT_TO_RIGHT
 TEXT_TO_LEFT
 TEXT_TO_DOWN
 TEXT_TO_UP
 TEXT_TO_ANGLE
 OP_COPY
 OP_ADD
 OP_SUBSTRACT
 OP_RESHADE
 CHANNEL_RED
 CHANNEL_GREEN
 CHANNEL_BLUE
 CHANNEL_ALPHA
 WINDOW_UNMANAGED
 WINDOW_MANAGED

=head1 SEE ALSO

adesklets manual

=for html <div />

=cut 

use strict;
use IPC::Open3;
use Cwd 'realpath';
my $pid = 0;

sub open_streams
{
    my ($path) = realpath($0);
    
    my %opthash = (
        '-h',2,'--help',2,
        '-f',1,'-k',1, '--killall',1,'-c',1, '--cleanup',1,
        '-i',1, '--installer',1,'-v',1, '--version',1,
    );

    foreach (@ARGV) { if (defined $opthash{$_}) {
        if ($opthash{$_}==2) {
            open(HELP,"| adesklets --help") or die $!;
            while(<HELP>) { print; }
            close(HELP);
            exit;
        } else { die "unsupported '$_' option.\n"; }
    }}
    
    if((!defined $ENV{ADESKLETS_ID})&&(-t STDIN))
    {
        print 'Do you want to (r)egister this desklet or to (t)est it? ';
        if(getc() eq 't')
        {
            print "\nNow testing...\n".('='x60)."\n",
                "If you do not see anything (or just an initial flicker\n".
                "in the top left corner of your screen), try `--help',\n".
                "and see the FAQ: `info adesklets'.\n".
                ('='x60)."\n";
            $path = ':';
        }
    }

    $pid = open3(\*OUT,\*IN,\*ERR,"adesklets $path ".join(" ",@ARGV)) or die $!;

    my $line = readline(ERR);
    if($line ne "event: ready!\n") { die $line; }
    
    if ((!defined $ENV{ADESKLETS_ID})&&($path ne ":"))
    {
        print "Registered. Run 'adesklets' to (re)start your desklets.\n".
            "Look at 'adesklets --help' for special options.\n";
        quit();
        close_streams();
        exit;
    }
}

sub close_streams
{
    close (OUT); close (IN); close (ERR);
    if($pid) { waitpid($pid,0); }
}

sub send_command 
{
    my ($command,@args) = @_;
    $command .= " ".join(' ',@args)."\n";
    syswrite OUT,$command;
    
    my $lines = "";
    while(1)
    {
        $lines .= readline(IN);
        if($lines =~ s/^(.*)command \d+ ok: ([^\n]*)\n//s)
        { 
            my ($prereturn,$return) = ($1,$2);
            if(($return."\n") ne $command)
            {
                my @integers;
                while($return =~ s/(\d+)//) { push(@integers,$1);}
                if($#integers == 0) { return $integers[0];}
                elsif($#integers > 0) { return @integers; }
            }
            if($prereturn ne "") { return split(/\n/,$prereturn); }
            return $return;
        } elsif ($lines =~ s/^(.*)command \d+ error: ([^\n]*)\n//s) {
            die $1.$2."\n";
        }
    }
}

sub event_loop
{
    my %functionhash = @_;
    foreach (keys %functionhash) 
        { adesklets::send_command("event_catch",$_); }

    while(1)
    {
        my $line = readline(ERR);
        if($line =~ s/\s*event: //)
        {
            $line =~ s/\s+$//;
            my @event = split / /,$line;
            my $name = shift @event;
            foreach my $key (keys %functionhash)
            {
                if(($name eq lc($key)) && ($functionhash{$key}))
                    { $functionhash{$key}->(@event); last; }
            }
        }
    }
}

# == prototypes == do not delete this comment and do not edit anything below
use constant TEXT_TO_RIGHT => 0;
use constant TEXT_TO_LEFT => 1;
use constant TEXT_TO_DOWN => 2;
use constant TEXT_TO_UP => 3;
use constant TEXT_TO_ANGLE => 4;
use constant OP_COPY => 0;
use constant OP_ADD => 1;
use constant OP_SUBSTRACT => 2;
use constant OP_RESHADE => 3;
use constant CHANNEL_RED => 0;
use constant CHANNEL_GREEN => 1;
use constant CHANNEL_BLUE => 2;
use constant CHANNEL_ALPHA => 3;
use constant WINDOW_UNMANAGED => 0;
use constant WINDOW_MANAGED => 1;
sub time_gate { return send_command('time_gate',@_); }
sub help { return send_command('help',@_); }
sub ping { return send_command('ping',@_); }
sub pause { return send_command('pause',@_); }
sub version { return send_command('version',@_); }
sub get_id { return send_command('get_id',@_); }
sub history { return send_command('history',@_); }
sub set { return send_command('set',@_); }
sub unset_all { return send_command('unset_all',@_); }
sub echo { return send_command('echo',@_); }
sub start_recording { return send_command('start_recording',@_); }
sub stop_recording { return send_command('stop_recording',@_); }
sub play_get_abort_on_events { return send_command('play_get_abort_on_events',@_); }
sub play_set_abort_on_events { return send_command('play_set_abort_on_events',@_); }
sub play { return send_command('play',@_); }
sub context_get_dither { return send_command('context_get_dither',@_); }
sub context_get_anti_alias { return send_command('context_get_anti_alias',@_); }
sub context_get_blend { return send_command('context_get_blend',@_); }
sub context_get_operation { return send_command('context_get_operation',@_); }
sub context_get_cliprect { return send_command('context_get_cliprect',@_); }
sub context_get_image { return send_command('context_get_image',@_); }
sub context_get_font { return send_command('context_get_font',@_); }
sub context_get_color_range { return send_command('context_get_color_range',@_); }
sub context_get_color_modifier { return send_command('context_get_color_modifier',@_); }
sub context_get_filter { return send_command('context_get_filter',@_); }
sub context_get_color { return send_command('context_get_color',@_); }
sub context_get_angle { return send_command('context_get_angle',@_); }
sub context_get_direction { return send_command('context_get_direction',@_); }
sub context_set_dither { return send_command('context_set_dither',@_); }
sub context_set_anti_alias { return send_command('context_set_anti_alias',@_); }
sub context_set_blend { return send_command('context_set_blend',@_); }
sub context_set_operation { return send_command('context_set_operation',@_); }
sub context_set_cliprect { return send_command('context_set_cliprect',@_); }
sub context_set_image { return send_command('context_set_image',@_); }
sub context_set_font { return send_command('context_set_font',@_); }
sub context_set_color_range { return send_command('context_set_color_range',@_); }
sub context_set_color_modifier { return send_command('context_set_color_modifier',@_); }
sub context_set_filter { return send_command('context_set_filter',@_); }
sub context_set_color { return send_command('context_set_color',@_); }
sub context_set_angle { return send_command('context_set_angle',@_); }
sub context_set_direction { return send_command('context_set_direction',@_); }
sub add_color_to_color_range { return send_command('add_color_to_color_range',@_); }
sub blend_image_onto_image { return send_command('blend_image_onto_image',@_); }
sub blend_image_onto_image_at_angle { return send_command('blend_image_onto_image_at_angle',@_); }
sub blend_image_onto_image_skewed { return send_command('blend_image_onto_image_skewed',@_); }
sub apply_filter { return send_command('apply_filter',@_); }
sub get_text_size { return send_command('get_text_size',@_); }
sub get_text_advance { return send_command('get_text_advance',@_); }
sub text_draw { return send_command('text_draw',@_); }
sub modify_color_modifier_gamma { return send_command('modify_color_modifier_gamma',@_); }
sub modify_color_modifier_brightness { return send_command('modify_color_modifier_brightness',@_); }
sub modify_color_modifier_contrast { return send_command('modify_color_modifier_contrast',@_); }
sub get_color_modifier_tables { return send_command('get_color_modifier_tables',@_); }
sub set_color_modifier_tables { return send_command('set_color_modifier_tables',@_); }
sub get_color_modifier_value { return send_command('get_color_modifier_value',@_); }
sub set_color_modifier_value { return send_command('set_color_modifier_value',@_); }
sub apply_color_modifier { return send_command('apply_color_modifier',@_); }
sub apply_color_modifier_to_rectangle { return send_command('apply_color_modifier_to_rectangle',@_); }
sub load_image_without_cache { return send_command('load_image_without_cache',@_); }
sub load_image { return send_command('load_image',@_); }
sub save_image { return send_command('save_image',@_); }
sub create_image { return send_command('create_image',@_); }
sub create_image_using_data { return send_command('create_image_using_data',@_); }
sub clone_image { return send_command('clone_image',@_); }
sub free_image { return send_command('free_image',@_); }
sub load_font { return send_command('load_font',@_); }
sub free_font { return send_command('free_font',@_); }
sub list_fonts { return send_command('list_fonts',@_); }
sub list_font_path { return send_command('list_font_path',@_); }
sub add_path_to_font_path { return send_command('add_path_to_font_path',@_); }
sub remove_path_from_font_path { return send_command('remove_path_from_font_path',@_); }
sub create_color_range { return send_command('create_color_range',@_); }
sub free_color_range { return send_command('free_color_range',@_); }
sub create_filter { return send_command('create_filter',@_); }
sub free_filter { return send_command('free_filter',@_); }
sub create_color_modifier { return send_command('create_color_modifier',@_); }
sub free_color_modifier { return send_command('free_color_modifier',@_); }
sub polygon_new { return send_command('polygon_new',@_); }
sub polygon_free { return send_command('polygon_free',@_); }
sub polygon_add_point { return send_command('polygon_add_point',@_); }
sub images_reset_all { return send_command('images_reset_all',@_); }
sub images_info { return send_command('images_info',@_); }
sub fonts_reset_all { return send_command('fonts_reset_all',@_); }
sub fonts_info { return send_command('fonts_info',@_); }
sub color_ranges_reset_all { return send_command('color_ranges_reset_all',@_); }
sub color_ranges_info { return send_command('color_ranges_info',@_); }
sub color_modifiers_reset_all { return send_command('color_modifiers_reset_all',@_); }
sub color_modifiers_info { return send_command('color_modifiers_info',@_); }
sub filters_reset_all { return send_command('filters_reset_all',@_); }
sub filters_info { return send_command('filters_info',@_); }
sub polygons_reset_all { return send_command('polygons_reset_all',@_); }
sub polygons_info { return send_command('polygons_info',@_); }
sub image_has_alpha { return send_command('image_has_alpha',@_); }
sub image_get_width { return send_command('image_get_width',@_); }
sub image_get_height { return send_command('image_get_height',@_); }
sub image_get_filename { return send_command('image_get_filename',@_); }
sub image_get_data { return send_command('image_get_data',@_); }
sub image_query_pixel { return send_command('image_query_pixel',@_); }
sub image_set_has_alpha { return send_command('image_set_has_alpha',@_); }
sub image_set_changes_on_disk { return send_command('image_set_changes_on_disk',@_); }
sub image_set_format { return send_command('image_set_format',@_); }
sub image_filter_recurse { return send_command('image_filter_recurse',@_); }
sub image_draw_line { return send_command('image_draw_line',@_); }
sub image_draw_rectangle { return send_command('image_draw_rectangle',@_); }
sub image_fill_rectangle { return send_command('image_fill_rectangle',@_); }
sub image_fill_color_range_rectangle { return send_command('image_fill_color_range_rectangle',@_); }
sub image_draw_ellipse { return send_command('image_draw_ellipse',@_); }
sub image_fill_ellipse { return send_command('image_fill_ellipse',@_); }
sub image_copy_alpha_to_image { return send_command('image_copy_alpha_to_image',@_); }
sub image_copy_alpha_rectangle_to_image { return send_command('image_copy_alpha_rectangle_to_image',@_); }
sub image_draw_polygon { return send_command('image_draw_polygon',@_); }
sub image_fill_polygon { return send_command('image_fill_polygon',@_); }
sub image_flip_horizontal { return send_command('image_flip_horizontal',@_); }
sub image_flip_vertical { return send_command('image_flip_vertical',@_); }
sub image_flip_diagonal { return send_command('image_flip_diagonal',@_); }
sub image_orientate { return send_command('image_orientate',@_); }
sub image_blur { return send_command('image_blur',@_); }
sub image_sharpen { return send_command('image_sharpen',@_); }
sub filter_set { return send_command('filter_set',@_); }
sub filter_set_red { return send_command('filter_set_red',@_); }
sub filter_set_green { return send_command('filter_set_green',@_); }
sub filter_set_blue { return send_command('filter_set_blue',@_); }
sub filter_set_alpha { return send_command('filter_set_alpha',@_); }
sub filter_constants { return send_command('filter_constants',@_); }
sub filter_divisors { return send_command('filter_divisors',@_); }
sub menu_fire { return send_command('menu_fire',@_); }
sub menu_reset_all { return send_command('menu_reset_all',@_); }
sub menu_add_menu { return send_command('menu_add_menu',@_); }
sub menu_add_submenu { return send_command('menu_add_submenu',@_); }
sub menu_add_item { return send_command('menu_add_item',@_); }
sub menu_add_separator { return send_command('menu_add_separator',@_); }
sub menu_end_submenu { return send_command('menu_end_submenu',@_); }
sub events_info { return send_command('events_info',@_); }
sub events_get_echo { return send_command('events_get_echo',@_); }
sub events_get_send_sigusr1 { return send_command('events_get_send_sigusr1',@_); }
sub window_reset { return send_command('window_reset',@_); }
sub window_show { return send_command('window_show',@_); }
sub window_hide { return send_command('window_hide',@_); }
sub window_resize { return send_command('window_resize',@_); }
sub window_get_transparency { return send_command('window_get_transparency',@_); }
sub window_get_background_grab { return send_command('window_get_background_grab',@_); }
sub window_get_background_image { return send_command('window_get_background_image',@_); }
sub window_get_managed_status { return send_command('window_get_managed_status',@_); }
sub window_set_transparency { return send_command('window_set_transparency',@_); }
sub window_set_background_grab { return send_command('window_set_background_grab',@_); }
sub window_set_background_image { return send_command('window_set_background_image',@_); }
sub screen_get_width { return send_command('screen_get_width',@_); }
sub screen_get_height { return send_command('screen_get_height',@_); }
sub screen_get_depth { return send_command('screen_get_depth',@_); }
sub get_charset { return send_command('get_charset',@_); }
sub set_charset { return send_command('set_charset',@_); }
sub charset_status { return send_command('charset_status',@_); }
sub x_status { return send_command('x_status',@_); }
sub quit { return send_command('quit',@_); }
1;
