OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/rtos/ecos-2.0/packages/services/gfx/mw/v2_0/src/demos/nanox
    from Rev 27 to Rev 174
    Reverse comparison

Rev 27 → Rev 174

/ntetris.syms
0,0 → 1,?rev2len?
ntetris_main
/launcher.c
0,0 → 1,599
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is NanoLauncher.
*
* The Initial Developer of the Original Code is Alex Holden.
* Portions created by Alex Holden are Copyright (C) 2000
* Alex Holden <alex@linuxhacker.org>. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public license (the "[GNU] License"), in which case the
* provisions of [GNU] License are applicable instead of those
* above. If you wish to allow use of your version of this file only
* under the terms of the [GNU] License and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the [GNU] License. If you do not delete
* the provisions above, a recipient may use your version of this file
* under either the MPL or the [GNU] License.
*/
 
/*
* A simple application launcher for Nano-X by Alex Holden.
*
* The application needs to be started with the first argument specifying
* the location of it's configuration file. The format of the file is
* extremely simple- each line can contain either a comment (indicated by
* beginning the line with a '#' symbol) or an item description.
* An item description consists of the name of the item (the title which
* appears underneath the icon on the launcher button) followed by the name
* of the icon file (or '-' for no icon) and the command to execute when the
* item is clicked on. The command can optionally be followed by a limited
* number of arguments to pass to the program when it is executed (increase
* MAX_ARGUMENTS in launcher.h if you need more). The program will currently
* only allow one icon size (specified at compile time by the ICON_WIDTH and
* ICON_HEIGHT parameters). The program only loads each icon file once even if
* it is used multiple times, so you can save a small amount of memory by
* using the same icon for several programs. If you want to change the size
* of the item buttons, change ITEM_WIDTH and ITEM_HEIGHT in launcher.h.
* The way the launcher decides whether to draw a vertical panel on the left
* hand side of the screen or a horizontal panel along the bottom is by
* looking at the width and height of the screen- the panel will be placed on
* the side on portrait screens and on the bottom on landscape screens.
*/
 
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
 
#define MWINCLUDECOLORS
#include "nano-X.h"
#include "launcher.h"
 
void reaper(int signum) { while(waitpid(WAIT_ANY, NULL, WNOHANG) > 0); }
 
void *my_malloc(size_t size)
{
void *ret;
 
if(!(ret = malloc(size))) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
 
return ret;
}
 
void usage(void)
{
fprintf(stderr, "Usage: launcher <config-file>\n");
exit(3);
}
 
prog_item *make_prog_item(char *buf, int lineno)
{
char *p, *pp, *command;
prog_item *prog;
int n;
 
p = buf;
 
prog = my_malloc(sizeof(prog_item));
 
for(n = 0; n < MAX_ARGUMENTS; n++) prog->argv[n] = NULL;
 
while(isspace(*p)) p++;
if(!*p) {
fprintf(stderr, "Premature end of line on line %d of config "
"file\n", lineno);
return 0;
}
command = p;
while(*p && (!isspace(*p))) p++;
*p++ = 0;
if(!(prog->command = strdup(command))) {
free(prog);
goto nomem;
}
pp = p - 1;
while(--pp != command) {
if(*pp == '/') {
pp++;
break;
}
}
if(!(prog->argv[0] = strdup(pp))) {
free(prog->command);
free(prog);
goto nomem;
}
 
n = 1;
while(*p) {
while(isspace(*p)) p++;
if(!*p) break;
pp = p;
while(*p && (!isspace(*p))) p++;
*p++ = 0;
if(!(prog->argv[n] = strdup(pp))) {
for(n = MAX_ARGUMENTS; n; n--)
if(prog->argv[n]) free(prog->argv[n]);
free(prog->command);
free(prog);
goto nomem;
}
if(++n == (MAX_ARGUMENTS - 1)) {
fprintf(stderr, "Too many arguments on line "
"%d of the config file\n", lineno);
break;
}
}
 
return prog;
 
nomem:
fprintf(stderr, "Out of memory parsing line %d of the config "
"file\n", lineno);
return 0;
}
 
void set_window_background_colour(char *buf, int lineno)
{
GR_WM_PROPERTIES props;
char *p = buf, *pp;
 
while(isspace(*p)) p++;
if(!*p) {
fprintf(stderr, "Premature end of line on line %d of config "
"file\n", lineno);
return;
}
pp = p;
while(*p && (!isspace(*p))) p++;
*p = 0;
 
if(!strcmp(pp, "BLACK")) props.background = BLACK;
else if(!strcmp(pp, "BLUE")) props.background = BLUE;
else if(!strcmp(pp, "GREEN")) props.background = GREEN;
else if(!strcmp(pp, "CYAN")) props.background = CYAN;
else if(!strcmp(pp, "RED")) props.background = RED;
else if(!strcmp(pp, "MAGENTA")) props.background = MAGENTA;
else if(!strcmp(pp, "BROWN")) props.background = BROWN;
else if(!strcmp(pp, "LTGRAY")) props.background = LTGRAY;
else if(!strcmp(pp, "GRAY")) props.background = GRAY;
else if(!strcmp(pp, "LTBLUE")) props.background = LTBLUE;
else if(!strcmp(pp, "LTGREEN")) props.background = LTGREEN;
else if(!strcmp(pp, "LTCYAN")) props.background = LTCYAN;
else if(!strcmp(pp, "LTRED")) props.background = LTRED;
else if(!strcmp(pp, "LTMAGENTA")) props.background = LTMAGENTA;
else if(!strcmp(pp, "YELLOW")) props.background = YELLOW;
else if(!strcmp(pp, "WHITE")) props.background = WHITE;
else {
fprintf(stderr, "Invalid colour \"%s\" on line %d of config "
"file\n", pp, lineno);
return;
}
 
props.flags = GR_WM_FLAGS_BACKGROUND;
GrSetWMProperties(GR_ROOT_WINDOW_ID, &props);
}
 
void parse_config_line(lstate *state, char *buf, int lineno)
{
char *p, *pp, *name, *icon;
int n;
litem *new_litem, *li;
sitem *new_sitem;
GR_IMAGE_INFO imageinfo;
 
p = buf;
 
if((!*p) || (*p == '#') || (*p == '\n')) return;
 
while(isspace(*p)) p++;
name = p;
while(*p && (!isspace(*p))) p++;
if(!*p) goto premature;
*p++ = 0;
 
if(!strcmp(name, "$screensaver")) {
new_sitem = my_malloc(sizeof(sitem));
if(!(new_sitem->prog = make_prog_item(p, lineno))) {
free(new_sitem);
return;
}
new_sitem->next = NULL;
if(!state->sitems) {
state->sitems = new_sitem;
state->cursitem = new_sitem;
} else {
new_sitem->next = state->sitems;
state->sitems = new_sitem;
}
return;
} else if(!strcmp(name, "$screensaver_timeout")) {
n = strtol(p, NULL, 10);
GrSetScreenSaverTimeout(n);
return;
} else if(!strcmp(name, "$window_background_image")) {
while(isspace(*p)) p++;
if(!*p) goto premature;
pp = p;
while(*p && (!isspace(*p))) p++;
*p = 0;
state->window_background_image = strdup(pp);
return;
} else if(!strcmp(name, "$window_background_mode")) {
state->window_background_mode = (int) strtol(p, NULL, 10);
return;
} else if(!strcmp(name, "$window_background_colour")) {
set_window_background_colour(p, lineno);
return;
}
 
while(isspace(*p)) p++;
if(!*p) goto premature;
icon = p;
while(*p && (!isspace(*p))) p++;
if(!*p) goto premature;
*p++ = 0;
 
new_litem = my_malloc(sizeof(litem));
if(!(new_litem->name = strdup(name))) {
free(new_litem);
goto nomem;
}
if(!(new_litem->icon = strdup(icon))) {
free(new_litem->name);
free(new_litem);
goto nomem;
}
if(!(new_litem->prog = make_prog_item(p, lineno))) {
free(new_litem->name);
free(new_litem->icon);
free(new_litem);
return;
}
new_litem->iconid = 0;
if(strcmp("-", icon)) {
li = state->litems;
while(li) {
if(!(strcmp(icon, li->name))) {
new_litem->iconid = li->iconid;
break;
}
li = li->next;
}
if(!new_litem->iconid) {
if(!(new_litem->iconid = GrLoadImageFromFile(icon, 0))){
fprintf(stderr, "Couldn't load icon \"%s\"\n",
icon);
} else {
GrGetImageInfo(new_litem->iconid, &imageinfo);
if((imageinfo.width != ICON_WIDTH) ||
(imageinfo.height != ICON_HEIGHT)) {
fprintf(stderr, "Icon \"%s\" is the "
"wrong size (%dx%d instead of %dx%d)"
"\n", icon, imageinfo.width,
imageinfo.height, ICON_WIDTH,
ICON_HEIGHT);
GrFreeImage(new_litem->iconid);
new_litem->iconid = 0;
}
}
}
}
 
new_litem->prev = NULL;
new_litem->next = NULL;
if(!state->litems) {
state->lastlitem = new_litem;
state->litems = new_litem;
} else {
new_litem->next = state->litems;
state->litems->prev = new_litem;
state->litems = new_litem;
}
 
state->numlitems++;
 
return;
 
nomem:
fprintf(stderr, "Out of memory\n");
exit(1);
 
premature:
fprintf(stderr, "Premature end of line on line %d of config file\n",
lineno);
}
 
void read_config(lstate *state)
{
int lineno = 1;
FILE *fp;
char *buf = my_malloc(256);
 
if(!(fp = fopen(state->config_file, "r"))) {
fprintf(stderr, "Couldn't open config file \"%s\"\n",
state->config_file);
exit(2);
}
 
state->litems = NULL;
state->numlitems = 0;
state->sitems = NULL;
 
while(fgets(buf, 256, fp)) {
parse_config_line(state, buf, lineno);
lineno++;
}
 
fclose(fp);
free(buf);
 
if(!state->numlitems) {
fprintf(stderr, "No valid launcher items in config file\n");
exit(5);
}
}
 
void draw_item(lstate *state, litem *item)
{
GR_SIZE width, height, base, x, len;
 
GrDrawImageToFit(item->wid, state->gc, ICON_X_POSITION, ICON_Y_POSITION,
ICON_WIDTH, ICON_HEIGHT, item->iconid);
 
len = strlen(item->name);
GrGetGCTextSize(state->gc, item->name, len, 0, &width, &height, &base);
if(width >= ITEM_WIDTH) x = 0;
else x = (ITEM_WIDTH - width) / 2;
 
GrText(item->wid, state->gc, x, TEXT_Y_POSITION, item->name, len, 0);
}
 
void handle_exposure_event(lstate *state)
{
GR_EVENT_EXPOSURE *event = &state->event.exposure;
litem *i = state->litems;
 
if(event->wid == state->main_window) return;
 
while(i) {
if(event->wid == i->wid) {
draw_item(state, i);
return;
}
i = i->next;
}
 
fprintf(stderr, "Got exposure event for unknown window %d\n",
event->wid);
}
 
void launch_program(prog_item *prog)
{
pid_t pid;
 
if((pid = fork()) == -1) perror("Couldn't fork");
else if(!pid) {
if(execvp(prog->command, prog->argv) == -1)
fprintf(stderr, "Couldn't start \"%s\": %s\n",
prog->command, strerror(errno));
exit(7);
}
}
 
void handle_mouse_event(lstate *state)
{
GR_EVENT_MOUSE *event = &state->event.mouse;
litem *i = state->litems;
 
if(event->wid == state->main_window) return;
 
while(i) {
if(event->wid == i->wid) {
launch_program(i->prog);
return;
}
i = i->next;
}
 
fprintf(stderr, "Got mouse event for unknown window %d\n", event->wid);
}
 
void handle_screensaver_event(lstate *state)
{
GR_EVENT_SCREENSAVER *event = &state->event.screensaver;
 
if(event->activate != GR_TRUE) return;
 
if(!state->sitems) {
fprintf(stderr, "Got screensaver activate event with no "
"screensavers defined\n");
return;
}
 
state->cursitem = state->cursitem->next;
if(!state->cursitem) state->cursitem = state->sitems;
 
launch_program(state->cursitem->prog);
}
 
void handle_event(lstate *state)
{
switch(state->event.type) {
case GR_EVENT_TYPE_EXPOSURE:
handle_exposure_event(state);
break;
case GR_EVENT_TYPE_BUTTON_DOWN:
handle_mouse_event(state);
break;
case GR_EVENT_TYPE_CLOSE_REQ:
break;
case GR_EVENT_TYPE_SCREENSAVER:
handle_screensaver_event(state);
break;
case GR_EVENT_TYPE_NONE:
break;
default:
fprintf(stderr, "Got unknown event type %d\n",
state->event.type);
break;
}
}
 
void do_event_loop(lstate *state)
{
do {
GrGetNextEvent(&state->event);
handle_event(state);
} while(state->event.type != GR_EVENT_TYPE_CLOSE_REQ);
}
 
void initialise(lstate *state)
{
GR_SCREEN_INFO si;
GR_IMAGE_ID back_image;
GR_IMAGE_INFO imageinfo;
int rows = 1, columns = 1, width, height, x = 0, y = 1;
GR_WM_PROPERTIES props;
litem *i;
 
if(GrOpen() < 0) {
fprintf(stderr, "Couldn't connect to Nano-X server\n");
exit(4);
}
 
state->window_background_mode = 0;
state->window_background_image = NULL;
 
read_config(state);
 
GrGetScreenInfo(&si);
 
if(si.rows > si.cols) {
rows = state->numlitems;
while((((rows / columns) + rows % columns) * ITEM_HEIGHT) >
si.rows) {
columns++;
}
if((columns * ITEM_WIDTH) > si.cols) goto toomany;
rows = (rows / columns) + (rows % columns);
width = columns * ITEM_WIDTH + 1 + columns;
height = rows * ITEM_HEIGHT + 1 + rows;
} else {
columns = state->numlitems;
while((((columns / rows) + (columns % rows)) * ITEM_WIDTH) >
si.cols) {
rows++;
}
if((rows * ITEM_HEIGHT) > si.rows) goto toomany;
columns = (columns / rows) + (columns % rows);
width = columns * ITEM_WIDTH + 1 + columns;
height = (rows * ITEM_HEIGHT) + 1 + rows;
y = si.rows - (rows * ITEM_HEIGHT) - 1 - rows;
}
 
state->gc = GrNewGC();
GrSetGCForeground(state->gc, ITEM_TEXT_COLOUR);
GrSetGCBackground(state->gc, ITEM_BACKGROUND_COLOUR);
 
if(state->window_background_image) {
if(!(back_image = GrLoadImageFromFile(
state->window_background_image, 0))) {
fprintf(stderr, "Couldn't load background image\n");
} else {
GrGetImageInfo(back_image, &imageinfo);
if(!(state->background_pixmap = GrNewPixmap(
imageinfo.width,
imageinfo.height, NULL))) {
fprintf(stderr, "Couldn't allocate pixmap "
"for background image\n");
} else {
GrDrawImageToFit(state->background_pixmap,
state->gc, 0, 0, imageinfo.width,
imageinfo.height, back_image);
GrFreeImage(back_image);
GrSetBackgroundPixmap(GR_ROOT_WINDOW_ID,
state->background_pixmap,
state->window_background_mode);
GrClearWindow(GR_ROOT_WINDOW_ID, GR_TRUE);
}
}
}
 
if(state->sitems)
GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_SCREENSAVER);
 
state->main_window = GrNewWindow(GR_ROOT_WINDOW_ID, 0, y, width, height,
0, ITEM_BACKGROUND_COLOUR, 0);
GrSelectEvents(state->main_window, GR_EVENT_MASK_CLOSE_REQ);
props.flags = GR_WM_FLAGS_PROPS;
props.props = GR_WM_PROPS_NOMOVE | GR_WM_PROPS_NODECORATE |
GR_WM_PROPS_NOAUTOMOVE | GR_WM_PROPS_NOAUTORESIZE;
GrSetWMProperties(state->main_window, &props);
 
i = state->lastlitem;
y = 0;
while(i) {
i->wid = GrNewWindow(state->main_window,
(x * ITEM_WIDTH) + x + 1,
(y * ITEM_HEIGHT) + y + 1, ITEM_WIDTH,
ITEM_HEIGHT, 1, ITEM_BACKGROUND_COLOUR,
ITEM_BORDER_COLOUR);
GrSelectEvents(i->wid, GR_EVENT_MASK_EXPOSURE |
GR_EVENT_MASK_BUTTON_DOWN);
GrMapWindow(i->wid);
i = i->prev;
if(++x == columns) {
x = 0;
y++;
}
}
 
GrMapWindow(state->main_window);
 
signal(SIGCHLD, &reaper);
 
return;
 
toomany:
fprintf(stderr, "Too many items to fit on screen\n");
exit(6);
}
 
int main(int argc, char *argv[])
{
lstate *state;
 
if(argc != 2) usage();
 
state = my_malloc(sizeof(lstate));
state->config_file = strdup(argv[1]);
 
initialise(state);
 
do_event_loop(state);
 
GrClose();
 
return 0;
}
/tux.gif Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
tux.gif Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: wait.c =================================================================== --- wait.c (nonexistent) +++ wait.c (revision 174) @@ -0,0 +1,13 @@ +/* + * Connect to the server, then wait until terminated (useful for stopping the server + * from exiting without a window manager) + */ + +#include "nano-X.h" + +int main() +{ + char c; + read(GrOpen(), &c, 1); + return 0; +} Index: nxlsclients.c =================================================================== --- nxlsclients.c (nonexistent) +++ nxlsclients.c (revision 174) @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2000 by VTech Informations LTD. + * This program is released under MPL. + * + * Vladimir Cotfas Oct 25, 2000 + */ +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" +#include "windef.h" + +/* which is the maximim window id?!?!*/ +#define LIMIT 10000 + +struct _colour { + unsigned long colour; + char* name; +}; +typedef struct _colour COLOURS; + +static COLOURS colour_table[] = { + { BLACK, "Black" }, + { BLUE, "Blue" }, + { GREEN, "Green"}, + { CYAN, "Cyan" }, + { RED, "Red" }, + { MAGENTA, "Magenta" }, + { BROWN, "Brown" }, + { LTGRAY, "LightGray" }, + { GRAY, "Gray" }, + { DKGRAY, "DarkGray" }, + { LTBLUE, "LightBlue" }, + { LTGREEN, "LightGreen" }, + { LTCYAN, "LightCyan" }, + { LTRED, "LightRed" }, + { LTMAGENTA, "LightMagenta" }, + { YELLOW, "Yellow" }, + { WHITE, "White" } +}; +#define NR_COLOURS (sizeof(colour_table) / sizeof(colour_table[0])) + +char* +lookupColour(unsigned long c) +{ + int i; + + for (i = 0; i < NR_COLOURS; i++) + if (c == colour_table[i].colour) + return colour_table[i].name; + + return "UanbleToComply"; +} + +struct _xlat { + unsigned event_type; + char* event_desc; +}; +typedef struct _xlat XLAT; + +static XLAT event_table[] = { + { GR_EVENT_TYPE_ERROR, "GR_EVENT_MASK_ERROR" }, +/* { GR_EVENT_TYPE_NONE, "GR_EVENT_MASK_NONE" }, */ + { GR_EVENT_TYPE_EXPOSURE, "GR_EVENT_MASK_EXPOSURE" }, + { GR_EVENT_TYPE_BUTTON_DOWN, "GR_EVENT_MASK_BUTTON_DOWN" }, + { GR_EVENT_TYPE_BUTTON_UP, "GR_EVENT_MASK_BUTTON_UP" }, + { GR_EVENT_TYPE_MOUSE_ENTER, "GR_EVENT_MASK_MOUSE_ENTER" }, + { GR_EVENT_TYPE_MOUSE_EXIT, "GR_EVENT_MASK_MOUSE_EXIT" }, + { GR_EVENT_TYPE_MOUSE_MOTION, "GR_EVENT_MASK_MOUSE_MOTION" }, + { GR_EVENT_TYPE_MOUSE_POSITION, "GR_EVENT_MASK_MOUSE_POSITION" }, + { GR_EVENT_TYPE_KEY_DOWN, "GR_EVENT_MASK_KEY_DOWN" }, + { GR_EVENT_TYPE_KEY_UP, "GR_EVENT_MASK_KEY_UP" }, + { GR_EVENT_TYPE_FOCUS_IN, "GR_EVENT_MASK_FOCUS_IN" }, + { GR_EVENT_TYPE_FOCUS_OUT, "GR_EVENT_MASK_FOCUS_OUT" }, + { GR_EVENT_TYPE_FDINPUT, "GR_EVENT_MASK_FDINPUT" }, + { GR_EVENT_TYPE_UPDATE, "GR_EVENT_MASK_UPDATE" }, + { GR_EVENT_TYPE_CHLD_UPDATE, "GR_EVENT_MASK_CHLD_UPDATE" }, + { GR_EVENT_TYPE_CLOSE_REQ, "GR_EVENT_MASK_CLOSE_REQ" } +}; +#define NR_MASKS (sizeof(event_table) / sizeof(event_table[0])) + +struct _wm_props { + GR_WM_PROPS prop; + char* prop_symbol; + char* prop_descr; +}; +typedef struct _wm_props WM_PROPS; + +static WM_PROPS props_table[] = { + /* Window properties */ + { GR_WM_PROPS_NOBACKGROUND, "GR_WM_PROPS_NOBACKGROUND", "Don't draw window background" }, + { GR_WM_PROPS_NOFOCUS, "GR_WM_PROPS_NOFOCUS", "Don't set focus to this window" }, + { GR_WM_PROPS_NOMOVE, "GR_WM_PROPS_NOMOVE", "Don't let user move window" }, + { GR_WM_PROPS_NORAISE, "GR_WM_PROPS_NORAISE", "Don't let user raise window" }, + { GR_WM_PROPS_NODECORATE, "GR_WM_PROPS_NODECORATE", "Don't redecorate window" }, + { GR_WM_PROPS_NOAUTOMOVE, "GR_WM_PROPS_NOAUTOMOVE", "Don't move window on decorating" }, + + /* default decoration style */ + { GR_WM_PROPS_APPWINDOW, "GR_WM_PROPS_APPWINDOW", "Leave appearance to WM" }, + { GR_WM_PROPS_APPMASK, "GR_WM_PROPS_APPMASK", "Appearance mask" }, + { GR_WM_PROPS_BORDER, "GR_WM_PROPS_BORDER", "Single line border" }, + { GR_WM_PROPS_APPFRAME, "GR_WM_PROPS_APPFRAME", "3D app frame" }, + { GR_WM_PROPS_CAPTION, "GR_WM_PROPS_CAPTION", "Title bar" }, + { GR_WM_PROPS_CLOSEBOX, "GR_WM_PROPS_CLOSEBOX", "Close box" }, +#if 0 + { GR_WM_PROPS_MAXIMIZED, "GR_WM_PROPS_MAXIMIZED", "Application is maximized" } +#endif +}; +#define NR_PROPS (sizeof(props_table) / sizeof(props_table[0])) + +int +main(int argc, char* argv[]) +{ + GR_WINDOW_ID w; + GR_WINDOW_INFO info; + + if (GrOpen() < 0) { + fprintf(stderr, "nxlsclients: cannot open graphics\n"); + exit(1); + } + + for (w = 0; w < LIMIT; w++) { + info.wid = -1; /* self-sabotaged like CCCP */ + + GrGetWindowInfo(w, &info); + + if (info.wid == -1) { + printf("Query wid = %d, GrGetWindowInfo() is not working!\n", w); + continue; + } + if (info.wid == 0) { +#if 0 + printf("Query wid = %d --> does not exist\n", w); +#endif + continue; + } + printf("Window id = %d\n", info.wid); + printf("\tAbsolute upper-left X: %d\n", info.x); + printf("\tAbsolute upper-left Y: %d\n", info.y); + printf("\tWidth = %d\n", info.width); + printf("\tHeight = %d\n", info.height); + printf("\tBorder: size = %d, colour = %s (#%06lX)\n", \ + info.bordersize, + lookupColour(info.bordercolor), info.bordercolor); + printf("\tBackground colour = %s (#%06lX)\n", \ + lookupColour(info.background), info.background); + + printf("\tParent = %d\n", info.parent); + printf("\tFirst child = %d\n", info.child); + printf("\tNext sibling? = %d\n", info.sibling); + + printf("\t%sinput-only, ", (info.inputonly == TRUE)?"": "not "); + printf("%smapped", (info.mapped == TRUE)?"": "not "); + if (info.mapped != TRUE) + printf(", unmapcount = %d", info.unmapcount); + printf("\n"); + + printf("\tEvent mask (0x%08lX):\n", info.eventmask); + { + int i, n = 0; + GR_EVENT_MASK tmp = info.eventmask; + + for (i = 0; i < NR_MASKS; i++) { + GR_EVENT_MASK mask = GR_EVENTMASK(event_table[i].event_type); + + if ((tmp & mask) == mask) { + printf("\t\t%s\n", event_table[i].event_desc); + n++; + } + } + if (!n) + printf("\t\tGR_EVENT_MASK_NONE (?!?!?)\n"); + } + + /* We don't use info.props, use GrGetWMProperties() intead */ + printf("\tWM Properties:\n"); + { + GR_WM_PROPERTIES wm_props; + + GrGetWMProperties(w, &wm_props); + + printf("\t\tTitle: "); + if ((wm_props.flags & GR_WM_FLAGS_TITLE ) == GR_WM_FLAGS_TITLE) + printf("'%s'\n", (char*)wm_props.title?:"(null)"); + else + printf("\n"); + + printf("\t\tBackground colour: "); + if ((wm_props.flags & GR_WM_FLAGS_BACKGROUND) == GR_WM_FLAGS_BACKGROUND) + printf("%s (#%06lX)\n", lookupColour(wm_props.background), + wm_props.background); + else + printf("\n"); + + printf("\t\tBorder size: "); + if ((wm_props.flags & GR_WM_FLAGS_BORDERSIZE) == GR_WM_FLAGS_BORDERSIZE) + printf("%d\n", wm_props.bordersize); + else + printf("\n"); + + printf("\t\tProperty bits (0x%08lX):\n", wm_props.props); + { + int i, n = 0; + + for (i = 0; i < NR_PROPS; i++) { + GR_WM_PROPS prop = props_table[i].prop; + if ((wm_props.props & prop) == prop) { + printf("\t\t\t%s (%s)\n", \ + props_table[i].prop_symbol, \ + props_table[i].prop_descr); + n++; + } + } + + if (!n) + printf("\t\tNONE (?!?!?)\n"); + } + + } + } + + GrClose(); + + return 0; + } Index: launcher.h =================================================================== --- launcher.h (nonexistent) +++ launcher.h (revision 174) @@ -0,0 +1,102 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is NanoLauncher. + * + * The Initial Developer of the Original Code is Alex Holden. + * Portions created by Alex Holden are Copyright (C) 2000 + * Alex Holden . All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public license (the "[GNU] License"), in which case the + * provisions of [GNU] License are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the [GNU] License and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the [GNU] License. If you do not delete + * the provisions above, a recipient may use your version of this file + * under either the MPL or the [GNU] License. + */ + +#ifndef LAUNCHER_H +#define LAUNCHER_H + +#define ITEM_WIDTH 100 +#define ITEM_HEIGHT 60 +#define ITEM_TEXT_COLOUR BLACK +#define ITEM_BORDER_COLOUR BLACK +#define ITEM_BACKGROUND_COLOUR LTGRAY +#define ICON_WIDTH 32 +#define ICON_HEIGHT 32 +#define ICON_X_POSITION ((ITEM_WIDTH - ICON_WIDTH) / 2) +#define ICON_Y_POSITION 6 +#define TEXT_Y_POSITION (ITEM_HEIGHT - 6) +#define MAX_ARGUMENTS 12 + +struct command_argv { + char *command; + char *argv[MAX_ARGUMENTS]; +}; +typedef struct command_argv prog_item; + +struct launcher_item { + char *name; + char *icon; + prog_item *prog; + struct launcher_item *next; + struct launcher_item *prev; + GR_IMAGE_ID iconid; + GR_WINDOW_ID wid; +}; +typedef struct launcher_item litem; + +struct screensaver_item { + prog_item *prog; + struct screensaver_item *next; +}; +typedef struct screensaver_item sitem; + +struct launcher_state { + char *config_file; + GR_WINDOW_ID main_window; + litem *litems; + litem *lastlitem; + int numlitems; + sitem *sitems; + sitem *cursitem; + GR_GC_ID gc; + GR_EVENT event; + int window_background_mode; + char *window_background_image; + GR_WINDOW_ID background_pixmap; +}; +typedef struct launcher_state lstate; + +void reaper(int signum); +void *my_malloc(size_t size); +void usage(void); +prog_item *make_prog_item(char *command, int lineno); +void set_window_background_colour(char *buf, int lineno); +void parse_config_line(lstate *state, char *buf, int lineno); +void read_config(lstate *state); +void draw_item(lstate *state, litem *item); +void handle_exposure_event(lstate *state); +void launch_program(prog_item *prog); +void handle_mouse_event(lstate *state); +void handle_screensaver_event(lstate *state); +void handle_event(lstate *state); +void do_event_loop(lstate *state); +void initialise(lstate *state); + +#endif Index: logfont_ksc.c =================================================================== --- logfont_ksc.c (nonexistent) +++ logfont_ksc.c (revision 174) @@ -0,0 +1,108 @@ +/* KSC5601 test program*/ +#include +#include +#include +#include +#if UNIX +#include +#endif +#define MWINCLUDECOLORS +#include "nano-X.h" +/* + * logical font demo for Nano-X + */ + +#define MAXW 630 +#define MAXH 470 + +int main(int argc, char **argv) +{ + GR_WINDOW_ID window; + GR_EVENT event; + GR_GC_ID gc; + GR_FONT_ID fontid; + int x, y, rnd = 0; + MWLOGFONT lf; + char description[128]; + + srand(time(0)); + + GrOpen(); + window = GrNewWindow(GR_ROOT_WINDOW_ID, 5, 5, MAXW, MAXH, 4, BLACK, BLUE); + GrMapWindow(window); + + gc = GrNewGC(); + + GrSelectEvents(window,GR_EVENT_MASK_ALL); + GrSetGCUseBackground(gc,GR_FALSE); + GrSetGCBackground(gc, GR_RGB(0, 0, 0)); + + y = 30; + x = 0; + + while(1) { + GrCheckNextEvent(&event); + + if(event.type == GR_EVENT_TYPE_CLOSE_REQ) { + GrClose(); + exit(0); + } + + sleep(1); + + MWLF_Clear(&lf); + description[0] = '\0'; + + // lf.lfSerif = 1; + + if ( rnd & 1 ) { + lf.lfWeight = MWLF_WEIGHT_BOLD; + strcat(description,"Bold "); + } + + + if ( rnd & 2 ) { + lf.lfItalic = 1; + strcat(description,"Italics "); + } + if ( rnd & 4 ) { + lf.lfOblique = 1; + strcat(description,"Oblique "); + } + + if ( rnd & 8 ) { + lf.lfMonospace = 1; + strcat(description,"绊沥气 Monospace "); + } else { + lf.lfProportional = 1; + strcat(description,"Proportional "); + } + + if ( argc > 1 ) + strcpy(lf.lfFaceName,argv[1]); + else + strcpy(lf.lfFaceName,"fantasy"); + + fontid = GrCreateFont(0, 0, &lf); + /* GrSetFontSize(fontid, 1+(int)(80.0 * rand() / (RAND_MAX+1.0))); */ + GrSetFontSize(fontid,26); + GrSetFontRotation(fontid, 330); /* 33 degrees*/ + GrSetFontAttr(fontid, GR_TFKERNING | GR_TFANTIALIAS, 0); + GrSetGCFont(gc, fontid); + /*GrSetGCBackground(gc, rand() & 0xffffff);*/ + GrSetGCForeground(gc, 0xffffff); + /* x = (int) ((MAXW * 1.0) *rand()/(RAND_MAX+1.0)); + y = (int) ((MAXH * 1.0) *rand()/(RAND_MAX+1.0)); */ + + GrText(window, gc,x,y, description, -1, GR_TFASCII); + + GrDestroyFont(fontid); + + rnd++; + y += 30; + if ( y > 460 ) + y = 0; + } + + GrClose(); +} Index: nanogui.ppm =================================================================== --- nanogui.ppm (nonexistent) +++ nanogui.ppm (revision 174) @@ -0,0 +1,2962 @@ +P6 +384 83 +255 +孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜赝赝赝赝靥靥靥靥靥厮厮厮厮厥厥厥厥厣厣厣厣厣厝厝厝厝厍厍 厍 厍 仄 仄 仄 仄 仄 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郫 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堀堀堀堀堀埭埭埭埭埽埽埽埽堍堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轂轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾輾輽輽輽迿迾迾迾迾迾迼迼迼迼迻迻迻迻迺迺迺迺迺迶迶迶迶迵迵迵迵迴迴迴迴迲迲迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邘邖邖邖邖邔邔邔邔邒邒邒邒邒邐邐邐邐邏邏邏邏邎邎邎邎邎邍鄧鄧鄧鄦鄦鄦鄦鄥鄥鄥鄥鄤鄤鄤鄤鄤鄡鄡鄡鄡鄠鄠鄠鄠鄟鄟鄟鄟鄟鄝鄝鄝鄝鄜醻醻醻醻醹醹醹醹醸醸醸醸醷醷醷醷醶醶醶醶醶醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜赝赝赝赝靥靥靥靥厮厮厮厮厮厥厥厥厥厣厣厣厣厝厝厝厝厝厍厍 厍 厍 仄 仄 仄 仄 嘏 嘏 嘏 嘏 倌 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾輾輽輽輽迿迾迾迾迾迼迼迼迼迻迻迻迻迻迺迺迺迺迶迶迶迶迵迵迵迵迵迴迴迴迴迲迲迲迲迱迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邖邔邔邔邔邒邒邒邒邐邐邐邐邏邏邏邏邏邎邎邎邎邍邍鄧鄧鄦鄦鄦鄦鄦鄥鄥鄥鄥鄤鄤鄤鄤鄡鄡鄡鄡鄡鄠鄠鄠鄠鄟鄟鄟鄟鄝鄝鄝鄝鄜醻醻醻醹醹醹醹醸醸醸醸醸醷醷醷醷醶醶醶醶醳醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜赝赝赝赝赝靥靥靥靥厮厮厮厮厥厥厥厥厣厣厣厣厣厝厝厝厝厍厍 厍 厍 仄 仄 仄 仄 仄 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堀堀堀堀堀埭埭埭埭埽埽埽埽堍堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾輾輽輽輽輽迾迾迾迾迾迼迼迼迼迻迻迻迻迺迺迺迺迺迶迶迶迶迵迵迵迵迴迴迴迴迴迲迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邘邖邖邖邖邔邔邔邔邒邒邒邒邒邐邐邐邐邏邏邏邏邎邎邎邎邎邍鄧鄧鄧鄦鄦鄦鄦鄥鄥鄥鄥鄥鄤鄤鄤鄤鄡鄡鄡鄡鄠鄠鄠鄠鄟鄟鄟鄟鄟鄝鄝鄝鄝鄜醻醻醻醻醹醹醹醹醸醸醸醸醷醷醷醷醷醶醶醶醶醳醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜赝赝赝赝靥靥靥靥厮厮厮厮厮厥厥厥厥厣厣厣厣厝厝厝厝厝厍厍 厍 厍 仄 仄 仄 仄 嘏 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诨 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郢 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨荨轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾輾輽輽輽迿迾迾迾迾迼迼迼迼迼迻迻迻迻迺迺迺迺迶迶迶迶迶迵迵迵迵迴迴迴迴迲迲迲迲迱迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邖邔邔邔邔邒邒邒邒邐邐邐邐邐邏邏邏邏邎邎邎邎邍邍鄧鄧鄦鄦鄦鄦鄦鄥鄥鄥鄥鄤鄤鄤鄤鄡鄡鄡鄡鄡鄠鄠鄠鄠鄟鄟鄟鄟鄝鄝鄝鄝鄝鄜醻醻醻醹醹醹醹醹醸醸醸醸醷醷醷醷醶醶醶醶醳醳醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜赝赝赝赝赝靥靥靥靥厮厮厮厮厥厥厥厥厥厣厣厣厣厝厝厝厝厍厍 厍 厍 厍 仄 仄 仄 仄 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诤 诤 诤 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀堀堀堀埭埭埭埭埽埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾輾輽輽輽輽迿迾迾迾迾迼迼迼迼迻迻迻迻迺迺迺迺迺迶迶迶迶迵迵迵迵迴迴迴迴迴迲迲迲迲迱迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔邔邔邒邒邒邒邐邐邐邐邏邏邏邏邎邎邎邎邎邍鄧鄧鄧鄦鄦鄦鄦鄥鄥鄥鄥鄥鄤鄤鄤鄤鄡鄡鄡鄡鄠鄠鄠鄠鄠鄟鄟鄟鄟鄝鄝鄝鄝鄜醻醻醻醻醹醹醹醹醸醸醸醸醷醷醷醷醷醶醶醶醶醳醳醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜赝赝赝赝靥靥靥靥赝赝赝靥靥厮厥厥厥厣厣厣厣厝厝厝厝厝厍厍 厍 厍 仄 仄 仄 仄 嘏 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诨 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郢 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄塄堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨荨轄轄轄轄轃轃轃轃轂轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾輾輽輽輽迿迾迾迾迾迼迼迼迼迼迻迻迻迻迺堋塄塄堙堙迶迶迶迵迵迵迵迴迴迴迴迲迲迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邖邔邔邔邔邒邒邒邒邐邐邐邐邐邏邏邏邏邎邎邎邎邍邍鄧鄧鄧鄦鄦鄦鄦鄥鄥鄥鄥鄤鄤鄤鄤鄤鄡鄡鄡鄡鄠鄠鄠鄠鄟鄟鄟鄟鄝鄝鄝鄝鄝鄜醻醻醻醹醹醹醹醹醸醸醸醸醷醷醷醷醶醶醶醶醶醳醳醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜赝赝赝赝hrzqf唊h~wgxn`oy\vh[q{aesaho]izga赝靥厥厣厣厣厝厝厝厝厍厍厍 厍 厍 仄 仄 仄 仄 嘏 嘏 嘏 倥 倌 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诤 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀堀堀堀埭埭埭埭埽埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾輾輽輽輽輽迿迾迾迾迾迼迼迼迼堍停zgank[tac{d^ofaip``wS_i]ddS`lZ\fXjlUpvV停堞迴迴迴迴迴迲迲迲迲迱迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔邔邔邒邒邒邒邐邐邐邐邏邏邏邏邏邎邎邎邎邍邍鄧鄧鄦鄦鄦鄦鄥鄥鄥鄥鄥鄤鄤鄤鄤鄡鄡鄡鄡鄠鄠鄠鄠鄠鄟鄟鄟鄟鄝鄝鄝鄝醻醻醻醻醹醹醹醹醸醸醸醸醸醷醷醷醷醶醶醶醶醳醳醳醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜赝赝mqkq}ot{om~wjrf|t_ru\nx]rsYmpdbpljndhhfjzjomkntpbkdh厮厣厝厝厝厝厍厍 厍 厍 仄 仄 仄 仄 仄 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郫 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄塄堙堙堙堙堞堞堞堞堀堀堀堀堀埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨荨轄轄轄轄轃轃轃轃轂轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾輾輽輽輽迿迾迾迾迾迾迼埽憈OpdbpljndhhfjzjomkntpbkdhlmajmadklXp]_rS^{Q[tV]rSfvPl{UvoXmnJ挞迴迲迲迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邘邖韦yt亂y厃u僿~wt剎gtxfuyo|np{qpv~tvqqo{oyzghqr`hrzqf唊h~wgx邎邎邎邎邍邍鄧鄧迻{d^ofaip``wS_i]ddS`lZ\fXjlUpvVrhLnmEopJvlNopIoqNmlHutOsnR迴鄠鄟鄟鄟鄟鄟鄝鄝鄝鄝{d^ofaip``wS_i]ddS`lZ\fXjlUpvVrhLnmEopJvlNopIoqNmlHutOsnRw}J醶醶醶醶醳醳醳醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜efpg乮d俤nxgl僲o~llwhczifwnlqjelgoilfk_oj`inqhclZkv]qt`sfbumdhiii厮厝厝厍厍厍 厍 厍 仄 仄 仄 仄 嘏 嘏 嘏 嘏 倌 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诤 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埽埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾輽輽輽輽迿迾迾迾迾胎nlqjelgoilfk_oj`inqhclZkv]qt`sfbumdhiii\ck[jpXt^d^e^i[foRdwYnkSndMobL^aQ迴迲迲迲迲迱迱迱邜邜邚邚邚邚邘邘邘邘邖邖pt~nytipoj{g~}oyovho~lu|llprv{{~{ymqkq}ot{om~wjrf|t_r邎邎邎邎邍邍鄧鄧轂tpbkdhlmajmadklXp]_rS^{Q[tV]rSfvPl{UvoXmnJedItcKwlLtdNtkP輿鄠鄟鄟鄟鄟鄝鄝鄝鄝tpbkdhlmajmadklXp]_rS^{Q[tV]rSfvPl{UvoXmnJedItcKwlLtdNtkPspB醶醶醶醳醳醳醳醳孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜jn|jk|\atbcz_jz_c}_c塲e媐p卌z哸x俷muos{asnaekZ^l\]ppcf|_bk^hd]ho^xkctjhtcfle]h厥厍厍 厍 厍 仄 仄 仄 仄 仄 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郫 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堀堀堀堀堀埭埭埭埭埽埽埽埽堍堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾輾輽輽輽迿迾迾迾抬cz哸x俷muos{asnaekZ^l\]ppcf|_bk^hd]ho^xkctjhtcfle]hW`md_baiega^kl]_k\`iMjdQkcU迲迲迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邘邖邖t{tt乽{塲n奺t刡n僩l唂t~bn|kk~krefpg乮d俤nxgl僲o~llwhczifw邎邎邎邎邍鄧鄧鄧轂t`sfbumdhiii\ck[jpXt^d^e^i[foRdwYnkSndMobL^aQfjPjeLguR^qP輿鄟鄟鄟鄟鄟鄝鄝鄝鄝t`sfbumdhiii\ck[jpXt^d^e^i[foRdwYnkSndMobL^aQfjPjeLguR^qPlsB醶醶醶醳醳醳醳醲孜孜孜孜孜孜孜孜孜孜孜孜孜孜孜eihk刧k乤b協atlWi]僱l刢i僛pu\yx]wnhwpmiv\kla`fjpkmqqeisbht\mlibpimsjnfUagPcqafoRo]厮厍厍 厍 仄 仄 仄 仄 嘏 嘏 嘏 嘏 倌 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诨 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾輾輽輽輽迿迾塥 +ci僛pu\yx]wnhwpmiv\kla`fjpkmqqeisbht\mlibpimsjnfUagPcqafoRo]Og\]^a`saZjT^nSbg\[jRZkR迲迲迲迲迱迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖co媖v坥{廸{恎r俇i協i奭r^uujn|jk|\atbcz_jz_c}_c塲e媐p卌z哸x傔邎邎邍邍鄧鄧鄦轂d]ho^xkctjhtcfle]hW`md_baiega^kl]_k\`iMjdQkcUjqTZsAbtNfjG輿鄟鄟鄟鄟鄝鄝鄝鄝鄝d]ho^xkctjhtcfle]hW`md_baiega^kl]_k\`iMjdQkcUjqTZsAbtNfjGrqT醶醶醳醳醳醳醳醲孜孜孜孜孜孜孜孜孜孜孜孜孜孜c`俫k唃b乢r卝a~h\|jen]wem俌ja]yWh~VmxZjvcco^br^jdcn\dlk_mjPhh]bwZik]ksPleXfmSbaQ`bZadXd^赝厍仄 仄 仄 仄 仄 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堀堀堀堀堀埭埭埭埭埽埽埽埽堍堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾輾輽輽輽輽轁n]wem俌ja]yWh~VmxZjvcco^br^jdcn\dlk_mjPhh]bwZik]ksPleXfmSbaQ`bZadXd^Vkd[x^ZuX\mbYi`[l\GtO迲迲迲迲迱迱邜邜邚邚邚邚邚邘邘邘邘邖邖邖so}en坮o刱j奩gZc宎g巈c巈ihk刧k乤b協atlWi]僱l刢i僛pu\yx]wn邎邎邎邍鄧鄧鄧鄦轂ibpimsjnfUagPcqafoRo]Og\]^a`saZjT^nSbg\[jRZkRbqGgtLdkKawG輾鄟鄟鄟鄟鄝鄝鄝鄝ibpimsjnfUagPcqafoRo]Og\]^a`saZjT^nSbg\[jRZkRbqGgtLdkKawG`vW醶醶醳醳醳醳醲醲孜孜孜孜孜孜孜孜孜孜孜孜孜^a塧\媋b抔fsf}me刯Z協isf^udm~glUe~]jwbmsSkwXZxXgpcqhfl`dqgPnoLkgXihTpkOnjPynXp]Vrc[m^QmgJtcXp[赝仄仄 仄 仄 嘏 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诨 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郢 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨荨轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾輾輽輽輽塥 +fisf^udm~glUe~]jwbmsSkwXZxXgpcqhfl`dqgPnoLkgXihTpkOnjPynXp]Vrc[m^QmgJtcXp[^jS\sYTuhRo_No`Tnb迲迲迲迱迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖e]tl噈k俴m坘`ni哸h廲`俫k唃b乢r卝a~h\|jen]wem俌ja]yWh~Vmx邎邎邍邍鄧鄧鄧鄦轂Zik]ksPleXfmSbaQ`bZadXd^Vkd[x^ZuX\mbYi`[l\GtOLpSTmSPmGVjL輾鄟鄟鄟鄝鄝鄝鄝鄝Zik]ksPleXfmSbaQ`bZadXd^Vkd[x^ZuX\mbYi`[l\GtOLpSTmSPmGVjL[lV醶醳醳醳醳醳醲醲孜孜孜孜孜孜孜孜孜孜孜孜cT恎Z刪\坆_ga坧S僯U奾c僱c}dh哣q奬k乪kv[ll`pxYfyQ^n]^wfhi\_eZgaNsfNo]TwdRtjDxeJleHsgXlaUvgIugUqgLrhRk\赝仄仄 仄 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诤 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀堀堀堀埭埭埭埭埽埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾輾輽輽輽踏hc僱c}dh哣q奬k乪kv[ll`pxYfyQ^n]^wfhi\_eZgaNsfNo]TwdRtjDxeJleHsgXlaUvgIugUqgLrhRk\UlVS|iWykClhQd]迲迲迲迱迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖`V|pi{sZ塦ezp^me僞a塧\媋b抔fsf}me刯Z協isf^udm~glUe~]jwbms邎邎邍鄧鄧鄧鄦鄦轂TpkOnjPynXp]Vrc[m^QmgJtcXp[^jS\sYTuhRo_No`TnbLs^QjWMm`JbU輾鄟鄟鄟鄝鄝鄝鄝TpkOnjPynXp]Vrc[m^QmgJtcXp[^jS\sYTuhRo_No`TnbLs^QjWMm`JbUTdU醶醳醳醳醳醲醲醲孜孜孜孜孜孜孜孜孜孜孜hZ奬`刌W刬_別S^N恈S妀X乢\峟m孻b匽gtRgvZfr`aeT_tSYz]YyZ[abiUd_Vl`UgeBnqQq_MoXBZPylEqbJwiPzoZvl[僷P|k_~_P|U靥仄 嘏 嘏 嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诨 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄塄堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨荨轄轄轄轄轃轃轃轃轂轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾輾輽輽cS妀X乢\峟m孻b匽gtRgvZfr`aeT_tSYz]YyZ[abiUd_Vl`UgeBnqQq_MoXBZPylEqbJwiPzoZvl[僷P|k_~_P|USsWIh`Hq[Do[迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邖`^~aQ乪M|kQ刢f俢T恎Z刪\坆_ga坧S僯U奾c僱c}dh哣q奬k乪kv[ll`px邎邍邍鄧鄧鄧鄦鄦轂RtjDxeJleHsgXlaUvgIugUqgLrhRk\UlVS|iWykClhQd]Qp^Fr[KcYMjZ輾鄟鄟鄝鄝鄝鄝鄝鄜RtjDxeJleHsgXlaUvgIugUqgLrhRk\UlVS|iWykClhQd]Qp^Fr[KcYMjZ\o[醶醳醳醳醳醲醲醲孜孜孜孜孜孜孜孜孜孜oh俧f|hl怸b嘯`刏\WY刏i}^l峘m區b|Wn]d}_ouRflXisShkVbzObrScqMlmXnmOhjTieTefWpjWvcWodPnfSolXskL~mPtgTuaNyiZxdUkf?w^厥嘏 嘏 嘏 倥 倌 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诤 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀堀堀堀埭埭埭埭埽埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾輾輽輽WY刏i}^l峘m區b|Wn]d}_ouRflXisShkVbzObrScqMlmXnmOhjTieTefWpjWvcWodPnfSolXskL~mPtgTuaNyiZxdUkf?w^@oeGkaGrX迲迲迱迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔gT}p^sWyk[俬Z奬`刌W刬_別S^N恈S妀X乢\峟m孻b匽gtRgvZfr`aeT_t邎邍邍鄧鄧鄦鄦鄦轂MoXBZPylEqbJwiPzoZvl[僷P|k_~_P|USsWIh`Hq[Do[KaYMpbOwS`wV輾鄟鄟鄝鄝鄝鄝醻MoXBZPylEqbJwiPzoZvl[僷P|k_~_P|USsWIh`Hq[Do[KaYMpbOwS`wVcr\醳醳醳醳醲醲醲醲孜孜孜孜孜孜孜孜孜ob巗h~lgz`q孿g~]^y_Y}`_Y^_p{Ra刄j係h~[^乛_{QemLlePlqK`zKY~XhtTbi_rm[ecL^bPl_RghJr`Rf[Nk_Phi\jk]clZhe`gcSleMp_CjdFe_?p]仄嘏 嘏 倥 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郫 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄塄堙堙堙堙堞堞堞堞堀堀堀堀堀埭埭埭埭埽埽埽埽堍堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轂轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾輾輽_Y}`_Y^_p{Ra刄j係h~[^乛_{QemLlePlqK`zKY~XhtTbi_rm[ecL^bPl_RghJr`Rf[Nk_Phi\jk]clZhe`gcSleMp_CjdFe_?p]>oYCf_迲迲迱迱邜邜邚邚邚邚邘邘邘邘邘邖邖邖邖邔o_ymfzwe{oh俧f|hl怸b嘯`刏\WY刏i}^l峘m區b|Wn]d}_ouRflXisShk邍邍鄧鄧鄧鄦鄦鄦轂WvcWodPnfSolXskL~mPtgTuaNyiZxdUkf?w^@oeGkaGrXFlXLnUEz_QzT輾鄟鄟鄝鄝鄝鄝鄜醻WvcWodPnfSolXskL~mPtgTuaNyiZxdUkf?w^@oeGkaGrXFlXLnUEz_QzTXp\醳醳醳醳醲醲醲醲孜孜孜孜孜孜孜孜孜yv刴o{nk坓vcnyTc僣echvas僢w乢q匱Y塧W凷Wr^^yX\qa]rPXpN\sZVwUYxNadagePjbM_aNv]Qsb\ed[^`YdZNh^IlQKlUVhfWvmJrcLw^MtcDqY@gX厮嘏 嘏 倌 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诤 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埽埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾輾{{^cechvas僢w乢q匱Y塧W凷Wr^^yX\qa]rPXpN\sZVwUYxNadagePjbM_aNv]Qsb\ed[^`YdZNh^IlQKlUVhfWvmJrcLw^MtcDqY@gXJf[?fY迲迱迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邔邔ke俿n{ob巗h~lgz`q孿g~]^y_Y}`_Y^_p{Ra刄j係h~[^乛_{QemLlePlq邍邍鄧鄧鄦鄦鄦鄦轂Jr`Rf[Nk_Phi\jk]clZhe`gcSleMp_CjdFe_?p]>oYCf_IdWLmYI{ZGjM輾鄟鄝鄝鄝鄝鄜醻Jr`Rf[Nk_Phi\jk]clZhe`gcSleMp_CjdFe_?p]>oYCf_IdWLmYI{ZGjM[tU醳醳醳醳醲醲醲醲孜孜孜孜孜孜孜孜irmwgn俢k區vz[g~]e~\c~Ya{Yk~TYqTf|MZvJdsO`uMauNaqU\pTWkMZlHOfOSgSc`ZbVKaTMg]FciK[\OdfUe_P_cXeYVkeWl]Pq_Sg^WwXIxRMsVDwRLoPElX厝倥 倌 倌 倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堀堀堀堀堀埭埭埭埭埽埽埽埽堍堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾輾郦 +]e~\c~Ya{Yk~TYqTf|MZvJdsO`uMauNaqU\pTWkMZlHOfOSgSc`ZbVKaTMg]FciK[\OdfUe_P_cXeYVkeWl]Pq_Sg^WwXIxRMsVDwRLoPElXGm`迲迱迱邜邜邚邚邚邚邘邘邘邘邘邖邖邖邖邔邔km唋syv刴o{nk坓vcnyTc僣echvas僢w乢q匱Y塧W凷Wr^^yX\qa]rPXp邍鄧鄧鄧鄦鄦鄦鄦轁\ed[^`YdZNh^IlQKlUVhfWvmJrcLw^MtcDqY@gXJf[?fYOnXEpMBlNMvL輾鄟鄝鄝鄝鄝鄜醻醻\ed[^`YdZNh^IlQKlUVhfWvmJrcLw^MtcDqY@gXJf[?fYOnXEpMBlNMvL_bS醳醳醳醲醲醲醲醱孜孜孜孜孜孜孜孜or僶qzaf|dhv]o~WhsSf]]tVckSUwQPoUayBYwNWvORyPSpCTwB]cKZkENoONfCQcJTbCYYEZXL]fJVWJNbL\[OceUUfQmTVnXVrYTr^QjOQsNItINqYEzXNtTQeR靥倥 倌 倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诨 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾軣WhsSf]]tVckSUwQPoUayBYwNWvORyPSpCTwB]cKZkENoONfCQcJTbCYYEZXL]fJVWJNbL\[OceUUfQmTVnXVrYTr^QjOQsNItINqYEzXNtTQeRRlT迱迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邖邔邔prxirmwgn俢k區vz[g~]e~\c~Ya{Yk~TYqTf|MZvJdsO`uMauNaqU\pTWk邍鄧鄧鄦鄦鄦鄦鄦轁OdfUe_P_cXeYVkeWl]Pq_Sg^WwXIxRMsVDwRLoPElXGm`CmWCiCNgNJoF輾鄝鄝鄝鄝鄝鄜醻醻OdfUe_P_cXeYVkeWl]Pq_Sg^WwXIxRMsVDwRLoPElXGm`CmWCiCNgNJoFKeV醳醳醳醲醲醲醲醱孜孜孜孜孜孜孜_i|^mtQwsUjtad~ba~XbzP\jYknXWuHTyOTkMXpEY嘚SKapH\wDUoITbK\fINd;Tc?OjFP]DPcGTb@SY?QU@JaDTjJOcGV[LoaAjaHn\Rq]PmUTtYFmWJ{YR`Gx\HmPXwW仄倌 倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诤 诤 诤 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀堀堀堀埭埭埭埭埽埽埽埽堍堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾輾ba~XbzP\jYknXWuHTyOTkMXpEY嘚SKapH\wDUoITbK\fINd;Tc?OjFP]DPcGTb@SY?QU@JaDTjJOcGV[LoaAjaHn\Rq]PmUTtYFmWJ{YR`Gx\HmPXwW迱迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔iq噊r僶qzaf|dhv]o~WhsSf]]tVckSUwQPoUayBYwNWvORyPSpCTwB]cKZk鄧鄧鄧鄦鄦鄦鄦鄥轁L\[OceUUfQmTVnXVrYTr^QjOQsNItINqYEzXNtTQeRRlTEpOVnKOkOPdS輾鄝鄝鄝鄝鄜醻醻醻L\[OceUUfQmTVnXVrYTr^QjOQsNItINqYEzXNtTQeRRlTEpOVnKOkOPdSPcR醳醳醲醲醲醲醲醱孜孜孜孜孜孜孜\dXg乗fSv}^tuNjuRbpHXnS[qQYlD]sMdgB[uPk:Pb4GgDSUGR^FQY8T]E^`@c\O_WLbYMsXMl^Ox[GkTUk]Fs]Iv\POFpWDkQ厥倌 倌 倌 倜 倜 倜 倜 俾 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诨 +诨 +诨 +诨 +诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郛 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郢 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭埭埭埭埭埽埽埽埽堍堍堍堍荨荨荨荨荨轄轄轄轄轃轃轃轃轂轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾狮NjuRbpHXnS[qQYlD]sMdgB[uPk:Pb4GgDSUGR^FQY8T]E^`@c\O_WLbYMsXMl^Ox[GkTUk]Fs]Iv\POFpWDkQ迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邖邔邔邔_i|^mtQwsUjtad~ba~XbzP\jYknXWuHTyOTkMXpEY嘚SKapH\wDUoITbK\f鄧鄧鄧鄦鄦鄦鄦鄥轁DTjJOcGV[LoaAjaHn\Rq]PmUTtYFmWJ{YR`Gx\HmPXwWQyP>bYIpOBiW輾鄝鄝鄝鄝鄜醻醻醻DTjJOcGV[LoaAjaHn\Rq]PmUTtYFmWJ{YR`Gx\HmPXwWQyP>bYIpOBiWKiV醳醳醲醲醲醲醱醱孜孜孜孜孜孜孜^dw^bw]bmXpuMhjOhhLhrPdmC[t;`oB[r5[sRb7NZ?Of>V]anC`^FS\HhMCdSP`UMdWH^VTcUSgVEuL@pVEgPEfUDmR倌 倌 倜 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 +诤 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 郯 郯 郫 郫 郫 郫 郛 郛 郛 +郛 +郗 +郗 +郗 +郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀堀堀堀埭埭埭埭埽埽埽埽埽堍堍堍堍荨荨荨荨轄轄轄轄轃轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾軣MhjOhhLhrPdmC[t;`oB[r5[sRb7NZ?Of>V]anC`^FS\HhMCdSP`UMdWH^VTcUSgVEuL@pVEgPEfU迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔邔\dXg乗fSv}^tuNjuRbpHXnS[qQYlD]sMdgB[uNhEQaDTY>RfCMc-Qd/TYNh.Xc^RNhEQaDTY>RfCMc-Qd/TYNh.Xc^RanC`^FS\HhMCdSP`UMdWH^VTcUSgVEuL@pVEgPEfUDmR@`TKaVI^M輾鄝鄝鄝鄜醻醻醻醹8cd>anC`^FS\HhMCdSP`UMdWH^VTcUSgVEuL@pVEgPEfUDmR@`TKaVI^MBdU醳醲醲醲醲醱醱醱孜孜孜孜孜孜Wo{QpyTh|QdjUdiLaxNjsI^jTZoHUmAai;\o1_k6fp*Qh7Js5Vd3SiEDgHfBVm:Vm5I]BS_?HT(Sf(Re!J]2Ol5M]0R^DOX;[S7RU6[G8KO/UI9VO@TP6WD;\LEXRK`[IaU厝倌 倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +鼐 芈 厝厝^b|Wn]d}_ouRfl厮厍厍倮 +偌 +诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 诙 时hl怸b嘯`刏\WY刏i}^l峘m區b|诟 诎 郗 +郗 +郜 +郜 +郜 +郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀堀堀堀埭埭埭埭埽郄 +诒 ]d}_ouRflXisShkVbzObrScqMlm~凮郫 堀轄轄轄轃轃轃轃轂轂轂轂轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾邾UdiLaxNjsI^jTZoHUmAai;\o1_k6fp*Qh7Js5Vd3SiEDgHfBVm:Vm5I]BS_?HT(Sf(Re!J]2Ol5M]0R^DOX;[S7RU6[G8KO/UI9VO@TP6WD;\LEXRK`[迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔邔邔Vn}Um}PgGktQ[sCavK_vHVlLVsA_y3ex=X{@Nz^R^RJd;PfAMjC]-T^%LV3RZ)F\(Bd6JX@J]:XL/OU2VO&OS-KM9VR8ON)[B:TE7aO;RE?[O厥倜 倜 倜 倜 俾 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +乜 仄靥`_Y^_p{Ra刄j係h~[^乛_{QemLlePlqK`zKY~Xht厣俾 倩 +诠 诠 诠 诠 诟 诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 郾 郾 诔 憜Xob巗h~lgz`q孿g~]^y_Y}`_Y^_p{Ra刄j係h~[^乛_{钳郜 +郜 +郜 +郢 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄塄堙堙堙堙堞堞堞堞堀堀堀堀堀埭埭郇 +虱Ra刄j係h~[^乛_{QemLlePlqK`zKY~XhtTbi_rm[ecL^bPl_泉轃轃轃轃轂轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾HfnQ^jJgnA_hJ_gA_nJfu=eh7^g3ih1Xb+GZ,Rf)Tf)H`3Lf2G`>Jd;PfAMjC]-T^%LV3RZ)F\(Bd6JX@J]ir8堞堞堞aj89VR8ON)[B:TE7aO;RE邜邜邚邚邚邚邘邘邘邘邘邖邖邖邖邔邔邔邔邒QpyTh|QdjUdiLaxNjsI^jTZoHUmAai;\o1_k6fp*Qh7Js5Vd3SiEDgfG輾鄝鄝鄜醻醻醻醻醹2Ol5M]0R^DOX;[S7RU6[G8KO/UI9VO@TP6WD;\LEXRK`[IaU6_M9lJ>fG7hR醲醲醲醲醱醱醱醱孜孜孜孜孜孜OjjDcqD]mBibCkdJYl?fw8drGfqEcoC`g5fa-`e2`b5T[6Oe=Oe1Ki&Jh"RY赝厥厣厣厥靥7:n4LX:PZ3H\*Gd;C_/Aa8K\?Lb.Qb'IQ+Oc,VZ-MO.OI4M?/[K7TF-YI3TH厮倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +倬 +亓 厥cnyTc僣echvas僢w乢q匱Y塧W凷Wr^^yX\qa]rPXpN\sZVwUYxNadagePjb啬 倩 +诠 诟 诟 诟 诟 诜 诜 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 诖 崉[km唋syv刴o{nk坓vcnyTc僣echvas僢w乢q匱Y塧W凷Wr^^yX\qa]r钱郜 +郢 +郢 +郢 +郢 +郦 +塥 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀堀堀埭郇 +唨Uas僢w乢q匱Y塧W凷Wr^^yX\qa]rPXpN\sZVwUYxNadagePjbM_aNv]Qsb\ed亁E埭轃轂轂轂轂轁轁轁轁轁轀轀轀轀輿輿輿輿輾輾輾軣BibCkdJYl?fw8drGfqEcoC`g5fa-`e2`b5T[6Oe=Oe1Ki&Jh"RY-Ub;Tg*Kl-Pm.9k:?g7:n4LX:PZ3H\*Gd軣迵迵迴迴迴迴迲迲迲迲埭7TF-YI邜邜邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔邔邔邒U\|M_jHfnQ^jJgnA_hJ_gA_nJfu=eh7^g3ih1Xb+GZ,Rf)Tf)H`3Lf2G`>Jd鄦鄦鄦鄦鄦鄥鄥鄥轁)F\(Bd6JX@J]:XL/OU2VO&OS-KM9VR8ON)[B:TE7aO;RE?[O=WCfm6[f:dd>fb4S]5Xc:\h ^[)VX'Ta赝厣厣厣厣厣厝靥6AU2?T2IZ2Ba46R38]7J]=KS/JO*PW)MD4LL3KS7GP=MM-UC-[U*[J3T?+\@倜 倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +乩 厝ck區vz[g~]e~\c~Ya{Yk~TYqTf|MZvJdsO`uMauNaqU\pTWkMZlHOfOSgSc`ZbVKaTMg]Fci啬 俸 +诟 诟 诟 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 诤 +ik卍n|prxirmwgn俢k區vz[g~]e~\c~Ya{Yk~TYqTf|MZvJdsO`uMauNaqU\pTWkMZl诓 郢 +郢 +郢 +郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堀堀堀堀郓 +亊[\c~Ya{Yk~TYqTf|MZvJdsO`uMauNaqU\pTWkMZlHOfOSgSc`ZbVKaTMg]FciK[\OdfUe_P_c~~A轂轂轂轂轁轁轁轁轀轀轀轀輿輿輿輿輿輾輾輾kvO@TnAXqfm6[f:dd>fb4S]5Xc:\h ^[)VX'Ta,N`&Rh3Rf5Tr+Og1Gl)Hi/Ji6AU2?T輽迵迵迵迴迴迴迴迴迲迲迲迲迱迱迻邜邚邚邚邚邘邘邘邘邘邖邖邖邖邔邔邔邔邒邒DcqD]mBibCkdJYl?fw8drGfqEcoC`g5fa-`e2`b5T[6Oe=Oe1Ki&Jh"RY-Ub鄦鄦鄦鄦鄥鄥鄥鄥轀*Gd;C_/Aa8K\?Lb.Qb'IQ+Oc,VZ-MO.OI4M?/[K7TF-YI3TH0]G.^D!bE輾鄝鄜醻醻醻醻醹醹*Gd;C_/Aa8K\?Lb.Qb'IQ+Oc,VZ-MO.OI4M?/[K7TF-YI3TH0]G.^D!bE%NI醲醲醲醱醱醱醱醱孜孜孜孜孜FbvEo}8ew4`m5Un;`m@ha;_n7\j6fh4ce>Yj3^^4_a:\_?_W-[c%V]/Ug%Ji厥厣厣厣厣厝厝厣Yj3^^4_a:\_?_W-[c%V]/Ug%Ji/Pp,No#Oi.Op"Lb(E_)6_5;[茻迵迵迵迵迵迴迴迴迴迲迲迲迲迱迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邖邔邔邔邔邒邒Cev<[m@TnAXqfm6[f:dd>fb4S]5Xc:\h ^[)VX'Ta,N`&Rh鄦鄦鄦鄦鄥鄥鄥鄥轀2Ba46R38]7J]=KS/JO*PW)MD4LL3KS7GP=MM-UC-[U*[J3T?+\@-YK-XN輾鄝鄜醻醻醻醹醹醹2Ba46R38]7J]=KS/JO*PW)MD4LL3KS7GP=MM-UC-[U*[J3T?+\@-YK-XN'QL醲醲醲醱醱醱醱醰孜孜孜孜孜>bx:l{ev=ck6Xq,cz-eq3\l?ja;cm2Sd'Us6ak.fa3fe5W])W`赝厥厣厣厣厣厝厝厝赝.=X.;d4LT/MM1LI5TP6ZJ4VN%UPYR*YV+TM1]R2_V1^S+PI5_N3SI2EK倜 倜 倜 俾 俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倮 +倏 +乩 厣^mtQwsUjtad~ba~XbzP\jYknXWuHTyOTkMXpEY嘚SKapH\wDUoITbK\fINd;Tc?OjFP]DPcGTb@SY?QU@JaDTjJOc啬 诜 诜 诜 诜 诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 Y{刐z圸t匼t噁l僟i|^mtQwsUjtad~ba~XbzP\jYknXWuHTyOTkMXpEY嘚SKapH\wDUoITbK\fINd;Tc?OjFP]郦 +塥 +塥 +塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀堀厏[ba~XbzP\jYknXWuHTyOTkMXpEY嘚SKapH\wDUoITbK\fINd;Tc?OjFP]DPcGTb@SY?QU@JaDTjJOcGV[LoaAjaHn\泉轁轁轁轁轀轀轀轀轀輿輿輿輿輾輾輾邾:Xi>ev=ck6Xq,cz-eq3\l?ja;cm2Sd'Us6ak.fa3fe5W])W`!I^$OZ#Of%D`&Gc%Je,>X0D^堙迶迵迵迵迵迴迴迴迴迴迲迲迲迲迱迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔邔邒邒邒8ew4`m5Un;`m@ha;_n7\j6fh4ce>Yj3^^4_a:\_?_W-[c%V]/Ug%Ji/Pp,No鄦鄦鄦鄥鄥鄥鄥鄥轀,EU+Pk:Pb4GgDSUGR^FQY8T]E^`@c\仄 诜 诜 诜 诙 诙 诙 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 郾 N剠c|Zo}Vw圿o刯q塡dXg乗fSv}^tuNjuRbpHXnS[qQYlD]sMdgB[uPk:Pb塥 +塥 +塥 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堙堞堞堞堞堀堀Sv}^tuNjuRbpHXnS[qQYlD]sMdgB[uPk:Pb4GgDSUGR^FQY8T]E^`@c\O_WLbYMsXMl^Ox[轁轁轁轀轀轀轀輿輿輿輿輾輾輾輾脓8et;esB`z3\{6az6hz7We-`c/Sg-Z_7ai0Yk0bg)V](^\3YX'Qh6Sc/Lb$Je%Lk#LZ*I\堙迶迶迵迵迵迵迴迴迴迴迲迲迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邖邖邖邖邖邔邔邔邔邒邒邒ev=ck6Xq,cz-eq3\l?ja;cm2Sd'Us6ak.fa3fe5W])W`!I^$OZ#Of鄦鄦鄦鄥鄥鄥鄥鄤轀4LT/MM1LI5TP6ZJ4VN%UPYR*YV+TM1]R2_V1^S+PI5_N3SI2EK8LG8TV輾鄜醻醻醻醹醹醹醹4LT/MM1LI5TP6ZJ4VN%UPYR*YV+TM1]R2_V1^S+PI5_N3SI2EK8LG8TV&QL醲醲醱醱醱醱醰醰孜孜孜孜孜Rb7NZ?Of>V]anC`^FS\厝俟 +诙 诙 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 AytUuUrzQjtZxz[v俓f{^dw^bw]bmXpuMhjOhhLhrPdmC[t;`oB[r5[sRbgoA塥 +堠 +堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞堀]bmXpuMhjOhhLhrPdmC[t;`oB[r5[sRb7NZ?Of>V]anC`^FS\HhMCdSP`UMdWH^V轁轀轀轀轀轀輿輿輿輿輾輾輾輾Ab2f{8c}=dx0kl1_i.bo1Zu)Ss/Th'\h-[g0]b*Rd.Si'Wh4Ll.Dd/K^2Q],Qb/Fl-Qh堙迶迶迵迵迵迵迴迴迴迴迴迲迲迲迲迱迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔邔邔邒邒邒=mr8et;esB`z3\{6az6hz7We-`c/Sg-Z_7ai0Yk0bg)V](^\3YX'Qh6Sc/Lb鄦鄦鄥鄥鄥鄥鄥鄤轀1Q[NhEQaDTY>RfCMc-Qd/TYNh.XcNhEQaDTY>RfCMc诙 堠 +堠 +堠 +堠 +塄 +塄 +塄 +塄塄堙堙堙堙堞堞堞堞堀Um}PgGktQ[sCavK_vHVlLVsA_y3ex=X{@NzNhEQaDTY>RfCMc-Qd/TYNh.Xc^R轀轀轀轀輿輿輿輿輿輾輾輾輾0dx/]'Y']~3au+\~6fy%^el#Wq!ZtPg!Zo$Rl)Zn.Yu5Mk(?],@c3J],Lg-@m!Aj迶迶迶迵迵迵迵迴迴迴迴迲迲迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邘邖邖邖邖邔邔邔邔邒邒邒邒Ab2f{8c}=dx0kl1_i.bo1Zu)Ss/Th'\h-[g0]b*Rd.Si'Wh4Ll.Dd/K^2Q]鄦鄦鄥鄥鄥鄥鄤鄤轀2[Z;ZX,YS8_R8\T)PT+ZQP\&VS!P_#RY!SO UVOTLH%DQ(EM5RM)LG輽鄜醻醻醻醹醹醹醹醹2[Z;ZX,YS8_R8\T)PT+ZQP\&VS!P_#RY!SO UVOTLH%DQ(EM5RM)LG2FR醲醱醱醱醱醱醰醰孜孜孜孜孜7c3h+f,Yz%\/\&Sq%Qs)Tu,en/mu'euXm"Pt%^d,Li0Rp(Wr2Vh靥厣厣厣厝厝厝厝厍厮3RX(Yb.aZ*YU(V[+V[,NJ*ZNNV RQJTHfBVm:Vm5I]BS_?HT(Sf(Re!J]2Ol5M]0R^DOX;[S7RU仄 诙 诙 诙 诘 诘 诘 诘 诖 诖 诖 诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 诘 M厈QuS|tKtqMr丱uzYlyWo{QpyTh|QdjUdiLaxNjsI^jTZoHUmAai;\o1_k6fp*Qh7Js5Vd3SiEDgHfBVm:Vm5I]BS_?HT(Sf郗 堠 +堠 +堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞堞黔Th|QdjUdiLaxNjsI^jTZoHUmAai;\o1_k6fp*Qh7Js5Vd3SiEDgHfBVm:Vm5I]BS_?HT(Sf(Re!J]2Ol5M]0R^DOX;[S7RU6[G8KO/UI9VOnq:轀轀轀輿輿輿輿輾輾輾輾転+f,Yz%\/\&Sq%Qs)Tu,en/mu'euXm"Pt%^d,Li0Rp(Wr2Vh$Bm'@`"DV.;\5F]輾迶迶迵迵迵迵迵迴迴迴迴迲迲迲迲迱迱迱邜邚邚邚邚邚邘邘邘邘邖邖邖邖邔邔邔邔邔邒邒邒邒0dx/]'Y']~3au+\~6fy%^el#Wq!ZtPg!Zo$Rl)Zn.Yu5Mk(?],@c3J]鄦鄦鄥鄥鄥鄥鄤鄤轀9X]:ZS1`O.bN6c[!eTTWNP#NYG_'ER'BbU\$ILXN"TU&HH(UK*QJ輽鄜醻醻醻醹醹醹醹醸9X]:ZS1`O.bN6c[!eTTWNP#NYG_'ER'BbU\$ILXN"TU&HH(UK*QJ+BU醲醱醱醱醱醰醰醰孜孜孜孜孜4d%e1e-ey#Sv,Qs#aq"^m-en+o{ vu!iq`o)Uq0^q [h,Xn.\d&Mq靥厣厣厣厝厝厝厝厍厮(Qc*]e#X^(Z^YSVW+LUWMNUWCMOJd;PfAMjC]-T^%LV3RZ)F\(Bd6JX@J]:XL/OU2VO倮 诙 诘 诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 Q垀W|KpxP{{HzHs刉dtNlwKi~U\|M_jHfnQ^jJgnA_hJ_gA_nJfu=eh7^g3ih1Xb+GZ,Rf)Tf)H`3Lf2G`>Jd;PfAMjC]-T^Zn>堠 +堠 +塄 +塄 +塄 +塄塄堙堙堙堙堞堞堞堞郛 U\|M_jHfnQ^jJgnA_hJ_gA_nJfu=eh7^g3ih1Xb+GZ,Rf)Tf)H`3Lf2G`>Jd;PfAMjC]-T^%LV3RZ)F\(Bd6JX@J]:XL/OU2VO&OS-KM9VR8ON郜 轀輿輿輿輿輿輾輾輾輾郦 +1e-ey#Sv,Qs#aq"^m-en+o{ vu!iq`o)Uq0^q [h,Xn.\d&Mq1C`,Ld'Cc'DTfhE迶迶迶迵迵迵迵迴迴迴迴迲迲迲迲迲迱迱邜邜邚邚邚邚邘邘邘邘邘邖邖邖邖邔邔邔邔邒邒邒邒邒+f,Yz%\/\&Sq%Qs)Tu,en/mu'euXm"Pt%^d,Li0Rp(Wr2Vh$Bm'@`"DV鄦鄥鄥鄥鄥鄤鄤鄤轀.aZ*YU(V[+V[,NJ*ZNNV RQJTfm6[f:dd>fb4S]5Xc:\h ^[)VX'Ta,N`&Rh3Rf5Tr+Og1Gl)Hi/Ji6AU2?T2IZ2Ba46R38]7J]=KS/JO*PW)MD厝诘 诘 诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 KxzYqy\qy[nqHn~Ho丟qtNj{Fg{DuwCev<[m@TnAXqfm6[f:dd>fb4S]5Xc:\h ^[)VX'Ta,N`&Rh3Rf5Tr+Og1Gl)Hi/Ji6AU2?T2IZ堠 +塄 +塄 +塄 +塄堙堙堙堙堞堞堞堞rXDuwCev<[m@TnAXqfm6[f:dd>fb4S]5Xc:\h ^[)VX'Ta,N`&Rh3Rf5Tr+Og1Gl)Hi/Ji6AU2?T2IZ2Ba46R38]7J]=KS/JO*PW)MD4LL3KS7GP=MM-UC輿輿輿輿輾輾輾輾輽0ev1cs!ex#j~_zhr b|%bxac_e]nbj\kbzRu&LvLuHt Yb&Nl"Eb'V`迶迶迶迵迵迵迵迴迴迴軣堞堀堀堀堀埭埭埭埭埭埭埭埭埽埽埽埽埽迶邖邖邖邔邔邔邔邒邒邒邒邒邐)l*a{*dy%_sekeh ljik!cn$btbs-dv#ar+[xLmNk(Hh,Mh)We+Mg鄥鄥鄥鄥鄥鄤鄤鄤轀 d`XUSW.Q]3Ib"S\SPUGRIORESNJ GWYNVS!QN]R"PO$XO輽鄜醻醻醻醻醹醹醹醹醸醸 d`XUSW.Q]3Ib"S\SPUGRIORESNJ GWYNVS!QN]R"PO$XO HO醱醱醱醱醰醰醰醰孜孜孜孜孜,hw"cz-]v jv#fh#bx]k ghcn ag_e\qXnXu[oNmRj\qPd靥厣厝厝厝厝厝厍厍 厮$WP_Q `K!Z_#ZQKWDU#PRHQQVMO^IPK#AHHE>MAREQ#ZI俾 俾 俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +厍Nl咷owFb|Fj|FbvEo}8ew4`m5Un;`m@ha;_n7\j6fh4ce>Yj3^^4_a:\_?_W-[c%V]/Ug%Ji/Pp,No#Oi.Op"Lb(E_)6_5;[Yj3^^4_a:\_?_W-[c%V]/Ug%Ji/Pp,No#Oi.Op"Lb(E_)6_5;[Yj3^^4_a:\_?_W-[c%V]/Ug%Ji/Pp,No#Oi.Op"Lb(E_)6_5;[MAREQ#ZI!LUNOYN#T[KT迶邖邖邔邔邔邔邒邒邒邒邐邐1cs!ex#j~_zhr b|%bxac_e]nbj\kbzRu&LvLuHt Yb&Nl"Eb鄥鄥鄥鄥鄤鄤鄤鄤轀[S&_O#SU+L_,Md*DZ$WM#LJHFZJVLMHLPNHCM"LSQOYC%NV輽鄜醻醻醻醹醹醹醹醹醸醸[S&_O#SU+L_,Md*DZ$WM#LJHFZJVLMHLPNHCM"LSQOYC%NVRZ醱醱醱醰醰醰醰醰孜孜孜孜赝n$hzaq'dxjc]]#Vi([nWfSoWk%^s^rdn]oRcVcesZk靥厣厝厝厝厝厍厍 厍 厮$OPQL]R U\$WRQV%WE%VEMRTWORNH%VN!TE MC"CHMVNK RJ俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +亓 Niy?i僆i?f?n>bx:l{ev=ck6Xq,cz-eq3\l?ja;cm2Sd'Us6ak.fa3fe5W])W`!I^$OZ#Of%D`&Gc%Je,>X0D^.BW68W.=X.;d4LT/MM1LI5TP6ZJ4VN%UPYR*YV厮诘 诘 诖 诖 诖 诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 M}zXqR倄JnvNiy?i僆i?f?n>bx:l{ev=ck6Xq,cz-eq3\l?ja;cm2Sd'Us6ak.fa3fe5W])W`!I^$OZ#Of%D`&Gc%Je,>X0D^.BW68W.=X.;dem=塄 +塄 +塄堙堙堙堙堞堞堞堞m卋>bx:l{ev=ck6Xq,cz-eq3\l?ja;cm2Sd'Us6ak.fa3fe5W])W`!I^$OZ#Of%D`&Gc%Je,>X0D^.BW68W.=X.;d4LT/MM1LI5TP6ZJ4VN%UPYR*YV+TM1]R2_V1^S+PI輿輿輾輾輾輾輽輽$hzaq'dxjc]]#Vi([nWfSoWk%^s^rdn]oRcVcesZkLnZ]\j堙迶迶迵迵迵迵迴迴迴迴$WRQV%WE%VEMRTWORNH%VN!TE MC"CHMVNK RJEOJ[RUJ]HQM\邖邔邔邔邔邒邒邒邒邒邐邐-]v jv#fh#bx]k ghcn ag_e\qXnXu[oNmRj\qPdXk#Qk Ui鄥鄥鄥鄥鄤鄤鄤鄤轀 `K!Z_#ZQKWDU#PRHQQVMO^IPK#AHHE>MAREQ#ZI!LUNO輽鄜醻醻醻醻醹醹醹醹醸醸醸 `K!Z_#ZQKWDU#PRHQQVMO^IPK#AHHE>MAREQ#ZI!LUNOYN醱醱醱醰醰醰醰醰孜孜孜孜赝^t"_seebj%jZ\c"Tc]b(Q[ Qb#QoUd!Zf#WvQc P_Zi]uQg靥厝厝厝厝厝厍厍 厍 厮PIXS%WV/[M)\P-YM'Q?)LD!SOJK#HH'JC&MH(^= OITPDRPV$IV俾 俾 俾 倭 倭 倭 +倭 +倮 +倮 +倮 +仄 Jux8i侫n:dp2k;\婣g?by1ov0dx/]'Y']~3au+\~6fy%^el#Wq!ZtPg!Zo$Rl)Zn.Yu5Mk(?],@c3J],Lg-@m!Aj1Ig/Fb(Pk/Pc9Md)T`9X]:ZS1`O.bN6c[!eTTWNP#NYG_'ER俣 诖 诖 诖 诔 诔 鄢 鄢 鄄 鄄 鄄 鄄 s哤I}u:rx7wEu嘐y>p2k;\婣g?by1ov0dx/]'Y']~3au+\~6fy%^el#Wq!ZtPg!Zo$Rl)Zn.Yu5Mk(?],@c3J],Lg-@m!Aj1Ig/Fb(Pk/Pc9Md)T`9X]努塄堙堙堙堙堞堞堞堞;\婣g?by1ov0dx/]'Y']~3au+\~6fy%^el#Wq!ZtPg!Zo$Rl)Zn.Yu5Mk(?],@c3J],Lg-@m!Aj1Ig/Fb(Pk/Pc9Md)T`9X]:ZS1`O.bN6c[!eTTWNP#NYG_'ER'BbU\$ILXN輾輾輾輾輽輽輽UqDm!NiTiQhTe%Q\%ZiSoNf#Op%Ml'Pg!QlKo LrQqPg#QaXn Ka輾迶迵迵迵迵迴迴迴迴迲!FX&OL-QJ%GKHH"FBFOBM AP'IP"BN?XE]!@b%I_0;W#:[BM0QH)EN!AdOb]h?邔邔邒邒邒邒邐邐邐邐Yp_cSqabRc&Yb+Xk&Kf!Qn+NoQm,OiQh'HoTmLwLjKoPeSf鄥鄥鄤鄤鄤鄤鄤鄡轀!U['SY'RN)XQWG\MPA'E<#GB!GF&LGNU GS'DR)PO%PS CW%=U%:V輼醻醻醻醹醹醹醹醹醸醸醸醸!U['SY'RN)XQWG\MPA'E<#GB!GF&LGNU GS'DR)PO%PS CW%=U%:V%7R醱醱醰醰醰醰醰醰孜孜孜赝赝#HY{Cy TwOiIfQlIvPqHrQpHr#Nr O_ Bi'CyQ{ Ql&Fw靥厝厝厝厍厍厍 厍 厍 厮"XYVU!SK%CU'H]0CU0FO#GJ(FU(GO&>S8_FT!>LBN!:WBN)>Y0?_俾 倭 倭 倭 倭 +倭 +倮 +倮 +倮 +厍C厐Ay>o2b:s;f7c3h+f,Yz%\/\&Sq%Qs)Tu,en/mu'euXm"Pt%^d,Li0Rp(Wr2Vh$Bm'@`"DV.;\5F]*Je5Me0Ed2Qf7V_3RX(Yb.aZ*YU(V[+V[,NJ*ZNNV RQJTo2b:s;f7c3h+f,Yz%\/\&Sq%Qs)Tu,en诖 郗 +诏 镰%^d,Li0Rp(Wr2Vh$Bm'@`"DV.;\5F]*Je5Me0Ed2Qf7V_3RX(Yb.aZ*YU堙堙堙堙堙堞堞堞郦 +:s;f7c3h+f,Yz%\/\&Sq%Qs)Tu,en/mu'euXm"Pt%^d,Li0Rp(Wr2Vh$Bm'@`"DV.;\5F]*Je5Me0Ed2Qf7V_3RX(Yb.aZ*YU(V[+V[,NJ*ZNNV RQJTS8_FT!>LBN!:WBN)>Y0?_%@\1BW'GV)DP3QX!E[SZ'EW迵邔邒邒邒邒邐邐邐邐Dm!NiTiQhTe%Q\%ZiSoNf#Op%Ml'Pg!QlKo LrQqPg#QaXn Ka鄥鄥鄤鄤鄤鄤鄡鄡轀Q^OW!FX&OL-QJ%GKHH"FBFOBM AP'IP"BN?XE]!@b%I_0;W#:[輼醻醻醻醹醹醹醹醸醸醸醸醸Q^OW!FX&OL-QJ%GKHH"FBFOBM AP'IP"BN?XE]!@b%I_0;W#:[BM醱醰醰醰醰醰醰醰孜孜赝赝赝)Jx(Iu(JxCo!Op RjAn#LuImHsH}BFk$Aj&Ky$?{">{%7|*7p靥厝厝厝厍厍 厍 厍 仄 厮EjNSGTL\Hd%{%7|*7p CuCoJl堙迵迵迵迵迴迴迴迴迲迲Hd%^#8XJd-Nh(GdKaESUi@邒邒邒邒邒邐邐邐邐Cy TwOiIfQlIvPqHrQpHr#Nr O_ Bi'CyQ{ Ql&Fw%Mc%PoIq鄥鄤鄤鄤鄤鄤鄡鄡轀!SK%CU'H]0CU0FO#GJ(FU(GO&>S8_FT!>LBN!:WBN)>Y0?_%@\1BW迾醻醻醻醹醹醹醹醸醸醸醸醷!SK%CU'H]0CU0FO#GJ(FU(GO&>S8_FT!>LBN!:WBN)>Y0?_%@\1BW'GV醱醰醰醰醰醰醰醰孜孜赝赝赝*Ov(Tv-CrBgRgDc'?n$NvLm"As>r;|Cu;rG(D}#C{>r!@q靥厝厝厝厍厍 厍 厍 仄 厮KhEZGZHlI]"AgAg!Ca8`=S.T *]!.X%9i*:X3D^%Hg"Be!8a倭 倭 倭 倭 +倭 +倮 +倮 +倮 +倮 ++q/x5t)v~-u2g5g.e/p)l*a{*dy%_sekeh ljik!cn$btbs厮倭 +诤 诤 诤 诤 诠 诠 俾 $I\(KQ.Q^)V\)NW,TS)Of*Ug%b_ d`XUSW.Q]3Ib"S\SPUGRIORES厮诖 诖 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 /t+r4rx+q/x5t)v~-u2g5g.e/p)l*a{*dy%_sekeh帘郗 +郗 +郜 +郜 +郜 +诏 +[xLmNk(Hh,Mh)We+Mg$I\(KQ.Q^)V\)NW,TS)Of*Ug%b_ d`XU堙堙堙堙堞堞堞堞`奯2g5g.e/p)l*a{*dy%_sekeh ljik!cn$btbs-dv#ar+[xLmNk轄轄轄轄轄轃轃轃郛 ,TS)Of*Ug%b_ d`XUSW.Q]3Ib"S\SPUGRIORESNJ GWYNVS!QN輾輾輽輽輽迿塥 +-CrBgRgDc'?n$NvLm"As>r;|Cu;rG(D}#C{>r!@q=n/@tApQdP迵迵迵迵迴迴迴迴迲迲I]"AgAg!Ca8`=S.T *]!.X%9i*:X3D^%Hg"Be!8a)DZ*@[/Kc$?d*Rh,L`SVF_RY邒邒邒邒邐邐邐邐邏(JxCo!Op RjAn#LuImHsH}BFk$Aj&Ky$?{">{%7|*7p CuCoJl鄥鄤鄤鄤鄤鄡鄡鄡轀GTL\Hd%^迾醻醻醹醹醹醹醸醸醸醸醸醷GTL\Hd%^#8X醰醰醰醰醰醰醰醰孜赝赝赝赝*Gs*ImGtIjDmHl9v)B <{&6s$.v;vAo/w"8n6x7o8o;s靥厝厝厍厍 厍 厍 仄 仄 厮MiKdA^J`FjIe2W8W:[3Y4T2a2X)2S85W/@T+EW-DZ#3a倭 倭 倭 +倭 +倮 +倮 +倮 +倮 +倮 +)ms pv2{z"m&k(w/j2o0ev1cs!ex#j~_zhr b|%bxac_e]n厮俳 +诤 诤 诤 诤 诠 诠 诠 诠 倮 +#LT&UN*YN!UT"UY&Z[$S`![Z[S&_O#SU+L_,Md*DZ$WM#LJHFZJVLMH诖 诔 诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 .v$y}"tt)ms pv2{z"m&k(w/j2o0ev1cs!ex#j~_zhr b|诟 郗 +郜 +郜 +郜 +郜 +郜 +Ru&LvLuHt Yb&Nl"Eb'V`#LT&UN*YN!UT"UY&Z[$S`![Z[S&_O堙堙堙堞堞堞堞堀&k(w/j2o0ev1cs!ex#j~_zhr b|%bxac_e]nbj\kbzRu&Lv荨轄轄轄轄轃轃轃轃轃郛 &Z[$S`![Z[S&_O#SU+L_,Md*DZ$WM#LJHFZJVLMHLPNHCM"LS輾輽輽輽輽迾埽GtIjDmHl9v)B <{&6s$.v;vAo/w"8n6x7o8o;s(6w)^"LTH]CcEZ#A\%R]OX堋邒邒邒邐邐邐邐邏-CrBgRgDc'?n$NvLm"As>r;|Cu;rG(D}#C{>r!@q=n/@tAp鄥鄤鄤鄤鄤鄡鄡鄡轀GZHlI]"AgAg!Ca8`=S.T *]!.X%9i*:X3D^%Hg"Be!8a)DZ*@[迾醻醻醹醹醹醹醸醸醸醸醷醷GZHlI]"AgAg!Ca8`=S.T *]!.X%9i*:X3D^%Hg"Be!8a)DZ*@[/Kc醰醰醰醰醰醰醰醰孜赝赝赝赝)Bs%Ij&HiEo"BoEk%6u%>q&:m5i2jMAREQ軣輽輽輽迿迾迾&HiEo"BoEk%6u%>q&:m5i2j^迾醻醹醹醹醹醹醸醸醸醸醷醷A^J`FjIe2W8W:[3Y4T2a2X)2S85W/@T+EW-DZ#3a D^(>^"LT醰醰醰醰醰醰醰醰赝赝赝赝赝)Bn$Df&Jr:r9p!?i ?n H`$Fi8oB\=iDb#Fg ?f 8e&0r7l!6r靥厝厍厍 厍 厍 厍 仄 仄 厮8g6c;e(Cm@nBl;lDq'1f'.W:R1R6\!3L%<[);Z86H*?W3=_倭 倭 倭 +倮 +倮 +倮 +倮 +倮 +啬 pv)+w{!h_#b,hn$hzaq'dxjc]]#Vi([nWfSoWk嘏诨 +诤 诤 诤 诤 诠 诠 诠 诠 诠 诟 俸 +$Vg`QQTQO#SL$OPQL]R U\$WRQV%WE%VEMRTWORNH%VN!TE偌 +诔 鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 ||)yu+q~ pv)+w{!h_#b,hn$hzaq'dxjc]]#Vi([n郗 +郜 +郜 +郜 +郜 +郜 +郢 +RcVcesZkLnZ]\jXeRf$Vg`QQTQO#SL$OPQL]R U\诖 堙堞堞堞堞堞堀_#b,hn$hzaq'dxjc]]#Vi([nWfSoWk%^s^rdn]oRc荨轄轄轄轄轃轃轃轃轃轂轂郛 $OPQL]R U\$WRQV%WE%VEMRTWORNH%VN!TE MC"CHMVNK郦 +輽輽輽迿迾迾&Jr:r9p!?i ?n H`$Fi8oB\=iDb#Fg ?f 8e&0r7l!6r&5u-s$-p*4k臐迵迴迴迴迴迴迲迲迲@nBl;lDq'1f'.W:R1R6\!3L%<[);Z86H*?W3=_!Gf K\F\(H^*CT4BW3Ge*LV&PT.SR邒邒邐邐邐邐邏邏&HiEo"BoEk%6u%>q&:m5i2jk!As2w:h2f=e3iBY7`7a=W4^9`3_ 5e/3c'0p靥厝厍厍 厍 厍 仄 仄 仄 厮"9k7f7e7b4i;o#6o%4u,>b)=d+9f25["4Y*,_&&P04Q06K62U6HV倭 倭 +倭 +倮 +倮 +倮 +倮 +倏 +啬 'e`_.`3hz#bs^t"_seebj%jZ\c"Tc]b(Q[ Qb#Qo倏 诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 厣S^(UR!YVIMPIXS%WV/[M)\P-YM'Q?)LD!SOJK#HH'JC&MH(^=偌 +诔 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 5o}-ow s|'e`_.`3hz#bs^t"_seebj%jZ\c"Tc]b郗 +郜 +郜 +郜 +郜 +郢 +郢 + P_Zi]uQg[^^gOc&XW_VY`S^(UR!YVIMPIXS%WV/[M诖 堙堞堞堞堞堀堀.`3hz#bs^t"_seebj%jZ\c"Tc]b(Q[ Qb#QoUd!Zf#WvQc P_荨轄轄轄轄轃轃轃轃轂轂轂轂PIXS%WV/[M)\P-YM'Q?)LD!SOJK#HH'JC&MH(^= OITPDRPV郦 +輽輽迿迾迾迾MbM!As2w:h2f=e3iBY7`7a=W4^9`3_ 5e/3c'0p#m4_!0o",i0v迵迴迴迴迴迲迲迲迲4i;o#6o%4u,>b)=d+9f25["4Y*,_&&P04Q06K62U6HV-@M)P]1QV"K`&IV5D`*Be)IZ.IR/=V邒邐邐邐邐邐邏邏&Jr:r9p!?i ?n H`$Fi8oB\=iDb#Fg ?f 8e&0r7l!6r&5u-s$-p鄤鄤鄤鄤鄡鄡鄡鄡輿;e(Cm@nBl;lDq'1f'.W:R1R6\!3L%<[);Z86H*?W3=_!Gf K\迾醹醹醹醹醹醸醸醸醸醷醷醷;e(Cm@nBl;lDq'1f'.W:R1R6\!3L%<[);Z86H*?W3=_!Gf K\F\醰醰醰醰醰醰醰醰赝赝赝赝靥=h 9m7l:[&Ad8Z7^4X7i2f'j.e4]1[6T0_'1`.h'_靥厍厍厍 厍 厍 仄 仄 仄 厮$=j!9l2g7k6r-w$+t(3v&9u,0u,.i!;d(3`18c%9_,4T15Z6=S%@Q倭 倭 +倮 +倮 +倮 +倮 +倮 +倏 +啬 e(Y"X%^{,e~#U}_{_uSnYp_cSqabRc&Yb+Xk&Kf!Qn诨 +诤 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 啬 *ZO%^[[UNIQM]T!U['SY'RN)XQWG\MPA'E<#GB!GF&LGNU偌 +鄢 鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 /ds-s}$re(Y"X%^{,e~#U}_{_uSnYp_cSqabRc&Yb郗 +郜 +郜 +郜 +郜 +郢 +郢 +'HoTmLwLjKoPeSf\_QaR[*ZO%^[[UNIQM]T!U['SY诖 堞堞堞堞堞堀堀,e~#U}_{_uSnYp_cSqabRc&Yb+Xk&Kf!Qn+NoQm,OiQh'Ho轄轄轄轄轄轃轃轃轃轂轂轂轂QM]T!U['SY'RN)XQWG\MPA'E<#GB!GF&LGNU GS'DR)PO%PS郦 +輽輽迿迾迾迾塥 +:[&Ad8Z7^4X7i2f'j.e4]1[6T0_'1`.h'_(*Zk!'g1i#6n聹迴迴迴迴迲迲迲迲6r-w$+t(3v&9u,0u,.i!;d(3`18c%9_,4T15Z6=S%@Q.>Y+QV,M_3@W3IW&=`*GQ+FY4AL6>Q輽邐邐邐邐邏邏邏>k!As2w:h2f=e3iBY7`7a=W4^9`3_ 5e/3c'0p#m4_!0o鄤鄤鄤鄡鄡鄡鄡鄠輿7e7b4i;o#6o%4u,>b)=d+9f25["4Y*,_&&P04Q06K62U6HV-@M)P]迾醹醹醹醹醸醸醸醸醸醷醷醷7e7b4i;o#6o%4u,>b)=d+9f25["4Y*,_&&P04Q06K62U6HV-@M)P]1QV醰醰醰醰醰醰醰醰赝赝赝靥靥8e;k?d"2W1b!6_3i4b/h6d#d.d>b6k,e ,j4^0jl靥厍厍 厍 厍 仄 仄 仄 仄 厮*1g)-m&3p%m"Iw(>e,4f/Bh-=f:P$:R F\倭 +倭 +倮 +倮 +倮 +倮 +倏 +倏 +啬 "`l-`wZ{*_{#\}!WxM}]rUqDm!NiTiQhTe%Q\%ZiSoNf诨 诤 诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 倏 +NOJ`RVMW J]UVQ^OW!FX&OL-QJ%GKHH"FBFOBM AP'IP偌 +鄢 鄢 鄄 鄄 鄄 鄄 鄄 郾 郾 郾 )jd&ZuWq"`l-`wZ{*_{#\}!WxM}]rUqDm!NiTiQhTe%Q\郜 +郜 +郜 +郜 +郢 +郢 +郢 +Ko LrQqPg#QaXn KaH^D`UbNOJ`RVMW J]UVQ^OW诖 堞堞堞堞堀堀堀#\}!WxM}]rUqDm!NiTiQhTe%Q\%ZiSoNf#Op%Ml'Pg!QlKo轄轄轄轄轃轃轃轃轂轂轂轂轂 J]UVQ^OW!FX&OL-QJ%GKHH"FBFOBM AP'IP"BN?XE]!@b郦 +輽迿迾迾迾迾迾"2W1b!6_3i4b/h6d#d.d>b6k,e ,j4^0jl'_l,a%._&1u,.m輼迴迴迲迲迲迲迲?g$/r#1a/j)0s.5w >m"Iw(>e,4f/Bh-=f:P$:R F\>SIY%;^+6V*:c+Ee%JW1FS2?R0AT堋邐邐邐邐邏邏邏7l:[&Ad8Z7^4X7i2f'j.e4]1[6T0_'1`.h'_(*Zk!'g鄤鄤鄤鄡鄡鄡鄡鄠輿2g7k6r-w$+t(3v&9u,0u,.i!;d(3`18c%9_,4T15Z6=S%@Q.>Y+QV迾醹醹醹醹醸醸醸醸醷醷醷醷2g7k6r-w$+t(3v&9u,0u,.i!;d(3`18c%9_,4T15Z6=S%@Q.>Y+QV,M_醰醰醰醰醰醰醰醰赝赝赝靥靥 +/_=g =i%2\-?c",b/d*^'i/k-.m5h6r'i%k+j"] $f&d厮厍厍 厍 厍 仄 仄 仄 仄 厮!*m"/q3l9f@d9i7g"4]%+y#=i"Dm$7c)>g,>c+S8_FT!>L诩 +鄢 鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 [iWr$Yn-\k)\o<[u.`x1[.U/\#HY{Cy TwOiIfQlIv郜 +郜 +郜 +郜 +郢 +郢 +郢 +'CyQ{ Ql&Fw%Mc%PoIqQnNbQaRdOaUf&L`"XYVU!SK%CU诖 堞堞堞堞堀堀堀1[.U/\#HY{Cy TwOiIfQlIvPqHrQpHr#Nr O_ Bi'Cy堀轄轄轄轃轃轃轃轂轂轂轂郗 "XYVU!SK%CU'H]0CU0FO#GJ(FU(GO&>S8_FT!>LBN!:WBN)>Y郦 +輽迿迾迾迾迾迼%2\-?c",b/d*^'i/k-.m5h6r'i%k+j"] $f&d %`1\-g$+g)&il*p迴迴迲迲迲迲迱聺9i7g"4]%+y#=i"Dm$7c)>g,>c+['?e*;Z%;`)@k&@h3:`/ERb6k,e ,j4^0jl'_l,a迶鄤鄡鄡鄡鄡鄡鄠^SO&3p%m"Iw(>e,4f/Bh-=f:P$:R F\>SIY迾醹醹醹醸醸醸醸醸醷醷醷醷&3p%m"Iw(>e,4f/Bh-=f:P$:R F\>SIY%;^醰醰醰醰醰醰醰醰赝赝靥靥靥U倭 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +)Xo0^s,Yv*Wv/]x:Q|2V)Jx(Iu(JxCo!Op RjAn#LuImHsH}俾 诤 诤 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 倬 +!DZ%QbHgNdEjNSGTL\Hd%{%7|*7p CuCoJlGnFeHe!DZ%QbHgNdEjNSGTL\诔 堞堞堞堀堀堀堀/]x:Q|2V)Jx(Iu(JxCo!Op RjAn#LuImHsH}BFk$Aj&Ky$?{陇轄轄轃轃轃轃轃轂轂轂轂NdEjNSGTL\Hd%U%,^&:V1:f+3Y$:_#9h9A]';\,>O*DT軤邐邐邐邏邏邏邏 =i%2\-?c",b/d*^'i/k-.m5h6r'i%k+j"] $f&d %`1\-g[QK鄤鄡鄡鄡鄡鄠鄠"/q3l9f@d9i7g"4]%+y#=i"Dm$7c)>g,>c+[迾醹醹醹醸醸醸醸醷醷醷醷醶3l9f@d9i7g"4]%+y#=i"Dm$7c)>g,>c+['?e醰醰醰醰醰醰醰醰赝赝靥靥靥5k+b#l+juuu!y(u-g +q)u'k 'gk&!k(j (b#k厮厍 厍 厍 仄 仄 仄 仄 嘏 厮2f4e 'n"*m-r)+o++Z'n(/h1k r厣诤 诤 诤 诠 诠 诠 诠 诟 诟 诟 诟 诜 倬 + CoCi"DfP`KhEZGZHlI]"AgAg!Ca8`=S.T *]!.X%9i诩 +鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郾 [d$Qs&Wz)Tn2Tx5Jm1Mw5`x:Nw0Nt*Ov(Tv-CrBgRgDc'?n$Nv郜 +郜 +郜 +郢 +郢 +郢 +郢 +(D}#C{>r!@q=n/@tApBo#Be Jn CoCi"DfP`KhEZGZHl诔 堞堞堞堀堀堀堀5`x:Nw0Nt*Ov(Tv-CrBgRgDc'?n$NvLm"As>r;|Cu;rG(D}#C{堀轄轃轃轃轃轂轂轂轂陇P`KhEZGZHlI]"AgAg!Ca8`=S.T *]!.X%9i*:X3D^%Hg"Be輽迿迾迾迾迾迼迼迼uuu!y(u-g +q)u'k 'gk&!k(j (b#k`YW$b ,b%m e#h)^輻迲迲迱迱迱邜邜邚邚邚邚邘4^HiHd7c"Hk9^$=['5\)5g3>e)7]13V6C[9EY(A\5AS*>U軤邐邐邏邏邏邏邏-_"4n"$j#'o"l&s$%j*2c$0m5_/p(p/g" d$h2o)_e +"c^-c邒鄡鄡鄡鄡鄠脪*f0i1e7i.n1_)d+c1p!6rCg"3a;j8jBk =f!Aa&>U%,^&:V迾醹醹醸醸醸醸醸醷醷醷醷醶0i1e7i.n1_)d+c1p!6rCg"3a;j8jBk =f!Aa&>U%,^&:V1:f醰醰醰醰醰醰醰醰赝赝靥靥靥$i"+k%rp (#xsl mg.s,{#v(i fc%f^"c厮厍 厍 仄 仄 仄 仄 仄 嘏 厮'`%a$h +e(e-'^!e%/_ 2m!0l;g +7m;o*r6j8b!@e%@l':p倮 +倮 +倮 +倮 +倮 +倏 +倏 +倏 +倏 +厝'Os!Pt"Kv+Sx*Ku+Ly*Gs*ImGtIjDmHl9v)B <{&6s$.v;v俾 诤 诠 诠 诠 诠 诠 诟 诟 诟 诟 诜 倬 +8xHv>iMgMiKdA^J`FjIe2W8W:[3Y4T2a2X)2S诩 +鄢 鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 !_d^vfx"Wz'Os!Pt"Kv+Sx*Ku+Ly*Gs*ImGtIjDmHl9v)B佦 +郜 +郜 +郢 +郢 +郢 +郢 +6x7o8o;s(6w)iMgMiKdA^J`诔 堞堞堞堀堀堀堀诓 *Ku+Ly*Gs*ImGtIjDmHl9v)B <{&6s$.v;vAo/w"8n6x7o8o埭轃轃轃轃轂轂轂昆>iMgMiKdA^J`FjIe2W8W:[3Y4T2a2X)2S85W/@T+EW-DZ輽迾迾迾迾迾迼迼迼HR^#xsl mg.s,{#v(i fc%f^"c"g -j +(_ 0l 4`$^#o$h(n.h翚迲迱迱邜邜邚邚邚邚邚邘;o*r6j8b!@e%@l':p&2g#4h'7d,0[)e醰醰醰醰醰醰醰醰赝靥靥靥靥)n&)wq"tux"q'~&}#t-s!z +/t%m"n+ln!jh厮厍 厍 仄 仄 仄 仄 嘏 嘏 厮"a"g$n!$j''m%+^l)%l(4k!2y!3n2x,v-z2tCpq&:m5i2jq郜 +郜 +郢 +郢 +郢 +郢 +郢 +-j%4r6p&0}!5v%7$6r(;t%=zq&:m5i2jo%Ae2l9^W!8Q$5Y":Z!3Y邐邐邏邏邏邏邎邎迯"tux"q'~&}#t-s!z +/t%m"n+ln!jh +lr g"e&q +!p'dk!b#r"a"g$n!$j''m%+^l)%l(4k!2y!3n2x,v-z2tCpo%Ae醹醹醸醸醸醸醷醷醷醷醷醶醶$n!$j''m%+^l)%l(4k!2y!3n2x,v-z2tCpo%Ae2l醰醰醰醰醰醰醰醰靥靥靥靥靥(v4j-o /v }*x 's%x +$ +/5s 1#%(v#q{厮厍 仄 仄 仄 仄 嘏 嘏 嘏 厮#{m }&x$s %t%o&u -} ,} %~.y'{)y:Dn 8t8tEx倮 +倮 +倮 +倏 +倏 +倏 +倏 +倏 +倬 +倬 +厥Gm#:h!>n@pDl?p@m>k!As2w:h2f=e3iBY7`7a=W4^9`3_ 5e/3c'0p#m4_!0o倬 +诜 倬 +,u.z3tb)=d+9f25["4Y*,_诨 +鄄 鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 >{;BuFjCnGm#:h!>n@pDl?p@m>k!As2w:h2f=e郜 +郢 +郢 +郢 +郢 +郢 +郦 +3_ 5e/3c'0p#m4_!0o",i0v4y,u.z3tk!As2w:h2f=e3iBY7`7a=W4^9`3_ 5e/3c'0p#m4_!0o",i0v4y,u.z3tb)=d+9f25["4Y*,_&&P04Q06K迿迾迾迾迾迼迼迼迼迼迻堍 's%x +$ +/5s 1#%(v#q{urv} "}p&il$kt#{m }&x$s %t%o&u -} ,} %~.y'{)y:Dn 8t8tEx >uAvc=j!B\;i=h 9m7l:[&Ad8Z7^4X7i2f'j.e4]1[6T0_'1`.h'_(*Zk!'g倬 +诜 倬 ++,v *q,f9j$=j!9l2g7k6r-w$+t(3v&9u,0u,.i!;d(3`18c诨 +鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 9p>{&ByOjKfM_>c=j!B\;i=h 9m7l:[&Ad8Z7^4X郜 +郢 +郢 +郢 +郢 +郦 +塥 +0_'1`.h'_(*Zk!'g1i#6n,p+,v *q,f9j$=j!9l2g7k诔 堞堀堀堀堀埭埭埭郗 ;i=h 9m7l:[&Ad8Z7^4X7i2f'j.e4]1[6T0_'1`.h'_(*Zk!'g1i#6n,p+,v *q,f9j$=j!9l2g7k6r-w$+t(3v&9u,0u,.i!;d(3`18c%9_,4Tc[B迿迾迾迾迾迼迼迼迼迻迻迻 ++m3p6q*|2|0~ +$ &'| (j !y } !z ! +ww #x$s*h!p$~/w#z#{{"x'n-m,y#)} +'6&+2qCm Ds@|!=pA~Ev3o9{(5j#5o%Af*u迾醹醸醸醸醸醸醷醷醷醷醶醶醶 }&x$s %t%o&u -} ,} %~.y'{)y:Dn 8t8tEx >uAvb6k,e ,j4^0jl'_l,a倬 +诜 倬 +!,n!,d4b6l*1g)-m&3p%m"Iw(>e,4f诨 +鄄 鄄 鄄 郾 郾 郾 郾 郯 郯 郯 Gx"FuPtOq@jScCc-@h?Y6Z8e;k?d"2W1b!6_3i4b郢 +郢 +郢 +郢 +郢 +郦 +塥 + ,j4^0jl'_l,a%._&1u,.m!,n!,d4b6l*1g)-m&3p%b6k,e ,j4^0jl'_l,a%._&1u,.m!,n!,d4b6l*1g)-m&3p%m"Iw(>e,4f/Bh-=f轂迾迾迾迾迾迼迼迼迼迻迻迻轀5w*,( ++~v%v~| +"%st q +v.z*p,v)v(r%n#&zto +$t$s0{,)!/}&.~,sCn$5|5r;ug,>c诨 +鄄 鄄 郾 郾 郾 郾 郾 郯 郯 郯 %Nt)Df>p*Ad.Lk+M^)N\B_)ImFf +/_=g =i%2\-?c",b/d*^郢 +郢 +郢 +郢 +郦 +塥 +塥 ++j"] $f&d %`1\-g$+g)&il*p'm/h$(f!*m"/q3l9f诔 堀堀堀堀埭埭埭埭埽郜 +/_=g =i%2\-?c",b/d*^'i/k-.m5h6r'i%k+j"] $f&d %`1\-g$+g)&il*p'm/h$(f!*m"/q3l9f@d9i7g"4]%+y#=i"Dm$7c)>g,>c+u;l7h /l01h!;d'4`邐邏邏邏邏邏邎邎邎邎邍1g+l!5z5w*,( ++~v%v~| +"%st q +v.z*p,v)v(r%n#&zto +$t$s0{,)!/}&.~,sCn$5|5r;uQ\U醹醸醸醸醸醸醷醷醷醷醶醶醶醶%n#&zto +$t$s0{,)!/}&.~,sCn$5|5r;uu醰醰醰醰醰醰醰醰靥靥厮厮厮,j5x&j'w&k5r,s ++j-q4o.e'q({嬝仄 仄 仄 嘏 嘏 嘏 嘏 倥 厥,{')#0y +,-y#)}"v +!y+t-|")x"/s&q.-j#3v8o倮 +倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +啬 ;s"4d8f5k+b#l+juuu!y(u-g +q)u'k 'gk&!k(j (b#k`YW倬 +诜 倬 + e#h)^ 1^2f4e 'n"*m-r)+o++Z'n(/h1k d(;b"?f#D_$1f%7q#6n)n&)wq"tux"q'~郢 +郢 +郢 +塥 +塥 +塥 +塥 ++ln!jh +lr g"e&q +!p'dk!b#r"a"g$n!$j诓 堀堀埭埭埭埭埭埽埽埽埽堍q"tux"q'~&}#t-s!z +/t%m"n+ln!jh +lr g"e&q +!p'dk!b#r"a"g$n!$j''m%+^l)%l(4k!2y!3n2x,v転迿迾迾迾迾迼迼迼迼迼迻迻迻迻迺迺迺迺迶RTZ2s&+uz~! (   %! *3'+$#"*!$s'*}!(s*x')u'3u|'|$| )l&*|*j'(n%g"%o#a$h邐邐邏邏邏邏邎邎邎邎邍邍鄧鄧鄧4p1o1h6j3n3u2+ "& +%&$  !$ +-+{-&"!,)#3p#r,~'#%&v/x+*oVOZ醹醹醸醸醸醸醷醷醷醷醶醶醶醶醶醳+{-&"!,)#3p#r,~'#%&v/x+*o*|#o )u!'f)(k醰醰醰醰醰醰醰醰靥厮厮厮厮4a/t3m$j(m#-n"~%w#{3|/#x1/#庁仄 仄 嘏 嘏 嘏 倥 倌 倌 厥)'-%$"'5/$"!'+{ 'n$(v'*m#*l$&v%&e!l&r倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +俳 +偌 +芈 %'wz*q(p$&}#q1 z ~+|""})|,v#v'{}v +zv n倬 +诙 倬 +i !d%i&tts.n"s!i! pi#q,s/t$v ~!/~3x诨 +郾 郾 郾 郾 郯 郯 郯 郯 郯 郫 'Re?e$Ag(?gFZ2d!1c/j9i%'wz*q(p$&}#q1 z郢 +郢 +郦 +塥 +塥 +塥 +堠 +'{}v +zv nw$igi !d%i&tts.n"s诓 堀堀埭埭埭埭埽埽埽埽埽堍郐 +$&}#q1 z ~+|""})|,v#v'{}v +zv nw$igi !d%i&tts.n"s!i! pi#q,s/t$v ~郦 +輽迿迾迾迾迾迼迼迼迼迻迻迻迻迻迺迺迺迺迶迶#x1/# , +,' ** *,- +.)'-%$"'5/$"!'+{ 'n$(v'*m#*l$&v%&e!l&r%r.!l&#v"-s".o+g迲邐邏邏邏邏邎邎邎邎邎邍邍鄧鄧鄦邖3i-s0s,}2s&+uz~! (   %! *3'+$#"*!$s'*}!(s*x')u'3u|'|醹醹醸醸醸醸醷醷醷醷醷醶醶醶醶醳醳+$#"*!$s'*}!(s*x')u'3u|'|$| )l&*|*j'(n醰醰醰醰醰醰醰醰靥厮厮厮厮.q0s&v#l*j!-x! ~")|+( ++!"椮仄 嘏 嘏 嘏 嘏 倥 倌 倌 厥1 +'"*.(/#:%%}&,x)"v$$n50v)4u8/s4(j #b*j-s)"m倏 +倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +俾 (v4j-o /v }*x 's%x +$ +/5s 1#%(v#q{urv倬 +诙 倬 +&il$kt#{m }&x$s %t%o&u -} ,} %~.y'{)y诨 +郾 郾 郾 郾 郯 郯 郯 郯 郫 郫 ?p%9h2aj3tGi7j5e.j6m0q+|$~+o"u&m,r(w*p ++m3p郢 +郦 +塥 +塥 +塥 +塥 +堠 + (j !y } !z ! +ww #x$s*h!p$~/w#z#{{诓 堀埭埭埭埭埽埽埽埽埽堍堍堍堍郯 *p ++m3p6q*|2|0~ +$ &'| (j !y } !z ! +ww #x$s*h!p$~/w#z#{{"x'n-m,y#)}郦 +輽輽迿迾迾迾迾迼迼迼迼迻迻迻迻迻迺迺迺迺迶迶迶迶迵#"&0~.}' +% +) + *,#* 7z4}*6x(5#*~(*k-&o6(w4#~0,p;*l2"l) h43z5#w%&m2y0u "xt軤邐邐邏邏邏邏邏邎邎邎邎邍邍鄧鄧鄦鄦鄦鄦轂+( ++!"(#-&, +-}#.211 +'"*.(/#:%%}&,x)"v$$n50v)4u8/s4(j迾醹醹醸醸醸醸醸醷醷醷醷醶醶醶醶醳醳醳"*.(/#:%%}&,x)"v$$n50v)4u8/s4(j #b*j-s)"m3u)%j'"l醰醰醰醰醰醰醰醰厮厮厮厮厥&nm!mt &w).q)*!{ %'&"%' 徹仄 嘏 嘏 嘏 倥 倌 倌 倌 厥, )%5&2x$1|#8{*((5~+({!2+~ r+#o-#o2"u&"{7u'r*q倏 +倏 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +倭 )n".l1g+l!5z5w*,( ++~v%v~| +"勝 +诙 倬 + +v.z*p,v)v(r%n#&zto +$t$s0{,)!/}&.~诤 +郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 7j:t>cAg3i0o ++g0s(v"t#%~-|)n".l1g+l!5z5w郢 +郦 +塥 +塥 +塥 +堠 +堠 +%v~| +"%st q +v.z*p,v)v(r%n#&z诓 堀埭埭埭埭埽埽埽埽堍堍堍堍堍荨郯 !5z5w*,( ++~v%v~| +"%st q +v.z*p,v)v(r%n#&zto +$t$s0{郦 +輽輽迿迾迾迾迾迾迼迼迼迼迻迻迻迻迺迺迺迺迺迶迶迶迶迵迵翚"%'  +*5 0 )$."&, )%5&2x$1|#8{*((5~+({!2+~ r+#o-#o2"u&"{7u'r*q,%%(x(#j軤邐邐邐邏邏邏邏邎邎邎邎邍邍鄧鄧鄧鄦鄦鄦鄦鄥轁}!#"&0~.}' +% +) + *,#* 7z4}*6x(5#*~(*k-&o6(w4#~0,p;*l迾醹醹醹醸醸醸醸醷醷醷醷醶醶醶醶醶醳醳醳#* 7z4}*6x(5#*~(*k-&o6(w4#~0,p;*l2"l) h43z5#w%&m2y0u "x醰醰醰醰醰醰醰醰厮厮厮厮厥"w!t mv'}%)$%!' #*,*'$$!⒇嘏 嘏 嘏 嘏 倌 倌 倌 倌 厥-/ 80?%5-%)z"(|##&.)! {(!y# s0w"!w$(p倏 +倏 +倬 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +倏 厮)s3z1 -w1|%v0{- +( ))(| +&x s }|倬 +诙 倬 + ~%0"" $.s#p 'w +| q'&y({.|.z0z)z*}诤 +郾 郾 郾 郯 郯 郯 郯 郫 郫 郫 $4r4q%@g =u=s:m3o 3q0m#&n#$q%{/|%&p)s3z1 -w郦 +塥 +塥 +塥 +塥 +堠 +堠 +(| +&x s }|$|| x ~%0"" $.s#p 'w诓 埭埭埭埭埽埽埽埽埽堍堍堍堍荨荨荨堀 -w1|%v0{- +( ))(| +&x s }|$|| x ~%0"" $.s#p 'w +| q'&y軣輽輽輽迿迾迾迾迾迼迼迼迼迻迻迻迻迻迺迺迺迺迶迶迶迶迵迵迵迵軣$$! "-* *4-/ 80?%5-%)z"(|##&.)! {(!y# s0w"!w$(p.4|6-~軤邐邐邐邏邏邏邏邏邎邎邎邎邍邍鄧鄧鄦鄦鄦鄦鄦鄥鄥轁%'&"%'  +*5 0 )$."&, )%5&2x$1|#8{*((5~+({!2+~ r+#o迾醹醹醹醸醸醸醸醸醷醷醷醷醶醶醶醶醳醳醳醳%5&2x$1|#8{*((5~+({!2+~ r+#o-#o2"u&"{7u'r*q,%%(x(#j醰醰醰醰醰醰醰醰厮厮厮厥厥} +xxtn%&'0"!+-%%%$$!(ω嘏 嘏 嘏 倥 倌 倌 倌 倌 厥*36%;)/"*(0)))!z } |傎 +倏 +倬 +倬 +倬 +倬 +俳 +俳 +俳 +俳 +偌 +偌 +偌 +诩 +诩 +诨 +诨 +诨 +诨 偌 +厍 2~2y *q +x't+q '|/x++$ +sxw倬 +诙 倬 +&y&#)y0r+|*{ 'tx#! +&#)} +',q/r$m诤 +郾 郾 郯 郯 郯 郯 郫 郫 郫 郫 @k^8`7e#?j" + * (C) 2000 Alex Holden + */ + +/* + Undefine this if solid window moves are incredibly slow on your hardware. + Unfortunately since outline moves are not supported yet, the only + alternative is "invisible" moving. +*/ +#define SHOW_WINDOW_MOTION + +/* + Define this if you want the mouse pointer to become bell shaped when over + the launcher window. +*/ +#undef USE_WEIRD_POINTER + +#include +#include +#include +#include +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" + +/* + * Definitions to make it easy to define cursors + */ +#define _ ((unsigned) 0) /* off bits */ +#define X ((unsigned) 1) /* on bits */ +#define MASK(a,b,c,d,e,f,g) \ + (((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) \ + + e) * 2) + f) * 2) + g) << 9) + +#define DEC_HEIGHT 7 +#define IDLE_DELAY 100000 + +static GR_WINDOW_ID w1; /* id for launcher window */ +static GR_GC_ID gc; /* graphics context for rectangle */ +static GR_GC_ID bgc; /* graphics context for rectangle */ +static GR_SCREEN_INFO si; /* information about screen */ +static int fwidth, fheight; +static int fbase; +static int num_apps = 0; + +void do_exposure(); +void do_buttondown(); +void do_buttonup(); +void do_update(); +void do_mouse(); + +struct app_info { + char app_id[10]; + char app_path[64]; +} Apps[] = { +#if ELKS + {"clock", "/root/nclock"}, + {"term", "/root/nterm"}, + {"demo", "/root/demo"}, + {"demo2", "/root/demo2"}, +#else + {"clock", "bin/nclock"}, + {"term", "bin/nterm"}, + {"demo", "bin/demo"}, + {"demo2", "bin/demo2"}, + {"ntest", "bin/ntest"}, +#endif + {"", ""} +}; + +typedef struct managed_window mwin; +struct managed_window { + GR_WINDOW_ID wid; /* Application's window */ + GR_WINDOW_ID fid; /* Title bar */ + GR_COORD x; /* Overall window X origin */ + GR_COORD y; /* Overall window Y origin */ + GR_SIZE width; /* Overall width of window */ + mwin * next; +}; + +mwin * mwins = NULL; +mwin * in_motion = NULL; +GR_COORD move_xoff; +GR_COORD move_yoff; + +/* + * Reap the dead children whenever we get a SIGCHLD. + */ +void reaper(int signum) { while(waitpid(WAIT_ANY, NULL, WNOHANG) > 0); } + +int +main(int argc,char **argv) +{ + GR_EVENT event; /* current event */ + struct app_info * act; + int width, height; + +#ifdef USE_WEIRD_POINTER + GR_BITMAP bitmap1fg[7]; /* bitmaps for first cursor */ + GR_BITMAP bitmap1bg[7]; +#endif + + for(act = Apps; act->app_id[0] != '\0'; act++, num_apps++); + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + GrGetScreenInfo(&si); + + signal(SIGCHLD, &reaper); + + gc = GrNewGC(); + bgc = GrNewGC(); + + GrSetGCForeground(bgc, GRAY); + GrSetGCFont(gc, GrCreateFont(GR_FONT_OEM_FIXED, 0, NULL)); + + GrGetGCTextSize(gc, "A", 1, GR_TFASCII, &fwidth, &fheight, &fbase); + width = fwidth * 8 + 4; + height = (fheight) * num_apps + 4; + + w1 = GrNewWindow(GR_ROOT_WINDOW_ID, 5, 5, width, + height, 1, WHITE, BLACK); + + GrSelectEvents(w1, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_BUTTON_DOWN + | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_CHLD_UPDATE); + + GrMapWindow(w1); + +#ifdef USE_WEIRD_POINTER + bitmap1bg[0] = MASK(_,_,X,X,X,_,_); + bitmap1bg[1] = MASK(_,X,X,X,X,X,_); + bitmap1bg[2] = MASK(_,X,X,X,X,X,_); + bitmap1bg[3] = MASK(_,X,X,X,X,X,_); + bitmap1bg[4] = MASK(_,X,X,X,X,X,_); + bitmap1bg[5] = MASK(_,X,X,X,X,X,_); + bitmap1bg[6] = MASK(X,X,X,X,X,X,X); + + bitmap1fg[0] = MASK(_,_,_,_,_,_,_); + bitmap1fg[1] = MASK(_,_,_,X,_,_,_); + bitmap1fg[2] = MASK(_,_,X,X,X,_,_); + bitmap1fg[3] = MASK(_,_,X,X,X,_,_); + bitmap1fg[4] = MASK(_,_,X,X,X,_,_); + bitmap1fg[5] = MASK(_,_,X,X,X,_,_); + bitmap1fg[6] = MASK(_,X,X,X,X,X,_); + + GrSetCursor(w1, 7, 7, 3, 3, WHITE, BLACK, bitmap1fg, bitmap1bg); +#endif + + GrFillRect(GR_ROOT_WINDOW_ID, bgc, 0, 0, si.cols, si.rows); + + GrSetGCForeground(gc, BLACK); + GrSetGCBackground(gc, WHITE); + + while (1) { + GrGetNextEvent(&event); + + switch (event.type) { + case GR_EVENT_TYPE_EXPOSURE: + do_exposure(&event.exposure); + break; + case GR_EVENT_TYPE_BUTTON_DOWN: + do_buttondown(&event.button); + break; + case GR_EVENT_TYPE_BUTTON_UP: + do_buttonup(&event.button); + break; + case GR_EVENT_TYPE_UPDATE: + do_update(&event.update); + break; + case GR_EVENT_TYPE_MOUSE_POSITION: + do_mouse(&event.mouse); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + } + } +} + +mwin * IsDecoration(GR_WINDOW_ID wid) +{ + mwin * mwp; + for(mwp = mwins; mwp; mwp = mwp->next) { + if (mwp->fid == wid) { + return mwp; + } + } + return NULL; +} + +mwin * FindWindow(GR_WINDOW_ID wid) +{ + mwin * mwp; + for(mwp = mwins; mwp; mwp = mwp->next) { + if (mwp->wid == wid) { + return mwp; + } + } + return NULL; +} + +mwin * NewWindow(GR_WINDOW_ID wid) +{ + mwin * mwp = malloc(sizeof(mwin)); + + if (mwp) { + mwp->wid = wid; + mwp->next = mwins; + mwins = mwp; + } + return mwp; +} + +void +do_update(ep) + GR_EVENT_UPDATE *ep; +{ + mwin * mwp; + mwin * tmwp; + GR_WINDOW_INFO winfo; + + if (IsDecoration(ep->wid)) return; + + if ((mwp = FindWindow(ep->wid)) == NULL) { + /* We have a new window */ + if (ep->utype != GR_UPDATE_MAP) return; + if ((mwp = NewWindow(ep->wid)) == NULL) { + printf("malloc failed\n"); + return; + } + GrGetWindowInfo(ep->wid, &winfo); + mwp->x = ep->x - winfo.bordersize; + mwp->y = ep->y - winfo.bordersize; + mwp->width = ep->width + 2 * winfo.bordersize; + GrMoveWindow(mwp->wid, mwp->x + winfo.bordersize, + mwp->y + DEC_HEIGHT + + 2 * winfo.bordersize); + mwp->fid = GrNewWindow(GR_ROOT_WINDOW_ID, mwp->x + 1, + mwp->y + 1, mwp->width - 2, + DEC_HEIGHT - 2, 1, BLUE, BLACK); + GrSelectEvents(mwp->fid, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_MOUSE_POSITION); + GrMapWindow(mwp->fid); + } else { + switch (ep->utype) { + case GR_UPDATE_UNMAP: + GrUnmapWindow(mwp->fid); + GrDestroyWindow(mwp->fid); + if (mwins == mwp) { + mwins = mwp->next; + } else for(tmwp = mwins; tmwp; tmwp = tmwp->next) { + if (tmwp->next == mwp) { + tmwp->next = mwp->next; + } + } + free(mwp); + break; + case GR_UPDATE_MOVE: + GrGetWindowInfo(ep->wid, &winfo); + if ((ep->x == (mwp->x + winfo.bordersize)) && + (ep->y == (mwp->y + winfo.bordersize + + DEC_HEIGHT))) { + return; + } + mwp->x = ep->x - winfo.bordersize; + mwp->y = ep->y - winfo.bordersize - DEC_HEIGHT; + GrMoveWindow(mwp->fid, mwp->x + 1, mwp->y + 1); + default: + break; + } + } +} + +/* + * Handle mouse position events + */ +void do_mouse(ep) + GR_EVENT_MOUSE *ep; +{ +#ifdef SHOW_WINDOW_MOTION + GR_WINDOW_INFO winfo; + + if(!in_motion) return; + + in_motion->x = ep->rootx - move_xoff - 1; + in_motion->y = ep->rooty - move_yoff - 1; + GrMoveWindow(in_motion->fid, in_motion->x + 1, in_motion->y + 1); + GrGetWindowInfo(in_motion->wid, &winfo); + GrMoveWindow(in_motion->wid, in_motion->x + winfo.bordersize - 1, + in_motion->y + 2 * winfo.bordersize + DEC_HEIGHT - 1); +#endif +} + +/* + * Here when an exposure event occurs. + */ +void +do_exposure(ep) + GR_EVENT_EXPOSURE *ep; +{ + struct app_info * act; + int app_no; + + if (ep->wid == w1) { + for(act=Apps,app_no=0;act->app_id[0]!='\0';act++,app_no++) { + GrText(w1, gc, 2, 2 + fheight * (app_no + 1), + act->app_id, -1, GR_TFBOTTOM); + } + } else if (ep->wid == GR_ROOT_WINDOW_ID) { + GrFillRect(GR_ROOT_WINDOW_ID, bgc, ep->x, ep->y, + ep->width, ep->height); + } +} + +extern char ** environ; + +void +do_buttondown(ep) + GR_EVENT_BUTTON *ep; +{ + mwin * mwp; + static int app_no; + + if (ep->wid == w1) { + app_no = ep->y / fheight; + if (app_no >= num_apps) { + app_no = num_apps - 1; + } + + if (!vfork()) { + char * nargv[2]; + + nargv[0] = Apps[app_no].app_path; + nargv[1] = 0; + execve(nargv[0], nargv, environ); + /* write(1, "\7", 1); */ + exit(1); + } + } else if ((mwp = IsDecoration(ep->wid)) != NULL) { + GrRaiseWindow(mwp->wid); + GrRaiseWindow(mwp->fid); + in_motion = mwp; + move_xoff = ep->x; + move_yoff = ep->y; + } +} + +void +do_buttonup(ep) +GR_EVENT_BUTTON *ep; +{ +#ifdef SHOW_WINDOW_MOTION + in_motion = NULL; +#else + mwin * mwp; + GR_WINDOW_INFO winfo; + + if ((mwp = IsDecoration(ep->wid)) != NULL) { + if (mwp == in_motion) { + mwp->x = ep->rootx - 1 - move_xoff; + mwp->y = ep->rooty - 1 - move_yoff; + GrMoveWindow(mwp->fid, mwp->x + 1, mwp->y + 1); + GrGetWindowInfo(mwp->wid, &winfo); + GrMoveWindow(mwp->wid, mwp->x + winfo.bordersize, + mwp->y + 2 * winfo.bordersize + DEC_HEIGHT); + in_motion = NULL; + } + } +#endif +} Index: nxview.c =================================================================== --- nxview.c (nonexistent) +++ nxview.c (revision 174) @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2000, 2001 Greg Haerr + * + * nxview - Nano-X image viewer + * + * Autorecognizes and displays BMP, GIF, JPEG, PNG and XPM files + */ +#include +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" + +int +main(int argc,char **argv) +{ + GR_IMAGE_ID image_id; + GR_WINDOW_ID window_id; + GR_GC_ID gc_id; + GR_SIZE w = -1; + GR_SIZE h = -1; + GR_EVENT event; + GR_SCREEN_INFO sinfo; + GR_IMAGE_INFO info; + char title[256]; + + if (argc < 2) { + printf("Usage: nxview [stretch]\n"); + exit(1); + } + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + if (!(image_id = GrLoadImageFromFile(argv[1], 0))) { + fprintf(stderr, "Can't load image file: %s\n", argv[1]); + exit(1); + } + + if(argc > 2) { + /* stretch to half screen size*/ + GrGetScreenInfo(&sinfo); + w = sinfo.cols/2; + h = sinfo.rows/2; + } else { + GrGetImageInfo(image_id, &info); + w = info.width; + h = info.height; + } + + sprintf(title, "nxview %s", argv[1]); + window_id = GrNewWindowEx(GR_WM_PROPS_APPWINDOW, title, + GR_ROOT_WINDOW_ID, 0, 0, w, h, BLACK); + + GrSelectEvents(window_id, + GR_EVENT_MASK_CLOSE_REQ|GR_EVENT_MASK_EXPOSURE); + + GrMapWindow(window_id); + + gc_id = GrNewGC(); + + while (1) { + GrGetNextEvent(&event); + switch(event.type) { + case GR_EVENT_TYPE_CLOSE_REQ: + GrDestroyWindow(window_id); + GrDestroyGC(gc_id); + GrFreeImage(image_id); + GrClose(); + exit(0); + /* no return*/ + case GR_EVENT_TYPE_EXPOSURE: + GrDrawImageToFit(window_id, gc_id, 0,0, w,h, image_id); + break; + } + } + + return 0; +} Index: world.map =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: world.map =================================================================== --- world.map (nonexistent) +++ world.map (revision 174)
world.map Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: demo.c =================================================================== --- demo.c (nonexistent) +++ demo.c (revision 174) @@ -0,0 +1,479 @@ +/* + * Demonstration program for Nano-X graphics. + */ +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" + +#if DOS_TURBOC +unsigned _stklen = 32768; +#endif + +/* + * Definitions to make it easy to define cursors + */ +#define _ ((unsigned) 0) /* off bits */ +#define X ((unsigned) 1) /* on bits */ +#define MASK(a,b,c,d,e,f,g) \ + (((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) \ + + e) * 2) + f) * 2) + g) << 9) + +#define W2_WIDTH 70 +#define W2_HEIGHT 40 + + +static GR_WINDOW_ID w1; /* id for large window */ +static GR_WINDOW_ID w2; /* id for small window */ +static GR_WINDOW_ID w3; /* id for third window */ +static GR_WINDOW_ID w4; /* id for grabbable window */ +static GR_WINDOW_ID w5; /* id for testing enter/exit window */ +static GR_GC_ID gc1; /* graphics context for text */ +static GR_GC_ID gc2; /* graphics context for rectangle */ +static GR_GC_ID gc3; /* graphics context for circles */ +static GR_GC_ID gc4; /* graphics context for lines */ +static GR_COORD begxpos; /* beginning x position */ +static GR_COORD xpos; /* x position for text drawing */ +static GR_COORD ypos; /* y position for text drawing */ +static GR_COORD linexpos; /* x position for line drawing */ +static GR_COORD lineypos; /* y position for line drawing */ +static GR_COORD xorxpos; /* x position for xor line */ +static GR_COORD xorypos; /* y position for xor line */ +static GR_BOOL lineok; /* ok to draw line */ +static GR_SIZE COLS, ROWS; +static GR_SCREEN_INFO si; /* information about screen */ + +void do_buttondown(GR_EVENT_BUTTON *bp); +void do_buttonup(GR_EVENT_BUTTON *bp); +void do_motion(GR_EVENT_MOUSE *mp); +void do_keystroke(GR_EVENT_KEYSTROKE *kp); +void do_exposure(GR_EVENT_EXPOSURE *ep); +void do_focusin(GR_EVENT_GENERAL *gp); +void do_focusout(GR_EVENT_GENERAL *gp); +void do_enter(GR_EVENT_GENERAL *gp); +void do_exit(GR_EVENT_GENERAL *gp); +void do_idle(void); +/* routine to handle errors */ +void errorcatcher(GR_EVENT *ep); + +int +main(int argc,char **argv) +{ + GR_EVENT event; /* current event */ + GR_BITMAP bitmap1fg[7]; /* bitmaps for first cursor */ + GR_BITMAP bitmap1bg[7]; + GR_BITMAP bitmap2fg[7]; /* bitmaps for second cursor */ + GR_BITMAP bitmap2bg[7]; + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + GrReqShmCmds(655360); + + GrGetScreenInfo(&si); +COLS = si.cols - 40; +ROWS = si.rows - 80; + + /* print error, but don't exit*/ + GrSetErrorHandler(errorcatcher); + + w1 = GrNewWindow(GR_ROOT_WINDOW_ID, 100, 50, COLS - 120, + ROWS - 60, 1, BROWN, WHITE); + w2 = GrNewWindow(GR_ROOT_WINDOW_ID, 6, 6, W2_WIDTH, W2_HEIGHT, 2, GREEN, + WHITE); + w3 = GrNewWindow(GR_ROOT_WINDOW_ID, 250, 30, 80, 100, 1, LTGRAY, + GREEN); + w4 = GrNewWindow(GR_ROOT_WINDOW_ID, 350, 20, 200, 150, 5, BLACK, WHITE); + w5 = GrNewWindow(GR_ROOT_WINDOW_ID, 11, 143, 209, 100, 1, BLUE, GREEN); + + GrSelectEvents(w1, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_FOCUS_IN | GR_EVENT_MASK_FOCUS_OUT | + GR_EVENT_MASK_CLOSE_REQ); + /* must select down and up for w2 to get implicit grab when + * running window manager, otherwise the wm-created parent + * window will get the grab, and we won't get the button up... + */ + GrSelectEvents(w2, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(w3, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_MOUSE_MOTION | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(w4, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_MOUSE_POSITION | + GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(w5, GR_EVENT_MASK_MOUSE_ENTER | + GR_EVENT_MASK_MOUSE_EXIT | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_CLOSE_REQ); + + GrMapWindow(w1); + GrMapWindow(w2); + GrMapWindow(w3); + GrMapWindow(w4); + GrMapWindow(w5); + + gc1 = GrNewGC(); + gc2 = GrNewGC(); + gc3 = GrNewGC(); + gc4 = GrNewGC(); + + GrSetGCForeground(gc1, RED); + GrSetGCBackground(gc1, BROWN); + GrSetGCForeground(gc2, MAGENTA); + GrSetGCMode(gc4, GR_MODE_XOR); + + bitmap1fg[0] = MASK(_,_,_,X,_,_,_); + bitmap1fg[1] = MASK(_,_,_,X,_,_,_); + bitmap1fg[2] = MASK(_,_,_,X,_,_,_); + bitmap1fg[3] = MASK(X,X,X,X,X,X,X); + bitmap1fg[4] = MASK(_,_,_,X,_,_,_); + bitmap1fg[5] = MASK(_,_,_,X,_,_,_); + bitmap1fg[6] = MASK(_,_,_,X,_,_,_); + + bitmap1bg[0] = MASK(_,_,X,X,X,_,_); + bitmap1bg[1] = MASK(_,_,X,X,X,_,_); + bitmap1bg[2] = MASK(X,X,X,X,X,X,X); + bitmap1bg[3] = MASK(X,X,X,X,X,X,X); + bitmap1bg[4] = MASK(X,X,X,X,X,X,X); + bitmap1bg[5] = MASK(_,_,X,X,X,_,_); + bitmap1bg[6] = MASK(_,_,X,X,X,_,_); + + bitmap2fg[0] = MASK(_,_,X,X,X,_,_); + bitmap2fg[1] = MASK(_,X,_,_,_,X,_); + bitmap2fg[2] = MASK(X,_,_,_,_,_,X); + bitmap2fg[3] = MASK(X,_,_,_,_,_,X); + bitmap2fg[4] = MASK(_,X,_,_,_,X,_); + bitmap2fg[5] = MASK(_,_,X,X,X,_,_); + + bitmap2bg[0] = MASK(_,_,X,X,X,_,_); + bitmap2bg[1] = MASK(_,X,X,X,X,X,_); + bitmap2bg[2] = MASK(X,X,X,X,X,X,X); + bitmap2bg[3] = MASK(X,X,X,X,X,X,X); + bitmap2bg[4] = MASK(_,X,X,X,X,X,_); + bitmap2bg[5] = MASK(_,_,X,X,X,_,_); + + GrSetCursor(w1, 7, 7, 3, 3, WHITE, BLACK, bitmap1fg, bitmap1bg); + GrSetCursor(w2, 7, 7, 3, 3, WHITE, BLACK, bitmap2fg, bitmap2bg); + + while (1) { + GrCheckNextEvent(&event); + + switch (event.type) { + case GR_EVENT_TYPE_BUTTON_DOWN: + do_buttondown(&event.button); + break; + + case GR_EVENT_TYPE_BUTTON_UP: + do_buttonup(&event.button); + break; + + case GR_EVENT_TYPE_MOUSE_POSITION: + case GR_EVENT_TYPE_MOUSE_MOTION: + do_motion(&event.mouse); + break; + + case GR_EVENT_TYPE_KEY_DOWN: + do_keystroke(&event.keystroke); + break; + + case GR_EVENT_TYPE_EXPOSURE: + do_exposure(&event.exposure); + break; + + case GR_EVENT_TYPE_FOCUS_IN: + do_focusin(&event.general); + break; + + case GR_EVENT_TYPE_FOCUS_OUT: + do_focusout(&event.general); + break; + + case GR_EVENT_TYPE_MOUSE_ENTER: + do_enter(&event.general); + break; + + case GR_EVENT_TYPE_MOUSE_EXIT: + do_exit(&event.general); + break; + + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + + case GR_EVENT_TYPE_NONE: + do_idle(); + break; + } + } +} + + +/* + * Here when a button is pressed. + */ +void +do_buttondown(GR_EVENT_BUTTON *bp) +{ + GR_PIXELVAL intable[W2_WIDTH * W2_HEIGHT]; + GR_PIXELVAL outtable[W2_WIDTH * W2_HEIGHT * 6]; + GR_PIXELVAL *inp; + GR_PIXELVAL *outp; + GR_PIXELVAL *oldinp; + GR_COORD row; + GR_COORD col; + + /*static int xx = 100; + static int yy = 50;*/ + + if (bp->wid == w3) { + GrRaiseWindow(w3); + GrReadArea(w2, 0, 0, W2_WIDTH, W2_HEIGHT, intable); + inp = intable; + outp = outtable; + for (row = 0; row < W2_HEIGHT; row++) { + oldinp = inp; + for (col = 0; col < W2_WIDTH; col++) { + *outp++ = *inp; + *outp++ = *inp++; + } + inp = oldinp; + for (col = 0; col < W2_WIDTH; col++) { + *outp++ = *inp; + *outp++ = *inp++; + } + inp = oldinp; + for (col = 0; col < W2_WIDTH; col++) { + *outp++ = *inp; + *outp++ = *inp++; + } + } + GrArea(w1, gc1, 0, 0, W2_WIDTH * 2, W2_HEIGHT * 3, outtable, + MWPF_PIXELVAL); + return; + } + + if (bp->wid == w4) { + GrRaiseWindow(w4); + linexpos = bp->x; + lineypos = bp->y; + xorxpos = bp->x; + xorypos = bp->y; + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + lineok = GR_TRUE; + return; + } + + if (bp->wid != w1) { + /* + * Cause a fatal error for testing if more than one + * button is pressed. + */ + if ((bp->buttons & -((int) bp->buttons)) != bp->buttons) + GrClearWindow(-1, 0); + return; + } + + GrRaiseWindow(w1); + /*GrMoveWindow(w1, ++xx, yy);*/ + + if (bp->buttons & GR_BUTTON_L) { + GrClearWindow(w1, GR_TRUE); + return; + } + + begxpos = bp->x; + xpos = bp->x; + ypos = bp->y; +} + + +/* + * Here when a button is released. + */ +void +do_buttonup(GR_EVENT_BUTTON *bp) +{ + if (bp->wid == w4) { + if (lineok) { + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + GrLine(w4, gc3, bp->x, bp->y, linexpos, lineypos); + } + lineok = GR_FALSE; + return; + } + + if (bp->wid == w2) { + GrClose(); + exit(0); + } +} + + +/* + * Here when the mouse has a motion event. + */ +void +do_motion(GR_EVENT_MOUSE *mp) +{ + if (mp->wid == w4) { + if (lineok) { + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + xorxpos = mp->x; + xorypos = mp->y; + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + } + return; + } + + if (mp->wid == w3) { + GrPoint(w3, gc3, mp->x, mp->y); + return; + } +} + + +/* + * Here when a keyboard press occurs. + */ +void +do_keystroke(GR_EVENT_KEYSTROKE *kp) +{ + GR_SIZE width; /* width of character */ + GR_SIZE height; /* height of character */ + GR_SIZE base; /* height of baseline */ + + if (kp->wid == w4) { + if (lineok) { + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + lineok = GR_FALSE; + } + return; + } + + GrGetGCTextSize(gc1, &kp->ch, 1, GR_TFASCII, &width, &height, &base); + if ((kp->ch == '\r') || (kp->ch == '\n')) { + xpos = begxpos; + ypos += height; + return; + } + if (kp->ch == '\b') { /* assumes fixed width font!! */ + if (xpos <= begxpos) + return; + xpos -= width; + GrSetGCForeground(gc3, BROWN); + GrFillRect(w1, gc3, xpos, ypos - height + base + 1, + width, height); + return; + } + GrText(w1, gc1, xpos, ypos + base, &kp->ch, 1, 0); + xpos += width; +} + + +/* + * Here when an exposure event occurs. + */ +void +do_exposure(GR_EVENT_EXPOSURE *ep) +{ + GR_POINT points[3]; + + if (ep->wid != w1) + return; + points[0].x = 311; + points[0].y = 119; + points[1].x = 350; + points[1].y = 270; + points[2].x = 247; + points[2].y = 147; + + GrFillRect(w1, gc2, 50, 50, 150, 200); + GrFillPoly(w1, gc2, 3, points); +} + + +/* + * Here when a focus in event occurs. + */ +void +do_focusin(GR_EVENT_GENERAL *gp) +{ + if (gp->wid != w1) + return; + GrSetBorderColor(w1, WHITE); +} + +/* + * Here when a focus out event occurs. + */ +void +do_focusout(GR_EVENT_GENERAL *gp) +{ + if (gp->wid != w1) + return; + GrSetBorderColor(w1, GRAY); +} + + +/* + * Here when a enter window event occurs. + */ +void +do_enter(GR_EVENT_GENERAL *gp) +{ + if (gp->wid != w5) + return; + GrSetBorderColor(w5, WHITE); + GrRaiseWindow(w5); +} + + +/* + * Here when a exit window event occurs. + */ +void +do_exit(GR_EVENT_GENERAL *gp) +{ + if (gp->wid != w5) + return; + GrSetBorderColor(w5, GREEN); + GrLowerWindow(w5); +} + + +/* + * Here to do an idle task when nothing else is happening. + * Just draw a randomly colored filled circle in the small window. + */ +void +do_idle(void) +{ + GR_COORD x; + GR_COORD y; + GR_SIZE rx; + GR_SIZE ry; + GR_COLOR color; + + x = rand() % 70; + y = rand() % 40; + rx = (rand() % 10) + 5; + ry = (rx * si.ydpcm) / si.xdpcm; /* make it appear circular */ + + color = rand() % si.ncolors; + + GrSetGCForeground(gc3, MWPALINDEX(color)); + GrFillEllipse(w2, gc3, x, y, rx, ry); +} + + +/* + * Here on a server error. Print the std message but don't exit. + */ +void +errorcatcher(GR_EVENT *ep) +{ + printf("nxclient: Error (%s) ", ep->error.name); + printf(nxErrorStrings[ep->error.code], ep->error.id); +} Index: launcher.cnf =================================================================== --- launcher.cnf (nonexistent) +++ launcher.cnf (revision 174) @@ -0,0 +1,55 @@ +# Sample launcher configuration file + +# These are the screen savers to use: +# A simple screen blanker: +# $screensaver bin/nsaver 1 +# Draws random dots: +$screensaver bin/nsaver 2 +# Draws random lines: +$screensaver bin/nsaver 3 +# Draws worms that crawl randomly around the screen: +$screensaver bin/nsaver 4 +# Draws a star field accelerating towards the viewer: +$screensaver bin/nsaver 5 +# Draws a simulated lightning storm: +$screensaver bin/nsaver 6 +# Draws an orbiting planet simulation: +$screensaver bin/nsaver 7 +# Draws a moire interference pattern: +$screensaver bin/nsaver 8 + +# This is the screen saver timeout delay (in seconds): +$screensaver_timeout 300 + +# This is the file to use as the root window background image: +$window_background_image bin/tux.gif + +# This is the mode to use for the window background: +# 0 = tile across screen +# 1 = draw once in centre of screen +# 2 = draw once at top left of screen +$window_background_mode 0 + +# This is the background colour to use for the root window: +# Possible values are: +# BLACK, BLUE, GREEN, RED, MAGENTA, BROWN, LTGRAY, GRAY, LTBLUE, LTGREEN, +# LTCYAN, LTRED, LTMAGENTA, YELLOW, WHITE. +# $window_background_colour GREEN + +# These are the launcher panel items. Each line is in the format: + +# The item name must not contain any spaces. +# <...> +# The item name must not contain any spaces. +# The icon filename can be the letter '-' to specify no icon. + +Tetris bin/ntetris.ppm bin/ntetris +Landmine - bin/landmine +Slider - bin/slider demos/nanox/slidebmp.bmp +Terminal - bin/nxterm +Clock - bin/nxclock +Map - bin/world +Scribble - bin/nxscribble +SoftKeyboard - bin/nxkbd +Logo - bin/nxview bin/nanogui.ppm +Roach - bin/nxroach -roaches 10 Index: getselection.c =================================================================== --- getselection.c (nonexistent) +++ getselection.c (revision 174) @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +#include "nano-X.h" + +static int bytes_received = 0; +static char *data = NULL; + +int got_client_data(GR_EVENT *event) +{ + GR_EVENT_CLIENT_DATA *ev = &event->clientdata; + + fprintf(stderr, "Got client data packet with serial number %ld for " + "window %d from window %d\n", ev->serial, ev->wid, + ev->rid); + if(!(data = realloc(data, bytes_received + ev->datalen))) { + fprintf(stderr, "Out of memory\n"); + exit(7); + } + memcpy(data + bytes_received, ev->data, ev->datalen); + free(ev->data); + + fprintf(stderr, "Got client data packet with serial number %ld for " + "window %d from window %d\n", ev->serial, ev->wid, + ev->rid); + fprintf(stderr, "Already received %d bytes, this packet is %ld bytes " + "long, and the total data length is %ld bytes so ", + bytes_received, ev->datalen, ev->len); + + bytes_received += ev->datalen; + if(bytes_received == ev->len) { + fprintf(stderr, "we have received all of the data now.\n"); + fprintf(stderr, "The data in the packet is:\n%s\n", data); + return 1; + } + else if(bytes_received < ev->len) { + fprintf(stderr, "this is not the last data packet.\n"); + return 0; + } else fprintf(stderr, "we have received too much data (shouldn't " + "happen)\n"); + + return 1; +} + +int main(int argc, char *argv[]) +{ + GR_CHAR *typelist, *p; + GR_WINDOW_ID sid, wid; + GR_EVENT event; + int n = 0, mimetype = -1; + + if(GrOpen() < 0) { + fprintf(stderr, "Couldn't connect to Nano-X server\n"); + return 1; + } + + sid = GrGetSelectionOwner(&typelist); + if(!sid) { + fprintf(stderr, "Clipboard is empty\n"); + return 2; + } + + if(!typelist) { + fprintf(stderr, "GrGetSelectionOwner() returned an empty " + "type list for window %d\n", sid); + return 3; + } + + fprintf(stderr, "Window %d owns the selection\n", sid); + fprintf(stderr, "It claims to be able to supply data in the following " + "types:\n%s\n", typelist); + + p = strtok(typelist, " "); + do { + if(!strncmp("text/plain", p, 10)) { + mimetype = n; + break; + } + n++; + } while((p = strtok(NULL, " "))); + + if(mimetype == -1) { + fprintf(stderr, "Type text/plain is not available\n"); + return 4; + } + + free(typelist); + + fprintf(stderr, "Type text/plain is available- requesting data\n"); + + wid = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, 1, 1, 0, 0, 0); + if(!wid) { + fprintf(stderr, "Couldn't get a window\n"); + return 5; + } + + GrSelectEvents(wid, GR_EVENT_MASK_CLIENT_DATA); + + GrRequestClientData(wid, sid, 0, mimetype); + + while(1) { + GrGetNextEventTimeout(&event, 4000); + switch(event.type) { + case GR_EVENT_TYPE_CLIENT_DATA: + if(got_client_data(&event)) + return 0; + break; + case GR_EVENT_TYPE_TIMEOUT: + fprintf(stderr, "Timed out waiting for data\n"); + return 6; + default: + break; + } + } + + return 0; +} Index: world.c =================================================================== --- world.c (nonexistent) +++ world.c (revision 174) @@ -0,0 +1,654 @@ +/* + * Draw a crude map of the world using mini-X graphics on MINIX. + * Converted from an Amiga program by Mike Groshart and Bob Dufford. + * Author: David I. Bell + * + * ported to 16 bit systems by Greg Haerr + */ +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" + +#if defined(MSDOS) || defined(__ECOS) +#include +#endif + +#if LINUX | DOS_DJGPP +#include +#include +#include +#include +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#if defined(DOS_DJGPP) || defined(__ECOS) +#define MAPFILE "world.map" +#else +#define MAPFILE "demos/nanox/world.map" /* was /usr/lib*/ +#endif + +#define SELECTBUTTON GR_BUTTON_L +#define COORDBUTTON GR_BUTTON_R + + +/* + * Definitions to use fixed point in place of true floating point. + */ +typedef long FLOAT; + +#define SCALE 100 /* fixed point scaling factor */ + +#define FFMUL(a,b) (((FLOAT)(a) * (b) + (SCALE / 2)) / SCALE) +#define FFDIV(a,b) (((FLOAT)(a) * SCALE) / (b)) +#define FIMUL(a,b) ((FLOAT)(a) * (b)) +#define FIDIV(a,b) ((FLOAT)(a) / (b)) +#define ITOF(a) ((FLOAT)(a) * SCALE) +#define FTOI(a) (((FLOAT)(a) + (SCALE / 2)) / SCALE) + + +#define QSPAN (90L*60*SCALE) /* equator to pole (90 degrees) */ +#define HSPAN (QSPAN*2) /* pole to pole (180 degrees) */ +#define WSPAN (QSPAN*4) /* around equator (360 degrees) */ + +#define ABS(n) (((n) < 0) ? -(n) : (n)) + + +/* + * Structure of a point in the database file. + */ +typedef struct { + short Code; /* type of point (see code_colors below) */ + short Lat; /* latitude in minutes */ + short Lon; /* longitude in minutes */ +} MWPACKED DBPOINT; + +#if BIGENDIAN +#define SHORT_SWAP(p) (p = ((p & 0xff) << 8) | ((p >> 8) & 0xff)) +#define DBPOINT_CONVERT(p) (SHORT_SWAP(p->Code),SHORT_SWAP(p->Lat),SHORT_SWAP(p->Lon)) +#else +#define DBPOINT_CONVERT(p) ((void)p) +#endif + +#define POINTSize sizeof(DBPOINT) +#define PCount 128 /* number of points to read at once */ + + +/* + * The following variables are the scaling factors to be used when drawing + * points. However, they are larger than the true value by a factor of 60. + * This is done because without real floating point, their true values are + * too small to be accurate enough. I cannot just increase the fixed point + * precision because that causes overflows. What a pain! + */ +static FLOAT X_Scale; +static FLOAT Y_Scale; + +/* + * Other variables. + */ +static FLOAT Latitude, Longitude; /* current center of view */ +static FLOAT zoom; /* current zoom scaling factor */ + +static FLOAT latradius; /* half of view of latitide */ +static FLOAT longradius; /* half of view of longitude */ +static FLOAT viewlong; /* amount of longitide in view */ +static FLOAT viewlat; /* amount of latitude in view */ + +static GR_SIZE mapwidth; /* width of map in pixels */ +static GR_SIZE mapheight; /* height of map in pixels */ +static GR_COORD mapxorig; /* one half of map width */ +static GR_COORD mapyorig; /* one half of map height */ +static GR_COORD selectx; /* x position of current selection */ +static GR_COORD selecty; /* y position of current selection */ +static GR_COORD selectptrx; /* x position of pointer in selection */ +static GR_COORD selectptry; /* y position of pointer in selection */ +static GR_SIZE selectwidth; /* width of current selection */ +static GR_SIZE selectheight; /* height of current selection */ +static int selectmode; /* selection mode */ +static GR_BOOL selectvisible; /* TRUE if selection is visible on screen */ +static GR_SIZE selectxscale; /* x scaling factor for selection rectangle */ +static GR_SIZE selectyscale; /* y scaling factor for selection rectangle */ +static GR_BOOL coordvisible; /* TRUE if coordinates are visible on screen */ +static GR_BOOL coordenabled; /* TRUE if coordinate display is enabled */ +static GR_COORD coordx; /* x position of coordinates */ +static GR_COORD coordy; /* y position of coordinates */ +static GR_COORD ptrx; /* latest x position of pointer */ +static GR_COORD ptry; /* latest y position of pointer */ +static char coordstring[32]; /* coordinate string */ + +static GR_WINDOW_ID mainwid; /* main window id */ +static GR_WINDOW_ID mapwid; /* window id for map */ +static GR_GC_ID mapgc; /* GC used for drawing map */ +static GR_GC_ID xorgc; /* GC used for rubber banding */ +static GR_SIZE COLS, ROWS; + + +/* + * Current selection mode + */ +#define SELECT_NONE 0 +#define SELECT_SCALE 1 +#define SELECT_MOVE 2 + +/* + * Order of color table (indexed by type of point): + * unused + * continents + * countries + * unused + * USA states + * islands + * lakes + * rivers + */ +static GR_COLOR code_colors[] = { + BLACK, GREEN, RED, BLACK, BROWN, GREEN, BLUE, BLUE +}; + + +static void load(); +static void setzoom(); +static void checkevent(); +static void doexposure(); +static void dobuttondown(); +static void dobuttonup(); +static void doposition(); +static void dokeydown(); +static void showselection(); +static void showcoords(); +static void mintostr(); + + +#ifdef __ECOS +int +world_main(int argc, char **argv) +#else +int +main(int argc, char **argv) +#endif +{ + GR_SCREEN_INFO si; + GR_WM_PROPERTIES props; + + if (GrOpen() < 0) { + fprintf(stderr, "Cannot open graphics\n"); + exit(1); + } + + GrReqShmCmds(65536); /* Test by Morten Rolland for shm support */ + + GrGetScreenInfo(&si); +#ifdef __ECOS +/* 240x320 screen*/ +COLS = si.cols - 10; +ROWS = si.rows - 40; +#else +COLS = si.cols - 40; +ROWS = si.rows - 80; +#endif + + mainwid = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, COLS, ROWS, + 0, BLACK, BLACK); + + /* set title */ + props.flags = GR_WM_FLAGS_TITLE | GR_WM_FLAGS_PROPS; + props.props = GR_WM_PROPS_BORDER | GR_WM_PROPS_CAPTION; + props.title = "NanoX World Map"; + GrSetWMProperties(mainwid, &props); + + mapwidth = COLS - 2; + mapheight = ROWS - 2; + mapxorig = mapwidth / 2; + mapyorig = mapheight / 2; + selectxscale = 4; + selectyscale = 3; + coordx = 0; + coordy = ROWS - 1; + mapwid = GrNewWindow(mainwid, 1, 1, mapwidth, mapheight, +#if 0 + 1, BLACK, WHITE); +#else + 1, LTGRAY, BLACK); +#endif + GrSelectEvents(mainwid, GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(mapwid, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_BUTTON_UP | + GR_EVENT_MASK_MOUSE_POSITION | GR_EVENT_MASK_KEY_DOWN); + + GrMapWindow(mainwid); + GrMapWindow(mapwid); + + mapgc = GrNewGC(); + xorgc = GrNewGC(); + GrSetGCMode(xorgc, GR_MODE_XOR); + + Longitude = ITOF(0); + Latitude = ITOF(0); + setzoom(ITOF(1)); + + while (1) + checkevent(); +} + + +static void +checkevent() +{ + GR_EVENT event; + + GrGetNextEvent(&event); + switch (event.type) { + case GR_EVENT_TYPE_EXPOSURE: + doexposure(&event.exposure); + break; + case GR_EVENT_TYPE_BUTTON_DOWN: + dobuttondown(&event.button); + break; + case GR_EVENT_TYPE_BUTTON_UP: + dobuttonup(&event.button); + break; + case GR_EVENT_TYPE_MOUSE_POSITION: + doposition(&event.mouse); + break; + case GR_EVENT_TYPE_KEY_DOWN: + dokeydown(&event.keystroke); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + } +} + + +static void +doexposure(ep) + GR_EVENT_EXPOSURE *ep; +{ + if (ep->wid != mapwid) + return; + + /* removed: helps with blink with nanowm*/ + /*GrClearWindow(mapwid, GR_FALSE);*/ + selectvisible = GR_FALSE; + coordvisible = GR_FALSE; + load(MAPFILE); + showselection(GR_TRUE); + showcoords(GR_TRUE); +} + + +static void +dobuttondown(bp) + GR_EVENT_BUTTON *bp; +{ + if (bp->wid != mapwid) + return; + + if (bp->changebuttons & SELECTBUTTON) { + showselection(GR_FALSE); + selectx = bp->x; + selecty = bp->y; + selectptrx = bp->x; + selectptry = bp->y; + selectwidth = 0; + selectheight = 0; + selectmode = SELECT_SCALE; + showselection(GR_TRUE); + } + + if (bp->changebuttons & COORDBUTTON) { + showcoords(GR_FALSE); + ptrx = bp->x; + ptry = bp->y; + coordenabled = GR_TRUE; + showcoords(GR_TRUE); + } +} + + +static void +dobuttonup(bp) + GR_EVENT_BUTTON *bp; +{ + if (bp->wid != mapwid) + return; + + if (bp->changebuttons & COORDBUTTON) { + showcoords(GR_FALSE); + coordenabled = GR_FALSE; + } + + if (bp->changebuttons & SELECTBUTTON) { + showselection(GR_FALSE); + if (selectmode == SELECT_NONE) + return; + selectmode = SELECT_NONE; + if (selectwidth <= 0) + return; + Longitude += + FIDIV(FIMUL(viewlong, selectx - mapxorig), mapwidth); + Latitude -= + FIDIV(FIMUL(viewlat, selecty - mapyorig), mapheight); + setzoom(FIDIV(FIMUL(zoom, mapwidth), selectwidth)); + GrClearWindow(mapwid, GR_TRUE); + } +} + + +static void +doposition(mp) + GR_EVENT_MOUSE *mp; +{ + GR_SIZE temp; + + if (mp->wid != mapwid) + return; + + if (coordenabled) { + showcoords(GR_FALSE); + ptrx = mp->x; + ptry = mp->y; + showcoords(GR_TRUE); + } + + showselection(GR_FALSE); + switch (selectmode) { + case SELECT_SCALE: + selectwidth = ABS(mp->x - selectx) * 2 + 1; + selectheight = ABS(mp->y - selecty) * 2 + 1; + temp = ((long) selectwidth) * selectyscale + / selectxscale; + if (selectheight < temp) + selectheight = temp; + temp = ((long) selectheight) * selectxscale + / selectyscale; + if (selectwidth < temp) + selectwidth = temp; + break; + + case SELECT_MOVE: + selectx += (mp->x - selectptrx); + selecty += (mp->y - selectptry); + break; + } + + selectptrx = mp->x; + selectptry = mp->y; + showselection(GR_TRUE); +} + + +static void +dokeydown(kp) + GR_EVENT_KEYSTROKE *kp; +{ + if (kp->wid != mapwid) + return; + + if (selectmode != SELECT_NONE) { + switch (kp->ch) { + case 's': /* scale selection */ + selectmode = SELECT_SCALE; + break; + + case 'm': /* move selection */ + selectmode = SELECT_MOVE; + break; + + case '\033': /* cancel selection */ + showselection(GR_FALSE); + selectmode = SELECT_NONE; + break; + } + return; + } + + switch (kp->ch) { + case 'q': /* quit */ + case 'Q': + GrClose(); + exit(0); + + case 't': /* redraw total map */ + Longitude = ITOF(0); + Latitude = ITOF(0); + setzoom(ITOF(1)); + GrClearWindow(mapwid, GR_TRUE); + } +} + + +/* + * Draw or erase the current selection if any is defined. + * The selection is a rectangle centered on a specified point, and with a + * specified width and height. Drawing and erasing the selection are the + * same drawing operation because of the XOR operation. + */ +static void +showselection(show) + GR_BOOL show; /* TRUE if show the selection */ +{ + if ((show == 0) == (selectvisible == 0)) + return; + if (selectmode == SELECT_NONE) + return; + GrRect(mapwid, xorgc, selectx - selectwidth / 2, + selecty - selectheight / 2, selectwidth, selectheight); + selectvisible = show; +} + + +/* + * Draw or erase the coordinate string of the current pointer position. + * Both of these are the same operation because of the XOR operation. + */ +static void +showcoords(show) + GR_BOOL show; /* TRUE if show the coordinates */ +{ + long curlong; + long curlat; + FLOAT ptrlat; + FLOAT ptrlong; + + if (((show == 0) == (coordvisible == 0)) || !coordenabled) + return; + + if (show) { + ptrlat = FIDIV(FIMUL(viewlat, ptry), mapheight - 1); + ptrlong = FIDIV(FIMUL(viewlong, ptrx), mapwidth - 1); + + curlat = FTOI(Latitude + latradius - ptrlat); + curlong = FTOI(Longitude - longradius + ptrlong); + + if (curlong > 180*60) + curlong -= 360*60; + if (curlong < -180*60) + curlong += 360*60; + + mintostr(coordstring, curlong); + strcat(coordstring, " "); + mintostr(coordstring + strlen(coordstring), curlat); + } + + GrText(mapwid, xorgc, coordx, coordy, coordstring, -1, GR_TFBOTTOM); + coordvisible = show; +} + + +/* + * Convert minutes to a string of the form "ddd'mm" and store it + * into the indicated buffer. + */ +static void +mintostr(buf, minutes) + char *buf; + long minutes; +{ + if (minutes < 0) { + minutes = -minutes; + *buf++ = '-'; + } + sprintf(buf, "%ld'%02ld", (long)(minutes / 60), (long)(minutes % 60)); +} + + +#if 0 +/* + * Convert "ddd'mm" to mins + */ +static long +degtomin(s) + char *s; +{ + int deg, minutes; + char str[10],*strchr(),*cp; + + strcpy(str,s); + if (cp = strchr(str,'\047')) { + *cp = '\0'; + minutes = atoi(++cp); + } else + minutes = 0; + if ((deg = atoi(str)) < 0) + minutes = -minutes; + return(deg * 60 + minutes); +} +#endif + + +/* + * Set the scale factors for the given zoom factor. + * The factors 3 and 4 are here to compensate for the screen aspect ratio. + */ +static void +setzoom(newzoom) + FLOAT newzoom; +{ + zoom = newzoom; + + Y_Scale = FIDIV(FIMUL(zoom, mapheight * 3), 180 * 4); + X_Scale = FIDIV(FIMUL(zoom, mapwidth), 360); + + viewlong = FFDIV(WSPAN, zoom); + viewlat = FFDIV(HSPAN * 4 / 3, zoom); + longradius = FIDIV(viewlong, 2); + latradius = FIDIV(viewlat, 2); +} + + +/* + * Read the database file and draw the world. + */ +static void +load(fn) + char *fn; +{ + register DBPOINT *pp; + DBPOINT *pend; + FLOAT x, y, LonPrv, LatPrv; + long oldlong = 0L; + GR_COORD xnew, ynew; + GR_COORD xold = 0, yold = 0; + GR_BOOL is_out; + GR_BOOL was_out; + GR_BOOL newseg = GR_FALSE; + GR_COLOR oldcolor; + GR_COLOR newcolor; + int n; + int fh; + DBPOINT p[PCount]; + + LonPrv = ITOF(0); + LatPrv = ITOF(0); + oldcolor = -1; + is_out = GR_FALSE; + was_out = GR_FALSE; + + fh = open(fn, O_BINARY | O_RDONLY); + if (fh < 0) { + GrClose(); + fprintf(stderr, "Cannot open %s\n", fn); + exit(1); + } + + while ((n = read(fh, p, PCount * POINTSize)) > 0) { + for (pp = p,pend = p + n/POINTSize; pp < pend; pp++) + { + DBPOINT_CONVERT(pp); + /* do displacement */ + x = ITOF(pp->Lon) - Longitude; + y = ITOF(pp->Lat) - Latitude; + + /* wrap around for East-West */ + if (x < -HSPAN) + x += WSPAN; + if (x > HSPAN) + x -= WSPAN; + + if (pp->Code > 5) { + newcolor = code_colors[pp->Code / 1000]; + if (newcolor != oldcolor) { + oldcolor = newcolor; + GrSetGCForeground(mapgc, oldcolor); + } + newseg = GR_TRUE; + } + + if (oldcolor == BLACK) + goto go_on; + + /* ignore points outside magnified area */ + if ((x < -longradius || x > longradius || + y < -latradius || y > latradius)) + { + is_out = 1; + if (was_out) { /* out to out */ + LonPrv = x; + LatPrv = y; + goto go_on; + } + + /* in to out */ + xold = mapxorig + FTOI(FFMUL(LonPrv, X_Scale)) / 60; + yold = mapyorig - FTOI(FFMUL(LatPrv, Y_Scale)) / 60; + } else { /* out to in */ + is_out = 0; + if (was_out) { + xold = mapxorig + + FTOI(FFMUL(LonPrv, X_Scale)) / 60; + yold = mapyorig - + FTOI(FFMUL(LatPrv, Y_Scale)) / 60; + } + /* in to in */ + } + LonPrv = x; + LatPrv = y; + + /* scale points w/in area to interlace screen */ + xnew = mapxorig + FTOI(FFMUL(x, X_Scale)) / 60; + ynew = mapyorig - FTOI(FFMUL(y, Y_Scale)) / 60; + + /* if new segment, move to place */ + if (newseg || ABS(oldlong - pp->Lon) > 180*60) { + xold = xnew; + yold = ynew; + } + oldlong = pp->Lon; + + GrLine(mapwid, mapgc, xold, yold, xnew, ynew); + xold = xnew; + yold = ynew; +go_on: + was_out = is_out; + newseg = GR_FALSE; + } + } + close(fh); +} + +/* END CODE */ Index: slidebmp.bmp =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: slidebmp.bmp =================================================================== --- slidebmp.bmp (nonexistent) +++ slidebmp.bmp (revision 174)
slidebmp.bmp Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: info.c =================================================================== --- info.c (nonexistent) +++ info.c (revision 174) @@ -0,0 +1,55 @@ +/* + * Display the results of various GrGetsomethingInfo() calls. + */ + +#include +#include +#include "nano-X.h" + +int main() +{ + GR_SCREEN_INFO si; + GR_FONT_INFO fi; + GR_GC_INFO gi; + GR_FONT fonts; + int x, y; + + GrOpen(); + GrGetScreenInfo(&si); + + printf("rows = %d\n", si.rows); + printf("cols = %d\n", si.cols); + printf("bpp = %d\n", si.bpp); + printf("planes = %d\n", si.planes); + printf("ncolors = %d\n", si.ncolors); + printf("buttons = 0x%x\n", si.buttons); + printf("modifiers = 0x%x\n", si.modifiers); + printf("fonts = %d\n", si.fonts); + + getch(); + + for(fonts = 0; fonts < si.fonts; fonts++) { +/* if(!GrGetFontInfo(fonts, &fi)) { */ + GrGetFontInfo(fonts, &fi); + if(1) { + printf("\nfont = %d\n", fi.font); + printf("height = %d\n", fi.height); + printf("maxwidth = %d\n", fi.maxwidth); + printf("baseline = %d\n", fi.baseline); + printf("fixed = %s\n", fi.fixed ? "TRUE" : "FALSE"); + printf("widths =\n"); + for(y = 0; y != 3; y++) { + for(x = 0; x != 7; x++) + printf("%2d", fi.widths[x * y]); + printf("\n"); + + getch(); + + } + } + } + + getch(); + + GrClose(); +} Index: Makefile =================================================================== --- Makefile (nonexistent) +++ Makefile (revision 174) @@ -0,0 +1,186 @@ +############################################################################## +# Microwindows template Makefile +# Copyright (c) 2000, 2002 Martin Jolicoeur, Greg Haerr +############################################################################## + +ifndef TOP +TOP = ../.. +CONFIG = $(TOP)/config +endif + +include $(CONFIG) + +VPATH := $(TOP)/demos/nanox + +######################## Additional Flags section ############################ + +# Directories list for header files +INCLUDEDIRS += +# Defines for preprocessor +DEFINES += + +# Compilation flags for C files OTHER than include directories +CFLAGS += +# Preprocessor flags OTHER than defines +CPPFLAGS += +# Linking flags +LDFLAGS += -lm + +############################# targets section ################################ + +ifeq ($(NANOX), Y) +ifeq ($(NANOXDEMO), Y) + +# If you want to create a library with the objects files, define the name here +LIBNAME = + +# List of objects to compile +ifeq ($(ARCH), ECOS) +OBJS = landmine.o +TARGETS = $(BUILD)/bin/landmine.o +OBJS += ntetris.o +TARGETS += $(BUILD)/bin/ntetris.o +OBJS += world.o +TARGETS += $(BUILD)/bin/world.o +else +OBJS = demo.o \ + move.o \ + landmine.o \ + world.o \ + nxclock.o \ + nxterm.o \ + nxview.o \ + nxlsclients.o \ + nxev.o \ + npanel.o \ + nterm.o \ + demo2.o \ + demo5.o \ + demo6.o \ + t1demo.o \ + ftdemo.o \ + logfont.o \ + slider.o \ + ntetris.o \ + launcher.o \ + nsaver.o \ + getselection.o \ + setselection.o + +TARGETS = $(TOP)/bin/demo $(TOP)/bin/move $(TOP)/bin/landmine \ + $(TOP)/bin/world $(TOP)/bin/nxclock $(TOP)/bin/nxterm \ + $(TOP)/bin/nxview $(TOP)/bin/nxlsclients $(TOP)/bin/nxev \ + $(TOP)/bin/npanel $(TOP)/bin/nterm \ + $(TOP)/bin/demo2 $(TOP)/bin/demo5 $(TOP)/bin/demo6 \ + $(TOP)/bin/t1demo $(TOP)/bin/ftdemo $(TOP)/bin/logfont \ + $(TOP)/bin/slider $(TOP)/bin/ntetris $(TOP)/bin/launcher \ + $(TOP)/bin/nsaver $(TOP)/bin/getselection $(TOP)/bin/setselection +endif + +all: default $(TARGETS) support + +support: world.map nanogui.ppm ntetris.ppm launcher.cnf tux.gif + $(CP) $^ $(BUILD)/bin +endif +endif + +######################### Makefile.rules section ############################# + +include $(TOP)/Makefile.rules + +ifeq ($(SHAREDLIBS), Y) +LD_NANOXCLIENTLIBS = $(CCNANOXCLIENTLIBS) +else +LD_NANOXCLIENTLIBS = $(NANOXCLIENTLIBS) +endif + +######################## Tools targets section ############################### + +$(BUILD)/bin/demo: demo.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/move: move.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/landmine: landmine.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/world: world.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/nxclock: nxclock.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/nxterm: nxterm.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/nxview: nxview.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/nxlsclients: nxlsclients.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/nxev: nxev.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/npanel: npanel.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/nterm: nterm.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/demo2: demo2.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/demo5: demo5.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/demo6: demo6.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/t1demo: t1demo.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/ftdemo: ftdemo.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/logfont: logfont.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/slider: slider.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/ntetris: ntetris.o $(NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/launcher: launcher.o $($NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/nsaver: nsaver.o $($NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/getselection: getselection.o $($NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +$(BUILD)/bin/setselection: setselection.o $($NANOXCLIENTLIBS) $(BUILD)/config + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LD_NANOXCLIENTLIBS) + +ifeq ($(ARCH), ECOS) +# Special build rules for linked in applications +$(BUILD)/bin/landmine.o: landmine.o +# $(CC) $(CFLAGS) $(LDFLAGS) $< -Wl,-r -Wl,--retain-symbols-file -Wl,landmine.syms -Wl,--defsym -Wl,landmine_main=main -o XX.o + $(CC) $(CFLAGS) $(LDFLAGS) $< -Wl,-r -Wl,--defsym -Wl,landmine_main=main -o XX.o + $(NM) XX.o | grep -v _main | grep ' T' | awk -f $(TOP)/ecos/retain.awk | xargs $(OBJCOPY) XX.o $@ + rm -f XX.o + +$(BUILD)/bin/ntetris.o: ntetris.o + $(CC) $(CFLAGS) $(LDFLAGS) $< -Wl,-r -Wl,--defsym -Wl,ntetris_main=main -o XX.o + $(NM) XX.o | grep -v _main | grep ' T' | awk -f $(TOP)/ecos/retain.awk | xargs $(OBJCOPY) XX.o $@ + rm -f XX.o + +$(BUILD)/bin/world.o: world.o + $(CC) $(CFLAGS) $(LDFLAGS) $< -Wl,-r -Wl,--defsym -Wl,world_main=main -o XX.o + $(NM) XX.o | grep -v _main | grep ' T' | awk -f $(TOP)/ecos/retain.awk | xargs $(OBJCOPY) XX.o $@ + rm -f XX.o +endif + Index: nsaver.c =================================================================== --- nsaver.c (nonexistent) +++ nsaver.c (revision 174) @@ -0,0 +1,959 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is NanoScreenSaver. + * + * The Initial Developer of the Original Code is Alex Holden. + * Portions created by Alex Holden are Copyright (C) 2000 + * Alex Holden . All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public license (the "[GNU] License"), in which case the + * provisions of [GNU] License are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the [GNU] License and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the [GNU] License. If you do not delete + * the provisions above, a recipient may use your version of this file + * under either the MPL or the [GNU] License. + */ +/* + * A collection of screen savers for Nano-X by Alex Holden. + */ + +#include +#include +#include +#include +#include + +#define MWINCLUDECOLORS +#include "nano-X.h" +#include "nsaver.h" + +void *my_malloc(size_t size) +{ + void *ret; + + if(!(ret = malloc(size))) { + fprintf(stderr, "Out of memory\n"); + exit(1); + } + + return ret; +} + +void get_random_point_on_screen(nstate *state, GR_COORD *x, GR_COORD *y, + GR_COLOR *c) +{ + if(x) { + *x = (int) RANDRANGE(0, (state->si.cols - 1.0)); + } + if(y) { + *y = (int) RANDRANGE(0, (state->si.rows - 1.0)); + } + if(c) { + *c = MWPALINDEX((int)RANDRANGE(0, (state->si.ncolors - 1))); + } +} + +void saver1_init(nstate *state) {} + +void saver1_exposure(nstate *state) +{ + GrClearWindow(state->main_window, 0); +} + +void saver1_animate(nstate *state) {} + +void saver2_init(nstate *state) +{ + (int)state->priv = SAVER2_MAXPIXELS; + state->animate_interval = SAVER2_DELAY; +} + +void saver2_exposure(nstate *state) +{ + GrClearWindow(state->main_window, 0); +} + +void saver2_animate(nstate *state) +{ + GR_COORD x, y; + GR_COLOR c; + int pixels = SAVER2_PIXELS_PER_FRAME; + + while(pixels--) { + if(!((int)state->priv--)) { + (int)state->priv = SAVER2_MAXPIXELS; + GrClearWindow(state->main_window, 0); + } + get_random_point_on_screen(state, &x, &y, &c); + GrSetGCForeground(state->main_gc, c); + GrPoint(state->main_window, state->main_gc, x, y); + } +} + +void saver3_init(nstate *state) +{ + s3state *s = my_malloc(sizeof(s3state)); + state->priv = s; + s->maxsegments = SAVER3_MAXSEGMENTS; + s->lastx = 0; + s->lasty = 0; + state->animate_interval = SAVER3_DELAY; +} + +void saver3_exposure(nstate *state) +{ + GrClearWindow(state->main_window, 0); +} + +void saver3_animate(nstate *state) +{ + GR_COORD newx, newy; + GR_COLOR c; + s3state *s = state->priv; + int pixels = SAVER3_SEGMENTS_PER_FRAME; + + while(pixels--) { + if(!(s->maxsegments--)) { + s->maxsegments = SAVER3_MAXSEGMENTS; + GrClearWindow(state->main_window, 0); + } + get_random_point_on_screen(state, &newx, &newy, &c); + GrSetGCForeground(state->main_gc, c); + GrLine(state->main_window, state->main_gc, s->lastx, s->lasty, + newx, newy); + s->lastx = newx; + s->lasty = newy; + } +} + +void saver4_init(nstate *state) +{ + int i; + + s4state *s = my_malloc(sizeof(s4state)); + state->priv = s; + + s->length = 0; + + for(i = 0; i < SAVER4_NUMWORMS; i++) { + s->tip = 0; + get_random_point_on_screen(state, &s->worms[i].points[0].x, + &s->worms[i].points[0].y, + &s->worms[i].colour); + } + + state->animate_interval = SAVER4_DELAY; +} + +void saver4_exposure(nstate *state) +{ + int i; + s4state *s = state->priv; + + GrClearWindow(state->main_window, 0); + + if(!s->length) return; + + for(i = 0; i < SAVER4_NUMWORMS; i++) { + GrSetGCForeground(state->main_gc, s->worms[i].colour); + GrPoints(state->main_window, state->main_gc, s->length, + s->worms[i].points); + } +} + +void saver4_get_new_worm_position(nstate *state, s4state *s, int worm, + GR_COORD *newx, GR_COORD *newy) +{ + int i; + GR_COORD oldx = s->worms[worm].points[s->tip].x; + GR_COORD oldy = s->worms[worm].points[s->tip].y; + + do { + i = (int)RANDRANGE(0, 3.0); + switch(i) { + case 0: + *newx = oldx + 1; + if(*newx == state->si.cols) *newx = 0; + break; + case 1: + *newx = oldx - 1; + if(*newx == -1) *newx = state->si.cols - 1; + break; + case 2: + *newx = oldx; + break; + } + + i = (int)RANDRANGE(0, 3.0); + switch(i) { + case 0: + *newy = oldy + 1; + if(*newy == state->si.rows) *newy = 0; + break; + case 1: + *newy = oldy - 1; + if(*newy == -1) *newy = state->si.rows - 1; + break; + case 2: + *newy = oldy; + break; + } + } while((*newx == oldx) && (*newy == oldy)); +} + +int saver4_worm_collides(nstate *state, s4state *s, int x, int y, int thisworm, + int thispoint) +{ + int i, n; + + for(i = 0; i < SAVER4_NUMWORMS; i++) { + for(n = 0; n < s->length; n++) { + if((i == thisworm) && (n == thispoint)) continue; + if((s->worms[i].points[n].x == x) && + (s->worms[i].points[n].y) == y) { + return 1; + } + } + } + return 0; +} + +void saver4_animate(nstate *state) +{ + int i, newx, newy, tail, newtip, tries; + s4state *s = state->priv; + + if(s->length == SAVER4_WORMLENGTH) tail = s->tip + 1; + else tail = 0; + if(tail == SAVER4_WORMLENGTH) tail = 0; + newtip = s->tip + 1; + if(newtip == SAVER4_WORMLENGTH) newtip = 0; + + for(i = 0; i < SAVER4_NUMWORMS; i++) { + if(!saver4_worm_collides(state, s, s->worms[i].points[tail].x, + s->worms[i].points[tail].y, i, tail)) { + GrSetGCForeground(state->main_gc, BLACK); + GrPoint(state->main_window, state->main_gc, + s->worms[i].points[tail].x, + s->worms[i].points[tail].y); + } + for(tries = SAVER4_COLLISION_RELUCTANCE; tries; tries--) { + saver4_get_new_worm_position(state, s, i, &newx, + &newy); + if(!saver4_worm_collides(state, s, newx, newy, -1, -1)) + break; + } + s->worms[i].points[newtip].x = newx; + s->worms[i].points[newtip].y = newy; + if(tries) { + GrSetGCForeground(state->main_gc, s->worms[i].colour); + GrPoint(state->main_window, state->main_gc, newx, newy); + } + } + + s->tip = newtip; + if(s->length < SAVER4_WORMLENGTH) s->length++; +} + +void saver5_init(nstate *state) +{ + int i; + + s5state *s = my_malloc(sizeof(s5state)); + state->priv = s; + + s->numstars = 0; + + for(i = 0; i < SAVER5_NUMSTARS; i++) { + s->stars[i].angle = RANDRANGE(0, (2 * M_PI)); + s->stars[i].pos = 1; + } + + state->animate_interval = SAVER5_DELAY; +} + +int saver5_drawstar(nstate *state, s5state *s, int star, int delete) +{ + int opp, adj; + GR_COORD x, y; + + if(delete) GrSetGCForeground(state->main_gc, BLACK); + else GrSetGCForeground(state->main_gc, WHITE); + + opp = (int)(sin(s->stars[star].angle) * s->stars[star].pos); + adj = (int)(cos(s->stars[star].angle) * s->stars[star].pos); + + x = (state->si.cols / 2) + adj; + y = (state->si.rows / 2) + opp; + + if((x < 0) || (y < 0) || (x >= state->si.cols) || (y >= state->si.rows)) + return 1; + + GrPoint(state->main_window, state->main_gc, x, y); + + return 0; +} + +void saver5_exposure(nstate *state) +{ + int i; + s5state *s = state->priv; + + GrClearWindow(state->main_window, 0); + + for(i = 0; i < SAVER5_NUMSTARS; i++) { + saver5_drawstar(state, s, i, 0); + } +} + +void saver5_animate(nstate *state) +{ + int i; + double position, scale, increment; + s5state *s = state->priv; + + if(s->numstars < SAVER5_NUMSTARS) { + s->numstars += SAVER5_STARS_INCREMENT; + if(s->numstars > SAVER5_NUMSTARS) + s->numstars = SAVER5_NUMSTARS; + } + + for(i = 0; i < s->numstars; i++) { + saver5_drawstar(state, s, i, 1); + position = (double)s->stars[i].pos / + (double)(state->si.cols / 2); + scale = sin((position * M_PI_2) + M_PI + M_PI_2) + 1.0; + increment = (scale * SAVER5_STARS_ACCEL_RATE) + 1; + s->stars[i].pos += (int) increment; + if(saver5_drawstar(state, s, i, 0)) { + s->stars[i].pos = 1; + s->stars[i].angle = RANDRANGE(0, (2 * M_PI)); + saver5_drawstar(state, s, i, 0); + } + } +} + +void saver6_init(nstate *state) +{ + int i, n; + + s6state *s = my_malloc(sizeof(s6state)); + state->priv = s; + + s->new_bolt_time = 0; + + for(i = 0; i < SAVER6_MAXBOLTS; i++) { + s->bolts[i].duration = 0; + for(n = 0; n < SAVER6_MAXFORKS; n++) { + s->bolts[i].forks[n].valid = 0; + } + } + + state->animate_interval = SAVER6_DELAY; +} + +void saver6_drawfork(nstate *state, s6state *s, int bolt, int fork, int delete) +{ + int i; + + if(delete) GrSetGCForeground(state->main_gc, BLACK); + for(i = 0; i < SAVER6_THICKNESS; i++) { + if(!delete) { + if((i < 2) || (i >= SAVER6_THICKNESS - 2)) + GrSetGCForeground(state->main_gc, LTBLUE); + else GrSetGCForeground(state->main_gc, WHITE); + } + GrPoly(state->main_window, state->main_gc, + s->bolts[bolt].forks[fork].valid, + s->bolts[bolt].forks[fork].vertices[i]); + } +} + +void saver6_drawbolt(nstate *state, s6state *s, int bolt, int delete) +{ + int n; + + for(n = 0; n < SAVER6_MAXFORKS; n++) + if(s->bolts[bolt].forks[n].valid) + saver6_drawfork(state, s, bolt, n, delete); +} + +void saver6_drawlightning(nstate *state, s6state *s, int delete) +{ + int i; + + for(i = 0; i < SAVER6_MAXBOLTS; i++) { + if(s->bolts[i].duration) { + if(delete) s->bolts[i].duration--; + saver6_drawbolt(state, s, i, delete); + } + } +} + +void saver6_exposure(nstate *state) +{ + s6state *s = state->priv; + + GrClearWindow(state->main_window, 0); + + saver6_drawlightning(state, s, 0); +} + +void saver6_setvertices(s6state *s, int bolt, int fork, int vert, GR_COORD x, + GR_COORD y) +{ + int i; + + for(i = 0; i < SAVER6_THICKNESS; i++) { + s->bolts[bolt].forks[fork].vertices[i][vert].x = x + i; + s->bolts[bolt].forks[fork].vertices[i][vert].y = y; + } +} + +void saver6_perturb(nstate *state, GR_COORD *x, GR_COORD *y, int maxperturb) +{ + *x += (int)RANDRANGE(0, (maxperturb - 1.0)) - + (double)(maxperturb / 2.0); + if(*x < 0) *x = 0; + if(*x > (state->si.cols - 1)) *x = state->si.cols - 1; + + *y += (int)RANDRANGE(0, (maxperturb - 1.0)) - + (double)(maxperturb / 2.0); + if(*y < 0) *y = 0; + if(*y > (state->si.cols - 1)) *y = state->si.cols - 1; +} + +void saver6_makefork(nstate *state, s6state *s, int bolt, int fork, GR_COORD x, + GR_COORD y) +{ + int i, vertices; + double length, incr, pos, angle, scale; + GR_COORD ex, ey, nx, ny, xlen, ylen; + + saver6_setvertices(s, bolt, fork, 0, x , y); + + scale = (double)(state->si.rows - y) / (double)state->si.rows; + + vertices = (int)(scale * RANDRANGE(SAVER6_MINFULLVERTICES, + SAVER6_MAXVERTICES)); + + if(vertices < SAVER6_MINVERTICES) vertices = SAVER6_MINVERTICES; + + s->bolts[bolt].forks[fork].valid = vertices; + + ey = state->si.rows - SAVER6_MAXEND_Y + + (int)RANDRANGE(0, SAVER6_MAXEND_Y - 1.0); + if((ey - y) <= 0) ey = SAVER6_MINDROP; + if(ey >= (state->si.rows - 1)) ey = state->si.rows - 1; + + if(!fork) { + ex = x + (int)RANDRANGE(0, ((state->si.cols - 1.0) / 2.0)); + } else { + ex = x + (int)(RANDRANGE(0, (ey - y)) / 2.0) - ((ey - y) / 2.0); + } + + if(ex >= state->si.cols) ex = state->si.cols - 1; + if(ex < 0) ex = 0; + + xlen = MAX(x, ex) - MIN(x, ex); + ylen = MAX(y, ey) - MIN(y, ey); + + length = sqrt(((double)(xlen * xlen) + (double)(ylen * ylen))); + incr = length / (vertices - 1); + angle = atan(((double)xlen / (double)ylen)); + + for(i = vertices - 1; i ; i--) { + pos = (incr * (i - 1)) + (RANDRANGE(0, SAVER6_MAXZIGZAG) - + ((double)SAVER6_MAXZIGZAG / 2.0)); + if(pos < 0) pos = 0; + if(pos > length) pos = length; + nx = x - (pos * sin(angle)); + ny = y + pos * cos(angle); + saver6_perturb(state, &nx, &ny, SAVER6_MAXZIGZAG); + saver6_setvertices(s, bolt, fork, i, nx , ny); + } +} + +int saver6_makeforks(nstate *state, s6state *s, int bolt, int fork, + int *vert, int *nextfork) +{ + int thisvert = 1, thisfork; + double prob; + + if(*vert == (s->bolts[bolt].forks[fork].valid - 1)) return 0; + if(*nextfork == SAVER6_MAXFORKS) return 0; + + prob = (double)SAVER6_FORK_PROBABILITY * ((double)*vert / + (double)s->bolts[bolt].forks[fork].valid) * + (1.0 / ((double)fork + 1.0)); + if(RANDRANGE(0, 1) < prob) { + thisfork = *nextfork; + saver6_makefork(state, s, bolt, thisfork, + s->bolts[bolt].forks[fork].vertices[0][*vert].x, + s->bolts[bolt].forks[fork].vertices[0][*vert].y); + *nextfork += 1; + while(saver6_makeforks(state, s, bolt, thisfork, &thisvert, + nextfork)); + } + + *vert += 1; + + return 1; +} + +void saver6_makebolt(nstate *state, s6state *s, int bolt) +{ + GR_COORD x; + int vert = 1, nextfork = 1, n; + + for(n = 0; n < SAVER6_MAXFORKS; n++) + s->bolts[bolt].forks[n].valid = 0; + + x = (int)RANDRANGE(0, (state->si.cols - 1.0)); + + saver6_makefork(state, s, bolt, 0, x, 0); + + while(saver6_makeforks(state, s, bolt, 0, &vert, &nextfork)); +} + +void saver6_newbolt(nstate *state, s6state *s) +{ + int i; + + for(i = 0; i < SAVER6_MAXBOLTS; i++) { + if(!s->bolts[i].duration) { + saver6_makebolt(state, s, i); + s->bolts[i].duration = RANDRANGE(SAVER6_MINDURATION, + SAVER6_MAXDURATION); + saver6_drawbolt(state, s, i, 0); + break; + } + } + + s->new_bolt_time = RANDRANGE(1, SAVER6_MAXNEWBOLTTIME); +} + +void saver6_perturb_bolt(nstate *state, s6state *s, int bolt, int fork) +{ + int m, o; + GR_COORD x, ox, y, oy; + + for(m = 1; m < s->bolts[bolt].forks[fork].valid; m++) { + ox = x = s->bolts[bolt].forks[fork].vertices[0][m].x; + oy = y = s->bolts[bolt].forks[fork].vertices[0][m].y; + saver6_perturb(state, &x, &y, SAVER6_MAXZIGZAG); + saver6_setvertices(s, bolt, fork, m, x, y); + for(o = fork + 1; o < SAVER6_MAXFORKS; o++) { + if((s->bolts[bolt].forks[o].vertices[0][0].x == ox) && + (s->bolts[bolt].forks[o].vertices[0][0].y + == oy)) { + saver6_setvertices(s, bolt, o, 0, x, y); + } + } + } +} + +void saver6_perturb_lightning(nstate *state, s6state *s) +{ + int i, n; + + for(i = 0; i < SAVER6_MAXBOLTS; i++) { + if(!s->bolts[i].duration) continue; + for(n = 0; n < SAVER6_MAXFORKS; n++) { + if(!s->bolts[i].forks[n].valid) continue; + saver6_perturb_bolt(state, s, i, n); + } + } +} + +void saver6_animate(nstate *state) +{ + s6state *s = state->priv; + + saver6_drawlightning(state, s, 1); + saver6_perturb_lightning(state, s); + saver6_drawlightning(state, s, 0); + + if(!s->new_bolt_time--) saver6_newbolt(state, s); +} + +/* The algorithm used in saver7 was adapted from "grav" by Greg Bowering */ + +void saver7_drawstar(nstate *state, s7state *s) +{ + GrSetGCForeground(state->main_gc, SAVER7_STARCOLOUR); + GrFillEllipse(state->main_window, state->main_gc, s->starx, s->stary, + SAVER7_STARRADIUS, SAVER7_STARRADIUS); +} + +void saver7_drawplanet(nstate *state, s7state *s, int planet, int erase) +{ + if(erase) GrSetGCForeground(state->main_gc, BLACK); + else GrSetGCForeground(state->main_gc, s->planets[planet].colour); + + if((s->planets[planet].ax < 0) || (s->planets[planet].ay < 0) || + (s->planets[planet].ax >= state->si.cols) || + (s->planets[planet].ay >= state->si.rows)) { + return; + } + + GrFillEllipse(state->main_window, state->main_gc, s->planets[planet].ax, + s->planets[planet].ay, + SAVER7_PLANETRADIUS, SAVER7_PLANETRADIUS); +} + +void saver7_calc_planet_position(nstate *state, s7state *s, int planet) +{ + if(s->planets[planet].r > -SAVER7_ALMOSTDIST) { + s->planets[planet].ax = (int)((double) state->si.cols * + (0.5 + (s->planets[planet].x / (s->planets[planet].r + + SAVER7_DIST)))); + s->planets[planet].ay = (int)((double) state->si.rows * + (0.5 + (s->planets[planet].y / (s->planets[planet].r + + SAVER7_DIST)))); + } else { + s->planets[planet].ax = -1; + s->planets[planet].ay = -1; + } +} + +void saver7_init(nstate *state) +{ + int i; + s7state *s = my_malloc(sizeof(s7state)); + state->priv = s; + + s->starx = state->si.cols / 2; + s->stary = state->si.rows / 2; + + for(i = 0; i < SAVER7_PLANETS; i++) { + s->planets[i].r = RANDRANGE(SAVER7_MIN_STARTDIM, + SAVER7_MAX_STARTDIM); + s->planets[i].x = RANDRANGE(SAVER7_MIN_STARTDIM, + SAVER7_MAX_STARTDIM); + s->planets[i].y = RANDRANGE(SAVER7_MIN_STARTDIM, + SAVER7_MAX_STARTDIM); + s->planets[i].rv = RANDRANGE(SAVER7_MIN_STARTVEL, + SAVER7_MAX_STARTVEL); + s->planets[i].xv = RANDRANGE(SAVER7_MIN_STARTVEL, + SAVER7_MAX_STARTVEL); + s->planets[i].yv = RANDRANGE(SAVER7_MIN_STARTVEL, + SAVER7_MAX_STARTVEL); + s->planets[i].colour = RANDRANGE(0, (state->si.ncolors - 1)); + saver7_calc_planet_position(state, s, i); + saver7_drawplanet(state, s, i, 0); + } + + saver7_drawstar(state, s); + + state->animate_interval = SAVER7_DELAY; +} + +void saver7_exposure(nstate *state) +{ + int i; + s7state *s = state->priv; + + GrClearWindow(state->main_window, 0); + + for(i = 0; i < SAVER7_PLANETS; i++) + saver7_drawplanet(state, s, i, 0); + + saver7_drawstar(state, s); +} + +void saver7_moveplanet(nstate *state, s7state *s, int planet) +{ + double dist; + double accel; + + dist = (s->planets[planet].x * s->planets[planet].x) + + (s->planets[planet].y * s->planets[planet].y) + + (s->planets[planet].r * s->planets[planet].r); + if(dist < SAVER7_COLLIDE) dist = SAVER7_COLLIDE; + dist = sqrt(dist); + dist = dist * dist * dist; + +#ifdef SAVER7_USE_DAMPING + accel = s->planets[planet].r * SAVER7_G / dist; + if(accel > SAVER7_MAX_ACCEL) accel = SAVER7_MAX_ACCEL; + else if(accel < -SAVER7_MAX_ACCEL) accel = -SAVER7_MAX_ACCEL; + s->planets[planet].rv = (s->planets[planet].rv + accel) * + SAVER7_DAMPING_FACTOR; + s->planets[planet].r += s->planets[planet].rv; + accel = s->planets[planet].x * SAVER7_G / dist; + if(accel > SAVER7_MAX_ACCEL) accel = SAVER7_MAX_ACCEL; + else if(accel < -SAVER7_MAX_ACCEL) accel = -SAVER7_MAX_ACCEL; + s->planets[planet].xv = (s->planets[planet].xv + accel) * + SAVER7_DAMPING_FACTOR; + s->planets[planet].x += s->planets[planet].xv; + accel = s->planets[planet].y * SAVER7_G / dist; + if(accel > SAVER7_MAX_ACCEL) accel = SAVER7_MAX_ACCEL; + else if(accel < -SAVER7_MAX_ACCEL) accel = -SAVER7_MAX_ACCEL; + s->planets[planet].yv = (s->planets[planet].yv + accel) * + SAVER7_DAMPING_FACTOR; + s->planets[planet].y += s->planets[planet].yv; +#else + accel = s->planets[planet].r * SAVER7_G / dist; + s->planets[planet].rv += accel; + s->planets[planet].r += s->planets[planet].rv; + accel = s->planets[planet].x * SAVER7_G / dist; + s->planets[planet].xv += accel; + s->planets[planet].x += s->planets[planet].xv; + accel = s->planets[planet].y * SAVER7_G / dist; + s->planets[planet].yv += accel; + s->planets[planet].y += s->planets[planet].yv; +#endif +} + +void saver7_animate(nstate *state) +{ + int i; + s7state *s = state->priv; + + for(i = 0; i < SAVER7_PLANETS; i++) { + saver7_moveplanet(state, s, i); + saver7_drawplanet(state, s, i, 1); + saver7_calc_planet_position(state, s, i); + saver7_drawplanet(state, s, i, 0); + } + saver7_drawstar(state, s); +} + +/* The algorithm used in saver8 is based on that found at: + http://www.go2net.com/internet/deep/1997/04/16/body.html */ + +void saver8_init(nstate *state) +{ + int red = 0, green = 0, blue = 0, step, i = 0; + + s8state *s = my_malloc(sizeof(s8state)); + state->priv = s; + + s->current_line = 0; + + step = 512 / SAVER8_NUMCOLOURS; + + for(green = 255; green > 0; green -= step, blue += step, i++) + s->colours[i] = GR_RGB(0, green, blue); + for(blue = 255; blue > 0; blue -= step, red += step, i++) + s->colours[i] = GR_RGB(red, 0, blue); + + state->animate_interval = SAVER8_DELAY; +} + +void saver8_drawpattern(nstate *state) +{ + int x, col, lines = SAVER8_LINES_PER_FRAME; + s8state *s = state->priv; + + if(!s->current_line) + s->factor = RANDRANGE(SAVER8_MINFACTOR, SAVER8_MAXFACTOR); + + while(s->current_line < state->si.rows) { + if(!--lines) return; + for(x = 0; x < state->si.cols; x++) { + col = ((((x * x) + (s->current_line * s->current_line)) + / s->factor) % SAVER8_NUMCOLOURS); + GrSetGCForeground(state->main_gc, s->colours[col]); + GrPoint(state->main_window, state->main_gc, x, + s->current_line); + } + s->current_line++; + } + s->current_line = 0; +} + +void saver8_exposure(nstate *state) +{ + s8state *s = state->priv; + + GrClearWindow(state->main_window, 0); + s->current_line = 0; + saver8_drawpattern(state); +} + +void saver8_animate(nstate *state) +{ + saver8_drawpattern(state); +} + +int init(nstate *state) +{ + GR_WM_PROPERTIES props; + GR_BITMAP cursor = 0; + + if(!GrOpen()) { + fprintf(stderr, "Couldn't connect to Nano-X server\n"); + return 3; + } + + GrGetScreenInfo(&state->si); + + state->main_window = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, + state->si.cols, state->si.rows, 0, BLACK, 0); + + GrSelectEvents(state->main_window, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_UP | + GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_MOUSE_MOTION | + GR_EVENT_MASK_KEY_UP | + GR_EVENT_MASK_KEY_DOWN | + GR_EVENT_MASK_FOCUS_OUT | + GR_EVENT_MASK_CLOSE_REQ); + + props.flags = GR_WM_FLAGS_PROPS; + props.props = GR_WM_PROPS_NOMOVE | GR_WM_PROPS_NODECORATE | + GR_WM_PROPS_NOAUTOMOVE | GR_WM_PROPS_NOAUTORESIZE; + GrSetWMProperties(state->main_window, &props); + + state->main_gc = GrNewGC(); + GrSetGCForeground(state->main_gc, WHITE); + GrSetGCBackground(state->main_gc, BLACK); + + state->animate_interval = 0; + + srand(time(0)); + + init_functions[state->saver](state); + + calculate_timeout(state); + + GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_SCREENSAVER); + + GrSetCursor(state->main_window, 1, 1, 1, 1, 0, 0, &cursor, &cursor); + + GrMapWindow(state->main_window); + + GrSetFocus(state->main_window); + + return 0; +} + +void calculate_timeout(nstate *state) +{ + struct timeval t; + long u; + + gettimeofday(&t, NULL); + u = t.tv_usec + (state->animate_interval * 1000); + state->timeout.tv_sec = t.tv_sec + (u / 1000000); + state->timeout.tv_usec = u % 1000000; +} + +unsigned long timeout_delay(nstate *state) +{ + struct timeval t; + signed long s, m, ret; + + gettimeofday(&t, NULL); + + if(!state->animate_interval) return 0; + + if((t.tv_sec > state->timeout.tv_sec) || + ((t.tv_sec == state->timeout.tv_sec) && + t.tv_usec >= state->timeout.tv_usec)) return 1; + + s = state->timeout.tv_sec - t.tv_sec; + m = ((state->timeout.tv_usec - t.tv_usec) / 1000); + ret = (unsigned long)((1000 * s) + m); + + if(ret <= 0) return 1; + else return ret; +} + +void do_animate(nstate *state) +{ + struct timeval t; + + if(!state->animate_interval) return; + + gettimeofday(&t, NULL); + + if((t.tv_sec > state->timeout.tv_sec) || + ((t.tv_sec == state->timeout.tv_sec) && + (t.tv_usec >= state->timeout.tv_usec))) { + animate_functions[state->saver](state); + calculate_timeout(state); + } +} + +int do_screensaver_event(nstate *state) +{ + GR_EVENT_SCREENSAVER *event = &state->event.screensaver; + + if(event->activate != GR_FALSE) { + fprintf(stderr, "Got a non-deactivate screensaver event\n"); + return 0; + } + + return 1; +} + +int handle_event(nstate *state) +{ + switch(state->event.type) { + case GR_EVENT_TYPE_EXPOSURE: + exposure_functions[state->saver](state); + case GR_EVENT_TYPE_TIMEOUT: + case GR_EVENT_TYPE_NONE: + break; + case GR_EVENT_TYPE_SCREENSAVER: + if(do_screensaver_event(state)) return 0; + break; + case GR_EVENT_TYPE_CLOSE_REQ: + case GR_EVENT_MASK_BUTTON_UP: + case GR_EVENT_MASK_BUTTON_DOWN: + case GR_EVENT_MASK_MOUSE_MOTION: + case GR_EVENT_MASK_KEY_UP: + case GR_EVENT_MASK_KEY_DOWN: + case GR_EVENT_MASK_FOCUS_OUT: + return 0; + default: + fprintf(stderr, "Got unknown event type %d\n", + state->event.type); + break; + } + do_animate(state); + return(1); +} + +int main(int argc, char *argv[]) +{ + int ret; + nstate *state = my_malloc(sizeof(nstate)); + + if(argc == 2) { + state->saver = atoi(argv[1]) - 1; + if((state->saver) < 0 || (state->saver >= NUM_SAVERS)) { + fprintf(stderr, "Invalid saver number \"%s\"\n", + argv[1]); + return 2; + } + } else state->saver = 0; + + if((ret = init(state))) return ret; + + do { + GrGetNextEventTimeout(&state->event, timeout_delay(state)); + } while(handle_event(state)); + + GrClose(); + + return 0; +} Index: landmine.syms =================================================================== --- landmine.syms (nonexistent) +++ landmine.syms (revision 174) @@ -0,0 +1 @@ +landmine_main Index: setselection.c =================================================================== --- setselection.c (nonexistent) +++ setselection.c (revision 174) @@ -0,0 +1,84 @@ +#include +#include +#include + +#include "nano-X.h" + +int main(int argc, char *argv[]) +{ + GR_WINDOW_ID wid; + GR_EVENT event; + FILE *fp; + char *buf = NULL; + int buf_size = 0; + int data_len = 0; + int ret = 0; + GR_EVENT_CLIENT_DATA_REQ *req; + GR_EVENT_SELECTION_CHANGED *sc; + + if(argc != 2) { + fprintf(stderr, "Usage: setselection \n"); + return 1; + } + + if(!(fp = fopen(argv[1], "r"))) { + fprintf(stderr, "Couldn't open text file\n"); + return 2; + } + + do { + data_len += ret; + buf_size = data_len + 65536; + if(!(buf = realloc(buf, buf_size))) { + fprintf(stderr, "Out of memory\n"); + return 3; + } + } while((ret = fread(buf + data_len, 1, 65536, fp)) > 0); + if(ret < 0) { + fprintf(stderr, "Failed to read text file sucessfully\n"); + return 2; + } + + if(GrOpen() < 0) { + fprintf(stderr, "Couldn't connect to Nano-X server\n"); + return 4; + } + + wid = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, 1, 1, 0, 0, 0); + if(!wid) { + fprintf(stderr, "Couldn't get a window\n"); + return 5; + } + + GrSelectEvents(wid, GR_EVENT_MASK_CLIENT_DATA_REQ | + GR_EVENT_MASK_SELECTION_CHANGED); + + GrSetSelectionOwner(wid, "nota/realtype text/plain non/existant " + "something/else"); + + while(1) { + GrGetNextEvent(&event); + switch(event.type) { + case GR_EVENT_TYPE_CLIENT_DATA_REQ: + req = &event.clientdatareq; + fprintf(stderr, "Got request with serial " + "number %ld from window %d for mime " + "type %d\n", req->serial, req->rid, + req->mimetype); + GrSendClientData(wid, req->rid, req->serial, + data_len, data_len, buf); + break; + case GR_EVENT_TYPE_SELECTION_CHANGED: + sc = &event.selectionchanged; + if(sc->new_owner != wid) { + fprintf(stderr, "Lost selection to " + "window %d\n", sc->new_owner); + return 0; + } + default: + break; + } + } + + return 0; +} Index: nxclock.c =================================================================== --- nxclock.c (nonexistent) +++ nxclock.c (revision 174) @@ -0,0 +1,260 @@ +/* + * nxclock - Nano-X clock program + * + * Copyright (C) 2000 by Greg Haerr + * Copyright (C) 1999 Alistair Riddoch + */ + +#include +#include +#include +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" + +/* If you need a clock bigger than 200x200 you will need to re-write the trig * + * to use longs. (Only applies under ELKS I think. */ +#define CWIDTH 100 /* Max 200 */ +#define CHEIGHT 100 /* Max 200 */ + +/* + * Definitions to make it easy to define cursors + */ +#define _ ((unsigned) 0) /* off bits */ +#define X ((unsigned) 1) /* on bits */ +#define MASK(a,b,c,d,e,f,g) \ + (((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) \ + + e) * 2) + f) * 2) + g) << 9) + +static GR_WINDOW_ID w1; /* id for window */ +static GR_GC_ID gc1; /* graphics context for text */ +static GR_GC_ID gc2; /* graphics context for rectangle */ +static int lh = -1, lm = -1, ls = -1; +static time_t then; + +static unsigned char trig[91] = + { 0, 4, 8, 13, 17, 22, 26, 31, 35, 40, 44, 48, 53, 57, 61, 66, + 70, 74, 79, 83, 87, 91, 95, 100, 104, 108, 112, 116, 120, 124, 128, + 131, 135, 139, 143, 146, 150, 154, 157, 161, 164, 167, 171, 174, 177, + 181, 184, 187, 190, 193, 196, 198, 201, 204, 207, 209, 212, 214, 217, + 219, 221, 223, 226, 228, 230, 232, 233, 235, 237, 238, 240, 242, 243, + 244, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 254, 255, 255, + 255, 255, 255, 255}; + +void do_exposure(); +void do_clock(); +void do_idle(); +void errorcatcher(); /* routine to handle errors */ + +int +main(int ac, char **av) +{ + GR_EVENT event; /* current event */ + GR_BITMAP bitmap1fg[7]; /* bitmaps for first cursor */ + GR_BITMAP bitmap1bg[7]; + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + /* create window*/ + w1 = GrNewWindowEx( + GR_WM_PROPS_NOAUTOMOVE|GR_WM_PROPS_BORDER|GR_WM_PROPS_CAPTION| + GR_WM_PROPS_CLOSEBOX, "nxclock", GR_ROOT_WINDOW_ID, + 10, 10, CWIDTH, CHEIGHT, GrGetSysColor(GR_COLOR_WINDOW)); + + GrSelectEvents(w1, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_CLOSE_REQ); + + gc1 = GrNewGC(); + gc2 = GrNewGC(); + + GrSetGCForeground(gc1, GrGetSysColor(GR_COLOR_WINDOW)); + GrSetGCBackground(gc1, GrGetSysColor(GR_COLOR_WINDOWTEXT)); + GrSetGCForeground(gc2, GrGetSysColor(GR_COLOR_WINDOWTEXT)); + GrSetGCBackground(gc2, GrGetSysColor(GR_COLOR_WINDOW)); + + bitmap1bg[0] = MASK(_,_,X,X,X,_,_); + bitmap1bg[1] = MASK(_,X,X,X,X,X,_); + bitmap1bg[2] = MASK(X,X,X,X,X,X,X); + bitmap1bg[3] = MASK(X,X,X,X,X,X,X); + bitmap1bg[4] = MASK(X,X,X,X,X,X,X); + bitmap1bg[5] = MASK(_,X,X,X,X,X,_); + bitmap1bg[6] = MASK(_,_,X,X,X,_,_); + + bitmap1fg[0] = MASK(_,_,_,X,_,_,_); + bitmap1fg[1] = MASK(_,X,_,X,_,X,_); + bitmap1fg[2] = MASK(_,_,_,X,_,_,_); + bitmap1fg[3] = MASK(X,_,_,X,X,_,X); + bitmap1fg[4] = MASK(_,_,_,_,_,_,_); + bitmap1fg[5] = MASK(_,X,_,_,_,X,_); + bitmap1fg[6] = MASK(_,_,_,X,_,_,_); + + GrSetCursor(w1, 7, 7, 3, 3, WHITE, BLACK, bitmap1fg, bitmap1bg); + GrMapWindow(w1); + + while (1) { + GrGetNextEventTimeout(&event, 500L); + + switch (event.type) { + case GR_EVENT_TYPE_EXPOSURE: + do_exposure(&event.exposure); + break; + + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + + case GR_EVENT_TYPE_TIMEOUT: + do_clock(); + break; + } + } +} + +int bsin(int angle) +{ + if(angle < 91) { + return trig[angle]; + } else if (angle < 181) { + return trig[180 - angle]; + } else if (angle < 271) { + return -trig[angle - 180]; + } else if (angle < 361) { + return -trig[360 - angle]; + } else { + return 0; + } +} + +int bcos(int angle) +{ + if(angle < 91) { + return trig[90 - angle]; + } else if (angle < 181) { + return -trig[angle - 90]; + } else if (angle < 271) { + return -trig[270 - angle]; + } else if (angle < 361) { + return trig[angle - 270]; + } else { + return 0; + } +} + +/* + * Here when an exposure event occurs. + */ +void +do_exposure(ep) + GR_EVENT_EXPOSURE *ep; +{ + GR_COORD midx = CWIDTH / 2; + GR_COORD midy = CHEIGHT / 2; + int i, l; + +/* GrFillRect(w1, gc2, 0, 0, CWIDTH, CHEIGHT); */ +/* GrFillEllipse(w1, gc1, midx, midy, midx, midy); */ + GrEllipse(w1, gc2, midx, midy, midx - 1, midy - 1); + for(i = 0; i < 60; i++) { + if (i%5 == 0) { + l = 5; + } else { + l = 0; + } + GrLine(w1, gc2, + midx + (((midx - 3) * bsin(i * 6)) >> 8), + midy + (((midy - 3) * bcos(i * 6)) >> 8), + midx + (((midx - 3 - l) * bsin(i * 6)) >> 8), + midy + (((midy - 3 - l) * bcos(i * 6)) >> 8)); + } + + lh = -1; lm = -1; ls = -1; + then = 0; + do_clock(); +} + +void draw_time(int hour, int minutes, int sec, GR_GC_ID gc ) +{ + GR_COORD midx = CWIDTH / 2; + GR_COORD midy = CHEIGHT / 2; + + GrLine(w1, gc1, + midx + (((midx - 8 - midx / 10) * bsin(ls)) >> 8), + midy - (((midy - 8 - midy / 10) * bcos(ls)) >> 8), + midx + (((midx - 8 - midx / 4) * bsin(ls)) >> 8), + midy - (((midy - 8 - midx / 4) * bcos(ls)) >> 8)); + GrLine(w1, gc2, + midx + (((midx - 8 - midx / 10) * bsin(sec)) >> 8), + midy - (((midy - 8 - midy / 10) * bcos(sec)) >> 8), + midx + (((midx - 8 - midx / 4) * bsin(sec)) >> 8), + midy - (((midy - 8 - midx / 4) * bcos(sec)) >> 8)); + if ((lm != minutes) || (ls == minutes)) { + GrLine(w1, gc1, + midx + (((midx - 8 - midx / 10) * bsin(lm)) >> 8), + midy - (((midy - 8 - midy / 10) * bcos(lm)) >> 8), + midx + (((midx / 5) * bsin(lm)) >> 8), + midy - (((midy / 5) * bcos(lm)) >> 8)); + GrLine(w1, gc2, + midx + (((midx - 8 - midx / 10) * bsin(minutes)) >> 8), + midy - (((midy - 8 - midy / 10) * bcos(minutes)) >> 8), + midx + (((midx / 5) * bsin(minutes)) >> 8), + midy - (((midy / 5) * bcos(minutes)) >> 8)); + GrLine(w1, gc1, + midx + (((midx - 8 - midx / 2) * bsin(lh)) >> 8), + midy - (((midy - 8 - midy / 2) * bcos(lh)) >> 8), + midx + (((midx / 5) * bsin(lh)) >> 8), + midy - (((midy / 5) * bcos(lh)) >> 8)); + GrLine(w1, gc2, + midx + (((midx - 8 - midx / 2) * bsin(hour)) >> 8), + midy - (((midy - 8 - midy / 2) * bcos(hour)) >> 8), + midx + (((midx / 5) * bsin(hour)) >> 8), + midy - (((midy / 5) * bcos(hour)) >> 8)); + } + lh = hour; + lm = minutes; + ls = sec; +} + +/* + * Update the clock if the seconds have changed. + */ +void +do_clock() +{ + struct timeval tv; + struct timezone tz; + struct tm * tp; + time_t now; + int minutes, hour, sec; + + gettimeofday(&tv, &tz); + now = tv.tv_sec - (60 * tz.tz_minuteswest); + if (now == then) { + return; + } + then = now; + tp = gmtime(&now); + minutes = tp->tm_min * 6; + sec = tp->tm_sec * 6; + hour = tp->tm_hour; + if (hour > 12) { + hour -= 12; + } + hour = hour*30 + minutes/12; + draw_time(hour, minutes, sec, gc2); +} + +#if 0 +/* + * Sleep a while to avoid using too much CPU time. + */ +void do_idle() +{ + struct timespec idletime; + idletime.tv_sec = 0; + idletime.tv_nsec = 100000; + nanosleep(&idletime, NULL); +} +#endif Index: README.world =================================================================== --- README.world (nonexistent) +++ README.world (revision 174) @@ -0,0 +1,64 @@ + WORLD + +This is a program that uses mini-X graphics in MINIX to display a map of +the world. The database for this map is supplied, and is an edited version +of the CIA database. The continents, islands, rivers, lakes, countries, +and the states of the USA are shown. I have slightly edited the database +to fix some arctic islands and remove the Berlin corridor. But some country +boundaries are obsolete, since this map is a few years old at least. + +This program only uses integer arithmetic. Floating point is simulated +using fixed point arithmetic. For this reason, the projection used in +the program is rather crude (latitude and longitude are linear and are +parallel lines). This means that there is much distortion for the lands +which are near the North and South poles. If floating point was avaiable, +a good projection could be used instead (such as a true spherical view!). + +The file "world.map" is the database, and should be installed in "/usr/lib". +Otherwise you need to edit world.c and change MAPFILE as desired. + +To build the program (assuming mini-X is installed), use the command: + + cc -o world world.c -lgraph + +When the program starts, it draws the whole world. After this is done, +you can use two of the mouse buttons and the keys to manipulate the view. + +To zoom in on a section of the map, move the mouse to the location that +you intend to zoom in on, and press the left mouse button. Then when you +drag the mouse, a rectangle (the zoom box) will be drawn to indicate the +current area that you are zooming into. Notice that the point that you +start the zoom box on will be the center of the zoom box, NOT one of its +corners. + +While keeping the mouse button pressed, you can use the 's' and 'm' keys +to switch between the 'scaling' and the 'moving' modes of the rectangle. +The scaling mode makes the size of the zoom box vary as you move the mouse, +but keeps the center of the zoom box fixed. The moving mode keeps the size +of the zoom box the same, but moves the box around as you move the mouse. +Note that the width and height of the zoom box change together to preserve +the aspect ratio of the zoom area. + +If you have started to do a zoom, but change your mind, then you can type +the escape key before letting up on the mouse button, and this will cancel +the zoom operation. If you really want to do a zoom, then simply let up +on the mouse button and the selected area will be redrawn to fit the screen. +At this point you can zoom in further if you wish. + +You can return to the top level map by typing 't'. Then you can zoom in +again on a different area of the map. Alternatively, you can "zoom out" +just a little by creating a zoom box larger than the screen size. This can +be done, for example, by starting a zoom near the top of the screen, and then +dragging the mouse down to the bottom of the screen. Repeating this process +lets you slowly reduce the magnification. + +If you press the right mouse button, the display will show the longitude +and latitude of the location on the map covered by the cursor. You can then +drag the mouse around with the button held down, and the coordinates will +continuously track the cursor location. Letting up on the mouse button +removes the coordinate display. + +Typing 'q' will quit from the world program. + +Enjoy! +David I. Bell Index: ntetris.ppm =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ntetris.ppm =================================================================== --- ntetris.ppm (nonexistent) +++ ntetris.ppm (revision 174)
ntetris.ppm Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: nsaver.h =================================================================== --- nsaver.h (nonexistent) +++ nsaver.h (revision 174) @@ -0,0 +1,273 @@ +#ifndef NSAVER_H +#define NSAVER_H +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is NanoScreenSaver. + * + * The Initial Developer of the Original Code is Alex Holden. + * Portions created by Alex Holden are Copyright (C) 2000 + * Alex Holden . All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public license (the "[GNU] License"), in which case the + * provisions of [GNU] License are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the [GNU] License and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the [GNU] License. If you do not delete + * the provisions above, a recipient may use your version of this file + * under either the MPL or the [GNU] License. + */ + +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#define RANDRANGE(LO, HI) ((LO) + ((double)((HI) - (LO)) * rand() \ + / (RAND_MAX + 1.0))) + +typedef struct { + GR_WINDOW_ID main_window; + GR_GC_ID main_gc; + GR_EVENT event; + long animate_interval; + struct timeval timeout; + int saver; + void *priv; + GR_SCREEN_INFO si; +} nstate; + +void *my_malloc(size_t size); +void get_random_point_on_screen(nstate *state, GR_COORD *x, GR_COORD *y, + GR_COLOR *c); +int init(nstate *state); +void calculate_timeout(nstate *state); +unsigned long timeout_delay(nstate *state); +unsigned long timeout_delay(nstate *state); +void do_animate(nstate *state); +int do_screensaver_event(nstate *state); +int handle_event(nstate *state); + +#define NUM_SAVERS 8 + +void saver1_init(nstate *state); +void saver1_exposure(nstate *state); +void saver1_animate(nstate *state); + +#define SAVER2_DELAY 1 +#define SAVER2_MAXPIXELS 65535 +#define SAVER2_PIXELS_PER_FRAME 16 + +void saver2_init(nstate *state); +void saver2_exposure(nstate *state); +void saver2_animate(nstate *state); + +#define SAVER3_DELAY 1 +#define SAVER3_MAXSEGMENTS 65535 +#define SAVER3_SEGMENTS_PER_FRAME 4 + +typedef struct { + int maxsegments; + GR_COORD lastx; + GR_COORD lasty; +} s3state; + +void saver3_init(nstate *state); +void saver3_exposure(nstate *state); +void saver3_animate(nstate *state); + +#define SAVER4_DELAY 4 +#define SAVER4_NUMWORMS 10 +#define SAVER4_WORMLENGTH 100 +#define SAVER4_COLLISION_RELUCTANCE 20 + +typedef struct { + GR_COLOR colour; + GR_POINT points[SAVER4_WORMLENGTH]; +} s4worm; + +typedef struct { + int length; + int tip; + s4worm worms[SAVER4_NUMWORMS]; +} s4state; + +void saver4_init(nstate *state); +void saver4_exposure(nstate *state); +void saver4_get_new_worm_position(nstate *state, s4state *s, int worm, + GR_COORD *newx, GR_COORD *newy); +int saver4_worm_collides(nstate *state, s4state *s, int x, int y, int thisworm, + int thispoint); +void saver4_animate(nstate *state); + +#define SAVER5_DELAY 1 +#define SAVER5_NUMSTARS 300 +#define SAVER5_STARS_INCREMENT 2 +#define SAVER5_STARS_ACCEL_RATE 30 + +typedef struct { + double angle; + int pos; +} s5star; + +typedef struct { + int numstars; + s5star stars[SAVER5_NUMSTARS]; +} s5state; + +void saver5_init(nstate *state); +int saver5_drawstar(nstate *state, s5state *s, int star, int delete); +void saver5_exposure(nstate *state); +void saver5_animate(nstate *state); + +#define SAVER6_DELAY 5 +#define SAVER6_MAXVERTICES 20 +#define SAVER6_MINFULLVERTICES 5 +#define SAVER6_MINVERTICES 3 +#define SAVER6_MINDROP 10 +#define SAVER6_MAXBOLTS 4 +#define SAVER6_MAXFORKS 20 +#define SAVER6_MAXEND_Y 50 +#define SAVER6_THICKNESS 6 +#define SAVER6_MINDURATION 10 +#define SAVER6_MAXDURATION 20 +#define SAVER6_MAXNEWBOLTTIME 300 +#define SAVER6_MAXZIGZAG 10 +#define SAVER6_MAXPERTURBATION 5 +#define SAVER6_FORK_PROBABILITY 0.5 + +typedef struct { + int valid; + GR_POINT vertices[SAVER6_THICKNESS][SAVER6_MAXVERTICES]; +} s6fork; + +typedef struct { + int duration; + s6fork forks[SAVER6_MAXFORKS]; +} s6bolt; + +typedef struct { + int new_bolt_time; + s6bolt bolts[SAVER6_MAXBOLTS]; +} s6state; + +void saver6_init(nstate *state); +void saver6_drawfork(nstate *state, s6state *s, int bolt, int fork, int delete); +void saver6_drawbolt(nstate *state, s6state *s, int bolt, int delete); +void saver6_drawlightning(nstate *state, s6state *s, int delete); +void saver6_exposure(nstate *state); +void saver6_setvertices(s6state *s, int bolt, int fork, int vert, GR_COORD x, + GR_COORD y); +void saver6_makefork(nstate *state, s6state *s, int bolt, int fork, GR_COORD x, + GR_COORD y); +void saver6_perturb(nstate *state, GR_COORD *x, GR_COORD *y, int maxperturb); +void saver6_makebolt(nstate *state, s6state *s, int bolt); +void saver6_newbolt(nstate *state, s6state *s); +void saver6_perturb_bolt(nstate *state, s6state *s, int bolt, int fork); +void saver6_perturb_lightning(nstate *state, s6state *s); +void saver6_animate(nstate *state); + +/* The algorithm used in saver7 was adapted from "grav" by Greg Bowering */ + +#define SAVER7_DELAY 2 +#define SAVER7_PLANETS 15 +#define SAVER7_PLANETS_USE_DAMPING +#define SAVER7_STARCOLOUR YELLOW +#define SAVER7_STARRADIUS 5 +#define SAVER7_PLANETRADIUS 3 +#define SAVER7_DIST 16.0 +#define SAVER7_ALMOSTDIST (SAVER7_DIST - 0.01) +#define SAVER7_MAX_STARTDIM (SAVER7_ALMOSTDIST / 2.0) +#define SAVER7_MIN_STARTDIM -SAVER7_MAX_STARTDIM +#define SAVER7_MAX_STARTVEL 0.04 +#define SAVER7_MIN_STARTVEL -SAVER7_MAX_STARTVEL +#define SAVER7_G -0.02 +#define SAVER7_COLLIDE 0.0001 +#define SAVER7_DAMPING_FACTOR 0.999999 +#define SAVER7_MAX_ACCEL 0.1 + +typedef struct { + double r; + double rv; + double x; + double xv; + double y; + double yv; + GR_COORD ax; + GR_COORD ay; + GR_COLOR colour; +} s7planet; + +typedef struct { + s7planet planets[SAVER7_PLANETS]; + GR_COORD starx; + GR_COORD stary; +} s7state; + +void saver7_init(nstate *state); +void saver7_exposure(nstate *state); +void saver7_animate(nstate *state); + +/* The algorithm used in saver8 is based on that found at: + http://www.go2net.com/internet/deep/1997/04/16/body.html */ + +#define SAVER8_DELAY 1 +#define SAVER8_NUMCOLOURS 64 /* Don't set this higher than 512! */ +#define SAVER8_MINFACTOR 1 +#define SAVER8_MAXFACTOR 20 +#define SAVER8_LINES_PER_FRAME 5 + +typedef struct { + GR_COLOR colours[SAVER8_NUMCOLOURS]; + int current_line; + int factor; +} s8state; + +void saver8_init(nstate *state); +void saver8_drawpattern(nstate *state); +void saver8_exposure(nstate *state); +void saver8_animate(nstate *state); + +typedef void(*saver_function)(nstate *); + +saver_function init_functions[NUM_SAVERS] = { + saver1_init, + saver2_init, + saver3_init, + saver4_init, + saver5_init, + saver6_init, + saver7_init, + saver8_init +}; +saver_function exposure_functions[NUM_SAVERS] = { + saver1_exposure, + saver2_exposure, + saver3_exposure, + saver4_exposure, + saver5_exposure, + saver6_exposure, + saver7_exposure, + saver8_exposure +}; +saver_function animate_functions[NUM_SAVERS] = { + saver1_animate, + saver2_animate, + saver3_animate, + saver4_animate, + saver5_animate, + saver6_animate, + saver7_animate, + saver8_animate +}; +#endif Index: move.c =================================================================== --- move.c (nonexistent) +++ move.c (revision 174) @@ -0,0 +1,107 @@ +#include +#define MWINCLUDECOLORS +#include "nano-X.h" +/* + * Demo to test child window movement and redrawing + */ +int +main(int ac,char **av) +{ + GR_COORD offset_x = 0, offset_y = 0; + GR_WINDOW_ID window1, subwindow1, subsubwin1; + GR_WINDOW_ID window2, subwindow2; + /*GR_WINDOW_ID subsubwin2;*/ + GR_EVENT event; + + fprintf(stderr,"This is a demo program.\n"); + fprintf(stderr,"Left-button drags window\n"); + fprintf(stderr,"Right-button raises window\n"); + + GrOpen(); + window1 = GrNewWindow(GR_ROOT_WINDOW_ID, 20, 20, 100, 60, 4, BLACK, BLUE); + subwindow1 = GrNewWindow(window1, 5, 5, 90, 50, 4, WHITE, RED); + subsubwin1 = GrNewWindow(subwindow1, 10, 10, 10, 10, 2, GREEN, BLUE); + + window2 = GrNewWindow(GR_ROOT_WINDOW_ID, 20, 100, 100, 60, 4, BLACK, BLUE); + subwindow2 = GrNewWindow(window2, 5, 5, 90, 50, 4, WHITE, RED); +/* subsubwin2 = GrNewWindow(subwindow2, 10, 10, 10, 10, 2, GREEN, BLUE); */ + + GrSelectEvents(window1, + GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_BUTTON_UP | + GR_EVENT_MASK_MOUSE_ENTER | + GR_EVENT_MASK_MOUSE_EXIT | + GR_EVENT_MASK_MOUSE_MOTION | + GR_EVENT_MASK_CLOSE_REQ); + + GrSelectEvents(window2, + GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_BUTTON_UP | + GR_EVENT_MASK_MOUSE_ENTER | + GR_EVENT_MASK_MOUSE_EXIT | + GR_EVENT_MASK_MOUSE_MOTION | + GR_EVENT_MASK_CLOSE_REQ); + + GrSelectEvents(subsubwin1, + GR_EVENT_MASK_BUTTON_DOWN | + 0); + + GrMapWindow(subsubwin1); + GrMapWindow(subwindow1); + GrMapWindow(window1); + + /*GrMapWindow(subsubwin2);*/ + GrMapWindow(subwindow2); + GrMapWindow(window2); + + while(1) { + GrGetNextEvent(&event); + + switch (event.type) { + case GR_EVENT_TYPE_NONE: + break; + case GR_EVENT_TYPE_BUTTON_DOWN: + offset_x = event.button.x; + offset_y = event.button.y; + + if (event.button.changebuttons & GR_BUTTON_R) { + GrRaiseWindow(event.button.wid); + } + if (event.button.wid == subsubwin1) { + GR_WINDOW_INFO winfo; + GrGetWindowInfo(subsubwin1, &winfo); + if (winfo.parent == subwindow1) { + GrReparentWindow(subsubwin1, subwindow2, 10, 10); + } else { + GrReparentWindow(subsubwin1, subwindow1, 10, 10); + } + } + case GR_EVENT_TYPE_MOUSE_MOTION: + if (event.mouse.buttons == GR_BUTTON_L && + (event.mouse.wid == window1 || event.mouse.wid == window2)) { + GrMoveWindow(event.mouse.wid, + event.mouse.rootx - offset_x, + event.mouse.rooty - offset_y); + } + if (event.mouse.buttons == GR_BUTTON_R) { + GrResizeWindow(event.mouse.wid, + event.mouse.x + 1, + event.mouse.y + 1); + } + break; + case GR_EVENT_TYPE_EXPOSURE: + /*GrFillRect(event.exposure.wid, defgc, + event.exposure.x, event.exposure.y, + event.exposure.width, event.exposure.height);*/ + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + default: + fprintf(stderr, "%d\n", event.type); + } + } + GrClose(); +} Index: demo2.c =================================================================== --- demo2.c (nonexistent) +++ demo2.c (revision 174) @@ -0,0 +1,92 @@ +#define MWINCLUDECOLORS +#include +#include "nano-X.h" + +#include + +int +main(int ac,char **av) +{ + GR_WINDOW_ID w, w2; + GR_GC_ID gc; + GR_EVENT event; + GR_WM_PROPERTIES props; + + if (GrOpen() < 0) { + printf("Can't open graphics\n"); + exit(1); + } + + /* pass errors through main loop*/ + GrSetErrorHandler(NULL); + +#define WIDTH 320 +#define HEIGHT 240 + w = GrNewWindow(GR_ROOT_WINDOW_ID, 20, 20, WIDTH, HEIGHT, + 0, GREEN, BLACK); + + w2 = GrNewWindow(w, 20, 20, 40, 40, 0, WHITE, BLACK); + + props.flags = GR_WM_FLAGS_PROPS | GR_WM_FLAGS_TITLE; + props.props = GR_WM_PROPS_NOBACKGROUND; + props.title = "Nano-X Demo2"; + GrSetWMProperties(w, &props); + + gc = GrNewGC(); + + GrSelectEvents(w, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_CLOSE_REQ + | GR_EVENT_MASK_BUTTON_DOWN + | GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_KEY_UP); + GrMapWindow(w); + GrSetFocus(w); + /* serious bug here: when wm running, w2 is mapped anyway!!*/ + /*GrMapWindow(w2);*/ + + for (;;) { + /*GR_EVENT_KEYSTROKE *kev;*/ + + GrGetNextEvent(&event); + switch (event.type) { + case GR_EVENT_TYPE_EXPOSURE: + GrSetGCForeground(gc,GrGetSysColor(GR_COLOR_APPWINDOW)); + GrFillRect(w, gc, event.exposure.x, event.exposure.y, + event.exposure.width, event.exposure.height); + GrSetGCForeground(gc, GrGetSysColor(GR_COLOR_APPTEXT)); + GrSetGCUseBackground(gc, GR_FALSE); + GrText(w, gc, 10, 30, "Hello World", -1, GR_TFASCII); +GrRect(w, gc, 5, 5, 300, 60); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + break; + case GR_EVENT_TYPE_ERROR: + printf("\7demo2: Error (%s) ", event.error.name); + printf(nxErrorStrings[event.error.code],event.error.id); + break; +#if 0 + case GR_EVENT_TYPE_BUTTON_DOWN: + /* test server error on bad syscall*/ + GrMapWindow(w2); + GrMoveWindow(GR_ROOT_WINDOW_ID, 0, 0); + { GR_SCREEN_INFO sinfo; GrGetScreenInfo(&sinfo); } + break; +#endif +#if 0 + case GR_EVENT_TYPE_KEY_DOWN: + kev = (GR_EVENT_KEYSTROKE *)&event; + printf("DOWN %d (%04x) %04x\n", + kev->ch, kev->ch, kev->modifiers); + break; + case GR_EVENT_TYPE_KEY_UP: + kev = (GR_EVENT_KEYSTROKE *)&event; + printf("UP %d (%04x) %04x\n", + kev->ch, kev->ch, kev->modifiers); + break; +#endif + } + } + + GrClose(); + return 0; +} Index: logfont.c =================================================================== --- logfont.c (nonexistent) +++ logfont.c (revision 174) @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#if UNIX +#include +#endif +#define MWINCLUDECOLORS +#include "nano-X.h" +/* + * logical font demo for Nano-X + */ + +#define MAXW 630 +#define MAXH 470 + +int main(int argc, char **argv) +{ + GR_WINDOW_ID window; + GR_EVENT event; + GR_GC_ID gc; + GR_FONT_ID fontid; + int x, y, rnd = 0; + MWLOGFONT lf; + char description[128]; + + srand(time(0)); + + GrOpen(); + window = GrNewWindow(GR_ROOT_WINDOW_ID, 5, 5, MAXW, MAXH, 4, BLACK, BLUE); + GrMapWindow(window); + + gc = GrNewGC(); + + GrSelectEvents(window,GR_EVENT_MASK_ALL); + GrSetGCUseBackground(gc,GR_FALSE); + GrSetGCBackground(gc, GR_RGB(0, 0, 0)); + + y = 30; + x = 0; + + while(1) { + GrCheckNextEvent(&event); + + if(event.type == GR_EVENT_TYPE_CLOSE_REQ) { + GrClose(); + exit(0); + } + + /*sleep(1);*/ + + MWLF_Clear(&lf); + description[0] = '\0'; + /*lf.lfSerif = 1;*/ + + if ( rnd & 1 ) { + lf.lfWeight = MWLF_WEIGHT_BOLD; + strcat(description,"Bold "); + } + + + if ( rnd & 2 ) { + lf.lfItalic = 1; + strcat(description,"Italics "); + } + if ( rnd & 4 ) { + lf.lfOblique = 1; + strcat(description,"Oblique "); + } + + if ( rnd & 8 ) { + lf.lfMonospace = 1; + strcat(description,"Monospace "); + } else { + lf.lfProportional = 1; + strcat(description,"Proportional "); + } + + if ( argc > 1 ) + strcpy(lf.lfFaceName,argv[1]); + else + strcpy(lf.lfFaceName,"fantasy"); + + fontid = GrCreateFont(0, 0, &lf); + /* GrSetFontSize(fontid, 1+(int)(80.0 * rand() / (RAND_MAX+1.0))); */ + GrSetFontSize(fontid,26); + GrSetFontRotation(fontid, 330); /* 33 degrees*/ + GrSetFontAttr(fontid, GR_TFKERNING | GR_TFANTIALIAS, 0); + GrSetGCFont(gc, fontid); + /*GrSetGCBackground(gc, rand() & 0xffffff);*/ + GrSetGCForeground(gc, 0xffffff); + /* x = (int) ((MAXW * 1.0) *rand()/(RAND_MAX+1.0)); + y = (int) ((MAXH * 1.0) *rand()/(RAND_MAX+1.0)); */ + + GrText(window, gc,x,y, description, -1, GR_TFASCII); + + GrDestroyFont(fontid); + + rnd++; + y += 30; + if ( y > 460 ) + y = 0; + } + + GrClose(); +} Index: demo4.c =================================================================== --- demo4.c (nonexistent) +++ demo4.c (revision 174) @@ -0,0 +1,87 @@ +/* + * Demonstration program for Nano-X blitting + */ +#include +#include +#include "nano-X.h" +#include "device.h" + +static GR_GC_ID gc1; /* graphics context for text */ +static GR_SCREEN_INFO si; /* information about screen */ + +#define GRAY14 MWRGB( 17, 17, 17 ) +#define GRAY13 MWRGB( 34, 34, 34 ) +#define GRAY12 MWRGB( 51, 51, 51 ) +#define GRAY11 MWRGB( 68, 68, 68 ) +#define GRAY10 MWRGB( 85, 85, 85 ) +#define GRAY9 MWRGB( 102, 102, 102 ) +#define GRAY8 MWRGB( 119, 119, 119 ) +#define GRAY7 MWRGB( 136, 136, 136 ) +#define GRAY6 MWRGB( 153, 153, 153 ) +#define GRAY5 MWRGB( 170, 170, 170 ) +#define GRAY4 MWRGB( 187, 187, 187 ) +#define GRAY3 MWRGB( 204, 204, 204 ) +#define GRAY2 MWRGB( 221, 221, 221 ) +#define GRAY1 MWRGB( 238, 238, 238 ) + +int +main(int argc,char **argv) +{ + GR_EVENT event; /* current event */ + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + GrGetScreenInfo(&si); + + gc1 = GrNewGC(); + + GrSetGCForeground(gc1, WHITE); + /*GrFillRect(GR_ROOT_WINDOW_ID, gc, 0, 0, 240, 320);*/ + + GrLine(GR_ROOT_WINDOW_ID, gc1, 4, 4, 634, 4); + GrLine(GR_ROOT_WINDOW_ID, gc1, 4, 4, 4, 474); + GrLine(GR_ROOT_WINDOW_ID, gc1, 634, 4, 634, 474); + GrLine(GR_ROOT_WINDOW_ID, gc1, 4, 474, 634, 474); + + /*GrJPEG(GR_ROOT_WINDOW_ID, gc, 0, 0, 400, 400, "/home/mart/nov9_pic1.jpg");*/ + +/* Bitblit function */ +{ + PSD mempsd; + int linelen, size; + void * pixels; + + mempsd = scrdev.AllocateMemGC(&scrdev); + GdCalcMemGCAlloc(mempsd, 50, 100, 0, 0, &size, &linelen); + pixels = malloc(size); + mempsd->flags |= PSF_ADDRMALLOC; + mempsd->MapMemGC(mempsd, 50, 100, scrdev.planes, scrdev.bpp, + linelen, size, pixels); + + /* Draw some stuff on offscreen */ + GdSetForeground(GdFindColor(GREEN)); + GdFillRect(mempsd, 0, 0, 50, 100); + GdSetForeground(GdFindColor(RED)); + GdFillRect(mempsd, 5, 20, 40, 60); + + /* blit */ + GdBlit(&scrdev, 10, 10, 50, 100, mempsd, 0, 0, 0); +} +/* GrSetGCForeground(gc, BLACK); + GrPoint(GR_ROOT_WINDOW_ID, gc, 0, 0); + + GrSetGCForeground(gc, GRAY10); + GrFillRect(GR_ROOT_WINDOW_ID, gc, 1, 1, 478, 638); +*/ + while (1) { + GrGetNextEvent(&event); + if(event.type == GR_EVENT_TYPE_CLOSE_REQ) break; + } + + GrClose(); + + return 0; +} Index: demo5.c =================================================================== --- demo5.c (nonexistent) +++ demo5.c (revision 174) @@ -0,0 +1,471 @@ +/* + * Demonstration program for off screen drawing with Nano-X. Based on demo.c + */ +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" + +/* + * Definitions to make it easy to define cursors + */ +#define _ ((unsigned) 0) /* off bits */ +#define X ((unsigned) 1) /* on bits */ +#define MASK(a,b,c,d,e,f,g) \ + (((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) \ + + e) * 2) + f) * 2) + g) << 9) + +#define W2_WIDTH 70 +#define W2_HEIGHT 40 + + +static GR_WINDOW_ID w1; /* id for large window */ +static GR_WINDOW_ID w2; /* id for small window */ +static GR_WINDOW_ID w3; /* id for third window */ +static GR_WINDOW_ID w4; /* id for grabbable window */ +static GR_WINDOW_ID w5; /* id for testing enter/exit window */ +static GR_WINDOW_ID p1; /* off screen pixmap */ +static GR_GC_ID gc1; /* graphics context for text */ +static GR_GC_ID gc2; /* graphics context for rectangle */ +static GR_GC_ID gc3; /* graphics context for circles */ +static GR_GC_ID gc4; /* graphics context for lines */ +static GR_COORD begxpos; /* beginning x position */ +static GR_COORD xpos; /* x position for text drawing */ +static GR_COORD ypos; /* y position for text drawing */ +static GR_COORD linexpos; /* x position for line drawing */ +static GR_COORD lineypos; /* y position for line drawing */ +static GR_COORD xorxpos; /* x position for xor line */ +static GR_COORD xorypos; /* y position for xor line */ +static GR_BOOL lineok; /* ok to draw line */ +static GR_SCREEN_INFO si; /* information about screen */ + +void do_buttondown(); +void do_buttonup(); +void do_motion(); +void do_keystroke(); +void do_exposure(); +void do_focusin(); +void do_focusout(); +void do_enter(); +void do_exit(); +void do_idle(); + +int +main(int argc,char **argv) +{ + GR_EVENT event; /* current event */ + GR_BITMAP bitmap1fg[7]; /* bitmaps for first cursor */ + GR_BITMAP bitmap1bg[7]; + GR_BITMAP bitmap2fg[7]; /* bitmaps for second cursor */ + GR_BITMAP bitmap2bg[7]; + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + GrGetScreenInfo(&si); + + w1 = GrNewWindow(GR_ROOT_WINDOW_ID, 100, 50, si.cols - 120, + si.rows - 60, 1, BROWN, WHITE); + w2 = GrNewWindow(GR_ROOT_WINDOW_ID, 6, 6, W2_WIDTH, W2_HEIGHT, 2, GREEN, + WHITE); + w3 = GrNewWindow(GR_ROOT_WINDOW_ID, 250, 30, 80, 100, 1, LTGRAY, + GREEN); + w4 = GrNewWindow(GR_ROOT_WINDOW_ID, 350, 20, 200, 150, 5, BLACK, WHITE); + w5 = GrNewWindow(GR_ROOT_WINDOW_ID, 11, 143, 209, 100, 1, BLUE, GREEN); + + p1 = GrNewPixmap(200,200,0); + + GrSelectEvents(w1, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_FOCUS_IN | GR_EVENT_MASK_FOCUS_OUT | + GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(w2, GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(w3, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_MOUSE_MOTION | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(w4, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_MOUSE_POSITION | + GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(w5, GR_EVENT_MASK_MOUSE_ENTER | + GR_EVENT_MASK_MOUSE_EXIT | GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(GR_ROOT_WINDOW_ID, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_CLOSE_REQ); + + GrMapWindow(w1); + GrMapWindow(w2); + GrMapWindow(w3); + GrMapWindow(w4); + GrMapWindow(w5); + + gc1 = GrNewGC(); + gc2 = GrNewGC(); + gc3 = GrNewGC(); + gc4 = GrNewGC(); + + GrSetGCForeground(gc1, RED); + GrSetGCBackground(gc1, BROWN); + GrSetGCForeground(gc2, MAGENTA); + GrSetGCMode(gc4, GR_MODE_XOR); + + bitmap1fg[0] = MASK(_,_,_,X,_,_,_); + bitmap1fg[1] = MASK(_,_,_,X,_,_,_); + bitmap1fg[2] = MASK(_,_,_,X,_,_,_); + bitmap1fg[3] = MASK(X,X,X,X,X,X,X); + bitmap1fg[4] = MASK(_,_,_,X,_,_,_); + bitmap1fg[5] = MASK(_,_,_,X,_,_,_); + bitmap1fg[6] = MASK(_,_,_,X,_,_,_); + + bitmap1bg[0] = MASK(_,_,X,X,X,_,_); + bitmap1bg[1] = MASK(_,_,X,X,X,_,_); + bitmap1bg[2] = MASK(X,X,X,X,X,X,X); + bitmap1bg[3] = MASK(X,X,X,X,X,X,X); + bitmap1bg[4] = MASK(X,X,X,X,X,X,X); + bitmap1bg[5] = MASK(_,_,X,X,X,_,_); + bitmap1bg[6] = MASK(_,_,X,X,X,_,_); + + bitmap2fg[0] = MASK(_,_,X,X,X,_,_); + bitmap2fg[1] = MASK(_,X,_,_,_,X,_); + bitmap2fg[2] = MASK(X,_,_,_,_,_,X); + bitmap2fg[3] = MASK(X,_,_,_,_,_,X); + bitmap2fg[4] = MASK(_,X,_,_,_,X,_); + bitmap2fg[5] = MASK(_,_,X,X,X,_,_); + + bitmap2bg[0] = MASK(_,_,X,X,X,_,_); + bitmap2bg[1] = MASK(_,X,X,X,X,X,_); + bitmap2bg[2] = MASK(X,X,X,X,X,X,X); + bitmap2bg[3] = MASK(X,X,X,X,X,X,X); + bitmap2bg[4] = MASK(_,X,X,X,X,X,_); + bitmap2bg[5] = MASK(_,_,X,X,X,_,_); + + GrSetCursor(w1, 7, 7, 3, 3, WHITE, BLACK, bitmap1fg, bitmap1bg); + GrSetCursor(w2, 7, 6, 3, 3, WHITE, BLACK, bitmap2fg, bitmap2bg); + + GrRect(GR_ROOT_WINDOW_ID, gc1, 0, 0, si.cols, si.rows); + + + while (1) { + GrGetNextEvent(&event); + + switch (event.type) { + case GR_EVENT_TYPE_BUTTON_DOWN: + do_buttondown(&event.button); + break; + + case GR_EVENT_TYPE_BUTTON_UP: + do_buttonup(&event.button); + break; + + case GR_EVENT_TYPE_MOUSE_POSITION: + case GR_EVENT_TYPE_MOUSE_MOTION: + do_motion(&event.mouse); + break; + + case GR_EVENT_TYPE_KEY_DOWN: + do_keystroke(&event.keystroke); + break; + + case GR_EVENT_TYPE_EXPOSURE: + do_exposure(&event.exposure); + break; + + case GR_EVENT_TYPE_FOCUS_IN: + do_focusin(&event.general); + break; + + case GR_EVENT_TYPE_FOCUS_OUT: + do_focusout(&event.general); + break; + + case GR_EVENT_TYPE_MOUSE_ENTER: + do_enter(&event.general); + break; + + case GR_EVENT_TYPE_MOUSE_EXIT: + do_exit(&event.general); + break; + + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + + case GR_EVENT_TYPE_NONE: + do_idle(); + break; + } + } +} + + +/* + * Here when a button is pressed. + */ +void +do_buttondown(bp) + GR_EVENT_BUTTON *bp; +{ + GR_PIXELVAL intable[W2_WIDTH * W2_HEIGHT]; + GR_PIXELVAL outtable[W2_WIDTH * W2_HEIGHT * 6]; + GR_PIXELVAL *inp; + GR_PIXELVAL *outp; + GR_PIXELVAL *oldinp; + GR_COORD row; + GR_COORD col; + + /*static int xx = 100; + static int yy = 50;*/ + + if (bp->wid == w3) { + GrRaiseWindow(w3); + GrReadArea(w2, 0, 0, W2_WIDTH, W2_HEIGHT, intable); + inp = intable; + outp = outtable; + for (row = 0; row < W2_HEIGHT; row++) { + oldinp = inp; + for (col = 0; col < W2_WIDTH; col++) { + *outp++ = *inp; + *outp++ = *inp++; + } + inp = oldinp; + for (col = 0; col < W2_WIDTH; col++) { + *outp++ = *inp; + *outp++ = *inp++; + } + inp = oldinp; + for (col = 0; col < W2_WIDTH; col++) { + *outp++ = *inp; + *outp++ = *inp++; + } + } + GrArea(w1, gc1, 0, 0, W2_WIDTH * 2, W2_HEIGHT * 3, outtable, + MWPF_PIXELVAL); + return; + } + + if (bp->wid == w4) { + /* Draw a line in the off screen pixmap. Won't be shown until the button + * is released + */ + + GrLine(p1, gc1, 0,0, bp->x, bp->y); + + GrRaiseWindow(w4); + linexpos = bp->x; + lineypos = bp->y; + xorxpos = bp->x; + xorypos = bp->y; + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + lineok = GR_TRUE; + return; + } + + if (bp->wid != w1) { + /* + * Cause a fatal error for testing if more than one + * button is pressed. + */ + if ((bp->buttons & -((int) bp->buttons)) != bp->buttons) + GrClearWindow(-1, 0); + return; + } + + GrRaiseWindow(w1); + /*GrMoveWindow(w1, ++xx, yy);*/ + + if (bp->buttons & GR_BUTTON_L) { + GrClearWindow(w1, GR_TRUE); + return; + } + + begxpos = bp->x; + xpos = bp->x; + ypos = bp->y; +} + + +/* + * Here when a button is released. + */ +void +do_buttonup(bp) + GR_EVENT_BUTTON *bp; +{ + if (bp->wid == w4) { + if (lineok) { + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + GrLine(w4, gc3, bp->x, bp->y, linexpos, lineypos); + } + lineok = GR_FALSE; + GrCopyArea(w1, gc4, 200,200, 200,200, p1,0,0,MWROP_SRCCOPY); + return; + } + + if (bp->wid == w2) { + GrClose(); + exit(0); + } +} + + +/* + * Here when the mouse has a motion event. + */ +void +do_motion(mp) + GR_EVENT_MOUSE *mp; +{ + if (mp->wid == w4) { + if (lineok) { + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + xorxpos = mp->x; + xorypos = mp->y; + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + } + return; + } + + if (mp->wid == w3) { + GrPoint(w3, gc3, mp->x, mp->y); + return; + } +} + + +/* + * Here when a keyboard press occurs. + */ +void +do_keystroke(kp) + GR_EVENT_KEYSTROKE *kp; +{ + GR_SIZE width; /* width of character */ + GR_SIZE height; /* height of character */ + GR_SIZE base; /* height of baseline */ + + if (kp->wid == w4) { + if (lineok) { + GrLine(w4, gc4, xorxpos, xorypos, linexpos, lineypos); + lineok = GR_FALSE; + } + return; + } + + GrGetGCTextSize(gc1, &kp->ch, 1, GR_TFASCII, &width, &height, &base); + if ((kp->ch == '\r') || (kp->ch == '\n')) { + xpos = begxpos; + ypos += height; + return; + } + if (kp->ch == '\b') { /* assumes fixed width font!! */ + if (xpos <= begxpos) + return; + xpos -= width; + GrSetGCForeground(gc3, BROWN); + GrFillRect(w1, gc3, xpos, ypos - height + base + 1, + width, height); + return; + } + GrText(w1, gc1, xpos, ypos + base, &kp->ch, 1, 0); + xpos += width; +} + + +/* + * Here when an exposure event occurs. + */ +void +do_exposure(ep) + GR_EVENT_EXPOSURE *ep; +{ + GR_POINT points[3]; + + if (ep->wid != w1) + return; + points[0].x = 311; + points[0].y = 119; + points[1].x = 350; + points[1].y = 270; + points[2].x = 247; + points[2].y = 147; + + GrFillRect(w1, gc2, 50, 50, 150, 200); + GrFillPoly(w1, gc2, 3, points); +} + + +/* + * Here when a focus in event occurs. + */ +void +do_focusin(gp) + GR_EVENT_GENERAL *gp; +{ + if (gp->wid != w1) + return; + GrSetBorderColor(w1, WHITE); +} + +/* + * Here when a focus out event occurs. + */ +void +do_focusout(gp) + GR_EVENT_GENERAL *gp; +{ + if (gp->wid != w1) + return; + GrSetBorderColor(w1, GRAY); +} + + +/* + * Here when a enter window event occurs. + */ +void +do_enter(gp) + GR_EVENT_GENERAL *gp; +{ + if (gp->wid != w5) + return; + GrSetBorderColor(w5, WHITE); + GrRaiseWindow(w5); +} + + +/* + * Here when a exit window event occurs. + */ +void +do_exit(gp) + GR_EVENT_GENERAL *gp; +{ + if (gp->wid != w5) + return; + GrSetBorderColor(w5, GREEN); + GrLowerWindow(w5); +} + + +/* + * Here to do an idle task when nothing else is happening. + * Just draw a randomly colored filled circle in the small window. + */ +void +do_idle() +{ + GR_COORD x; + GR_COORD y; + GR_SIZE rx; + GR_SIZE ry; + GR_COLOR color; + + x = rand() % 70; + y = rand() % 40; + rx = (rand() % 10) + 5; + ry = (rx * si.ydpcm) / si.xdpcm; /* make it appear circular */ + + color = rand() % si.ncolors; + + GrSetGCForeground(gc3, MWPALINDEX(color)); + GrFillEllipse(w2, gc3, x, y, rx, ry); +} Index: landmine.doc =================================================================== --- landmine.doc (nonexistent) +++ landmine.doc (revision 174) @@ -0,0 +1,108 @@ + LANDMINE + + +Landmine is a game in which you try to safely move step by step from the +top left corner of a square board to the bottom right corner of the board. +Scattered among the cells of the board are invisible mines which blow up +if you step on them. When you step on a mine, one of your legs is blown +off, and if you lose both legs, then the game is over. + +Steps are made one at a time from any cell you have already visited to +any of the eight possible cells which are adjacent to it. At the start +of the game you are placed in the top left corner of the board, which is +guaranteed to have no mine in it. There are also no mines immediately +adjacent to the starting cell. There is also a guaranteed path from the +starting cell to the finishing cell which does not encounter any mines. + +You cannot see the mines, however you have a detector which indicates +the presence of the mines. The detector cannot locate the direction of +any individual mine, but it does indicate the number of mines immediately +adjacent to your cell. By using this information from all the cells you +have already visited, you can usually deduce where the mines must be. +In this way, you can find your way safely to the destination cell. Some +of the deductions that can be made are very subtle, and experience will +improve your scores dramatically. + +When landmine is started up under mini-X, the board is displayed at the +left side, some buttons are displayed at the upper right, and some statistics +are displayed at the lower right. To make a step, use the mouse to move the +cursor onto the cell that you wish to step on, and press a button. A number +will appear in that square (if there is no mine there!) indicating now many +mines are adjacent to that square. You can step onto any cell which is +adjacent to any cell you have already stepped on. + +In order to help you deduce where the mines are and what steps are safe, +you can mark any non-visited cell as containing a mine. To do this, move +the mouse to that cell, and then type a space. A red circle will then +appear in that cell to indicate that you think it contains a mine. A +side effect of doing this is that you cannot accidentally step on the +square while it is marked. Notice that the cell is marked as you request +whether or not a mine is actually there, thus if you mistakenly mark a +cell, you are likely to get confused and later step on a real mine! If +you think that a cell is marked in error, you can clear the marking by +moving the mouse to the cell and then typing another space. + +If you step on a mine, you will hear a beep, and a red circle will flash +on and off for a few seconds to indicate that the mine has exploded. +Then the mine will be removed, and the counts in the adjacent cells +will be adjusted to reflect the new situation with one less mine. Your +number of legs is also reduced by 1, and the cursor shape is changed to +indicate this. If you lose both legs, then the game is lost. If you +successfully make it to the lower right corner, then the game is won. + +When the game is over, the location of all mines are marked with red circles. +In addition, if you had marked cells as containing mines, but the cells were +wrongly marked, then those cells are shown with green circles. After you +have analyzed the results of the game, you can start a new game by using +the NEW GAME button. + +The three buttons on the top right of the screen are QUIT, SAVE GAME, +and NEW GAME. The buttons are activated by moving the cursor to the +interior of the button, and pressing any mouse button. No confirmation +is asked for these actions. + +QUIT will immediately quit playing and return you to text mode and exit. +However, if you had started landmine with a filename to restore from, +then the current status will be saved back to that file. If you had not +supplied a filename on starting, and have not saved the game using the +SAVE GAME button, then QUIT will quit without saving anything. + +SAVE GAME is used to save the current status of the game without exiting. +This lets you make sure that the game is saved away when you have been +playing for a long time and are worried about crashes. If you had given +a file for restoring of previous games, then the game will be saved back +into that file. If you had not specified a filename, then a default name +of "landmine.save" will be used. If the save operation works, the button +will momentarily flash. If the save operation fails, then a beep will +be sounded. + +NEW GAME is used to start a new game. This button can only be used after +a game has just been completed. That is, after both legs have been blown +off or you have reached the destination cell, you use this button to +begin another game. + +When starting landmine, you can specify some options on the command line. +The options are the following: + + landmine [-s n] [-m n] [savefile] + +The savefile is the filename to save the game into when the SAVE GAME or +QUIT buttons are used, as described above. + +The -s option sets the size of the board. The size is the number of cells +across the board, and also down the board. The board size can be set to +any size from 3 to 30. The default size is 15. + +The -m option sets the number of mines on the board. This can be set from +1 to 50% of the number of cells on the board. The default number of mines +is 15% of the number of cells on the board. For the default board size, +the default number of mines is 33. + +The statistics saved in the save file are kept for each combination of +board size and mines, thus you can play with many different combinations +of values and the statistics will be kept separately. There is a limit +of 1000 different combinations that can be saved. + +You cannot change the board size or number of mines while a game is in +progress. To change the parameters, finish the game, save the game into a +file and exit, then restart landmine giving the new parameters. Index: demo6.c =================================================================== --- demo6.c (nonexistent) +++ demo6.c (revision 174) @@ -0,0 +1,165 @@ +/* + * Demonstrates loading a binary PPM file and displaying it in a window + * as a Pixmap. + */ + +/* Comment this definition out if you don't want to use server side pixmaps */ +/* (it will be slower but will work on device drivers without bitblt) */ +#define USE_PIXMAPS + +#include +#include +#include +#include +#include + +GR_WINDOW_ID window; /* ID for output window */ +#ifdef USE_PIXMAPS +GR_WINDOW_ID pmap; /* ID for pixmap */ +#endif +GR_GC_ID gc; /* Graphics context */ +int width, height; /* Size of image */ +unsigned char *data; /* Local copy of image data */ + +void do_exposure(GR_EVENT_EXPOSURE *event) +{ + /* The window has been exposed so redraw it */ +#ifdef USE_PIXMAPS + GrCopyArea(window, gc, 0, 0, width, height, pmap, 0, 0, MWROP_SRCCOPY); +#else + GrArea(window, gc, 0, 0, width, height, data, MWPF_RGB); +#endif +} + +void errorhandler(GR_EVENT *ep) +{ + printf("Error (%s) code %d id %d", ep->error.name, + ep->error.code, ep->error.id); + exit(1); +} + +int main(int argc, char *argv[]) +{ + unsigned char line[256]; + GR_EVENT event; + FILE *infile; + int i, o; + unsigned char *p; + + if(argc != 2) { + printf("Usage: demo6 \n"); + exit(1); + } + + if(!(infile = fopen(argv[1], "r"))) { + printf("Couldn't open \"%s\" for reading: %s\n", argv[1], + strerror(errno)); + exit(2); + } + + /* Read magic number (P6 = colour, binary encoded PPM file) */ + if(!fgets(line, 256, infile)) goto truncated; + if(line[0] != 'P' || line[1] != '6') { + printf("Unsupported PPM type or not a PPM file.\n"); + printf("Please supply a valid P6 format file (colour, with " + "binary encoding).\n"); + } + + /* Strip comments */ + do { + if(!fgets(line, 256, infile)) goto truncated; + } while(line[0] == '#'); + + /* Read width and height */ + sscanf(line, "%i %i", &width, &height); + + /* Read the maximum colour value */ + if(!fgets(line, 256, infile)) goto truncated; + sscanf(line, "%i", &i); + if(i != 255) { + printf("Truecolour mode only is supported\n"); + exit(4); + } + + /* Calculate how many bytes of image data there is */ + i = width * height * 3; + /* Calculate how many bytes of data there will be after unpacking */ + o = width * height * 4; + + /* Allocate the space to store the data whilst it's being loaded */ + if(!(data = malloc(o))) { + printf("Not enough memory to load image\n"); + exit(5); + } + + /* Read the data in and unpack it to RGBX format */ + /* The lower byte isn't used so we don't set it to anything */ + p = data; + while(o) { + if(fread(p, 1, 3, infile) != 3) goto truncated; + p += 4; + o -= 4; + } + + /* We don't need the input file anymore so close it */ + fclose(infile); + + /* Register the error handler */ + GrSetErrorHandler(errorhandler); + + if(GrOpen() < 0) { + printf("Couldn't connect to Nano-X server\n"); + exit(6); + } + +#ifdef USE_PIXMAPS + /* Create the pixmap to store the picture in */ + pmap = GrNewPixmap(width, height, NULL); +#endif + + /* Create a graphics context */ + gc = GrNewGC(); + +#ifdef USE_PIXMAPS + /* Copy the image data into the pixmap */ + GrArea(pmap, gc, 0, 0, width, height, data, MWPF_RGB); + /* We can free the image data now because it's stored in the pixmap */ + free(data); +#endif + + /* Create a window to output the image to */ + window = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, width, height, 0, 0, 0); + + /* Select expose events so we can redraw the image when necessary */ + GrSelectEvents(window, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_CLOSE_REQ); + + /* Make the window visible */ + GrMapWindow(window); + +#ifdef USE_PIXMAPS + /* Paint the pixmap onto it */ + GrCopyArea(window, gc, 0, 0, width, height, pmap, 0, 0, + MWROP_SRCCOPY); +#else + GrArea(window, gc, 0, 0, width, height, data, MWPF_RGB); +#endif + + while(1) { + GrGetNextEvent(&event); + switch(event.type) { + case GR_EVENT_TYPE_EXPOSURE: + do_exposure(&event.exposure); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + } + } + + return 0; + +truncated: + printf("Error: File appears to be truncated\n"); + exit(3); +} Index: nxterm.c =================================================================== --- nxterm.c (nonexistent) +++ nxterm.c (revision 174) @@ -0,0 +1,1182 @@ +/* + * nxterm - terminal emulator for Nano-X + * + * (C) 1994,95,96 by Torsten Scherer (TeSche) + * itschere@techfak.uni-bielefeld.de + * + * - quite some changes for W1R1 + * - yet more changes for W1R2 + * + * TeSche 01/96: + * - supports W_ICON & W_CLOSE + * - supports /etc/utmp logging for SunOS4 and Linux + * - supports catching of console output for SunOS4 + * Phx 02-06/96: + * - supports NetBSD-Amiga + * Eero 11/97: + * - unsetenv(DISPLAY), setenv(LINES, COLUMNS). + * - Add new text modes (you need to use terminfo...). + * Eero 2/98: + * - Implemented fg/bgcolor setting. With monochrome server it changes + * bgmode variable, which tells in which mode to draw to screen + * (M_CLEAR/M_DRAW) and affects F_REVERSE settings. + * - Added a couple of checks. + * + * TODO: + * - Allocate and set sensible window palette for fg/bg color setting. + * - add scroll-region ('cs') command. Fairly many programs + * can take advantage of that. + * - Add xterm like mouse event to terminfo key event conversion... :) + * - check if current NetBSD really needs ifdefs below with + * current W server/library. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" +#include "nxterm.h" + +#define TITLE "nxterm" + +#define SMALLBUFFER 80 +#define LARGEBUFFER 1024 + +/* + * some pty helper functions + */ +#ifdef linux +#define NSIG _NSIG +#endif + +#ifdef __FreeBSD__ +#include +#endif + + +/* + * some global variables + */ + +static GR_WINDOW_ID w1; /* id for window */ +static GR_GC_ID gc1; /* graphics context */ +static GR_FONT_ID regFont; +/*static GR_FONT_ID boldFont;*/ + +static GR_SCREEN_INFO si; /* screen info */ +static GR_FONT_INFO fi; /* Font Info */ +static GR_WINDOW_INFO wi; +static GR_GC_INFO gi; +static GR_BOOL havefocus = GR_FALSE; + +static short winw, winh, pid, console; +static int pipeh; +static short cblink = 0, visualbell = 0, debug = 0; +#ifdef __FreeBSD__ +static char pty[SMALLBUFFER]; +static struct winsize winsz; +#endif + +#define fonh fi.height +#define fonw fi.maxwidth + +int term_init(); + +/****************************************************************************/ + +/* + * + */ + +/* static int isIconified; */ +static int isMaximized=0; + +void maximize(void) +{ + static short x0, y0, w, h, w_max,h_max; + + if (!isMaximized) + { + + w_max=si.cols-wi.bordersize; + h_max=si.rows-wi.bordersize; + GrMoveWindow(w1,0,0); + GrResizeWindow(w1,w_max, h_max); + isMaximized=1; + } + else + { + GrResizeWindow(w1, w, h); + GrMoveWindow(w1, x0, y0); + isMaximized=0; + } +} + + +/****************************************************************************/ + + +/* + * some common tool functions + */ + +void sigpipe(int sig) +{ + /* this one musn't close the window */ +/* _write_utmp(pty, "", "", 0); */ + kill(-pid, SIGHUP); + _exit(sig); +} + + +void sigchld(int sig) +{ +/* _write_utmp(pty, "", "", 0); */ + _exit(sig); +} + + +void sigquit(int sig) +{ + signal(sig, SIG_IGN); + kill(-pid, SIGHUP); +} + + +/* + * this is the wterm terminal code, almost like VT52 + */ + +short bgmode, escstate, curx, cury, curon, curvis; +short savx, savy, wrap, style; +short col, row, colmask = 0x7f, rowmask = 0x7f; + +/* + * something to buffer plain text output + */ + +short sbufcnt = 0; +short sbufx, sbufy; +char lineBuffer[SMALLBUFFER+1]; +char *sbuf=lineBuffer; + +void sflush(void) +{ + if (sbufcnt) + { + GrText(w1,gc1, sbufx*fonw, sbufy*fonh, sbuf, sbufcnt, GR_TFTOP); + sbufcnt = 0; + } +} + + +void lineRedraw(void) +{ + GrSetGCForeground(gc1,gi.background); + GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh); + GrSetGCForeground(gc1,gi.foreground); + + if (sbufcnt) + { + sbuf[sbufcnt] = 0; + GrText(w1,gc1, sbufx*fonw, sbufy*fonh, sbuf, sbufcnt, GR_TFTOP); + } +} + +void sadd (char c) +{ + if (sbufcnt == SMALLBUFFER) + { + sflush (); + } + + if (!sbufcnt) + { + sbufx = curx; + sbufy = cury; + } + + sbuf[sbufcnt++] = c; +} + +void show_cursor (void) +{ + GrSetGCMode(gc1,GR_MODE_XOR); + GrSetGCForeground(gc1, WHITE); + GrFillRect(w1, gc1, curx*fonw, cury*fonh+1, fonw, fonh-1); + GrSetGCForeground(gc1, gi.foreground); + GrSetGCMode(gc1,GR_MODE_COPY); +} + + +void draw_cursor (void) +{ + if (!curvis) + { + curvis = 1; + show_cursor(); + } +} +void hide_cursor (void) +{ + if (curvis) + { + curvis = 0; + show_cursor(); + } +} + + +void vscroll(int lines) +{ + hide_cursor(); + GrCopyArea(w1,gc1,0, 0, winw, winh-(lines*fonh), + w1, 0, (lines*fonh), MWROP_SRCCOPY); + + GrSetGCForeground(gc1,gi.background); + GrFillRect(w1, gc1, 0, winh-(lines*fonh), + winw, (lines*fonh)); + GrSetGCForeground(gc1,gi.foreground); +} + +void esc5(unsigned char c) /* setting background color */ +{ + + GrSetGCBackground(gc1, c); + GrGetGCInfo(gc1,&gi); + escstate = 0; +} + +void esc4(unsigned char c) /* setting foreground color */ +{ + GrSetGCForeground(gc1,c); + GrGetGCInfo(gc1,&gi); + escstate = 0; +} + +void esc3(unsigned char c) /* cursor position x axis */ +{ + curx = (c - 32) & colmask; + if (curx >= col) + curx = col - 1; + else if (curx < 0) + curx = 0; + escstate = 0; +} + + +void esc2(unsigned char c) /* cursor position y axis */ +{ + cury = (c - 32) & rowmask; + if (cury >= row) + cury = row - 1; + else if (cury < 0) + cury = 0; + escstate = 3; +} + + +void esc1(unsigned char c) /* various control codes */ +{ + static int ReverseMode=0; + escstate = 0; + + switch(c) + { + case 'A':/* cursor up */ + hide_cursor(); + if ((cury -= 1) < 0) + cury = 0; + break; + + case 'B':/* cursor down */ + hide_cursor(); + if ((cury += 1) >= row) + cury = row - 1; + break; + + case 'C':/* cursor right */ + hide_cursor(); + if ((curx += 1) >= col) + curx = col - 1; + break; + + case 'D':/* cursor left */ + hide_cursor(); + if ((curx -= 1) < 0) + curx = 0; + break; + + case 'E':/* clear screen & home */ + GrClearWindow(w1, 0); + curx = 0; + cury = 0; + break; + + case 'H':/* cursor home */ + curx = 0; + cury = 0; + break; + + case 'I':/* reverse index */ + if ((cury -= 1) < 0) + { + cury = 0; + vscroll(1); + } + break; + + case 'J':/* erase to end of page */ + + if (cury < row-1) + { + GrSetGCForeground(gc1,gi.background); + GrFillRect(w1,gc1, 0,(cury+1)*fonh, winw, (row-1-cury)*fonh); + GrSetGCForeground(gc1,gi.foreground); + } + GrSetGCForeground(gc1,gi.background); + GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh); + GrSetGCForeground(gc1,gi.foreground); + break; + + case 'K':/* erase to end of line */ + GrSetGCForeground(gc1,gi.background); + GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh); + GrSetGCForeground(gc1,gi.foreground); + break; + + case 'L':/* insert line */ + if (cury < row-1) + { + vscroll(1); + } + curx = 0; + break; + + case 'M':/* delete line */ + if (cury < row-1) + { + vscroll(1); + } + curx = 0; + break; + + case 'Y':/* position cursor */ + escstate = 2; + break; + + case 'b':/* set foreground color */ + escstate = 4; + break; + + case 'c':/* set background color */ + escstate = 5; + break; + + case 'd':/* erase beginning of display */ +/* w_setmode(win, bgmode); */ + if (cury > 0) + { + GrSetGCForeground(gc1,gi.background); + GrFillRect(w1,gc1, 0, 0, winw, cury*fonh); + GrSetGCForeground(gc1,gi.foreground); + } + if (curx > 0) + { + GrSetGCForeground(gc1,gi.background); + GrFillRect(w1,gc1, 0, cury*fonh, curx*fonw, fonh); + GrSetGCForeground(gc1,gi.foreground); + } + break; + + case 'e':/* enable cursor */ + curon = 1; + break; + + case 'f':/* disable cursor */ + curon = 0; + break; + + case 'j':/* save cursor position */ + savx = curx; + savy = cury; + break; + + case 'k':/* restore cursor position */ + curx = savx; + cury = savy; + break; + + case 'l':/* erase entire line */ + GrSetGCForeground(gc1,gi.background); + GrRect(w1,gc1, 0, cury*fonh, winw, fonh); + GrSetGCForeground(gc1,gi.foreground); + curx = 0; + break; + + case 'o':/* erase beginning of line */ + if (curx > 0) + { + GrSetGCForeground(gc1,gi.background); + GrRect(w1,gc1,0, cury*fonh, curx*fonw, fonh); + GrSetGCForeground(gc1,gi.foreground); + } + break; + + case 'p':/* enter reverse video mode */ + { + if(!ReverseMode) + { + GrSetGCForeground(gc1,gi.background); + GrSetGCBackground(gc1,gi.foreground); + ReverseMode=1; + } + } + break; + + case 'q':/* exit reverse video mode */ + { + if(ReverseMode) + { + GrSetGCForeground(gc1,gi.foreground); + GrSetGCBackground(gc1,gi.background); + ReverseMode=0; + } + } + break; + + case 'v':/* enable wrap at end of line */ + wrap = 1; + break; + + case 'w':/* disable wrap at end of line */ + wrap = 0; + break; + +/* and these are the extentions not in VT52 */ + + case 'G': /* clear all attributes */ + break; + + case 'g': /* enter bold mode */ +/* GrSetGCFont(gc1, boldFont); */ + break; + + case 'h': /* exit bold mode */ +/* GrSetGCFont(gc1, regFont); */ + break; + + case 'i': /* enter underline mode */ + break; + + /* j, k and l are already used */ + + case 'm': /* exit underline mode */ + break; + +/* these ones aren't yet on the termcap entries */ + + case 'n': /* enter italic mode */ + break; + /* o, p and q are already used */ + + case 'r': /* exit italic mode */ + break; + + case 's': /* enter light mode */ + break; + + case 't': /* exit ligth mode */ + break; + + default: /* unknown escape sequence */ + break; + } +} + +/* + * un-escaped character print routine + */ + +void esc0 (unsigned char c) +{ + switch (c) + { + case 0: + /* + * printing \000 on a terminal means "do nothing". + * But since we use \000 as string terminator none + * of the characters that follow were printed. + * + * perl -e 'printf("a%ca", 0);' + * + * said 'a' in a wterm, but should say 'aa'. This + * bug screwed up most ncurses programs. + * + * kay. + */ + break; + + case 7: /* bell */ + if (visualbell) + { +/* w_setmode(win, M_INVERS); */ +/* w_pbox(win, 0, 0, winw, winh); */ +/* w_test(win, 0, 0); */ +/* w_pbox(win, 0, 0, winw, winh); */ + ; + } + else + { + ; + GrBell(); + } + break; + + case 8: /* backspace */ + lineRedraw(); + if (--curx < 0) + { + curx = 0; + } + break; + + case 9: /* tab */ + { + int borg,i; + + borg=(((curx >> 3) + 1) << 3); + if(borg >= col) + { + borg=col-1; + } + borg=borg-curx; + for(i=0; i < borg; ++i){sadd(' ');} + if ((curx = ((curx >> 3) + 1) << 3) >= col) + { + curx = col - 1; + } + } + break; + + case 10: /* line feed */ + sflush(); + if (++cury >= row) + { + vscroll(1); + cury = row-1; + } + break; + + case 13: /* carriage return */ + sflush(); + curx = 0; + break; + + case 27: /* escape */ + sflush(); + escstate = 1; + break; + + case 127: /* delete */ + break; + + default: /* any printable char */ + sadd(c); + if (++curx >= col) + { + sflush(); + if (!wrap) + { + curx = col-1; + } + else + { + curx = 0; + if (++cury >= row) + { + vscroll(1); + } + } + } + break; + } +} + + +void printc(unsigned char c) +{ + switch(escstate) + { + case 0: + esc0(c); + break; + + case 1: + sflush(); + esc1(c); + break; + + case 2: + sflush(); + esc2(c); + break; + + case 3: + sflush(); + esc3(c); + break; + + case 4: + sflush(); + esc4(c); + break; + + case 5: + sflush(); + esc5(c); + break; + + default: + escstate = 0; + break; + } +} + + +void init() +{ + curx = savx = 0; + cury = savy = 0; + wrap = 1; + curon = 1; + curvis = 0; + escstate = 0; +} + + +/* + * general code... + */ + +void +term(void) +{ + long in, l; + GR_EVENT wevent; + GR_EVENT_KEYSTROKE *kp; + unsigned char buf[LARGEBUFFER]; + + GrRegisterInput(pipeh); + while (42) { + if (havefocus) + draw_cursor(); + GrGetNextEvent(&wevent); + + switch(wevent.type) { + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + break; + + case GR_EVENT_TYPE_KEY_DOWN: + kp=(GR_EVENT_KEYSTROKE *)&wevent; + /* toss all special keys*/ + if (kp->ch & MWKEY_NONASCII_MASK) + break; + *buf = kp->ch & 0xff; + write(pipeh, buf,1); + break; + + case GR_EVENT_TYPE_FOCUS_IN: + havefocus = GR_TRUE; + break; + + case GR_EVENT_TYPE_FOCUS_OUT: + havefocus = GR_FALSE; + hide_cursor(); + break; + + case GR_EVENT_TYPE_UPDATE: + /* + * if we get temporarily unmapped (moved), + * set cursor state off. + */ + if (wevent.update.utype == GR_UPDATE_UNMAPTEMP) + curvis = 0; + break; + + case GR_EVENT_TYPE_FDINPUT: + hide_cursor(); + while ((in = read(pipeh, buf, sizeof(buf))) > 0) { + for (l=0; l] [-s ]\n"); + printf(" [-g ] [-v] [-c] [-h] [program {args}]\n"); + exit(0); +} + + +void *mysignal(int signum, void *handler) +{ + struct sigaction sa, so; + + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(signum, &sa, &so); + + return so.sa_handler; +} + +/* + * guess what... :) + */ + +int main(int argc, char **argv) +{ + GR_BITMAP bitmap1fg[7]; /* mouse cursor */ + GR_BITMAP bitmap1bg[7]; + GR_WM_PROPERTIES props; + + short xp, yp, fsize; + char *family, *shell = NULL, *cptr, *geometry = NULL; + struct passwd *pw; + char buf[80]; + short uid; + char thesh[128]; +#ifdef __FreeBSD__ + char *ptr; +#endif + +#ifdef SIGTTOU + /* just in case we're started in the background */ + signal(SIGTTOU, SIG_IGN); +#endif + + /* who am I? */ + if (!(pw = getpwuid((uid = getuid())))) + { + fprintf(stderr, "error: wterm can't determine determine your login name\n"); + exit(-1); + } + + + if (GrOpen() < 0) + { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + GrGetScreenInfo(&si); + /* + * scan arguments... + */ + + console = 0; + argv++; + while (*argv && **argv=='-') + switch (*(*argv+1)) + { + case 'b': + cblink = 1; + argv++; + break; + + case 'c': + console = 1; + argv++; + break; + + case 'd': + debug = 1; + argv++; + break; + + case 'f': + if (*++argv) { + family = *argv++; + } else { + usage("-f option requires an argument"); + } + break; + + case 's': + if (*++argv) { + fsize = atoi(*argv++); + } else { + usage("-s option requires an argument"); + } + break; + + case 'g': + if (*++argv) { + geometry = *argv++; + } else { + usage("-g option requires an argument"); + } + break; + + case 'h': + /* this will never return */ + usage(""); + + case 'v': + visualbell = 1; + argv++; + break; + + default: + usage("unknown option"); + } + + /* + * now *argv either points to a program to start or is zero + */ + + if (*argv) { + shell = *argv; + } + if (!shell) { + shell = getenv("SHELL="); + } + if (!shell) { + shell = pw->pw_shell; + } + if (!shell) { + shell = "/bin/sh"; + } + + if (!*argv) { + /* + * the '-' makes the shell think it is a login shell, + * we leave argv[0] alone if it isn`t a shell (ie. + * the user specified the program to run as an argument + * to wterm. + */ + cptr = strrchr(shell, '/'); + sprintf (thesh, "-%s", cptr ? cptr + 1 : shell); + *--argv = thesh; + } + + col = 80; + row = 25; + xp = 0; + yp = 0; + if (geometry) + { + if (col < 1) + { + col = 80; + } + if (row < 1) + { + row = 25; + } + if (col > 0x7f) + colmask = 0xffff; + if (row > 0x7f) + rowmask = 0xffff; + } + + regFont=GrCreateFont(GR_FONT_SYSTEM_FIXED, 0, NULL); + /*regFont=GrCreateFont(GR_FONT_OEM_FIXED, 0, NULL);*/ + /*boldFont=GrCreateFont(GR_FONT_SYSTEM_FIXED, 0, NULL);*/ + GrGetFontInfo(regFont, &fi); + + winw=col*fi.maxwidth; + winh=row*fi.height; + w1 = GrNewWindow(GR_ROOT_WINDOW_ID, 10,10,winw, winh,0,BLACK,LTBLUE); + props.flags = GR_WM_FLAGS_TITLE; + props.title = TITLE; + GrSetWMProperties(w1, &props); + + GrSelectEvents(w1, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_KEY_DOWN | + GR_EVENT_MASK_FOCUS_IN | GR_EVENT_MASK_FOCUS_OUT | + GR_EVENT_MASK_UPDATE | GR_EVENT_MASK_CLOSE_REQ); + + GrMapWindow(w1); + + gc1 = GrNewGC(); + GrSetGCFont(gc1, regFont); + +#define _ ((unsigned) 0) /* off bits */ +#define X ((unsigned) 1) /* on bits */ +#define MASK(a,b,c,d,e,f,g) \ + (((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) \ + + e) * 2) + f) * 2) + g) << 9) + bitmap1fg[0] = MASK(_,_,X,_,X,_,_); + bitmap1fg[1] = MASK(_,_,_,X,_,_,_); + bitmap1fg[2] = MASK(_,_,_,X,_,_,_); + bitmap1fg[3] = MASK(_,_,_,X,_,_,_); + bitmap1fg[4] = MASK(_,_,_,X,_,_,_); + bitmap1fg[5] = MASK(_,_,_,X,_,_,_); + bitmap1fg[6] = MASK(_,_,X,_,X,_,_); + + bitmap1bg[0] = MASK(_,X,X,X,X,X,_); + bitmap1bg[1] = MASK(_,_,X,X,X,_,_); + bitmap1bg[2] = MASK(_,_,X,X,X,_,_); + bitmap1bg[3] = MASK(_,_,X,X,X,_,_); + bitmap1bg[4] = MASK(_,_,X,X,X,_,_); + bitmap1bg[5] = MASK(_,_,X,X,X,_,_); + bitmap1bg[6] = MASK(_,X,X,X,X,X,_); + GrSetCursor(w1, 7, 7, 3, 3, GREEN, BLACK, bitmap1fg, bitmap1bg); + GrSetGCForeground(gc1, GREEN); + GrSetGCBackground(gc1, BLACK); + GrGetWindowInfo(w1,&wi); + GrGetGCInfo(gc1,&gi); + + sprintf(buf, "wterm: %s", shell); + + /* + * what kind of terminal do we want to emulate? + */ +#ifdef __FreeBSD__ + putenv ("TERM=wterm"); +#else + putenv ("TERM=vt52"); +#endif + + /* + * this one should enable us to get rid of an /etc/termcap entry for + * both curses and ncurses, hopefully... + */ + + if (termcap_string) + { + sprintf (termcap_string + strlen (termcap_string), "li#%d:co#%d:", + row, col); + putenv (termcap_string); + } + /* in case program absolutely needs terminfo entry, these 'should' + * transmit the screen size of correctly (at least xterm sets these + * and everything seems to work correctly...). Unlike putenv(), + * setenv() allocates also the given string not just a pointer. + */ + sprintf (buf, "%d", col); + setenv ("COLUMNS", buf, 1); + sprintf (buf, "%d", row); + setenv ("LINES", buf, 1); + + init(); + + /* + * create a pty + */ +#ifdef __FreeBSD__ + winsz.ws_col = col; + winsz.ws_row = row; + if ((pid = forkpty(&pipeh, pty, NULL, &winsz)) < 0) + { + fprintf(stderr,"wterm: can't create pty\r\n"); + perror("wterm"); + sleep(2); + GrKillWindow(w1); + exit(-1); + } + + if ((ptr = rindex(pty, '/'))) + { + strcpy(pty, ptr + 1); + } + + if (!pid) + { + int i; + for (i = getdtablesize(); --i >= 3; ) + close (i); + /* + * SIG_IGN are not reset on exec() + */ + for (i = NSIG; --i >= 0; ) + signal (i, SIG_DFL); + + /* caution: start shell with correct user id! */ + seteuid(getuid()); + setegid(getgid()); + + /* this shall not return */ + execvp(shell, argv); + + /* oops? */ + fprintf(stderr,"wterm: can't start shell\r\n"); + sleep(3); + GrKillWindow(w1); + _exit(-1); + } +#else + pipeh = term_init(); +#endif + +/* _write_utmp(pty, pw->pw_name, "", time(0)); */ + +#if 0 + /* catch some signals */ + mysignal(SIGTERM, sigquit); + mysignal(SIGHUP, sigquit); + mysignal(SIGINT, SIG_IGN); + mysignal(SIGQUIT, sigquit); + mysignal(SIGPIPE, sigpipe); + mysignal(SIGCHLD, sigchld); +#endif + + /* prepare to catch console output */ + if (console) + { + /* for any OS chr$(7) might cause endless loops if + * catched from console + */ + visualbell = 1; + console = 0; /* data will come to normal pipe handle */ + ioctl(pipeh, TIOCCONS, 0); + } + + term(); + return 0; +} + +#if ELKS +char * nargv[2] = {"/bin/sash", NULL}; +#else +#if DOS_DJGPP +char * nargv[2] = {"bash", NULL}; +#else +char * nargv[2] = {"/bin/sh", NULL}; +#endif +#endif + +void sigchild(int signo) +{ + GrClose(); + exit(0); +} + +int term_init() +{ + int tfd; + int n = 0; + pid_t pid; + char pty_name[12]; + +again: + sprintf(pty_name, "/dev/ptyp%d", n); + if ((tfd = open(pty_name, O_RDWR | O_NONBLOCK)) < 0) { + if ((errno == EBUSY || errno == EIO) && n < 10) { + n++; + goto again; + } + fprintf(stderr, "Can't create pty %s\n", pty_name); + return -1; + } + signal(SIGCHLD, sigchild); + signal(SIGINT, sigchild); + if ((pid = fork()) == -1) { + fprintf(stderr, "No processes\n"); + return -1; + } + if (!pid) { + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(tfd); + + setsid(); + pty_name[5] = 't'; + if ((tfd = open(pty_name, O_RDWR)) < 0) { + fprintf(stderr, "Child: Can't open pty %s\n", pty_name); + exit(1); + } + close(STDERR_FILENO); + dup2(tfd, STDIN_FILENO); + dup2(tfd, STDOUT_FILENO); + dup2(tfd, STDERR_FILENO); + execv(nargv[0], nargv); + exit(1); + } + return tfd; +} + +#if 0 +void _write_utmp(char *line, char *user, char *host, int time) +{ + int fh, offset, isEmpty, isLine; + struct utmp ut; + + if ((fh = open("/etc/utmp", O_RDWR)) < 0) { + return; + } + + /* first of all try to find an entry with the same line */ + + offset = 0; + isEmpty = -1; + isLine = -1; + + while ((isLine < 0) && (read(fh, &ut, sizeof(ut)) == sizeof(ut))) { + if (!ut.ut_line[0]) + { + if (isEmpty < 0) + { + isEmpty = offset; + } + } + else + { + if (!strncmp(ut.ut_line, line, sizeof(ut.ut_line))) { + isLine = offset; + } + } + offset += sizeof(ut); + } + + if (isLine != -1) { + /* we've found a match */ + lseek(fh, isLine, SEEK_SET); + } else if (isEmpty != -1) { + /* no match found, but at least an empty entry */ + lseek(fh, isLine, SEEK_SET); + } else { + /* not even an empty entry found, assume we can append to the file */ + } + + if (time) + { + strncpy(ut.ut_line, line, sizeof(ut.ut_line)); + strncpy(ut.ut_name, user, sizeof(ut.ut_name)); + strncpy(ut.ut_host, host, sizeof(ut.ut_host)); + ut.ut_time = time; + } + else + { + memset(&ut, 0, sizeof(ut)); + } + write(fh, &ut, sizeof(ut)); + close(fh); +} +#endif Index: ftdemo.c =================================================================== --- ftdemo.c (nonexistent) +++ ftdemo.c (revision 174) @@ -0,0 +1,156 @@ +/* + * Demonstration program for freetype truetype font support + * Martin Jolicoeur 2000 martinj@visuaide.com. + */ +#include +#define MWINCLUDECOLORS +#include "nano-X.h" + +#if HAVE_T1LIB_SUPPORT +#define FONTNAME "bchr" +#if 0 +#define FONTNAME "bchb" +#define FONTNAME "dcr10" +#define FONTNAME "dcbx10" +#endif +#elif HAVE_FREETYPE_SUPPORT +#define FONTNAME "lt1-r-omega-serif" +#if 0 +#define FONTNAME "times" +#define FONTNAME "cour" +#endif +#else +#define FONTNAME GR_FONT_SYSTEM_VAR +#endif + +#define MAXW 400 +#define MAXH 400 + +GR_GC_ID gid; +GR_FONT_ID fontid, fontid2; +GR_BOOL kerning = GR_FALSE; +GR_BOOL aa = GR_TRUE; +GR_BOOL underline = GR_FALSE; +int angle = 0; +int state = GR_TFBOTTOM; +char buffer[128]; +int n; +void Render(GR_WINDOW_ID window); + +int +main() +{ + FILE *file; + GR_EVENT event; + GR_WINDOW_ID window; + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + window = GrNewWindow(GR_ROOT_WINDOW_ID, 50,50, MAXW,MAXH, 4, BLACK, WHITE); + GrMapWindow(window); + + gid = GrNewGC (); + GrSelectEvents(window, GR_EVENT_MASK_KEY_DOWN | + GR_EVENT_MASK_CLOSE_REQ | GR_EVENT_MASK_EXPOSURE); + + if ((file = fopen("ftdemo.txt", "r")) == NULL) { + printf("Can't open text file\n"); + return (-1); + } + + n = 0; + + if(fgets(buffer, 128, file) != NULL) { + for (n = 0; n < 128 && buffer[n]; n++) { + if (buffer[n] == '\n') + break; + } + } + fclose(file); + + fontid = GrCreateFont(FONTNAME, 20, NULL); + fontid2 = GrCreateFont(FONTNAME, 36, NULL); + + Render(window); + + while (1) { + GrGetNextEvent(&event); + + switch (event.type) { + case GR_EVENT_TYPE_KEY_DOWN: + switch(event.keystroke.ch) { + case 171: /* + */ + case '+': + case '=': + angle += 100; /* Increase 10 degrees */ + angle %= 3600; + break; + case 173: /* - */ + case '-': + case '_': + angle -= 100; /* Decrease 10 degrees */ + angle %= 3600; + break; + case 'a': + aa = (aa == GR_FALSE)?GR_TRUE:GR_FALSE; + break; + case 'k': + kerning = (kerning == GR_FALSE)?GR_TRUE:GR_FALSE; + break; + case 'l': + state = (state == GR_TFBOTTOM)?GR_TFBASELINE: \ + (state == GR_TFBASELINE)?GR_TFTOP:GR_TFBOTTOM; + break; + case 'u': + underline = underline? GR_FALSE: GR_TRUE; + break; + default: + continue; + /* Unknown keystroke */ + } + Render(window); + break; + case GR_EVENT_TYPE_EXPOSURE: + Render(window); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + } + } + + return 0; +} + +void Render(GR_WINDOW_ID window) +{ + GrSetGCBackground(gid, WHITE); + GrSetGCForeground (gid, WHITE); + GrSetGCUseBackground(gid, GR_FALSE); + GrFillRect(window, gid, 0, 0, MAXW, MAXH); + GrSetGCForeground (gid, BLACK); + + /* Draw menu */ + GrSetGCFont(gid, fontid); + GrSetFontAttr(fontid, GR_TFKERNING | GR_TFANTIALIAS, 0); + GrText(window, gid, 5, 20, "+ Rotate string clockwise", 25, GR_TFASCII); + GrText(window, gid, 5, 40, "- Rotate string counter-clockwise", 34, GR_TFASCII); + GrText(window, gid, 5, 60, "a Toggle anti-aliasing", 22, GR_TFASCII); + GrText(window, gid, 5, 80, "k Toggle kerning", 16, GR_TFASCII); + GrText(window, gid, 5, 100, "u Toggle underline", 18, GR_TFASCII); + GrText(window, gid, 5, 120, "l Toggle alignment bottom/baseline/top", 39, GR_TFASCII); + + /* Draw test string */ + GrSetGCFont(gid, fontid2); + GrSetFontAttr(fontid2, (kerning?GR_TFKERNING:0) | (aa?GR_TFANTIALIAS:0) | + (underline?GR_TFUNDERLINE: 0), -1); + GrSetFontRotation(fontid2, angle); + GrText(window, gid, MAXW/2, MAXH/2, buffer, n, state|GR_TFUTF8); + + /* Draw arrow */ + GrLine (window, gid, (MAXW/2)-10 , MAXH/2, (MAXW/2)+10, MAXH/2); + GrLine (window, gid, MAXW/2, (MAXH/2)-10, MAXW/2, (MAXH/2)+10); +} Index: nxev.c =================================================================== --- nxev.c (nonexistent) +++ nxev.c (revision 174) @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2000 by VTech Informations LTD + * + * This program is released under MPL + * + * Vladimir Cotfas , Nov 7, 2000 + */ + +#include +#include +#include +#define MWINCLUDECOLORS +#include "nano-X.h" + + +static GR_WINDOW_ID w1; /* id for large window */ +static GR_WINDOW_ID w2; /* id for child window */ +static GR_GC_ID gc1; /* graphics context for text */ + +#define ALT_CURSOR + +#define WIDTH 100 +#define HEIGHT 100 + +#ifdef ALT_CURSOR +/* + * Definitions to make it easy to define cursors + */ +#define _ ((unsigned) 0) /* off bits */ +#define X ((unsigned) 1) /* on bits */ +#define MASK(a,b,c,d,e,f,g) \ + (((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) \ + + e) * 2) + f) * 2) + g) << 9) +#endif + +struct _xlat { + GR_UPDATE_TYPE type; + const char* name; +}; +typedef struct _xlat XLAT; + +static XLAT update_types[] = { + { 0, "none" }, + { GR_UPDATE_MAP, "GR_UPDATE_MAP" }, + { GR_UPDATE_UNMAP, "GR_UPDATE_UNMAP" }, + { GR_UPDATE_MOVE, "GR_UPDATE_MOVE" }, + { GR_UPDATE_SIZE, "GR_UPDATE_SIZE" }, + { GR_UPDATE_UNMAPTEMP, "GR_UPDATE_UNMAPTEMP" }, + { GR_UPDATE_ACTIVATE, "GR_UPDATE_ACTIVATE" }, + { GR_UPDATE_DESTROY, "GR_UPDATE_DESTROY" } +}; +#define NR_UPDATES 7 + +struct XLAT { + int event_type; + char* event_desc; +}; + +static struct XLAT table[] = { + { GR_EVENT_TYPE_ERROR, "GR_EVENT_TYPE_ERROR" }, + { GR_EVENT_TYPE_NONE, "GR_EVENT_TYPE_NONE" }, + { GR_EVENT_TYPE_EXPOSURE, "GR_EVENT_TYPE_EXPOSURE" }, + { GR_EVENT_TYPE_BUTTON_DOWN, "GR_EVENT_TYPE_BUTTON_DOWN" }, + { GR_EVENT_TYPE_BUTTON_UP, "GR_EVENT_TYPE_BUTTON_UP" }, + { GR_EVENT_TYPE_MOUSE_ENTER, "GR_EVENT_TYPE_MOUSE_ENTER" }, + { GR_EVENT_TYPE_MOUSE_EXIT, "GR_EVENT_TYPE_MOUSE_EXIT" }, + { GR_EVENT_TYPE_MOUSE_MOTION, "GR_EVENT_TYPE_MOUSE_MOTION" }, + { GR_EVENT_TYPE_MOUSE_POSITION, "GR_EVENT_TYPE_MOUSE_POSITION" }, + { GR_EVENT_TYPE_KEY_DOWN, "GR_EVENT_TYPE_KEY_DOWN" }, + { GR_EVENT_TYPE_KEY_UP, "GR_EVENT_TYPE_KEY_UP" }, + { GR_EVENT_TYPE_FOCUS_IN, "GR_EVENT_TYPE_FOCUS_IN" }, + { GR_EVENT_TYPE_FOCUS_OUT, "GR_EVENT_TYPE_FOCUS_OUT" }, + { GR_EVENT_TYPE_FDINPUT, "GR_EVENT_TYPE_FDINPUT" }, + { GR_EVENT_TYPE_UPDATE, "GR_EVENT_TYPE_UPDATE" }, + { GR_EVENT_TYPE_CHLD_UPDATE, "GR_EVENT_TYPE_CHLD_UPDATE" }, + { GR_EVENT_TYPE_CLOSE_REQ, "GR_EVENT_TYPE_CLOSE_REQ" }, +}; + +#define table_SZ (sizeof(table) / sizeof(table[0])) + +char* +lookupEvent(int type) +{ + int i; + + for (i = 0; i < table_SZ; i++) + if (table[i].event_type == type) + return table[i].event_desc; + + return NULL; +} + +int +main(int argc, char **argv) +{ + GR_EVENT event; /* current event */ + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + GrReqShmCmds(65536); /* shared mem is suposed to be faster */ + + w1 = GrNewWindow(GR_ROOT_WINDOW_ID, + 0, 0, + WIDTH, HEIGHT, + 4, + WHITE, BLACK); + GrSelectEvents(w1, 0xffffffffl); /* all events :) */ + + w2 = GrNewWindow(w1, + 10, 10, + WIDTH / 4, HEIGHT / 4, + 4, + WHITE, BLACK); + GrSelectEvents(w2, 0xffffffffl); /* all events :) */ + + + { + GR_WM_PROPERTIES props; + + props.flags = GR_WM_FLAGS_PROPS | GR_WM_FLAGS_TITLE; + + props.props = GR_WM_PROPS_BORDER | GR_WM_PROPS_CAPTION | \ + GR_WM_PROPS_CAPTION | GR_WM_PROPS_CLOSEBOX; + props.title = "nano-X Events"; + GrSetWMProperties(w1, &props); + } + + GrMapWindow(w1); + GrMapWindow(w2); + + gc1 = GrNewGC(); + + GrSetGCForeground(gc1, BLACK); + GrSetGCBackground(gc1, WHITE); + + +#ifdef ALT_CURSOR + { + GR_BITMAP bitmap1fg[7]; /* bitmaps for cursor */ + GR_BITMAP bitmap1bg[7]; + + bitmap1bg[0] = MASK(X,X,X,X,X,X,X); + bitmap1bg[1] = MASK(_,X,X,X,X,X,_); + bitmap1bg[2] = MASK(_,_,X,X,X,_,_); + bitmap1bg[3] = MASK(_,_,_,X,_,_,_); + bitmap1bg[4] = MASK(_,_,X,X,X,_,_); + bitmap1bg[5] = MASK(_,X,X,X,X,X,_); + bitmap1bg[6] = MASK(X,X,X,X,X,X,X); + + bitmap1fg[0] = MASK(X,X,X,X,X,X,X); + bitmap1fg[1] = MASK(_,X,X,X,X,X,_); + bitmap1fg[2] = MASK(_,_,X,X,X,_,_); + bitmap1fg[3] = MASK(_,_,_,X,_,_,_); + bitmap1fg[4] = MASK(_,_,X,X,X,_,_); + bitmap1fg[5] = MASK(_,X,X,X,X,X,_); + bitmap1fg[6] = MASK(X,X,X,X,X,X,X); + + GrSetCursor(w1, 7, 7, 3, 3, WHITE, BLACK, bitmap1fg, bitmap1bg); + } +#endif + + + for (;;) { + GrGetNextEvent(&event); + + printf("%s (0x%x)\n", \ + lookupEvent(event.type), event.type); + + switch(event.type) { + case GR_EVENT_TYPE_EXPOSURE: + { + printf("\twid = %d\n", event.exposure.wid); + printf("\t(X, Y) = (%d, %d)\n", \ + event.exposure.x, event.exposure.y); + printf("\twidth = %d, height = %d\n", \ + event.exposure.width, event.exposure.height); + } + break; + case GR_EVENT_TYPE_BUTTON_DOWN: + case GR_EVENT_TYPE_BUTTON_UP: + { + printf("\twid = %d\n", event.button.wid); + printf("\tsub-window id = %d\n", event.button.subwid); + printf("\troot window (X, Y) coordinates = (%d, %d)\n", \ + event.button.rootx, event.button.rooty); + printf("\t(X, Y) = (%d, %d)\n", \ + event.button.x, event.button.y); + printf("\tbuttons: %04X, ", event.button.buttons); + printf("changed buttons: %04X\n", event.button.changebuttons); + printf("\tmodifiers: %04X\n", event.button.modifiers); + } + break; + case GR_EVENT_TYPE_MOUSE_ENTER: + case GR_EVENT_TYPE_MOUSE_EXIT: + case GR_EVENT_TYPE_MOUSE_MOTION: + case GR_EVENT_TYPE_MOUSE_POSITION: + { + printf("\twid = %d\n", event.mouse.wid); + printf("\tsub-window id = %d\n", event.mouse.subwid); + printf("\troot window (X, Y) coordinates = (%d, %d)\n", \ + event.mouse.rootx, event.mouse.rooty); + printf("\t(X, Y) = (%d, %d)\n", \ + event.mouse.x, event.mouse.y); + printf("\tbuttons: %04X\n", event.mouse.buttons); + printf("\tmodifiers: %04X\n", event.mouse.modifiers); + } + break; + case GR_EVENT_TYPE_KEY_DOWN: + case GR_EVENT_TYPE_KEY_UP: + { + printf("\twid = %d\n", event.keystroke.wid); + printf("\tsub-window id = %d\n", event.keystroke.subwid); + printf("\troot window (X, Y) coordinates = (%d, %d)\n", \ + event.keystroke.rootx, event.keystroke.rooty); + printf("\t(X, Y) = (%d, %d)\n", \ + event.keystroke.x, event.keystroke.y); + printf("\tbuttons: %04X\n", event.keystroke.buttons); + printf("\tmodifiers: %04X\n", event.keystroke.modifiers); + printf("\tUnicode-16 keyvalue: %d, ASCII: %d\n", \ + (int)event.keystroke.ch, event.keystroke.ch); + printf("\tscancode: %02X\n", + (int)event.keystroke.scancode); + } + break; + case GR_EVENT_TYPE_FOCUS_IN: + printf("\twid = %d\n", event.general.wid); + printf("\told focus = %d\n", event.general.otherid); + break; + case GR_EVENT_TYPE_FOCUS_OUT: + printf("\twid = %d\n", event.general.wid); + printf("\tnew focus = %d\n", event.general.otherid); + break; + case GR_EVENT_TYPE_UPDATE: + case GR_EVENT_TYPE_CHLD_UPDATE: + { + printf("\twid = %d\n", event.update.wid); + printf("\tsub-window id = %d\n", event.update.subwid); + printf("\t(X, Y) = (%d, %d)\n", \ + event.update.x, event.update.y); + printf("\twidth = %d, height = %d\n", \ + event.update.width, event.update.height); + { + GR_UPDATE_TYPE u = event.update.utype; + const char* p; + + p = (u > NR_UPDATES)? \ + "": \ + update_types[u].name; + + printf("\tupdate_type: %s (%d)\n", + p, u); + } + } + break; + case GR_EVENT_TYPE_TIMEOUT: + printf("\ttimeout?\n"); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + /* no return*/ + } + } + + return 0; +} Index: nxterm.h =================================================================== --- nxterm.h (nonexistent) +++ nxterm.h (revision 174) @@ -0,0 +1,65 @@ +/* These contained 'pt:re=\\EC' entries. I deleted them from MiNT and linux + * because neither of my (linux) termcap nor terminfo manual pages listed + * them. + * ++eero + */ +#ifdef __MINT__ + +static char termcap_string[1024] = +"TERMCAP=wterm|WTerm terminal:al=\\EL:am:bc=\\ED:bl=^G:bs:cd=\\EJ:\ +ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:is=\\Ev\\Eq:\ +l0=F10:le=\\ED:ms:nd=\\EC:rc=\\Ek:rs=\\Ev\\Eq\\EE:sc=\\Ej:sr=\\EI:\ +ti=\\Ev\\Ee\\EG:up=\\EA:ve=\\Ee:vi=\\Ef:so=\\Ep:se=\\Eq:mb=\\Ei:md=\\Eg:\ +mr=\\Ep:me=\\EG:te=\\EG:us=\\Ei:ue=\\EG:\ +kb=^H:kl=\\ED:kr=\\EC:ku=\\EA:kd=\\EB:kI=\\EI:kh=\\EE:kP=\\Ea:kN=\\Eb:k0=\\EY:\ +k1=\\EP:k2=\\EQ:k3=\\ER:k4=\\ES:k5=\\ET:k6=\\EU:k7=\\EV:k8=\\EW:k9=\\EX:\ +s0=\\Ey:s1=\\Ep:s2=\\Eq:s3=\\Er:s4=\\Es:s5=\\Et:s6=\\Eu:s7=\\Ev:s8=\\Ew:\ +s9=\\Ex:"; + +#elif defined(linux) || defined(__FreeBSD__) + +static char termcap_string[1024] = +"TERMCAP=wterm|WTerm terminal:al=\\EL:am:bc=\\ED:bl=^G:bs:cd=\\EJ:\ +ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:is=\\Ev\\Eq:\ +l0=F10:le=\\ED:ms:nd=\\EC:rc=\\Ek:rs=\\Ev\\Eq\\EE:sc=\\Ej:sr=\\EI:\ +ti=\\Ev\\Ee\\EG:up=\\EA:ve=\\Ee:vi=\\Ef:so=\\Ep:se=\\Eq:mb=\\Ei:md=\\Eg:\ +mr=\\Ep:me=\\EG:te=\\EG:us=\\Ei:ue=\\EG:\ +kb=^H:kl=\\E[D:kr=\\E[C:ku=\\E[A:kd=\\E[B:kI=\\EI:kh=\\EE:kP=\\Ea:kN=\\Eb:\ +k0=\\EY:k1=\\EP:k2=\\EQ:k3=\\ER:k4=\\ES:k5=\\ET:k6=\\EU:k7=\\EV:k8=\\EW:\ +k9=\\EX:s0=\\Ey:s1=\\Ep:s2=\\Eq:s3=\\Er:s4=\\Es:s5=\\Et:s6=\\Eu:s7=\\Ev:\ +s8=\\Ew:s9=\\Ex:"; + +#elif defined(sun) + + /* only very basic cursor keys so far... */ + +static char termcap_string[1024] = +"TERMCAP=wterm|WTerm terminal:al=\\EL:am:bc=\\ED:bl=^G:bs:cd=\\EJ:\ +ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:is=\\Ev\\Eq:\ +l0=F10:le=\\ED:ms:nd=\\EC:pt:re=\\EC:rc=\\Ek:rs=\\Ev\\Eq\\EE:sc=\\Ej:sr=\\EI:\ +ti=\\Ev\\Ee\\EG:up=\\EA:ve=\\Ee:vi=\\Ef:so=\\Ep:se=\\Eq:mb=\\Ei:md=\\Eg:\ +mr=\\Ep:me=\\EG:te=\\EG:us=\\Ei:ue=\\EG:\ +kb=^H:kl=\\E[D:kr=\\E[C:ku=\\E[A:kd=\\E[B:\ +k1=\\E[224z:k2=\\E[225z:k3=\\E[226z:k4=\\E[227z:k5=\\E[228z:\ +k6=\\E[229z:k7=\\E[230z:k8=\\E[231z:k9=\\E[232z:k0=\\E[233z:\ +kN=\\E[222z:kP=\\E[216z:kh=\\E[214z:kH=\\E220z:"; + +#elif defined(__NetBSD__) + +static char termcap_string[1024] = +"TERMCAP=wterm|WTerm terminal:al=\\EL:am:bc=\\ED:bl=^G:bs:cd=\\EJ:\ +ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:is=\\Ev\\Eq:\ +l0=F10:le=\\ED:ms:nd=\\EC:pt:re=\\EC:rc=\\Ek:rs=\\Ev\\Eq\\EE:sc=\\Ej:sr=\\EI:\ +ti=\\Ev\\Ee\\EG:up=\\EA:ve=\\Ee:vi=\\Ef:so=\\Ep:se=\\Eq:mb=\\Ei:md=\\Eg:\ +mr=\\Ep:me=\\EG:te=\\EG:us=\\Ei:ue=\\EG:\ +kb=^H:kl=\\E[D:kr=\\E[C:ku=\\E[A:kd=\\E[B:\ +k1=\\E[224z:k2=\\E[225z:k3=\\E[226z:k4=\\E[227z:k5=\\E[228z:\ +k6=\\E[229z:k7=\\E[230z:k8=\\E[231z:k9=\\E[232z:k0=\\E[233z:\ +kN=\\E[222z:kP=\\E[216z:kh=\\E[214z:kH=\\E220z:"; + +#else + +#error oops, a new operating system? + +#endif + Index: slider.c =================================================================== --- slider.c (nonexistent) +++ slider.c (revision 174) @@ -0,0 +1,344 @@ +/* Copyright (c) 2000 Simon Wood + * + * This program is licensed under the same terms that Microwindows + * and Nano-X are licensed under. See the file LICENSE accompanying + * this distribution. + */ + +#include +#include +#include +#include + +#define MWINCLUDECOLORS +#include "nano-X.h" + +/* set up size of the grid */ +#define WIDTH_IN_TILES 4 +#define HEIGHT_IN_TILES 4 +#define MAX_TILES (WIDTH_IN_TILES * HEIGHT_IN_TILES) +#define USE_IMAGE 1 + +static int value[WIDTH_IN_TILES][HEIGHT_IN_TILES]; +static int calc_width, calc_height; +static int tile_width = 40; +static int tile_height = 40; + +#if USE_IMAGE +static void * image_addr; +static int using_image = 1; +static GR_WINDOW_ID image; /* storage area for image */ +#endif + +static GR_WINDOW_ID master; /* id for whole window */ +static GR_WINDOW_ID buttons; /* id for buttons */ +static GR_WINDOW_ID tiles; /* id for play area */ +static GR_GC_ID gc1; /* graphics context for text */ + +static int value[WIDTH_IN_TILES][HEIGHT_IN_TILES]; + +/* function prototypes */ +static void HandleEvents(); +static void RefreshWindow(); +static void RandomiseTiles(); +static void MoveTile(); +static void DrawTile(); + +int +main(int argc,char **argv) +{ + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + gc1 = GrNewGC(); + +#if USE_IMAGE + image = GrNewWindow(GR_ROOT_WINDOW_ID, 300, 0, (WIDTH_IN_TILES * tile_width), + (HEIGHT_IN_TILES * tile_height), 4, BLACK, WHITE); + + if(argc != 2) + /* No image specified, use numered tiles */ + using_image = 0; + else { + /* need to find out image size.... */ + image_addr = malloc(4 * (WIDTH_IN_TILES * tile_width) * + (HEIGHT_IN_TILES * tile_height) ); + + image = GrNewPixmap((WIDTH_IN_TILES * tile_width), + (HEIGHT_IN_TILES * tile_height), image_addr); + + GrDrawImageFromFile(image, gc1, 0, 0, + GR_IMAGE_MAX_SIZE, GR_IMAGE_MAX_SIZE, argv[1], 0); + } +#endif + + /* calculate size of tile area */ + calc_width = 10 + (WIDTH_IN_TILES * tile_width); + calc_height = 15 + 35 + (HEIGHT_IN_TILES * tile_height); +#if 0 + /* enforce minimum size */ + if (calc_width < 240) calc_width=240; + if (calc_height < 320) calc_height=320; +#endif + master = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, calc_width, calc_height, 1, RED, WHITE); + buttons = GrNewWindow((GR_WINDOW_ID) master, 5, 5, (calc_width - 5), 35, 1, RED, RED); + + tiles = GrNewWindow((GR_WINDOW_ID) master, (calc_width/2) - (WIDTH_IN_TILES * tile_width /2), + 45 + ((calc_height - 50)/2) - (HEIGHT_IN_TILES * tile_height /2), + (WIDTH_IN_TILES * tile_width), (HEIGHT_IN_TILES * tile_height), 1, RED, RED); + + GrMapWindow(master); + GrMapWindow(buttons); + GrMapWindow(tiles); + + /* set random seed */ + srandom((int) getpid()); + + RandomiseTiles(); + + GrSelectEvents(master, GR_EVENT_MASK_EXPOSURE|GR_EVENT_MASK_CLOSE_REQ); + GrSelectEvents(buttons, GR_EVENT_MASK_BUTTON_DOWN); + GrSelectEvents(tiles, GR_EVENT_MASK_BUTTON_DOWN); + + RefreshWindow(); + + while (GR_TRUE) { + GR_EVENT event; + + GrGetNextEvent(&event); + HandleEvents(&event); + } +} + + +/* + * Read the next event and handle it. + */ +void +HandleEvents(GR_EVENT *ep) +{ + switch (ep->type) { + case GR_EVENT_TYPE_BUTTON_DOWN: + if (ep->button.wid == buttons) { + if (ep->button.x < (calc_width/2)) { + /* 'Again' */ + RandomiseTiles(); + RefreshWindow(); + } else { + /* 'Quit' */ + GrClose(); +#if USE_IMAGE + if (using_image) + free(image_addr); +#endif + exit(0); + } + } + + if (ep->button.wid == tiles) { + /* Try to move selected tile */ + MoveTile( (int)(ep->button.x / tile_width), + (int)(ep->button.y / tile_height) ); + } + break; + + case GR_EVENT_TYPE_EXPOSURE: + RefreshWindow(); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + } + +} + +void +RefreshWindow() +{ + int xpos, ypos; + + GrSetGCForeground(gc1, WHITE); + GrSetGCBackground(gc1, RED); + + /* draw the buttons */ + GrRect(buttons, gc1, 0, 0, (calc_width - 12)/2, 34); + GrRect(buttons, gc1, (calc_width - 8)/2, 0, (calc_width - 12)/2, 34); + +#if 0 /* for when center align text works */ + GrText(buttons, gc1, (calc_width - 10)/4, 22, "Again", 5, 0); + GrText(buttons, gc1, (calc_width - 10)*3/4, 22, "Quit", 4, 0); +#else + GrText(buttons, gc1, 5, 22, "Again", 5, 0); + GrText(buttons, gc1, (calc_width / 2) + 5, 22, "Quit", 4, 0); +#endif + + /* draw the tiles */ + for (ypos=0; ypos< HEIGHT_IN_TILES; ypos++){ + for (xpos=0; xpos< WIDTH_IN_TILES; xpos++){ + DrawTile(xpos, ypos); + } + } +} + +void +RandomiseTiles() +{ + int count, xpos, ypos; + + /* allocate all the numbers in order 1..MAX_TILES */ + for (ypos=0; ypos< HEIGHT_IN_TILES; ypos++){ + for (xpos=0; xpos< WIDTH_IN_TILES; xpos++){ + value[xpos][ypos] = 1 + xpos + (WIDTH_IN_TILES * ypos); + } + } + + /* position of 'hole' */ + xpos = WIDTH_IN_TILES - 1; + ypos = HEIGHT_IN_TILES - 1; + + /* randomly slide them around, ALL games can therefore solved - so no excusses!! */ + for (count=0; count< MAX_TILES * 1000; count++){ + switch(random() % 4) { + case 0: + if (ypos < HEIGHT_IN_TILES - 1) { + value[xpos][ypos] = value[xpos][ypos+1]; + ypos++; + value[xpos][ypos] = MAX_TILES; + } + break; + case 1: + if (xpos > 0) { + value[xpos][ypos] = value[xpos - 1][ypos]; + xpos--; + value[xpos][ypos] = MAX_TILES; + } + break; + case 2: + if (ypos > 0) { + value[xpos][ypos] = value[xpos][ypos - 1]; + ypos--; + value[xpos][ypos] = MAX_TILES; + } + break; + case 3: + if (xpos < WIDTH_IN_TILES - 1) { + value[xpos][ypos] = value[xpos + 1][ypos]; + xpos++; + value[xpos][ypos] = MAX_TILES; + } + break; + } + } +} + +void +MoveTile(xpos, ypos) + int xpos, ypos; +{ + /* check all possible moves to see if there is the blank (N,E,S,W) */ + if (ypos > 0 && value[xpos][ypos - 1] == MAX_TILES) { + value[xpos][ypos - 1] = value[xpos][ypos]; + value[xpos][ypos] = MAX_TILES; + DrawTile(xpos, ypos - 1); + DrawTile(xpos, ypos); + } + + if (xpos < (WIDTH_IN_TILES - 1) && value[xpos + 1][ypos] == MAX_TILES) { + value[xpos + 1][ypos] = value[xpos][ypos]; + value[xpos][ypos] = MAX_TILES; + DrawTile(xpos + 1, ypos); + DrawTile(xpos, ypos); + } + + if (ypos < (HEIGHT_IN_TILES - 1) && value[xpos][ypos + 1] == MAX_TILES) { + value[xpos][ypos + 1] = value[xpos][ypos]; + value[xpos][ypos] = MAX_TILES; + DrawTile(xpos, ypos + 1); + DrawTile(xpos, ypos); + } + + if (xpos > 0 && value[xpos - 1][ypos] == MAX_TILES) { + value[xpos - 1][ypos] = value[xpos][ypos]; + value[xpos][ypos] = MAX_TILES; + DrawTile(xpos - 1, ypos); + DrawTile(xpos, ypos); + } + + /* check for a winner */ + if (value[WIDTH_IN_TILES - 1][HEIGHT_IN_TILES - 1] == MAX_TILES) { + int winner = 0; + for (ypos=0; ypos< HEIGHT_IN_TILES; ypos++){ + for (xpos=0; xpos< WIDTH_IN_TILES; xpos++){ + if (value[xpos][ypos] == winner + 1) + winner++; + else + winner=0; + } + } + if (winner == MAX_TILES) { + /* Do winning screen */ + int loop = MAX_TILES; + for(loop=0; loop < MAX_TILES; loop++) { + for(winner=0; winner < (MAX_TILES - loop) ; winner++) { + + /* move tiles around */ + xpos = winner % WIDTH_IN_TILES; + ypos = (int)(winner/WIDTH_IN_TILES); + value[xpos][ypos] = loop + winner + 1; + DrawTile(winner % WIDTH_IN_TILES, (int)(winner/WIDTH_IN_TILES)); + } + GrFlush(); + for(winner=0; winner < 10000000 ; winner++); + /* delay loop */ + } + /* Print message */ + GrSetGCForeground(gc1, WHITE); + GrSetGCBackground(gc1, RED); + GrText(tiles, gc1, ((WIDTH_IN_TILES * tile_width)/2) - 40, (HEIGHT_IN_TILES * tile_height)/2, "Well Done!!", -1, 0); + } + + } +} + + +void +DrawTile(xpos, ypos) + int xpos, ypos; +{ + char text[]="00"; + + /* blank out old tile */ + GrSetGCForeground(gc1, RED); + GrFillRect(tiles, gc1, (xpos* tile_width), (ypos*tile_height), tile_width, tile_height); + + if (value[xpos][ypos] != MAX_TILES ) { + /* re-draw tile and number */ + GrSetGCForeground(gc1, WHITE); + GrSetGCBackground(gc1, RED); + GrRect(tiles, gc1, (xpos*tile_width), (ypos*tile_height), tile_width, tile_height); + +#if USE_IMAGE + if (using_image) { + /* copy from image window */ + GrCopyArea(tiles, gc1, 1 + (xpos*tile_width), 1 + (ypos*tile_height), + tile_width - 2, tile_height - 2, image, + 1 + (((value[xpos][ypos] - 1) % WIDTH_IN_TILES) * tile_width), + 1 + (((int)(value[xpos][ypos] - 1) / WIDTH_IN_TILES) * tile_height), 0); + } else { +#endif + /* label the tile with a number */ + if (value[xpos][ypos] > 9) + text[0] = 48 + (int)(value[xpos][ypos]/10); + else + text[0] = 32; + + text[1] = 48 + value[xpos][ypos] % 10; + + GrText(tiles, gc1, (xpos*tile_width) + (tile_width /2) - 5, (ypos*tile_height) + (tile_height/2) + 5, &text, -1, 0); +#if USE_IMAGE + } +#endif + } +} Index: polytest.c =================================================================== --- polytest.c (nonexistent) +++ polytest.c (revision 174) @@ -0,0 +1,160 @@ +#include +#include "nano-X.h" + +void draw(GR_EVENT * e) +{ + GR_GC_ID gc; + GR_POINT points[4]; + + int x = 10; + int y = 10; + int sz = 20; + int sz2 = 5; + + gc = GrNewGC(); + + GrSetGCBackground(gc, GR_RGB(0,0,0)); + //GrSetGCMode(gc, GR_MODE_XOR); + + points[0].x = x; + points[0].y = y; + + points[1].x = x + sz; + points[1].y = y; + + points[2].x = x + (sz/2) ; + points[2].y = y + sz; + + GrSetGCForeground(gc, GR_RGB(255,255,255)); + GrFillPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,3,points); + points[3].x = x; + points[3].y = y; + GrSetGCForeground(gc,GR_RGB(0,255,0)); + GrPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,4,points); + + y += sz + 10; + + points[0].x = x; + points[0].y = y; + + points[1].x = x + sz + 1; + points[1].y = y; + + points[2].x = x + (sz/2) ; + points[2].y = y + sz; + + GrSetGCForeground(gc, GR_RGB(255,255,255)); + GrFillPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,3,points); + points[3].x = x; + points[3].y = y; + GrSetGCForeground(gc,GR_RGB(0,255,0)); + GrPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,4,points); + + y += sz + 10; + + points[0].x = x; + points[0].y = y; + + points[1].x = x + sz - 1; + points[1].y = y; + + points[2].x = x + (sz/2) ; + points[2].y = y + sz; + + GrSetGCForeground(gc, GR_RGB(255,255,255)); + GrFillPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,3,points); + points[3].x = x; + points[3].y = y; + GrSetGCForeground(gc,GR_RGB(0,255,0)); + GrPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,4,points); + + /* draw right arrow*/ + sz = 10; + sz2 = 8; + + x = 60; + y = 60; + + points[0].x = x; + points[0].y = y; + + y -= sz; + + points[1].x = x + sz2; + points[1].y = y; + + y -= sz; + + points[2].x = x; + points[2].y = y; + + GrSetGCForeground(gc, GR_RGB(255,255,255)); + GrFillPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,3,points); + + points[3].x = x; + points[3].y = 60; + + GrSetGCForeground(gc,GR_RGB(0,255,0)); + GrPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,4,points); + + GrSetGCForeground(gc,GR_RGB(255,255,255)); + + x = 60; + y = 90; + + points[0].x = x; + points[0].y = y; + + y -= sz; + + points[1].x = x + sz2; + points[1].y = y; + + y -= sz; + + points[2].x = x; + points[2].y = y; + + GrSetGCForeground(gc, GR_RGB(255,255,255)); + GrFillPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,3,points); + points[3].x = x; + points[3].y = 90; + //GrPoly(((GR_EVENT_EXPOSURE*)e)->wid,gc,4,points); + + GrDestroyGC(gc); +} + +main() +{ + GR_EVENT event; + GR_WINDOW_ID w; + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + /* create window*/ + w = GrNewWindowEx( + GR_WM_PROPS_NOAUTOMOVE|GR_WM_PROPS_BORDER|GR_WM_PROPS_CAPTION| + GR_WM_PROPS_CLOSEBOX, "POLY FILL", GR_ROOT_WINDOW_ID, + 10, 10, 100, 300, GR_RGB(0,0,0)); + // w = GrNewWindow(0,100,100,100,100,3,GR_RGB(0,0,255),GR_RGB(0,0,0)); + + GrSelectEvents(w, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_CLOSE_REQ); + GrMapWindow(w); + + while (1) { + GrGetNextEvent(&event); + + switch (event.type) { + case GR_EVENT_TYPE_EXPOSURE: + draw(&event); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + } + } + +} Index: nterm.c =================================================================== --- nterm.c (nonexistent) +++ nterm.c (revision 174) @@ -0,0 +1,328 @@ +/* + * Nano-X terminal emulator + * + * Al Riddoch + * Greg Haerr + */ + +#include +#include +#include +#include +#include +#include + +#define MWINCLUDECOLORS +#include "nano-X.h" + +#define HAVEBLIT 0 /* set if have bitblit (experimental)*/ + +#define _ ((unsigned) 0) /* off bits */ +#define X ((unsigned) 1) /* on bits */ +#define MASK(a,b,c,d,e,f,g) \ + (((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) \ + + e) * 2) + f) * 2) + g) << 9) + +#if DOS_DJGPP +#define SIGCHLD 17 /* from Linux */ +#endif + +static GR_WINDOW_ID w1; /* id for window */ +static GR_GC_ID gc1; /* graphics context */ +static GR_GC_ID gc3; /* graphics context */ +static GR_COORD xpos; /* x coord for text */ +static GR_COORD ypos; /* y coord for text */ +static GR_SCREEN_INFO si; /* screen info */ +static int tfd; + +void do_buttondown(); +void do_buttonup(); +void do_motion(); +void text_init(); +int term_init(); +void do_keystroke(); +void do_focusin(); +void do_focusout(); +void do_enter(); +void do_exit(); +void do_fdinput(); +void printg(); +void HandleEvent(GR_EVENT *ep); + +int main(int argc, char ** argv) +{ + GR_BITMAP bitmap1fg[7]; /* mouse cursor */ + GR_BITMAP bitmap1bg[7]; + + if (GrOpen() < 0) { + fprintf(stderr, "cannot open graphics\n"); + exit(1); + } + + GrGetScreenInfo(&si); + + w1 = GrNewWindow(GR_ROOT_WINDOW_ID, 50, 30, si.cols - 120, + si.rows - 60, 1, WHITE, LTBLUE); + + GrSelectEvents(w1, GR_EVENT_MASK_BUTTON_DOWN | + GR_EVENT_MASK_KEY_DOWN | GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_FOCUS_IN | GR_EVENT_MASK_FOCUS_OUT | + GR_EVENT_MASK_CLOSE_REQ); + + GrMapWindow(w1); + + gc1 = GrNewGC(); + gc3 = GrNewGC(); + + GrSetGCForeground(gc1, GRAY); + GrSetGCBackground(gc1, LTBLUE); + GrSetGCFont(gc1, GrCreateFont(GR_FONT_SYSTEM_FIXED, 0, NULL)); + /*GrSetGCFont(gc1, GrCreateFont(GR_FONT_OEM_FIXED, 0, NULL));*/ + GrSetGCForeground(gc3, WHITE); + GrSetGCBackground(gc3, BLACK); + + bitmap1fg[0] = MASK(_,_,X,_,X,_,_); + bitmap1fg[1] = MASK(_,_,_,X,_,_,_); + bitmap1fg[2] = MASK(_,_,_,X,_,_,_); + bitmap1fg[3] = MASK(_,_,_,X,_,_,_); + bitmap1fg[4] = MASK(_,_,_,X,_,_,_); + bitmap1fg[5] = MASK(_,_,_,X,_,_,_); + bitmap1fg[6] = MASK(_,_,X,_,X,_,_); + + bitmap1bg[0] = MASK(_,X,X,X,X,X,_); + bitmap1bg[1] = MASK(_,_,X,X,X,_,_); + bitmap1bg[2] = MASK(_,_,X,X,X,_,_); + bitmap1bg[3] = MASK(_,_,X,X,X,_,_); + bitmap1bg[4] = MASK(_,_,X,X,X,_,_); + bitmap1bg[5] = MASK(_,_,X,X,X,_,_); + bitmap1bg[6] = MASK(_,X,X,X,X,X,_); + + GrSetCursor(w1, 7, 7, 3, 3, WHITE, BLACK, bitmap1fg, bitmap1bg); + + /*GrFillRect(GR_ROOT_WINDOW_ID, gc1, 0, 0, si.cols, si.rows);*/ + + GrSetGCForeground(gc1, BLACK); + GrSetGCBackground(gc1, WHITE); + text_init(); + if (term_init() < 0) { + GrClose(); + exit(1); + } + + /* we want tfd events also*/ + GrRegisterInput(tfd); + +#if 1 + GrMainLoop(HandleEvent); +#else + while(1) { + GR_EVENT ev; + + GrGetNextEvent(&ev); + HandleEvent(&ev); + } +#endif + /* notreached*/ + return 0; +} + +void +HandleEvent(GR_EVENT *ep) +{ + switch (ep->type) { + case GR_EVENT_TYPE_KEY_DOWN: + do_keystroke(&ep->keystroke); + break; + + case GR_EVENT_TYPE_FOCUS_IN: + do_focusin(&ep->general); + break; + + case GR_EVENT_TYPE_FOCUS_OUT: + do_focusout(&ep->general); + break; + + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + + case GR_EVENT_TYPE_FDINPUT: + do_fdinput(); + break; + } +} + +#if ELKS +char * nargv[2] = {"/bin/sash", NULL}; +#else +#if DOS_DJGPP +char * nargv[2] = {"bash", NULL}; +#else +char * nargv[2] = {"/bin/sh", NULL}; +#endif +#endif + +void sigchild(int signo) +{ + printg("We have a signal right now!\n"); + GrClose(); + exit(0); +} + +int term_init() +{ + char pty_name[12]; + int n = 0; + pid_t pid; + +again: + sprintf(pty_name, "/dev/ptyp%d", n); + if ((tfd = open(pty_name, O_RDWR | O_NONBLOCK)) < 0) { + if ((errno == EBUSY || errno == EIO) && n < 10) { + n++; + goto again; + } + fprintf(stderr, "Can't create pty %s\n", pty_name); + return -1; + } + signal(SIGCHLD, sigchild); + signal(SIGINT, sigchild); + if ((pid = fork()) == -1) { + fprintf(stderr, "No processes\n"); + return -1; + } + if (!pid) { + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + close(tfd); + + setsid(); + pty_name[5] = 't'; + if ((tfd = open(pty_name, O_RDWR)) < 0) { + fprintf(stderr, "Child: Can't open pty %s\n", pty_name); + exit(1); + } + dup2(tfd, STDIN_FILENO); + dup2(tfd, STDOUT_FILENO); + dup2(tfd, STDERR_FILENO); + execv(nargv[0], nargv); + exit(1); + } + return 0; +} + + +GR_SIZE width; /* width of character */ +GR_SIZE height; /* height of character */ +GR_SIZE base; /* height of baseline */ + +void text_init() +{ + GrGetGCTextSize(gc1, "A", 1, GR_TFASCII, &width, &height, &base); +} + +void char_del(GR_COORD x, GR_COORD y) +{ + xpos -= width; + GrFillRect(w1, gc3, x, y /*- height*/ /*+ base*/ + 1, width, height); +} + +void char_out(GR_CHAR ch) +{ + switch(ch) { + case '\r': + xpos = 0; + return; + case '\n': + ypos += height; + if(ypos > si.rows - 60 - height) { + ypos -= height; +#if HAVEBLIT + bogl_cfb8_blit(50, 30, si.cols-120, + si.rows-60-height, 50, 30+height); + GrFillRect(w1, gc3, 50, ypos, si.cols-120, height); +#else + /* FIXME: changing FALSE to TRUE crashes nano-X*/ + /* clear screen, no scroll*/ + ypos = 0; + GrClearWindow(w1, GR_FALSE); +#endif + } + return; + case '\007': /* bel*/ + return; + case '\t': + xpos += width; + while((xpos/width) & 7) + char_out(' '); + return; + case '\b': /* assumes fixed width font!!*/ + if (xpos <= 0) + return; + char_del(xpos, ypos); + return; + } + GrText(w1, gc1, xpos+1, ypos, &ch, 1, GR_TFTOP); + xpos += width; +} + +void printg(char * text) +{ + int i; + + for(i = 0; i < strlen(text); i++) { + char_out(text[i]); + } +} + + +/* + * Here when a keyboard press occurs. + */ +void +do_keystroke(kp) + GR_EVENT_KEYSTROKE *kp; +{ + char foo; + + foo = kp->ch; + write(tfd, &foo, 1); +} + + +/* + * Here when a focus in event occurs. + */ +void +do_focusin(gp) + GR_EVENT_GENERAL *gp; +{ + if (gp->wid != w1) + return; + GrSetBorderColor(w1, LTBLUE); +} + +/* + * Here when a focus out event occurs. + */ +void +do_focusout(gp) + GR_EVENT_GENERAL *gp; +{ + if (gp->wid != w1) + return; + GrSetBorderColor(w1, GRAY); +} + +/* + * Here to read the shell input file descriptor. + */ +void +do_fdinput() +{ + char c; + + if (read(tfd, &c, 1) == 1) + char_out(c); +} Index: landmine.c =================================================================== --- landmine.c (nonexistent) +++ landmine.c (revision 174) @@ -0,0 +1,1337 @@ +/* + * Landmine, the game. + * Written for mini-X by David I. Bell. + */ + +#include +#include +#include +#if UNIX | DOS_DJGPP +#include +#include +#include +#endif +#define MWINCLUDECOLORS +#include "nano-X.h" + + +#define MINSIZE 3 /* minimum size of board */ +#define MAXSIZE 30 /* maximum size of board */ +#define SIZE 15 /* default size of playing board */ +#define MINEPERCENT 15 /* default percentage of mines */ +#define SAVEFILE "landmine.save" /* default save file name */ +#define MAGIC 649351261 /* magic number in save files */ +#define MAXPARAMS 1000 /* maximum different game parameters */ + +#define FULLSIZE (MAXSIZE + 2) /* board size including borders */ + +#ifdef __ECOS +/* 240x320 screen values*/ +#define BOARDGAP 2 /* millimeter gap around board */ +#define RIGHTGAP 2 /* mm gap between board, right side */ +#define BUTTONGAP 5 /* mm gap between buttons */ +#define STATUSGAP 10 /* mm gap between buttons and status */ + +#define BUTTONWIDTH 80 /* width of buttons (pixels) */ +#define BUTTONHEIGHT 25 /* height of buttons (pixels) */ +#define RIGHTSIDE 90 /* pixels to guarantee for right side */ +#define BOARDBORDER 2 /* border size around board */ +#else +#define BOARDGAP 10 /* millimeter gap around board */ +#define RIGHTGAP 15 /* mm gap between board, right side */ +#define BUTTONGAP 20 /* mm gap between buttons */ +#define STATUSGAP 35 /* mm gap between buttons and status */ + +#define BUTTONWIDTH 80 /* width of buttons (pixels) */ +#define BUTTONHEIGHT 25 /* height of buttons (pixels) */ +#define RIGHTSIDE 150 /* pixels to guarantee for right side */ +#define BOARDBORDER 2 /* border size around board */ +#endif + +/* + * Print the number of steps taken. + * This is used twice, and is a macro to guarantee that + * the two printouts match. + */ +#define PRINTSTEPS printline(2, "Steps: %3d\n", steps) + + +/* + * Typedefs local to this program. + */ +typedef unsigned short CELL; /* cell value */ +typedef int POS; /* cell position */ + + +/* + * For defining bitmaps easily. + */ +#define X ((unsigned) 1) +#define _ ((unsigned) 0) + +#define BITS(a,b,c,d,e,f,g,h,i) \ + (((((((((a*2+b)*2+c)*2+d)*2+e)*2+f)*2+g)*2+h)*2+i) << 7) + + +static GR_BITMAP twolegs_fg[] = { /* two legs foreground */ + BITS(_,_,_,_,_,_,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,_,X,_,_,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,X,_,X,_,X,_,X,_), + BITS(_,X,_,X,X,X,_,X,_), + BITS(_,_,_,X,_,X,_,_,_), + BITS(_,_,_,X,_,X,_,_,_), + BITS(_,_,X,X,_,X,X,_,_), + BITS(_,_,_,_,_,_,_,_,_) +}; + +static GR_BITMAP twolegs_bg[] = { /* two legs background */ + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,X,X,X,X,X,X,X,_), + BITS(X,X,X,X,X,X,X,X,X), + BITS(X,X,X,X,_,X,X,X,X), + BITS(X,X,X,X,X,X,X,X,X), + BITS(X,X,X,X,X,X,X,X,X), + BITS(_,X,X,X,X,X,X,X,_), + BITS(_,X,X,X,X,X,X,X,_), + BITS(_,X,X,X,X,X,X,X,_) +}; + + +static GR_BITMAP oneleg_fg[] = { /* one leg foreground */ + BITS(_,_,_,_,_,_,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,_,X,_,_,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,X,_,X,_,X,_,X,_), + BITS(_,_,_,X,X,X,_,X,_), + BITS(_,_,_,_,_,X,_,_,_), + BITS(_,_,_,_,_,X,_,_,_), + BITS(_,_,_,_,_,X,X,_,_), + BITS(_,_,_,_,_,_,_,_,_), +}; + + +static GR_BITMAP oneleg_bg[] = { /* one leg background */ + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,X,X,X,X,X,X,X,_), + BITS(X,X,X,X,X,X,X,X,X), + BITS(X,X,X,X,_,X,X,X,X), + BITS(X,X,X,X,X,X,X,X,X), + BITS(_,_,X,X,X,X,X,X,X), + BITS(_,_,_,_,X,X,X,X,_), + BITS(_,_,_,_,X,X,X,X,_), + BITS(_,_,_,_,X,X,X,X,_) +}; + + +static GR_BITMAP noleg_fg[] = { /* no legs foreground */ + BITS(_,_,_,_,_,_,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,_,X,_,_,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,X,_,X,_,X,_,X,_), + BITS(_,_,_,X,X,X,_,_,_), + BITS(_,_,_,_,_,_,_,_,_), + BITS(_,_,_,_,_,_,_,_,_), + BITS(_,_,_,_,_,_,_,_,_), + BITS(_,_,_,_,_,_,_,_,_), +}; + + +static GR_BITMAP noleg_bg[] = { /* no legs background */ + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,X,X,X,X,X,X,X,_), + BITS(X,X,X,X,X,X,X,X,X), + BITS(X,X,X,X,_,X,X,X,X), + BITS(X,X,X,X,X,X,X,X,X), + BITS(_,_,X,X,X,X,X,_,_), + BITS(_,_,_,_,_,_,_,_,_), + BITS(_,_,_,_,_,_,_,_,_), + BITS(_,_,_,_,_,_,_,_,_) +}; + + +/* + * Components of a cell. + */ +#define F_EMPTY ' ' /* default value for empty square */ +#define F_REMEMBER '*' /* character to remember mine */ +#define F_WRONG 'X' /* character to remember wrong guess */ +#define F_DISPLAY 0xff /* character to be displayed here */ +#define F_MINE 0x100 /* TRUE if a mine is here */ +#define F_EDGE 0x200 /* TRUE if this is edge of the world */ +#define F_OLD 0x400 /* TRUE if been at this square before */ +#define F_REACH 0x800 /* TRUE if can reach this square */ +#define F_FLAGS 0xff00 /* all flags */ + + +/* + * The status of the game. + * This structure is read and written from the save file. + */ +static struct status { /* status of games */ + long s_magic; /* magic number */ + short s_playing; /* TRUE if playing a game */ + short s_size; /* current size of board */ + short s_mines; /* current number of mines on board */ + short s_legs; /* number of legs left */ + short s_steps; /* number of steps taken this game */ + short s_index; /* current game parameter index */ + short s_sizeparam[MAXPARAMS]; /* table of size parameters */ + short s_mineparam[MAXPARAMS]; /* table of mine parameters */ + long s_games0[MAXPARAMS]; /* games finished with no legs */ + long s_games1[MAXPARAMS]; /* games finished with one leg */ + long s_games2[MAXPARAMS]; /* games finished with two legs */ + long s_steps0[MAXPARAMS]; /* steps taken in no leg games */ + long s_steps1[MAXPARAMS]; /* steps taken in one leg games */ + long s_steps2[MAXPARAMS]; /* steps taken in two leg games */ + CELL s_board[FULLSIZE*FULLSIZE]; /* board layout */ +} st; + + +/* + * Definitions to make structure references easy. + */ +#define magic st.s_magic +#define playing st.s_playing +#define size st.s_size +#define mines st.s_mines +#define legs st.s_legs +#define steps st.s_steps +#define index st.s_index +#define sizeparam st.s_sizeparam +#define mineparam st.s_mineparam +#define games0 st.s_games0 +#define games1 st.s_games1 +#define games2 st.s_games2 +#define steps0 st.s_steps0 +#define steps1 st.s_steps1 +#define steps2 st.s_steps2 +#define board st.s_board + + +#define boardpos(row, col) (((row) * FULLSIZE) + (col)) +#define ismine(cell) ((cell) & F_MINE) +#define isedge(cell) ((cell) & F_EDGE) +#define isold(cell) ((cell) & F_OLD) +#define isseen(cell) (((cell) & F_DISPLAY) == F_REMEMBER) +#define isknown(cell) (((cell) & F_DISPLAY) != F_EMPTY) +#define displaychar(cell) ((cell) & F_DISPLAY) +#define badsquare(n) (((n) <= 0) || ((n) > size)) + + +/* + * Offsets for accessing adjacent cells. + */ +static POS steptable[8] = { + FULLSIZE, -FULLSIZE, 1, -1, FULLSIZE-1, + FULLSIZE+1, -FULLSIZE-1, -FULLSIZE+1 +}; + + +static GR_WINDOW_ID mainwid; /* main window id */ +static GR_WINDOW_ID boardwid; /* board window id */ +static GR_WINDOW_ID statwid; /* status display window id */ +static GR_WINDOW_ID quitwid; /* window id for quit button */ +static GR_WINDOW_ID savewid; /* window id for save button */ +static GR_WINDOW_ID newgamewid; /* window id for new game button */ + +static GR_GC_ID boardgc; /* graphics context for board */ +static GR_GC_ID cleargc; /* GC for clearing cell of board */ +static GR_GC_ID redgc; /* GC for drawing red */ +static GR_GC_ID greengc; /* GC for drawing green */ +static GR_GC_ID blackgc; /* GC for drawing black */ +static GR_GC_ID delaygc; /* GC for delaying */ +static GR_GC_ID statgc; /* GC for status window */ +static GR_GC_ID buttongc; /* GC for drawing buttons */ +static GR_GC_ID xorgc; /* GC for inverting things */ + +static GR_SIZE xp; /* pixels for x direction per square */ +static GR_SIZE yp; /* pixels for y direction per square */ +static GR_SIZE statwidth; /* width of window drawing text in */ +static GR_SIZE statheight; /* height of window drawing text in */ +static GR_SIZE charheight; /* height of characters */ +static GR_COORD charxpos; /* current X position for characters */ +static GR_COORD charypos; /* current Y position for characters */ + +static GR_SCREEN_INFO si; /* window information */ +static GR_FONT_INFO fi; /* font information */ + +static GR_SIZE COLS, ROWS; + +static char *savefile; /* filename for saving game */ + + +/* + * Procedures. + */ +static void printline(GR_COORD, char *, ...); +static void newline(); +static void delay(); +static void dokey(); +static void handleevent(); +static void doexposure(); +static void dobutton(); +static void drawbomb(); +static void drawstatus(); +static void drawbutton(); +static void drawboard(); +static void drawcell(); +static void cellcenter(); +static void clearcell(); +static void newgame(); +static void movetopos(); +static void setcursor(); +static void togglecell(); +static void gameover(); +static void readgame(); +static void findindex(); +static POS findcell(); +static GR_BOOL checkpath(); +static GR_BOOL writegame(); + +int +main(argc,argv) + int argc; + char **argv; +{ + GR_COORD x; + GR_COORD y; + GR_SIZE width; + GR_SIZE height; + GR_COORD rightx; /* x coordinate for right half stuff */ + GR_BOOL setsize; /* TRUE if size of board is set */ + GR_BOOL setmines; /* TRUE if number of mines is set */ + GR_SIZE newsize = 10; /* desired size of board */ + GR_COUNT newmines = 25; /* desired number of mines */ + GR_WM_PROPERTIES props; + + setmines = GR_FALSE; + setsize = GR_FALSE; + + argc--; + argv++; + while ((argc > 0) && (**argv == '-')) { + switch (argv[0][1]) { + case 'm': + if (argc <= 0) { + fprintf(stderr, "Missing mine count\n"); + exit(1); + } + argc--; + argv++; + newmines = atoi(*argv); + setmines = GR_TRUE; + break; + + case 's': + if (argc <= 0) { + fprintf(stderr, "Missing size\n"); + exit(1); + } + argc--; + argv++; + newsize = atoi(*argv); + setsize = GR_TRUE; + break; + + default: + fprintf(stderr, "Unknown option \"-%c\"\n", + argv[0][1]); + exit(1); + } + argc--; + argv++; + } + if (argc > 0) + savefile = *argv; + + srand(time(0)); + + readgame(savefile); + + if (setsize) { + if ((newsize < MINSIZE) || (newsize > MAXSIZE)) { + fprintf(stderr, "Illegal board size\n"); + exit(1); + } + if (newsize != size) { + if (steps && playing) { + fprintf(stderr, + "Cannot change size while game is in progress\n"); + exit(1); + } + playing = GR_FALSE; + size = newsize; + if (!playing) + mines = (size * size * MINEPERCENT) / 100; + } + } + + if (setmines) { + if ((newmines <= 0) || ((newmines > (size * size) / 2))) { + fprintf(stderr, "Illegal number of mines\n"); + exit(1); + } + if (newmines != mines) { + if (steps && playing) { + fprintf(stderr, + "Cannot change mines while game is in progress\n"); + exit(1); + } + playing = GR_FALSE; + mines = newmines; + } + } + + findindex(); + + /* + * Parameters of the game have been verified. + * Now open the graphics and play the game. + */ + + if (GrOpen() < 0) { + fprintf(stderr, "Cannot open graphics\n"); + exit(1); + } + + GrReqShmCmds(655360); /* Test by Morten Rolland for shm support */ + + GrGetScreenInfo(&si); + GrGetFontInfo(0, &fi); + charheight = fi.height; + + /* + * Create the main window which will contain all the others. + */ +#if 0 +COLS = si.cols - 40; +#else +COLS = si.cols; +#endif +ROWS = si.rows - 80; + mainwid = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, COLS, ROWS, + 0, BLACK, WHITE); + + /* set title */ + props.flags = GR_WM_FLAGS_TITLE | GR_WM_FLAGS_PROPS; + props.props = GR_WM_PROPS_APPFRAME | GR_WM_PROPS_CAPTION; + props.title = "Land Mine"; + GrSetWMProperties(mainwid, &props); + + /* + * Create the board window which lies at the left side. + * Make the board square, and as large as possible while still + * leaving room to the right side for statistics and buttons. + */ + width = COLS - RIGHTSIDE - (si.xdpcm * RIGHTGAP / 10) - BOARDBORDER * 2; + height = (((long) width) * si.ydpcm) / si.xdpcm; + if (height > ROWS /* - y * 2*/) { + height = ROWS - BOARDBORDER * 2; + width = (((long) height) * si.xdpcm) / si.ydpcm; + } + xp = width / size; + yp = height / size; + + width = xp * size - 1; + height = yp * size - 1; + x = BOARDBORDER; + y = (ROWS - height) / 2; + + rightx = x + width + (si.xdpcm * RIGHTGAP / 10); + boardwid = GrNewWindow(mainwid, x, y, width, height, BOARDBORDER, + BLUE, WHITE); + /* + * Create the buttons. + */ + x = rightx; + y = (si.ydpcm * BOARDGAP / 10); + quitwid = GrNewWindow(mainwid, x, y, BUTTONWIDTH, BUTTONHEIGHT, + 1, RED, WHITE); + + y += (si.ydpcm * BUTTONGAP / 10); + savewid = GrNewWindow(mainwid, x, y, BUTTONWIDTH, BUTTONHEIGHT, + 1, GREEN, WHITE); + + y += (si.ydpcm * BUTTONGAP / 10); + newgamewid = GrNewWindow(mainwid, x, y, BUTTONWIDTH, BUTTONHEIGHT, + 1, GREEN, WHITE); + + /* + * Create the statistics window. + */ + x = rightx; + y += (si.ydpcm * STATUSGAP / 10); + width = COLS - x; + height = ROWS - y; + statwid = GrNewWindow(mainwid, x, y, width, height, 0, + 0, 0); + statwidth = width; + statheight = height; + + /* + * Create the GC for drawing the board. + */ + boardgc = GrNewGC(); + cleargc = GrNewGC(); + delaygc = GrNewGC(); + redgc = GrNewGC(); + greengc = GrNewGC(); + statgc = GrNewGC(); + blackgc = GrNewGC(); + buttongc = GrNewGC(); + xorgc = GrNewGC(); + GrSetGCBackground(boardgc, BLUE); + GrSetGCForeground(cleargc, BLUE); + GrSetGCForeground(redgc, RED); + GrSetGCForeground(greengc, GREEN); + GrSetGCForeground(statgc, GRAY); + GrSetGCForeground(delaygc, BLACK); + GrSetGCForeground(blackgc, BLACK); + GrSetGCMode(delaygc, GR_MODE_XOR); + GrSetGCMode(xorgc, GR_MODE_XOR); + GrSetGCUseBackground(boardgc, GR_FALSE); + GrSetGCUseBackground(buttongc, GR_FALSE); + + GrSelectEvents(mainwid, GR_EVENT_MASK_CLOSE_REQ); + + GrSelectEvents(boardwid, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN | GR_EVENT_MASK_KEY_DOWN); + + GrSelectEvents(statwid, GR_EVENT_MASK_EXPOSURE); + + GrSelectEvents(quitwid, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + GrSelectEvents(newgamewid, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + GrSelectEvents(savewid, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + setcursor(); + + GrMapWindow(mainwid); + GrMapWindow(boardwid); + GrMapWindow(statwid); + GrMapWindow(quitwid); + GrMapWindow(savewid); + GrMapWindow(newgamewid); + + if (!playing) + newgame(); + + while (GR_TRUE) { + GR_EVENT event; + + GrGetNextEvent(&event); + handleevent(&event); + } +} + + +/* + * Read the next event and handle it. + */ +static void +handleevent(GR_EVENT *ep) +{ + switch (ep->type) { + case GR_EVENT_TYPE_BUTTON_DOWN: + dobutton(&ep->button); + break; + + case GR_EVENT_TYPE_EXPOSURE: + doexposure(&ep->exposure); + break; + + case GR_EVENT_TYPE_KEY_DOWN: + dokey(&ep->keystroke); + break; + + case GR_EVENT_TYPE_CLOSE_REQ: + GrClose(); + exit(0); + } +} + + +/* + * Handle exposure events. + */ +static void +doexposure(ep) + GR_EVENT_EXPOSURE *ep; +{ + if (ep->wid == boardwid) { + drawboard(); + return; + } + + if (ep->wid == statwid) { + drawstatus(); + return; + } + + if (ep->wid == quitwid) { + drawbutton(quitwid, "QUIT"); + return; + } + + if (ep->wid == savewid) { + drawbutton(savewid, "SAVE GAME"); + return; + } + + if (ep->wid == newgamewid) { + drawbutton(newgamewid, "NEW GAME"); + return; + } +} + + +/* + * Here when we get a button down event. + */ +static void +dobutton(bp) + GR_EVENT_BUTTON *bp; +{ + if (bp->wid == boardwid) { + movetopos(findcell(bp->x, bp->y)); + return; + } + + if (bp->wid == quitwid) { + GrFillRect(quitwid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT); + GrFlush(); + if (savefile) + writegame(savefile); + GrClose(); + exit(0); + } + + if (bp->wid == savewid) { + GrFillRect(savewid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT); + GrFlush(); + if (savefile == NULL) + savefile = SAVEFILE; + if (writegame(savefile)) + write(1, "\007", 1); + else + delay(); + GrFillRect(savewid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT); + } + + if (bp->wid == newgamewid) { + GrFillRect(newgamewid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT); + GrFlush(); + /*if (playing) + write(1, "\007", 1); + else {*/ + newgame(); + delay(); + /*}*/ + GrFillRect(newgamewid, xorgc, 0, 0, BUTTONWIDTH, BUTTONHEIGHT); + } +} + + +/* + * Here when we get a keypress in a window. + */ +static void +dokey(kp) + GR_EVENT_KEYSTROKE *kp; +{ + if ((kp->wid != boardwid) || !playing) + return; + + switch (kp->ch) { + case ' ': /* remember or forget mine */ + togglecell(findcell(kp->x, kp->y)); + break; + } +} + + +/* + * Redraw the board. + */ +static void +drawboard() +{ + GR_COORD row; + GR_COORD col; + + for (row = 1; row < size; row++) { + GrLine(boardwid, boardgc, 0, row * yp - 1, size * xp - 1, + row * yp - 1); + GrLine(boardwid, boardgc, row * xp - 1, 0, + row * xp - 1, size * yp - 1); + } + for (row = 0; row < FULLSIZE; row++) { + for (col = 0; col < FULLSIZE; col++) { + drawcell(boardpos(row, col)); + } + } +} + + +/* + * Draw a cell on the board. + */ +static void +drawcell(pos) + POS pos; /* position to be drawn */ +{ + GR_COORD x; + GR_COORD y; + GR_SIZE chwidth; + GR_SIZE chheight; + GR_SIZE chbase; + CELL cell; + GR_CHAR ch; + + cell = board[pos]; + if (!isknown(cell)) + return; + + ch = displaychar(cell); + if (ch == F_WRONG) { + drawbomb(pos, greengc, GR_FALSE); + return; + } + + if (isold(cell)) { + clearcell(pos); + cellcenter(pos, &x, &y); + GrGetGCTextSize(boardgc, &ch, 1, GR_TFASCII, &chwidth, + &chheight, &chbase); + GrText(boardwid, boardgc, x - chwidth / 2 + 1, + y + chheight / 2, &ch, 1, GR_TFBOTTOM); + return; + } + + drawbomb(pos, redgc, GR_FALSE); +} + + +/* + * Clear a particular cell. + */ +static void +clearcell(pos) + POS pos; /* position to be cleared */ +{ + GR_COORD row; + GR_COORD col; + + row = pos / FULLSIZE; + col = pos % FULLSIZE; + GrFillRect(boardwid, cleargc, col * xp - xp, row * yp - yp, + xp - 1, yp - 1); +} + + +/* + * Draw a bomb in a window using the specified GC. + * The bomb is animated and the terminal is beeped if necessary. + */ +static void +drawbomb(pos, gc, animate) + POS pos; /* position to draw bomb at */ + GR_GC_ID gc; /* GC for drawing (red or green) */ + GR_BOOL animate; /* TRUE to animate the bomb */ +{ + GR_COORD x; + GR_COORD y; + GR_COUNT count; + + if (animate) + write(1, "\007", 1); + + cellcenter(pos, &x, &y); + + count = (animate ? 8 : 1); + for (;;) { + GrFillEllipse(boardwid, gc, x, y, xp / 2 - 3, yp / 2 - 3); + if (--count == 0) + return; + delay(); + clearcell(pos); + delay(); + } +} + + +/* + * Draw a button which has a specified label string centered in it. + */ +static void +drawbutton(window, label) + GR_WINDOW_ID window; + char *label; +{ + GR_SIZE width; + GR_SIZE height; + GR_SIZE base; + + GrGetGCTextSize(buttongc, label, strlen(label), GR_TFASCII, &width, + &height, &base); + GrText(window, buttongc, (BUTTONWIDTH - width) / 2, + (BUTTONHEIGHT - height) / 2 + height - 1, + label, -1, GR_TFBOTTOM); +} + + +/* + * Set the cursor as appropriate. + * The cursor changes depending on the number of legs left. + */ +static void +setcursor() +{ + GR_BITMAP *fgbits; /* bitmap for foreground */ + GR_BITMAP *bgbits; /* bitmap for background */ + + switch (legs) { + case 0: + fgbits = noleg_fg; + bgbits = noleg_bg; + break; + case 1: + fgbits = oneleg_fg; + bgbits = oneleg_bg; + break; + default: + fgbits = twolegs_fg; + bgbits = twolegs_bg; + break; + } + GrSetCursor(boardwid, 9, 12, 4, 6, WHITE, BLACK, fgbits, bgbits); +} + + +/* + * Delay for a while so that something can be seen. + * This is done by drawing a large rectangle over the window using a mode + * of XOR with the value of 0, (which does nothing except waste time). + */ +static void +delay() +{ + GR_COUNT i; + + for (i = 0; i < 1; i++) { + GrFillRect(boardwid, delaygc, 0, 0, xp * size - 1, + yp * size - 1); + GrFlush(); + } +} + + +/* + * Calculate the coordinates of the center of a cell on the board. + * The coordinates are relative to the origin of the board window. + */ +static void +cellcenter(pos, retx, rety) + POS pos; /* position to find center of */ + GR_COORD *retx; /* returned X coordinate */ + GR_COORD *rety; /* returned Y coordinate */ +{ + *retx = (pos % FULLSIZE) * xp - 1 - xp / 2; + *rety = (pos / FULLSIZE) * yp - 1 - yp / 2; +} + + +/* + * Draw the status information in the status window. + */ +static void +drawstatus() +{ + long score; + long allsteps; + long games; + + score = 0; + games = games0[index]; + allsteps = steps0[index]; + score += games1[index]; + games += games1[index]; + allsteps += steps1[index]; + score += games2[index] * 2; + games += games2[index]; + allsteps += steps2[index]; + + printline(0, "Size: %2d\n", size); + printline(1, "Mines: %3d\n", mines); + PRINTSTEPS; + printline(3, "Legs: %d\n", legs); + + printline(5, "Won games: %3d\n", games2[index]); + printline(6, "1-leg games:%3d\n", games1[index]); + printline(7, "Lost games: %3d\n", games0[index]); + + if (games) { + printline(9, "Legs/game: %3d.%03d\n", score / games, + ((score * 1000) / games) % 1000); + + printline(10, "Steps/game:%3d.%03d\n", allsteps / games, + ((allsteps * 1000) / games) % 1000); + } +} + + +/* + * Printf routine for windows, which can print at particular lines. + * A negative line number means continue printing at the previous location. + * Assumes the status window for output. + */ +static void printline(GR_COORD row, char * fmt, ...) +{ + va_list ap; + GR_COUNT cc; + GR_SIZE width; + char *cp; + char buf[256]; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + if (row >= 0) { + charxpos = 0; + charypos = charheight * row + charheight - 1; + } + + cp = buf; + for (;;) { + cc = 0; + width = 0; + while (*cp >= ' ') { + width += fi.widths[(int)*cp++]; + cc++; + } + if (width) { + GrText(statwid, statgc, charxpos, charypos, + cp - cc, cc, GR_TFBOTTOM); + charxpos += width; + } + + switch (*cp++) { + case '\0': + return; + case '\n': + newline(); + break; + case '\r': + charxpos = 0; + break; + } + } +} + + +/* + * Clear the remainder of the line and move to the next line. + * This assumes output is in the status window. + */ +static void +newline() +{ + GrFillRect(statwid, blackgc, charxpos, charypos - charheight + 1, + statwidth - charxpos, charheight); + charxpos = 0; + charypos += charheight; +} + + +/* + * Translate a board window coordinate into a cell position. + * If the coordinate is outside of the window, or exactly on one + * of the interior lines, then a coordinate of 0 is returned. + */ +static POS +findcell(x, y) + GR_COORD x; + GR_COORD y; +{ + GR_COORD row; + GR_COORD col; + + if (((x % xp) == 0) || ((y % yp) == 0)) + return 0; + row = (y / yp) + 1; + col = (x / xp) + 1; + if ((row <= 0) || (row > size) || (col <= 0) || (col > size)) + return 0; + return boardpos(row, col); +} + + +/* + * Initialize the board for playing + */ +static void +newgame() +{ + GR_COORD row; + GR_COORD col; + GR_COUNT count; + CELL cell; + POS pos; + + for (row = 0; row < FULLSIZE; row++) { + for (col = 0; col < FULLSIZE; col++) { + cell = F_EMPTY; + if (badsquare(row) || badsquare(col)) + cell |= F_EDGE; + board[boardpos(row, col)] = cell; + } + } + + playing = GR_TRUE; + count = 0; + legs = 2; + steps = 0; + drawstatus(); + setcursor(); + + while (count < mines) { + do { + row = (rand() / 16) % (size * size + 1); + } while (row == (size * size)); + + col = (row % size) + 1; + row = (row / size) + 1; + pos = boardpos(row, col); + + if ((pos == boardpos(1,1)) || (pos == boardpos(1,2)) || + (pos == boardpos(2,1)) || (pos == boardpos(2,2)) || + (pos == boardpos(size,size))) + continue; + + if (!ismine(board[pos]) && checkpath(pos)) + count++; + } + + board[boardpos(1,1)] = (F_OLD | '0'); + + GrClearWindow(boardwid, GR_TRUE); +} + + +/* + * Check to see if there is still a path from the top left corner to the + * bottom right corner, if a new mine is placed at the indicated position. + * Returns GR_TRUE if mine was successfully placed. + */ +static GR_BOOL +checkpath(pos) + POS pos; /* position to place mine at */ +{ + CELL *bp; /* current board position */ + CELL *endbp; /* ending position */ + POS endpos; /* ending position */ + GR_COUNT count; /* number of neighbors */ + GR_COUNT i; /* loop counter */ + GR_BOOL more; /* GR_TRUE if new square reached */ + + /* + * Begin by assuming there is a mine at the specified location, + * and then count neighbors. If there are less than two other + * mines or edge squares, then there must still be a path. + */ + board[pos] |= F_MINE; + + count = 0; + + for (i = 7; i >= 0; i--) { + if (board[pos + steptable[i]] & (F_MINE | F_EDGE)) + count++; + } + + if (count < 2) + return GR_TRUE; + + /* + * Two or more neighbors, so we must do the full check. + * First clear the reach flag, except for the top left corner. + */ + endpos = boardpos(size, size); + bp = &board[endpos]; + endbp = bp; + while (bp != board) + *bp-- &= ~F_REACH; + board[boardpos(1,1)] |= F_REACH; + + /* + * Now loop looking for new squares next to already reached squares. + * Stop when no more changes are found, or when the lower right + * corner is reached. + */ + do { + more = GR_FALSE; + for (bp = &board[boardpos(1,1)]; bp != endbp; bp++) { + if (*bp & F_REACH) { + for (i = 7; i >= 0; i--) { + if ((bp[steptable[i]] & (F_MINE | F_REACH | F_EDGE)) == 0) { + bp[steptable[i]] |= F_REACH; + more = GR_TRUE; + } + } + } + } + + if (board[endpos] & F_REACH) + return GR_TRUE; + } while (more); + + /* + * Cannot reach the lower right corner, so remove the mine and fail. + */ + board[pos] &= ~F_MINE; + + return GR_FALSE; +} + + +/* + * Move to a particular position and see if we hit a mine. + * If not, then count the number of mines adjacent to us so it can be seen. + * If we are stepping onto a location where we remembered a mine is at, + * then don't do it. Moving is only allowed to old locations, or to + * locations adjacent to old ones. + */ +static void +movetopos(newpos) + POS newpos; /* position to move to */ +{ + POS fixpos; /* position to fix up */ + CELL cell; /* current cell */ + GR_COUNT count; /* count of cells */ + GR_COUNT i; /* index for neighbors */ + + if ((newpos < 0) || (newpos >= (FULLSIZE * FULLSIZE)) || !playing) + return; + + cell = board[newpos]; + + if (isedge(cell) || (isseen(cell)) || isold(cell)) + return; + + count = isold(cell); + for (i = 0; i < 8; i++) + if (isold(board[newpos + steptable[i]])) + count++; + + if (count <= 0) + return; + + cell = (cell & F_FLAGS) | F_OLD; + steps++; + + PRINTSTEPS; + + if (ismine(cell)) { /* we hit a mine */ + legs--; + board[newpos] = (F_REMEMBER | F_MINE); + cell = (F_EMPTY | F_OLD); + board[newpos] = cell; + drawbomb(newpos, redgc, GR_TRUE); + clearcell(newpos); + setcursor(); + for (i = 0; i < 8; i++) { + fixpos = newpos + steptable[i]; + if (isold(board[fixpos])) { + board[fixpos]--; + drawcell(fixpos); + } + } + drawstatus(); + } + + count = 0; + for (i = 0; i < 8; i++) + if (ismine(board[newpos + steptable[i]])) + count++; + board[newpos] = cell | (count + '0'); + + drawcell(newpos); + + if ((legs <= 0) || (newpos == boardpos(size,size))) + gameover(); +} + + +/* + * Remember or forget the location of a mine. + * This is for informational purposes only and does not affect anything. + */ +static void +togglecell(pos) + POS pos; /* position to toggle */ +{ + CELL cell; + + if ((pos <= 0) || !playing) + return; + + cell = board[pos]; + if (isknown(cell)) { + if (!isseen(cell)) + return; + board[pos] = (board[pos] & F_FLAGS) | F_EMPTY; + clearcell(pos); + return; + } + + board[pos] = (board[pos] & F_FLAGS) | F_REMEMBER; + drawcell(pos); +} + + +/* + * Here when the game is over. + * Show where the mines are, and give the results. + */ +static void +gameover() +{ + POS pos; + CELL cell; + + playing = GR_FALSE; + switch (legs) { + case 0: + games0[index]++; + steps0[index] += steps; + break; + case 1: + games1[index]++; + steps1[index] += steps; + break; + case 2: + games2[index]++; + steps2[index] += steps; + break; + } + + for (pos = 0; pos < (FULLSIZE * FULLSIZE); pos++) { + cell = board[pos]; + if (isseen(cell)) + cell = (cell & F_FLAGS) | F_WRONG; + if (ismine(cell)) + cell = (cell & F_FLAGS) | F_REMEMBER; + board[pos] = cell; + } + + drawboard(); + drawstatus(); +} + + +/* + * Search the game parameter table for the current board size and + * number of mines, and set the index for those parameters so that + * the statistics can be accessed. Allocates a new index if necessary. + */ +static void +findindex() +{ + for (index = 0; index < MAXPARAMS; index++) { + if ((sizeparam[index] == size) && (mineparam[index] == mines)) + return; + } + for (index = 0; index < MAXPARAMS; index++) { + if (sizeparam[index] == 0) { + sizeparam[index] = size; + mineparam[index] = mines; + return; + } + } + fprintf(stderr, "Too many parameters in save file\n"); + exit(1); +} + + +/* + * Read in a saved game if available, otherwise start from scratch. + * Exits if an error is encountered. + */ +static void +readgame(name) + char *name; /* filename */ +{ + int fd; + + fd = -1; + if (name) + fd = open(name, 0); + + if (fd < 0) { + magic = MAGIC; + size = SIZE; + mines = (size * size * MINEPERCENT) / 100; + playing = GR_FALSE; + return; + } + + if (read(fd, &st, sizeof(st)) != sizeof(st)) + magic = 0; + close(fd); + + if ((magic != MAGIC) || (size > MAXSIZE)) { + fprintf(stderr, "Save file format is incorrect\n"); + exit(1); + } +} + + +/* + * Write the current game to a file. + * Returns nonzero on an error. + */ +static GR_BOOL +writegame(name) + char *name; /* filename */ +{ + int fd; + + if (name == NULL) + return GR_TRUE; + + fd = creat(name, 0666); + if (fd < 0) + return GR_TRUE; + + if (write(fd, &st, sizeof(st)) != sizeof(st)) { + close(fd); + return GR_TRUE; + } + close(fd); + return GR_FALSE; +} + +/* END CODE */ Index: ntetris.c =================================================================== --- ntetris.c (nonexistent) +++ ntetris.c (revision 174) @@ -0,0 +1,981 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is NanoTetris. + * + * The Initial Developer of the Original Code is Alex Holden. + * Portions created by Alex Holden are Copyright (C) 2000 + * Alex Holden . All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public license (the "[GNU] License"), in which case the + * provisions of [GNU] License are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the [GNU] License and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the [GNU] License. If you do not delete + * the provisions above, a recipient may use your version of this file + * under either the MPL or the [GNU] License. + */ + +/* + * A Nano-X Tetris clone by Alex Holden. + * + * The objective is to keep placing new pieces for as long as possible. When a + * horizontal line is filled with blocks, it will vanish, and everything above + * it will drop down a line. It quickly gets difficult because the speed + * increases with the score. Unlike with some Tetris clones, no bonus points + * are awarded for matching colours, completing more than one line at a time, + * or for using the "drop shape to bottom" function. + * + * The box in the top left of the game window is the score box. The top score + * is the highest score you have achieved since last resetting the high score + * counter. The counter is stored when the game exits in the file specified by + * the HISCORE_FILE parameter ("/usr/games/nanotetris.hiscore" by default). + * Note that no attempt is made to encrypt the file, so anybody with write + * access to the file can alter the contents of it using a text editor. + * + * The box below the score box is the next shape box. This contains a "preview" + * of the next shape to appear, so that you can plan ahead as you are building + * up the blocks. + * + * The game functions can be controlled using either the mouse (or a touch pad, + * touch screen, trackball, etc.) and the buttons below the next shape box, or + * with the following keyboard keys: + * + * Q = quit game + * N = new game + * P = pause game + * C = continue game + * D = rotate shape anticlockwise + * F = rotate shape clockwise + * J = move shape left + * K = move shape right + * Space Bar = drop shape to bottom. + * + * The reason for the unconventional use of D, F, J, and K keys is that they + * are all in the "home" position of a QWERTY keyboard, which makes them very + * easy to press if you are used to touch typing. + * + * I'll leave it to you to figure out which mouse operated movement button does + * what (it's pretty obvious). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ECOS +#define random rand +#define srandom srand +#endif + +#define MWINCLUDECOLORS +#include + +#include "ntetris.h" + +void *my_malloc(size_t size) +{ + void *ret; + + if(!(ret = malloc(size))) { + fprintf(stderr, "Out of memory\n"); + exit(1); + } + + return ret; +} + +#ifdef HAVE_USLEEP +void msleep(long ms) +{ + usleep(ms * 1000); +} +#else +void msleep(long ms) +{ + struct timespec req, rem; + + req.tv_sec = ms / 1000000; + req.tv_nsec = (ms % 1000000) * 1000000; + + while(nanosleep(&req, &rem) == -1) { + if(errno == EINTR) { + req.tv_sec = rem.tv_sec; + req.tv_nsec = rem.tv_nsec; + continue; + } else { + perror("nanosleep() failed"); + return; + } + } +} +#endif + +#ifdef USE_HISCORE_FILE +void read_hiscore(nstate *state) +{ + FILE *f; + int i, n; + + if(!(f = fopen(HISCORE_FILE, "r"))) { + if(errno != ENOENT) + perror("Couldn't open high score file for reading"); + state->hiscore = state->fhiscore = 0; + return; + } + + i = fscanf(f, "%d", &n); + fclose(f); + + if(i != 1) { + fprintf(stderr, "Couldn't read high score file\n"); + n = 0; + } + + state->hiscore = state->fhiscore = n; +} + +void write_hiscore(nstate *state) +{ + FILE *f; + + if(state->score > state->hiscore) state->hiscore = state->score; + if(state->hiscore <= state->fhiscore) return; + + if(!(f = fopen(HISCORE_FILE, "w"))) { + perror("Couldn't open high score file for writing"); + return; + } + + if((fprintf(f, "%d", state->hiscore)) == -1) { + perror("Couldn't write to high score file"); + } + + fclose(f); +} +#else +void read_hiscore(nstate *state) +{ + state->hiscore = 0; +} + +void write_hiscore(nstate *state) {} +#endif + +int will_collide(nstate *state, int x, int y, int orientation) +{ + int r, c, xx, yy; + char ch = 0; + + draw_shape(state, state->current_shape.x, state->current_shape.y, 1); + for(r = 0; ch < 3; r++) { + ch = 0; + for(c = 0; ch < 2; c++) { + ch = shapes[state->current_shape.type] + [orientation][r][c]; + if(ch == 1) { + yy = y + r; + xx = x + c; + if((yy == WELL_HEIGHT) || (xx == WELL_WIDTH) || + (state->blocks[0][yy][xx])) { + draw_shape(state, + state->current_shape.x, + state->current_shape.y, 0); + return 1; + } + } + } + } + draw_shape(state, state->current_shape.x, state->current_shape.y, 0); + + return 0; +} + +void draw_shape(nstate *state, GR_COORD x, GR_COORD y, int erase) +{ + int r, c, yy, xx; + GR_COLOR col; + char ch = 0; + + if(erase) col = 0; + else col = state->current_shape.colour; + + for(r = 0; ch < 3; r++) { + ch = 0; + for(c = 0; ch < 2; c++) { + ch = shapes[state->current_shape.type] + [state->current_shape.orientation][r][c]; + if(ch == 1) { + yy = y + r; + xx = x + c; + state->blocks[0][yy][xx] = col; + } + } + } +} + +void draw_well(nstate *state, int forcedraw) +{ + int x, y; + + for(y = WELL_NOTVISIBLE; y < WELL_HEIGHT; y++) { + for(x = 0; x < WELL_WIDTH; x++) { + if(forcedraw || (state->blocks[0][y][x] != + state->blocks[1][y][x])) { + state->blocks[1][y][x] = state->blocks[0][y][x]; + GrSetGCForeground(state->wellgc, + state->blocks[0][y][x]); + GrFillRect(state->well_window, state->wellgc, + (BLOCK_SIZE * x), + (BLOCK_SIZE * (y - WELL_NOTVISIBLE)), + BLOCK_SIZE, BLOCK_SIZE); + } + } + } + + GrFlush(); +} + +void draw_score(nstate *state) +{ + char buf[32]; + + GrFillRect(state->score_window, state->scoregcb, 0, 0, + SCORE_WINDOW_WIDTH, SCORE_WINDOW_HEIGHT); + + sprintf(buf, "%d", state->score); + GrText(state->score_window, state->scoregcf, TEXT_X_POSITION, + TEXT2_Y_POSITION, buf, strlen(buf), 0); + sprintf(buf, "%d", state->hiscore); + GrText(state->score_window, state->scoregcf, TEXT_X_POSITION, + TEXT_Y_POSITION, buf, strlen(buf), 0); +} + +void draw_next_shape(nstate *state) +{ + int r, c, startx, starty, x, y; + char ch = 0; + + GrFillRect(state->next_shape_window, state->nextshapegcb, 0, 0, + NEXT_SHAPE_WINDOW_WIDTH, NEXT_SHAPE_WINDOW_HEIGHT); + + GrSetGCForeground(state->nextshapegcf, state->next_shape.colour); + + startx = (BLOCK_SIZE * ((NEXT_SHAPE_WINDOW_SIZE / 2) - + (shape_sizes[state->next_shape.type] + [state->next_shape.orientation][0] / 2))); + starty = (BLOCK_SIZE * ((NEXT_SHAPE_WINDOW_SIZE / 2) - + (shape_sizes[state->next_shape.type] + [state->next_shape.orientation][1] / 2))); + + for(r = 0; ch < 3; r++) { + ch = 0; + for(c = 0; ch < 2; c++) { + ch = shapes[state->next_shape.type] + [state->next_shape.orientation][r][c]; + if(ch == 1) { + x = startx + (c * BLOCK_SIZE); + y = starty + (r * BLOCK_SIZE); + GrFillRect(state->next_shape_window, + state->nextshapegcf, x, y, + BLOCK_SIZE, BLOCK_SIZE); + } + } + } +} + +void draw_new_game_button(nstate *state) +{ + GrFillRect(state->new_game_button, state->buttongcb, 0, 0, + NEW_GAME_BUTTON_WIDTH, NEW_GAME_BUTTON_HEIGHT); + GrText(state->new_game_button, state->buttongcf, TEXT_X_POSITION, + TEXT_Y_POSITION, "New Game", 8, 0); +} + +void draw_anticlockwise_button(nstate *state) +{ + if(!state->running_buttons_mapped) return; + GrFillRect(state->anticlockwise_button, state->buttongcb, 0, 0, + ANTICLOCKWISE_BUTTON_WIDTH, ANTICLOCKWISE_BUTTON_HEIGHT); + GrText(state->anticlockwise_button, state->buttongcf, TEXT_X_POSITION, + TEXT_Y_POSITION, " /", 4, 0); +} + +void draw_clockwise_button(nstate *state) +{ + if(!state->running_buttons_mapped) return; + GrFillRect(state->clockwise_button, state->buttongcb, 0, 0, + CLOCKWISE_BUTTON_WIDTH, CLOCKWISE_BUTTON_HEIGHT); + GrText(state->clockwise_button, state->buttongcf, TEXT_X_POSITION, + TEXT_Y_POSITION, " \\", 4, 0); +} + +void draw_left_button(nstate *state) +{ + if(!state->running_buttons_mapped) return; + GrFillRect(state->left_button, state->buttongcb, 0, 0, + LEFT_BUTTON_WIDTH, LEFT_BUTTON_HEIGHT); + GrText(state->left_button, state->buttongcf, TEXT_X_POSITION, + TEXT_Y_POSITION, " <", 3, 0); +} + +void draw_right_button(nstate *state) +{ + if(!state->running_buttons_mapped) return; + GrFillRect(state->right_button, state->buttongcb, 0, 0, + RIGHT_BUTTON_WIDTH, RIGHT_BUTTON_HEIGHT); + GrText(state->right_button, state->buttongcf, TEXT_X_POSITION, + TEXT_Y_POSITION, " >", 4, 0); +} + +void draw_drop_button(nstate *state) +{ + if(!state->running_buttons_mapped) return; + GrFillRect(state->drop_button, state->buttongcb, 0, 0, + DROP_BUTTON_WIDTH, DROP_BUTTON_HEIGHT); + GrText(state->drop_button, state->buttongcf, TEXT_X_POSITION, + TEXT_Y_POSITION, " Drop", 8, 0); +} + +void draw_pause_continue_button(nstate *state) +{ + if((state->running_buttons_mapped) && (state->state == STATE_STOPPED)) { + GrUnmapWindow(state->pause_continue_button); + GrUnmapWindow(state->anticlockwise_button); + GrUnmapWindow(state->clockwise_button); + GrUnmapWindow(state->left_button); + GrUnmapWindow(state->right_button); + GrUnmapWindow(state->drop_button); + state->running_buttons_mapped = 0; + return; + } + if((!state->running_buttons_mapped) && (state->state == STATE_RUNNING)){ + GrMapWindow(state->pause_continue_button); + GrMapWindow(state->anticlockwise_button); + GrMapWindow(state->clockwise_button); + GrMapWindow(state->left_button); + GrMapWindow(state->right_button); + GrMapWindow(state->drop_button); + state->running_buttons_mapped = 1; + return; + } + if(!state->running_buttons_mapped) return; + GrFillRect(state->pause_continue_button, state->buttongcb, 0, 0, + PAUSE_CONTINUE_BUTTON_WIDTH, PAUSE_CONTINUE_BUTTON_HEIGHT); + if(state->state == STATE_PAUSED) { + GrText(state->pause_continue_button, state->buttongcf, + TEXT_X_POSITION, TEXT_Y_POSITION, " Continue", 9, 0); + } else { + GrText(state->pause_continue_button, state->buttongcf, + TEXT_X_POSITION, TEXT_Y_POSITION, " Pause", 8, 0); + } +} + +int block_is_all_in_well(nstate *state) +{ + if(state->current_shape.y >= WELL_NOTVISIBLE) + return 1; + + return 0; +} + +void delete_line(nstate *state, int line) +{ + int x, y; + + if(line < WELL_NOTVISIBLE) return; + + for(y = line - 1; y; y--) + for(x = WELL_WIDTH; x; x--) + state->blocks[0][y + 1][x] = state->blocks[0][y][x]; + + draw_well(state, 0); +} + +void block_reached_bottom(nstate *state) +{ + int x, y; + + if(!block_is_all_in_well(state)) { + state->state = STATE_STOPPED; + return; + } + + for(y = WELL_HEIGHT - 1; y; y--) { + for(x = 0; x < WELL_WIDTH; x++) + if(!state->blocks[0][y][x]) goto nr; + msleep(DELETE_LINE_DELAY); + delete_line(state, y); + state->score += SCORE_INCREMENT; + if((LEVELS > (state->level + 1)) && (((state->level + 1) * + LEVEL_DIVISOR) <= state->score)) + state->level++; + draw_score(state); + y++; + nr: + } + + choose_new_shape(state); + draw_next_shape(state); +} + +void move_block(nstate *state, int direction) +{ + if(direction == 0) { + if(!state->current_shape.x) return; + else { + if(!will_collide(state, (state->current_shape.x - 1), + state->current_shape.y, + state->current_shape.orientation)) { + draw_shape(state, state->current_shape.x, + state->current_shape.y, 1); + state->current_shape.x--; + draw_shape(state, state->current_shape.x, + state->current_shape.y, 0); + draw_well(state, 0); + } + } + } else { + if(!will_collide(state, (state->current_shape.x + 1), + state->current_shape.y, + state->current_shape.orientation)) { + draw_shape(state, state->current_shape.x, + state->current_shape.y, 1); + state->current_shape.x++; + draw_shape(state, state->current_shape.x, + state->current_shape.y, 0); + draw_well(state, 0); + } + } +} + +void rotate_block(nstate *state, int direction) +{ + int neworientation = 0; + + if(direction == 0) { + if(!state->current_shape.orientation) + neworientation = MAXORIENTATIONS - 1; + else neworientation = state->current_shape.orientation - 1; + } else { + neworientation = state->current_shape.orientation + 1; + if(neworientation == MAXORIENTATIONS) neworientation = 0; + } + + if(!will_collide(state, state->current_shape.x, state->current_shape.y, + neworientation)) { + draw_shape(state, state->current_shape.x, + state->current_shape.y, 1); + state->current_shape.orientation = neworientation; + draw_shape(state, state->current_shape.x, + state->current_shape.y, 0); + draw_well(state, 0); + } +} + +int drop_block_1(nstate *state) +{ + if(will_collide(state, state->current_shape.x, + (state->current_shape.y + 1), + state->current_shape.orientation)) { + block_reached_bottom(state); + return 1; + } + + draw_shape(state, state->current_shape.x, state->current_shape.y, 1); + state->current_shape.y++; + draw_shape(state, state->current_shape.x, state->current_shape.y, 0); + + draw_well(state, 0); + + return 0; +} + +void drop_block(nstate *state) +{ + while(!drop_block_1(state)) msleep(DROP_BLOCK_DELAY); +} + +void handle_exposure_event(nstate *state) +{ + GR_EVENT_EXPOSURE *event = &state->event.exposure; + + if(event->wid == state->score_window) { + draw_score(state); + return; + } + if(event->wid == state->next_shape_window) { + draw_next_shape(state); + return; + } + if(event->wid == state->new_game_button) { + draw_new_game_button(state); + return; + } + if(event->wid == state->pause_continue_button) { + draw_pause_continue_button(state); + return; + } + if(event->wid == state->anticlockwise_button) { + draw_anticlockwise_button(state); + return; + } + if(event->wid == state->clockwise_button) { + draw_clockwise_button(state); + return; + } + if(event->wid == state->left_button) { + draw_left_button(state); + return; + } + if(event->wid == state->right_button) { + draw_right_button(state); + return; + } + if(event->wid == state->drop_button) { + draw_drop_button(state); + return; + } + if(event->wid == state->well_window) { + draw_well(state, 1); + return; + } +} + +void handle_mouse_event(nstate *state) +{ + GR_EVENT_MOUSE *event = &state->event.mouse; + + if(event->wid == state->new_game_button) { + state->state = STATE_NEWGAME; + return; + } + if(event->wid == state->pause_continue_button) { + if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; + else state->state = STATE_PAUSED; + return; + } + if(event->wid == state->anticlockwise_button) { + if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; + rotate_block(state, 0); + return; + } + if(event->wid == state->clockwise_button) { + if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; + rotate_block(state, 1); + return; + } + if(event->wid == state->left_button) { + if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; + move_block(state, 0); + return; + } + if(event->wid == state->right_button) { + if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; + move_block(state, 1); + return; + } + if(event->wid == state->drop_button) { + if(state->state == STATE_PAUSED) state->state = STATE_RUNNING; + drop_block(state); + return; + } +} + +void handle_keyboard_event(nstate *state) +{ + GR_EVENT_KEYSTROKE *event = &state->event.keystroke; + + switch(event->ch) { + case 'q': + case 'Q': + case MWKEY_CANCEL: + state->state = STATE_EXIT; + return; + case 'n': + case 'N': + case MWKEY_APP1: + state->state = STATE_NEWGAME; + return; + } + + if(state->state == STATE_STOPPED) return; + + state->state = STATE_RUNNING; + + switch(event->ch) { + case 'p': + case 'P': + state->state = STATE_PAUSED; + break; + case 'j': + case 'J': + case MWKEY_LEFT: + move_block(state, 0); + break; + case 'k': + case 'K': + case MWKEY_RIGHT: + move_block(state, 1); + break; + case 'd': + case 'D': + case MWKEY_UP: + rotate_block(state, 0); + break; + case 'f': + case 'F': + case MWKEY_DOWN: + rotate_block(state, 1); + break; + case ' ': + case MWKEY_MENU: + drop_block(state); + break; + } +} + +void handle_event(nstate *state) +{ + switch(state->event.type) { + case GR_EVENT_TYPE_EXPOSURE: + handle_exposure_event(state); + break; + case GR_EVENT_TYPE_BUTTON_DOWN: + handle_mouse_event(state); + break; + case GR_EVENT_TYPE_KEY_DOWN: + handle_keyboard_event(state); + break; + case GR_EVENT_TYPE_CLOSE_REQ: + state->state = STATE_EXIT; + break; + case GR_EVENT_TYPE_TIMEOUT: + break; + default: + fprintf(stderr, "Unhandled event type %d\n", + state->event.type); + break; + } +} + +void clear_well(nstate *state) +{ + int x, y; + + for(y = 0; y < WELL_HEIGHT; y++) + for(x = 0; x < WELL_WIDTH; x++) { + state->blocks[0][y][x] = 0; + state->blocks[1][y][x] = 0; + } +} + +/* Dirty hack alert- this is to avoid using any floating point math */ +int random8(int limit) +{ + int ret; + + do { ret = random() & 7; } while(ret > limit); + + return ret; +} + +void choose_new_shape(nstate *state) +{ + state->current_shape.type = state->next_shape.type; + state->current_shape.orientation = state->next_shape.orientation; + state->current_shape.colour = state->next_shape.colour; + state->current_shape.x = (WELL_WIDTH / 2) - 2; + state->current_shape.y = WELL_NOTVISIBLE - + shape_sizes[state->next_shape.type] + [state->next_shape.orientation][1] - 1; + state->next_shape.type = random8(MAXSHAPES - 1); + state->next_shape.orientation = random8(MAXORIENTATIONS - 1); + state->next_shape.colour = block_colours[random8(MAX_BLOCK_COLOUR)]; +} + +void new_game(nstate *state) +{ + clear_well(state); + if(state->score > state->hiscore) state->hiscore = state->score; + state->score = 0; + state->level = 0; + draw_score(state); + choose_new_shape(state); + draw_next_shape(state); + draw_well(state, 1); + if(state->state == STATE_NEWGAME) state->state = STATE_RUNNING; +} + +void init_game(nstate *state) +{ + GR_WM_PROPERTIES props; + + if(GrOpen() < 0) { + fprintf(stderr, "Couldn't connect to Nano-X server\n"); + exit(1); + } + + state->main_window = GrNewWindow(GR_ROOT_WINDOW_ID, + MAIN_WINDOW_X_POSITION, + MAIN_WINDOW_Y_POSITION, + MAIN_WINDOW_WIDTH, + MAIN_WINDOW_HEIGHT, 0, + MAIN_WINDOW_BACKGROUND_COLOUR, 0); + /* set title */ + props.flags = GR_WM_FLAGS_TITLE | GR_WM_FLAGS_PROPS; + props.props = GR_WM_PROPS_BORDER | GR_WM_PROPS_CAPTION; + props.title = "Nano-Tetris"; + GrSetWMProperties(state->main_window, &props); + GrSelectEvents(state->main_window, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_CLOSE_REQ | + GR_EVENT_MASK_KEY_DOWN | + GR_EVENT_MASK_TIMEOUT); + + state->score_window = GrNewWindow(state->main_window, + SCORE_WINDOW_X_POSITION, + SCORE_WINDOW_Y_POSITION, + SCORE_WINDOW_WIDTH, + SCORE_WINDOW_HEIGHT, 0, + SCORE_WINDOW_BACKGROUND_COLOUR, 0); + GrSelectEvents(state->score_window, GR_EVENT_MASK_EXPOSURE); + GrMapWindow(state->score_window); + state->scoregcf = GrNewGC(); + GrSetGCForeground(state->scoregcf, SCORE_WINDOW_FOREGROUND_COLOUR); + GrSetGCBackground(state->scoregcf, SCORE_WINDOW_BACKGROUND_COLOUR); + state->scoregcb = GrNewGC(); + GrSetGCForeground(state->scoregcb, SCORE_WINDOW_BACKGROUND_COLOUR); + + state->next_shape_window = GrNewWindow(state->main_window, + NEXT_SHAPE_WINDOW_X_POSITION, + NEXT_SHAPE_WINDOW_Y_POSITION, + NEXT_SHAPE_WINDOW_WIDTH, + NEXT_SHAPE_WINDOW_HEIGHT, 0, + NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR, 0); + GrSelectEvents(state->next_shape_window, GR_EVENT_MASK_EXPOSURE); + GrMapWindow(state->next_shape_window); + state->nextshapegcf = GrNewGC(); + state->nextshapegcb = GrNewGC(); + GrSetGCForeground(state->nextshapegcb, + NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR); + + state->new_game_button = GrNewWindow(state->main_window, + NEW_GAME_BUTTON_X_POSITION, + NEW_GAME_BUTTON_Y_POSITION, + NEW_GAME_BUTTON_WIDTH, + NEW_GAME_BUTTON_HEIGHT, 0, + BUTTON_BACKGROUND_COLOUR, 0); + GrSelectEvents(state->new_game_button, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + GrMapWindow(state->new_game_button); + state->buttongcf = GrNewGC(); + GrSetGCForeground(state->buttongcf, BUTTON_FOREGROUND_COLOUR); + GrSetGCBackground(state->buttongcf, BUTTON_BACKGROUND_COLOUR); + state->buttongcb = GrNewGC(); + GrSetGCForeground(state->buttongcb, BUTTON_BACKGROUND_COLOUR); + + state->pause_continue_button = GrNewWindow(state->main_window, + PAUSE_CONTINUE_BUTTON_X_POSITION, + PAUSE_CONTINUE_BUTTON_Y_POSITION, + PAUSE_CONTINUE_BUTTON_WIDTH, + PAUSE_CONTINUE_BUTTON_HEIGHT, 0, + BUTTON_BACKGROUND_COLOUR, 0); + GrSelectEvents(state->pause_continue_button, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + state->anticlockwise_button = GrNewWindow(state->main_window, + ANTICLOCKWISE_BUTTON_X_POSITION, + ANTICLOCKWISE_BUTTON_Y_POSITION, + ANTICLOCKWISE_BUTTON_WIDTH, + ANTICLOCKWISE_BUTTON_HEIGHT, 0, + BUTTON_BACKGROUND_COLOUR, + 0); + GrSelectEvents(state->anticlockwise_button, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + state->clockwise_button = GrNewWindow(state->main_window, + CLOCKWISE_BUTTON_X_POSITION, + CLOCKWISE_BUTTON_Y_POSITION, + CLOCKWISE_BUTTON_WIDTH, + CLOCKWISE_BUTTON_HEIGHT, 0, + BUTTON_BACKGROUND_COLOUR, + 0); + GrSelectEvents(state->clockwise_button, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + state->left_button = GrNewWindow(state->main_window, + LEFT_BUTTON_X_POSITION, + LEFT_BUTTON_Y_POSITION, + LEFT_BUTTON_WIDTH, + LEFT_BUTTON_HEIGHT, 0, + BUTTON_BACKGROUND_COLOUR, + 0); + GrSelectEvents(state->left_button, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + state->right_button = GrNewWindow(state->main_window, + RIGHT_BUTTON_X_POSITION, + RIGHT_BUTTON_Y_POSITION, + RIGHT_BUTTON_WIDTH, + RIGHT_BUTTON_HEIGHT, 0, + BUTTON_BACKGROUND_COLOUR, + 0); + GrSelectEvents(state->right_button, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + state->drop_button = GrNewWindow(state->main_window, + DROP_BUTTON_X_POSITION, + DROP_BUTTON_Y_POSITION, + DROP_BUTTON_WIDTH, + DROP_BUTTON_HEIGHT, 0, + BUTTON_BACKGROUND_COLOUR, + 0); + GrSelectEvents(state->drop_button, GR_EVENT_MASK_EXPOSURE | + GR_EVENT_MASK_BUTTON_DOWN); + + state->well_window = GrNewWindow(state->main_window, + WELL_WINDOW_X_POSITION, + WELL_WINDOW_Y_POSITION, + WELL_WINDOW_WIDTH, + WELL_WINDOW_HEIGHT, 0, + WELL_WINDOW_BACKGROUND_COLOUR, 0); + GrSelectEvents(state->well_window, GR_EVENT_MASK_EXPOSURE); + GrMapWindow(state->well_window); + state->wellgc = GrNewGC(); + + GrMapWindow(state->main_window); + + state->state = STATE_STOPPED; + state->score = 0; + read_hiscore(state); + state->level = 0; + state->running_buttons_mapped = 0; + + srandom(time(0)); + + choose_new_shape(state); + new_game(state); +} + +void calculate_timeout(nstate *state) +{ + struct timeval t; + long u; + + gettimeofday(&t, NULL); + u = t.tv_usec + (delays[state->level] * 1000); + state->timeout.tv_sec = t.tv_sec + (u / 1000000); + state->timeout.tv_usec = u % 1000000; +} + +unsigned long timeout_delay(nstate *state) +{ + struct timeval t; + signed long s, m, ret; + + gettimeofday(&t, NULL); + + if((t.tv_sec > state->timeout.tv_sec) || + ((t.tv_sec == state->timeout.tv_sec) && + t.tv_usec >= state->timeout.tv_usec)) return 1; + + s = state->timeout.tv_sec - t.tv_sec; + m = ((state->timeout.tv_usec - t.tv_usec) / 1000); + ret = (unsigned long)((1000 * s) + m); +/* + fprintf(stderr, "t.tv_sec = %ld, t.tv_usec = %ld, timeout.tv_sec = " + "%ld, timeout.tv_usec = %ld, s = %ld, m = %ld, ret = %ld\n", + t.tv_sec, t.tv_usec, state->timeout.tv_sec, + state->timeout.tv_usec, s, m, ret); +*/ + if(ret <= 0) return 1; + else return ret; +} + +void do_update(nstate *state) +{ + struct timeval t; + + gettimeofday(&t, NULL); + + if((t.tv_sec > state->timeout.tv_sec) || + ((t.tv_sec == state->timeout.tv_sec) && + (t.tv_usec >= state->timeout.tv_usec))) { + drop_block_1(state); + calculate_timeout(state); + } +} + +void do_pause(nstate *state) +{ + draw_pause_continue_button(state); + while(state->state == STATE_PAUSED) { + GrGetNextEvent(&state->event); + handle_event(state); + } + draw_pause_continue_button(state); +} + +void wait_for_start(nstate *state) +{ + draw_pause_continue_button(state); + while(state->state == STATE_STOPPED) { + GrGetNextEvent(&state->event); + handle_event(state); + } + if(state->state == STATE_NEWGAME) state->state = STATE_RUNNING; + draw_pause_continue_button(state); + calculate_timeout(state); +} + +void run_game(nstate *state) +{ + while(state->state == STATE_RUNNING) { + GrGetNextEventTimeout(&state->event, timeout_delay(state)); + handle_event(state); + if(state->state == STATE_PAUSED) do_pause(state); + if(state->state == STATE_RUNNING) do_update(state); + } +} + +void main_game_loop(nstate *state) +{ + wait_for_start(state); + while(state->state != STATE_EXIT) { + if(state->state == STATE_RUNNING) run_game(state); + if(state->state == STATE_STOPPED) wait_for_start(state); + if(state->state != STATE_EXIT) new_game(state); + } +} + +int main(int argc, char *argv[]) +{ + nstate *state = my_malloc(sizeof(nstate)); + + init_game(state); + main_game_loop(state); + + write_hiscore(state); + + GrClose(); + + return 0; +} Index: t1demo.c =================================================================== --- t1demo.c (nonexistent) +++ t1demo.c (revision 174) @@ -0,0 +1,191 @@ +/* + * font demo for Nano-X + * also includes region clipping demo + */ +#include +#include +#if UNIX | DOS_DJGPP +#include +#endif +#define MWINCLUDECOLORS +#include "nano-X.h" + +#define MAXW (630-50) +#define MAXH (470-50) + +#define CLIP_POLYGON 0 /* =1 for polygonal region test*/ + +#if HAVE_HZK_SUPPORT +#define BIG5 + +#define MAXFONTS 1 +#ifndef BIG5 +#define FONT1 "HZKFONT" +#define FONT2 "HZKFONT" +#define FONT3 "HZKFONT" +#define FONT4 "HZKFONT" +#define FONT5 "HZKFONT" +#else +#define FONT1 "HZXFONT" +#define FONT2 "HZXFONT" +#define FONT3 "HZXFONT" +#define FONT4 "HZXFONT" +#define FONT5 "HZXFONT" +#endif +#elif HAVE_T1LIB_SUPPORT +#define MAXFONTS 5 +#define FONT1 "bchr" +#define FONT2 "bchb" +#define FONT3 "dcr10" +#define FONT4 "dcbx10" +#define FONT5 "bchri" +#else +/* truetype*/ +#define MAXFONTS 5 +#define FONT1 "lt1-r-omega-serif" +#define FONT2 "arial" +#define FONT3 "times" +#define FONT4 "cour" +#define FONT5 "timesi" +#endif + +static char * names[5] = { FONT1, FONT2, FONT3, FONT4, FONT5 }; + +int main() +{ + GR_WINDOW_ID window; + GR_EVENT event; + GR_GC_ID gc; + GR_FONT_ID fontid; + int i, x, y; + GR_REGION_ID regionid = 0; +#if CLIP_POLYGON + GR_POINT points[]={ {100, 100}, + {300, 100}, + {300, 300}, + {100, 300}}; +#else + GR_RECT clip_rect={100,100,300,300}; +#endif + + srand(time(0)); + + GrOpen(); + window = GrNewWindow(GR_ROOT_WINDOW_ID, 50,50, MAXW,MAXH, 4, BLACK,BLUE); + GrMapWindow(window); + + gc = GrNewGC(); + +#if CLIP_POLYGON + /* polygon clip region*/ + regionid = GrNewPolygonRegion(MWPOLY_EVENODD, 3, points); +#else + /* rectangle clip region*/ + regionid = GrNewRegion(); + GrUnionRectWithRegion(regionid, &clip_rect); +#endif + + GrSetGCRegion(gc, regionid); + + GrSelectEvents(window,GR_EVENT_MASK_ALL); + GrSetGCUseBackground(gc,GR_FALSE); + GrSetGCBackground(gc, GR_RGB(0, 0, 0)); + while(1) { + GrCheckNextEvent(&event); + + i = (int)((float)MAXFONTS * rand() / (RAND_MAX + 1.0)); + fontid = GrCreateFont(names[i], 20, NULL); + GrSetFontSize(fontid, 1+(int)(80.0 * rand() / (RAND_MAX+1.0))); + GrSetFontRotation(fontid, 330); /* 33 degrees*/ + GrSetFontAttr(fontid, GR_TFKERNING | GR_TFANTIALIAS, 0); + GrSetGCFont(gc, fontid); + /*GrSetGCBackground(gc, rand() & 0xffffff);*/ + GrSetGCForeground(gc, rand() & 0xffffff); + x = (int) ((MAXW * 1.0) *rand()/(RAND_MAX+1.0)); + y = (int) ((MAXH * 1.0) *rand()/(RAND_MAX+1.0)); + +#if HAVE_HZK_SUPPORT + { /* to test Unicode 16 chinese characters display ,use HZK font Bitmap font (Metrix font). */ +#ifndef BIG5 + char buffer[256]; + buffer[0]=0x6c; + buffer[1]=0x49; + buffer[2]=0x73; + buffer[3]=0x8b; + buffer[4]=0x79; + buffer[5]=0xd1; + buffer[6]=0x62; + buffer[7]=0x80; + buffer[8]=0x61; + buffer[9]=0x00; + buffer[10]=0x41; + buffer[11]=0x00; + + buffer[12]=0x00; + buffer[13]=0xa1; + buffer[14]=0x00; + buffer[15]=0xa6; + buffer[16]=0x6c; + buffer[17]=0x49; + buffer[18]=0x0; + buffer[19]=0x0; + GrText(window, gc,x,y+20, buffer,17, GR_TFUC16); + x=0;y=16; + GrText(window, gc,x,y+20, buffer,17, GR_TFUC16); +#else + unsigned short buffer[7]; + buffer[0]=0x9060; + buffer[1]=0x898b; + buffer[2]=0x79d1; + buffer[3]=0x6280; + buffer[4]=0x0061; + buffer[5]=0x0041; + buffer[6]=0x0; + GrText(window, gc,x,y+20, buffer,7, GR_TFUC16); + x=0;y=16; + GrText(window, gc,x,y+20, buffer,7, GR_TFUC16); +#endif + } + +#ifndef BIG5 + x=0;y=16; + /* HZK Metrix font test, includes Chinese and English*/ + GrText(window, gc,x,y, "Microwindows,欢迎使用中英文点阵字体", + -1, GR_TFASCII); +#else + GrText(window, gc,x,y, "Microwindows,舧ㄏノい璣ゅ翴皚砰", + -1, GR_TFASCII); + x=0;y=16*3+4; + GrText(window, gc,x,y, "89:", -1, GR_TFASCII); +#endif + GrFlush(); + +#else /* !HZK_FONT_SUPPORT*/ + +#if HAVE_BIG5_SUPPORT + /* ENCODING_BIG5 test*/ + GrText(window, gc,x,y, "眃眃", -1, GR_TFASCII); +#else +#if HAVE_GB2312_SUPPORT + /* ENCODING_GB2312 test*/ + GrText(window, gc,x,y, "\275\241\275\241", -1, GR_TFASCII); +#else + /* ASCII test*/ + GrText(window, gc,x,y, "Microwindows", -1, GR_TFASCII); +#endif +#endif + +#endif /* HZK_FONT_SUPPORT*/ + + + GrDestroyFont(fontid); + + if(event.type == GR_EVENT_TYPE_CLOSE_REQ) { + GrClose(); + exit(0); + } + } + + GrDestroyRegion(regionid); + GrClose(); +} Index: ntetris.h =================================================================== --- ntetris.h (nonexistent) +++ ntetris.h (revision 174) @@ -0,0 +1,414 @@ +#ifndef NTETRIS_H +#define NTETRIS_H + +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is NanoTetris. + * + * The Initial Developer of the Original Code is Alex Holden. + * Portions created by Alex Holden are Copyright (C) 2000 + * Alex Holden . All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public license (the "[GNU] License"), in which case the + * provisions of [GNU] License are applicable instead of those + * above. If you wish to allow use of your version of this file only + * under the terms of the [GNU] License and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the [GNU] License. If you do not delete + * the provisions above, a recipient may use your version of this file + * under either the MPL or the [GNU] License. + */ + +/* + * Anything which is configurable should be in this file. + * Unfortunately I haven't really bothered to comment anything except for the + * array of shape descriptions (you can add your own new shapes quite easily). + */ + +#ifndef __ECOS +#define USE_HISCORE_FILE +#define HISCORE_FILE "/usr/games/nanotetris.hiscore" +#endif +#undef HAVE_USLEEP +#define BLOCK_SIZE 10 +#define BORDER_WIDTH 10 +#define CONTROL_BAR_WIDTH 90 +#define BUTTON_HEIGHT 20 +#define BUTTON_WIDTH (CONTROL_BAR_WIDTH - BORDER_WIDTH) +#define BUTTON_BACKGROUND_COLOUR LTGRAY +#define BUTTON_FOREGROUND_COLOUR BLACK +#define MOVEMENT_BUTTON_WIDTH ((BUTTON_WIDTH / 2) - 1) +#define TEXT_X_POSITION 5 +#define TEXT_Y_POSITION 15 +#define TEXT2_Y_POSITION 30 +#define WELL_WIDTH 12 +#define WELL_HEIGHT 28 +#define WELL_VISIBLE_HEIGHT 24 +#define WELL_NOTVISIBLE (WELL_HEIGHT - WELL_VISIBLE_HEIGHT) +#define LEVEL_DIVISOR 500 +#ifdef __ECOS +#define DROP_BLOCK_DELAY 10 +#else +#define DROP_BLOCK_DELAY 25 +#endif +#define DELETE_LINE_DELAY 300 +#define SCORE_INCREMENT 100 + +#define MAIN_WINDOW_X_POSITION 0 +#define MAIN_WINDOW_Y_POSITION 0 +#define MAIN_WINDOW_WIDTH (CONTROL_BAR_WIDTH + (2 * BORDER_WIDTH) + \ + (WELL_WIDTH * BLOCK_SIZE)) +#define MAIN_WINDOW_HEIGHT ((2 * BORDER_WIDTH) + \ + (WELL_VISIBLE_HEIGHT * BLOCK_SIZE)) +#define MAIN_WINDOW_BACKGROUND_COLOUR BLUE + +#define SCORE_WINDOW_WIDTH BUTTON_WIDTH +#define SCORE_WINDOW_HEIGHT 35 +#define SCORE_WINDOW_X_POSITION BORDER_WIDTH +#define SCORE_WINDOW_Y_POSITION BORDER_WIDTH +#define SCORE_WINDOW_BACKGROUND_COLOUR BLACK +#define SCORE_WINDOW_FOREGROUND_COLOUR LTGREEN + +#define NEXT_SHAPE_WINDOW_SIZE 6 +#define NEXT_SHAPE_WINDOW_WIDTH (NEXT_SHAPE_WINDOW_SIZE * BLOCK_SIZE) +#define NEXT_SHAPE_WINDOW_HEIGHT (NEXT_SHAPE_WINDOW_SIZE * BLOCK_SIZE) +#define NEXT_SHAPE_WINDOW_X_POSITION (BORDER_WIDTH + 10) +#define NEXT_SHAPE_WINDOW_Y_POSITION ((2 * BORDER_WIDTH) + SCORE_WINDOW_HEIGHT) +#define NEXT_SHAPE_WINDOW_BACKGROUND_COLOUR BLACK + +#define NEW_GAME_BUTTON_WIDTH BUTTON_WIDTH +#define NEW_GAME_BUTTON_HEIGHT BUTTON_HEIGHT +#define NEW_GAME_BUTTON_X_POSITION BORDER_WIDTH +#define NEW_GAME_BUTTON_Y_POSITION ((3 * BORDER_WIDTH) + SCORE_WINDOW_HEIGHT \ + + NEXT_SHAPE_WINDOW_HEIGHT) + +#define PAUSE_CONTINUE_BUTTON_WIDTH BUTTON_WIDTH +#define PAUSE_CONTINUE_BUTTON_HEIGHT BUTTON_HEIGHT +#define PAUSE_CONTINUE_BUTTON_X_POSITION BORDER_WIDTH +#define PAUSE_CONTINUE_BUTTON_Y_POSITION ((4 * BORDER_WIDTH) + \ + SCORE_WINDOW_HEIGHT + NEXT_SHAPE_WINDOW_HEIGHT + \ + NEW_GAME_BUTTON_HEIGHT) + +#define ANTICLOCKWISE_BUTTON_WIDTH MOVEMENT_BUTTON_WIDTH +#define ANTICLOCKWISE_BUTTON_HEIGHT BUTTON_HEIGHT +#define ANTICLOCKWISE_BUTTON_X_POSITION BORDER_WIDTH +#define ANTICLOCKWISE_BUTTON_Y_POSITION ((5 * BORDER_WIDTH) + \ + SCORE_WINDOW_HEIGHT + NEXT_SHAPE_WINDOW_HEIGHT + \ + NEW_GAME_BUTTON_HEIGHT + PAUSE_CONTINUE_BUTTON_HEIGHT) + +#define CLOCKWISE_BUTTON_WIDTH MOVEMENT_BUTTON_WIDTH +#define CLOCKWISE_BUTTON_HEIGHT BUTTON_HEIGHT +#define CLOCKWISE_BUTTON_X_POSITION (ANTICLOCKWISE_BUTTON_X_POSITION + \ + ANTICLOCKWISE_BUTTON_WIDTH + 2) +#define CLOCKWISE_BUTTON_Y_POSITION ANTICLOCKWISE_BUTTON_Y_POSITION + +#define LEFT_BUTTON_WIDTH MOVEMENT_BUTTON_WIDTH +#define LEFT_BUTTON_HEIGHT BUTTON_HEIGHT +#define LEFT_BUTTON_X_POSITION BORDER_WIDTH +#define LEFT_BUTTON_Y_POSITION (ANTICLOCKWISE_BUTTON_Y_POSITION + \ + ANTICLOCKWISE_BUTTON_HEIGHT + 2) + +#define RIGHT_BUTTON_WIDTH MOVEMENT_BUTTON_WIDTH +#define RIGHT_BUTTON_HEIGHT BUTTON_HEIGHT +#define RIGHT_BUTTON_X_POSITION (LEFT_BUTTON_X_POSITION + LEFT_BUTTON_WIDTH + 2) +#define RIGHT_BUTTON_Y_POSITION LEFT_BUTTON_Y_POSITION + +#define DROP_BUTTON_WIDTH BUTTON_WIDTH +#define DROP_BUTTON_HEIGHT BUTTON_HEIGHT +#define DROP_BUTTON_X_POSITION BORDER_WIDTH +#define DROP_BUTTON_Y_POSITION (LEFT_BUTTON_Y_POSITION + LEFT_BUTTON_HEIGHT + 2) + +#define WELL_WINDOW_WIDTH (BLOCK_SIZE * WELL_WIDTH) +#define WELL_WINDOW_HEIGHT (BLOCK_SIZE * WELL_VISIBLE_HEIGHT) +#define WELL_WINDOW_X_POSITION (CONTROL_BAR_WIDTH + BORDER_WIDTH) +#define WELL_WINDOW_Y_POSITION BORDER_WIDTH +#define WELL_WINDOW_BACKGROUND_COLOUR BLACK + +enum { + STATE_STOPPED, + STATE_RUNNING, + STATE_PAUSED, + STATE_NEWGAME, + STATE_EXIT, + STATE_UNKNOWN +}; + +typedef GR_COLOR block; + +struct ntetris_shape { + int type; + int orientation; + GR_COLOR colour; + int x; + int y; +}; +typedef struct ntetris_shape shape; + +struct ntetris_state { + block blocks[2][WELL_HEIGHT][WELL_WIDTH]; + int score; + int hiscore; + int fhiscore; + int level; + int state; + int running_buttons_mapped; + shape current_shape; + shape next_shape; + GR_WINDOW_ID main_window; + GR_WINDOW_ID score_window; + GR_WINDOW_ID next_shape_window; + GR_WINDOW_ID new_game_button; + GR_WINDOW_ID pause_continue_button; + GR_WINDOW_ID anticlockwise_button; + GR_WINDOW_ID clockwise_button; + GR_WINDOW_ID left_button; + GR_WINDOW_ID right_button; + GR_WINDOW_ID drop_button; + GR_WINDOW_ID well_window; + GR_GC_ID scoregcf; + GR_GC_ID scoregcb; + GR_GC_ID nextshapegcf; + GR_GC_ID nextshapegcb; + GR_GC_ID buttongcf; + GR_GC_ID buttongcb; + GR_GC_ID wellgc; + GR_EVENT event; + struct timeval timeout; +}; +typedef struct ntetris_state nstate; + +void *my_malloc(size_t size); +void msleep(long ms); +void read_hiscore(nstate *state); +void write_hiscore(nstate *state); +int will_collide(nstate *state, int x, int y, int orientation); +void draw_shape(nstate *state, GR_COORD x, GR_COORD y, int erase); +void draw_well(nstate *state, int forcedraw); +void draw_score(nstate *state); +void draw_next_shape(nstate *state); +void draw_new_game_button(nstate *state); +void draw_anticlockwise_button(nstate *state); +void draw_clockwise_button(nstate *state); +void draw_left_button(nstate *state); +void draw_right_button(nstate *state); +void draw_drop_button(nstate *state); +void draw_pause_continue_button(nstate *state); +int block_is_all_in_well(nstate *state); +void delete_line(nstate *state, int line); +void block_reached_bottom(nstate *state); +void move_block(nstate *state, int direction); +void rotate_block(nstate *state, int direction); +void drop_block(nstate *state); +void handle_exposure_event(nstate *state); +void handle_mouse_event(nstate *state); +void handle_keyboard_event(nstate *state); +void handle_event(nstate *state); +void clear_well(nstate *state); +int random8(int limit); +void choose_new_shape(nstate *state); +void new_game(nstate *state); +void init_game(nstate *state); +void calculate_timeout(nstate *state); +unsigned long timeout_delay(nstate *state); +void do_update(nstate *state); +void do_pause(nstate *state); +void wait_for_start(nstate *state); +void run_game(nstate *state); +void main_game_loop(nstate *state); + +#define LEVELS 12 +static const int delays[] = {600, 550, 500, 450, 400, 350, + 300, 250, 200, 150, 100, 50}; +#define MAX_BLOCK_COLOUR 3 +static const GR_COLOR block_colours[] = { + LTRED, LTGREEN, LTBLUE, YELLOW +}; + +/* + * This isn't the most space efficient way of storing the shape patterns, but + * it's quick and easy to parse, and only takes a few hundred bytes of code + * space anyway. 0 means "not filled", 1 means "filled", 2 means "go to next + * line", and 3 means "end of pattern". There are four patterns for each shape; + * one for each orientation. Adding new shapes is quite easy- just increase + * MAXSHAPES by the number of shapes you add, then add the four pattern + * descriptions (each one should be the previous one rotated clockwise) for + * each shape. If you need to use more than MAXROWS rows (including the "end + * of line" marker), increase MAXROWS. Ditto for MAXCOLS. Increasing + * MAXORIENTATIONS (to get more than four orientations) may work, but it's + * untested, and remember that if you increase it you'll have to add the new + * orientations for all of the original shapes as well as your new ones. Also + * remember to add the new shapes the the array of shape sizes below. + */ +#define MAXSHAPES 7 +#define MAXORIENTATIONS 4 +#define MAXCOLS 5 +#define MAXROWS 4 +static const char shapes[MAXSHAPES][MAXORIENTATIONS][MAXROWS][MAXCOLS] = { + { /* **** */ + { + {1,1,1,1,3} + }, + { + {1,2}, + {1,2}, + {1,2}, + {1,3} + }, + { + {1,1,1,1,3} + }, + { + {1,2}, + {1,2}, + {1,2}, + {1,3} + } + }, + { /* * + *** */ + { + {0,0,1,2}, + {1,1,1,3} + }, + { + {1,2}, + {1,2}, + {1,1,3} + }, + { + {1,1,1,2}, + {1,3} + }, + { + {1,1,2}, + {0,1,2}, + {0,1,3} + } + }, + { /* * + *** */ + { + {1,2}, + {1,1,1,3} + }, + { + {1,1,2}, + {1,2}, + {1,3} + }, + { + {1,1,1,2}, + {0,0,1,3} + }, + { + {0,1,2}, + {0,1,2}, + {1,1,3} + } + }, + { /* ** + ** */ + { + {1,1,2}, + {0,1,1,3} + }, + { + {0,1,2}, + {1,1,2}, + {1,3} + }, + { + {1,1,2}, + {0,1,1,3} + }, + { + {0,1,2}, + {1,1,2}, + {1,3} + } + }, + { /* ** + ** */ + { + {0,1,1,2}, + {1,1,3} + }, + { + {1,2}, + {1,1,2}, + {0,1,3} + }, + { + {0,1,1,2}, + {1,1,3} + }, + { + {1,2}, + {1,1,2}, + {0,1,3} + } + }, + { /* ** + ** */ + { + {1,1,2}, + {1,1,3} + }, + { + {1,1,2}, + {1,1,3} + }, + { + {1,1,2}, + {1,1,3} + }, + { + {1,1,2}, + {1,1,3} + } + }, + { /* * + *** */ + { + {0,1,2}, + {1,1,1,3} + }, + { + {1,2}, + {1,1,2}, + {1,3} + }, + { + {1,1,1,2}, + {0,1,3} + }, + { + {0,1,2}, + {1,1,2}, + {0,1,3} + } + } +}; +static const unsigned char shape_sizes[MAXSHAPES][MAXORIENTATIONS][2] = { + {{4,1},{1,4},{4,1},{1,4}}, + {{3,2},{2,3},{3,2},{2,3}}, + {{3,2},{2,3},{3,2},{2,3}}, + {{3,2},{2,3},{3,2},{2,3}}, + {{3,2},{2,3},{3,2},{2,3}}, + {{2,2},{2,2},{2,2},{2,2}}, + {{3,2},{2,3},{3,2},{2,3}} +}; +#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.