"Fossies" - the Fresh Open Source Software archive 
Member "spectemu-0.99.3/xutils.c" of archive spectemu-0.99.3.tar.gz:
/*
* Copyright (C) 1996-2004 Szeredi Miklos
* Email: mszeredi@inf.bme.hu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. See the file COPYING.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* #define DEBUG_COLOR */
#include "xscr.h"
#include "spscr.h"
#include "spscr_p.h"
#include "ax.h"
#include "xdispkb.h"
#include "spperif.h"
#include "interf.h"
#include "spconf_p.h"
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#define MAX_SEARCH_DEPTH 8
int privatemap = 0;
int fullscreen = 0;
#define RES_WIDTH 320
#define RES_HEIGHT 240
static int current_fullscreen = 0;
static Window fs_win;
static void move_mouse_to(int x, int y)
{
XWarpPointer(xsp_disp, None, RootWindow(xsp_disp, xsp_scr), 0, 0, 0, 0,
x, y);
}
#ifdef HAVE_XF86VIDMODE
#include <X11/extensions/xf86vmode.h>
static XF86VidModeModeInfo saved_mode;
static struct {
int x, y;
} saved_view;
static int use_vidmode = 0;
Bool XF86VidModeGetModeInfo(Display *dpy, int scr, XF86VidModeModeInfo *info)
{
XF86VidModeModeLine *l = (XF86VidModeModeLine*)
((char*)info + sizeof info->dotclock);
return XF86VidModeGetModeLine(dpy, scr, &info->dotclock, l);
}
static void save_mode(void)
{
if(use_vidmode) {
memset(&saved_mode, 0, sizeof(saved_mode));
XF86VidModeGetModeInfo(xsp_disp, xsp_scr, &saved_mode);
XF86VidModeGetViewPort(xsp_disp, xsp_scr, &saved_view.x,
&saved_view.y);
}
}
static void restore_mode(void)
{
if(use_vidmode) {
XF86VidModeSwitchToMode(xsp_disp, xsp_scr, &saved_mode);
XFree(saved_mode.private);
move_mouse_to(saved_view.x, saved_view.y);
// XF86VidModeSetViewPort(xsp_disp, xsp_scr, saved_view.x, saved_view.y);
}
}
static int cmpmodes(const void *va, const void *vb)
{
XF86VidModeModeInfo *a = *(XF86VidModeModeInfo**)va;
XF86VidModeModeInfo *b = *(XF86VidModeModeInfo**)vb;
if(a->hdisplay != b->hdisplay)
return a->hdisplay - b->hdisplay;
else
return a->vdisplay - b->vdisplay;
}
static void set_best_resolution(int width, int height)
{
XF86VidModeModeInfo **modes;
int i;
int nmodes;
if(use_vidmode) {
if( XF86VidModeGetAllModeLines(xsp_disp, xsp_scr, &nmodes, &modes) ) {
qsort(modes, nmodes, sizeof *modes, cmpmodes);
for ( i = 0; i < nmodes; ++i ) {
if ( (modes[i]->hdisplay >= width) &&
(modes[i]->vdisplay >= height) )
break;
}
if ( i < nmodes )
XF86VidModeSwitchToMode(xsp_disp, xsp_scr, modes[i]);
XFree(modes);
}
}
}
static void check_vidmode(void)
{
int vidmode_event, vidmode_error;
use_vidmode = 0;
if ( XF86VidModeQueryExtension(xsp_disp, &vidmode_event, &vidmode_error) )
{
/* FIXME: The extension only works on local displays */
use_vidmode = 1;
}
}
static void get_real_resolution(int* w, int* h)
{
if ( use_vidmode ) {
XF86VidModeModeLine mode;
int unused;
if ( XF86VidModeGetModeLine(xsp_disp, xsp_scr, &unused, &mode) ) {
*w = mode.hdisplay;
*h = mode.vdisplay;
return;
}
}
*w = DisplayWidth(xsp_disp, xsp_scr);
*h = DisplayHeight(xsp_disp, xsp_scr);
}
#else /* HAVE_XF86VIDMODE */
static void check_vidmode(void)
{
}
static void save_mode(void)
{
}
static void restore_mode(void)
{
}
static void set_best_resolution(int width, int height)
{
}
static void get_real_resolution(int* w, int* h)
{
*w = DisplayWidth(xsp_disp, xsp_scr);
*h = DisplayHeight(xsp_disp, xsp_scr);
}
#endif /* HAVE_XF86VIDMODE */
static int resize_fullscreen(void)
{
int x, y;
int real_w, real_h;
if ( current_fullscreen ) {
resize_spect_scr(1);
XSync(xsp_disp, False);
/* Switch resolution and cover it with the fs_win */
move_mouse_to(0, 0);
set_best_resolution(RES_WIDTH, RES_HEIGHT);
move_mouse_to(0, 0);
get_real_resolution(&real_w, &real_h);
XResizeWindow(xsp_disp, fs_win, real_w, real_h);
move_mouse_to(real_w/2, real_h/2);
/* Center and reparent the drawing window */
x = (real_w - RES_WIDTH)/2;
y = (real_h - RES_HEIGHT)/2;
XReparentWindow(xsp_disp, xsp_win, fs_win, x, y);
/* FIXME: move the mouse to the old relative location */
XRaiseWindow(xsp_disp, fs_win);
XSync(xsp_disp, False);
}
return(1);
}
static void fs_map_event(XEvent *ev, void *ptr)
{
ev = ev;
ptr = ptr;
/* Grab the mouse on the fullscreen window
The event handling will know when we become active, and then
enter fullscreen mode if we can't grab the mouse this time.
*/
if ( XGrabPointer(xsp_disp, fs_win, True, 0, GrabModeAsync, GrabModeAsync,
fs_win, None, CurrentTime) != GrabSuccess ) {
/* We lost the grab, so fall back to windowed mode */
XUnmapWindow(xsp_disp, fs_win);
return;
}
save_mode();
current_fullscreen = 1;
resize_fullscreen();
}
void enter_fullscreen(void)
{
int real_w, real_h;
/* Map the fullscreen window to blank the screen */
get_real_resolution(&real_w, &real_h);
XResizeWindow(xsp_disp, fs_win, real_w, real_h);
XMapRaised(xsp_disp, fs_win);
/* Wait until the window is mapped */
}
void leave_fullscreen(void)
{
if ( current_fullscreen ) {
restore_mode();
XReparentWindow(xsp_disp, xsp_win, top_win, 0, 0);
XUnmapWindow(xsp_disp, fs_win);
XSync(xsp_disp, False);
current_fullscreen = 0;
}
}
void spscr_toggle_fullscreen(void)
{
fullscreen = !fullscreen;
if(!fullscreen)
leave_fullscreen();
else
enter_fullscreen();
sp_init_screen_mark(); /* Redraw screen */
}
void init_xutils(void)
{
XSetWindowAttributes attr;
check_vidmode();
attr.override_redirect = True;
attr.background_pixel = BlackPixel(xsp_disp, xsp_scr);
attr.colormap = XDefaultColormap(xsp_disp, xsp_scr);
fs_win = XCreateWindow(xsp_disp, RootWindow(xsp_disp, xsp_scr), 0, 0,
32, 32, 0, CopyFromParent, CopyFromParent,
CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWColormap,
&attr);
aX_add_event_proc(xsp_disp, fs_win, MapNotify,
fs_map_event, StructureNotifyMask, NULL);
}
static unsigned cdist(XColor *c1, XColor *c2)
{
int dr, dg, db;
dr = (c1->red - c2->red) >> 8;
dg = (c1->green - c2->green) >> 8;
db = (c1->blue - c2->blue) >> 8;
return dr * dr + dg * dg + db * db;
}
static int already_alloced(pixt *colors, int num, pixt pix)
{
int i;
for(i = 0; i < num; i++) if(colors[i] == pix) return 1;
return 0;
}
#define MYINF ((unsigned) -1)
static int search_colors(Colormap cmap, unsigned dp)
{
int c;
XColor xcolor, tmpcolor;
pixt pix;
XColor *scrcolors = NULL;
unsigned ncolors = 0;
unsigned dist, mindist;
pixt minpix;
int failed = 0, lfailed;
int fails[COLORNUM];
if(dp < 4) failed = 1;
if(!failed) {
if(dp <= MAX_SEARCH_DEPTH) {
ncolors = 1 << dp;
scrcolors = malloc(sizeof(XColor) * ncolors);
if(scrcolors != NULL) {
for(pix = 0; pix < ncolors; pix++) scrcolors[pix].pixel = pix;
XQueryColors(xsp_disp, cmap, scrcolors, (int) ncolors);
}
}
for(c = 0; c < COLORNUM; c++) {
xcolor.red = spscr_crgb[c].r << 10;
xcolor.green = spscr_crgb[c].g << 10;
xcolor.blue = spscr_crgb[c].b << 10;
lfailed = 0;
if(!XAllocColor(xsp_disp, cmap, &xcolor) ||
already_alloced(xsp_colors, c, xcolor.pixel)) {
if(scrcolors != NULL) {
#ifdef DEBUG_COLOR
fprintf(stderr,
"XAllocColor failed, searching all colors...\n");
#endif
mindist = MYINF;
for(pix = 0; pix < ncolors; pix++) {
dist = cdist(&scrcolors[pix], &xcolor);
if(dist < mindist) {
tmpcolor.red = scrcolors[pix].red;
tmpcolor.green = scrcolors[pix].green;
tmpcolor.blue = scrcolors[pix].blue;
if(XAllocColor(xsp_disp, cmap, &tmpcolor) &&
!already_alloced(xsp_colors, c, tmpcolor.pixel))
{
if(mindist != MYINF)
XFreeColors(xsp_disp, cmap, &minpix, 1, 0);
mindist = dist;
minpix = pix;
}
}
}
if(mindist == MYINF) {
lfailed = 1;
#ifdef DEBUG_COLOR
fprintf(stderr, "Search failed\n");
#endif
}
else xsp_colors[c] = minpix;
}
else {
#ifdef DEBUG_COLOR
fprintf(stderr, "XAllocColor failed\n");
#endif
lfailed = 1;
}
}
else xsp_colors[c] = xcolor.pixel;
if(lfailed) {
fails[c] = 1;
failed = 1;
}
else fails[c] = 0;
#ifdef DEBUG_COLOR
tmpcolor.pixel = xsp_colors[c];
XQueryColor(xsp_disp, cmap, &tmpcolor);
fprintf(stderr,
"Color %2i (%3i %3i %3i) -> Pixel %5lu (%3i %3i %3i)\n",
c, spscr_crgb[c].r, spscr_crgb[c].g, spscr_crgb[c].b,
xsp_colors[c], tmpcolor.red>>10, tmpcolor.green>>10,
tmpcolor.blue>>10);
#endif
}
if(failed) {
for(c = 0; c < COLORNUM; c++) {
if(!fails[c])
XFreeColors(xsp_disp, cmap, &xsp_colors[c], 1, 0);
xsp_colors[c] = c;
}
}
}
if(scrcolors != NULL) free(scrcolors);
if(failed) return 0;
return 1;
}
static int firstalloced = 1;
static int currprivate;
int allocate_colors(void)
{
int color_res;
Colormap defcmap;
if(!firstalloced && !currprivate)
XFreeColors(xsp_disp, xsp_cmap, xsp_colors, COLORNUM, 0);
defcmap = DefaultColormap(xsp_disp, xsp_scr);
color_res = search_colors(defcmap, xsp_depth);
if((!color_res || privatemap) &&
(xsp_visual->class == PseudoColor || xsp_visual->class == GrayScale)) {
XColor xcolor;
int c;
if(color_res) XFreeColors(xsp_disp, defcmap, xsp_colors, COLORNUM, 0);
if(firstalloced || !currprivate)
xsp_cmap = XCreateColormap(xsp_disp, xsp_win, xsp_visual, AllocAll);
if(xsp_depth <= MAX_SEARCH_DEPTH) { /* Is this good? */
for(c = 0; c < (1 << xsp_depth); c++) {
xcolor.pixel = c;
XQueryColor(xsp_disp, defcmap, &xcolor);
XStoreColor(xsp_disp, xsp_cmap, &xcolor);
}
}
for(c = 0; c < COLORNUM; c++) {
xcolor.pixel = xsp_colors[c];
xcolor.red = spscr_crgb[c].r << 10;
xcolor.green = spscr_crgb[c].g << 10;
xcolor.blue = spscr_crgb[c].b << 10;
xcolor.flags = DoRed | DoGreen | DoBlue;
XStoreColor(xsp_disp, xsp_cmap, &xcolor);
}
color_res = 1;
currprivate = 1;
}
else {
if(!firstalloced && currprivate) XFreeColormap(xsp_disp, xsp_cmap);
xsp_cmap = defcmap;
currprivate = 0;
}
firstalloced = 0;
return color_res;
}
void spscr_refresh_colors(void)
{
if(!allocate_colors()) put_msg("Could not allocate colors");
kb_refresh_colormap();
XSetWindowColormap(xsp_disp, xsp_win, xsp_cmap);
XSetWindowBackground(xsp_disp, xsp_win, xsp_colors[7]);
XInstallColormap(xsp_disp, xsp_cmap);
spxs_init_color();
sp_init_screen_mark();
}
#define MAX_RES_NAME 64
#define MAXLINELEN 512
void spcf_read_xresources(void)
{
int i;
char resname[MAX_RES_NAME], resclass[MAX_RES_NAME];
char line[MAXLINELEN+1];
char *val;
resname[0] = '.';
resclass[0] = '.';
resname[MAX_RES_NAME-1] = '\0';
resclass[MAX_RES_NAME-1] = '\0';
for(i = 0; spcf_options[i].option != NULL; i++) {
strncpy(resname+1, spcf_options[i].option, MAX_RES_NAME-2);
strncpy(resclass+1, spcf_options[i].option, MAX_RES_NAME-2);
resclass[1] = toupper(resclass[1]);
val = aX_get_prog_res(resname, resclass);
if(val != NULL) spcf_set_val(i, val, NULL, 0, 0);
}
strcpy(resname+1, "color");
strcpy(resclass+1, "Color");
for(i = 0; i < COLORNUM; i++) {
sprintf(resname+6, "%i", i);
sprintf(resclass+6, "%i", i);
val = aX_get_prog_res(resname, resclass);
if(val != NULL) spcf_set_color(i, val, NULL, 0, 0);
}
strcpy(resname+1, "keys");
strcpy(resclass+1, "Keys");
val = aX_get_prog_res(resname, resclass);
if(val != NULL) {
char *ival, *attr;
int l;
int col;
while(*val) {
for(i = 0; val[i] && val[i] != ';'; i++);
l = i;
if(i > MAXLINELEN) i = MAXLINELEN;
strncpy(line, val, (size_t) i);
line[i] = '\0';
if(spcf_parse_conf_line(line, &attr, &ival, &col) > 0) {
int ix;
ix = spcf_match_keydef(attr, "");
if(ix >= 0) spcf_set_key(ix, ival, NULL, 0, 0);
}
if(!val[l]) break;
val += (l+1);
}
}
}