/* Printer status information */
/* !Printers application related operations */
/* Created 04.10.2005 T. Milius
   Changed 04.10.2005 T. Milius */
/* (c) Copyright 2005 by Thomas Milius Stade, Germany
   Source must not be altered without agreement of the owner.
   The owner of the source is allowed to use this code inside programs without
   publishing the code of this programs. These programs may be commercial.
   Other developers can use this source freely inside own software if the source
   code of this programs is made public to same conditions like valid to this code
   and no commercial profit is taken from the programs based on this code

   Code or parts of it are not allowed to be used within GPL code or
   similar licenses which are "infecting" other code and trying to "supersede"
   other licenses. */
/* RISC OS */

#ifndef printers_h
#define printers_h

/* !!!!!!!!!! libraries !!!!!!!!!! */
/* ---------- ANSI-C ---------- */

/* ------------ own ------------ */
#include "common.h"
#include "printeractions.h"

/* !!!!!!!!!!! definitions !!!!!!!!!! */
#define PRINTER_ICON_HANDLE_UNKNOWN 0xFFFFFFFF

#define ICONBAR_WINDOW_HANDLE 0xFFFFFFFE

/* !!!!!!!!!! data structures !!!!!!!!!! */
struct task_buffer_struct {
unsigned long task_handle;
char *task_name;
unsigned long used_memory;
unsigned long flags;
};

struct icon_block_struct {
long bbox[4];
unsigned long flags;
/* should be a union, however more details are not needed */
char icon_data[12];
};

struct icon_info_struct {
unsigned long window_handle;
unsigned long icon_handle;
struct icon_block_struct icon_block;
};

struct wimp_message_struct {
unsigned long length;
unsigned long task_handle_sender;
unsigned long my_ref;
unsigned long your_ref;
unsigned long message_action;
/* Should be a union, but not reqired */
unsigned long data[4];
};

struct mouse_click_struct {
long mouse_x;
long mouse_y;
unsigned long buttons;
unsigned long window_handle;
unsigned long icon_handle;
};

/* !!!!!!!!!! support functions !!!!!!!!!! */

/* !!!!!!!!!! functions !!!!!!!!!! */
unsigned long determine_actual_printer(void)
{
int i;
struct icon_info_struct icon_info;
struct wimp_message_struct wimp_message;
_kernel_swi_regs regs;

/* Scan all ICONBAR icons */
/* Note: Wimp_WhichIcon doesn't work properly on RISC OS 4.02 and has odd
         behaviour on RISC OS 5.10. So scan is done by hand. */
i=0;
while (i < 256) {
  /* Check whether selected */
  icon_info.window_handle=ICONBAR_WINDOW_HANDLE;
  icon_info.icon_handle=i;
  regs.r[1]=(int) &icon_info;
  if (!_kernel_swi(Wimp_GetIconState, &regs, &regs)) {
    /* it can be only a selected item */
    if ((icon_info.icon_block.flags & 0x00A00000) == 0x00200000) {
      /* Send Pseudo Message to determine task */
      wimp_message.length=20;
      wimp_message.your_ref=0;
      wimp_message.message_action=0x000400C6;
      wimp_message.data[0]=0x00000000;
      regs.r[0]=19;
      regs.r[1]=(int) &wimp_message;
      regs.r[2]=ICONBAR_WINDOW_HANDLE;
      regs.r[3]=i;
      if (!_kernel_swi(Wimp_SendMessage, &regs, &regs)) {
        if (regs.r[2] == printeractions_common.printers_task_handle) {
          return i;
          }
        }
      }
    }
  i++;
  }
return PRINTER_ICON_HANDLE_UNKNOWN;
}

struct printer_struct *activate_printer(unsigned long icon_handle)
{
char printer_name[40];
char connection_name[MAX_CONNECTION_NAME];
unsigned long min_time;
struct mouse_click_struct mouse_click;
struct printer_struct *new_printer;
struct icon_info_struct icon_info;
_kernel_swi_regs regs;

if (icon_handle == PRINTER_ICON_HANDLE_UNKNOWN) {
  return NULL;
  }
/* Activate by message */
mouse_click.mouse_x=0;
mouse_click.mouse_y=0;
mouse_click.buttons=4;
mouse_click.window_handle=ICONBAR_WINDOW_HANDLE;
mouse_click.icon_handle=icon_handle;
regs.r[0]=6;
regs.r[1]=(int) &mouse_click;
regs.r[2]=ICONBAR_WINDOW_HANDLE;
regs.r[3]=(int) icon_handle;
if (_kernel_swi(Wimp_SendMessage, &regs, &regs)) {
  return NULL;
  }
_kernel_swi(OS_ReadMonotonicTime, &regs, &regs);
/* Limit check loop to 2 seconds in case of error */
min_time=(unsigned long) regs.r[0] + 200;
do {
  /* give !Printers the chance to receive the message */
  my_poll(POLL_SIMPLE);
  /* Check whether selected */
  icon_info.window_handle=ICONBAR_WINDOW_HANDLE;
  icon_info.icon_handle=icon_handle;
  regs.r[1]=(int) &icon_info;
  if (_kernel_swi(Wimp_GetIconState, &regs, &regs)) {
    return NULL;
    }
  _kernel_swi(OS_ReadMonotonicTime, &regs, &regs);
  if (((unsigned long) regs.r[0]) > min_time) {
    return NULL;
    }
  }
while((icon_info.icon_block.flags & 0x00A00000) != 0x00200000);
/* Determine printer name */
/* necassary to detect failures */
regs.r[4]=0;
if (_kernel_swi(PDriver_Info, &regs, &regs)) {
  return NULL;
  }
if (!regs.r[4]) {
  return NULL;
  }
strcpy(printer_name, (char *) regs.r[4]);
/* Determine connection */
if (!getenv("Printer$Path")) {
  return NULL;
  }
strncpy(connection_name, getenv("Printer$Path"), MAX_CONNECTION_NAME-1);
connection_name[MAX_CONNECTION_NAME-1]='\0';
/* Check whether this printer already exists. */
if ((new_printer=printer_find(printer_name)) != NULL) {
  /* If it has the same connection then keep entry */
  if (strcmp(connection_name, new_printer->connection_name) == 0) {
    /* If the connection is faulty this will be handled at another step */
    return new_printer;
    }
  /* Check whether there are connections using this printer. */
/* Existing connections must be dropped for they are invalid. */
/* ??? */
  /* Use printer entry for update */
  }
else {
  /* Setup new printer entry */
  if ((new_printer=add_printer()) == NULL) {
    return NULL;
    }
  strcpy(new_printer->printer_name, printer_name);
  }
/* Any error of the following operation is stored inside printer
   structure and handled on another step. */
if (!determine_printer_connection(new_printer,
                                  connection_name)) {
  if (printeractions_common.printers_scan_flag &&
      (new_printer->connection_type == CONNECTION_ACCESS)) {
    /* Ignore shared printers at this step. Recursion is logically
       not possible. */
    drop_printer(new_printer);
    return NULL;
    }
  }
return new_printer;
}

bool scan_printers(void)
{
unsigned long actual_printers_printer;
int i;
struct icon_info_struct icon_info;
struct wimp_message_struct wimp_message;
_kernel_swi_regs regs;

printeractions_common.printers_scan_flag=true;
actual_printers_printer=determine_actual_printer();
/* Scan all ICONBAR icons */
/* Note: Wimp_WhichIcon doesn't work properly on RISC OS 4.02 and has odd
         behaviour on RISC OS 5.10. So scan is done by hand. */
for (i=0; i < 256; i++) {
  /* Check whether selected */
  icon_info.window_handle=ICONBAR_WINDOW_HANDLE;
  icon_info.icon_handle=i;
  regs.r[1]=(int) &icon_info;
  if (!_kernel_swi(Wimp_GetIconState, &regs, &regs)) {
    /* it can be only a selectable item */
    if ((icon_info.icon_block.flags & 0x00C00000) == 0x00000000) {
      /* Send Pseudo Message to determine task */
      wimp_message.length=20;
      wimp_message.your_ref=0;
      wimp_message.message_action=0x000400C6;
      wimp_message.data[0]=0x00000000;
      regs.r[0]=19;
      regs.r[1]=(int) &wimp_message;
      regs.r[2]=ICONBAR_WINDOW_HANDLE;
      regs.r[3]=i;
      if (!_kernel_swi(Wimp_SendMessage, &regs, &regs)) {
        if (regs.r[2] == printeractions_common.printers_task_handle) {
          activate_printer(i);
          }
        }
      }
    }
  i++;
  }
/* reactivate old printer */
activate_printer(actual_printers_printer);
printeractions_common.printers_scan_flag=false;
return true;
}

bool determine_printers_handle(void)
{
struct task_buffer_struct task_buffer;
_kernel_swi_regs regs;

regs.r[0]=0;
while (regs.r[0] >= 0) {
  regs.r[1]=(int) &task_buffer;
  regs.r[2]=sizeof(struct task_buffer_struct);
  if (_kernel_swi(TaskManager_EnumerateTasks, &regs, &regs)) {
    return false;
    }
  if (strcmp(task_buffer.task_name, "Printer Manager") == 0) {
    printeractions_common.printers_task_handle=task_buffer.task_handle;
    return true;
    }
  }
return false;
}

#endif
