diff options
Diffstat (limited to 'src/Fl_Screen_Driver.cxx')
| -rw-r--r-- | src/Fl_Screen_Driver.cxx | 176 |
1 files changed, 166 insertions, 10 deletions
diff --git a/src/Fl_Screen_Driver.cxx b/src/Fl_Screen_Driver.cxx index 526f37b1e..4abecc956 100644 --- a/src/Fl_Screen_Driver.cxx +++ b/src/Fl_Screen_Driver.cxx @@ -3,7 +3,7 @@ // // All screen related calls in a driver style class. // -// Copyright 1998-2016 by Bill Spitzak and others. +// Copyright 1998-2017 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -24,6 +24,10 @@ #include <FL/Fl_Group.H> #include <FL/Fl_Window.H> #include <FL/Fl_Input.H> +#include <FL/Fl_Window_Driver.H> +#include <FL/Fl_Image_Surface.H> +#include <FL/Fl_Box.H> +#include <FL/Fl_Tooltip.H> char Fl_Screen_Driver::bg_set = 0; char Fl_Screen_Driver::bg2_set = 0; @@ -110,7 +114,7 @@ int Fl_Screen_Driver::screen_num(int x, int y) // Return the number of pixels common to the two rectangular areas -static inline float fl_intersection(int x1, int y1, int w1, int h1, +float Fl_Screen_Driver::fl_intersection(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { if(x1+w1 < x2 || x2+w2 < x1 || y1+h1 < y2 || y2+h2 < y1) @@ -154,7 +158,7 @@ void Fl_Screen_Driver::compose_reset() { } uchar *Fl_Screen_Driver::read_image(uchar *p, int X, int Y, int w, int h, int alpha) { - uchar *image_data; + uchar *image_data = NULL; Fl_RGB_Image *img; if (fl_find(fl_window) == 0) { // read from off_screen buffer img = read_win_rectangle(p, X, Y, w, h, alpha); @@ -165,14 +169,16 @@ uchar *Fl_Screen_Driver::read_image(uchar *p, int X, int Y, int w, int h, int al } else { img = traverse_to_gl_subwindows(Fl_Window::current(), p, X, Y, w, h, alpha, NULL); } - if (img->w() > w) { - Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w, h); + if (img) { + if (img->w() > w) { + Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w, h); + delete img; + img = img2; + } + img->alloc_array = 0; + image_data = (uchar*)img->array; delete img; - img = img2; } - img->alloc_array = 0; - image_data = (uchar*)img->array; - delete img; return image_data; } @@ -268,7 +274,9 @@ Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, uchar *p, } else { top = full_img->h() - (origin_y - y + img->h()); } - write_image_inside(full_img, img, origin_x - x, top); + int nscreen = c->as_window()->driver()->screen_num(); + float s = Fl::screen_driver()->scale(nscreen); + write_image_inside(full_img, img, (origin_x - x) * s, top * s); delete img; } } @@ -346,6 +354,154 @@ int Fl_Screen_Driver::input_widget_handle_key(int key, unsigned mods, unsigned s return -1; } + +#if defined(FLTK_HIDPI_SUPPORT) || !(defined(WIN32) || defined(__APPLE__)) + +void Fl_Screen_Driver::rescale_all_windows_from_screen(int screen, float f) +{ + float old_f = this->scale(screen); + if (f == old_f) return; + this->scale(screen, f); + Fl_Graphics_Driver *d = Fl_Display_Device::display_device()->driver(); + d->scale(f); + int i = 0, count = 0; // count top-level windows, except transient scale-displaying window + Fl_Window *win = Fl::first_window(); + while (win) { + if (!win->parent() && (win->driver()->screen_num() == screen || rescalable() == SYSTEMWIDE_APP_SCALING) && + win->user_data() != &Fl_Screen_Driver::transient_scale_display) count++; + win = Fl::next_window(win); + } + Fl_Window **win_array = new Fl_Window*[count]; + win = Fl::first_window(); // memorize all top-level windows + while (win) { + if (!win->parent() && win->user_data() != &Fl_Screen_Driver::transient_scale_display && + (win->driver()->screen_num() == screen || rescalable() == SYSTEMWIDE_APP_SCALING) ) { + win_array[i++] = win; + } + win = Fl::next_window(win); + } + for (i = count - 1; i >= 0; i--) { // rescale all top-level windows, finishing with front one + win = win_array[i]; + int oldx = win->x(), oldy = win->y(); + win->hide(); + win->driver()->screen_num(screen); + win->position(oldx*old_f/f, oldy*old_f/f); + win->driver()->force_position(1); + if (win->fullscreen_active()) { + win->size(win->w() * old_f/f, win->h() * old_f/f); + } + win->show(); + win->wait_for_expose(); + } + delete[] win_array; +} + +static void del_transient_window(void *data) { + Fl_Window *win = (Fl_Window*)data; + delete (Fl_RGB_Image*)win->child(0)->user_data(); + Fl::delete_widget(win); +} + +void Fl_Screen_Driver::transient_scale_display(float f, int nscreen) +{ // transiently show the new scaling value using a shaped window + int w = 150; + // draw a white rounded box on black background + Fl_Screen_Driver *d = Fl::screen_driver(); + float s = d->scale(nscreen); + if (s > 3) s = 3; // limit the growth of the transient window + Fl_Image_Surface *surf = new Fl_Image_Surface(w*s, w*s/2); + Fl_Surface_Device::push_current(surf); + fl_color(FL_BLACK); + fl_rectf(-1, -1, w*s+2, w*s+2); + Fl_Box *b = new Fl_Box(FL_RFLAT_BOX, 0, 0, w*s, w*s/2, ""); + b->color(FL_WHITE); + surf->draw(b); + delete b; + Fl_RGB_Image* img = surf->image(); // img will be the window's shape + Fl_Surface_Device::pop_current(); + delete surf; + //create a window shaped with the rounded box + int X, Y, W, H; + Fl::screen_xywh(X, Y, W, H, nscreen); + w /= d->scale(nscreen)/s; + Fl_Window *win = new Fl_Window((X + W/2) -w/2, (Y + H/2) -w/4, w, w/2, 0); + b = new Fl_Box(FL_FLAT_BOX, 0, 0, w, w/2, NULL); + char str[10]; + sprintf(str, "%d %%", int(f * 100 + 0.5)); + b->copy_label(str); + b->labelfont(FL_TIMES_BOLD); + b->labelsize(30 * s / d->scale(nscreen)); + b->labelcolor(FL_BLACK); + b->color(Fl_Tooltip::color()); + win->end(); + win->shape(img); + b->user_data(img); + win->user_data((void*)&transient_scale_display); // prevent this window from being rescaled later + win->set_output(); + win->set_non_modal(); + win->driver()->screen_num(nscreen); + win->driver()->force_position(1); + win->show(); + Fl::add_timeout(1, del_transient_window, win); // delete after 1 sec +} + +// respond to Ctrl-'+' and Ctrl-'-' and Ctrl-'0' (Ctrl-'=' is same as Ctrl-'+') by rescaling all windows +int Fl_Screen_Driver::scale_handler(int event) +{ + if ( event != FL_SHORTCUT || (!Fl::event_command()) ) return 0; + int key = Fl::event_key() & ~(FL_SHIFT+FL_COMMAND); + if (key == '=' || key == '-' || key == '+' || key == '0' || key == 0xE0/* for '0' on Fr keyboard */) { + int i, count; + if (Fl::grab()) return 0; // don't rescale when menu windows are on + Fl_Widget *wid = Fl::focus(); + if (!wid) return 0; + int screen = wid->top_window()->driver()->screen_num(); + Fl_Screen_Driver *screen_dr = Fl::screen_driver(); + static float initial_scale = screen_dr->scale(screen); + static float scaling_values[] = {0.5, 2.f/3, 0.8, 0.9, 1, 1.1, 1.2, 4.f/3, 1.5, 1.7, 2, 2.4, 3, + 4, 5.5, 6.5, 7.5, 9.75 }; + float f, old_f = screen_dr->scale(screen)/initial_scale; + if (key == '0' || key == 0xE0) f = 1; + else { + count = sizeof(scaling_values)/sizeof(float); + for (i = 0; i < count; i++) { + if (old_f >= scaling_values[i] - 1e-4 && (i+1 >= count || old_f < scaling_values[i+1] - 1e-4)) { + break; + } + } + if (key == '-') i--; else i++; + if (i < 0) i = 0; if (i >= count) i = count - 1; + f = scaling_values[i]; + } + if (f == old_f) return 1; + screen_dr->rescale_all_windows_from_screen(screen, f*initial_scale); + Fl_Screen_Driver::transient_scale_display(f, screen); + screen_dr->init_workarea(); + return 1; + } + return 0; +} + +#endif // FLTK_HIDPI_SUPPORT + + +// determine the scaling value used at startup time (helps supporting HiDPI displays) +float Fl_Screen_Driver::default_scale_factor() +{ + float factor = 1; +#if defined(FLTK_HIDPI_SUPPORT) || !(defined(WIN32) || defined(__APPLE__)) + char *p = 0; + if ((p = getenv("FLTK_SCALING_FACTOR"))) { + sscanf(p, "%f", &factor); + } + else { + factor = desktop_scale_factor(); + } +#endif // FLTK_HIDPI_SUPPORT + return factor; +} + + // // End of "$Id$". // |
