From a8d448ad19509d7a72cc7a1c6e1ca2405332d796 Mon Sep 17 00:00:00 2001 From: janwas Date: Wed, 3 Mar 2004 15:16:20 +0000 Subject: [PATCH] no message This was SVN commit r167. --- source/lib/detect.h | 1 + source/lib/res/file.cpp | 3 +- source/lib/res/font.cpp | 18 +-- source/lib/res/h_mgr.cpp | 96 +++++++----- source/lib/res/h_mgr.h | 43 +++--- source/lib/res/mem.h | 1 - source/lib/res/vfs.cpp | 2 +- source/lib/res/zip.cpp | 2 +- source/lib/sysdep/win/waio.cpp | 241 ++++++++++++++++++++---------- source/lib/sysdep/win/wdetect.cpp | 15 +- source/lib/sysdep/x.cpp | 7 +- 11 files changed, 267 insertions(+), 162 deletions(-) diff --git a/source/lib/detect.h b/source/lib/detect.h index 831380db2c..9e5f842c85 100755 --- a/source/lib/detect.h +++ b/source/lib/detect.h @@ -27,6 +27,7 @@ extern "C" { // useful for choosing a video mode. not called by detect(). +// if we fail, don't change the outputs (assumed initialized to defaults) extern void get_cur_resolution(int& xres, int& yres); diff --git a/source/lib/res/file.cpp b/source/lib/res/file.cpp index 3e8882c0aa..c532f2cb2b 100755 --- a/source/lib/res/file.cpp +++ b/source/lib/res/file.cpp @@ -728,8 +728,7 @@ ssize_t file_io(File* const f, const size_t raw_ofs, size_t raw_size, void** con { if(raw_ofs >= f->size) return ERR_EOF; - size_t bytes_left = f->size - raw_ofs; // > 0 - size_t max_size = MIN(bytes_left, raw_size); + raw_size = MIN(f->size - raw_ofs, raw_size); } // writing: make sure buffer is valid else diff --git a/source/lib/res/font.cpp b/source/lib/res/font.cpp index 631662d30f..56d91050ee 100755 --- a/source/lib/res/font.cpp +++ b/source/lib/res/font.cpp @@ -138,19 +138,19 @@ static int Font_reload(Font* f, const char* fn) Handle err = vfs_load(fn, tmp_file, file_size); if(err <= 0) return (int)err; - void* p = mem_alloc(file_size + 1); - if(!p) + void* file = mem_alloc(file_size + 1); + if(!file) return ERR_NO_MEM; - memcpy(p, tmp_file, file_size); - ((char*)p)[file_size] = 0; // 0-terminate for sscanf + memcpy(file, tmp_file, file_size); + ((char*)file)[file_size] = 0; // 0-terminate for sscanf int pos; // current position in the file - const char* file = (const char*)p; + const char* p = (const char*)file; // read header char tex_filename[PATH_MAX]; int x_stride, y_stride; // glyph spacing in texture - if(sscanf(file, "%s\n%d %d\n%n", tex_filename, &x_stride, &y_stride, &pos) != 3) + if(sscanf(p, "%s\n%d %d\n%n", tex_filename, &x_stride, &y_stride, &pos) != 3) { debug_out("Font_reload: \"%s\": header is invalid", fn); return -1; @@ -160,15 +160,15 @@ static int Font_reload(Font* f, const char* fn) int adv[128]; for(int i = 32; i < 128; i++) { - file += pos; - if(sscanf(file, "%d %n", &adv[i], &pos) != 1) + p += pos; + if(sscanf(p, "%d %n", &adv[i], &pos) != 1) { debug_out("Font_reload: \"%s\": glyph width array is invalid", fn); return -1; } } - mem_free(p); + mem_free(file); // load glyph texture const Handle ht = tex_load(tex_filename); diff --git a/source/lib/res/h_mgr.cpp b/source/lib/res/h_mgr.cpp index 7f54b3c3d5..6c68d38917 100755 --- a/source/lib/res/h_mgr.cpp +++ b/source/lib/res/h_mgr.cpp @@ -1,4 +1,4 @@ -// handle-based resource manager +// handle manager // // Copyright (c) 2003 Jan Wassenberg // @@ -33,28 +33,50 @@ // handle // -// TODO: explain handle scheme, how it solves problems +// handles are an indirection layer between client code and resources. +// they allow an important check not possible with a direct pointer: +// guaranteeing the handle references a given resource /instance/. +// +// problem: code C1 allocates a resource, and receives a pointer p to its +// control block. C1 passes p on to C2, and later frees it. +// now other code allocates a resource, and happens to reuse the free slot +// pointed to by p (also possible if simply allocating from the heap). +// when C2 accesses p, the pointer is valid, but we cannot tell that +// it is referring to a resource that had already been freed. big trouble. +// +// solution: each allocation receives a unique tag (a global counter that +// is large enough to never overflow). Handles include this tag, as well +// as a reference (array index) to the control block, which isn't directly +// accessible. when dereferencing the handle, we check if the handle's tag +// matches the copy stored in the control block. this protects against stale +// handle reuse, double-free, and accidentally referencing other resources. +// +// type: each handle has an associated type. these must be checked to prevent +// using textures as sounds, for example. with the manual vtbl scheme, +// this type is actually a pointer to the resource object's vtbl, and is +// set up via H_TYPE_DEFINE. see header for rationale. this means that +// types are private to the module that declared the handle; knowledge +// of the type ensures the caller actually declared, and owns the resource. // 0 = invalid handle value // < 0 is an error code (we assume < 0 <==> MSB is set - // true for 1s and 2s complement and sign-magnitude systems) -// -// tag = 1-based; index = 0-based -// -// shift value = # bits between LSB and field LSB. -// may be larger than the field type - only shift Handle vars! // fields: -// - allows checking if the resource has been freed -// determines maximum unambiguous resource allocs +// (shift value = # bits between LSB and field LSB. +// may be larger than the field type - only shift Handle vars!) + +// - tag (1-based) ensures the handle references a certain resource instance. +// (field width determines maximum unambiguous resource allocs) #define TAG_BITS 32 const uint TAG_SHIFT = 0; -const Handle TAG_MASK = (((Handle)1) << TAG_BITS) - 1; -// - index into data array -// determines maximum (currently open) handles +const u32 TAG_MASK = 0xffffffff; // safer than (1 << 32) - 1 + +// - index (0-based) points to control block in our array. +// (field width determines maximum currently open handles) #define IDX_BITS 16 const uint IDX_SHIFT = 32; -const u32 IDX_MASK = (((Handle)1) << IDX_BITS) - 1; +const i32 IDX_MASK = (1l << IDX_BITS) - 1; cassert(IDX_BITS + TAG_BITS <= sizeof(Handle)*CHAR_BIT); @@ -156,17 +178,11 @@ static HDATA* h_data(const i32 idx) } - - -int h_data_tag = 0; - // get HDATA for the given handle. verifies the handle // isn't invalid or an error code, and checks the tag field. // used by the few functions callable for any handle type, e.g. h_filename. static HDATA* h_data_any_type(const Handle h) { - h_data_tag++; - #ifdef PARANOIA check_heap(); #endif @@ -222,7 +238,7 @@ static void cleanup(void) if(hd) { // somewhat messy, but this only happens on cleanup. - // better, i think, than an additional h_free(i32 idx) version. + // better than an additional h_free(i32 idx) version though. Handle h = handle(i, hd->tag); h_free(h, hd->type); } @@ -239,15 +255,10 @@ static void cleanup(void) -static int alloc_idx(i32* pidx, HDATA** phd) +// idx and hd are undefined if we fail. +// called by h_alloc only. +static int alloc_idx(i32& idx, HDATA*& hd) { - assert(pidx && phd && "alloc_idx: invalid param"); - *pidx = 0; - *phd = 0; - - i32 idx; - HDATA* hd; - // we already know the first free entry if(first_free != -1) { @@ -297,8 +308,6 @@ have_idx:; if(idx > last_in_use) last_in_use = idx; - *pidx = idx; - *phd = hd; return 0; } @@ -319,9 +328,14 @@ int h_free(Handle& h, H_Type type) if(!hd) return ERR_INVALID_HANDLE; - // not the last reference - if(--hd->refs) - return 0; + // have valid refcount (don't decrement if alread 0) + if(hd->refs > 0) + { + hd->refs--; + // not the last reference + if(hd->refs > 0) + return 0; + } // TODO: keep this handle open (cache) @@ -345,7 +359,9 @@ int h_free(Handle& h, H_Type type) // any further params are passed to type's init routine Handle h_alloc(H_Type type, const char* fn, uint flags, ...) { -// ONCE(atexit(cleanup)) + ONCE(atexit(cleanup)) + + Handle err; i32 idx; HDATA* hd; @@ -400,13 +416,15 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...) */ } - if(alloc_idx(&idx, &hd) < 0) - return 0; + err = alloc_idx(idx, hd); + if(err < 0) + return err; static u32 tag; if(++tag >= TAG_MASK) { - assert(!"h_alloc: tag overflow - may not notice stale handle reuse (increase TAG_BITS)"); + assert(0 && "h_alloc: tag overflow - allocations are no longer unique."\ + "may not notice stale handle reuse. increase TAG_BITS."); tag = 1; } @@ -427,11 +445,11 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...) if(vtbl->reload) { - int err = vtbl->reload(hd->user, fn); + err = vtbl->reload(hd->user, fn); if(err < 0) { h_free(h, type); - return 0; + return err; } } diff --git a/source/lib/res/h_mgr.h b/source/lib/res/h_mgr.h index 6cdbb7a50e..81afa603f7 100755 --- a/source/lib/res/h_mgr.h +++ b/source/lib/res/h_mgr.h @@ -1,4 +1,4 @@ -// handle based caching resource manager +// handle manager // // Copyright (c) 2003 Jan Wassenberg // @@ -16,8 +16,8 @@ // Jan.Wassenberg@stud.uni-karlsruhe.de // http://www.stud.uni-karlsruhe.de/~urkt/ -#ifndef __RES_H__ -#define __RES_H__ +#ifndef H_MGR_H__ +#define H_MGR_H__ #ifdef __cplusplus extern "C" { @@ -71,14 +71,14 @@ but- has to handle variable params, a bit ugly // - class (difficult to compare type, handle manager needs to know of all users) // // checked in h_alloc: -// - user_size must fit in what res.cpp is offering (currently 44 bytes) +// - user_size must fit in what the handle manager provides // - name must not be 0 // // init: user data is initially zeroed -// dtor: user data is zeroed automatically afterwards +// dtor: user data is zeroed afterwards // reload: if this resource type is opened by another resource's reload, // our reload routine MUST check if already opened! This is relevant when -// a file is invalidated: if e.g. a sound object opens a file, the handle +// a file is reloaded: if e.g. a sound object opens a file, the handle // manager calls the reload routines for the 2 handles in unspecified order. // ensuring the order would require a tag field that can't overflow - // not really guaranteed with 32-bit handles. it'd also be more work @@ -96,17 +96,24 @@ struct H_VTbl typedef H_VTbl* H_Type; #define H_TYPE_DEFINE(t)\ -static void t##_init(t*, va_list);\ -static int t##_reload(t*, const char*);\ -static void t##_dtor(t*);\ -static H_VTbl V_##t = {\ - (void(*)(void*, va_list))t##_init,\ - (int(*)(void*, const char*))t##_reload,\ - (void(*)(void*))t##_dtor,\ - sizeof(t),\ - #t\ -};\ -static H_Type H_##t = &V_##t; + /* forward decls */\ + static void t##_init(t*, va_list);\ + static int t##_reload(t*, const char*);\ + static void t##_dtor(t*);\ + static H_VTbl V_##t =\ + {\ + (void(*)(void*, va_list))t##_init,\ + (int(*)(void*, const char*))t##_reload,\ + (void(*)(void*))t##_dtor,\ + sizeof(t), /* control block size */\ + #t /* name */\ + };\ + static H_Type H_##t = &V_##t; + + // note: we cast to void* pointers so the functions can be declared to + // take the control block pointers, instead of requiring a cast in each. + // the forward decls ensure the function signatures are correct. + // * = H_USER_DATA(, ) #define H_USER_DATA(h, type) (type*)h_user_data(h, H_##type); @@ -185,4 +192,4 @@ extern int res_cur_scope; #endif -#endif // #ifndef __RES_H__ +#endif // #ifndef H_MGR_H__ diff --git a/source/lib/res/mem.h b/source/lib/res/mem.h index 5ad07ade10..3e3c03b49d 100755 --- a/source/lib/res/mem.h +++ b/source/lib/res/mem.h @@ -24,7 +24,6 @@ extern void* mem_alloc(size_t size, uint align = 1, uint flags = 0, Handle* ph = #define mem_free(p) mem_free_p((void*&)p) extern int mem_free_p(void*& p); -// faster than mem_free(void*) - no scan of open handles for the pointer extern int mem_free_h(Handle& hm); // create a H_MEM handle of type MEM_USER, diff --git a/source/lib/res/vfs.cpp b/source/lib/res/vfs.cpp index ff192e6fbd..533317e426 100755 --- a/source/lib/res/vfs.cpp +++ b/source/lib/res/vfs.cpp @@ -577,7 +577,7 @@ Handle vfs_load(const char* fn, void*& p, size_t& size) size = vf->size; { // VC6 goto fix - size_t nread = vfs_io(hf, 0, size, p); + ssize_t nread = vfs_io(hf, 0, size, p); if(nread > 0) hm = mem_assign(p, size); } diff --git a/source/lib/res/zip.cpp b/source/lib/res/zip.cpp index b54e7f955f..92c3e3cd58 100755 --- a/source/lib/res/zip.cpp +++ b/source/lib/res/zip.cpp @@ -82,7 +82,7 @@ ssize_t zip_inflate(uintptr_t ctx, void* in, size_t in_size) size_t avail_out = stream->avail_out; assert(avail_out <= prev_avail_out); // make sure output buffer size didn't magically increase - size_t nread = prev_avail_out - avail_out; + ssize_t nread = (ssize_t)(prev_avail_out - avail_out); if(!nread) return (err < 0)? err : 0; // try to pass along the ZLib error code, but make sure diff --git a/source/lib/sysdep/win/waio.cpp b/source/lib/sysdep/win/waio.cpp index ccbeffaa60..11c00b2d64 100755 --- a/source/lib/sysdep/win/waio.cpp +++ b/source/lib/sysdep/win/waio.cpp @@ -30,7 +30,7 @@ ////////////////////////////////////////////////////////////////////////////// // -// +// AioHandles // ////////////////////////////////////////////////////////////////////////////// @@ -54,8 +54,6 @@ private: uint size; }; -static AioHandles* aio_hs; - AioHandles::~AioHandles() { @@ -76,6 +74,14 @@ AioHandles::~AioHandles() } +bool is_valid_file_handle(HANDLE h) +{ + SetLastError(0); + bool valid = (GetFileSize(h, 0) != INVALID_FILE_SIZE); + assert(valid); + return valid; +} + // get async capable handle to file HANDLE AioHandles::get(int fd) { @@ -85,6 +91,11 @@ HANDLE AioHandles::get(int fd) if((unsigned)fd < size) h = hs[fd]; + else + assert(0); + + if(!is_valid_file_handle(h)) + return INVALID_HANDLE_VALUE; win_unlock(WAIO_CS); @@ -110,10 +121,20 @@ int AioHandles::set(int fd, HANDLE h) size = size2; } - if(hs[fd] != INVALID_HANDLE_VALUE) + if(h == INVALID_HANDLE_VALUE) + ; + else { - assert("set_aio_h: handle already set!"); - goto fail; + if(hs[fd] != INVALID_HANDLE_VALUE) + { + assert("AioHandles::set: handle already set!"); + goto fail; + } + if(!is_valid_file_handle(h)) + { + assert("AioHandles::set: setting invalid handle"); + goto fail; + } } hs[fd] = h; @@ -123,79 +144,14 @@ int AioHandles::set(int fd, HANDLE h) fail: win_unlock(WAIO_CS); + assert(0 && "AioHandles::set failed"); return -1; } -int aio_assign_handle(uintptr_t handle) -{ - // - // CRT stores osfhandle. if we pass an invalid handle (say, 0), - // we get an exception when closing the handle if debugging. - // events can be created relatively quickly (~1800 clocks = 1µs), - // and are also freed with CloseHandle, so just pass that. - HANDLE h = CreateEvent(0,0,0,0); - if(h == INVALID_HANDLE_VALUE) - return -1; - - int fd = _open_osfhandle((intptr_t)h, 0); - if(fd < 0) - return fd; - - return aio_hs->set(fd, (HANDLE)handle); -} - -static void init(); - -// open fn in async mode; associate with fd (retrieve via aio_h(fd)) -int aio_open(const char* fn, int mode, int fd) -{ -WIN_ONCE(init()); // TODO: need to do this elsewhere in case other routines called first? - - // interpret mode - DWORD access = GENERIC_READ; // assume O_RDONLY - DWORD share = 0; - if(mode & O_WRONLY) - access = GENERIC_WRITE; - else if(mode & O_RDWR) - access = GENERIC_READ|GENERIC_WRITE; - else - share = FILE_SHARE_READ; - DWORD create = OPEN_EXISTING; - if(mode & O_CREAT) - create = (mode & O_EXCL)? CREATE_NEW : CREATE_ALWAYS; - DWORD flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN; - - // open file - HANDLE h = CreateFile(fn, access, share, 0, create, flags, 0); - if(h == INVALID_HANDLE_VALUE) - return -1; - - if(aio_hs->set(fd, h) < 0) - { - CloseHandle(h); - return -1; - } - - return 0; -} - - -int aio_close(int fd) -{ - HANDLE h = aio_hs->get(fd); - if(h == INVALID_HANDLE_VALUE) // out of bounds or already closed - return -1; - - CloseHandle(h); - aio_hs->set(fd, INVALID_HANDLE_VALUE); - return 0; -} - - ////////////////////////////////////////////////////////////////////////////// // -// +// Req // ////////////////////////////////////////////////////////////////////////////// @@ -206,7 +162,7 @@ struct Req aiocb* cb; OVERLAPPED ovl; - // hEvent signals when transfer complete + // hEvent signals when transfer complete // read into a separate align buffer if necessary // (note: unaligned writes aren't supported. see aio_rw) @@ -269,6 +225,7 @@ Req* Reqs::find(const aiocb* cb) if(r->cb == cb) return r; + assert(0 && "Reqs::find failed"); return 0; } @@ -292,17 +249,27 @@ Req* Reqs::alloc(const aiocb* cb) return r; } + +////////////////////////////////////////////////////////////////////////////// +// +// init / cleanup +// +////////////////////////////////////////////////////////////////////////////// + +static AioHandles* aio_hs; +static Reqs* reqs; + + // Win32 functions require sector aligned transfers. // max of all drives' size is checked in init(). static size_t sector_size = 4096; // minimum: one page -////////////////////////////////////////////////////////////////////////////// -// -// -// -////////////////////////////////////////////////////////////////////////////// -static Reqs* reqs; +static void cleanup(void) +{ + delete aio_hs; + delete reqs; +} // caller ensures this is not re-entered! @@ -311,6 +278,8 @@ static void init() reqs = new Reqs; aio_hs = new AioHandles; + atexit(cleanup); + // Win32 requires transfers to be sector aligned. // find maximum of all drive's sector sizes, then use that. // (it's good to know this up-front, and checking every open() is slow). @@ -339,6 +308,92 @@ static void init() } + + +int aio_assign_handle(uintptr_t handle) +{ + // + // CRT stores osfhandle. if we pass an invalid handle (say, 0), + // we get an exception when closing the handle if debugging. + // events can be created relatively quickly (~1800 clocks = 1µs), + // and are also freed with CloseHandle, so just pass that. + HANDLE h = CreateEvent(0,0,0,0); + if(h == INVALID_HANDLE_VALUE) + { + assert(0 && "aio_assign_handle failed"); + return -1; + } + + int fd = _open_osfhandle((intptr_t)h, 0); + if(fd < 0) + { + assert(0 && "aio_assign_handle failed"); + return fd; + } + + return aio_hs->set(fd, (HANDLE)handle); +} + + + + +// open fn in async mode; associate with fd (retrieve via aio_h(fd)) +int aio_open(const char* fn, int mode, int fd) +{ +WIN_ONCE(init()); // TODO: need to do this elsewhere in case other routines called first? + + // interpret mode + DWORD access = GENERIC_READ; // assume O_RDONLY + DWORD share = 0; + if(mode & O_WRONLY) + access = GENERIC_WRITE; + else if(mode & O_RDWR) + access = GENERIC_READ|GENERIC_WRITE; + else + share = FILE_SHARE_READ; + DWORD create = OPEN_EXISTING; + if(mode & O_CREAT) + create = (mode & O_EXCL)? CREATE_NEW : CREATE_ALWAYS; + DWORD flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN; + + // open file + HANDLE h = CreateFile(fn, access, share, 0, create, flags, 0); + if(h == INVALID_HANDLE_VALUE) + { + assert(0 && "aio_open failed"); + return -1; + } + + if(aio_hs->set(fd, h) < 0) + { + assert(0 && "aio_open failed"); + CloseHandle(h); + return -1; + } + + return 0; +} + + +int aio_close(int fd) +{ + HANDLE h = aio_hs->get(fd); + if(h == INVALID_HANDLE_VALUE) // out of bounds or already closed + { + assert(0 && "aio_close failed"); + return -1; + } + + SetLastError(0); + if(!CloseHandle(h)) + assert(0); + aio_hs->set(fd, INVALID_HANDLE_VALUE); + return 0; +} + + + + // called by aio_read, aio_write, and lio_listio // cb->aio_lio_opcode specifies desired operation // @@ -347,9 +402,15 @@ static void init() static int aio_rw(struct aiocb* cb) { if(!cb) + { + assert(0); return -EINVAL; + } if(cb->aio_lio_opcode == LIO_NOP) + { + assert(0); return 0; + } HANDLE h = aio_hs->get(cb->aio_fildes); if(h == INVALID_HANDLE_VALUE) @@ -360,7 +421,10 @@ static int aio_rw(struct aiocb* cb) Req* r = reqs->alloc(cb); if(!r) + { + assert(0); return -1; + } size_t ofs = 0; size_t size = cb->aio_nbytes; @@ -406,6 +470,8 @@ static int aio_rw(struct aiocb* cb) } } + r->ovl.Internal = r->ovl.InternalHigh = 0; + #if _MSC_VER >= 1300 r->ovl.Pointer = (void*)ofs; #else @@ -414,6 +480,8 @@ static int aio_rw(struct aiocb* cb) assert(cb->aio_buf != 0); + SetLastError(0); + DWORD size32 = (DWORD)(size & 0xffffffff); ResetEvent(r->ovl.hEvent); BOOL ok = (cb->aio_lio_opcode == LIO_READ)? @@ -443,11 +511,20 @@ int lio_listio(int mode, struct aiocb* const cbs[], int n, struct sigevent* se) { UNUSED(se) + int err = 0; + for(int i = 0; i < n; i++) - aio_rw(cbs[i]); // aio_rw checks for 0 param + { + int ret = aio_rw(cbs[i]); // aio_rw checks for 0 param + if(ret < 0) + err = ret; + } + + if(err < 0) + return err; if(mode == LIO_WAIT) - aio_suspend(cbs, n, 0); + return aio_suspend(cbs, n, 0); return 0; } diff --git a/source/lib/sysdep/win/wdetect.cpp b/source/lib/sysdep/win/wdetect.cpp index 9535f41f96..3cb8c21cb8 100755 --- a/source/lib/sysdep/win/wdetect.cpp +++ b/source/lib/sysdep/win/wdetect.cpp @@ -30,13 +30,20 @@ #endif +// useful for choosing a video mode. not called by detect(). +// if we fail, don't change the outputs (assumed initialized to defaults) void get_cur_resolution(int& xres, int& yres) { - static DEVMODE dm; + DEVMODEA dm; + memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); - EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm); - xres = dm.dmPelsWidth; - yres = dm.dmPelsHeight; + // dm.dmDriverExtra already set to 0 by memset + + if(EnumDisplaySettingsA(0, ENUM_CURRENT_SETTINGS, &dm)) + { + xres = dm.dmPelsWidth; + yres = dm.dmPelsHeight; + } } diff --git a/source/lib/sysdep/x.cpp b/source/lib/sysdep/x.cpp index 4cad2c7918..47012a0e11 100755 --- a/source/lib/sysdep/x.cpp +++ b/source/lib/sysdep/x.cpp @@ -20,15 +20,12 @@ #include // useful for choosing a video mode. not called by detect(). +// if we fail, don't change the outputs (assumed initialized to defaults) void get_cur_resolution(int& xres, int& yres) { - Display* disp = XOpenDisplay(NULL); + Display* disp = XOpenDisplay(0); if(!disp) - { - xres = 1024; - yres = 768; return; - } int screen = XDefaultScreen(disp); xres = XDisplayWidth (disp, screen);