/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at
golgotha_source@usa.net (Subject should have "GOLG" in it)
***********************************************************************/
#include "video/x11/x11_display.hh"
#include "image/context.hh"
#define DEPTH 16
x11_display_class x11_display_instance;
x11_display_class::x11_display_class()
{
shm_extension=0;
mouse_save=screen=0;
context=0;
shm_image=0;
ximage=0;
}
void x11_display_input_class::resize(int w, int h)
{
x11_display_class *d=(x11_display_class *)i4_display;
if (w!=d->width() || h!=d->height())
{
d->destroy_X_image();
d->create_X_image(w,h);
}
}
void x11_display_input_class::note_event(XEvent &xev)
{
x11_display_class *d=(x11_display_class *)i4_display;
if (d->shm_extension)
d->shm_extension->note_event(xev);
}
i4_image_class *x11_display_class::get_back_buffer(int x1, int y1, int x2, int y2)
{
if (x2pal);
screen->put_part(im, 0,0, x1,y1,x2,y2);
return im;
}
i4_bool x11_display_class::open_X_window(w32 width, w32 height, i4_display_class::mode *mode)
{
if (input.create_window(0,0,width,height, this, i4_F, get_visual(input.display)))
{
i4_pixel_format f;
f.red_mask = mode->red_mask;
f.green_mask = mode->green_mask;
f.blue_mask = mode->blue_mask;
f.alpha_mask = 0;
f.calc_shift();
f.lookup = 0;
f.pixel_depth = I4_16BIT;
pal = i4_pal_man.register_pal(&f);
if (shm_extension)
{
char *ds_name=getenv("DISPLAY");
if (!ds_name)
ds_name="unix:0.0";
if (!shm_extension->available(input.display,ds_name))
shm_extension=0;
}
create_X_image(width, height);
return i4_T;
}
else
return i4_F;
}
void x11_display_class::close_X_window()
{
destroy_X_image();
if (shm_extension)
shm_extension->shutdown(input.display);
if (mouse_save)
{
delete mouse_save;
mouse_save=0;
}
if (mouse_pict)
{
delete mouse_pict;
mouse_pict=0;
}
}
i4_bool x11_display_class::close()
{
if (screen)
close_X_window();
return i4_T;
}
void x11_display_class::init()
{
if (input.display || input.open_display())
{
me.add_to_list("X Windows", 0, this, i4_display_list);
input.close_display();
}
}
// initialize_mode need not call close() to switch to another mode
i4_bool x11_display_class::initialize_mode()
{
memcpy(&cur_mode, &amode, sizeof(cur_mode));
// this should open an X window
return open_X_window(cur_mode.xres, cur_mode.yres, &cur_mode);
}
XVisualInfo *x11_display_class::get_visual(Display *display)
{
return input.find_visual_with_depth(DEPTH);
}
i4_display_class::mode *x11_display_class::get_first_mode(int driver_id)
{
if (!input.open_display())
return 0;
else
{
XVisualInfo *v = get_visual(input.display);
if (v)
{
strcpy(amode.name,"Standard X11 window");
amode.flags=mode::RESOLUTION_DETERMINED_ON_OPEN;
amode.bits_per_pixel=DEPTH;
amode.red_mask = v->red_mask;
amode.green_mask = v->green_mask;
amode.blue_mask = v->blue_mask;
XFree((char *)v);
Window root;
int x,y;
unsigned w,h,bord,depth;
if (XGetGeometry(input.display,
RootWindow(input.display,DefaultScreen(input.display)),&root,
&x,&y,&w,&h,&bord,&depth)==0)
i4_error("can't get root window attributes");
amode.xres=w;
amode.yres=h;
amode.assoc=this; // so we know in 'initialize_mode' that we created this mode
return &amode;
}
return 0;
}
}
void x11_display_class::destroy_X_image()
{
if (shm_extension)
{
if (shm_image)
shm_extension->destroy_shm_image(input.display, shm_image);
shm_image=0;
}
else
{
if (ximage)
XDestroyImage(ximage);
ximage=0;
}
if (screen)
{
delete screen;
screen=0;
}
if (context)
{
delete context;
context=0;
}
}
void x11_display_class::create_X_image(w32 width, w32 height)
{
destroy_X_image();
if (shm_extension)
{
w16 w=width,h=height;
shm_image=shm_extension->create_shm_image(input.display,
input.mainwin,
input.gc,
input.my_visual->visual,
input.my_visual->depth,
w,h); // actual width and height from X
screen=i4_create_image(w,h,pal,
(w8 *)shm_image->data,
w*(DEPTH/8));
}
else
{
ximage = XCreateImage(input.display,
input.my_visual->visual,
input.my_visual->depth,
ZPixmap,
0,
(char *)i4_malloc(width*height*(DEPTH/8),"Ximage"),
width,
height,
32,
0 );
screen=i4_create_image(width, height, pal,
(w8 *)ximage->data,
width*(DEPTH/8)); // bytes per line
}
if (context)
delete context;
context=new i4_draw_context_class(0,0,screen->width()-1,screen->height()-1);
context->both_dirty=new i4_rect_list_class;
context->single_dirty=new i4_rect_list_class;
}
void x11_display_class::flush() // the actual work of the function is in copy_part_to_vram
{
int mw,mh;
i4_coord rmx,rmy;
sw32 mx=input.mouse_x, my=input.mouse_y;
if (mx<0) mx=0;
if (my<0) my=0;
rmx=mx-mouse_hot_x;
rmy=my-mouse_hot_y;
if (mouse_pict)
{
mw=mouse_pict->width();
mh=mouse_pict->height();
if (pal->source.pixel_depth==I4_8BIT)
mouse_save->set_pal(pal);
i4_draw_context_class save_context(0,0,mw-1,mh-1);
screen->put_part(mouse_save,0,0,rmx,rmy,rmx+mw-1,rmy+mh-1,
save_context); // save area behind mouse
mouse_pict->put_image_trans(screen,rmx,rmy,mouse_trans,*context);
}
i4_rect_list_class::area_iter a;
for (a=context->single_dirty->list.begin();
a!=context->single_dirty->list.end();
++a)
context->both_dirty->add_area(a->x1, a->y1, a->x2, a->y2);
context->single_dirty->delete_list();
context->both_dirty->intersect_area(0,0,width()-1,height()-1);
a=context->both_dirty->list.begin();
i4_bool error=i4_F;
for (;a!=context->both_dirty->list.end();++a)
error=(i4_bool)(error & copy_part_to_vram(a->x1,a->y1,a->x1,a->y1,a->x2,a->y2));
if (!error)
context->both_dirty->delete_list();
if (mouse_pict)
mouse_save->put_part(screen,rmx,rmy,0,0,mw-1,mh-1,*context); // restore area behind mouse
}
i4_bool x11_display_class::copy_part_to_vram(i4_coord x, i4_coord y,
i4_coord x1, i4_coord y1,
i4_coord x2, i4_coord y2)
// this should copy a portion of an image to the actual screen at offset x, y
{
if (shm_image)
return shm_image->copy_part_to_vram(shm_extension,x,y,x1,y1,x2,y2);
else
{
XPutImage(input.display, input.mainwin, input.gc, ximage,x1,y1,x,y,x2-x1+1,y2-y1+1);
return i4_T;
}
}
i4_bool x11_display_class::set_mouse_shape(i4_cursor_class *cursor)
{
if (mouse_pict)
{
delete mouse_pict;
delete mouse_save;
}
mouse_trans=cursor->trans;
mouse_pict=cursor->pict->copy();
mouse_save=i4_create_image(mouse_pict->width(),mouse_pict->height(),screen->get_pal());
mouse_hot_x=cursor->hot_x;
mouse_hot_y=cursor->hot_y;
return i4_T;
}