summaryrefslogtreecommitdiff
path: root/src/Fl_Screen_Driver.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/Fl_Screen_Driver.cxx')
-rw-r--r--src/Fl_Screen_Driver.cxx176
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$".
//