Main Page Namespace List Class Hierarchy Alphabetical List Compound List File List Namespace Members Compound Members File Members Related Pages

FltkOpenGLDisplayDevice.C

Go to the documentation of this file.
00001 /***************************************************************************
00002 *cr 
00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 
00004 *cr University of Illinois 
00005 *cr All Rights Reserved 
00006 *cr 
00007 ***************************************************************************/
00008 /***************************************************************************
00009 * RCS INFORMATION:
00010 *
00011 * $RCSfile: FltkOpenGLDisplayDevice.C,v $
00012 * $Author: johns $ $Locker: $ $State: Exp $
00013 * $Revision: 1.77 $ $Date: 2020年04月23日 07:07:42 $
00014 *
00015 ***************************************************************************/
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <math.h>
00027 #include "FltkOpenGLDisplayDevice.h"
00028 #include "Inform.h"
00029 #include "utilities.h"
00030 #include "config.h" // VMD version strings etc
00031 #include "VMDApp.h" 
00032 #include "FL/Fl.H"
00033 #include "FL/Fl_Gl_Window.H"
00034 #include "FL/forms.H"
00035 
00036 // FLTK High-DPI display support:
00037 // FLTK versions 1.3.5 and later incorporate Apple-specific extensions
00038 // for retina display support. 
00039 //
00040 // On Apple MacOS when High-DPI Retina displays are enabled, 
00041 // FLTK apparently uses a hard-coded 2:1 pixel to drawing unit scale factor 
00042 //
00043 // High-DPI support on Win32, Win64, and X-Windows require further
00044 // special handling available only in FLTK 1.4.x, which was redesigned with
00045 // a new per-screen scale factor:
00046 // https://www.fltk.org/doc-1.4/drawing.html
00047 //
00048 // On Windows, X-Windows, the window-specific scale factor is:
00049 // int nscreen = windows->screen_num();
00050 // float s = Fl::screen_scale(nscreen);
00051 //
00052 // The active scale factor can be overridden with the use of the
00053 // FLTK_SCALING_FACTOR environment variable, and FLTK windows
00054 // will respond to (cmd | ctrl)/+/-/0 (like a web browser) to allow
00055 // interactive adjustment of scaling factor.
00056 // FLTK 1.4.x adds Fl_Image::scale() to impact image drawing.
00057 //
00058 // Older discussions:
00059 // https://www.oyranos.org/2016/01/high-dpi-with-fltk/index.html
00060 // https://groups.google.com/forum/#!topic/fltkgeneral/qS-A50x6owk
00061 //
00062 #if defined(__APPLE__)
00063 #if (FL_MAJOR_VERSION >= 1) && (((FL_MINOR_VERSION >= 3) && (FL_PATCH_VERSION >= 5)) || (FL_MINOR_VERSION >= 4))
00064 #define VMDFLTKUSEHIGHDPIRETINA 1
00065 #endif
00066 #endif
00067 
00070 class myglwindow : public Fl_Gl_Window {
00071 FltkOpenGLDisplayDevice *dispdev;
00072 VMDApp *app; // cached VMDApp handle for use in drag-and-drop
00073 int dragpending; // flag indicating incoming PASTE event is drag-and-drop
00074 
00075 public:
00076 myglwindow(int wx, int wy, int width, int height, const char *nm, 
00077 FltkOpenGLDisplayDevice *d, VMDApp *vmdapp) 
00078 : Fl_Gl_Window(wx, wy, width, height, nm), dispdev(d), app(vmdapp), dragpending(0) {
00079 // XXX this may not be reliable on MacOS X with recent revs of FLTK
00080 size_range(1,1,0,0); // resizable to full screen
00081 }
00082 
00083 
00084 int handle(int event) {
00085 // handle paste operations
00086 if (event == FL_PASTE) {
00087 // ignore paste operations that weren't due to drag-and-drop
00088 // since they could be any arbitrary data/text, and not just filenames.
00089 if (dragpending) {
00090 int len = Fl::event_length();
00091 
00092 // ignore zero-length paste events (why do these occur???)
00093 if (len > 0) {
00094 int numfiles, i;
00095 const char *lastc;
00096 int lasti;
00097 FileSpec spec;
00098 const char *ctext = Fl::event_text();
00099 char *filename = (char *) malloc((1 + len) * sizeof(char));
00100 
00101 for (lasti=0,lastc=ctext,numfiles=0,i=0; i<len; i++) {
00102 // parse out all but last filename, which doesn't have a CR
00103 if (ctext[i] == '\n') {
00104 memcpy(filename, lastc, (i-lasti)*sizeof(char));
00105 filename[i-lasti] = '0円';
00106 
00107 // attempt to load the file into a new molecule
00108 app->molecule_load(-1, filename, NULL, &spec);
00109 
00110 lasti=i+1;
00111 lastc=&ctext[lasti];
00112 numfiles++;
00113 }
00114 
00115 // special-case last filename, since there's no CR
00116 if (i == (len-1)) {
00117 memcpy(filename, lastc, (1+i-lasti)*sizeof(char));
00118 filename[1+i-lasti] = '0円';
00119 
00120 // attempt to load the file into a new molecule
00121 app->molecule_load(-1, filename, NULL, &spec);
00122 numfiles++;
00123 }
00124 }
00125 
00126 free(filename);
00127 }
00128 
00129 dragpending = 0; // no longer waiting for drag-and-drop paste
00130 }
00131 
00132 return 1; // indicate that we handled the paste operation
00133 }
00134 
00135 // handle drag-and-drop operations
00136 if (event == FL_DND_ENTER || event == FL_DND_DRAG) {
00137 return 1; // indicate that we want the drag-and-drop operation
00138 }
00139 if (event == FL_DND_RELEASE) {
00140 Fl::paste(*this);
00141 dragpending = 1; // flag to expect incoming paste due to DND operation
00142 return 1;
00143 }
00144 // end of cut-paste and drag-and-drop handling
00145 
00146 switch (event) {
00147 case FL_MOUSEWHEEL:
00148 dispdev->lastevent = event;
00149 dispdev->lastzdelta = Fl::event_dy();
00150 break;
00151 case FL_PUSH:
00152 dispdev->lastevent = event;
00153 dispdev->lastbtn = Fl::event_button();
00154 if (dispdev->lastbtn == FL_LEFT_MOUSE && Fl::event_state(FL_META)) {
00155 dispdev->lastbtn = FL_MIDDLE_MOUSE; 
00156 }
00157 break;
00158 case FL_DRAG:
00159 dispdev->lastevent = event;
00160 break;
00161 case FL_RELEASE:
00162 dispdev->lastevent = event;
00163 break;
00164 #if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 1)
00165 case FL_KEYDOWN:
00166 #else
00167 // This event code is superceded by FL_KEYDOWN in newer revs of FLTK
00168 case FL_KEYBOARD:
00169 #endif
00170 dispdev->lastevent = event;
00171 dispdev->lastkeycode = Fl::event_key();
00172 dispdev->lastbtn = *Fl::event_text();
00173 break; 
00174 default:
00175 return Fl_Gl_Window::handle(event);
00176 }
00177 return 1;
00178 }
00179 void draw() {
00180 dispdev->reshape();
00181 dispdev->_needRedraw = 1;
00182 app->VMDupdate(VMD_IGNORE_EVENTS);
00183 } 
00184 // override the hide() method since we have no way of getting it back
00185 void hide() {
00186 if (fl_show_question("Really Quit?", 0))
00187 app->VMDexit("",0,0);
00188 }
00189 };
00190 
00191 
00192 // static data for this object
00193 static const char *glStereoNameStr[OPENGL_STEREO_MODES] = 
00194 { "Off", 
00195 "QuadBuffered", 
00196 "HDTV SideBySide",
00197 "Checkerboard",
00198 "ColumnInterleaved",
00199 "RowInterleaved",
00200 "Anaglyph", 
00201 "SideBySide", 
00202 "AboveBelow",
00203 "Left", 
00204 "Right" };
00205 
00206 static const char *glRenderNameStr[OPENGL_RENDER_MODES] =
00207 { "Normal",
00208 "GLSL",
00209 "Acrobat3D" }; 
00210 
00211 static const char *glCacheNameStr[OPENGL_CACHE_MODES] =
00212 { "Off",
00213 "On" };
00214 
00216 
00217 // constructor ... open a window and set initial default values
00218 FltkOpenGLDisplayDevice::FltkOpenGLDisplayDevice(int argc, char **argv, 
00219 VMDApp *vmdapp_p, int *size, int *loc)
00220 : OpenGLRenderer((char *) "VMD " VMDVERSION " OpenGL Display") {
00221 
00222 vmdapp = vmdapp_p; // save VMDApp handle for use by drag-and-drop handlers, 
00223 // and GPU memory management routines
00224 
00225 // set up data possible before opening window
00226 stereoNames = glStereoNameStr;
00227 stereoModes = OPENGL_STEREO_MODES;
00228 
00229 // GLSL is only available on MacOS X 10.4 and later.
00230 renderNames = glRenderNameStr;
00231 renderModes = OPENGL_RENDER_MODES;
00232 
00233 cacheNames = glCacheNameStr;
00234 cacheModes = OPENGL_CACHE_MODES;
00235 
00236 #if defined(VMDFLTKUSEHIGHDPIRETINA)
00237 if (getenv("VMDNOHIGHDPI") != NULL) {
00238 msgWarn << "User override: High-DPI OpenGL display support disabled." << sendmsg;
00239 } else {
00240 // Enable High-DPI support on Apple Retina displays when supported by
00241 // the underlying FLTK version
00242 // Global FLTK function to activate support for high-DPI Apple Retina
00243 // displays. This must be called before _any_ Fl_Gl_Window is shown.
00244 // When active, the pixel_w() and pixel_h() methods must be used instead
00245 // of w() and h(), e.g., glViewport(0, 0, pixel_w(), pixel_h()).
00246 Fl::use_high_res_GL(1);
00247 msgInfo << "High-DPI OpenGL display support enabled." << sendmsg;
00248 }
00249 #endif
00250 
00251 // open the window
00252 int SX = 100, SY = 100, W, H;
00253 
00254 W = size[0];
00255 H = size[1];
00256 if (loc) {
00257 SX = loc[0];
00258 SY = loc[1];
00259 }
00260 window = new myglwindow(SX, SY, W, H, name, this, vmdapp_p);
00261 
00262 ext->hasstereo = FALSE; // stereo is off initially
00263 ext->stereodrawforced = FALSE; // stereo not forced initially
00264 ext->hasmultisample = FALSE; // multisample is off initially
00265 
00266 int rc=0;
00267 // FLTK stereo support only started working for MacOS X at around version 1.1.7
00268 #if (FL_MAJOR_VERSION >= 1) && (((FL_MINOR_VERSION >= 1) && (FL_PATCH_VERSION >= 7)) || ((FL_MINOR_VERSION >= 1) && (FL_PATCH_VERSION >= 7)))
00269 // find an appropriate visual and colormap ...
00270 if (getenv("VMDPREFERSTEREO") != NULL) {
00271 // Stereo limps along with FLTK 1.1.7 on MacOS X
00272 rc = window->mode(FL_RGB8 | FL_DOUBLE | FL_STENCIL | FL_STEREO);
00273 ext->hasstereo = TRUE;
00274 #if defined(__APPLE__)
00275 ext->stereodrawforced = TRUE; // forced draw in stereo all the time when on
00276 #endif
00277 // FLTK multisample antialiasing still doesn't actually work in 
00278 // MacOS X as of FLTK 1.1.10...
00279 #if !defined(__APPLE__)
00280 // } else if (getenv("VMDPREFERMULTISAMPLE") != NULL) {
00281 } else if (rc != 0) {
00282 rc = window->mode(FL_RGB8 | FL_DOUBLE | FL_STENCIL | FL_MULTISAMPLE);
00283 ext->hasmultisample = TRUE; // FLTK only does SGI multisample, no ARB yet
00284 #endif
00285 } else {
00286 rc = window->mode(FL_RGB8 | FL_DOUBLE | FL_STENCIL);
00287 }
00288 #else
00289 // find an appropriate visual and colormap ...
00290 rc = window->mode(FL_RGB8 | FL_DOUBLE | FL_STENCIL);
00291 #endif
00292 
00293 window->show();
00294 // (7) bind the rendering context to the window
00295 window->make_current();
00296 
00297 // (8) actually request the window to be displayed
00298 screenX = Fl::w();
00299 screenY = Fl::h(); 
00300 
00301 // (9) configure the rendering properly
00302 setup_initial_opengl_state(); // setup initial OpenGL state
00303 
00304 // set flags for the capabilities of this display
00305 // whether we can do antialiasing or not.
00306 if (ext->hasmultisample) 
00307 aaAvailable = TRUE; // we use multisampling over other methods
00308 else
00309 aaAvailable = FALSE; // no non-multisample implementation yet
00310 
00311 // set default settings
00312 if (ext->hasmultisample) {
00313 aa_on(); // enable fast multisample based antialiasing by default
00314 // other antialiasing techniques are slow, so only multisample
00315 // makes sense to enable by default.
00316 } 
00317 
00318 cueingAvailable = TRUE;
00319 cueing_on(); // leave depth cueing on by default, despite the speed hit.
00320 
00321 cullingAvailable = TRUE;
00322 culling_off();
00323 
00324 set_sphere_mode(sphereMode);
00325 set_sphere_res(sphereRes);
00326 set_line_width(lineWidth);
00327 set_line_style(lineStyle);
00328 
00329 // reshape and clear the display, which initializes some other variables
00330 reshape();
00331 normal();
00332 clear();
00333 update();
00334 }
00335 
00336 // destructor ... close the window
00337 FltkOpenGLDisplayDevice::~FltkOpenGLDisplayDevice(void) {
00338 free_opengl_ctx(); // free display lists, textures, etc
00339 delete window;
00340 }
00341 
00343 
00344 //
00345 // get the current state of the device's pointer (i.e. cursor if it has one)
00346 //
00347 
00348 // abs pos of cursor from lower-left corner of display
00349 int FltkOpenGLDisplayDevice::x(void) {
00350 //Fl::check();
00351 #if defined(VMDFLTKUSEHIGHDPIRETINA)
00352 // Enable High-DPI support on Apple Retina displays when supported by
00353 // the underlying FLTK version
00354 // When FLTK high-DPI support is enabled, it is necessary to multiply
00355 // values returned by event_x() by the result of 
00356 // Fl_Gl_Window::pixels_per_unit() to get correct GL-window pixel 
00357 // coordinates.
00358 // XXX Docs bug: FLTK docs don't specify how event_x_root() is affected, but
00359 // it appears to follow the same behavior as event_x().
00360 return Fl::event_x_root() * window->pixels_per_unit(); 
00361 #elif 1
00362 return Fl::event_x_root(); 
00363 #else
00364 int x, y;
00365 Fl::get_mouse(x, y);
00366 return x; 
00367 #endif
00368 }
00369 
00370 
00371 // same, for y direction
00372 int FltkOpenGLDisplayDevice::y(void) {
00373 //Fl::check();
00374 #if defined(VMDFLTKUSEHIGHDPIRETINA)
00375 // Enable High-DPI support on Apple Retina displays when supported by
00376 // the underlying FLTK version
00377 // When FLTK high-DPI support is enabled, it is necessary to multiply
00378 // values returned by event_y() by the result of 
00379 // Fl_Gl_Window::pixels_per_unit() to get correct GL-window pixel 
00380 // coordinates.
00381 // XXX Docs bug: FLTK docs don't specify how event_y_root() is affected, but
00382 // it appears to follow the same behavior as event_y().
00383 return screenY - (Fl::event_y_root() * window->pixels_per_unit());
00384 #elif 1
00385 return screenY - Fl::event_y_root();
00386 #else
00387 int x, y;
00388 Fl::get_mouse(x, y);
00389 return screenY - y; 
00390 #endif
00391 }
00392 
00393 // return the current state of the shift, control, and alt keys
00394 int FltkOpenGLDisplayDevice::shift_state(void) {
00395 Fl::check();
00396 
00397 int retval = 0;
00398 int keymask = (int) Fl::event_state();
00399 if (keymask & FL_SHIFT)
00400 retval |= SHIFT;
00401 if (keymask & FL_CTRL)
00402 retval |= CONTROL;
00403 if (keymask & FL_ALT)
00404 retval |= ALT;
00405 return retval;
00406 }
00407 
00408 // return the spaceball state, if any
00409 int FltkOpenGLDisplayDevice::spaceball(int *rx, int *ry, int *rz, int *tx, int *ty,
00410 int *tz, int *buttons) {
00411 // not implemented yet
00412 return 0;
00413 }
00414 
00415 
00416 // set the Nth cursor shape as the current one. If no arg given, the
00417 // default shape (n=0) is used.
00418 void FltkOpenGLDisplayDevice::set_cursor(int n) {
00419 switch (n) {
00420 default:
00421 case DisplayDevice::NORMAL_CURSOR: window->cursor(FL_CURSOR_ARROW); break;
00422 case DisplayDevice::TRANS_CURSOR: window->cursor(FL_CURSOR_MOVE); break;
00423 case DisplayDevice::SCALE_CURSOR: window->cursor(FL_CURSOR_WE); break;
00424 case DisplayDevice::PICK_CURSOR: window->cursor(FL_CURSOR_CROSS); break;
00425 case DisplayDevice::WAIT_CURSOR: window->cursor(FL_CURSOR_WAIT); break;
00426 }
00427 }
00428 
00429 
00430 //
00431 // event handling routines
00432 //
00433 
00434 // read the next event ... returns an event type (one of the above ones),
00435 // and a value. Returns success, and sets arguments.
00436 int FltkOpenGLDisplayDevice::read_event(long &retdev, long &retval) {
00437 #if !defined(__APPLE__)
00438 // disabled on OSX to avoid problems with Tcl/Tk mishandling events.
00439 // XXX this code was previously being used on MacOS X for Intel, but
00440 // it seems that it should match what we do on PowerPC so we 
00441 // do the same in all MacOS X cases now.
00442 Fl::check();
00443 #endif
00444 
00445 switch (lastevent) {
00446 case FL_MOUSEWHEEL:
00447 // XXX tests on the Mac show that FLTK is using a coordinate system 
00448 // backwards from what is used on Windows' zDelta value.
00449 if (lastzdelta < 0) {
00450 retdev = WIN_WHEELUP;
00451 } else {
00452 retdev = WIN_WHEELDOWN;
00453 }
00454 break;
00455 case FL_PUSH:
00456 case FL_DRAG:
00457 case FL_RELEASE:
00458 if (lastbtn == FL_LEFT_MOUSE) retdev = WIN_LEFT;
00459 else if (lastbtn == FL_MIDDLE_MOUSE) retdev = WIN_MIDDLE;
00460 else if (lastbtn == FL_RIGHT_MOUSE) retdev = WIN_RIGHT;
00461 else {
00462 //printf("unknown button: %d\n", lastbtn);
00463 }
00464 retval = (lastevent == FL_PUSH || lastevent == FL_DRAG);
00465 break;
00466 
00467 #if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 1)
00468 case FL_KEYDOWN:
00469 #else
00470 // This event code is superceded by FL_KEYDOWN in newer revs of FLTK
00471 case FL_KEYBOARD:
00472 #endif
00473 // check function keys first
00474 if (lastkeycode >= FL_F && lastkeycode <= FL_F_Last) {
00475 retdev = (lastkeycode - FL_F) + ((int) WIN_KBD_F1);
00476 } else {
00477 switch(lastkeycode) {
00478 case FL_Escape: retdev = WIN_KBD_ESCAPE; break;
00479 case FL_Up: retdev = WIN_KBD_UP; break;
00480 case FL_Down: retdev = WIN_KBD_DOWN; break;
00481 case FL_Left: retdev = WIN_KBD_LEFT; break;
00482 case FL_Right: retdev = WIN_KBD_RIGHT; break;
00483 case FL_Page_Up: retdev = WIN_KBD_PAGE_UP; break;
00484 case FL_Page_Down: retdev = WIN_KBD_PAGE_UP; break;
00485 case FL_Home: retdev = WIN_KBD_HOME; break;
00486 case FL_End: retdev = WIN_KBD_END; break;
00487 case FL_Insert: retdev = WIN_KBD_INSERT; break;
00488 case FL_Delete: retdev = WIN_KBD_DELETE; break;
00489 
00490 default:
00491 retdev = WIN_KBD;
00492 break;
00493 }
00494 }
00495 retval = lastbtn;
00496 break;
00497 
00498 default:
00499 return 0;
00500 }
00501 lastevent = 0;
00502 return 1;
00503 }
00504 
00505 //
00506 // virtual routines for preparing to draw, drawing, and finishing drawing
00507 //
00508 
00509 // reshape the display after a shape change
00510 void FltkOpenGLDisplayDevice::reshape(void) {
00511 
00512 #if defined(VMDFLTKUSEHIGHDPIRETINA)
00513 // Enable High-DPI support on Apple Retina displays when supported by
00514 // the underlying FLTK version
00515 xSize = window->w() * window->pixels_per_unit();
00516 ySize = window->h() * window->pixels_per_unit();
00517 xOrig = window->x() * window->pixels_per_unit();
00518 yOrig = screenY - (window->y() * window->pixels_per_unit()) - ySize;
00519 #else
00520 xSize = window->w();
00521 ySize = window->h();
00522 xOrig = window->x();
00523 yOrig = screenY - window->y() - ySize;
00524 #endif
00525 
00526 switch (inStereo) {
00527 case OPENGL_STEREO_SIDE:
00528 set_screen_pos(0.5f * (float)xSize / (float)ySize);
00529 break;
00530 
00531 case OPENGL_STEREO_ABOVEBELOW:
00532 set_screen_pos(2.0f * (float)xSize / (float)ySize);
00533 break;
00534 
00535 case OPENGL_STEREO_STENCIL_CHECKERBOARD:
00536 case OPENGL_STEREO_STENCIL_COLUMNS:
00537 case OPENGL_STEREO_STENCIL_ROWS:
00538 enable_stencil_stereo(inStereo);
00539 set_screen_pos((float)xSize / (float)ySize);
00540 break;
00541 
00542 default:
00543 set_screen_pos((float)xSize / (float)ySize);
00544 break;
00545 }
00546 }
00547 
00548 unsigned char * FltkOpenGLDisplayDevice::readpixels_rgb3u(int &x, int &y) {
00549 unsigned char * img;
00550 
00551 x = xSize;
00552 y = ySize;
00553 
00554 if ((img = (unsigned char *) malloc(x * y * 3)) != NULL) {
00555 #if !defined(WIREGL) 
00556 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00557 glReadPixels(0, 0, x, y, GL_RGB, GL_UNSIGNED_BYTE, img);
00558 #endif
00559 } else {
00560 x = 0;
00561 y = 0;
00562 } 
00563 
00564 return img; 
00565 }
00566 
00567 unsigned char * FltkOpenGLDisplayDevice::readpixels_rgba4u(int &x, int &y) {
00568 unsigned char * img;
00569 
00570 x = xSize;
00571 y = ySize;
00572 
00573 if ((img = (unsigned char *) malloc(x * y * 4)) != NULL) {
00574 #if !defined(WIREGL) 
00575 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00576 glReadPixels(0, 0, x, y, GL_RGBA, GL_UNSIGNED_BYTE, img);
00577 #endif
00578 } else {
00579 x = 0;
00580 y = 0;
00581 } 
00582 
00583 return img; 
00584 }
00585 
00586 
00587 // update after drawing
00588 void FltkOpenGLDisplayDevice::update(int do_update) {
00589 if(do_update)
00590 window->swap_buffers();
00591 
00592 glDrawBuffer(GL_BACK);
00593 }
00594 
00595 void FltkOpenGLDisplayDevice::do_resize_window(int w, int h) {
00596 #if defined(VMDFLTKUSEHIGHDPIRETINA)
00597 // when running in High-DPI / retina mode, the user specifies VMD image 
00598 // resolutions in real rendered pixels, not pseudo pixels, so we have to 
00599 // pre-divide out the scale factor since FLTK will multiply it back in.
00600 window->size(w / window->pixels_per_unit(), h / window->pixels_per_unit());
00601 #else
00602 window->size(w, h);
00603 #endif
00604 
00605 // XXX this may not be reliable on MacOS X with recent revs of FLTK
00606 window->size_range(1,1,0,0); // resizable to full screen
00607 }
00608 
00609 void FltkOpenGLDisplayDevice::do_reposition_window(int xpos, int ypos) {
00610 window->position(xpos, ypos);
00611 // XXX this may not be reliable on MacOS X with recent revs of FLTK
00612 window->size_range(1,1,0,0); // resizable to full screen
00613 }
00614 
00615 

Generated on Mon Nov 17 02:46:12 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /