ROVLib Tutorial - Memory (1)

© Jason Tribbeck 2002

Memory (1)

In this tutorial, we will be loading a dropped DrawFile, changing the canvas' size to fit, allocating memory and displaying the DrawFile.

The source code

/**
 * Memory.c - Memory allocation
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

#include "kernel.h"

#include "main.h"
#include "canvas.h"
#include "menu.h"
#include "baricon.h"
#include "extras.h"
#include "draw.h"
#include "drawrender.h"
#include "file.h"

void click(int icn);
void choose(menu m, int item);
void menu_click(canvas c);
void redraw(canvas c, int x0, int y0, int x1, int y1);
void load(canvas c, char *filename, int type, int size);

static canvas c;
static menu iconm;

static void *drawfile = NULL;
static int drawfile_size = 0;

int main(int argc, char **argv) {
  canvas c_proginfo;

  main_init("My Application");
  canvas_init();
  menu_init();

  c = canvas_create(640, 480, "My Application");
  canvas_setfullsize(c, 0, 0, 1024, 768);
  canvas_addhandler(c, CANVAS_REDRAWHANDLER, redraw);
  canvas_addhandler(c, CANVAS_LOADHANDLER, load);
  canvas_colour(c, 0);
  canvas_make(c);

  baricon("file_ff8", click);

  canvas_addhandler(CANVAS_ICONBAR, CANVAS_MENUHANDLER, menu_click);
  canvas_addhandler(CANVAS_ICONBAR, CANVAS_LOADHANDLER, load);

  c_proginfo = create_infobox("My Application", "An example ROVLib application",
                              "© Jason Tribbeck", "1.00 (14 Feb 2002)");

  iconm = menu_create("Menu test", 2, choose, NULL);
  menu_add(iconm, "Info");
  menu_add(iconm, "Quit");

  menu_attachpane(iconm, 0, c_proginfo);

  canvas_opencentre(c);

  main_poll();
}

void click(int icn) {
  canvas_reopen(c);
}

void menu_click(canvas c) {
  menu_displayiconbar(iconm);
}

void choose(menu m, int item) {
  switch(item) {
    case 1 :
      exit(0);
      break;
  }
}

void redraw(canvas c, int x0, int y0, int x1, int y1) {
  if(drawfile != NULL) {
    drawrender_render(drawfile, drawfile_size, 0, 0, x0, y0, x1, y1, 1.0, 1.0);
  }
}

void load(canvas c, char *filename, int type, int size) {
  if(type == 0xaff) {
    /* If memory's already been allocated (for a previous one), free it */
    if(drawfile != NULL) {
      rfree(drawfile);
    }

    /* Get the real size */
    size = file_size(filename);

    /* Allocate memory for it */
    drawfile = rmalloc(size);

    /* Check to see if memory was actually allocated for it */
    if(drawfile != NULL) {
      drawfile_size = size;
      file_load(filename, drawfile);
      canvas_setfullsize(c, 0, 0, drawrender_xsize(drawfile, 1.0), drawrender_ysize(drawfile, 1.0));
    } else {
      swerr(FALSE, "Not enough memory to load '%s'", filename);
    }
    canvas_forceredraw(c);
  } else {
    swerr(FALSE, "I cannot load '%s' as it is not a DrawFile", filename);
  }
}

Here, we have made three major changes:

  1. Added scroll bars to the canvas by setting a size larger than the initially allocated size
  2. Modified the redraw event handler to render the DrawFile on the canvas.
  3. Extended the load event handler to allocate memory for the DrawFile, resize the canvas and then redraw tha canvas.

The first canvas_setfullsize is a shorthand way of adding scroll bars to the canvas - ROVLib knows that the canvas has not been made into a window yet, and sets the scroll bar flags. It also sets the extent of the canvas from (0,0) to (1024, 768), but keeps the canvas' physical size to 640x480 as initially created.

The load event handler also checks to see if the memory was actually allocated, and issues a warning if not. The canvas is redrawn anyway, as the old DrawFile has been erased from memory.

rfree? rmalloc?

If you look closely at the memory allocation, you will see that it calls a function called "rmalloc". This is ROVLib's version of malloc, and performs exactly the same operation - except that if you rfree a chunk of memory, ROVLib will try to return memory back to the WIMP.

ROVLib has the equivalent of malloc, calloc and free, but not realloc (rcalloc also does not clear memory).

For this example, using rmalloc is fine, but there is a better solution - which is the subject of the next tutorial!

Running the application.

If you drop a DrawFile onto the window or icon, then it will be loaded, with the canvas' size being set to the size of the DrawFile. As an example:

Note that some applications (notably ArtWorks) do not give the DrawFile correct bounding boxes, and you will have display problems with these. To fix them, load them into !Draw, select everything (Ctrl-A), move it a small amount and then save it.

Epilogue

You have seen the following:

That's rather a lot in one tutorial, but the program is getting more and more useful!