summaryrefslogtreecommitdiff
path: root/frontends/atari/gemtk
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/atari/gemtk')
-rw-r--r--frontends/atari/gemtk/aestabs.c191
-rw-r--r--frontends/atari/gemtk/aestabs.h56
-rwxr-xr-xfrontends/atari/gemtk/dragdrop.c515
-rwxr-xr-xfrontends/atari/gemtk/dragdrop.h4
-rw-r--r--frontends/atari/gemtk/gemtk.h298
-rw-r--r--frontends/atari/gemtk/guiwin.c1430
-rw-r--r--frontends/atari/gemtk/guiwin.h4
-rw-r--r--frontends/atari/gemtk/msgbox.c110
-rw-r--r--frontends/atari/gemtk/msgbox.h5
-rw-r--r--frontends/atari/gemtk/objc.c522
-rw-r--r--frontends/atari/gemtk/objc.h7
-rw-r--r--frontends/atari/gemtk/redrawslots.c123
-rw-r--r--frontends/atari/gemtk/redrawslots.h25
-rw-r--r--frontends/atari/gemtk/utils.c144
-rw-r--r--frontends/atari/gemtk/utils.h5
-rw-r--r--frontends/atari/gemtk/vaproto.c170
-rw-r--r--frontends/atari/gemtk/vaproto.h121
17 files changed, 3730 insertions, 0 deletions
diff --git a/frontends/atari/gemtk/aestabs.c b/frontends/atari/gemtk/aestabs.c
new file mode 100644
index 000000000..519676514
--- /dev/null
+++ b/frontends/atari/gemtk/aestabs.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2013 Ole Loots <ole@monochrom.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <gem.h>
+#include <cflib.h>
+#include "aestabs.h"
+
+#ifndef NDEBUG
+# define DEBUG_PRINT(x) printf x
+#else
+# define DEBUG_PRINT(x)
+#endif
+
+
+AES_TABLIST * tablist_declare(OBJECT *tree, aes_tablist_user_func user_func)
+{
+ AES_TABLIST * newlist = malloc(sizeof(AES_TABLIST));
+
+ newlist->first = NULL;
+ newlist->tree = tree;
+ newlist->user_func = user_func;
+ DEBUG_PRINT(("aes_tablist_declare: %p\n", newlist));
+ return(newlist);
+}
+
+
+AES_TAB * tablist_add(AES_TABLIST * tablist, short obj_tab, OBJECT * page_tree,
+ short obj_page)
+{
+ AES_TAB * newtab = malloc(sizeof(AES_TAB));
+
+ assert(newtab);
+ assert(tablist);
+
+ newtab->next = NULL;
+ newtab->prev = NULL;
+ newtab->obj_tab = obj_tab;
+ newtab->obj_page = obj_page;
+ newtab->page_tree = page_tree;
+
+ if(newtab->page_tree == NULL){
+ newtab->page_tree = tablist->tree;
+ }
+
+ if (tablist->first == NULL) {
+ tablist->first = newtab;
+ set_state(tablist->tree, newtab->obj_tab, OS_SELECTED, 0);
+ } else {
+ AES_TAB *tmp = tablist->first;
+ while( tmp->next != NULL ) {
+ tmp = tmp->next;
+ }
+ tmp->next = newtab;
+ newtab->prev = tmp;
+ newtab->next = NULL;
+ set_state(tablist->tree, newtab->obj_tab, OS_SELECTED, 0);
+ }
+
+ // TODO: Set the visible flag on that register?
+
+ DEBUG_PRINT(("tablist_add: Tab=%p\n", newtab));
+
+ return(newtab);
+}
+
+
+short tablist_activate(AES_TABLIST * tablist, short tab, short options)
+{
+ AES_TAB *tmp, *activated=NULL, *deactivated=NULL;
+ struct aes_tab_s *active;
+ short activated_pg = -1;
+ short is_tab = 0;
+
+ assert(tablist);
+ assert(tablist->first);
+
+ active = tablist_get_active(tablist);
+
+ if (active != NULL) {
+ if ((options & AES_TABLIST_OPTION_FORCE_EVENTS) == 0) {
+ if(active->obj_tab == tab)
+ return(0);
+ }
+ }
+
+ tmp = tablist->first;
+ while (tmp != NULL) {
+ if(tmp->obj_tab == tab) {
+ is_tab = 1;
+ }
+ tmp = tmp->next;
+ }
+
+ if(is_tab == 0) {
+ return(0);
+ }
+
+ tmp = tablist->first;
+ while ( tmp != NULL ) {
+ if(tab != tmp->obj_tab) {
+ if (get_state(tablist->tree, tmp->obj_tab, OS_SELECTED) != 0) {
+ deactivated = tmp;
+ set_state(tablist->tree, tmp->obj_tab, OS_SELECTED, 0);
+ }
+ // the tab registers can share the same page, consider that:
+ if (tablist->tree == tmp->page_tree
+ && activated_pg != tmp->obj_page) {
+
+ set_flag(tablist->tree, tmp->obj_page, OF_HIDETREE, 1);
+ }
+ } else {
+ activated = tmp;
+ // this tab must the selected / visible
+ set_state(tablist->tree, tmp->obj_tab, OS_SELECTED, 1);
+ if(tablist->tree == tmp->page_tree)
+ set_flag(tablist->tree, tmp->obj_page, OF_HIDETREE, 0);
+ activated_pg = tmp->obj_page;
+ }
+ tmp = tmp->next;
+ }
+
+ if(tablist->user_func != NULL) {
+ AES_TABLIST_FUNC_ARGS args;
+ if(deactivated){
+ args.event = AES_TABLIST_TAB_DEACTIVATED;
+ args.tab = deactivated;
+ tablist->user_func(tablist, &args);
+ }
+ if(activated){
+ args.event = AES_TABLIST_TAB_ACTIVATED;
+ args.tab = activated;
+ tablist->user_func(tablist, &args);
+ }
+ }
+ return(1);
+}
+
+struct aes_tab_s *tablist_get_active(AES_TABLIST * tablist)
+{
+ AES_TAB *tmp = tablist->first;
+ while( tmp != NULL ) {
+ if(get_state(tablist->tree, tmp->obj_tab, OS_SELECTED) != 0) {
+ // that's the one
+ return(tmp);
+ }
+ tmp = tmp->next;
+ }
+ return(NULL);
+}
+
+AES_TAB * tablist_find(AES_TABLIST * tablist, OBJECT * page, short tab)
+{
+ AES_TAB *tmp = tablist->first;
+ while( tmp != NULL ) {
+ if((tmp->page_tree == page) && (tab == tmp->obj_tab)) {
+ return(tmp);
+ }
+ tmp = tmp->next;
+ }
+ return(NULL);
+}
+
+void tablist_delete(AES_TABLIST *tablist)
+{
+ AES_TAB *tmp = tablist->first, *cur;
+ while ( tmp != NULL ) {
+ cur = tmp;
+ tmp = tmp->next;
+ DEBUG_PRINT(("tablist_delete, Freeing tab: %p\n", cur));
+ free(cur);
+ }
+ DEBUG_PRINT(("tablist_delete, Freeing list: %p\n", tablist));
+ free(tablist);
+}
diff --git a/frontends/atari/gemtk/aestabs.h b/frontends/atari/gemtk/aestabs.h
new file mode 100644
index 000000000..c72054acc
--- /dev/null
+++ b/frontends/atari/gemtk/aestabs.h
@@ -0,0 +1,56 @@
+#ifndef AESTABS_H_INCLUDED
+#define AESTABS_H_INCLUDED
+
+struct aes_tab_s;
+struct aes_tablist_s;
+typedef struct aes_tab_s AES_TAB;
+typedef struct aes_tablist_s AES_TABLIST;
+
+#define AES_TABLIST_TAB_ACTIVATED 0x01
+#define AES_TABLIST_TAB_DEACTIVATED 0x02
+
+#define AES_TABLIST_OPTION_FORCE_EVENTS 0x01 // do not eat events which do
+ // not changed the internal state
+ // this is required for tabs which
+ // require "activate" events
+ // for tabs which are already
+ // selected.
+
+
+struct aes_tablist_user_args_s
+{
+ short event;
+ AES_TAB *tab;
+};
+
+typedef struct aes_tablist_user_args_s AES_TABLIST_FUNC_ARGS;
+
+typedef void (*aes_tablist_user_func)(AES_TABLIST * list,
+ AES_TABLIST_FUNC_ARGS * args);
+
+struct aes_tab_s {
+ short obj_tab;
+ short obj_page;
+ OBJECT * page_tree;
+ AES_TAB * next, *prev;
+};
+
+struct aes_tablist_s {
+ OBJECT *tree;
+ AES_TAB * first;
+ aes_tablist_user_func user_func;
+};
+
+
+
+AES_TABLIST * tablist_declare(OBJECT *tree, aes_tablist_user_func user_func);
+void tablist_delete(AES_TABLIST * tablist);
+AES_TAB * tablist_add(AES_TABLIST * tablist, short tab, OBJECT *page_tree,
+ short page);
+short tablist_activate(AES_TABLIST * tablist, short tab, short option);
+struct aes_tab_s *tablist_get_active(AES_TABLIST * tablist);
+AES_TAB * tablist_find(AES_TABLIST * tablist, OBJECT *page, short tab);
+
+#define AES_TAB_IS_ACTIVE(l, x) (tablist_get_active(l) == x)
+
+#endif // AESTABS_H_INCLUDED
diff --git a/frontends/atari/gemtk/dragdrop.c b/frontends/atari/gemtk/dragdrop.c
new file mode 100755
index 000000000..a4b7b82a3
--- /dev/null
+++ b/frontends/atari/gemtk/dragdrop.c
@@ -0,0 +1,515 @@
+/*
+* Routine pour Drag and drop sous MultiTos
+* source: D&D Atari, demo OEP (Alexander Lorenz)
+*
+* Struktur OEP (oep.apid): AES-ID der Applikation
+*
+* (Tab = 4)
+*/
+
+#ifdef __PUREC__
+#include <tos.h>
+#else
+#include <osbind.h>
+#include <mintbind.h>
+#include <signal.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "gemtk.h"
+#include "cflib.h"
+
+#ifndef EACCDN
+#define EACCDN (-36)
+#endif
+
+#ifndef FA_HIDDEN
+#define FA_HIDDEN 0x02
+#endif
+
+static char pipename[] = "U:\\PIPE\\DRAGDROP.AA";
+static long pipesig;
+
+/*
+* Routinen fr den Sender
+*/
+
+/*
+* Erzeugt Pipe fr D&D
+*
+* Eingabeparameter:
+* pipe - Pointer auf 2 Byte Buffer fr Pipeextension
+*
+* Ausgabeparameters:
+* keine
+*
+* Returnwert:
+* >0: Filehandle der Pipe
+* -1: Fehler beim Erzeugen der Pipe
+*/
+
+short gemtk_dd_create(short *pipe)
+{
+ long fd = -1;
+
+ pipename[17] = 'A';
+ pipename[18] = 'A' - 1;
+
+ do /* ouvre un pipe inoccup‚ */
+ {
+ pipename[18]++;
+ if (pipename[18] > 'Z')
+ {
+ pipename[17]++;
+ if (pipename[17] > 'Z')
+ break;
+ else
+ pipename[18] = 'A';
+ }
+
+ /* FA_HIDDEN fr Pipe notwendig! */
+
+ fd = Fcreate(pipename, FA_HIDDEN);
+
+ } while (fd == (long) EACCDN);
+
+ if (fd < 0L)
+ return(-1);
+
+ *pipe = (pipename[17] << 8) | pipename[18];
+
+
+ /* Signalhandler konfigurieren */
+
+ gemtk_dd_getsig(&pipesig);
+
+
+ return((short) fd);
+}
+
+
+
+/*
+* Sendet AP_DRAGDROP an Empf„ngerapplikation
+*
+* Eingabeparameter:
+* apid - AES-ID der Emf„ngerapp.
+* fd - Filehandle der D&D-Pipe
+* winid - Handle des Zielfensters (0 fr Desktopfenster)
+* mx/my - Maus X und Y Koord.
+* (-1/-1 fr einen fake Drag&Drop)
+* kstate - Sondertastenstatus
+* pipename - Extension der D&D-Pipe
+*
+* Ausgabeparameter:
+* keine
+*
+* Returnwert:
+* >0: kein Fehler
+* -1: Empf„ngerapp. gibt DD_NAK zurck
+* -2: Empf„ngerapp. antwortet nicht (Timeout)
+* -3: Fehler bei appl_write()
+*/
+
+short gemtk_dd_message(short apid, short fd, short winid, short mx, short my, short kstate, short pipeid)
+{
+ char c;
+ short i, msg[8];
+ long fd_mask;
+
+
+ /* AES-Message define and post */
+
+ msg[0] = AP_DRAGDROP;
+ msg[1] = _AESapid;
+ msg[2] = 0;
+ msg[3] = winid;
+ msg[4] = mx;
+ msg[5] = my;
+ msg[6] = kstate;
+ msg[7] = pipeid;
+
+ i = appl_write(apid, 16, msg);
+
+ if (i == 0)
+ {
+ gemtk_dd_close(fd);
+ return(-3);
+ }
+
+
+ /* receiver reaction */
+
+ fd_mask = (1L << fd);
+ i = Fselect(DD_TIMEOUT, &fd_mask, 0L, 0L);
+ if (!i || !fd_mask)
+ {
+ /* Timeout eingetreten */
+
+ gemtk_dd_close(fd);
+ return(-2);
+ }
+
+
+ /* le recepteur refuse (lecture du pipe) */
+
+ if (Fread(fd, 1L, &c) != 1L)
+ {
+ gemtk_dd_close(fd);
+ return(-1);
+ }
+
+ if (c != DD_OK)
+ {
+ gemtk_dd_close(fd);
+ return(-1);
+ }
+
+ return(1);
+}
+
+
+
+/*
+* Liest die 8 "bevorzugten" Extensionen der Empf„ngerapplikation
+*
+* Eingabeparameter:
+* fd - Filehandle der D&D-Pipe
+*
+* Ausgabeparameters:
+* exts - 32 Bytebuffer fr die 8 bevorzugten Extensionen
+* der Zielapp.
+*
+* Returnwert:
+* >0: kein Fehler
+* -1: Fehler beim Lesen aus der Pipe
+*/
+
+short gemtk_dd_rexts(short fd, char *exts)
+{
+ if (Fread(fd, DD_EXTSIZE, exts) != DD_EXTSIZE)
+ {
+ gemtk_dd_close(fd);
+ return(-1);
+ }
+
+ return(1);
+}
+
+
+
+/*
+* Testet, ob der Empf„nger einen Datentyp akzeptiert
+*
+* Eingabeparameter:
+* fd - Filehandle (von gemtk_dd_create())
+* ext - Zeiger auf Datentyp (4 Bytes zB. "ARGS")
+* text - Zeiger auf Datenbeschreibung (optional, zB. "DESKTOP args")
+* name - Zeiger auf Datendateiname (optional, zB. "SAMPLE.TXT")
+* size - Anzahl Bytes der zu sendenden Daten
+*
+* Ausgabeparameter:
+* keine
+*
+* Returnwert:
+* DD_OK - Empf„nger akzeptiert Datentyp
+* DD_NAK - Empf„nger brach Drag&Drop ab
+* DD_EXT - Empf„nger lehnt Datentyp ab
+* DD_LEN - Empf„nger kann Datenmenge nicht verarbeiten
+* DD_TRASH - Drop erfolgte auf Mlleimer
+* DD_PRINTER - Drop erfolgte auf Drucker
+* DD_CLIPBOARD - Drop erfolgte auf Clipboard
+*/
+
+short gemtk_dd_stry(short fd, char *ext, char *text, char *name, long size)
+{
+ char c;
+ short hdrlen, i;
+
+ /* 4 Bytes fr "ext", 4 Bytes fr "size",
+ 2 Bytes fr Stringendnullen */
+
+ hdrlen = (short) (4 + 4 + strlen(text)+1 + strlen(name)+1);
+
+
+ /* Header senden */
+
+ if (Fwrite(fd, 2L, &hdrlen) != 2L)
+ return(DD_NAK);
+
+ i = (short) Fwrite(fd, 4L, ext);
+ i += (short) Fwrite(fd, 4L, &size);
+ i += (short) Fwrite(fd, strlen(text)+1, text);
+ i += (short) Fwrite(fd, strlen(name)+1, name);
+
+ if (i != hdrlen)
+ return(DD_NAK);
+
+
+ /* auf die Antwort warten */
+
+ if (Fread(fd, 1L, &c) != 1L)
+ return(DD_NAK);
+
+ return(c);
+}
+
+
+
+/* Routinen fr Sender und Empf„nger */
+
+/*
+* Pipe schliežen (Drag&Drop beenden/abbrechen)
+*/
+
+void gemtk_dd_close(short fd)
+{
+ /* Signalhandler restaurieren */
+
+ gemtk_dd_setsig(pipesig);
+
+
+ Fclose(fd);
+}
+
+
+/*
+* Signalhandler fr D&D konfigurieren
+*
+* Eingabeparameter:
+* oldsig - Zeiger auf 4 Byte Puffer fr alten Handlerwert
+*
+* Ausgabeparameter:
+* keine
+*
+* Returnwerte:
+* keine
+*/
+
+void gemtk_dd_getsig(long *oldsig)
+{
+ *oldsig = (long) Psignal(SIGPIPE, (void *) SIG_IGN);
+}
+
+
+/*
+* Signalhandler nach D&D restaurieren
+*
+* Eingabeparameter:
+* oldsig - Alter Handlerwert (von gemtk_dd_getsig)
+*
+* Ausgabeparameter:
+* keine
+*
+* Returnwerte:
+* keine
+*/
+
+void gemtk_dd_setsig(long oldsig)
+{
+ if (oldsig != -32L)
+ Psignal(SIGPIPE, (void *) oldsig);
+}
+
+
+
+/* Routinen fr Empf„nger */
+
+/*
+* Drag&Drop Pipe ”ffnen
+*
+* Eingabeparameter:
+* ddnam - Extension der Pipe (letztes short von AP_DRAGDROP)
+* ddmsg - DD_OK oder DD_NAK
+*
+* Ausgabeparameter:
+* keine
+*
+* Returnwerte:
+* >0 - Filehandle der Drag&Drop pipe
+* -1 - Drag&Drop abgebrochen
+*/
+
+short gemtk_dd_open(short ddnam, char ddmsg)
+{
+ long fd;
+
+ pipename[17] = (ddnam & 0xff00) >> 8;
+ pipename[18] = ddnam & 0x00ff;
+
+ fd = Fopen(pipename, 2);
+
+ if (fd < 0L)
+ return(-1);
+
+
+ /* Signalhandler konfigurieren */
+
+ gemtk_dd_getsig(&pipesig);
+
+
+ if (Fwrite((short) fd, 1L, &ddmsg) != 1L)
+ {
+ gemtk_dd_close((short) fd);
+ return(-1);
+ }
+
+ return((short) fd);
+}
+
+
+
+/*
+* Schreibt die 8 "bevorzugten" Extensionen der Applikation
+*
+* Eingabeparameter:
+* fd - Filehandle der D&D-Pipe
+* exts - Liste aus acht 4 Byte Extensionen die verstanden
+* werden. Diese Liste sollte nach bevorzugten Datentypen
+* sortiert sein. Sollten weniger als DD_NUMEXTS
+* Extensionen untersttzt werden, muž die Liste mit
+* Nullen (0) aufgefllt werden!
+*
+* Ausgabeparameter:
+* keine
+*
+* Returnwert:
+* >0: kein Fehler
+* -1: Fehler beim Schreiben in die Pipe
+*/
+
+short gemtk_dd_sexts(short fd, char *exts)
+{
+ if (Fwrite(fd, DD_EXTSIZE, exts) != DD_EXTSIZE)
+ {
+ gemtk_dd_close(fd);
+ return(-1);
+ }
+
+ return(1);
+}
+
+
+
+/*
+* N„chsten Header vom Sender holen
+*
+* Eingabeparameter:
+* fd - Filehandle der Pipe (von gemtk_dd_open())
+*
+* Ausgabeparameters:
+* name - Zeiger auf Buffer fr Datenbeschreibung (min. DD_NAMEMAX!)
+* file - Zeiger auf Buffer fr Datendateiname (min. DD_NAMEMAX!)
+* whichext- Zeiger auf Buffer fr Extension (4 Bytes)
+* size - Zeiger auf Buffer fr Datengr”že (4 Bytes)
+*
+* Returnwert:
+* >0: kein Fehler
+* -1: Sender brach Drag&Drop ab
+*
+* On lit dans le pipe qui normalement est constitu‚ de:
+* 1 short: taille du header
+* 4 CHAR: type de donn‚e (extension)
+* 1 long: taille des donn‚es
+* STRING: description des donn‚es
+* STRING: nom du fichiers
+* soit au minimun 11 octets (cas ou les string sont r‚duites … \0)
+* les string sont limit‚ a 128 octets
+*/
+
+short gemtk_dd_rtry(short fd, char *name, char *file, char *whichext, long *size)
+{
+ char buf[DD_NAMEMAX * 2];
+ short hdrlen, i, len;
+
+ if (Fread(fd, 2L, &hdrlen) != 2L)
+ return(-1);
+
+
+ if (hdrlen < 9) /* il reste au minimum 11 - 2 = 9 octets a lire */
+ {
+ /* sollte eigentlich nie passieren */
+
+ return(-1); /* erreur taille incorrecte */
+ }
+
+ if (Fread(fd, 4L, whichext) != 4L) /* lecture de l'extension */
+ return(-1);
+
+ if (Fread(fd, 4L, size) != 4L) /* lecture de la longueurs des donn‚es */
+ return(-1);
+
+ hdrlen -= 8; /* on a lu 8 octets */
+
+ if (hdrlen > DD_NAMEMAX*2)
+ i = DD_NAMEMAX*2;
+ else
+ i = hdrlen;
+
+ len = i;
+
+ if (Fread(fd, (long) i, buf) != (long) i)
+ return(-1);
+
+ hdrlen -= i;
+
+ strncpy(name, buf, DD_NAMEMAX);
+
+ i = (short) strlen(name) + 1;
+
+ if (len - i > 0)
+ strncpy(file, buf + i, DD_NAMEMAX);
+ else
+ file[0] = '\0';
+
+
+ /* weitere Bytes im Header in den Mll */
+
+ while (hdrlen > DD_NAMEMAX*2)
+ {
+ if (Fread(fd, DD_NAMEMAX*2, buf) != DD_NAMEMAX*2)
+ return(-1);
+
+ hdrlen -= DD_NAMEMAX*2;
+ }
+
+ if (hdrlen > 0)
+ {
+ if (Fread(fd, (long) hdrlen, buf) != (long) hdrlen)
+ return(-1);
+ }
+
+ return(1);
+}
+
+
+
+/*
+* Sendet der Senderapplikation eine 1 Byte Antwort
+*
+* Eingabeparameter:
+* fd - Filehandle der Pipe (von gemtk_dd_open())
+* ack - Byte das gesendet werden soll (zB. DD_OK)
+*
+* Ausgabeparameter:
+* keine
+*
+* Returnwert:
+* >0: kein Fehler
+* -1: Fehler (die Pipe wird automatisch geschlossen!)
+*/
+
+short gemtk_dd_reply(short fd, char ack)
+{
+ if (Fwrite(fd, 1L, &ack) != 1L)
+ {
+ gemtk_dd_close(fd);
+ return(-1);
+ }
+
+ return(1);
+}
+
+
diff --git a/frontends/atari/gemtk/dragdrop.h b/frontends/atari/gemtk/dragdrop.h
new file mode 100755
index 000000000..38466137b
--- /dev/null
+++ b/frontends/atari/gemtk/dragdrop.h
@@ -0,0 +1,4 @@
+#ifndef DD_H_INCLUDED
+#define DD_H_INCLUDED
+
+#endif
diff --git a/frontends/atari/gemtk/gemtk.h b/frontends/atari/gemtk/gemtk.h
new file mode 100644
index 000000000..e5915e6eb
--- /dev/null
+++ b/frontends/atari/gemtk/gemtk.h
@@ -0,0 +1,298 @@
+#ifndef GEMTK_H_INCLUDED
+#define GEMTK_H_INCLUDED
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <mint/osbind.h>
+#include <mint/cookie.h>
+
+#include <gem.h>
+#include <cflib.h>
+
+
+/* -------------------------------------------------------------------------- */
+/* SYSTEM UTILS */
+/* -------------------------------------------------------------------------- */
+
+/* System type detection added by [GS] */
+/* detect the system type, AES + kernel */
+#define SYS_TOS 0x0001
+#define SYS_MAGIC 0x0002
+#define SYS_MINT 0x0004
+#define SYS_GENEVA 0x0010
+#define SYS_NAES 0x0020
+#define SYS_XAAES 0x0040
+#define sys_type() (_systype_v ? _systype_v : _systype())
+#define sys_MAGIC() ((sys_type() & SYS_MAGIC) != 0)
+#define sys_NAES() ((sys_type() & SYS_NAES) != 0)
+#define sys_XAAES() ((sys_type() & SYS_XAAES) != 0)
+
+#define TOS4VER 0x03300 /* this is assumed to be the last single tasking OS */
+
+extern unsigned short _systype_v;
+unsigned short _systype (void);
+
+/* GEMTK Utils API: */
+
+#define GEMTK_DBG_GRECT(s,g) \
+ printf("%s", s); \
+ printf("\tx0: %d, \n", (g)->g_x); \
+ printf("\ty0: %d, \n", (g)->g_y); \
+ printf("\tx1: %d, \n", (g)->g_x+(g)->g_w); \
+ printf("\ty1: %d, \n", (g)->g_y+(g)->g_h); \
+ printf("\tw: %d, \n", (g)->g_w); \
+ printf("\th: %d \n", (g)->g_h); \
+
+/*
+* Chech for GRECT intersection without modifiend the src rectangles
+* return true when the GRECT's intersect, fals otherwise.
+*/
+bool gemtk_rc_intersect_ro(GRECT *a, GRECT *b);
+
+/*
+* Convert keycode returned by evnt_multi to ascii value
+*/
+int gemtk_keybd2ascii( int keybd, int shift);
+
+/** set VDI clip area by passing an GRECT */
+void gemtk_clip_grect(VdiHdl vh, GRECT *rect);
+
+void gemtk_wind_get_str(short aes_handle, short mode, char *str, int len);
+
+/* send application message */
+void gemtk_send_msg(short msg_type, short data2, short data3, short data4,
+ short data5, short data6, short data7);
+
+
+#ifndef POINT_WITHIN
+# define POINT_WITHIN(_x,_y, r) ((_x >= r.g_x) && (_x <= r.g_x + r.g_w ) \
+ && (_y >= r.g_y) && (_y <= r.g_y + r.g_h))
+#endif
+
+#ifndef RC_WITHIN
+# define RC_WITHIN(a,b) \
+ (((a)->g_x >= (b)->g_x) \
+ && (((a)->g_x + (a)->g_w) <= ((b)->g_x + (b)->g_w))) \
+ && (((a)->g_y >= (b)->g_y) \
+ && (((a)->g_y + (a)->g_h) <= ((b)->g_y + (b)->g_h)))
+#endif
+
+#ifndef MAX
+# define MAX(_a,_b) ((_a>_b) ? _a : _b)
+#endif
+
+#ifndef MIN
+# define MIN(_a,_b) ((_a<_b) ? _a : _b)
+#endif
+
+#ifndef SET_BIT
+# define SET_BIT(field,bit,val) field = (val)?((field)|(bit)):((field) & ~(bit))
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* MultiTOS Drag & Drop */
+/* -------------------------------------------------------------------------- */
+short gemtk_dd_create(short *pipe);
+short gemtk_dd_message(short apid, short fd, short winid, short mx, short my, short kstate, short pipename);
+short gemtk_dd_rexts(short fd, char *exts);
+short gemtk_dd_stry(short fd, char *ext, char *text, char *name, long size);
+void gemtk_dd_close(short fd);
+void gemtk_dd_getsig(long *oldsig);
+void gemtk_dd_setsig(long oldsig);
+short gemtk_dd_open(short ddnam, char ddmsg);
+short gemtk_dd_sexts(short fd, char *exts);
+short gemtk_dd_rtry(short fd, char *name, char *file, char *whichext, long *size);
+short gemtk_dd_reply(short fd, char ack);
+
+/* -------------------------------------------------------------------------- */
+/* AV/VA Protocol Module */
+/* -------------------------------------------------------------------------- */
+int gemtk_av_init(const char *appname);
+void gemtk_av_exit(void);
+bool gemtk_av_send (short message, const char * data1, const char * data2);
+bool gemtk_av_dispatch (short msg[8]);
+
+/* -------------------------------------------------------------------------- */
+/* Message Box module */
+/* -------------------------------------------------------------------------- */
+#define GEMTK_MSG_BOX_ALERT 1
+#define GEMTK_MSG_BOX_CONFIRM 2
+
+short gemtk_msg_box_show(short type, const char * msg);
+
+/* -------------------------------------------------------------------------- */
+/* GUIWIN Module */
+/* -------------------------------------------------------------------------- */
+#define GEMTK_WM_FLAG_PREPROC_WM 0x01 // let guiwin API handle some events
+#define GEMTK_WM_FLAG_RECV_PREPROC_WM 0x02 // get notified even when pre-processed
+#define GEMTK_WM_FLAG_HAS_VTOOLBAR 0x04 // the attached toolbar is vertical
+#define GEMTK_WM_FLAG_CUSTOM_TOOLBAR 0x08 // no internal toolbar handling
+ // (Except considering it's size)
+#define GEMTK_WM_FLAG_CUSTOM_SCROLLING 0x20 // no internal scroller handling
+
+#define GEMTK_WM_FLAG_DEFAULTS \
+ (GEMTK_WM_FLAG_PREPROC_WM | GEMTK_WM_FLAG_RECV_PREPROC_WM)
+
+#define GEMTK_WM_STATUS_ICONIFIED 0x01
+#define GEMTK_WM_STATUS_SHADED 0x02
+
+#define GEMTK_WM_VSLIDER 0x01
+#define GEMTK_WM_HSLIDER 0x02
+#define GEMTK_WM_VH_SLIDER 0x03
+
+/*
+ Message sent to the client application when an AES object is
+ clicked in an window which contains an form.
+
+ Message Parameters:
+ msg[4] = Clicked Object.
+ msg[5] = Number of clicks.
+ msg[6] = Modifier keys.
+*/
+#define GEMTK_WM_WM_FORM_CLICK 1001
+#define GEMTK_WM_WM_FORM_KEY 1002
+
+struct gemtk_window_s;
+
+/** list struct for managing AES windows */
+typedef struct gemtk_window_s GUIWIN;
+
+/** GUIWIN event handler */
+typedef short (*gemtk_wm_event_handler_f)(GUIWIN *gw,
+ EVMULT_OUT *ev_out, short msg[8]);
+
+typedef void (*gemtk_wm_redraw_f)(GUIWIN *win, uint16_t msg, GRECT *clip);
+
+struct gemtk_wm_scroll_info_s {
+
+ /** Definition of a content unit (horizontal) measured in pixel */
+ int x_unit_px;
+
+ /** Definition of content unit (vertical) measured in pixel */
+ int y_unit_px;
+
+ /** Current scroll position (in content units) */
+ int x_pos;
+
+ /** Current scroll position (in content units) */
+ int y_pos;
+
+ /** Size of content (horizontal) measured in content units */
+ int x_units;
+
+ /** Size of content (vertical) measured in content units */
+ int y_units;
+};
+
+/** Well known areas inside the window */
+enum guwin_area_e {
+ GEMTK_WM_AREA_WORK = 0,
+ GEMTK_WM_AREA_TOOLBAR,
+ GEMTK_WM_AREA_CONTENT
+};
+
+/* -------------------------------------------------------------------------- */
+/* GUIWIN functions (document in guiwin.c) */
+/* -------------------------------------------------------------------------- */
+
+short
+gemtk_wm_init(void);
+
+void gemtk_wm_exit(void);
+
+GUIWIN * gemtk_wm_add(short handle, uint32_t flags,
+ gemtk_wm_event_handler_f handler);
+
+GUIWIN * gemtk_wm_find(short handle);
+
+void gemtk_wm_dump_window_info(GUIWIN *win);
+
+short gemtk_wm_remove(GUIWIN *win);
+
+GUIWIN * gemtk_wm_validate_ptr(GUIWIN *win);
+
+GUIWIN *gemtk_wm_link(GUIWIN *win);
+
+GUIWIN *gemtk_wm_unlink(GUIWIN *win);
+
+short gemtk_wm_dispatch_event(EVMULT_IN *ev_in, EVMULT_OUT *ev_out, short msg[8]);
+
+void gemtk_wm_get_grect(GUIWIN *win, enum guwin_area_e mode, GRECT *dest);
+
+short gemtk_wm_get_toolbar_edit_obj(GUIWIN *win);
+
+short gemtk_wm_get_handle(GUIWIN *win);
+
+uint32_t gemtk_wm_get_state(GUIWIN *win);
+
+void gemtk_wm_set_toolbar(GUIWIN *win, OBJECT *toolbar, short idx,
+ uint32_t flags);
+
+void gemtk_wm_set_event_handler(GUIWIN *win,gemtk_wm_event_handler_f cb);
+
+void gemtk_wm_set_user_data(GUIWIN *win, void *data);
+
+void * gemtk_wm_get_user_data(GUIWIN *win);
+
+struct gemtk_wm_scroll_info_s * gemtk_wm_get_scroll_info(GUIWIN *win);
+
+void gemtk_wm_set_scroll_grid(GUIWIN * win, short x, short y);
+
+void gemtk_wm_set_content_units(GUIWIN * win, short x, short y);
+
+void gemtk_wm_set_form(GUIWIN *win, OBJECT *tree, short index);
+
+void gemtk_wm_set_toolbar_size(GUIWIN *win, uint16_t s);
+
+void gemtk_wm_set_toolbar_edit_obj(GUIWIN *win, uint16_t obj, short kreturn);
+
+void gemtk_wm_set_toolbar_redraw_func(GUIWIN *win, gemtk_wm_redraw_f func);
+
+bool gemtk_wm_update_slider(GUIWIN *win, short mode);
+
+void gemtk_wm_scroll(GUIWIN *gw, short orientation, int units, bool refresh);
+
+void gemtk_wm_send_msg(GUIWIN *win, short msgtype, short a, short b, short c,
+ short d);
+
+short gemtk_wm_exec_msg(GUIWIN *win, short msg_type, short a, short b, short c,
+ short d);
+
+void gemtk_wm_exec_redraw(GUIWIN *win, GRECT *area);
+
+VdiHdl gemtk_wm_get_vdi_handle(GUIWIN *win);
+
+short getm_wm_get_toolbar_edit_obj(GUIWIN *win);
+
+bool gemtk_wm_has_intersection(GUIWIN *win, GRECT *work);
+
+void gemtk_wm_toolbar_redraw(GUIWIN *win, uint16_t msg, GRECT *clip);
+
+void gemtk_wm_form_redraw(GUIWIN *gw, GRECT *clip);
+
+void gemtk_wm_clear(GUIWIN *win);
+
+/* -------------------------------------------------------------------------- */
+/* AES SCROLLER MODULE */
+/* -------------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* AES TABS MODULE */
+/* -------------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* AES OBJECT TREE TOOLS */
+/* -------------------------------------------------------------------------- */
+char gemtk_obj_set_str_safe(OBJECT * tree, short idx, const char *txt);
+char *gemtk_obj_get_text(OBJECT * tree, short idx);
+GRECT * gemtk_obj_screen_rect(OBJECT * tree, short obj);
+bool gemtk_obj_is_inside(OBJECT * tree, short obj, GRECT *area);
+OBJECT *gemtk_obj_get_tree(int idx);
+void gemtk_obj_mouse_sprite(OBJECT *tree, int index);
+OBJECT *gemtk_obj_tree_copy(OBJECT *tree);
+OBJECT * gemtk_obj_create_popup_tree(const char **items, int nitems,
+ char * selected, bool horizontal,
+ int max_width, int max_height);
+void gemtk_obj_destroy_popup_tree(OBJECT * popup);
+#endif // GEMTK_H_INCLUDED
diff --git a/frontends/atari/gemtk/guiwin.c b/frontends/atari/gemtk/guiwin.c
new file mode 100644
index 000000000..ea0f8f917
--- /dev/null
+++ b/frontends/atari/gemtk/guiwin.c
@@ -0,0 +1,1430 @@
+/*
+ * Copyright 2012 Ole Loots <ole@monochrom.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <gem.h>
+#include <gemx.h>
+#include <cflib.h>
+
+#include "gemtk.h"
+#include "vaproto.h"
+
+//#define DEBUG_PRINT(x) printf x
+#define DEBUG_PRINT(x)
+
+struct gemtk_window_s {
+
+ /** The AES handle of the window */
+ short handle;
+
+ /** the generic event handler function for events passed to the client */
+ gemtk_wm_event_handler_f handler_func;
+
+ /** The toolbar redraw function, if any */
+ gemtk_wm_redraw_f toolbar_redraw_func;
+
+ /** window configuration */
+ uint32_t flags;
+
+ /** window state */
+ uint32_t state;
+
+ /** AES Tree used as toolbar */
+ OBJECT *toolbar;
+
+ /** Current edit object selected in the toolbar, if any. */
+ short toolbar_edit_obj;
+
+ /** Current selected object in the toolbar, if any. */
+ short toolbar_focus_obj;
+
+ /** Describes the start of the toolbar tree (usually 0) */
+ short toolbar_idx;
+
+ /** depending on the flag GEMTK_WM_FLAG_HAS_VTOOLBAR this defines the toolbar
+ height or the toolbar width (GEMTK_WM_FLAG_HAS_VTOOLBAR means width).
+ */
+ short toolbar_size;
+
+ /** AES Object tree to be used for windowed dialogs. */
+ OBJECT *form;
+
+ /** Current form edit object, if any. */
+ short form_edit_obj;
+
+ /** Current form focus object, if any */
+ short form_focus_obj;
+
+ /** Describes the start of the form tree */
+ short form_idx;
+
+ /** Scroll state */
+ struct gemtk_wm_scroll_info_s scroll_info;
+
+ /** Arbitary data set by the user */
+ void *user_data;
+
+ /** linked list items */
+ struct gemtk_window_s *next, *prev;
+};
+
+static GUIWIN * winlist;
+static VdiHdl v_vdi_h = -1;
+static short work_out[57];
+
+static void move_rect(GUIWIN * win, GRECT *rect, int dx, int dy)
+{
+ INT16 xy[ 8];
+ long dum = 0L;
+ GRECT g;
+
+ VdiHdl vh = gemtk_wm_get_vdi_handle(win);
+
+ while(!wind_update(BEG_UPDATE));
+ graf_mouse(M_OFF, 0L);
+
+ /* get intersection with screen area */
+ wind_get_grect(0, WF_CURRXYWH, &g);
+ if(!rc_intersect(&g, rect)){
+ goto error;
+ }
+ xy[0] = rect->g_x;
+ xy[1] = rect->g_y;
+ xy[2] = xy[0] + rect->g_w-1;
+ xy[3] = xy[1] + rect->g_h-1;
+ xy[4] = xy[0] + dx;
+ xy[5] = xy[1] + dy;
+ xy[6] = xy[2] + dx;
+ xy[7] = xy[3] + dy;
+ vro_cpyfm(vh, S_ONLY, xy, (MFDB *)&dum, (MFDB *)&dum);
+
+error:
+ graf_mouse(M_ON, 0L);
+ wind_update(END_UPDATE);
+}
+
+/**
+* Handles common events.
+* returns 0 when the event was not handled, 1 otherwise.
+*/
+static short preproc_wm(GUIWIN * gw, EVMULT_OUT *ev_out, short msg[8])
+{
+ GRECT g, g_ro, g2;
+ short retval = 1;
+ int val = 1;
+ struct gemtk_wm_scroll_info_s *slid;
+
+ switch(msg[0]) {
+
+ case WM_HSLID:
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_CONTENT, &g);
+ wind_set(gw->handle, WF_HSLIDE, msg[4], 0, 0, 0);
+ slid = gemtk_wm_get_scroll_info(gw);
+ val = (float)(slid->x_units-(g.g_w/slid->x_unit_px))/1000*(float)msg[4];
+ if(val != slid->x_pos) {
+ if (val < slid->x_pos) {
+ val = -(MAX(0, slid->x_pos-val));
+ } else {
+ val = val-slid->x_pos;
+ }
+ gemtk_wm_scroll(gw, GEMTK_WM_HSLIDER, val, false);
+ }
+ break;
+
+ case WM_VSLID:
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_CONTENT, &g);
+ wind_set(gw->handle, WF_VSLIDE, msg[4], 0, 0, 0);
+ slid = gemtk_wm_get_scroll_info(gw);
+ val = (float)(slid->y_units-(g.g_h/slid->y_unit_px))/1000*(float)msg[4];
+ if(val != slid->y_pos) {
+ if (val < slid->y_pos) {
+ val = -(slid->y_pos - val);
+ } else {
+ val = val -slid->y_pos;
+ }
+ gemtk_wm_scroll(gw, GEMTK_WM_VSLIDER, val, false);
+ }
+ break;
+
+ case WM_ARROWED:
+ if((gw->flags & GEMTK_WM_FLAG_CUSTOM_SCROLLING) == 0) {
+
+ slid = gemtk_wm_get_scroll_info(gw);
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_CONTENT, &g);
+ g_ro = g;
+
+ switch(msg[4]) {
+
+ case WA_UPPAGE:
+ /* scroll page up */
+ gemtk_wm_scroll(gw, GEMTK_WM_VSLIDER, -(g.g_h/slid->y_unit_px),
+ true);
+ break;
+
+ case WA_UPLINE:
+ /* scroll line up */
+ gemtk_wm_scroll(gw, GEMTK_WM_VSLIDER, -1, true);
+ break;
+
+ case WA_DNPAGE:
+ /* scroll page down */
+ gemtk_wm_scroll(gw, GEMTK_WM_VSLIDER, g.g_h/slid->y_unit_px,
+ true);
+ break;
+
+ case WA_DNLINE:
+ /* scroll line down */
+ gemtk_wm_scroll(gw, GEMTK_WM_VSLIDER, +1, true);
+ break;
+
+ case WA_LFPAGE:
+ /* scroll page left */
+ gemtk_wm_scroll(gw, GEMTK_WM_HSLIDER, -(g.g_w/slid->x_unit_px),
+ true);
+ break;
+
+ case WA_LFLINE:
+ /* scroll line left */
+ gemtk_wm_scroll(gw, GEMTK_WM_HSLIDER, -1,
+ true);
+ break;
+
+ case WA_RTPAGE:
+ /* scroll page right */
+ gemtk_wm_scroll(gw, GEMTK_WM_HSLIDER, (g.g_w/slid->x_unit_px),
+ true);
+ break;
+
+ case WA_RTLINE:
+ /* scroll line right */
+ gemtk_wm_scroll(gw, GEMTK_WM_HSLIDER, 1,
+ true);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case WM_TOPPED:
+ wind_set(gw->handle, WF_TOP, 1, 0, 0, 0);
+ break;
+
+ case WM_MOVED:
+ wind_get_grect(gw->handle, WF_CURRXYWH, &g);
+ wind_set(gw->handle, WF_CURRXYWH, msg[4], msg[5], g.g_w, g.g_h);
+
+ if (gw->form) {
+
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_CONTENT, &g);
+ slid = gemtk_wm_get_scroll_info(gw);
+
+ gw->form[gw->form_idx].ob_x = g.g_x -
+ (slid->x_pos * slid->x_unit_px);
+
+ gw->form[gw->form_idx].ob_y = g.g_y -
+ (slid->y_pos * slid->y_unit_px);
+ }
+
+ break;
+
+ case WM_SIZED:
+ case WM_REPOSED:
+ wind_get_grect(gw->handle, WF_FULLXYWH, &g2);
+ wind_get_grect(gw->handle, WF_CURRXYWH, &g);
+ g.g_w = MIN(msg[6], g2.g_w);
+ g.g_h = MIN(msg[7], g2.g_h);
+ if(g2.g_w != g.g_w || g2.g_h != g.g_h) {
+ wind_set(gw->handle, WF_CURRXYWH, g.g_x, g.g_y, g.g_w, g.g_h);
+ if((gw->flags & GEMTK_WM_FLAG_CUSTOM_SCROLLING) == 0) {
+ if(gemtk_wm_update_slider(gw, GEMTK_WM_VH_SLIDER)) {
+ gemtk_wm_exec_redraw(gw, NULL);
+ }
+ }
+ }
+
+
+ break;
+
+ case WM_FULLED:
+ wind_get_grect(DESKTOP_HANDLE, WF_WORKXYWH, &g);
+ wind_get_grect(gw->handle, WF_CURRXYWH, &g2);
+ if(g.g_w == g2.g_w && g.g_h == g2.g_h) {
+ wind_get_grect(gw->handle, WF_PREVXYWH, &g);
+ }
+ wind_set_grect(gw->handle, WF_CURRXYWH, &g);
+ if((gw->flags & GEMTK_WM_FLAG_CUSTOM_SCROLLING) == 0) {
+ if(gemtk_wm_update_slider(gw, GEMTK_WM_VH_SLIDER)) {
+ gemtk_wm_exec_redraw(gw, NULL);
+ }
+ }
+ break;
+
+ case WM_ICONIFY:
+ wind_set(gw->handle, WF_ICONIFY, msg[4], msg[5], msg[6], msg[7]);
+ gw->state |= GEMTK_WM_STATUS_ICONIFIED;
+ break;
+
+ case WM_UNICONIFY:
+ wind_set(gw->handle, WF_UNICONIFY, msg[4], msg[5], msg[6], msg[7]);
+ gw->state &= ~(GEMTK_WM_STATUS_ICONIFIED);
+ break;
+
+ case WM_SHADED:
+ gw->state |= GEMTK_WM_STATUS_SHADED;
+ break;
+
+ case WM_UNSHADED:
+ gw->state &= ~(GEMTK_WM_STATUS_SHADED);
+ break;
+
+ case WM_REDRAW:
+ if ((gw->flags & GEMTK_WM_FLAG_CUSTOM_TOOLBAR) == 0
+ && (gw->toolbar != NULL)) {
+ g.g_x = msg[4];
+ g.g_y = msg[5];
+ g.g_w = msg[6];
+ g.g_h = msg[7];
+ if((gw->state & GEMTK_WM_STATUS_ICONIFIED) == 0){
+ gemtk_wm_toolbar_redraw(gw, WM_REDRAW, &g);
+ }
+ }
+ if (gw->form != NULL) {
+ g.g_x = msg[4];
+ g.g_y = msg[5];
+ g.g_w = msg[6];
+ g.g_h = msg[7];
+ gemtk_wm_form_redraw(gw, &g);
+ }
+ break;
+
+ default:
+ retval = 0;
+ break;
+
+ }
+
+ return(retval);
+}
+
+/**
+* Preprocess mouse events
+*/
+static short preproc_mu_button(GUIWIN * gw, EVMULT_OUT *ev_out, short msg[8])
+{
+ short retval = 0, obj_idx = 0;
+
+ DEBUG_PRINT(("preproc_mu_button\n"));
+
+ // toolbar handling:
+ if ((gw->flags & GEMTK_WM_FLAG_CUSTOM_TOOLBAR) == 0
+ && gw->toolbar != NULL) {
+
+ GRECT tb_area;
+
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_TOOLBAR, &tb_area);
+
+ if (POINT_WITHIN(ev_out->emo_mouse.p_x,
+ ev_out->emo_mouse.p_y, tb_area)) {
+
+ gw->toolbar[gw->toolbar_idx].ob_x = tb_area.g_x;
+ gw->toolbar[gw->toolbar_idx].ob_y = tb_area.g_y;
+ obj_idx = objc_find(gw->toolbar,
+ gw->toolbar_idx, 8,
+ ev_out->emo_mouse.p_x,
+ ev_out->emo_mouse.p_y);
+
+ gw->toolbar_focus_obj = obj_idx;
+
+ DEBUG_PRINT(("Toolbar index: %d\n", obj_idx));
+ if (obj_idx > -1
+ && (gw->toolbar[obj_idx].ob_state & OS_DISABLED)== 0
+ && ((gw->flags & GEMTK_WM_FLAG_CUSTOM_TOOLBAR) == 0)) {
+
+ uint16_t type = (gw->toolbar[obj_idx].ob_type & 0xFF);
+ uint16_t nextobj;
+
+ DEBUG_PRINT(("toolbar item type: %d, toolbar_edit_obj: %d\n",
+ type, gw->toolbar_edit_obj));
+ // Report mouse click to the tree:
+ retval = form_wbutton(gw->toolbar, gw->toolbar_focus_obj,
+ ev_out->emo_mclicks, &nextobj,
+ gw->handle);
+ if (nextobj == obj_idx
+ && (type == G_FTEXT || type == G_FBOXTEXT)) {
+ gw->toolbar_edit_obj = obj_idx;
+ }
+ else {
+ gw->toolbar_edit_obj = -1;
+ }
+ }
+
+ // send WM_TOOLBAR message
+ short oldevents = ev_out->emo_events;
+ short msg_out[8] = {WM_TOOLBAR, gl_apid,
+ 0, gw->handle,
+ obj_idx, ev_out->emo_mclicks,
+ ev_out->emo_kmeta, ev_out->emo_mbutton
+ };
+ ev_out->emo_events = MU_MESAG;
+ // notify the window about toolbar click:
+ gw->handler_func(gw, ev_out, msg_out);
+ ev_out->emo_events = oldevents;
+ retval = 1;
+ } else {
+ if (gw->toolbar_edit_obj != -1) {
+ gw->toolbar_edit_obj = -1;
+ }
+ }
+ }
+
+ if (gw->form != NULL) {
+
+ GRECT content_area;
+ struct gemtk_wm_scroll_info_s *slid;
+
+ DEBUG_PRINT(("preproc_mu_button: handling form click.\n"));
+
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_CONTENT, &content_area);
+
+ if (POINT_WITHIN(ev_out->emo_mouse.p_x,
+ ev_out->emo_mouse.p_y, content_area)) {
+
+ slid = gemtk_wm_get_scroll_info(gw);
+
+ // adjust form position (considering window and scroll position):
+ gw->form[gw->form_idx].ob_x = content_area.g_x -
+ (slid->x_pos * slid->x_unit_px);
+ gw->form[gw->form_idx].ob_y = content_area.g_y -
+ (slid->y_pos * slid->y_unit_px);
+
+ obj_idx = objc_find(gw->form, gw->form_idx, 8,
+ ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y);
+ gw->form_focus_obj = obj_idx;
+ DEBUG_PRINT(("Window Form click, obj: %d\n", gw->form_focus_obj));
+ if (obj_idx > -1
+ && (gw->form[obj_idx].ob_state & OS_DISABLED)== 0) {
+
+ uint16_t type = (gw->form[obj_idx].ob_type & 0xFF);
+ uint16_t nextobj;
+
+ DEBUG_PRINT(("type: %d\n", type));
+
+ retval = form_wbutton(gw->form, gw->form_focus_obj,
+ ev_out->emo_mclicks, &nextobj,
+ gw->handle);
+
+ if (nextobj == obj_idx
+ && (type == G_FTEXT || type == G_FBOXTEXT)) {
+ gw->form_edit_obj = obj_idx;
+ }
+ else {
+ gw->form_edit_obj = -1;
+ }
+
+ short oldevents = ev_out->emo_events;
+ short msg_out[8] = { GEMTK_WM_WM_FORM_CLICK, gl_apid,
+ 0, gw->handle,
+ gw->form_focus_obj, ev_out->emo_mclicks,
+ ev_out->emo_kmeta, 0
+ };
+ ev_out->emo_events = MU_MESAG;
+ // notify the window about form click:
+ gw->handler_func(gw, ev_out, msg_out);
+ ev_out->emo_events = oldevents;
+ retval = 1;
+ evnt_timer(150);
+ }
+ }
+ else {
+ gw->form_edit_obj = -1;
+
+ }
+ }
+
+ return(retval);
+}
+
+/**
+* Preprocess keyboard events (for forms/toolbars)
+*/
+static short preproc_mu_keybd(GUIWIN * gw, EVMULT_OUT *ev_out, short msg[8])
+{
+ short retval = 0;
+
+ if ((gw->toolbar != NULL) && (gw->toolbar_edit_obj > -1)) {
+
+ short next_edit_obj = gw->toolbar_edit_obj;
+ short next_char = -1;
+ short edit_idx;
+ short r;
+
+ DEBUG_PRINT(("%s, gw: %p, toolbar_edit_obj: %d\n", __FUNCTION__, gw,
+ gw->toolbar_edit_obj));
+
+ r = form_wkeybd(gw->toolbar, gw->toolbar_edit_obj, next_edit_obj,
+ ev_out->emo_kreturn,
+ &next_edit_obj, &next_char, gw->handle);
+
+ if (next_edit_obj != gw->toolbar_edit_obj) {
+ gemtk_wm_set_toolbar_edit_obj(gw, next_edit_obj,
+ ev_out->emo_kreturn);
+ } else {
+ if (next_char > 13) {
+ r = objc_wedit(gw->toolbar, gw->toolbar_edit_obj,
+ ev_out->emo_kreturn, &edit_idx,
+ EDCHAR, gw->handle);
+ }
+ }
+ //retval = 1;
+ /*gemtk_wm_send_msg(gw, GEMTK_WM_WM_FORM_KEY, gw->toolbar_edit_obj,
+ ev_out->emo_kreturn, 0, 0);*/
+ }
+
+ if((gw->form != NULL) && (gw->form_edit_obj > -1) ) {
+
+ short next_edit_obj = gw->form_edit_obj;
+ short next_char = -1;
+ short edit_idx;
+ short r;
+
+ r = form_wkeybd(gw->form, gw->form_edit_obj, next_edit_obj,
+ ev_out->emo_kreturn,
+ &next_edit_obj, &next_char, gw->handle);
+
+ if (next_edit_obj != gw->form_edit_obj) {
+
+ if(gw->form_edit_obj != -1) {
+ objc_wedit(gw->form, gw->form_edit_obj,
+ ev_out->emo_kreturn, &edit_idx,
+ EDEND, gw->handle);
+ }
+
+ gw->form_edit_obj = next_edit_obj;
+
+ objc_wedit(gw->form, gw->form_edit_obj,
+ ev_out->emo_kreturn, &edit_idx,
+ EDINIT, gw->handle);
+ } else {
+ if(next_char > 13)
+ r = objc_wedit(gw->form, gw->form_edit_obj,
+ ev_out->emo_kreturn, &edit_idx,
+ EDCHAR, gw->handle);
+ }
+ }
+ return(retval);
+}
+
+/**
+* Default toolbar redraw function
+*/
+static void std_toolbar_redraw(GUIWIN *gw, uint16_t msg, GRECT *clip)
+{
+ GRECT g, tb_area;
+
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_TOOLBAR, &tb_area);
+
+ assert(gw->toolbar);
+ assert(gw->toolbar_idx >= 0);
+
+ // Update object position:
+ gw->toolbar[gw->toolbar_idx].ob_x = tb_area.g_x;
+ gw->toolbar[gw->toolbar_idx].ob_y = tb_area.g_y;
+ gw->toolbar[gw->toolbar_idx].ob_width = tb_area.g_w;
+ gw->toolbar[gw->toolbar_idx].ob_height = tb_area.g_h;
+
+ wind_get_grect(gw->handle, WF_FIRSTXYWH, &g);
+ while (g.g_h > 0 || g.g_w > 0) {
+ if(rc_intersect(clip, &g)) {
+ objc_draw(gw->toolbar, gw->toolbar_idx, 8, g.g_x, g.g_y,
+ g.g_w, g.g_h);
+
+ }
+ wind_get_grect(gw->handle, WF_NEXTXYWH, &g);
+ }
+}
+
+/**
+* Event Dispatcher function. The guiwin API doesn't own an event loop,
+* so you have to inform it for every event that you want it to handle.
+*/
+short gemtk_wm_dispatch_event(EVMULT_IN *ev_in, EVMULT_OUT *ev_out, short msg[8])
+{
+ GUIWIN *dest;
+ short retval = 0;
+ bool handler_called = false;
+
+ if( (ev_out->emo_events & MU_MESAG) != 0 ) {
+ DEBUG_PRINT(("gemtk_wm_handle_event_multi_fast: %d (%x)\n", msg[0],
+ msg[0]));
+ switch (msg[0]) {
+ case WM_REDRAW:
+ case WM_CLOSED:
+ case WM_TOPPED:
+ case WM_ARROWED:
+ case WM_HSLID:
+ case WM_VSLID:
+ case WM_FULLED:
+ case WM_SIZED:
+ case WM_REPOSED:
+ case WM_MOVED:
+ case WM_NEWTOP:
+ case WM_UNTOPPED:
+ case WM_ONTOP:
+ case WM_BOTTOM:
+ case WM_ICONIFY:
+ case WM_UNICONIFY:
+ case WM_ALLICONIFY:
+ case WM_TOOLBAR:
+ case AP_DRAGDROP:
+ case AP_TERM:
+ case AP_TFAIL:
+ dest = gemtk_wm_find(msg[3]);
+ if (dest) {
+ DEBUG_PRINT(("Found WM_ dest: %p (%d), flags: %d, cb: %p\n",
+ dest, dest->handle, dest->flags,
+ dest->handler_func));
+ if (dest->flags&GEMTK_WM_FLAG_PREPROC_WM) {
+ retval = preproc_wm(dest, ev_out, msg);
+ if(((retval == 0)||(dest->flags&GEMTK_WM_FLAG_RECV_PREPROC_WM))) {
+ retval = dest->handler_func(dest, ev_out, msg);
+ handler_called = true;
+ }
+ } else {
+ if (dest->handler_func) {
+ retval = dest->handler_func(dest, ev_out, msg);
+ handler_called = true;
+ }
+ }
+
+ }
+ break;
+// TODO: check code with Thing! Desktop
+/*
+ We receive VA_PROTOSTATUS but AV_START doesn't seem to cause
+ an TeraDesk response. Check if something happens with Thing!
+ Desktop.
+
+ case VA_PROTOSTATUS:
+ case VA_VIEWED:
+ case AV_STARTED:
+ gemtk_av_dispatch(msg);
+ break;
+*/
+ }
+ } else {
+
+ short h_aes;
+ h_aes = wind_find(ev_out->emo_mouse.p_x, ev_out->emo_mouse.p_y);
+ if(h_aes > 0 && (ev_out->emo_events != MU_TIMER)) {
+
+ dest = gemtk_wm_find(h_aes);
+
+ if (dest == NULL || dest->handler_func == NULL)
+ return(0);
+
+ DEBUG_PRINT(("Found Event receiver GUIWIN: %p (%d), flags: %d, cb: %p\n",
+ dest, dest->handle, dest->flags, dest->handler_func));
+
+ if ((ev_out->emo_events & MU_BUTTON) != 0) {
+ DEBUG_PRINT(("gemtk_wm_handle_event_multi_fast: MU_BUTTON -> "
+ "%d / %d\n", ev_out->emo_mouse.p_x,
+ ev_out->emo_mouse.p_y));
+ retval = preproc_mu_button(dest, ev_out, msg);
+ if(retval != 0) {
+ handler_called = true;
+ }
+ }
+
+ if ((ev_out->emo_events & MU_KEYBD)) {
+ DEBUG_PRINT(("gemtk_wm_handle_event_multi_fast: MU_KEYBD -> %x\n",
+ ev_out->emo_kreturn));
+ retval = preproc_mu_keybd(dest, ev_out, msg);
+ if(retval != 0) {
+ handler_called = true;
+ }
+ }
+
+ if (handler_called==false) {
+ retval = dest->handler_func(dest, ev_out, msg);
+ }
+ }
+ }
+
+ return(retval);
+}
+
+/**
+* Initialises the guiwin API
+*/
+short gemtk_wm_init(void)
+{
+ if(v_vdi_h == -1) {
+ short dummy;
+ short work_in[12] = {Getrez()+2,1,1,1,1,1,1,1,1,1,2,1};
+ v_vdi_h=graf_handle(&dummy, &dummy, &dummy, &dummy);
+ v_opnvwk(work_in, &v_vdi_h, work_out);
+ }
+ return(0);
+}
+
+void gemtk_wm_exit(void)
+{
+ v_clsvwk(v_vdi_h);
+}
+
+/**
+* Adds and AES handle to the guiwin list and creates and GUIWIN management
+* structure.
+*
+* \param handle The AES handle
+* \param flags Creation flags, configures how the AES window is handled
+* \param cb event handler function for that window
+*/
+GUIWIN * gemtk_wm_add(short handle, uint32_t flags, gemtk_wm_event_handler_f cb)
+{
+
+ GUIWIN *win = calloc(1, sizeof(GUIWIN));
+
+ assert(win!=NULL);
+ DEBUG_PRINT(("gemtk_wm_add: %d, %p, cb: %p\n", handle, win, cb));
+
+ win->handle = handle;
+ win->handler_func = cb;
+ win->flags = flags;
+ gemtk_wm_link(win);
+
+ DEBUG_PRINT(("Added guiwin: %p, tb: %p\n", win, win->toolbar));
+ return(win);
+}
+
+/**
+* Returns an GUIWIN* for AES handle, when that AES window is managed by gemtk_wm
+*/
+GUIWIN *gemtk_wm_find(short handle)
+{
+ GUIWIN *g;
+ DEBUG_PRINT(("guiwin search handle: %d\n", handle));
+ for (g = winlist; g != NULL; g=g->next) {
+ if(g->handle == handle) {
+ DEBUG_PRINT(("guiwin found handle: %p\n", g));
+ return(g);
+ }
+ }
+ return(NULL);
+}
+
+void gemtk_wm_dump_window_info(GUIWIN *win)
+{
+
+
+
+ char title[255];
+ GRECT work_area;
+ GRECT curr_area;
+ GRECT gemtk_work_area;
+ GRECT gemtk_toolbar_area;
+ GRECT gemtk_free_area;
+ short handle;
+ struct gemtk_wm_scroll_info_s *slid;
+
+ handle = gemtk_wm_get_handle(win);
+
+ assert(handle);
+
+ gemtk_wind_get_str(handle, WF_NAME, title, 255);
+ wind_get_grect(handle, WF_WORKXYWH, &work_area);
+ wind_get_grect(handle, WF_CURRXYWH, &curr_area);
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_CONTENT, &gemtk_free_area);
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_WORK, &gemtk_work_area);
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_TOOLBAR, &gemtk_toolbar_area);
+ slid = gemtk_wm_get_scroll_info(win);
+
+ printf ("GEMTK Window: %p (AES handle: %d)\n", win, win->handle);
+ printf ("Title: %s\n", title);
+ GEMTK_DBG_GRECT ("WF_WORKXYWH: \n", &work_area)
+ GEMTK_DBG_GRECT ("WF_CURRXYWH: \n", &curr_area)
+ GEMTK_DBG_GRECT ("GEMTK_WM_AREA_CONTENT:\n", &gemtk_free_area)
+ GEMTK_DBG_GRECT ("GEMTK_WM_AREA_WORK:\n", &gemtk_work_area)
+ GEMTK_DBG_GRECT ("GEMTK_WM_AREA_TOOLBAR:\n", &gemtk_toolbar_area)
+ printf ("Slider X pos: %d\n", slid->x_pos);
+ printf ("Slider Y pos: %d\n", slid->y_pos);
+ printf ("Slider X units: %d\n", slid->x_unit_px);
+ printf ("Slider Y units: %d\n", slid->y_unit_px);
+
+
+#undef DBG_GRECT
+};
+
+/**
+* Check's if the pointer is managed by the guiwin API.
+*/
+GUIWIN *gemtk_wm_validate_ptr(GUIWIN *win)
+{
+ GUIWIN *g;
+ for( g = winlist; g != NULL; g=g->next ) {
+ DEBUG_PRINT(("guiwin gemtk_wm_validate_ptr check: %p\n", g));
+ if(g == win) {
+ DEBUG_PRINT(("gemtk_wm_validate_ptr valid: %p\n", g));
+ return(g);
+ }
+ }
+ return(NULL);
+}
+
+/**
+* Add the GUIWIN to the list of handled windows.
+*/
+GUIWIN *gemtk_wm_link(GUIWIN *win)
+{
+ /* Make sure the window is not linked: */
+ GUIWIN *win_val = gemtk_wm_validate_ptr(win);
+ if(win_val){
+ DEBUG_PRINT(("GUIWIN %p is already linked!\n", win));
+ return(NULL);
+ }
+
+ if (winlist == NULL) {
+ winlist = win;
+ win->next = NULL;
+ win->prev = NULL;
+ } else {
+ GUIWIN *tmp = winlist;
+ while( tmp->next != NULL ) {
+ tmp = tmp->next;
+ }
+ tmp->next = win;
+ win->prev = tmp;
+ win->next = NULL;
+ }
+ return(win);
+}
+
+/**
+* Remove the GUIWIN from the list of handled windows.
+*/
+GUIWIN *gemtk_wm_unlink(GUIWIN *win)
+{
+ GUIWIN * win_val;
+
+ /* Make sure the window is linked: */
+ win_val = gemtk_wm_validate_ptr(win);
+ if (win_val == NULL){
+ DEBUG_PRINT(("GUIWIN %p is not linked!\n", win));
+ return(NULL);
+ }
+
+
+ /* unlink the window: */
+ if(win->prev != NULL ) {
+ win->prev->next = win->next;
+ } else {
+ winlist = win->next;
+ }
+ if (win->next != NULL) {
+ win->next->prev = win->prev;
+ }
+ return(win);
+}
+
+/**
+* Remove an GUIWIN from the list of managed windows and free the GUIWIN.
+* Call this when the AES window is closed or deleted.
+*/
+short gemtk_wm_remove(GUIWIN *win)
+{
+ gemtk_wm_unlink(win);
+ DEBUG_PRINT(("guiwin free: %p\n", win));
+ free(win);
+ return(0);
+}
+
+/** Calculate & get a well known area within the GUIWIN.
+* \param win The GUIWIN ptr.
+* \param mode Specifies the area to retrieve.
+* \param dest The calculated rectangle.
+*/
+void gemtk_wm_get_grect(GUIWIN *win, enum guwin_area_e mode, GRECT *dest)
+{
+
+ assert(win != NULL);
+
+ wind_get_grect(win->handle, WF_WORKXYWH, dest);
+
+ if (mode == GEMTK_WM_AREA_CONTENT) {
+ GRECT tb_area;
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_TOOLBAR, &tb_area);
+ if (win->flags & GEMTK_WM_FLAG_HAS_VTOOLBAR) {
+ dest->g_x += tb_area.g_w;
+ dest->g_w -= tb_area.g_w;
+ }
+ else {
+ dest->g_y += tb_area.g_h;
+ dest->g_h -= tb_area.g_h;
+ }
+ } else if (mode == GEMTK_WM_AREA_TOOLBAR) {
+ if (win->toolbar) {
+ if (win->flags & GEMTK_WM_FLAG_HAS_VTOOLBAR) {
+ dest->g_w = win->toolbar_size;
+ } else {
+ dest->g_h = win->toolbar_size;
+ }
+ }
+ else {
+ dest->g_w = 0;
+ dest->g_h = 0;
+ }
+ }
+}
+
+
+/**
+* Scroll the content area (GEMTK_WM_AREA_CONTENT) in the specified dimension
+* (GEMTK_WM_VSLIDER, GEMTK_WM_HSLIDER)
+* \param win The GUIWIN
+* \param orientation GEMTK_WM_VSLIDER or GEMTK_WM_HSLIDER
+* \param units the amout to scroll (pass negative values to scroll up)
+* \param refresh Sliders will be updated when this flag is set
+*/
+void gemtk_wm_scroll(GUIWIN *win, short orientation, int units, bool refresh)
+{
+ struct gemtk_wm_scroll_info_s *slid = gemtk_wm_get_scroll_info(win);
+ int oldpos = 0, newpos = 0, vis_units=0, pix = 0;
+ int abs_pix = 0;
+ GRECT *redraw=NULL, g, g_ro;
+
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_CONTENT, &g);
+ g_ro = g;
+
+ if (orientation == GEMTK_WM_VSLIDER) {
+ pix = units*slid->y_unit_px;
+ abs_pix = abs(pix);
+ oldpos = slid->y_pos;
+ vis_units = g.g_h/slid->y_unit_px;
+ newpos = slid->y_pos = MIN(slid->y_units-vis_units,
+ MAX(0, slid->y_pos+units));
+ if(newpos < 0) {
+ newpos = slid->y_pos = 0;
+ }
+ if(oldpos == newpos)
+ return;
+
+ if (units>=vis_units || gemtk_wm_has_intersection(win, &g_ro)) {
+ // send complete redraw
+ redraw = &g_ro;
+ } else {
+ // only adjust ypos when scrolling down:
+ if(pix < 0 ) {
+ // blit screen area:
+ g.g_h -= abs_pix;
+ move_rect(win, &g, 0, abs_pix);
+ g.g_y = g_ro.g_y;
+ g.g_h = abs_pix;
+ redraw = &g;
+ } else {
+ // blit screen area:
+ g.g_y += abs_pix;
+ g.g_h -= abs_pix;
+ move_rect(win, &g, 0, -abs_pix);
+ g.g_y = g_ro.g_y + g_ro.g_h - abs_pix;
+ g.g_h = abs_pix;
+ redraw = &g;
+ }
+ }
+ } else {
+ pix = units*slid->x_unit_px;
+ abs_pix = abs(pix);
+ oldpos = slid->x_pos;
+ vis_units = g.g_w/slid->x_unit_px;
+ newpos = slid->x_pos = MIN(slid->x_units-vis_units,
+ MAX(0, slid->x_pos+units));
+
+ if(newpos < 0) {
+ newpos = slid->x_pos = 0;
+ }
+
+ if(oldpos == newpos)
+ return;
+ if (units>=vis_units || gemtk_wm_has_intersection(win, &g_ro)) {
+ // send complete redraw
+ redraw = &g_ro;
+ } else {
+ // only adjust ypos when scrolling down:
+ if(pix < 0 ) {
+ // blit screen area:
+ g.g_w -= abs_pix;
+ move_rect(win, &g, abs_pix, 0);
+ g.g_x = g_ro.g_x;
+ g.g_w = abs_pix;
+ redraw = &g;
+ } else {
+ // blit screen area:
+ g.g_x += abs_pix;
+ g.g_w -= abs_pix;
+ move_rect(win, &g, -abs_pix, 0);
+ g.g_x = g_ro.g_x + g_ro.g_w - abs_pix;
+ g.g_w = abs_pix;
+ redraw = &g;
+ }
+ }
+ }
+
+ if (refresh) {
+ gemtk_wm_update_slider(win, orientation);
+ }
+
+ if ((redraw != NULL) && (redraw->g_h > 0)) {
+ gemtk_wm_exec_redraw(win, redraw);
+ }
+}
+
+/**
+* Refresh the sliders of the window.
+* \param win the GUIWIN
+* \param mode bitmask, valid bits: GEMTK_WM_VSLIDER, GEMTK_WM_HSLIDER
+*/
+bool gemtk_wm_update_slider(GUIWIN *win, short mode)
+{
+ GRECT viewport;
+ struct gemtk_wm_scroll_info_s * slid;
+ unsigned long size, pos;
+ int old_x, old_y;
+
+ short handle = gemtk_wm_get_handle(win);
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_CONTENT, &viewport);
+ slid = gemtk_wm_get_scroll_info(win);
+
+ old_x = slid->x_pos;
+ old_y = slid->y_pos;
+
+ // TODO: check if the window has sliders of that direction...?
+
+ if((mode & GEMTK_WM_VSLIDER) && (slid->y_unit_px > 0)) {
+ if ( slid->y_units < (long)viewport.g_h/slid->y_unit_px) {
+ size = 1000L;
+ } else
+ size = MAX( 50L, (unsigned long)viewport.g_h*1000L/
+ (unsigned long)(slid->y_unit_px*slid->y_units));
+ wind_set(handle, WF_VSLSIZE, (int)size, 0, 0, 0);
+
+ if (slid->y_units > (long)viewport.g_h/slid->y_unit_px) {
+ pos = (unsigned long)slid->y_pos *1000L/
+ (unsigned long)(slid->y_units-viewport.g_h/slid->y_unit_px);
+ wind_set(handle, WF_VSLIDE, (int)pos, 0, 0, 0);
+ } else if (slid->y_pos) {
+ slid->y_pos = 0;
+ wind_set(handle, WF_VSLIDE, 0, 0, 0, 0);
+ }
+ }
+ if((mode & GEMTK_WM_HSLIDER) && (slid->x_unit_px > 0)) {
+ if ( slid->x_units < (long)viewport.g_w/slid->x_unit_px)
+ size = 1000L;
+ else
+ size = MAX( 50L, (unsigned long)viewport.g_w*1000L/
+ (unsigned long)(slid->x_unit_px*slid->x_units));
+ wind_set(handle, WF_HSLSIZE, (int)size, 0, 0, 0);
+
+ if( slid->x_units > (long)viewport.g_w/slid->x_unit_px) {
+ pos = (unsigned long)slid->x_pos*1000L/
+ (unsigned long)(slid->x_units-viewport.g_w/slid->x_unit_px);
+ wind_set(handle, WF_HSLIDE, (int)pos, 0, 0, 0);
+ } else if (slid->x_pos) {
+ slid->x_pos = 0;
+ wind_set(handle, WF_HSLIDE, 0, 0, 0, 0);
+ }
+ }
+
+ if(old_x != slid->x_pos || old_y != slid->y_pos) {
+ return(true);
+ }
+ return(false);
+}
+
+/**
+* Return the AES handle for the GUIWIN.
+*/
+short gemtk_wm_get_handle(GUIWIN *win)
+{
+ return(win->handle);
+}
+
+/**
+* Return the VDI handle for an GUIWIN.
+*/
+VdiHdl gemtk_wm_get_vdi_handle(GUIWIN *win)
+{
+ return(v_vdi_h);
+}
+
+/**
+* Returns the state bitmask of the window
+*/
+uint32_t gemtk_wm_get_state(GUIWIN *win)
+{
+ return(win->state);
+}
+
+/**
+* Set and new event handler function.
+*/
+void gemtk_wm_set_event_handler(GUIWIN *win,gemtk_wm_event_handler_f cb)
+{
+ win->handler_func = cb;
+}
+
+/**
+* Configure the window so that it shows an toolbar or at least reserves
+* an area to draw an toolbar.
+* \param win The GUIWIN
+* \param toolbar the AES form
+* \param idx index within the toolbar tree (0 in most cases...)
+* \param flags optional configuration flags
+*/
+//TODO: document flags
+void gemtk_wm_set_toolbar(GUIWIN *win, OBJECT *toolbar, short idx, uint32_t flags)
+{
+ win->toolbar = toolbar;
+ win->toolbar_idx = idx;
+ win->toolbar_edit_obj = -1;
+ if (flags & GEMTK_WM_FLAG_HAS_VTOOLBAR) {
+ win->flags |= GEMTK_WM_FLAG_HAS_VTOOLBAR;
+ win->toolbar_size = win->toolbar[idx].ob_width;
+ }
+ else {
+ win->toolbar_size = win->toolbar[idx].ob_height;
+ }
+ gemtk_wm_set_toolbar_redraw_func(win, std_toolbar_redraw);
+}
+
+/** Update width/height of the toolbar region
+* \param win the GUIWIN
+* \param s the width or height, depending on the flag GEMTK_WM_FLAG_HAS_VTOOLBAR
+*/
+void gemtk_wm_set_toolbar_size(GUIWIN *win, uint16_t s)
+{
+ win->toolbar_size = s;
+}
+
+short gemtk_wm_get_toolbar_edit_obj(GUIWIN *win)
+{
+ return(win->toolbar_edit_obj);
+}
+
+/** Set the current active edit object */
+void gemtk_wm_set_toolbar_edit_obj(GUIWIN *win, uint16_t obj, short kreturn)
+{
+ short edit_idx;
+
+ DEBUG_PRINT(("%s, win: %p, obj: %d, kret: %d\n", __FUNCTION__,
+ win, obj, kreturn));
+
+ if (obj != win->toolbar_edit_obj) {
+
+ DEBUG_PRINT(("%s, current edit obj: %d\n", __FUNCTION__,
+ win->toolbar_edit_obj));
+
+ if(win->toolbar_edit_obj != -1) {
+ objc_wedit(win->toolbar, win->toolbar_edit_obj, kreturn, &edit_idx,
+ EDEND, win->handle);
+ }
+
+ win->toolbar_edit_obj = obj;
+
+ objc_wedit(win->toolbar, win->toolbar_edit_obj, kreturn, &edit_idx,
+ EDINIT, win->handle);
+ } else {
+ DEBUG_PRINT(("%s, nothing to do!\n", __FUNCTION__));
+ }
+}
+
+/** Set an custom toolbar redraw function which is called instead of
+* default drawing routine.
+* \param win the GUIWIN
+* \param func the custom redraw function
+*/
+void gemtk_wm_set_toolbar_redraw_func(GUIWIN *win, gemtk_wm_redraw_f func)
+{
+ win->toolbar_redraw_func = func;
+}
+
+/**
+* Attach an arbitary pointer to the GUIWIN
+*/
+void gemtk_wm_set_user_data(GUIWIN *win, void *data)
+{
+ win->user_data = data;
+}
+
+/**
+* Retrieve the user_data pointer attached to the GUIWIN.
+*/
+void *gemtk_wm_get_user_data(GUIWIN *win)
+{
+ return(win->user_data);
+}
+
+/** Get the scroll management structure for a GUIWIN
+*/
+struct gemtk_wm_scroll_info_s *gemtk_wm_get_scroll_info(GUIWIN *win) {
+ return(&win->scroll_info);
+}
+
+/**
+* Get the amount of content dimensions within the window
+* which is calculated by using the scroll_info attached to the GUIWIN.
+*/
+void gemtk_wm_set_scroll_grid(GUIWIN * win, short x, short y)
+{
+ struct gemtk_wm_scroll_info_s *slid = gemtk_wm_get_scroll_info(win);
+
+ assert(slid != NULL);
+
+ slid->y_unit_px = x;
+ slid->x_unit_px = y;
+}
+
+
+/** Set the size of the content measured in content units
+* \param win the GUIWIN
+* \param x horizontal size
+* \param y vertical size
+*/
+void gemtk_wm_set_content_units(GUIWIN * win, short x, short y)
+{
+ struct gemtk_wm_scroll_info_s *slid = gemtk_wm_get_scroll_info(win);
+
+ assert(slid != NULL);
+
+ slid->x_units = x;
+ slid->y_units = y;
+}
+
+/** Send an Message to a GUIWIN using AES message pipe
+* \param win the GUIWIN which shall receive the message
+* \param msg_type the WM_ message definition
+* \param a the 4th parameter to appl_write
+* \param b the 5th parameter to appl_write
+* \param c the 6th parameter to appl_write
+* \param d the 7th parameter to appl_write
+*/
+void gemtk_wm_send_msg(GUIWIN *win, short msg_type, short a, short b, short c,
+ short d)
+{
+ short msg[8];
+
+ msg[0] = msg_type;
+ msg[1] = gl_apid;
+ msg[2] = 0;
+ msg[3] = (win != NULL) ? win->handle : 0;
+ msg[4] = a;
+ msg[5] = b;
+ msg[6] = c;
+ msg[7] = d;
+
+ appl_write(gl_apid, 16, &msg);
+}
+
+/** Directly execute an Message to a GUIWIN using the internal dispatcher function.
+* This only works for managed windows which have the,
+ GEMTK_WM_FLAG_PREPROC_WM flag set.
+ This call does not send any AES messages.
+* \param win the GUIWIN which shall receive the message
+* \param msg_type the WM_ message definition
+* \param a the 4th parameter to appl_write
+* \param b the 5th parameter to appl_write
+* \param c the 6th parameter to appl_write
+* \param d the 7th parameter to appl_write
+*/
+short gemtk_wm_exec_msg(GUIWIN *win, short msg_type, short a, short b, short c,
+ short d)
+{
+ short msg[8], retval;
+
+ EVMULT_OUT event_out;
+
+ msg[0] = msg_type;
+ msg[1] = gl_apid;
+ msg[2] = 0;
+ msg[3] = win->handle;
+ msg[4] = a;
+ msg[5] = b;
+ msg[6] = c;
+ msg[7] = d;
+
+ event_out.emo_events = MU_MESAG;
+ retval = preproc_wm(win, &event_out, msg);
+ if (retval == 0 || (win->flags & GEMTK_WM_FLAG_PREPROC_WM) != 0){
+ retval = win->handler_func(win, &event_out, msg);
+ }
+
+ return(retval);
+}
+
+void gemtk_wm_exec_redraw(GUIWIN *win, GRECT *area)
+{
+ GRECT work;
+
+ if (area == NULL) {
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_WORK, &work);
+ if (work.g_w < 1 || work.g_h < 1) {
+ if (win->toolbar != NULL) {
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_TOOLBAR, &work);
+ if (work.g_w < 1 || work.g_h < 1) {
+ return;
+ }
+ }
+ }
+ area = &work;
+ }
+
+ gemtk_wm_exec_msg(win, WM_REDRAW, area->g_x, area->g_y, area->g_w,
+ area->g_h);
+}
+
+/** Attach an AES FORM to the GUIWIN, similar feature like the toolbar
+*/
+void gemtk_wm_set_form(GUIWIN *win, OBJECT *tree, short index)
+{
+ DEBUG_PRINT(("Setting form %p (%d) for window %p\n", tree, index, win));
+ win->form = tree;
+ win->form_edit_obj = -1;
+ win->form_focus_obj = -1;
+ win->form_idx = index;
+}
+
+/** Checks if a GUIWIN is overlapped by other windows.
+*/
+bool gemtk_wm_has_intersection(GUIWIN *win, GRECT *work)
+{
+ GRECT area, mywork;
+ bool retval = true;
+
+ if (work == NULL) {
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_CONTENT, &mywork);
+ work = &mywork;
+ }
+
+ wind_get_grect(win->handle, WF_FIRSTXYWH, &area);
+ while (area.g_w) {
+ //GRECT * ptr = &area;
+ if (RC_WITHIN(work, &area)) {
+ retval = false;
+ }
+ wind_get_grect(win->handle, WF_NEXTXYWH, &area);
+ }
+
+ return(retval);
+}
+
+/** Execute an toolbar redraw
+* \param msg specifies the AES message which initiated the redraw, or 0 when
+* the function was called without AES message context.
+*/
+void gemtk_wm_toolbar_redraw(GUIWIN *gw, uint16_t msg, GRECT *clip)
+{
+ GRECT tb_area, tb_area_ro;
+
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_TOOLBAR, &tb_area_ro);
+
+ if(clip == NULL) {
+ clip = &tb_area_ro;
+ }
+
+ tb_area = tb_area_ro;
+
+ if (rc_intersect(clip, &tb_area)) {
+ gw->toolbar_redraw_func(gw, msg, &tb_area);
+ }
+}
+
+/** Execute FORM redraw
+*/
+void gemtk_wm_form_redraw(GUIWIN *gw, GRECT *clip)
+{
+ GRECT area, area_ro, g;
+ struct gemtk_wm_scroll_info_s *slid;
+ //int new_x, new_y, old_x, old_y;
+
+ DEBUG_PRINT(("gemtk_wm_form_redraw\n"));
+
+ // calculate form coordinates, include scrolling:
+ gemtk_wm_get_grect(gw, GEMTK_WM_AREA_CONTENT, &area_ro);
+ slid = gemtk_wm_get_scroll_info(gw);
+
+ // Update form position:
+ gw->form[gw->form_idx].ob_x = area_ro.g_x - (slid->x_pos * slid->x_unit_px);
+ gw->form[gw->form_idx].ob_y = area_ro.g_y - (slid->y_pos * slid->y_unit_px);
+
+ if(clip == NULL) {
+ clip = &area_ro;
+ }
+
+ area = area_ro;
+
+ /* Walk the AES rectangle list and redraw the visible areas of the window:*/
+ if(rc_intersect(clip, &area)) {
+
+ wind_get_grect(gw->handle, WF_FIRSTXYWH, &g);
+ while (g.g_h > 0 || g.g_w > 0) {
+ if(rc_intersect(&area, &g)) {
+ objc_draw(gw->form, gw->form_idx, 8, g.g_x, g.g_y,
+ g.g_w, g.g_h);
+
+ }
+ wind_get_grect(gw->handle, WF_NEXTXYWH, &g);
+ }
+ }
+}
+
+
+/** Fill the content area with white color
+*/
+void gemtk_wm_clear(GUIWIN *win)
+{
+ GRECT area, g;
+ short pxy[4];
+ VdiHdl vh;
+
+ vh = gemtk_wm_get_vdi_handle(win);
+
+ if(win->state & GEMTK_WM_STATUS_ICONIFIED) {
+ // also clear the toolbar area when iconified:
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_WORK, &area);
+ } else {
+ gemtk_wm_get_grect(win, GEMTK_WM_AREA_CONTENT, &area);
+ }
+
+ vsf_interior(vh, FIS_SOLID);
+ vsf_color(vh, 0);
+ vswr_mode(vh, MD_REPLACE);
+ wind_get_grect(win->handle, WF_FIRSTXYWH, &g);
+ while (g.g_h > 0 || g.g_w > 0) {
+ if(rc_intersect(&area, &g)) {
+ pxy[0] = g.g_x;
+ pxy[1] = g.g_y;
+ pxy[2] = g.g_x+g.g_w-1;
+ pxy[3] = g.g_y+g.g_h-1;
+ v_bar(vh, pxy);
+ }
+ wind_get_grect(win->handle, WF_NEXTXYWH, &g);
+ }
+}
diff --git a/frontends/atari/gemtk/guiwin.h b/frontends/atari/gemtk/guiwin.h
new file mode 100644
index 000000000..6daf16ca9
--- /dev/null
+++ b/frontends/atari/gemtk/guiwin.h
@@ -0,0 +1,4 @@
+#ifndef OPKG_GUI_GUIWIN_H
+#define OPKG_GUI_GUIWIN_
+
+#endif /* OPKG_GUIWIN_H */
diff --git a/frontends/atari/gemtk/msgbox.c b/frontends/atari/gemtk/msgbox.c
new file mode 100644
index 000000000..89ca75a46
--- /dev/null
+++ b/frontends/atari/gemtk/msgbox.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2013 Ole Loots <ole@monochrom.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gem.h>
+#include "gemtk.h"
+
+#ifndef min
+# define min(x,y) ((x<y) ? x : y )
+#endif
+
+/***
+ * Display an message box
+ *
+ * \param type Valid values: GEMTK_MSG_BOX_CONFIRM, GEMTK_MSG_BOX_ALERT
+ * \param msg The message / query to display
+ * \return 0 on "No"
+ *
+ */
+short gemtk_msg_box_show(short type, const char * msg)
+{
+ #define GEMTK_MSG_BOX_STR_SIZE 256
+ short retval=0, i=0, z=0, l=0;
+ char c;
+ int len_msg = strlen(msg);
+
+ // TODO: localize strings
+ const char *str_yes = "Yes";
+ const char *str_no = "No";
+ const char *str_ok = "OK";
+ char msg_box_str[GEMTK_MSG_BOX_STR_SIZE];
+ char *dst = msg_box_str;
+
+ memset(msg_box_str, 0, GEMTK_MSG_BOX_STR_SIZE);
+
+ strncat(msg_box_str, "[1]", GEMTK_MSG_BOX_STR_SIZE);
+ strncat(msg_box_str, "[", GEMTK_MSG_BOX_STR_SIZE);
+
+ dst = msg_box_str + strlen(msg_box_str);
+
+ for (i=0; i<min(len_msg,40*5); i++) {
+
+ c = msg[i];
+
+ if(c==0)
+ break;
+
+ if (z==40) {
+ if(l==4){
+ break;
+ }
+ z = 0;
+ l++;
+ *dst = (char)'|';
+ dst++;
+ }
+
+ if ((c=='\r' || c=='\n') && *dst != '|') {
+ if(l==4){
+ break;
+ }
+ z = 0;
+ l++;
+ *dst = '|';
+ dst++;
+ }
+ else {
+ z++;
+ *dst = c;
+ dst++;
+ }
+ }
+ strncat(msg_box_str, "][", GEMTK_MSG_BOX_STR_SIZE);
+
+ if(type == GEMTK_MSG_BOX_CONFIRM){
+ strncat(msg_box_str, str_yes, GEMTK_MSG_BOX_STR_SIZE);
+ strncat(msg_box_str, "|", GEMTK_MSG_BOX_STR_SIZE);
+ strncat(msg_box_str, str_no, GEMTK_MSG_BOX_STR_SIZE);
+ } else {
+ strncat(msg_box_str, str_ok, GEMTK_MSG_BOX_STR_SIZE);
+ }
+ strncat(msg_box_str, "]", GEMTK_MSG_BOX_STR_SIZE);
+
+ retval = form_alert(type, msg_box_str);
+ if(type == GEMTK_MSG_BOX_CONFIRM){
+ if(retval != 1){
+ retval = 0;
+ }
+ }
+ return(retval);
+
+ #undef GEMTK_MSG_BOX_STR_SIZE
+}
diff --git a/frontends/atari/gemtk/msgbox.h b/frontends/atari/gemtk/msgbox.h
new file mode 100644
index 000000000..7a46900ef
--- /dev/null
+++ b/frontends/atari/gemtk/msgbox.h
@@ -0,0 +1,5 @@
+#ifndef GUIMSG_H_INCLUDED
+#define GUIMSG_H_INCLUDED
+
+
+#endif // GUIMSG_H_INCLUDED
diff --git a/frontends/atari/gemtk/objc.c b/frontends/atari/gemtk/objc.c
new file mode 100644
index 000000000..855413e0b
--- /dev/null
+++ b/frontends/atari/gemtk/objc.c
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2013 Ole Loots <ole@monochrom.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Module Description:
+ *
+ * AES Object tree tools.
+ *
+ */
+
+#include <assert.h>
+#include "gemtk.h"
+
+char *gemtk_obj_get_text(OBJECT * tree, short idx)
+{
+ static char p[]="";
+
+ switch (tree[idx].ob_type & 0x00FF) {
+ case G_BUTTON:
+ case G_STRING:
+ case G_TITLE:
+ return( tree[idx].ob_spec.free_string);
+ case G_TEXT:
+ case G_BOXTEXT:
+ case G_FTEXT:
+ case G_FBOXTEXT:
+ return (tree[idx].ob_spec.tedinfo->te_ptext);
+ case G_ICON:
+ case G_CICON:
+ return (tree[idx].ob_spec.iconblk->ib_ptext);
+ break;
+
+ default:
+ break;
+ }
+ return (p);
+}
+
+static void set_text(OBJECT *obj, short idx, char * text, int len)
+{
+ char spare[255];
+
+ if( len > 254 )
+ len = 254;
+ if( text != NULL ) {
+ strncpy(spare, text, 254);
+ } else {
+ strcpy(spare, "");
+ }
+
+ set_string(obj, idx, spare);
+}
+
+char gemtk_obj_set_str_safe(OBJECT * tree, short idx, const char *txt)
+{
+ char spare[204];
+ short type = 0;
+ short maxlen = 0;
+
+
+ type = (tree[idx].ob_type & 0xFF);
+ if (type == G_FTEXT || type == G_FBOXTEXT) {
+ TEDINFO *ted = ((TEDINFO *)get_obspec(tree, idx));
+ maxlen = ted->te_tmplen+1;
+ if (maxlen > 200) {
+ maxlen = 200;
+ } else if (maxlen < 0) {
+ maxlen = 0;
+ }
+ } else {
+ assert((type == G_FTEXT) || (type == G_FBOXTEXT));
+ }
+
+ snprintf(spare, maxlen, "%s", txt);
+ set_string(tree, idx, spare);
+
+ return(0);
+}
+
+OBJECT *gemtk_obj_get_tree(int idx)
+{
+
+ OBJECT *tree;
+
+ rsrc_gaddr(R_TREE, idx, &tree);
+
+ return tree;
+}
+
+bool gemtk_obj_is_inside(OBJECT * tree, short obj, GRECT *area)
+{
+ GRECT obj_screen;
+ bool ret = false;
+
+ objc_offset(tree, obj, &obj_screen.g_x, &obj_screen.g_y);
+ obj_screen.g_w = tree[obj].ob_width;
+ obj_screen.g_h = tree[obj].ob_height;
+
+ ret = RC_WITHIN(&obj_screen, area);
+
+ return(ret);
+}
+
+GRECT * gemtk_obj_screen_rect(OBJECT * tree, short obj)
+{
+ static GRECT obj_screen;
+
+ get_objframe(tree, obj, &obj_screen);
+
+ return(&obj_screen);
+}
+
+
+void gemtk_obj_mouse_sprite(OBJECT *tree, int index)
+{
+ MFORM mform;
+ int dum;
+
+ if ((tree[index].ob_type & 0xFF) != G_ICON)
+ return;
+
+ dum = tree[index].ob_spec.iconblk->ib_char;
+ mform . mf_nplanes = 1;
+ mform . mf_fg = (dum>>8)&0x0F;
+ mform . mf_bg = dum>>12;
+ mform . mf_xhot = 0; /* to prevent the mform to "jump" on the */
+ mform . mf_yhot = 0; /* screen (zebulon rules!) */
+
+ for( dum = 0; dum<16; dum ++) {
+ mform . mf_mask[dum] = tree[index].ob_spec.iconblk->ib_pmask[dum];
+ mform . mf_data[dum] = tree[index].ob_spec.iconblk->ib_pdata[dum];
+ }
+ graf_mouse(USER_DEF, &mform);
+}
+
+
+/*
+ * gemtk_obj_tree_copy
+ *
+ * Copy a complete object-tree including all substructures (optional).
+ *
+ * CAUTION: The object-tree *must* have the LASTOB-flag (0x20) set in
+ * it's physically last member.
+ *
+ * BUG: Up to now tree_copy won't copy the color-icon-structure,
+ * because I'm too lazy ;) Maybe I'll do that one day. If you need it
+ * urgently, contact me and force me to work... Btw, this doesn't mean
+ * that G_CICONs won't be copied at all, but the copied tree will
+ * share the CICONBLKs with the original.
+ *
+ * Input:
+ * tree: Pointer to tree which should be copied
+ * what: Specifies what substructures should be copied, too (see the
+ * C_xxx-definitions in tree-copy.h for details)
+ *
+ * Output:
+ * NULL: Tree couldn't be copied (due to lack of memory)
+ * otherwise: Pointer to copied tree, use free to dealloc it's memory
+ */
+OBJECT *gemtk_obj_tree_copy(OBJECT *tree)
+{
+ int16_t i, objects;
+ size_t to_malloc, size;
+ OBJECT *new_tree;
+ char *area;
+
+ /* Calculate the number of bytes we need for the new tree */
+ to_malloc = (size_t) 0;
+ for (i = 0;;) {
+
+ /* Size of the OBJECT-structure itself */
+ to_malloc += sizeof(OBJECT);
+
+ switch (tree[i].ob_type & 0xff) {
+ case G_TEXT:
+ case G_BOXTEXT:
+ case G_FTEXT:
+ case G_FBOXTEXT:
+ /* Size of a TEDINFO-structure */
+ to_malloc += sizeof(TEDINFO);
+
+ /* Sizes of the strings in the TEDINFO-structure */
+ to_malloc += (size_t)tree[i].ob_spec.tedinfo->te_txtlen;
+ to_malloc += (size_t)tree[i].ob_spec.tedinfo->te_txtlen;
+ to_malloc += (size_t)tree[i].ob_spec.tedinfo->te_tmplen;
+ break;
+
+ case G_IMAGE:
+
+ /* Size of the BITBLK-structure */
+ to_malloc += sizeof(BITBLK);
+
+ /* Size of the image-data in the BITBLK-structure */
+ to_malloc += (size_t)((int32_t)tree[i].ob_spec.bitblk->bi_wb *
+ (int32_t)tree[i].ob_spec.bitblk->bi_hl);
+
+ break;
+
+ case G_USERDEF:
+ /* Size of the USERBLK-structure */
+ to_malloc += sizeof(USERBLK);
+ break;
+
+ case G_BUTTON:
+ case G_STRING:
+ case G_TITLE:
+ /* Size of the string (with one null character at the end) */
+ to_malloc += strlen(tree[i].ob_spec.free_string) + 1L;
+ break;
+
+ case G_ICON:
+ /* Size of the ICONBLK-structure */
+ to_malloc += sizeof(BITBLK);
+
+ /* Sizes of icon-data, icon-mask and icon-text */
+ to_malloc += (size_t)((int32_t)tree[i].ob_spec.iconblk->ib_wicon *
+ (int32_t)tree[i].ob_spec.iconblk->ib_hicon /
+ 4L + 1L +
+ (int32_t)strlen(tree[i].ob_spec.iconblk->ib_ptext));
+
+ break;
+ }
+
+ /* If the size is odd, make it even */
+ if ((long)to_malloc & 1)
+ to_malloc++;
+
+ /* Exit if we've reached the last object in the tree */
+ if (tree[i].ob_flags & OF_LASTOB)
+ break;
+
+ i++;
+ }
+
+ objects = i + 1;
+
+ /* If there's not enough memory left for the new tree, return NULL */
+ if ((new_tree = (OBJECT *)calloc(1, to_malloc)) == NULL) {
+ return(NULL);
+ }
+
+ /*
+ * area contains a pointer to the area where we copy the structures to
+ */
+ area = (char *)((int32_t)new_tree+(int32_t)objects*(int32_t)sizeof(OBJECT));
+
+ for (i = 0; i < objects; i++) {
+
+ /* Copy the contents of the OBJECT-structure */
+ new_tree[i] = tree[i];
+
+ /* This was added to assure true copies of the object type */
+ new_tree[i].ob_type = tree[i].ob_type;
+
+ switch (tree[i].ob_type & 0xff) {
+ case G_TEXT:
+ case G_BOXTEXT:
+ case G_FTEXT:
+ case G_FBOXTEXT:
+
+ /* Copy the contents of the TEDINFO-structure */
+ *(TEDINFO *)area = *tree[i].ob_spec.tedinfo;
+ new_tree[i].ob_spec.tedinfo = (TEDINFO *)area;
+ area += sizeof(TEDINFO);
+
+ /* Copy the strings in the TEDINFO-structure */
+ strncpy(area, tree[i].ob_spec.tedinfo->te_ptext,
+ tree[i].ob_spec.tedinfo->te_txtlen);
+ new_tree[i].ob_spec.tedinfo->te_ptext = area;
+ area += tree[i].ob_spec.tedinfo->te_txtlen;
+ strncpy(area, tree[i].ob_spec.tedinfo->te_ptmplt,
+ tree[i].ob_spec.tedinfo->te_tmplen);
+ new_tree[i].ob_spec.tedinfo->te_ptmplt = area;
+ area += tree[i].ob_spec.tedinfo->te_tmplen;
+ strncpy(area, tree[i].ob_spec.tedinfo->te_pvalid,
+ tree[i].ob_spec.tedinfo->te_txtlen);
+ new_tree[i].ob_spec.tedinfo->te_pvalid = area;
+ area += tree[i].ob_spec.tedinfo->te_txtlen;
+
+ break;
+
+ case G_IMAGE:
+
+ /* Copy the contents of the BITBLK-structure */
+ *(BITBLK *)area = *tree[i].ob_spec.bitblk;
+ new_tree[i].ob_spec.bitblk = (BITBLK *)area;
+ area += sizeof(BITBLK);
+
+ /* Copy the image-data */
+ size = (size_t)((int32_t)tree[i].ob_spec.bitblk->bi_wb *
+ (int32_t)tree[i].ob_spec.bitblk->bi_hl);
+ memcpy(area, tree[i].ob_spec.bitblk->bi_pdata, size);
+ new_tree[i].ob_spec.bitblk->bi_pdata = (int16_t *)area;
+ area += size;
+
+ break;
+
+ case G_USERDEF:
+
+ /* Copy the contents of the USERBLK-structure */
+ *(USERBLK *)area = *tree[i].ob_spec.userblk;
+ new_tree[i].ob_spec.userblk = (USERBLK *)area;
+ area += sizeof(USERBLK);
+
+ break;
+
+ case G_BUTTON:
+ case G_STRING:
+ case G_TITLE:
+
+ /* Copy the string */
+ size = strlen(tree[i].ob_spec.free_string) + 1L;
+ strcpy(area, tree[i].ob_spec.free_string);
+ new_tree[i].ob_spec.free_string = area;
+ area += size;
+
+ break;
+
+ case G_ICON:
+
+ /* Copy the contents of the ICONBLK-structure */
+ *(ICONBLK *)area = *tree[i].ob_spec.iconblk;
+ new_tree[i].ob_spec.iconblk = (ICONBLK *)area;
+ area += sizeof(ICONBLK);
+
+ size = (size_t)((int32_t)tree[i].ob_spec.iconblk->ib_wicon *
+ (int32_t)tree[i].ob_spec.iconblk->ib_hicon /
+ 8L);
+ /* Copy the mask-data */
+ memcpy(area, tree[i].ob_spec.iconblk->ib_pmask, size);
+ new_tree[i].ob_spec.iconblk->ib_pmask = (int16_t *)area;
+ area += size;
+
+ /* Copy the icon-data */
+ memcpy(area, tree[i].ob_spec.iconblk->ib_pdata, size);
+ new_tree[i].ob_spec.iconblk->ib_pdata = (int16_t *)area;
+ area += size;
+ size = strlen(tree[i].ob_spec.iconblk->ib_ptext) + 1L;
+
+ /* Copy the icon-string */
+ strcpy(area, tree[i].ob_spec.iconblk->ib_ptext);
+ new_tree[i].ob_spec.iconblk->ib_ptext = area;
+ area += size;
+
+ break;
+ }
+
+ /* Assure that area contains an even address */
+ if ((int32_t)area & 1)
+ area++;
+ }
+
+ return(new_tree);
+}
+
+/***
+ * Create a simple OBJECT tree from a list of strings, to be used with menu_popup
+ * OBJECT ownership is passed to caller.
+ * Call gemtk_obj_destroy_popup_tree once the popup isn't needed anymore.
+ *
+ * \param items A list of string to be used as items
+ * \param nitems The number of items in the list
+ * \param selected The text of the selected item
+ * \param horizontal Set to true to render the tree horizontally
+ * \param max_width -1: autodetect width
+ * \param max_heigth -1: autodetect height (set to postive value when using a vertical scrolling popup)
+ * \return a pointer to the new OBJECT tree
+ */
+OBJECT * gemtk_obj_create_popup_tree(const char **items, int nitems,
+ char * selected, bool horizontal,
+ int max_width, int max_height)
+{
+ OBJECT * popup = NULL;
+ int box_width = 0;
+ int box_height = 0;
+ int char_width = 10;
+ int char_height = 16;
+ int item_height; // height of each item
+
+ assert(items != NULL);
+
+ item_height = char_height;
+
+ /* Allocate room for n items and the root G_BOX: */
+ popup = calloc(nitems+1, sizeof(OBJECT));
+ assert(popup != null);
+
+ for (int i=0; i<nitems; i++) {
+
+ int len = strlen(items[i]);
+
+ if (horizontal && (max_width<1)) {
+ box_width += (len * char_width)+4;
+ }
+ else if (!horizontal){
+ /* Detect max width, used for vertical rendering: */
+ if(len*char_width > box_width){
+ box_width = (len+2) * char_width;
+ }
+ //if (max_height < 1) {
+ box_height += item_height;
+ //}
+ }
+ }
+
+ if (max_width>0){
+ box_width = max_width;
+ }
+
+ if (horizontal) {
+ box_height = item_height;
+ }
+ else if(max_height > 0){
+ // TODO: validate max_height, shrink values larger than screen height
+ //box_height = max_height;
+ }
+
+/*
+ printf("popup height: %d, popup width: %d\n", box_height, box_width);
+*/
+
+ popup[0].ob_next = -1; /**< object's next sibling */
+ popup[0].ob_head = 1; /**< head of object's children */
+ popup[0].ob_tail = nitems; /**< tail of object's children */
+ popup[0].ob_type = G_BOX; /**< type of object */
+ popup[0].ob_flags = OF_FL3DBAK; /**< flags */
+ popup[0].ob_state = OS_NORMAL; /**< state */
+ popup[0].ob_spec.index = (long) 16650496L; /**< object-specific data */
+ popup[0].ob_x = 0; /**< upper left corner of object */
+ popup[0].ob_y = 0; /**< upper left corner of object */
+ popup[0].ob_width = box_width; /**< width of obj */
+ popup[0].ob_height = box_height;
+
+
+
+ /* Add items to popup: */
+ int xpos = 0, ypos = 0;
+
+ for (int i=0; i<nitems; i++) {
+
+ int state = OS_NORMAL;
+ int flags = OF_NONE;
+ int item_width;
+ char * string = calloc(1, strlen(items[i])+3);
+
+ snprintf(string, strlen(items[i])+3, " %s", items[i]);
+
+ if (selected != NULL) {
+ if (strcmp(selected, items[i]) == 0) {
+ state |= OS_CHECKED;
+ }
+ }
+
+ if (i == nitems-1) {
+ flags |= OF_LASTOB;
+ }
+
+ item_width = (horizontal) ? ((int)strlen(items[i])*char_width)+2 : box_width;
+/*
+ printf("addin popup item \"%s\" (w: %d, h: %d, flags: %x) at %d/%d\n", items[i],
+ item_width, item_height, flags,
+ xpos, ypos);
+*/
+
+ popup[i+1].ob_next = ((flags&OF_LASTOB) != 0) ? 0 : i+2; /**< object's next sibling */
+ popup[i+1].ob_head = -1; /**< head of object's children */
+ popup[i+1].ob_tail = -1; /**< tail of object's children */
+ popup[i+1].ob_type = G_STRING; /**< type of object */
+ popup[i+1].ob_flags = flags; /**< flags */
+ popup[i+1].ob_state = state; /**< state */
+ popup[i+1].ob_spec.free_string = string; /**< object-specific data */
+ popup[i+1].ob_x = xpos; /**< upper left corner of object */
+ popup[i+1].ob_y = ypos; /**< upper left corner of object */
+ popup[i+1].ob_width = item_width; /**< width of obj */
+ popup[i+1].ob_height = item_height;
+
+ if (horizontal) {
+ xpos += item_width;
+ }
+ else {
+ ypos += item_height;
+ }
+
+ }
+
+ return(popup);
+}
+
+/***
+ * Free memory of an OBJECT tree created with gemtk_obj_create_popup_tree.
+ *
+ * \param popup The tree to destroy
+ */
+void gemtk_obj_destroy_popup_tree(OBJECT * popup)
+{
+ int i=0;
+
+ while (1) {
+ if (popup[i].ob_type == G_STRING) {
+ free(popup[i+1].ob_spec.free_string);
+ }
+ if((popup[i].ob_flags & OF_LASTOB) != OF_LASTOB){
+ break;
+ }
+ i++;
+ }
+
+ free(popup);
+}
diff --git a/frontends/atari/gemtk/objc.h b/frontends/atari/gemtk/objc.h
new file mode 100644
index 000000000..6fa1072b7
--- /dev/null
+++ b/frontends/atari/gemtk/objc.h
@@ -0,0 +1,7 @@
+#ifndef GEMTK_OBJC_H
+#define GEMTK_OBJC_H
+
+
+
+#endif // GEMTK_OBJC_H
+
diff --git a/frontends/atari/gemtk/redrawslots.c b/frontends/atari/gemtk/redrawslots.c
new file mode 100644
index 000000000..ee5627daf
--- /dev/null
+++ b/frontends/atari/gemtk/redrawslots.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2011 Ole Loots <ole@monochrom.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#define WITH_RECT
+#include "gemtk.h"
+#undef WITH_RECT
+
+void redraw_slots_init(struct s_redrw_slots * slots, short size)
+{
+ // TODO: allocate slots dynamically!
+ slots->size = MIN( MAX_REDRW_SLOTS , size);
+ slots->areas_used = 0;
+}
+
+void redraw_slots_free(struct s_redrw_slots * slots)
+{
+ // TOOD: free areas...
+}
+
+
+static inline bool rect_intersect( struct rect * box1, struct rect * box2 )
+{
+ if (box2->x1 < box1->x0)
+ return false;
+
+ if (box2->y1 < box1->y0)
+ return false;
+
+ if (box2->x0 > box1->x1)
+ return false;
+
+ if (box2->y0 > box1->y1)
+ return false;
+
+ return true;
+}
+
+
+void redraw_slot_schedule_grect(struct s_redrw_slots * slots, GRECT *area,
+ bool force)
+{
+ redraw_slot_schedule(slots, area->g_x, area->g_y,
+ area->g_x + area->g_w, area->g_y + area->g_h, force);
+}
+
+/*
+ schedule redraw coords.
+*/
+void redraw_slot_schedule(struct s_redrw_slots * slots, short x0, short y0,
+ short x1, short y1, bool force)
+{
+ int i = 0;
+ struct rect area;
+
+ area.x0 = x0;
+ area.y0 = y0;
+ area.x1 = x1;
+ area.y1 = y1;
+
+ if (force == false) {
+ for (i=0; i<slots->areas_used; i++) {
+ if (slots->areas[i].x0 <= x0
+ && slots->areas[i].x1 >= x1
+ && slots->areas[i].y0 <= y0
+ && slots->areas[i].y1 >= y1) {
+ /* the area is already queued for redraw */
+ return;
+ } else {
+ if (rect_intersect(&slots->areas[i], &area )) {
+ slots->areas[i].x0 = MIN(slots->areas[i].x0, x0);
+ slots->areas[i].y0 = MIN(slots->areas[i].y0, y0);
+ slots->areas[i].x1 = MAX(slots->areas[i].x1, x1);
+ slots->areas[i].y1 = MAX(slots->areas[i].y1, y1);
+ return;
+ }
+ }
+ }
+ }
+
+ if (slots->areas_used < slots->size) {
+ slots->areas[slots->areas_used].x0 = x0;
+ slots->areas[slots->areas_used].x1 = x1;
+ slots->areas[slots->areas_used].y0 = y0;
+ slots->areas[slots->areas_used].y1 = y1;
+ slots->areas_used++;
+ } else {
+ /*
+ we are out of available slots, merge box with last slot
+ this is dumb... but also a very rare case.
+ */
+ slots->areas[slots->size-1].x0 = MIN(slots->areas[i].x0, x0);
+ slots->areas[slots->size-1].y0 = MIN(slots->areas[i].y0, y0);
+ slots->areas[slots->size-1].x1 = MAX(slots->areas[i].x1, x1);
+ slots->areas[slots->size-1].y1 = MAX(slots->areas[i].y1, y1);
+ }
+done:
+ return;
+}
+
+void redraw_slots_remove_area(struct s_redrw_slots * slots, int i)
+{
+ int x;
+ for(x = i+1; i<slots->areas_used; x++){
+ slots->areas[x-1] = slots->areas[x];
+ }
+ slots->areas_used--;
+}
diff --git a/frontends/atari/gemtk/redrawslots.h b/frontends/atari/gemtk/redrawslots.h
new file mode 100644
index 000000000..9691fb4bc
--- /dev/null
+++ b/frontends/atari/gemtk/redrawslots.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012 Ole Loots <ole@monochrom.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef ATARI_REDRAW_SLOTS_H
+#define ATARI_REDRAW_SLOTS_H
+
+#include <mt_gem.h>
+
+#endif
diff --git a/frontends/atari/gemtk/utils.c b/frontends/atari/gemtk/utils.c
new file mode 100644
index 000000000..63e6330ec
--- /dev/null
+++ b/frontends/atari/gemtk/utils.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2013 Ole Loots <ole@monochrom.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <mt_gem.h>
+#include "gemtk.h"
+
+/* -------------------------------------------------------------------------- */
+/* GEM Utillity functions: */
+/* -------------------------------------------------------------------------- */
+
+unsigned short _systype_v;
+unsigned short _systype (void)
+{
+ int32_t * cptr = NULL;
+ _systype_v = SYS_TOS;
+
+ cptr = (int32_t *)Setexc(0x0168, -1L);
+ if (cptr == NULL ) {
+ return _systype_v; /* stone old TOS without any cookie support */
+ }
+ while (*cptr) {
+ if (*cptr == C_MgMc || *cptr == C_MgMx ) {
+ _systype_v = (_systype_v & ~0xF) | SYS_MAGIC;
+ } else if (*cptr == C_MiNT ) {
+ _systype_v = (_systype_v & ~0xF) | SYS_MINT;
+ } else if (*cptr == C_Gnva /* Gnva */ ) {
+ _systype_v |= SYS_GENEVA;
+ } else if (*cptr == C_nAES /* nAES */ ) {
+ _systype_v |= SYS_NAES;
+ }
+ cptr += 2;
+ }
+ if (_systype_v & SYS_MINT) { /* check for XaAES */
+ short out = 0, u;
+ if (wind_get (0, (((short)'X') <<8)|'A', &out, &u,&u,&u) && out) {
+ _systype_v |= SYS_XAAES;
+ }
+ }
+ return _systype_v;
+}
+
+bool gemtk_rc_intersect_ro(GRECT *a, GRECT *b)
+{
+ GRECT r1, r2;
+
+ r1 = *a;
+ r2 = *b;
+
+ return((bool)rc_intersect(&r1, &r2));
+}
+
+
+typedef struct {
+ char *unshift;
+ char *shift;
+ char *capslock;
+} KEYTAB;
+
+int gemtk_keybd2ascii( int keybd, int shift)
+{
+
+ KEYTAB *key;
+ key = (KEYTAB *)Keytbl( (char*)-1, (char*)-1, (char*)-1);
+ return (shift)?key->shift[keybd>>8]:key->unshift[keybd>>8];
+}
+
+
+void gemtk_clip_grect(VdiHdl vh, GRECT *rect)
+{
+ PXY pxy[2];
+
+ pxy[0].p_x = rect->g_x;
+ pxy[0].p_y = rect->g_y;
+ pxy[1].p_x = pxy[0].p_x + rect->g_w - 1;
+ pxy[1].p_y = pxy[0].p_y + rect->g_h - 1;
+
+ vs_clip_pxy(vh, pxy);
+}
+
+/** Send an Message to a GUIWIN using AES message pipe
+* \param win the GUIWIN which shall receive the message
+* \param msg_type the WM_ message definition
+* \param a the 4th parameter to appl_write
+* \param b the 5th parameter to appl_write
+* \param c the 6th parameter to appl_write
+* \param d the 7th parameter to appl_write
+*/
+void gemtk_send_msg(short msg_type, short data2, short data3, short data4,
+ short data5, short data6, short data7)
+{
+ short msg[8];
+
+ msg[0] = msg_type;
+ msg[1] = gl_apid;
+ msg[2] = data2;
+ msg[3] = data3;
+ msg[4] = data4;
+ msg[5] = data5;
+ msg[6] = data6;
+ msg[7] = data7;
+
+ appl_write(gl_apid, 16, &msg);
+}
+
+
+void gemtk_wind_get_str(short aes_handle, short mode, char *str, int len)
+{
+
+ // TODO: remove or implement function
+
+ if(len>255) {
+ len = 255;
+ }
+
+ memset(str, 0, len);
+ return;
+ /*
+
+ wind_get(aes_handle, mode, (short)(((unsigned long)tmp_str)>>16),
+ (short)(((unsigned long)tmp_str) & 0xffff), 0, 0);
+
+ strncpy(str, tmp_str, len);
+ */
+}
+
+
diff --git a/frontends/atari/gemtk/utils.h b/frontends/atari/gemtk/utils.h
new file mode 100644
index 000000000..7ebbcf228
--- /dev/null
+++ b/frontends/atari/gemtk/utils.h
@@ -0,0 +1,5 @@
+#ifndef UTILS_H_INCLUDED
+#define UTILS_H_INCLUDED
+
+
+#endif // UTILS_H_INCLUDED
diff --git a/frontends/atari/gemtk/vaproto.c b/frontends/atari/gemtk/vaproto.c
new file mode 100644
index 000000000..45e47225c
--- /dev/null
+++ b/frontends/atari/gemtk/vaproto.c
@@ -0,0 +1,170 @@
+#include <limits.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <gem.h>
+
+#include "vaproto.h"
+#include "gemtk.h"
+
+#ifndef NDEBUG
+# define DEBUG_PRINT(x) printf x
+#else
+# define DEBUG_PRINT(x)
+#endif
+
+
+/* Global memory, at least 1024 bytes large: */
+static char *va_helpbuf;
+
+/* Desktop's AES ID: */
+static short av_shell_id = -1;
+
+/* What AV commands can desktop do? */
+static short av_shell_status = 0;
+
+/* The application name used for AV/VA messages: */
+static const char * av_clientname = "gemtk_av_app";
+
+
+static short get_avserver(void)
+{
+ short ret = -100;
+ const char * av_env = getenv("AVSERVER");
+ if (av_env) {
+ char av_envname[9];
+ strncpy(av_envname,av_env, 8);
+ av_envname[8] = '\0';
+ while (strlen (av_envname) < 8) {
+ strcat(av_envname, " ");
+ }
+ ret = appl_find (av_envname);
+ }
+ return ret;
+}
+
+/**
+ * initialitze the AV client API
+ * \param appname Name of the application passed to menu_register()
+ * \return returns 1 on success, otherwise an negative error code.
+ *
+ */
+int gemtk_av_init(const char *appname)
+{
+ short mode = 0x0003 /* prefer TT ram */
+ | 0x0020; /* global accesible */
+
+ if(av_shell_id != -1) {
+ /* Already initialized */
+ return(1);
+ }
+
+ va_helpbuf = (char*)Mxalloc(1024, mode);
+
+ if(va_helpbuf == NULL){
+ gemtk_msg_box_show(GEMTK_MSG_BOX_ALERT, "Could not allocate AV memory!");
+ return(-1);
+ }
+
+ if(appname != NULL){
+ av_clientname = appname;
+ }
+
+ av_shell_id = get_avserver();
+ DEBUG_PRINT(("AV Server ID: %d", av_shell_id));
+
+ gemtk_av_send(AV_PROTOKOLL, NULL, NULL);
+
+ va_helpbuf[0] = '\0';
+}
+
+void gemtk_av_exit(void)
+{
+ if(av_shell_id == -1) {
+ /* Nothing to do */
+ return;
+ }
+
+ if (av_shell_status & AA_EXIT) {
+ /* AV server knows AV_EXIT */
+ gemtk_av_send(AV_EXIT, NULL, NULL);
+ }
+
+ if(va_helpbuf != NULL){
+ free(va_helpbuf);
+ va_helpbuf = NULL;
+ }
+
+ av_shell_id = -1;
+
+}
+
+bool gemtk_av_send (short message, const char * data1, const char * data2)
+{
+ short msg[8];
+ short to_ap_id = av_shell_id;
+
+ /* - 100 to ap id would be no AV server */
+ if (to_ap_id == -100){
+ return false;
+ }
+
+ msg[0] = message;
+ msg[1] = gl_apid;
+ msg[7] = msg[6] = msg[5] = msg[4] = msg[3] = msg[2] = 0;
+
+ switch (message)
+ {
+ case AV_EXIT:
+ msg[3] = gl_apid;
+ break;
+ case AV_PROTOKOLL:
+ msg[3] = VV_START | VV_ACC_QUOTING;
+ *(char **)(msg+6) = strcpy (va_helpbuf, av_clientname);
+ break;
+ case AV_STARTPROG:
+ DEBUG_PRINT(("AV_STARTPROG: %s (%s)\n", data1, data2));
+ *(char **)(msg+3) = strcpy(va_helpbuf, data1);
+ *(char **)(msg+5) = strcpy(va_helpbuf, data2);
+ break;
+ case AV_VIEW:
+ DEBUG_PRINT(("AV_VIEW: %s (%d)\n", data1, (short)data2));
+ *(char **)(msg+3) = strcpy(va_helpbuf, data1);
+ msg[5] = (short)data2;
+ break;
+ default:
+ return false; /* not supported */
+ }
+
+ return (appl_write (to_ap_id, 16, msg) > 0);
+}
+
+bool gemtk_av_dispatch (short msg[8])
+{
+
+ if(av_shell_id == -1)
+ return(false);
+
+ switch (msg[0]) {
+ case VA_PROTOSTATUS :
+ DEBUG_PRINT(("AV STATUS: %d for %d\n", msg[3], msg[1]));
+ if (msg[1] == av_shell_id) {
+ av_shell_status = msg[3];
+ if(av_shell_status & AA_STARTPROG){
+ printf(" AA_STARTPROG\n");
+ }
+ }
+ break;
+
+ default:
+ DEBUG_PRINT(("Unknown AV message: %d", msg[0]));
+ break;
+ }
+
+ return(true);
+}
+
+
diff --git a/frontends/atari/gemtk/vaproto.h b/frontends/atari/gemtk/vaproto.h
new file mode 100644
index 000000000..84e0ecf0b
--- /dev/null
+++ b/frontends/atari/gemtk/vaproto.h
@@ -0,0 +1,121 @@
+#ifndef VAPROTO_H_INCLUDED
+#define VAPROTO_H_INCLUDED
+
+
+#define VAPRO 1
+
+/* AES-Messages */
+
+typedef enum
+{
+ AV_PROTOKOLL = 0x4700,
+ VA_PROTOSTATUS = 0x4701,
+ AV_GETSTATUS = 0x4703,
+ AV_STATUS = 0x4704,
+ VA_SETSTATUS = 0x4705,
+ AV_SENDKEY = 0x4710,
+ VA_START = 0x4711,
+ AV_ASKFILEFONT = 0x4712,
+ VA_FILEFONT = 0x4713,
+ AV_ASKCONFONT = 0x4714,
+ VA_CONFONT = 0x4715,
+ AV_ASKOBJECT = 0x4716,
+ VA_OBJECT = 0x4717,
+ AV_OPENCONSOLE = 0x4718,
+ VA_CONSOLEOPEN = 0x4719,
+ AV_OPENWIND = 0x4720,
+ VA_WINDOPEN = 0x4721,
+ AV_STARTPROG = 0x4722,
+ VA_PROGSTART = 0x4723,
+ AV_ACCWINDOPEN = 0x4724,
+ VA_DRAGACCWIND = 0x4725,
+ AV_ACCWINDCLOSED = 0x4726,
+
+ AV_COPY_DRAGGED = 0x4728,
+ VA_COPY_COMPLETE = 0x4729,
+ AV_PATH_UPDATE = 0x4730,
+ AV_WHAT_IZIT = 0x4732,
+ VA_THAT_IZIT = 0x4733,
+ AV_DRAG_ON_WINDOW = 0x4734,
+ VA_DRAG_COMPLETE = 0x4735,
+ AV_EXIT = 0x4736,
+ AV_STARTED = 0x4738,
+ VA_FONTCHANGED = 0x4739,
+ AV_XWIND = 0x4740,
+ VA_XOPEN = 0x4741,
+
+/* Neue Messages seit dem 26.06.1995 */
+
+ AV_VIEW = 0x4751,
+ VA_VIEWED = 0x4752,
+ AV_FILEINFO = 0x4753,
+ VA_FILECHANGED = 0x4754,
+ AV_COPYFILE = 0x4755,
+ VA_FILECOPIED = 0x4756,
+ AV_DELFILE = 0x4757,
+ VA_FILEDELETED = 0x4758,
+ AV_SETWINDPOS = 0x4759,
+ VA_PATH_UPDATE = 0x4760,
+ VA_HIGH /* HR please always do this! */
+} AV_VA;
+
+
+/* Objekttypen fÂr VA_THAT_IZIT */
+
+enum
+{
+ VA_OB_UNKNOWN,
+ VA_OB_TRASHCAN,
+ VA_OB_SHREDDER,
+ VA_OB_CLIPBOARD,
+ VA_OB_FILE,
+ VA_OB_FOLDER,
+ VA_OB_DRIVE,
+ VA_OB_WINDOW,
+ VA_OB_NOTEPAD,
+ VA_OB_NOTE
+};
+
+typedef enum
+{
+ VV_SETSTATUS = 0x0001,
+ VV_START = 0x0002,
+ VV_STARTED = 0x0004,
+ VV_FONTCHANGED = 0x0008,
+ VV_ACC_QUOTING = 0x0010,
+ VV_PATH_UPDATE = 0x0020
+} av_va_give;
+
+typedef enum
+{ /* mp[3]: */
+ AA_SENDKEY = 0x0001, /* b0: MAGXDESK, THING */
+ AA_ASKFILEFONT = 0x0002, /* b1: THING */
+ AA_ASKCONFONT = 0x0004, /* b2: THING */
+ AA_ASKOBJECT = 0x0008,
+ AA_OPENWIND = 0x0010, /* b4: MAGXDESK, THING */
+ AA_STARTPROG = 0x0020, /* b5: MAGXDESK, THING */
+ AA_ACCWIND = 0x0040, /* b6: THING */
+ AA_STATUS = 0x0080, /* b7: THING */
+ AA_COPY_DRAGGED= 0x0100, /* b8: THING */
+ AA_DRAG_ON_WINDOW=0x0200, /* b9: MAGXDESK, THING */
+ AA_EXIT = 0x0400, /* b10: MAGXDESK, THING */
+ AA_XWIND = 0x0800, /* b11: MAGXDESK, THING */
+ AA_FONTCHANGED = 0x1000, /* b2: THING */
+ AA_STARTED = 0x2000, /* b13: MAGXDESK, THING */
+ AA_SRV_QUOTING = 0x4000, /* b14: THING */
+ AA_FILE = 0x8000, /* b15: THING */
+ /* mp[4]: THING */
+ AA_COPY = 0x0001,
+ AA_DELETE = 0x0002,
+ AA_VIEW = 0x0004,
+ AA_SETWINDPOS = 0x0008,
+ AA_COPYFILELINK= 0x0010,
+ AA_SENDCLICK = 0x0020
+} av_va_have;
+
+/* Makros zum Testen auf Quoting */
+
+#define VA_ACC_QUOTING(a) ((a) & VV_ACC_QUOTING)
+#define VA_SERVER_QUOTING(a) ((a) & AA_SRV_QUOTING)
+
+#endif // VAPROTO_H_INCLUDED