2011/04/28

Silly random placement rectangle drawer in gtk with cairo

Wow that was a mouthful.  I've been working with cairo/gtk for a design project so I thought it might be fun to do something stupid but fun(at least for me) with it.  Shitty code but meh.


While taking a screen shot I realized that if you drag a window over it clears that section etc.  oopsy   If i have time and if I care I'll look into that. 

Here's the C code randraw.c:
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <cairo.h>

/* compile with
 *      gcc -o randraw randraw.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0 cairo)
 */

//all the data needed
typedef struct {
        int x_len;
        int y_len;
        int num;
        double red;
        double green;
        double blue;
        GtkWidget *drawA1;
        GtkWidget *drawA2;
} data_t;

//global pointer for the data
data_t *gdata;

//function to clear the drawing area
void clear_screen (){
        cairo_t *cr;
        cr = gdk_cairo_create(gdata->drawA1->window);
        cairo_set_source_rgba(cr,0,0,0,1);
        cairo_paint_with_alpha(cr,1);

        cairo_destroy(cr);
}

//displays the preview of the color to be drawn
void preview(){
        cairo_t *cr;
        cr = gdk_cairo_create(gdata->drawA2->window);
        cairo_set_source_rgba(cr,gdata->red,gdata->green,gdata->blue,1);
        //cairo_fill(cr);
        cairo_paint_with_alpha(cr,1);

        cairo_destroy(cr);
}

//for when the draw button is pressed, does all of the drawing, hurp
G_MODULE_EXPORT void draw(GtkWidget *widget, gpointer data){
        cairo_t *cr;
        int i = 0;
        int ranW, ranH;

        cr = gdk_cairo_create(gdata->drawA1->window);

        for (i = 0; i < gdata->num; i++){
                //calc the random points
                do {
                        ranW = rand() % gdata->drawA1->allocation.width;
                } while (ranW + gdata->x_len >= gdata->drawA1->allocation.width);

                do {
                        ranH = rand() % gdata->drawA1->allocation.height;
                } while (ranH + gdata->y_len >= gdata->drawA1->allocation.height);

                //selects the color
                cairo_set_source_rgb(cr,gdata->red,gdata->green,gdata->blue);
                //draws a rectange
                cairo_rectangle(cr, ranW, ranH, gdata->x_len, gdata->y_len);
                //draws the rects it to cr
                cairo_fill(cr);
        }

        cairo_destroy(cr);

}
//updates on the buttons
G_MODULE_EXPORT void y_update(GtkWidget *y_len_i, gpointer data){
        const gchar *string;
        int temp = 0;
        string = gtk_entry_get_text(GTK_ENTRY(y_len_i));
        if(sscanf(string,"%d",&temp) != 0){
                if (temp > 0){
                        gdata->y_len = temp;
                } else
                        fprintf(stderr, "y has to be greater than 0\n");
        } 
}

G_MODULE_EXPORT void x_update(GtkWidget *x_len_i, gpointer data){
        const gchar *string;
        int temp = 0;
        string = gtk_entry_get_text(GTK_ENTRY(x_len_i));
        if(sscanf(string,"%d",&temp) != 0){
                if (temp > 0){
                        gdata->x_len = temp;
                } else
                        fprintf(stderr, "x has to be greater than 0\n");
        }
}

G_MODULE_EXPORT void num_update(GtkWidget *num_i, gpointer data){
        const gchar *string;
        int temp = 0;
        string = gtk_entry_get_text(GTK_ENTRY(num_i));
        if(sscanf(string,"%d",&temp) != 0){
                if (temp > 0) {
                        gdata->num = temp;
                } else
                        fprintf(stderr, "pixel count has to be greater than 0\n");
        }
}

G_MODULE_EXPORT void red_update(GtkWidget *red_i, gpointer data){
        const gchar *string;
        float temp  = 0.0;
        string = gtk_entry_get_text(GTK_ENTRY(red_i));
        if(sscanf(string,"%f",&temp) != 0){
                if ( !(temp < 0.0 || temp > 1.0)) {
                        gdata->red = temp;
                        preview();
                } else
                        fprintf(stderr, "red component has to be >= 0 and <= 1\n");
        }
}

G_MODULE_EXPORT void green_update(GtkWidget *green_i, gpointer data){
        const gchar *string;
        float temp  = 0.0;
        string = gtk_entry_get_text(GTK_ENTRY(green_i));
        if(sscanf(string,"%f",&temp) != 0){
                if ( !(temp < 0.0 || temp > 1.0)) {
                        gdata->green = temp;
                        preview();
                } else
                        fprintf(stderr, "green component has to be >= 0 and <= 1\n");
        }
}

G_MODULE_EXPORT void blue_update(GtkWidget *blue_i, gpointer data){
        const gchar *string;
        float temp  = 0.0;
        string = gtk_entry_get_text(GTK_ENTRY(blue_i));
        if(sscanf(string,"%f",&temp) != 0){
                if ( !(temp < 0.0 || temp > 1.0)) {
                        gdata->blue = temp;
                        preview();
                } else
                        fprintf(stderr, "blue component has to be >= 0 and <= 1\n");
        }
}

//for calling the preview on startup
G_MODULE_EXPORT void init_preview(GtkWidget *widget, gpointer data){
        preview();
}

//for setting the screen color on start up
G_MODULE_EXPORT void clear_scn(GtkWidget *widget, gpointer data){
        //clear_screen();
}

int main(int argc, char **argv){
        GtkBuilder *builder;
        GtkWidget *window;
        GError *error = NULL;
        data_t maindata;
        gdata = &maindata;

        maindata.x_len = 1;
        maindata.y_len = 1;
        maindata.num = 1;
        maindata.red = 1.0;
        maindata.blue = 1.0;
        maindata.green = 1.0;

        /* init gtk+ and strip the gtk arguments */
        gtk_init(&argc, &argv);

        /* creat new gtkbuilder object */
        builder = gtk_builder_new();

        /* load UI from file, if there's an arror it quits */
        if(!gtk_builder_add_from_file(builder, "randraw.glade", &error)){
                g_warning("%s", error->message);
                g_free(error);
                return 1;
        }

        /* gets main window pointer */ 
        window = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
        gdata->drawA1 = GTK_WIDGET(gtk_builder_get_object(builder, "drawingarea1"));
        gdata->drawA2 = GTK_WIDGET(gtk_builder_get_object(builder, "drawingarea2"));
       
        /* connects the signals */
        gtk_builder_connect_signals(builder, NULL);

        /* destorys builder since it isn't needed */
        g_object_unref(G_OBJECT(builder));


        /* for stopping the main gtk when the window gets destroyed */
        g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL);
        g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);

        gtk_widget_set_app_paintable(gdata->drawA1, TRUE);
        gtk_widget_set_app_paintable(gdata->drawA2, TRUE);

        /* shows window */
        gtk_widget_show(window);

        clear_screen();

        /* main loop */
        gtk_main();
       
        return 0;
}
Ugh, I need to find a better way to post code on here.
here's the glade file randraw.glade:
<?xml version="1.0"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkWindow" id="window1">
    <property name="width_request">800</property>
    <property name="height_request">600</property>
    <property name="title" translatable="yes">Larks Randow Rectangle Drawer</property>
    <child>
      <object class="GtkHBox" id="hbox1">
        <property name="visible">True</property>
        <property name="spacing">3</property>
        <child>
          <object class="GtkDrawingArea" id="drawingarea1">
            <property name="width_request">600</property>
            <property name="visible">True</property>
            <signal name="expose_event" handler="clear_screen"/>
          </object>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkTable" id="table1">
            <property name="visible">True</property>
            <property name="n_rows">15</property>
            <property name="n_columns">2</property>
            <child>
              <object class="GtkEntry" id="x_len_i">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">1</property>
                <signal name="changed" handler="x_update"/>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="x_len_l">
                <property name="visible">True</property>
                <property name="label" translatable="yes">x length (int)</property>
              </object>
              <packing>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="y_len_l">
                <property name="visible">True</property>
                <property name="label" translatable="yes">y length (int)</property>
              </object>
              <packing>
                <property name="top_attach">2</property>
                <property name="bottom_attach">3</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkEntry" id="y_len_i">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">1</property>
                <signal name="changed" handler="y_update"/>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">2</property>
                <property name="bottom_attach">3</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="num_l">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Number of
pixels (int)</property>
              </object>
              <packing>
                <property name="top_attach">4</property>
                <property name="bottom_attach">5</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkEntry" id="num_i">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">1</property>
                <signal name="changed" handler="num_update"/>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">4</property>
                <property name="bottom_attach">5</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="red_l">
                <property name="visible">True</property>
                <property name="yalign">0.55000001192092896</property>
                <property name="label" translatable="yes">Red (float)
(0.0 - 1.0)</property>
              </object>
              <packing>
                <property name="top_attach">6</property>
                <property name="bottom_attach">7</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="green_l">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Green (float)
  (0.0 - 1.0)</property>
              </object>
              <packing>
                <property name="top_attach">8</property>
                <property name="bottom_attach">9</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="blue_l">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Blue (float)
(0.0 - 1.0)</property>
              </object>
              <packing>
                <property name="top_attach">10</property>
                <property name="bottom_attach">11</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkEntry" id="red_i">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">1.0</property>
                <signal name="changed" handler="red_update"/>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">6</property>
                <property name="bottom_attach">7</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkEntry" id="green_i">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">1.0</property>
                <signal name="changed" handler="green_update"/>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">8</property>
                <property name="bottom_attach">9</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkEntry" id="blue_i">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="invisible_char">&#x25CF;</property>
                <property name="text" translatable="yes">1.0</property>
                <signal name="changed" handler="blue_update"/>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">10</property>
                <property name="bottom_attach">11</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkTable" id="table2">
                <property name="visible">True</property>
                <property name="n_rows">3</property>
                <property name="n_columns">3</property>
                <property name="column_spacing">20</property>
                <property name="row_spacing">20</property>
                <child>
                  <object class="GtkButton" id="draw_b">
                    <property name="label" translatable="yes">Draw</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <signal name="clicked" handler="draw"/>
                  </object>
                  <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">GTK_FILL</property>
                    <property name="y_options">GTK_FILL</property>
                  </packing>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
              </object>
              <packing>
                <property name="top_attach">14</property>
                <property name="bottom_attach">15</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
            <child>
              <object class="GtkTable" id="table3">
                <property name="visible">True</property>
                <property name="n_rows">3</property>
                <property name="n_columns">3</property>
                <property name="column_spacing">20</property>
                <property name="row_spacing">20</property>
                <child>
                  <object class="GtkButton" id="clear_b">
                    <property name="label" translatable="yes">Clear screen</property>
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="receives_default">True</property>
                    <signal name="clicked" handler="clear_scn"/>
                  </object>
                  <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">GTK_FILL</property>
                    <property name="y_options">GTK_FILL</property>
                  </packing>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">14</property>
                <property name="bottom_attach">15</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="preview_l">
                <property name="visible">True</property>
                <property name="label" translatable="yes">Preview Color</property>
              </object>
              <packing>
                <property name="top_attach">12</property>
                <property name="bottom_attach">13</property>
                <property name="x_options"></property>
              </packing>
            </child>
            <child>
              <object class="GtkTable" id="table4">
                <property name="visible">True</property>
                <property name="n_rows">3</property>
                <property name="n_columns">3</property>
                <child>
                  <object class="GtkDrawingArea" id="drawingarea2">
                    <property name="width_request">75</property>
                    <property name="height_request">50</property>
                    <property name="visible">True</property>
                    <signal name="no_expose_event" handler="init_preview"/>
                    <signal name="expose_event" handler="init_preview"/>
                  </object>
                  <packing>
                    <property name="left_attach">1</property>
                    <property name="right_attach">2</property>
                    <property name="top_attach">1</property>
                    <property name="bottom_attach">3</property>
                    <property name="x_options"></property>
                    <property name="y_options"></property>
                  </packing>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
                <child>
                  <placeholder/>
                </child>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="right_attach">2</property>
                <property name="top_attach">12</property>
                <property name="bottom_attach">13</property>
                <property name="x_options"></property>
                <property name="y_options"></property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">False</property>
            <property name="padding">4</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
Assuming you're not brain damaged I also tarballed them and put them on mediafire here.

2011/04/24

Move to Different X-screens with a Perl Script

I tried writing this in a bash script but for some reason I failed miserably so I wrote it in some I knew.   I have my XFCE WM where it focuses where the mouse is so if you don't have it set up like that, it may not completely work right, I dunno. 

#!/usr/bin/perl
use strict;
use warnings;

my $display = $ENV{'DISPLAY'};
#print "my dispaly is $display\n";
if (!(defined $display)){
        exit 1;
}
elsif ($display eq ":0.1") {
        system("xdotool mousemove --screen 0 640 512");
        #print("Switching to xscreen 0\n");
}
else {
        system("xdotool mousemove --screen 1 920 600");
        #print("Switching to xscreen 1\n");
}

exit 0;
 This can easily be changed to suit your own needs.  You could have one called move right, left etc if you have more than two x-screens.  The "640 512" and "920 600" are the x y cords of the middle of my screen.  See the man page for xdotool for more info.

It's a real quick and dirty script so.  If you make any improvements to it, please let me know!

2011/02/25

irssi Fun

For those who don't know, irssi is an irc client which uses perl5 scripts.  perl for these types of things is your friend.  It makes parsing through text a breeze.  Plus it's fairy C like in nature.  For some good learning references for perl5 see:
http://learn.perl.org/books/beginning-perl/

This is what I did to get started. I read through about the first 8 chapters or so and played with ideas code they listed in there.  There's also some stuff writing irssi scripts.
http://juerd.nl/site.plp/irssiscripttut

Although I mostly just read the scripst on irssi's site:
http://scripts.irssi.org/

Now on to some of the basics of writing a irssi script.  First you need to include some stuff for irssi.  The first part of my bot's script looks like this.

  use strict;
  use vars qw($VERSION %IRSSI);
  use Irssi;   # qw(command_bind signal_add);
  use File::Copy;
  use Encode;
 
  $VERSION = '0.35';
  %IRSSI = (
          authors         =>      'larks',
          contant         =>      'this blog',
          name            =>      'LarksBot',
          description     =>      'LarksBots script',
          license         =>      'I dunno'
  );
You need to have the "use vars qw($VERSION %IRSSI)" and the "use Irssi" in there.  Basically making sure the script can use irssi functions and has the right variables.  Then you have to naturally setting the $VERSION and %IRSSI variables.

Next is tying in the functions to the irssi signals.  There's a list of irssi signals here:
http://irssi.org/documentation/signals

For my bot I used the "message public" signal.  So to use a function/subroutine "event_msg" I used
Irssi::signal_add("message public", "event_mesg");

"Irssi::signal_add" is naturally a function that "use Irssi" provides.  It adds a signal to a function/etc in a script.  If you look at the link above, for the signals, you'll see:

"message public", SERVER_REC, char *msg, char *nick, char *address, char *target

where,
    "message public" is the signal name

    "SERVER_REC" is the server info
    "char *msg" is the message that is received
    "char *nick" is the nick that sent the mesage
    "char *address" is the address of the nick that sent it
    "char * target" is the channel it was sent to.

Everything after the signal name is an input to your function.  To have meaning variables etc something like this can be used.

sub event_mesg {
         my($server, $msg, $nick, $address, $target) = @_;
         #meaningful code here
}
This will extract the data from the input array, @_, and save it to the variables which are much easier to work with that trying to keep up with $_[2] etc.

So now that you have your script includes etc and the signal set up, what do you do with it?  Well let's start with a simple hello world script.


  1 use strict;
  2 use Irssi;
  3 use vars qw($VERSION %IRSSI);
  4
  5 $VERSION = "1.0";
  6 %IRSSI = (
  7     authors => 'larks',
  8     contact => 'larks blog',
  9     name => 'hello world',
 10     description => 'a simple hello world script',
 11     license => 'GPL v2',
 12     url => 'http://larkstongues42.blogspot.com/'
 13 );
 14
 15 sub event_msg {
 16         my($server, $msg, $nick, $address, $target) = @_;
 17         $_ = $msg;
 18         if (/^\.hello\s*$/i) {
 19         $server->command('msg '.$target.' Hello world!');
 20         }
 21         return 0;
 22 }
 23 Irssi::signal_add('message public', 'event_msg');
which will produce

23:25:56 <~`-`> .hello
23:25:56 <~larks> Hello world!
It's often convenient to use $_ so that when checking the messages for something you don't have to use "$msg =~ /somethingofind/" rather than "/somethingtofind". The
$server->command('msg '.$target.' Hello world!');
command is really the
Irssi::Server::command($server,'msg '.$target.' Hello world!');
command. Taken from perl.txt from the irssi documentation:

If there's a "Xxxx::" text before the command, it means that it belongs to
that package. Like "Server::command" means that you should either call it as
  Irssi::Server::command($server, $cmd);
or more easily:
  $server->command($cmd);
 The docs that come with irssi have a wealth of information.  They're in "/usr/share/doc/irssi/" if you use Debian.  There's a ton of useful Irssi commands listed in the documentation which I highly suggest you read over.  With a decent knowledge of perl, reading over some docs and experimenting, you can really get pretty far.  I honestly hadn't done much programming before starting this other that microcontroller stuff which is completely different and I've managed to do some pretty interesting stuff.  Most of it is isn't that hard, it's just specifying what you want, planing out your code, and then writing it.  Another useful trick it so write the code in a plain old perl script and get it working before trying to code it into an irssi script.  This splits up the process into a debugging stage for the actual algorithms(if you can call them that) and interfacing with irssi.  Sometimes this can't be done, but it's pretty useful when you can. 

Well this concludes my very simple bare bones irssi scripting how to.

2011/02/23

Hello World

This is my blog for random technical stuff.  By that I mean linux, coding, EE/CompE stuff and of the likes.  I'll most likely do a entry on irssi bot scripting before too long.  See you around.