X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fmain-x11.c;h=1073be3f93684623ef82ec2b15371e5803e99513;hb=8c269bce318e5179aa5c6586c406841e3ffcd877;hp=c7f6d6658affa1a70306fe5d97e26ad83db0773d;hpb=3fccd87834d9d3b4cdd44d32c6d6f3570c2bffc1;p=hengband%2Fhengband.git diff --git a/src/main-x11.c b/src/main-x11.c index c7f6d6658..1073be3f9 100644 --- a/src/main-x11.c +++ b/src/main-x11.c @@ -9,7 +9,7 @@ */ -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT /* * ÆüËܸì(EUC-JAPAN)Âбþ (-DJP) * ¡¦´Á»ú¥Õ¥©¥ó¥È¤Î°·¤¤¤òÄɲà @@ -123,6 +123,7 @@ #if 0 char *XSetIMValues(XIM, ...); /* Hack for XFree86 4.0 */ #endif +#include #endif /* __MAKEDEPEND__ */ @@ -386,7 +387,7 @@ struct infofnt /* Init an infowin by giving father as an (info_win*) (or NULL), and data */ #define Infowin_init_dad(D,X,Y,W,H,B,FG,BG) \ Infowin_init_data(((D) ? ((D)->win) : (Window)(None)), \ - X,Y,W,H,B,FG,BG) + X,Y,W,H,B,FG,BG) /* Init a top level infowin by pos,size,bord,Colors */ @@ -455,7 +456,7 @@ static infowin *Infowin = (infowin*)(NULL); static infowin *Focuswin = (infowin*)(NULL); #endif static infoclr *Infoclr = (infoclr*)(NULL); -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT static infofnt *Infofnt = (infofnt*)(NULL); static infofnt *Infokfnt = (infofnt*)(NULL); #else @@ -468,9 +469,9 @@ static infofnt *Infofnt = (infofnt*)(NULL); /**** Generic code ****/ -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT #define Infokfnt_set(I) \ - (Infokfnt = (I)) + (Infokfnt = (I)) #endif /* * Init the current metadpy, with various initialization stuff. @@ -745,7 +746,7 @@ static errr Infowin_init_real(Window xid) * If 'dad == None' assume 'dad == root' */ static errr Infowin_init_data(Window dad, int x, int y, int w, int h, - int b, Pixell fg, Pixell bg) + int b, Pixell fg, Pixell bg) { Window xid; @@ -935,7 +936,7 @@ static errr Infowin_fill(void) { /* Execute the request */ XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, - 0, 0, Infowin->w, Infowin->h); + 0, 0, Infowin->w, Infowin->h); /* Success */ return (0); @@ -1161,7 +1162,7 @@ static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip) /* Set up the GC mask */ gc_mask = (GCFunction | GCBackground | GCForeground | - GCFillStyle | GCGraphicsExposures); + GCFillStyle | GCGraphicsExposures); /* Create the GC detailed above */ gc = XCreateGC(Metadpy->dpy, Metadpy->root, gc_mask, &gcv); @@ -1227,7 +1228,7 @@ static errr Infofnt_nuke(void) { infofnt *ifnt = Infofnt; -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT infofnt *ikfnt = Infokfnt; #endif /* Deal with 'name' */ @@ -1237,21 +1238,26 @@ static errr Infofnt_nuke(void) string_free(ifnt->name); } -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT if (ikfnt->name) { /* Free the name */ string_free(ikfnt->name); } #endif + /* Nuke info if needed */ if (ifnt->nuke) { /* Free the font */ +#ifdef USE_FONTSET + XFreeFontSet(Metadpy->dpy, ifnt->info); +#else XFreeFont(Metadpy->dpy, ifnt->info); +#endif } -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT if (ikfnt->nuke) { /* Free the font */ @@ -1268,7 +1274,7 @@ static errr Infofnt_nuke(void) /* * Prepare a new 'infofnt' */ -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT static errr Infofnt_prepare(XFontStruct *info, XFontStruct *kinfo) #else #ifdef USE_FONTSET @@ -1281,7 +1287,7 @@ static errr Infofnt_prepare(XFontStruct *info) { infofnt *ifnt = Infofnt; -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT infofnt *ikfnt = Infokfnt; #endif XCharStruct *cs; @@ -1330,7 +1336,7 @@ static errr Infofnt_prepare(XFontStruct *info) else ifnt->twid = ifnt->wid; -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT /* Assign the struct */ ikfnt->info = kinfo; @@ -1361,7 +1367,7 @@ static errr Infofnt_prepare(XFontStruct *info) /* * Initialize a new 'infofnt'. */ -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT static errr Infofnt_init_real(XFontStruct *info, XFontStruct *kinfo) #else #ifdef USE_FONTSET @@ -1375,17 +1381,17 @@ static errr Infofnt_init_real(XFontStruct *info) /* Wipe the thing */ (void)WIPE(Infofnt, infofnt); -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT WIPE(Infokfnt, infofnt); #endif /* No nuking */ Infofnt->nuke = 0; -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT Infokfnt->nuke = 0; #endif /* Attempt to prepare it */ -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT return (Infofnt_prepare (info, kinfo)); #else return (Infofnt_prepare(info)); @@ -1402,10 +1408,10 @@ static errr Infofnt_init_real(XFontStruct *info) * Inputs: * name: The name of the requested Font */ -#ifdef _JP -static errr Infofnt_init_data(cptr name, cptr kname) +#ifdef USE_JP_FONTSTRUCT +static void Infofnt_init_data(cptr name, cptr kname) #else -static errr Infofnt_init_data(cptr name) +static void Infofnt_init_data(cptr name) #endif { @@ -1419,16 +1425,16 @@ static errr Infofnt_init_data(cptr name) #endif -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT XFontStruct *kinfo; #endif /*** Load the info Fresh, using the name ***/ /* If the name is not given, report an error */ - if (!name) return (-1); + if (!name || !*name) quit("Missing font!"); -#ifdef _JP - if (!kname) return (-1); +#ifdef USE_JP_FONTSTRUCT + if (!kname || !*kname) quit("Missing kanji font!"); #endif /* Attempt to load the font */ #ifdef USE_FONTSET @@ -1442,16 +1448,16 @@ static errr Infofnt_init_data(cptr name) } #else info = XLoadQueryFont(Metadpy->dpy, name); -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT kinfo = XLoadQueryFont(Metadpy->dpy, kname); #endif #endif /* The load failed, try to recover */ - if (!info) return (-1); -#ifdef _JP - if (!kinfo) return (-1); + if (!info) quit_fmt("Failed to find font:\"%s\"", name); +#ifdef USE_JP_FONTSTRUCT + if (!kinfo) quit_fmt("Failed to find font:\"%s\"", kname); #endif @@ -1461,11 +1467,11 @@ static errr Infofnt_init_data(cptr name) /* Wipe the thing */ (void)WIPE(Infofnt, infofnt); -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT WIPE(Infokfnt, infofnt); #endif /* Attempt to prepare it */ -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT if (Infofnt_prepare(info, kinfo)) #else if (Infofnt_prepare(info)) @@ -1477,32 +1483,29 @@ static errr Infofnt_init_data(cptr name) XFreeFontSet(Metadpy->dpy, info); #else XFreeFont(Metadpy->dpy, info); -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT XFreeFont(Metadpy->dpy, kinfo); #endif #endif /* Fail */ - return (-1); + quit_fmt("Failed to prepare font:\"%s\"", name); } /* Save a copy of the font name */ Infofnt->name = string_make(name); -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT Infokfnt->name = string_make(kname); #endif /* Mark it as nukable */ Infofnt->nuke = 1; -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT Infokfnt->nuke = 1; #endif - - /* Success */ - return (0); } -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT /* * EUCÆüËܸ쥳¡¼¥É¤ò´Þ¤àʸ»úÎó¤òɽ¼¨¤¹¤ë (Xlib) */ @@ -1532,65 +1535,65 @@ XDrawMultiString(display,d,gc, x, y, string, len, afont, #ifdef TOFU if ( (*str) == 0x7f ) { - - /* 0x7F¤Ï¢£¤Ç·è¤áÂǤÁ */ - - /* Ϣ³¤¹¤ë0x7F¤ÎŤµ¤ò¸¡½Ð */ - slen = 0; - while ( str < endp && (*str) == 0x7f ) { - slen++; + + /* 0x7F¤Ï¢£¤Ç·è¤áÂǤÁ */ + + /* Ϣ³¤¹¤ë0x7F¤ÎŤµ¤ò¸¡½Ð */ + slen = 0; + while ( str < endp && (*str) == 0x7f ) { + slen++; str++; - } - - /* ÉÁ²è */ - XFillRectangle( display, d, gc, x, y-afont_ascent, - slen * afont_width, afont_height); + } + + /* ÉÁ²è */ + XFillRectangle( display, d, gc, x, y-afont_ascent, + slen * afont_width, afont_height); - /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */ - x += afont_width * slen; + /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */ + x += afont_width * slen; } else #endif if ( iskanji(*str) ) { - - /* UJIS¤Î»Ï¤Þ¤ê */ - - /* Ϣ³¤¹¤ëUJISʸ»ú¤ÎŤµ¤ò¸¡½Ð */ - slen = 0; - while ( str < endp && *str && iskanji(*str) ) { - kanji[slen].byte1 = *str++ & 0x7f; - kanji[slen++].byte2 = *str++ & 0x7f; - } - - /* ÉÁ²è */ - XSetFont( display, gc, kfont->fid ); - XDrawImageString16( display, d, gc, x, y, kanji, slen ); + + /* UJIS¤Î»Ï¤Þ¤ê */ + + /* Ϣ³¤¹¤ëUJISʸ»ú¤ÎŤµ¤ò¸¡½Ð */ + slen = 0; + while ( str < endp && *str && iskanji(*str) ) { + kanji[slen].byte1 = *str++ & 0x7f; + kanji[slen++].byte2 = *str++ & 0x7f; + } + + /* ÉÁ²è */ + XSetFont( display, gc, kfont->fid ); + XDrawImageString16( display, d, gc, x, y, kanji, slen ); - /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */ - x += kfont_width * slen; - + /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */ + x += kfont_width * slen; + } else { - - /* Èó´Á»ú(=ASCII¤È²¾Äê)¤Î»Ï¤Þ¤ê */ - - /* Ϣ³¤¹¤ëASCIIʸ»ú¤ò¸¡½Ð */ - p = str; - slen = 0; - while ( str < endp && *str && !iskanji(*str) ) { + + /* Èó´Á»ú(=ASCII¤È²¾Äê)¤Î»Ï¤Þ¤ê */ + + /* Ϣ³¤¹¤ëASCIIʸ»ú¤ò¸¡½Ð */ + p = str; + slen = 0; + while ( str < endp && *str && !iskanji(*str) ) { #ifdef TOFU - if (*str == 0x7f)break; -#endif - str++; - slen++; - } - - /* ÉÁ²è */ - XSetFont( display, gc, afont->fid ); - XDrawImageString( display, d, gc, x, y, p, slen ); - - /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */ - x += afont_width * slen; + if (*str == 0x7f)break; +#endif + str++; + slen++; + } + + /* ÉÁ²è */ + XSetFont( display, gc, afont->fid ); + XDrawImageString( display, d, gc, x, y, p, slen ); + + /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */ + x += afont_width * slen; } } } @@ -1626,19 +1629,17 @@ static errr Infofnt_text_std(int x, int y, cptr str, int len) /*** Actually draw 'str' onto the infowin ***/ -#if 1 -#ifndef JP +#ifndef USE_FONTSET /* Be sure the correct font is ready */ XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid); #endif -#endif /*** Handle the fake mono we can enforce on fonts ***/ /* Monotize the font */ if (Infofnt->mono) { -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT /* Be sure the correct font is ready */ XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid); #endif @@ -1647,7 +1648,7 @@ static errr Infofnt_text_std(int x, int y, cptr str, int len) { /* Note that the Infoclr is set up to contain the Infofnt */ XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc, - x + i * Infofnt->wid + Infofnt->off, y, str + i, 1); + x + i * Infofnt->wid + Infofnt->off, y, str + i, 1); } } @@ -1655,23 +1656,20 @@ static errr Infofnt_text_std(int x, int y, cptr str, int len) else { /* Note that the Infoclr is set up to contain the Infofnt */ -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT /* ´Á»ú¥Õ¥©¥ó¥È¤Îɽ¼¨Éý¤Ï ASCII¥Õ¥©¥ó¥È¤Î2Çܤ˸ÇÄê */ XDrawMultiString(Metadpy->dpy, Infowin->win, Infoclr->gc, - x, y, str, len, - Infofnt->info, Infofnt->wid, Infofnt->hgt, - Infofnt->asc, - Infokfnt->info, Infofnt->wid * 2); + x, y, str, len, + Infofnt->info, Infofnt->wid, Infofnt->hgt, + Infofnt->asc, + Infokfnt->info, Infofnt->wid * 2); #else #ifdef USE_FONTSET - /* Delete rectangle first */ - XClearArea(Metadpy->dpy, Infowin->win, x, y - Infofnt->asc, len * Infofnt->wid, Infofnt->hgt, FALSE); - XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info, - Infoclr->gc, x, y, str, len); + Infoclr->gc, x, y, str, len); #else XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc, - x, y, str, len); + x, y, str, len); #endif #endif @@ -1762,7 +1760,7 @@ struct term_data term t; infofnt *fnt; -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT infofnt *kfnt; #endif @@ -1773,15 +1771,11 @@ struct term_data XImage *tiles; -#ifdef USE_TRANSPARENCY - /* Tempory storage for overlaying tiles. */ XImage *TmpImage; #endif -#endif - }; @@ -1796,6 +1790,38 @@ struct term_data static term_data data[MAX_TERM_DATA]; +/* Use short names for the most commonly used elements of various structures. */ +#define DPY (Metadpy->dpy) +#define WIN (Infowin->win) + + +/* Describe a set of co-ordinates. */ +typedef struct co_ord co_ord; +struct co_ord +{ + int x; + int y; +}; + + +/* + * A special structure to store information about the text currently + * selected. + */ +typedef struct x11_selection_type x11_selection_type; +struct x11_selection_type +{ + bool select; /* The selection is currently in use. */ + bool drawn; /* The selection is currently displayed. */ + term *t; /* The window where the selection is found. */ + co_ord init; /* The starting co-ordinates. */ + co_ord cur; /* The end co-ordinates (the current ones if still copying). */ + co_ord old; /* The previous end co-ordinates. */ + Time time; /* The time at which the selection was finalised. */ +}; + +static x11_selection_type s_ptr[1]; + /* * Process a keypress event @@ -1898,6 +1924,10 @@ static void react_keypress(XKeyEvent *xev) } case XK_Delete: + { + Term_keypress(0x7f); + return; + } case XK_BackSpace: { Term_keypress('\010'); @@ -1910,18 +1940,18 @@ static void react_keypress(XKeyEvent *xev) if (ks) { sprintf(msg, "%c%s%s%s%s_%lX%c", 31, - mc ? "N" : "", ms ? "S" : "", - mo ? "O" : "", mx ? "M" : "", - (unsigned long)(ks), 13); + mc ? "N" : "", ms ? "S" : "", + mo ? "O" : "", mx ? "M" : "", + (unsigned long)(ks), 13); } /* Hack -- Use the Keycode */ else { sprintf(msg, "%c%s%s%s%sK_%X%c", 31, - mc ? "N" : "", ms ? "S" : "", - mo ? "O" : "", mx ? "M" : "", - ev->keycode, 13); + mc ? "N" : "", ms ? "S" : "", + mo ? "O" : "", mx ? "M" : "", + ev->keycode, 13); } /* Enqueue the "macro trigger" string */ @@ -1937,6 +1967,528 @@ static void react_keypress(XKeyEvent *xev) } +/* + * Find the square a particular pixel is part of. + */ +static void pixel_to_square(int * const x, int * const y, + const int ox, const int oy) +{ + (*x) = (ox - Infowin->ox) / Infofnt->wid; + (*y) = (oy - Infowin->oy) / Infofnt->hgt; +} + +/* + * Find the pixel at the top-left corner of a square. + */ +static void square_to_pixel(int * const x, int * const y, + const int ox, const int oy) +{ + (*x) = ox * Infofnt->wid + Infowin->ox; + (*y) = oy * Infofnt->hgt + Infowin->oy; +} + +/* + * Convert co-ordinates from starting corner/opposite corner to minimum/maximum. + */ +static void sort_co_ord(co_ord *min, co_ord *max, + const co_ord *b, const co_ord *a) +{ + min->x = MIN(a->x, b->x); + min->y = MIN(a->y, b->y); + max->x = MAX(a->x, b->x); + max->y = MAX(a->y, b->y); +} + +/* + * Remove the selection by redrawing it. + */ +static void mark_selection_clear(int x1, int y1, int x2, int y2) +{ + Term_redraw_section(x1,y1,x2,y2); +} + +/* + * Select an area by drawing a grey box around it. + * NB. These two functions can cause flicker as the selection is modified, + * as the game redraws the entire marked section. + */ +static void mark_selection_mark(int x1, int y1, int x2, int y2) +{ + square_to_pixel(&x1, &y1, x1, y1); + square_to_pixel(&x2, &y2, x2, y2); + XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1, + x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1); +} + +/* + * Mark a selection by drawing boxes around it (for now). + */ +static void mark_selection(void) +{ + co_ord min, max; + term *old = Term; + bool draw = s_ptr->select; + bool clear = s_ptr->drawn; + + /* Open the correct term if necessary. */ + if (s_ptr->t != old) Term_activate(s_ptr->t); + + if (clear) + { + sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old); + mark_selection_clear(min.x, min.y, max.x, max.y); + } + if (draw) + { + sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur); + mark_selection_mark(min.x, min.y, max.x, max.y); + } + + /* Finish on the current term. */ + if (s_ptr->t != old) Term_activate(old); + + s_ptr->old.x = s_ptr->cur.x; + s_ptr->old.y = s_ptr->cur.y; + s_ptr->drawn = s_ptr->select; +} + +/* + * Forget a selection for one reason or another. + */ +static void copy_x11_release(void) +{ + /* Deselect the current selection. */ + s_ptr->select = FALSE; + + /* Remove its graphical represesntation. */ + mark_selection(); +} + +/* + * Start to select some text on the screen. + */ +static void copy_x11_start(int x, int y) +{ + if (s_ptr->select) copy_x11_release(); + + /* Remember where the selection started. */ + s_ptr->t = Term; + s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x; + s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y; +} + +/* + * Respond to movement of the mouse when selecting text. + */ +static void copy_x11_cont(int x, int y, unsigned int buttons) +{ + /* Use the nearest square within bounds if the mouse is outside. */ + x = MIN(MAX(x, 0), Term->wid-1); + y = MIN(MAX(y, 0), Term->hgt-1); + + /* The left mouse button isn't pressed. */ + if (~buttons & Button1Mask) return; + + /* Not a selection in this window. */ + if (s_ptr->t != Term) return; + + /* Not enough movement. */ + if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return; + + /* Something is being selected. */ + s_ptr->select = TRUE; + + /* Track the selection. */ + s_ptr->cur.x = x; + s_ptr->cur.y = y; + + /* Hack - display it inefficiently. */ + mark_selection(); +} + +/* + * Respond to release of the left mouse button by putting the selected text in + * the primary buffer. + */ +static void copy_x11_end(const Time time) +{ + /* No selection. */ + if (!s_ptr->select) return; + + /* Not a selection in this window. */ + if (s_ptr->t != Term) return; + + /* Remember when the selection was finalised. */ + s_ptr->time = time; + + /* Acquire the primary selection. */ + XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time); + if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win) + { + /* Failed to acquire the selection, so forget it. */ + /* bell("Failed to acquire primary buffer."); */ + s_ptr->select = FALSE; + mark_selection(); + } +} + + +static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text; + +/* + * Set the required variable atoms at start-up to avoid errors later. + */ +static void set_atoms(void) +{ + xa_targets = XInternAtom(DPY, "TARGETS", False); + xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False); + xa_text = XInternAtom(DPY, "TEXT", False); + xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False); +} + + +static Atom request_target = 0; + +/* + * Send a message to request that the PRIMARY buffer be sent here. + */ +static void paste_x11_request(Atom target, const Time time) +{ + /* + * It's from some sample programs on the web. + * What does it mean? -- XXX + */ + Atom property = XInternAtom(DPY, "__COPY_TEXT", False); + + /* Check the owner. */ + if (XGetSelectionOwner(DPY, XA_PRIMARY) == None) + { + /* No selection. */ + /* bell("No selection found."); */ + return; + } + + request_target = target; + + /* Request the event */ + XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time); +} + + +/* + * Add the contents of the PRIMARY buffer to the input queue. + * + * Hack - This doesn't use the "time" of the event, and so accepts anything a + * client tries to send it. + */ +static void paste_x11_accept(const XSelectionEvent *ptr) +{ + unsigned long left; + const long offset = 0; + const long length = 32000; + XTextProperty xtextproperty; + errr err = 0; + + /* + * It's from some sample programs on the web. + * What does it mean? -- XXX + */ + Atom property = XInternAtom(DPY, "__COPY_TEXT", False); + + + /* Failure. */ + if (ptr->property == None) + { + if (request_target == xa_compound_text) + { + /* Re-request as STRING */ + paste_x11_request(XA_STRING, ptr->time); + } + else + { + request_target = 0; + plog("Paste failure (remote client could not send)."); + } + return; + } + + if (ptr->selection != XA_PRIMARY) + { + plog("Paste failure (remote client did not send primary selection)."); + return; + } + + if (ptr->target != request_target) + { + plog("Paste failure (selection in unknown format)."); + return; + } + + /* Get text */ + if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset, + length, TRUE, request_target, + &xtextproperty.encoding, + &xtextproperty.format, + &xtextproperty.nitems, + &left, + &xtextproperty.value) + != Success) + { + /* Failure */ + return; + } + + if (request_target == xa_compound_text) + { + char **list; + int count; + + XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count); + + if (list) + { + int i; + + for (i = 0; i < count; i++) + { + /* Paste the text. */ + err = type_string(list[i], 0); + + if (err) break; + } + + /* Free the string */ + XFreeStringList(list); + } + } + else /* if (request_target == XA_STRING) */ + { + /* Paste the text. */ + err = type_string((char *)xtextproperty.value, xtextproperty.nitems); + } + + /* Free the data pasted. */ + XFree(xtextproperty.value); + + /* No room. */ + if (err) + { + plog("Paste failure (too much text selected)."); + } +} + + +/* + * Add a character to a string in preparation for sending it to another + * client as a STRING. + * This doesn't change anything, as clients tend not to have difficulty in + * receiving this format (although the standard specifies a restricted set). + * Strings do not have a colour. + */ +static bool paste_x11_send_text(XSelectionRequestEvent *rq) +{ + char buf[1024]; + char *list[1000]; + co_ord max, min; + int x,y,l,n; + byte a; + char c; + + /* Too old, or incorrect call. */ + if (rq->time < s_ptr->time) return FALSE; + + /* Work out which way around to paste. */ + sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur); + + /* Paranoia. */ + if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN) + { + /* bell("Someone stole my selection!"); */ + return FALSE; + } + + /* Delete the old value of the property. */ + XDeleteProperty(DPY, rq->requestor, rq->property); + + for (n = 0, y = 0; y < Term->hgt; y++) + { +#ifdef JP + int kanji = 0; +#endif + if (y < min.y) continue; + if (y > max.y) break; + + for (l = 0, x = 0; x < Term->wid; x++) + { +#ifdef JP + if (x > max.x) break; + + /* Find the character. */ + Term_what(x, y, &a, &c); + + if (1 == kanji) kanji = 2; + else if (iskanji(c)) kanji = 1; + else kanji = 0; + + if (x < min.x) continue; + + /* + * A single kanji character was divided in two... + * Delete the garbage. + */ + if ((2 == kanji && x == min.x) || + (1 == kanji && x == max.x)) + c = ' '; +#else + if (x > max.x) break; + if (x < min.x) continue; + + /* Find the character. */ + Term_what(x, y, &a, &c); +#endif + + /* Add it. */ + buf[l] = c; + l++; + } + + /* Ignore trailing spaces */ + while (buf[l-1] == ' ') l--; + + /* Terminate all line unless it's single line. */ + if (min.y != max.y) + { + buf[l] = '\n'; + l++; + } + + /* End of string */ + buf[l] = '\0'; + + list[n++] = (char *)string_make(buf); + } + + /* End of the list */ + list[n] = NULL; + + + if (rq->target == XA_STRING) + { + for (n = 0; list[n]; n++) + { + /* Send the (non-empty) string. */ + XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8, + PropModeAppend, (unsigned char *)list[n], strlen(list[n])); + } + } + + else if (rq->target == xa_text || + rq->target == xa_compound_text) + { + XTextProperty text_prop; + XICCEncodingStyle style; + + if (rq->target == xa_text) + style = XStdICCTextStyle; + else /* if (rq->target == xa_compound_text) */ + style = XCompoundTextStyle; + + if (Success == + XmbTextListToTextProperty(DPY, list, n, style, &text_prop)) + { + /* Send the compound text */ + XChangeProperty(DPY, + rq->requestor, + rq->property, + text_prop.encoding, + text_prop.format, + PropModeAppend, + text_prop.value, + text_prop.nitems); + + /* Free the data. */ + XFree(text_prop.value); + } + } + + /* Free the list of strings */ + for (n = 0; list[n]; n++) + { + string_free(list[n]); + } + + return TRUE; +} + +/* + * Send some text requested by another X client. + */ +static void paste_x11_send(XSelectionRequestEvent *rq) +{ + XEvent event; + XSelectionEvent *ptr = &(event.xselection); + + /* Set the event parameters. */ + ptr->type = SelectionNotify; + ptr->property = rq->property; + ptr->display = rq->display; + ptr->requestor = rq->requestor; + ptr->selection = rq->selection; + ptr->target = rq->target; + ptr->time = rq->time; + + /* Paste the appropriate information for each target type. + * Note that this currently rejects MULTIPLE targets. + */ + + if (rq->target == XA_STRING || + rq->target == xa_text || + rq->target == xa_compound_text) + { + if (!paste_x11_send_text(rq)) + ptr->property = None; + } + else if (rq->target == xa_targets) + { + Atom target_list[4]; + target_list[0] = XA_STRING; + target_list[1] = xa_text; + target_list[2] = xa_compound_text; + target_list[3] = xa_targets; + XChangeProperty(DPY, rq->requestor, rq->property, rq->target, + (8 * sizeof(target_list[0])), PropModeReplace, + (unsigned char *)target_list, + (sizeof(target_list) / sizeof(target_list[0]))); + } + else if (rq->target == xa_timestamp) + { + XChangeProperty(DPY, rq->requestor, rq->property, rq->target, + (8 * sizeof(Time)), PropModeReplace, + (unsigned char *)s_ptr->time, 1); + } + else + { + ptr->property = None; + } + + /* Send whatever event we're left with. */ + XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event); +} + + +/* + * Handle various events conditional on presses of a mouse button. + */ +static void handle_button(Time time, int x, int y, int button, + bool press) +{ + /* The co-ordinates are only used in Angband format. */ + pixel_to_square(&x, &y, x, y); + + if (press && button == 1) copy_x11_start(x, y); + if (!press && button == 1) copy_x11_end(time); + if (!press && button == 2) paste_x11_request(xa_compound_text, time); +} /* @@ -1951,7 +2503,7 @@ static errr CheckEvent(bool wait) term_data *td = NULL; infowin *iwin = NULL; - int i, x, y; + int i; #ifdef USE_XIM redo_checkevent: @@ -1960,6 +2512,13 @@ static errr CheckEvent(bool wait) /* Do not wait unless requested */ if (!wait && !XPending(Metadpy->dpy)) return (1); + /* + * Hack - redraw the selection, if needed. + * This doesn't actually check that one of its squares was drawn to, + * only that this may have happened. + */ + if (s_ptr->select && !s_ptr->drawn) mark_selection(); + /* Load the Event */ XNextEvent(Metadpy->dpy, xev); @@ -2043,13 +2602,16 @@ static errr CheckEvent(bool wait) /* Switch on the Type */ switch (xev->type) { - -#if 0 - case ButtonPress: case ButtonRelease: { - int z = 0; + bool press = (xev->type == ButtonPress); + + /* Where is the mouse */ + int x = xev->xbutton.x; + int y = xev->xbutton.y; + + int z; /* Which button is involved */ if (xev->xbutton.button == Button1) z = 1; @@ -2057,12 +2619,10 @@ static errr CheckEvent(bool wait) else if (xev->xbutton.button == Button3) z = 3; else if (xev->xbutton.button == Button4) z = 4; else if (xev->xbutton.button == Button5) z = 5; - - /* Where is the mouse */ - x = xev->xbutton.x; - y = xev->xbutton.y; + else z = 0; /* XXX Handle */ + handle_button(xev->xbutton.time, x, y, z, press); break; } @@ -2070,10 +2630,6 @@ static errr CheckEvent(bool wait) case EnterNotify: case LeaveNotify: { - /* Where is the mouse */ - x = xev->xcrossing.x; - y = xev->xcrossing.y; - /* XXX Handle */ break; @@ -2082,28 +2638,51 @@ static errr CheckEvent(bool wait) case MotionNotify: { /* Where is the mouse */ - x = xev->xmotion.x; - y = xev->xmotion.y; + int x = xev->xmotion.x; + int y = xev->xmotion.y; + unsigned int z = xev->xmotion.state; + + /* Convert to co-ordinates Angband understands. */ + pixel_to_square(&x, &y, x, y); + + /* Highlight the current square, if appropriate. */ + /* highlight_square(window, y, x); */ + + /* Alter the selection if appropriate. */ + copy_x11_cont(x, y, z); /* XXX Handle */ break; } + case SelectionNotify: + { + paste_x11_accept(&(xev->xselection)); + break; + } + + case SelectionRequest: + { + paste_x11_send(&(xev->xselectionrequest)); + break; + } + + case SelectionClear: + { + s_ptr->select = FALSE; + mark_selection(); + break; + } + case KeyRelease: { /* Nothing */ break; } -#endif - case KeyPress: { - /* Save the mouse location */ - x = xev->xkey.x; - y = xev->xkey.y; - /* Hack -- use "old" term */ Term_activate(&old_td->t); @@ -2256,7 +2835,7 @@ static bool check_file(cptr s) /* * Initialize sound */ -static void init_sound() +static void init_sound(void) { int i; char wav[128]; @@ -2264,7 +2843,7 @@ static void init_sound() char dir_xtra_sound[1024]; /* Build the "sound" path */ - path_build(dir_xtra_sound, 1024, ANGBAND_DIR_XTRA, "sound"); + path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound"); /* Prepare the sounds */ for (i = 1; i < SOUND_MAX; i++) @@ -2273,7 +2852,7 @@ static void init_sound() sprintf(wav, "%s.wav", angband_sound_name[i]); /* Access the sound */ - path_build(buf, 1024, dir_xtra_sound, wav); + path_build(buf, sizeof(buf), dir_xtra_sound, wav); /* Save the sound filename, if it exists */ if (check_file(buf)) sound_file[i] = string_make(buf); @@ -2299,9 +2878,8 @@ static errr Term_xtra_x11_sound(int v) if (!sound_file[v]) return (1); sprintf(buf,"./playwave.sh %s\n", sound_file[v]); - system(buf); - return (0); + return (system(buf) < 0); } #endif /* USE_SOUND */ @@ -2322,7 +2900,7 @@ static errr Term_xtra_x11_level(int v) /* Activate the font */ Infofnt_set(td->fnt); -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT Infokfnt_set(td->kfnt); #endif } @@ -2359,9 +2937,9 @@ static errr Term_xtra_x11_react(void) /* Create pixel */ pixel = create_pixel(Metadpy->dpy, - color_table[i][1], - color_table[i][2], - color_table[i][3]); + color_table[i][1], + color_table[i][2], + color_table[i][3]); /* Change the foreground */ Infoclr_set(clr[i]); @@ -2388,7 +2966,7 @@ static errr Term_xtra_x11(int n, int v) #ifdef USE_SOUND /* Make a special sound */ - case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v)); + case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v)); #endif /* Flush the output XXX XXX */ @@ -2407,7 +2985,7 @@ static errr Term_xtra_x11(int n, int v) case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v)); /* Clear the screen */ - case TERM_XTRA_CLEAR: Infowin_wipe(); return (0); + case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0); /* Delay for some milliseconds */ case TERM_XTRA_DELAY: usleep(1000 * v); return (0); @@ -2428,19 +3006,55 @@ static errr Term_xtra_x11(int n, int v) */ static errr Term_curs_x11(int x, int y) { - /* Draw the cursor */ - Infoclr_set(xor); + if (use_graphics) + { + XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc, + x * Infofnt->wid + Infowin->ox, + y * Infofnt->hgt + Infowin->oy, + Infofnt->wid - 1, Infofnt->hgt - 1); + XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc, + x * Infofnt->wid + Infowin->ox + 1, + y * Infofnt->hgt + Infowin->oy + 1, + Infofnt->wid - 3, Infofnt->hgt - 3); + } + else + { + /* Draw the cursor */ + Infoclr_set(xor); -#ifdef JP - if (use_bigtile && x + 1 < Term->wid && (Term->old->a[y][x+1] == 255 || (iskanji(Term->old->c[y][x]) && !(Term->old->a[y][x] & 0x80)))) -#else - if (use_bigtile && x + 1 < Term->wid && Term->old->a[y][x+1] == 255) -#endif - Infofnt_text_non(x, y, " ", 2); + /* Hilite the cursor character */ + Infofnt_text_non(x, y, " ", 1); + } + + /* Success */ + return (0); +} + + +/* + * Draw the double width cursor + */ +static errr Term_bigcurs_x11(int x, int y) +{ + if (use_graphics) + { + XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc, + x * Infofnt->wid + Infowin->ox, + y * Infofnt->hgt + Infowin->oy, + Infofnt->twid - 1, Infofnt->hgt - 1); + XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc, + x * Infofnt->wid + Infowin->ox + 1, + y * Infofnt->hgt + Infowin->oy + 1, + Infofnt->twid - 3, Infofnt->hgt - 3); + } else - /* Hilite the cursor character */ - Infofnt_text_non(x, y, " ", 1); + { + /* Draw the cursor */ + Infoclr_set(xor); + /* Hilite the cursor character */ + Infofnt_text_non(x, y, " ", 2); + } /* Success */ return (0); } @@ -2457,6 +3071,9 @@ static errr Term_wipe_x11(int x, int y, int n) /* Mega-Hack -- Erase some space */ Infofnt_text_non(x, y, "", n); + /* Redraw the selection if any, as it may have been obscured. (later) */ + s_ptr->drawn = FALSE; + /* Success */ return (0); } @@ -2473,6 +3090,9 @@ static errr Term_text_x11(int x, int y, int n, byte a, cptr s) /* Draw the text */ Infofnt_text_std(x, y, s, n); + /* Redraw the selection if any, as it may have been obscured. (later) */ + s_ptr->drawn = FALSE; + /* Success */ return (0); } @@ -2483,18 +3103,13 @@ static errr Term_text_x11(int x, int y, int n, byte a, cptr s) /* * Draw some graphical characters. */ -# ifdef USE_TRANSPARENCY static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp) -# else /* USE_TRANSPARENCY */ -static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp) -# endif /* USE_TRANSPARENCY */ { int i, x1, y1; byte a; char c; -#ifdef USE_TRANSPARENCY byte ta; char tc; @@ -2502,7 +3117,6 @@ static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp) int k,l; unsigned long pixel, blank; -#endif /* USE_TRANSPARENCY */ term_data *td = (term_data*)(Term->data); @@ -2522,7 +3136,18 @@ static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp) x1 = (c&0x7F) * td->fnt->twid; y1 = (a&0x7F) * td->fnt->hgt; -#ifdef USE_TRANSPARENCY + /* Illegal tile index */ + if (td->tiles->width < x1 + td->fnt->wid || + td->tiles->height < y1 + td->fnt->hgt) + { + /* Draw black square */ + XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc, + x, y, + td->fnt->twid, td->fnt->hgt); + + /* Skip drawing tile */ + continue; + } ta = *tap++; tc = *tcp++; @@ -2532,15 +3157,18 @@ static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp) y2 = (ta&0x7F) * td->fnt->hgt; /* Optimise the common case */ - if ((x1 == x2) && (y1 == y2)) + if (((x1 == x2) && (y1 == y2)) || + !(((byte)ta & 0x80) && ((byte)tc & 0x80)) || + td->tiles->width < x2 + td->fnt->wid || + td->tiles->height < y2 + td->fnt->hgt) { /* Draw object / terrain */ XPutImage(Metadpy->dpy, td->win->win, - clr[0]->gc, - td->tiles, - x1, y1, - x, y, - td->fnt->twid, td->fnt->hgt); + clr[0]->gc, + td->tiles, + x1, y1, + x, y, + td->fnt->twid, td->fnt->hgt); } else { @@ -2568,25 +3196,16 @@ static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp) /* Draw to screen */ XPutImage(Metadpy->dpy, td->win->win, - clr[0]->gc, - td->TmpImage, - 0, 0, x, y, - td->fnt->twid, td->fnt->hgt); + clr[0]->gc, + td->TmpImage, + 0, 0, x, y, + td->fnt->twid, td->fnt->hgt); } - -#else /* USE_TRANSPARENCY */ - - /* Draw object / terrain */ - XPutImage(Metadpy->dpy, td->win->win, - clr[0]->gc, - td->tiles, - x1, y1, - x, y, - td->fnt->twid, td->fnt->hgt); - -#endif /* USE_TRANSPARENCY */ } + /* Redraw the selection if any, as it may have been obscured. (later) */ + s_ptr->drawn = FALSE; + /* Success */ return (0); } @@ -2604,6 +3223,10 @@ IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2) XIMStyles *xim_styles = NULL; int i; + /* Unused */ + (void)unused1; + (void)unused2; + xim = XOpenIM(display, NULL, NULL, NULL); if(!xim){ printf("can't open IM\n"); @@ -2652,7 +3275,11 @@ static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data) { int i; - if (call_data == NULL){ + /* Unused */ + (void)xim; + (void)client_data; + + if (call_data == NULL){ XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL); } @@ -2678,12 +3305,10 @@ static errr term_data_init(term_data *td, int i) { term *t = &td->t; - bool fixed = FALSE; - cptr name = angband_term_name[i]; cptr font; -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT cptr kfont; #endif @@ -2776,7 +3401,7 @@ static errr term_data_init(term_data *td, int i) } } -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT /* Window specific font name */ sprintf(buf, "ANGBAND_X11_KFONT_%d", i); @@ -2882,7 +3507,7 @@ static errr term_data_init(term_data *td, int i) /* Prepare the standard font */ -#ifdef _JP +#ifdef USE_JP_FONTSTRUCT MAKE(td->fnt, infofnt); Infofnt_set(td->fnt); MAKE(td->kfnt, infofnt); @@ -2906,13 +3531,13 @@ static errr term_data_init(term_data *td, int i) MAKE(td->win, infowin); Infowin_set(td->win); Infowin_init_top(x, y, wid, hgt, 0, - Metadpy->fg, Metadpy->bg); + Metadpy->fg, Metadpy->bg); /* Ask for certain events */ #if defined(USE_XIM) - Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | FocusChangeMask); + Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask); #else - Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask); + Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask); #endif /* Set the window name */ @@ -3006,6 +3631,7 @@ static errr term_data_init(term_data *td, int i) /* Hooks */ t->xtra_hook = Term_xtra_x11; t->curs_hook = Term_curs_x11; + t->bigcurs_hook = Term_bigcurs_x11; t->wipe_hook = Term_wipe_x11; t->text_hook = Term_text_x11; @@ -3038,11 +3664,7 @@ errr init_x11(int argc, char *argv[]) int pict_wid = 0; int pict_hgt = 0; -#ifdef USE_TRANSPARENCY - char *TmpData; -#endif /* USE_TRANSPARENCY */ - #endif /* USE_GRAPHICS */ @@ -3099,25 +3721,32 @@ errr init_x11(int argc, char *argv[]) } #ifdef USE_LOCALE + +#ifdef JP + /* Get locale information from environment variables */ setlocale(LC_ALL, ""); + #ifdef DEFAULT_LOCALE if(!strcmp(setlocale(LC_ALL, NULL), "C")){ printf("try default locale \"%s\"\n", DEFAULT_LOCALE); setlocale(LC_ALL, DEFAULT_LOCALE); } #endif + + if(!strcmp(setlocale(LC_ALL, NULL), "C")) { - char *current_locale = setlocale(LC_ALL, NULL); -/* printf("set locale to \"%s\"\n", current_locale); */ - if(!strcmp(current_locale, "C")){ - printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n"); - } + printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n"); } if(!XSupportsLocale()){ printf("can't support locale in X\n"); setlocale(LC_ALL, "C"); } +#else + /* Set locale to "C" without using environment variables */ + setlocale(LC_ALL, "C"); +#endif /* JP */ + #endif /* USE_LOCALE */ @@ -3154,9 +3783,9 @@ errr init_x11(int argc, char *argv[]) { /* Create pixel */ pixel = create_pixel(Metadpy->dpy, - color_table[i][1], - color_table[i][2], - color_table[i][3]); + color_table[i][1], + color_table[i][2], + color_table[i][3]); } /* Initialize the color */ @@ -3164,6 +3793,10 @@ errr init_x11(int argc, char *argv[]) } + /* Prepare required atoms. */ + set_atoms(); + + /* Initialize the windows */ for (i = 0; i < num_term; i++) { @@ -3207,7 +3840,7 @@ errr init_x11(int argc, char *argv[]) { case GRAPHICS_ORIGINAL: /* Try the "8x8.bmp" file */ - path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/8x8.bmp"); + path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp"); /* Use the "8x8.bmp" file if it exists */ if (0 == fd_close(fd_open(filename, O_RDONLY))) @@ -3224,7 +3857,7 @@ errr init_x11(int argc, char *argv[]) case GRAPHICS_ADAM_BOLT: /* Try the "16x16.bmp" file */ - path_build(filename, 1024, ANGBAND_DIR_XTRA, "graf/16x16.bmp"); + path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp"); /* Use the "16x16.bmp" file if it exists */ if (0 == fd_close(fd_open(filename, O_RDONLY))) @@ -3266,11 +3899,10 @@ errr init_x11(int argc, char *argv[]) /* Resize tiles */ td->tiles = ResizeImage(dpy, tiles_raw, - pict_wid, pict_hgt, - td->fnt->twid, td->fnt->hgt); + pict_wid, pict_hgt, + td->fnt->twid, td->fnt->hgt); } -#ifdef USE_TRANSPARENCY /* Initialize the transparency masks */ for (i = 0; i < num_term; i++) { @@ -3295,8 +3927,6 @@ errr init_x11(int argc, char *argv[]) td->fnt->twid, td->fnt->hgt, 8, 0); } -#endif /* USE_TRANSPARENCY */ - /* Free tiles_raw? XXX XXX */ }