diff options
Diffstat (limited to 'frontends/atari/gemtk')
-rw-r--r-- | frontends/atari/gemtk/aestabs.c | 191 | ||||
-rw-r--r-- | frontends/atari/gemtk/aestabs.h | 56 | ||||
-rwxr-xr-x | frontends/atari/gemtk/dragdrop.c | 515 | ||||
-rwxr-xr-x | frontends/atari/gemtk/dragdrop.h | 4 | ||||
-rw-r--r-- | frontends/atari/gemtk/gemtk.h | 298 | ||||
-rw-r--r-- | frontends/atari/gemtk/guiwin.c | 1430 | ||||
-rw-r--r-- | frontends/atari/gemtk/guiwin.h | 4 | ||||
-rw-r--r-- | frontends/atari/gemtk/msgbox.c | 110 | ||||
-rw-r--r-- | frontends/atari/gemtk/msgbox.h | 5 | ||||
-rw-r--r-- | frontends/atari/gemtk/objc.c | 522 | ||||
-rw-r--r-- | frontends/atari/gemtk/objc.h | 7 | ||||
-rw-r--r-- | frontends/atari/gemtk/redrawslots.c | 123 | ||||
-rw-r--r-- | frontends/atari/gemtk/redrawslots.h | 25 | ||||
-rw-r--r-- | frontends/atari/gemtk/utils.c | 144 | ||||
-rw-r--r-- | frontends/atari/gemtk/utils.h | 5 | ||||
-rw-r--r-- | frontends/atari/gemtk/vaproto.c | 170 | ||||
-rw-r--r-- | frontends/atari/gemtk/vaproto.h | 121 |
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
|