Subversion Repositories Filer-Free

Rev

Rev 58 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

// This file is part of the free Filer module for RISC OS.
// Copyright © 2007 Graham Shaw.
// Redistribution and modification are permitted under the terms of the
// GNU General Public License (version 2 or any later version).

#include <setjmp.h>
#include <signal.h>
#include <kernel.h>

#include "oslib/os.h"

#include "window.h"
#include "menu.h"
#include "application.h"

/** The recovery routine for handling a RISC OS error. */
static jmp_buf jmp_oserror;

/** Handle a RISC OS error signal.
 * This function is the signal handler for a RISC OS error.  It performs
 * a long jump to the recovery routine that should previously have been
 * specified in jmp_oserror.
 *
 * Note that performing a long jump out of a signal handler is not fully
 * portable, but it is acceptable in this context.
 */

static void handle_oserror(int)
{
        longjmp(jmp_oserror,1);
};

application::application(const char* appname,wimp_message_list* messages):
        _appname(appname),
        _handle(0),
        _quit(false),
        _current_menu(0),
        _current_drag(0)
{
        _handle=wimp_initialise(310,appname,messages,0);
}

application::~application()
{}

void application::run(int* pollword)
{
        // Set signal handler for RISC OS errors.
        // (Note that jmp_oserror has not been initialised yet, so it is
        // important that no RISC OS errors occur between this point and
        // when it is initialised.)
        signal(SIGOSERROR,&handle_oserror);

        // Main polling loop: repeat until quit flag is set to true.
        while (!_quit)
        {
                // Establish signal handler for RISC OS errors.
                if (setjmp(jmp_oserror)==0)
                {
                        // Poll the window manager.
                        static wimp_block block;
                        wimp_poll_flags flags=poll_flags();
                        if (pollword) flags|=wimp_GIVEN_POLLWORD;
                        wimp_event_no event=wimp_poll(flags,&block,pollword);

                        // Handle the resulting event.
                        handle_event(event,block);
                }
                else
                {
                        // Recovery from a RISC OS error: display error window.
                        wimp_report_error((os_error*)_kernel_last_oserror(),
                                wimp_ERROR_BOX_OK_ICON,_appname);

                        // Reestablish signal handler.
                        signal(SIGOSERROR,&handle_oserror);
                }
        }
}

window* application::find_window(wimp_w handle)
{
        return _windows.find(handle);
}

wimp_poll_flags application::poll_flags()
{
        return 0;
}

void application::handle_event(wimp_event_no event,wimp_block& block)
{
        menu* m;
        window* w;
        switch (event)
        {
        case wimp_REDRAW_WINDOW_REQUEST:
                if (w=_windows.find(((wimp_draw&)block).w))
                {
                        w->handle_redraw_request((wimp_draw&)block);
                }
        break;
        case wimp_OPEN_WINDOW_REQUEST:
                if (w=_windows.find(block.open.w))
                {
                        w->handle_open_request(block.open);
                }
                break;
        case wimp_CLOSE_WINDOW_REQUEST:
                if (w=_windows.find(block.close.w))
                {
                        w->handle_close_request(block.close);
                }
                break;
        case wimp_MOUSE_CLICK:
                if (block.pointer.w==wimp_ICON_BAR)
                {
                        handle_mouse_click(block.pointer);
                }
                else if (w=_windows.find(block.pointer.w))
                {
                        w->handle_mouse_click(block.pointer);
                }
                break;
        case wimp_USER_DRAG_BOX:
                if (w=_current_drag)
                {
                        _current_drag=0;
                        w->handle_user_drag_box(block.dragged);
                }
                break;
        case wimp_KEY_PRESSED:
                if (w=_windows.find(block.key.w))
                {
                        w->handle_key_pressed(block.key);
                }
                else
                {
                        handle_key_pressed(block.key);
                }
                break;
        case wimp_MENU_SELECTION:
                if (m=_current_menu)
                {
                        _current_menu=0;
                        m->handle_menu_selection(block.selection);
                }
                break;
        case wimp_USER_MESSAGE:
        case wimp_USER_MESSAGE_RECORDED:
                switch (block.message.action)
                {
                case message_QUIT:
                        _quit=true;
                        break;
                case message_DATA_SAVE:
                case message_DATA_SAVE_ACK:
                case message_DATA_LOAD:
                case message_DATA_LOAD_ACK:
                        if (w=_windows.find(block.message.data.data_xfer.w))
                        {
                                w->handle_data_xfer(block.message);
                        }
                        break;
                case message_MENUS_DELETED:
                        if (m=_current_menu)
                        {
                                _current_menu=0;
                                m->handle_menus_deleted();
                        }
                        break;
                default:
                        handle_user_message(event,block.message);
                        break;
                }
                break;
        }
}

void application::handle_mouse_click(wimp_pointer& block)
{}

void application::handle_key_pressed(wimp_key& block)
{
        wimp_process_key(block.c);
}

void application::handle_user_message(wimp_event_no event,
        wimp_message& message)
{}

void application::register_window(window& w)
{
        _windows.insert(w);
}

void application::deregister_window(window& w)
{
        _windows.erase(w);
}

void application::register_menu(menu& m)
{
        _current_menu=&m;
}

void application::register_drag(window& w)
{
        _current_drag=&w;
}