Icônification et Drag & Drop : ça va être
chaud !
Préambule
Pas de listing dans cet article... Vous trouverez tout ce qu'il faut dans le source LST avec le
ressource correspondant dans le dossier BONUX. Ce programme, si vous le
compilez, est un des modules pour Joe : le générateur de tags <IMG>. A
vous donc d'analyser le code et d'apprendre. Cet article se bornera donc à décrire les
principes de l'icônification et du Drag&Drop.
NB : concernant le copyright de JOE_IMG (c'est son nom :), vous avez le droit
seulement de l'analyser et de faire des copier/coller de procédures pour vos propres
programmes, voire créer un générateur d'autre tag, que le pack Joe Good's
Tricks ne contient pas.
Vous n'avez aucun donc droit pour modifier, recompiler et de proposer ce programme à la place
de l'original. Si vous avez des améliorations à suggérer, passez-moi un
e-mail, on essayera de s'arranger :-)
La mise en icône
Très facile à faire puisqu'il faut surveiller certains messages dans l'EVNT_MULTI
de la boucle principale et appeler les fonctions WIND_GET et WIND_SET avec les paramètres
adéquats. A vous ensuite avec une variable booléenne d'afficher le contenu de
la fenêtre (car on a toujours une fenêtre, même si elle a la taille d'une
icône).
Constante | Opcode | Message |
WM_ICONIFY | 34 | L'utilisateur a cliqué sur le
bouton icônification et le GEM vous prévient qu'il faut modifier l'aspect de la
fenêtre avec WIND_SET. Vous récupérez avec le message GEM, dans le
buffer des messages :
INT{msg_buf%+6} (ou MENU(3)) : handle de la fenêtre
INT{msg_buf%+8} : sa position en x
INT{msg_buf%+10} : sa position en y
INT{msg_buf%+12} : sa largeur
INT{msg_buf%+14} : sa hauteur
Ce sont les coordonnées externe de la fenêtre, il faut donc à partir de
maintenant noter l'état icônifié dans une variable booléenne,
et faire un WIND_SET(26) (au lieu du paramètre 5) avec les nouvelles
coordonnéées.
Attention ici, car il existe des petits programmes permettant de placer à loisir les
fenêtre icônifiées, comme Alice 1.1. Il faut donc, après le
WIND_SET(26), un WIND_GET(4) pour avoir les vraies coordonnées internes, celles
fournies par le message GEM (et traitées par WIND_CALC) pouvant être erronées. |
WM_UNICONIFY | 35 | On a
double-cliqué sur la fenêtre icônifiée, il faut donc la remettre
à son état "normal". Les coordonnées fournies par le message GEM
(mêmes offsets et types que pour WM_ICONIFY) sont ceux de la feneêtre et on remet
celle-ci à son état initial avec WIND_SET(27) (au lieu de 5). Si vous ne voulez
pas utiliser les coordonnées du message GEM, utilisez WIN_SET(28) avec les vôtres. |
WM_ALLICONIFY | 36 | L'utilisateur
veut icônifier TOUTES les fenêtres de l'application et a appuyé sur Control
en même temps de l'item d'icônification de la fenêtre.
Personnellement, je n'ai jamais utilisé cette fonctionnalité. Mais d'après
ce que j'ai compris, on obtient dans le buffer des messages les coordonnées d'une unique
fenêtre (même offsets et types que plus haut). En plus des fonctions à
appeler et code à écrire, identiques à WM_ICONIFY, il faut une variable
booléenne en plus, celle indiquant que tous est mis dans une unique fenêtre, afin de
différencier l'affichage dans la fenêtre icônifée et surtout lors de
la désicônification par le message WM_UNICONIFY : utilisez plutôt un
tableau et sauvez vous-même les coordonnées de vos fenêtres avant le
WIND_SET(26) de l'icônification et utilisez WIND_SET(28) lors de la
désicônification. |
Pas besoin de redessiner l'intérieur des fenêtres, le GEM remarque que vous avez
modifié sa taille et vous envoye un message de WM_REDRAW. C'est donc au niveau des
routines de redessin qu'il faut faire intervenir vos variables booléennes et dessiner ce
qu'il convient : icône ou affichage normal.
De même il est important, pour la compatibilité avec les serveur
d'icônification comme Alice, très courants Outre-Rhin, de ne pas tenir compte des
coordonnées fournies avec les messages 34 et 36 pour connaître les
coordonnées pour l'affichage, mais faire son propre WIND_GET(4). Ces
petits utilitaires ne sont (pour l'instant du moins) pas capables d'intercepter les
coordonnées fenêtres données dans les messages GEM et de les
corriger.
On drague ou on droppe ?
Attention ici : les OPEN et autres fonctions typiques GFA sont interdites. Pour plus de
sécurité on emploie les bons vieux et légaux GEMDOS pour les
opérations disques. Bien que l'on emploie pas de disque dur, ni disquette pour les
transferts de données d'une application à l'autre, on utilise lecteur virtuel
U:\ , employez donc les appels légaux, le GFA n'étant pas toujours
très net ;-) .
MagiC, MultiTOS ou tout autre AES supérieur ou égal à 3.99 est
nécessaire. Il faut donc tester la version de l'AES. A ce propos, il y a un bug dans mes
programmes, je crois que je teste le TOS plutôt que l'AES... De toute façon, la
présence du lecteur U:\ indique que l'OS en question est moderne (Souvenez-vous qu'on ne
peut aller au dela du lecteur P pour les monoTOS, même celui du Falcon).
Vu le peu de performance de ma mémoire (ça fait longtemps que j'ai pas revu mes
routines de D&D, celles de Joe datent de la version 1.1 !), j'ai repris la trame du Compendium et
explicité certains passages.
RECEVOIR en Drag&Drop :
- attendre le message AP_DRAGDROP (63) pour l'EVNT_MULTI de la boucle principale et récupérer certaines valeurs de ce
buffer :
INT{msg_buf%+6} (ou MENU(3)) : handle fenêtre sur laquelle on a déposé quelque chose
INT{msg_buf%+8} : position X de la souris lors du dépôt
INT{msg_buf%+10} : position en Y
INT{msg_buf%+12} : état du clavier (touches Control, Alt, Shift)
INT{msg_buf%+14} (offset 7) : extension du fichier à ouvrir
Par un MKI$ avec la valeur de l'offset 7, on obtient un fichier qu'il faut ouvrir :
U:\PIPE\DRAGDROP.xx où xx est ce MKI$(INT{msg_buf%+14}).
- Lorsque ce fichier est ouvert en lecture/écriture avec un GEMDOS, écrivez
toujours avec un GEMDOS un mot nul (DD_OK ou 0 sur un WORD). Si vous êtes
fâché que que vous voulez rien recevoir, écrivez 1 sur un WORD (DD_NAK).
- Puis construisez dans un tampon mémoire de 32 octets, contenant 8 extensions de fichiers de 4 octets
chacunes : exemple avec ".TXT", ".DOC", etc. Cette liste correspond aux fichiers que
votre application PEUT gérer. Pour des images bitmaps, vu le nombre important de formats, on
emploie le format .IMG , pour l'ascii, c'est .TXT ... vous pouvez créer vos
propres formats, mais n'oubliez pas que le Drag&Drop est l'échange de données
interapplications, donc la compatibilité de fichiers doit être maximum ;-)
Attention, ARGS (donc sans point) est considéré comme l'échange d'un nom
de fichier(s) (ou d'autres arguments). PATH correspond à l'échange d'un chemin
et possède un protocole qui s'éloigne de la méthode décrite ici,
que malheureusement pour moi, je n'ai pas réussi à comprendre.
N'oubliez pas qu'on travaille comme en C. Si vous n'avez pas assez d'extensions à
donner, remplissez le reste avec des null-bytes. Ecrivez ensuite ce tampon dans le fichier
DRAGDROP.xx .
- Lisez ensuite un mot (WORD ou INT) sur ce fichier, cette valeur est la taille de
l'entête que vous devez lire ensuite. Donc si c'est 0, on abandonne et si vous lisez la
valeur 16, lisez ensuite 16
octets. Dans cette entête est contenu : 4 octets correspondant au format de fichier
de votre liste que l'application extérieure a reconnue et est prête à vous
envoyer, ensuite un LONG (4 octets) correspondant à la taille des données qui
vont être transmises, puis une chaîne de texte terminé par un null-byte (une
chaîne en C, quoi :) explicitant ce qui va être échangée (si on
ne veut pas expliciter, un null-byte suffit), et enfin le nom d'un fichier qui accompagne les
données (null-byte si cela ne correspond pas à un fichier).
Donc les deux derniers éléments sont facultatifs. On peut s'en passer, mais il
faut, si vous envoyez des données en Drag&Drop, les prendre en compte pour la
compatibilité.
- On analyse donc les éléments de cet entête, et on écrit un WORD
sur le fichier d'échange, selon les valeurs :
Constante | Valeur | Explication |
DD_OK | 0 | On est
prêt à recevoir des données. Après l'écriture de DD_OK dans
le fichier, on va pouvoir lire par GEMDOS, toujours sur ce même fichier, les
données, la taille de celles-ci étant fournie dans l'entête plus haut.
Attention, ici, vous lisez des données, mais il faut les stocker dans une zone
mémoire que VOUS devez allouer VOUS-MEMES. |
DD_NAK | 1 | On est des
petits branleurs et on abandonne. Ne pas oublier de fermer le fichier avec un GEMDOS. |
DD_EXT | 2 | Le format de
fichier ne nous convient pas, et, après l'écriture du mot DD_EXT par notre
application, on attend un autre mot (taille d'une nouvelle l'entête), suivi de la nouvelle
entête elle-même. Et c'est reparti comme en 14 ! |
DD_LEN | 3 | Notre application
ne peut recevoir autant de données. On attend donc une autre taille d'entête puis
son entête. |
Si votre application est un bureau GEM, les valeurs suivantes sont
employées |
DD_TRASH | 4 | C'est en
fait sur votre poubelle qu'on a déposé l'objet du Drag&Drop. On ne fait rien
et on ferme le fichier, car c'est à l'application étrangère de
détruire ce qu'il a déposé sur la poubelle (ça peut être un
morceau de texte, pas nécessairement un fichier entier) |
DD_PRINTER | 5 | Même
chose : mais pour l'imprimante. On ferme tout et c'est l'application qui a engendré
le Drag&Drop d'imprimer elle-même ce qui a été (non)-échangé. |
DD_CLIPBOARD | 6 | Idem,
mais pour le presse-papier, l'application étrangère doit elle-même sauver
dans le clipboard (comme un bête Control+V). |
- Quoiqu'il se soit passé, on ferme à la fin U:\PIPE\DRADROP.?? .
Attention les arguments ARGS sont échangés comme des arguments d'une ligne de
commande.
ENVOYER en Drag&Drop
On considère d'abord que vous avez déjà sélectionné ce que
vous aller envoyer à une autre application. En général cela se fait
à la souris en employant les fonction GRAF_? . Essayer de faire cela
élégamment, car il faut que vos Drags et vos Drops soient ergonomiques si vous
voulez qu'on les emploie.
Donc vous avez avec la souris fait un glisser-déposer sur
une fenêtre quelconque. Si c'est une des vôtres, c'est à vous de gérer
cela, si cette fenêtre n'est pas la vôtre, vous pouvez alors faire un Drag&Drop.
Utilisez WIND_FIND et WIND_GET(20 WM_OWNER) pour connaître l'ap_id& de l'application
dans laquelle vous avez déposer vos trésors. Le Drag&Drop peut alors
commencer.
- Utilisez la fonction GEMDOS Psignal() (spécial MiNT et comprise par MagiC) qui permet
d'ignorer les messages Drag&Drop de réception possibles qui peuvent nous être
envoyés (signaux SIGPIPE(13), mais ne me demandez rien, je suis un bleu comme vous dans
cette fonction. J'ai trimé pour que cela marche, mais je n'ai par contre pas compris
grand chose).
- Créez le fichier U:\PIPE\DRADROP.xx où xx est deux caractères ASCII
qu'on pourra convertir en WORD. Il faut faire des test avant de créer le fichier pour
voir s'il n'existe pas déjà. En général on prend d'abord "AA", puis
"AB" sinon, etc. Si la création échoue, on essaye une autre extension. Ce fichier
doit être caché, selon le Compendium.
- utilisez APPL_WRITE vers l'application dont vous connaissez l'ap_id& (avec ce qu'on a
dit plus haut avec WM_OWNER. Le buffer de 16 octets doit être remplie de cette
manière :
Offset (en octets) | Contenu (en mot, INT) |
+0 | AP_DRAGDROP (63) |
+2 | votre ap_id& |
+4 | 0 |
+6 | Handle de la fenêtre où a
été déposé les données à échanger |
+8 | Position en X de la souris à ce moment |
+10 | Position en Y de la souris |
+12 | Etat des touches Control, Alternate et Shift
à ce moment (utilisation de GRAF_MKSTATE) |
+14 | le xx, extension du fichier de Drag&Drop,
converti en WORD grâce à CVI("xx") |
- Utiliser ensuite la fonction GEMDOS Fselect() pour attendre une possible réponse
(délai de 3 à 4 secondes selon le Compendium).
- Si on a eut une réponse avant l'échéance, on lit un mot dans le
fichier. Si ce WORD est nul (DD_OK) on continue, si ce dernier est à 1 (DD_NAK), on
abandonne.
- Si on a lu 0, on lit ensuite 32 octets. Ce petit tampon correspond aux formats de fichiers
que l'autre application peut recevoir. si on trouve .TXT , alors on pourra lui envoyer du
texte au format ASCII. Idem pour .IMG ou .GEM , etc. En général, 8 types de
fichiers suffisent. Si notre application ne veux pas envoyer à ces 8 formats, on peut
continuer en renvoyant plus tard le type de format voulu dans l'entête qui va suivre. A
l'autre application de s'accorder. Mais en général, les formats
échangés sont de type .TXT et ARGS, le reste du tampon étant rempli par
des zéros.
- On construit ensuite un entête, avec tout d'abord le format voulu (4 octets, exemple
.TXT), puis sur un LONG (4 octets) la longueur des données à envoyer, puis une
chaîne C décrivant le type de données échangées (ou un
null-byte) (exmple : Texte ASCII), et enfin un nom de fichier facultatif (ou un null-byte
obligatoirement sinon).
On regarde combien cela fait en taille (n'oubliez pas de compter les null-bytes avec) et on
écrit cette taille en WORD dans le fichier de Drag&Drop, puis tout de suite après
l'entête elle-même.
- On a ensuite une réponse de l'application réceptrice en lisant un WORD dans
le fichier. Ce sont exactement les codes DD_OK, DD_TRASH et cie plus haut ! Mais ici
faites attention : on est dans l'autre position, celle de l'envoyeur.
Dans le cas favorable (DD_OK lu), on écrit dans le fichier les données à
envoyer, puis on ferme et (je suppose) on rétablie la fonction Psignal à son
état initial.
Ce n'est qu'un au revoir !
Compliqué, le Drag&Drop ? Pas vraiment. Les principales difficultés
viennent en fait des fonctions que, nous, pauvres GFA-lamerz, n'employons jamais (Psignal et
Fselect), mais aussi du fait de coder dans la même application les fonctions pour envoyer
ET recevoir. Je mélangeais tout à un moment donné !
Mais une fois codé et compris, on peu oublier : les routines de Drag&Drop
s'intégreront parfaitement dans votre bibliothèque de fonctions-maisons.
Un dernier point que j'ai oublié de souligner : tout se fait grâce à
l'OS, pas besoin de mémoire tampon non protégée pour échanger des
données. Le protocole est donc sécurisé : toutes les allocs
mémoires peuvent être en mémoire protégée. Le GEM et ses
enhanced clones comme MagiC, au contraire de certains OS
commerciaux et billesques, sont faits dès le départ pour évoluer,
étant bâtis sur des bases solides.
Bref, le TOS et le GEM en particulier, c'est pas un OS de mauviettes.
Rajah Lone
écrit le 4 Juin 99