[AD] Real weird unix bug, help wanted |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
Hi,
First a short intro I'm a volunteer software packager for the Fedora
Linux Distro and I've recently been packaging allegro using software.
I've already send 2 patches for bugs I found to the list, one for digmid
and one for alsa sound on bigendian machines.
I've spend my last 2 days debugging a real weird problem and any
help/input is appreciated.
There is a problem (under unix using the X11-system driver) when calling
set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, ... when changing from a
windowed display to a fullscreen display.
I'm not at all sure that this is allegro's fault it might very well be
the brand spanking new modular Xorg 7.0 release I'm using. While we're
on the topic, I'm using (and you might need an exact copy to reproduce):
-athlon64 2800+
-radeon 9250 / 9200pro with 256 mb ram
-latest x86_64 (64 bits) version of Fedora (FC5test3 + updates)
-using gnome with the (default) metacity window manager.
-allegro-4.2.0-8 as packaged by Fedora-Extras
Back to the problem, the problem is in src/x/xwin.c around line 734:
if (fullscreen) {
AL_CONST char *fc;
char tmp1[64], tmp2[128];
int i;
/* Switch video mode. */
if (!_xvidmode_private_set_fullscreen(w, h)) {
ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("C
return 0;
}
/* Hack: make the window fully visible and center cursor. */
XMoveWindow(_xwin.display, _xwin.window, 0, 0);
XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
/* This chunk is disabled by default because of problems on KDE
fc = get_config_string(uconvert_ascii("graphics", tmp1),
uconvert_ascii("force_centering", tmp2),
NULL);
if ((fc) && ((i = ugetc(fc)) != 0) && ((i == 'y') || (i == 'Y') ||
XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0,
XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w -
XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0,
XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w -
}
XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, w / 2,
XSync(_xwin.display, False);
/* Grab the keyboard and mouse. */
if (XGrabKeyboard(_xwin.display, XDefaultRootWindow(_xwin.display)
GrabModeAsync, GrabModeAsync, CurrentTime) != Gr
ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("C
return 0;
}
_xwin.keyboard_grabbed = 1;
if (XGrabPointer(_xwin.display, _xwin.window, False,
PointerMotionMask | ButtonPressMask |
GrabModeAsync, GrabModeAsync, _xwin.window, None,
ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Ca
return 0;
}
_xwin.mouse_grabbed = 1;
}
This should create an unmanaged window with its left top at position 0.0
of the root window. Now the problem is that with one allegro using
program, sometimes it is as if the XMoveWindow call and the XGrabPointer
call fail silently. In this case the window is at its last position
(before the set_gfx_mode call) and the mouse is ungrabbed, thus I can
pan around the rest of my desktop. It is as if both the move and the
mousegrab never happened. Strange enough the keyboardgrab has happened.
I've attached a very much minimized version of the program causing this
problem and I've also found a workaround. There is a define called
workaround in the top of the file, comment this to get the buggy
behaviour. Once you have the file compiled with the workaround define
commented press any key todo the fullscreen<->window toggle. Within say
10 toggle you should see the unwanted behaviour of the window not being
at 0.0 (the viewport will be there) and then you can also freely cause
the mouse to move outside the window and thus the viewport to scroll.
The workaround consists of waiting for the key which was pressed to be
released before doing the switch. Don't ask me why but this fixes it (it
took me ages (hours) to find this, looking at how other programs without
the problem did it).
I've also written an alternative workaround which works from within
allegro, add the following lines right before the XMoveWindow call:
/* HACK HACK HACK, XMoveWindow and XGrabPointer seem to fail
(silently!) when called on a window when keys are still
pressed. */
do {
char keys[32];
XQueryKeymap(_xwin.display, keys);
for (i=0; (i<32) && (keys[i]==0); i++) {}
} while(i<32);
/* Hack: make the window fully visible and center cursor. */
XMoveWindow(_xwin.display, _xwin.window, 0, 0);
Notice that I've also put the XMoveWindow call above for clearity, you
only need this once! I do not advocate this fix as a good one, nor
advice to include it in allegro. Its just extra info.
I hope someone can help (if anyone can reproduce this please let me
know, that alone would be great, esp with an other X-server (version)
then we can rule out certain things).
I know the attached test-case isn't all that simple but it is as good as
it gets, its much smaller then the original game having the problem.
Thanks & Regards,
Hans
#include <allegro.h>
#include <stdlib.h>
#include <stdio.h>
#define GRAIN 1000
// comment this to get the bug
// #define workaround
int grand(int number)
{
if (number == 0)
return 0;
return random() % number;
}
BITMAP *menu_bmp;
RGB palet [256];
enum
{
COLOUR_BLACK = 192,
COLOUR_GREY1,
COLOUR_GREY2,
COLOUR_GREY3,
COLOUR_GREY4,
COLOUR_GREY5,
COLOUR_GREY6,
//COLOUR_GREY7,
COLOUR_WHITE,
COLOUR_ORANGE1,
COLOUR_ORANGE2,
COLOUR_ORANGE3,
COLOUR_ORANGE4,
COLOUR_ORANGE5,
COLOUR_ORANGE6,
COLOUR_ORANGE7,
COLOUR_ORANGE8,
COLOUR_YELLOW1,
COLOUR_YELLOW2,
COLOUR_YELLOW3,
COLOUR_YELLOW4,
COLOUR_YELLOW5,
COLOUR_YELLOW6,
COLOUR_YELLOW7,
COLOUR_YELLOW8,
COLOUR_RED1,
COLOUR_RED2,
COLOUR_RED3,
COLOUR_RED4,
COLOUR_RED5,
COLOUR_RED6,
COLOUR_RED7,
COLOUR_RED8,
COLOUR_GREEN1,
COLOUR_GREEN2,
COLOUR_GREEN3,
COLOUR_GREEN4,
COLOUR_GREEN5,
COLOUR_GREEN6,
COLOUR_GREEN7,
COLOUR_GREEN8,
COLOUR_BLUE1,
COLOUR_BLUE2,
COLOUR_BLUE3,
COLOUR_BLUE4,
COLOUR_BLUE5,
COLOUR_BLUE6,
COLOUR_BLUE7,
COLOUR_BLUE8,
COLOUR_PURPLE1,
COLOUR_PURPLE2,
COLOUR_PURPLE3,
COLOUR_PURPLE4,
COLOUR_PURPLE5,
COLOUR_PURPLE6,
COLOUR_PURPLE7,
COLOUR_PURPLE8,
COLOUR_X1,
COLOUR_X2,
COLOUR_X3,
COLOUR_X4,
COLOUR_X5,
COLOUR_X6,
COLOUR_X7,
COLOUR_X8
//COLOUR_WRITING,
//COLOUR_BROWN
};
int base_palette [64] [3] =
{
{0, 0, 0},
{0, 0, 1},
{10, 10, 10},
{20, 20, 20},
{30, 30, 30},
{40, 40, 40},
{50, 50, 50},
{63, 63, 63}, // greys
{8, 3, 0},
{16, 6, 0},
{24, 9, 0},
{32, 12, 0},
{40, 15, 0},
{48, 18, 0},
{56, 21, 0},
{63, 24, 0}, // Oranges
{8, 8, 0},
{16, 16, 0},
{24, 24, 4},
{32, 32, 8},
{40, 40, 12},
{48, 48, 16},
{56, 56, 20},
{63, 63, 24}, // yellows
{8, 0, 0},
{16, 0, 0},
{24, 0, 0},
{32, 3, 3},
{40, 5, 5},
{48, 7, 7},
{56, 9, 9},
{63, 11, 11}, // Reds
{0, 8, 0},
{0, 16, 0},
{3, 24, 3},
{6, 32, 6},
{8, 40, 8},
{12, 48, 12},
{16, 56, 16},
{20, 63, 20}, // Greens
{0, 0, 8},
{0, 0, 16},
{4, 4, 24},
{8, 8, 32},
{12, 12, 40},
{16, 16, 48},
{20, 20, 56},
{24, 24, 63}, // Blues
{8, 0, 8},
{16, 0, 16},
{24, 0, 24},
{32, 0, 32},
{40, 0, 40},
{48, 0, 48},
{56, 0, 56},
{63, 0, 63}, // Purples
{8, 3, 8},
{16, 5, 16},
{24, 9, 24},
{32, 12, 32},
{40, 34, 40},
{48, 40, 48},
{56, 50, 56},
{63, 55, 63}, // X colours
};
int limit_colour(int colour_input)
{
if (colour_input < 0) return 0;
if (colour_input > 63) return 63;
return colour_input;
}
enum
{
TRANS_WHITE = 195,
TRANS_PURPLE, // 196
TRANS_LBLUE, // 197
TRANS_DBLUE, // 198
TRANS_YELLOW, // 199
TRANS_LGREEN, // 200
TRANS_DGREEN, // 201
TRANS_LORANGE, // 202
TRANS_DORANGE, // 203
TRANS_LRED, // 204
TRANS_DRED, // 205
TRANS_WHITE2, // 206
// Special white which doesn't overwrite other colours (for shockwaves etc)
TRANS_LGREY, // 207
TRANS_DGREY, // 208
TRANS_GREY, // 209
// GREY is special. It's the only transparency which preserves colour, not
// just brightness, and it takes up four times as much space in the
// palette as the others. WHITE, LGREY and DGREY are just normal
// transparencies, and both will overwrite GREY.
// GREY should be last, but for:
TRANS_END //207
// must be the last trans + 1
};
void init_palette(void)
{
int i;
// colour_table("First");
for (i = 0; i < 64; i ++)
{
// Grey
palet[i + 128].r = limit_colour(base_palette [i] [0] + 20);
palet[i + 128].g = limit_colour(base_palette [i] [1] + 20);
palet[i + 128].b = limit_colour(base_palette [i] [2] + 20);
palet[i + 192].r = base_palette [i] [0];
palet[i + 192].g = base_palette [i] [1];
palet[i + 192].b = base_palette [i] [2];
}
for (i = 0; i < 8; i ++)
{
// White - should be same as WHITE2 (below)
// palet[i].r = limit_colour(32 + i * 4);
// palet[i].g = limit_colour(32 + i * 4);
// palet[i].b = limit_colour(32 + i * 4);
palet[i].r = limit_colour(48 + i * 2);
palet[i].g = limit_colour(48 + i * 2);
palet[i].b = limit_colour(48 + i * 2);
// Purple
palet[i + 8].r = limit_colour(32 + i * 4);
palet[i + 8].g = limit_colour(i * 3);
palet[i + 8].b = limit_colour(32 + i * 4);
// LBlue
palet[i + 16].r = limit_colour(10 + i * 3);
palet[i + 16].g = limit_colour(10 + i * 3);
palet[i + 16].b = limit_colour(47 + i * 2);
// DBlue
palet[i + 24].r = limit_colour(i * 2);
palet[i + 24].g = limit_colour(i * 2);
palet[i + 24].b = limit_colour(21 + i * 4);
// Yellow
palet[i + 32].r = limit_colour(47 + i * 3);
palet[i + 32].g = limit_colour(47 + i * 3);
palet[i + 32].b = limit_colour(10 + i * 3);
// LGreen
palet[i + 40].r = limit_colour(i * 3);
palet[i + 40].g = limit_colour(32 + i * 4);
palet[i + 40].b = limit_colour(i * 3);
// DGreen
palet[i + 48].r = limit_colour(i * 2);
palet[i + 48].g = limit_colour(21 + i * 4);
palet[i + 48].b = limit_colour(i * 2);
// LOrange
palet[i + 56].r = limit_colour(47 + i * 3);
palet[i + 56].g = limit_colour(20 + i * 3);
palet[i + 56].b = limit_colour(5 + i * 2);
// DOrange
palet[i + 64].r = limit_colour(25 + i * 4);
palet[i + 64].g = limit_colour(12 + i * 3);
palet[i + 64].b = limit_colour(i * 2);
// LRed
palet[i + 72].r = limit_colour(47 + i * 2);
palet[i + 72].g = limit_colour(10 + i * 3);
palet[i + 72].b = limit_colour(10 + i * 3);
// DRed
palet[i + 80].r = limit_colour(20 + i * 4);
palet[i + 80].g = limit_colour(i * 2);
palet[i + 80].b = limit_colour(i * 2);
// White2 - should be same as WHITE (above)
// palet[i + 88].r = limit_colour(32 + i * 4);
// palet[i + 88].g = limit_colour(32 + i * 4);
// palet[i + 88].b = limit_colour(32 + i * 4);
palet[i + 88].r = limit_colour(48 + i * 2);
palet[i + 88].g = limit_colour(48 + i * 2);
palet[i + 88].b = limit_colour(48 + i * 2);
// LGrey
palet[i + 96].r = limit_colour(24 + i * 4);
palet[i + 96].g = limit_colour(24 + i * 4);
palet[i + 96].b = limit_colour(24 + i * 4);
// DGrey
palet[i + 104].r = limit_colour(12 + i * 4);
palet[i + 104].g = limit_colour(12 + i * 4);
palet[i + 104].b = limit_colour(12 + i * 4);
/* // White
palet[i].r = limit_colour(21 + i * 6);
palet[i].g = limit_colour(21 + i * 6);
palet[i].b = limit_colour(21 + i * 6);
// Purple
palet[i + 8].r = limit_colour(21 + i * 6);
palet[i + 8].g = limit_colour(i * 3 - 12);
palet[i + 8].b = limit_colour(21 + i * 6);
// LBlue
palet[i + 16].r = limit_colour(i * 4 - 12);
palet[i + 16].g = limit_colour(i * 4 - 12);
palet[i + 16].b = limit_colour(21 + i * 6);
// DBlue
palet[i + 24].r = limit_colour(i * 2 - 12);
palet[i + 24].g = limit_colour(i * 2 - 12);
palet[i + 24].b = limit_colour(10 + i * 5);
// LGreen
palet[i + 32].r = limit_colour(i * 4 - 12);
palet[i + 32].g = limit_colour(21 + i * 6);
palet[i + 32].b = limit_colour(i * 4 - 12);
// DGreen
palet[i + 40].r = limit_colour(i * 2 - 12);
palet[i + 40].g = limit_colour(10 + i * 5);
palet[i + 40].b = limit_colour(i * 2 - 12);
// Yellow
palet[i + 48].r = limit_colour(21 + i * 6);
palet[i + 48].g = limit_colour(21 + i * 6);
palet[i + 48].b = limit_colour(i * 4 - 12);
// LOrange
palet[i + 56].r = limit_colour(21 + i * 6);
palet[i + 56].g = limit_colour(12 + i * 5);
palet[i + 56].b = limit_colour(i * 4 - 12);
// DOrange
palet[i + 64].r = limit_colour(10 + i * 5);
palet[i + 64].g = limit_colour(6 + i * 4);
palet[i + 64].b = limit_colour(i * 4 - 12);
// LRed
palet[i + 72].r = limit_colour(21 + i * 6);
palet[i + 72].g = limit_colour(i * 4 - 12);
palet[i + 72].b = limit_colour(i * 4 - 12);
// DRed
palet[i + 80].r = limit_colour(10 + i * 5);
palet[i + 80].g = limit_colour(i * 2 - 12);
palet[i + 80].b = limit_colour(i * 2 - 12);
*/
}
palet[0].r = 0;
palet[0].g = 0;
palet[0].b = 0;
/* for (i = 0; i < 192; i ++)
{
palet[i].r = 0;
palet[i].b = 0;
palet[i].g = 0;
}*/
/* pork_create_color_table(&trans_table, palet);
color_map = &trans_table;
set_palette(palet); */
/*
BITMAP *pbmp = create_bitmap(16, 16);
int x, y;
for (x = 0; x < 16; x ++)
{
for (y = 0; y < 16; y ++)
{
putpixel(pbmp, y, x, y + (x * 16));
if (y + (x * 16) < 192)
putpixel(pbmp, y, x, 0);
}
}
save_bitmap("palbmp3.pcx", pbmp, palet);
for (x = 192; x < 256; x ++)
{
rectfill(screen, (x - 192) * 6, 1, (x - 192) * 6 + 6, 10, x);
}
do
{
} while (key [KEY_U] == 0);
*/
// int j;
/* for (i = 0; i < 256; i ++)
{
j = limit_colour((palet[i].r + palet[i].g + palet[i].b) / 3);
mono_palet [i].r = j;
mono_palet [i].g = j;
mono_palet [i].b = j;
}
mono_palet [222].r = 60;
mono_palet [222].g = 40;
mono_palet [222].b = 0;
mono_palet [223].r = 0;
mono_palet [223].g = 60;
mono_palet [223].b = 10; // these colours used for 'you win'/'game over'
*/
}
int grid_x_speed, grid_y_speed, grid_x, grid_y, grid_x_accel, grid_y_accel;
void draw_scrolling_grid(int min_x, int min_y, int max_x, int max_y, int colour)
{
int i, j, x1, y1;
int x_offset = (grid_x / GRAIN) % 50;
int y_offset = (grid_y / GRAIN) % 50;
for (i = 0; i < 15; i ++)
{
x1 = i * 50 + x_offset;
if (x1 < min_x || x1 > max_x)
continue;
vline(menu_bmp, x1, min_y, max_y, colour);
}
for (j = 0; j < 12; j ++)
{
y1 = j * 50 + y_offset;
if (y1 < min_y || y1 > max_y)
continue;
hline(menu_bmp, min_x, y1, max_x, colour);
}
}
void make_grid_scroll(void)
{
grid_x += grid_x_speed;
grid_y += grid_y_speed;
grid_x %= 50000;
grid_y %= 50000;
grid_x_speed += grid_x_accel;
if (grid_x_speed > 3000) grid_x_speed = 3000;
if (grid_x_speed < -3000) grid_x_speed = -3000;
grid_y_speed += grid_y_accel;
if (grid_y_speed > 3000) grid_y_speed = 3000;
if (grid_y_speed < -3000) grid_y_speed = -3000;
// if (menu_counter % 32 == 0)
{
grid_x_accel = grand(301) - 150;
// if (grid_x_speed > 3000) grid_x_speed = 3000;
// if (grid_x_speed < -3000) grid_x_speed = -3000;
grid_y_accel = grand(301) - 150;
// if (grid_y_speed > 3000) grid_y_speed = 3000;
// if (grid_y_speed < -3000) grid_y_speed = -3000;
}
}
void show_grid(int grid_colour, int border_colour)
{
rectfill(menu_bmp, 10, 10, 630, 470, COLOUR_GREY1);
rect(menu_bmp, 10, 10, 630, 470, border_colour - 4);
rect(menu_bmp, 9, 9, 631, 471, border_colour - 2);
rect(menu_bmp, 8, 8, 632, 472, border_colour);
draw_scrolling_grid(11, 11, 629, 469, grid_colour);
}
volatile unsigned char ticked;
void tickover(void)
{
ticked ++;
// tick_counter++; // assumes it'll wrap at 256
}
END_OF_FUNCTION (tickover);
int main (void)
{
int i;
allegro_init();
install_keyboard();
LOCK_FUNCTION (tickover);
LOCK_VARIABLE (ticked);
install_int (tickover, 30);
init_palette();
set_color_depth(8);
menu_bmp = create_bitmap(640, 480);
while(1) {
if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0) != 0) {
printf("fout: %s\n", allegro_error);
exit(1);
}
set_palette(palet);
do {
while(ticked == 0)
rest(1);
ticked --;
make_grid_scroll();
clear_bitmap(menu_bmp);
show_grid(COLOUR_GREEN3, COLOUR_GREEN8);
acquire_screen();
blit(menu_bmp, screen, 0, 0, 0, 0, 640, 480);
release_screen();
for (i = 0; i < 128; i++)
if (key[i])
break;
} while (i == 128);
#ifdef workaround
while (key[i]) {}
#endif
if (set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0) != 0) {
printf("fout: %s\n", allegro_error);
exit(1);
}
set_palette(palet);
do {
while(ticked == 0)
rest(1);
ticked --;
make_grid_scroll();
clear_bitmap(menu_bmp);
show_grid(COLOUR_GREEN3, COLOUR_GREEN8);
acquire_screen();
blit(menu_bmp, screen, 0, 0, 0, 0, 640, 480);
release_screen();
for (i = 0; i < 128; i++)
if (key[i])
break;
} while (i == 128);
#ifdef workaround
while (key[i]) {}
#endif
}
}