diff -up fltk-1.3.x-r9671/FL/Fl_Window.H.multihead fltk-1.3.x-r9671/FL/Fl_Window.H --- fltk-1.3.x-r9671/FL/Fl_Window.H.multihead 2013-08-21 15:39:12.913459946 -0500 +++ fltk-1.3.x-r9671/FL/Fl_Window.H 2013-08-21 15:39:12.924459833 -0500 @@ -54,7 +54,7 @@ class Fl_RGB_Image; class FL_EXPORT Fl_Window : public Fl_Group { static char *default_xclass_; - // Note: we must use separate statements for each of the following 4 variables, + // Note: we must use separate statements for each of the following 8 variables, // with the static attribute, otherwise MS VC++ 2008/2010 complains :-( // AlbrechtS 04/2012 #if FLTK_ABI_VERSION < 10302 @@ -73,6 +73,22 @@ class FL_EXPORT Fl_Window : public Fl_Gr static // when these members are static, ABI compatibility with 1.3.0 is respected #endif int no_fullscreen_h; +#if FLTK_ABI_VERSION < 10302 + static // when these members are static, ABI compatibility with 1.3.0 is respected +#endif + int fullscreen_screen_top; +#if FLTK_ABI_VERSION < 10302 + static // when these members are static, ABI compatibility with 1.3.0 is respected +#endif + int fullscreen_screen_bottom; +#if FLTK_ABI_VERSION < 10302 + static // when these members are static, ABI compatibility with 1.3.0 is respected +#endif + int fullscreen_screen_left; +#if FLTK_ABI_VERSION < 10302 + static // when these members are static, ABI compatibility with 1.3.0 is respected +#endif + int fullscreen_screen_right; friend class Fl_X; Fl_X *i; // points at the system-specific stuff @@ -430,13 +446,15 @@ public: */ void show(int argc, char **argv); /** - Makes the window completely fill the screen, without any window - manager border visible. You must use fullscreen_off() to undo - this. + Makes the window completely fill one or more screens, without any + window manager border visible. You must use fullscreen_off() to + undo this. \note On some platforms, this can result in the keyboard being grabbed. The window may also be recreated, meaning hide() and show() will be called. + + \see void Fl_Window::fullscreen_screens() */ void fullscreen(); /** @@ -453,6 +471,17 @@ public: */ unsigned int fullscreen_active() const { return flags() & FULLSCREEN; } /** + Sets which screens should be used when this window is in fullscreen + mode. The window will be resized to the top of the screen with index + \p top, the bottom of the screen with index \p bottom, etc. + + If this method is never called, or if any argument is < 0, then the + window will be resized to fill the screen it is currently on. + + \see void Fl_Window::fullscreen() + */ + void fullscreen_screens(int top, int bottom, int left, int right); + /** Iconifies the window. If you call this when shown() is false it will show() it as an icon. If the window is already iconified this does nothing. diff -up fltk-1.3.x-r9671/FL/win32.H.multihead fltk-1.3.x-r9671/FL/win32.H --- fltk-1.3.x-r9671/FL/win32.H.multihead 2013-08-21 15:39:12.914459936 -0500 +++ fltk-1.3.x-r9671/FL/win32.H 2013-08-21 15:39:12.925459823 -0500 @@ -80,6 +80,7 @@ public: static Fl_X* i(const Fl_Window* w) {return w->i;} static int fake_X_wm(const Fl_Window* w,int &X, int &Y, int &bt,int &bx,int &by); + void make_fullscreen(int X, int Y, int W, int H); void setwindow(Fl_Window* wi) {w=wi; wi->i=this;} void flush() {w->flush();} void set_minmax(LPMINMAXINFO minmax); diff -up fltk-1.3.x-r9671/src/Fl_cocoa.mm.multihead fltk-1.3.x-r9671/src/Fl_cocoa.mm --- fltk-1.3.x-r9671/src/Fl_cocoa.mm.multihead 2013-08-21 15:39:12.907460008 -0500 +++ fltk-1.3.x-r9671/src/Fl_cocoa.mm 2013-08-21 15:39:12.926459813 -0500 @@ -2173,9 +2173,32 @@ void Fl_X::make(Fl_Window* w) NSRect crect; if (w->fullscreen_active()) { - int sx, sy, sw, sh; - Fl::screen_xywh(sx, sy, sw, sh, w->x(), w->y(), w->w(), w->h()); - w->resize(sx, sy, sw, sh); + int top, bottom, left, right; + int sx, sy, sw, sh, X, Y, W, H; + + top = w->fullscreen_screen_top; + bottom = w->fullscreen_screen_bottom; + left = w->fullscreen_screen_left; + right = w->fullscreen_screen_right; + + if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { + top = Fl::screen_num(w->x(), w->y(), w->w(), w->h()); + bottom = top; + left = top; + right = top; + } + + Fl::screen_xywh(sx, sy, sw, sh, top); + Y = sy; + Fl::screen_xywh(sx, sy, sw, sh, bottom); + H = sy + sh - Y; + Fl::screen_xywh(sx, sy, sw, sh, left); + X = sx; + Fl::screen_xywh(sx, sy, sw, sh, right); + W = sx + sw - X; + + w->resize(X, Y, W, H); + winstyle = NSBorderlessWindowMask; winlevel = NSStatusWindowLevel; } diff -up fltk-1.3.x-r9671/src/Fl_win32.cxx.multihead fltk-1.3.x-r9671/src/Fl_win32.cxx --- fltk-1.3.x-r9671/src/Fl_win32.cxx.multihead 2013-08-21 15:39:12.916459915 -0500 +++ fltk-1.3.x-r9671/src/Fl_win32.cxx 2013-08-21 15:39:12.927459802 -0500 @@ -1391,19 +1391,42 @@ void Fl_Window::resize(int X,int Y,int W } } -static void make_fullscreen(Fl_Window *w, Window xid, int X, int Y, int W, int H) { +void Fl_X::make_fullscreen(int X, int Y, int W, int H) { + int top, bottom, left, right; int sx, sy, sw, sh; - Fl::screen_xywh(sx, sy, sw, sh, X, Y, W, H); + + top = w->fullscreen_screen_top; + bottom = w->fullscreen_screen_bottom; + left = w->fullscreen_screen_left; + right = w->fullscreen_screen_right; + + if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { + top = Fl::screen_num(X, Y, W, H); + bottom = top; + left = top; + right = top; + } + + Fl::screen_xywh(sx, sy, sw, sh, top); + Y = sy; + Fl::screen_xywh(sx, sy, sw, sh, bottom); + H = sy + sh - Y; + Fl::screen_xywh(sx, sy, sw, sh, left); + X = sx; + Fl::screen_xywh(sx, sy, sw, sh, right); + W = sx + sw - X; + DWORD flags = GetWindowLong(xid, GWL_STYLE); flags = flags & ~(WS_THICKFRAME|WS_CAPTION); SetWindowLong(xid, GWL_STYLE, flags); + // SWP_NOSENDCHANGING is so that we can override size limits - SetWindowPos(xid, HWND_TOP, sx, sy, sw, sh, SWP_NOSENDCHANGING | SWP_FRAMECHANGED); + SetWindowPos(xid, HWND_TOP, X, Y, W, H, SWP_NOSENDCHANGING | SWP_FRAMECHANGED); } void Fl_Window::fullscreen_x() { _set_fullscreen(); - make_fullscreen(this, fl_xid(this), x(), y(), w(), h()); + i->make_fullscreen(x(), y(), w(), h()); Fl::handle(FL_FULLSCREEN, this); } @@ -1658,8 +1681,8 @@ Fl_X* Fl_X::make(Fl_Window* w) { monitor the window was placed on. */ RECT rect; GetWindowRect(x->xid, &rect); - make_fullscreen(w, x->xid, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top); + x->make_fullscreen(rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top); } x->next = Fl_X::first; diff -up fltk-1.3.x-r9671/src/Fl_Window_fullscreen.cxx.multihead fltk-1.3.x-r9671/src/Fl_Window_fullscreen.cxx --- fltk-1.3.x-r9671/src/Fl_Window_fullscreen.cxx.multihead 2012-03-23 11:47:53.000000000 -0500 +++ fltk-1.3.x-r9671/src/Fl_Window_fullscreen.cxx 2013-08-21 15:39:12.928459792 -0500 @@ -36,6 +36,10 @@ int Fl_Window::no_fullscreen_x = 0; int Fl_Window::no_fullscreen_y = 0; int Fl_Window::no_fullscreen_w = 0; int Fl_Window::no_fullscreen_h = 0; +int Fl_Window::fullscreen_screen_top = -1; +int Fl_Window::fullscreen_screen_bottom = -1; +int Fl_Window::fullscreen_screen_left = -1; +int Fl_Window::fullscreen_screen_right = -1; #endif void Fl_Window::border(int b) { @@ -95,6 +99,23 @@ void Fl_Window::fullscreen_off() { fullscreen_off(no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h); } +void Fl_Window::fullscreen_screens(int top, int bottom, int left, int right) { + if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { + fullscreen_screen_top = -1; + fullscreen_screen_bottom = -1; + fullscreen_screen_left = -1; + fullscreen_screen_right = -1; + } else { + fullscreen_screen_top = top; + fullscreen_screen_bottom = bottom; + fullscreen_screen_left = left; + fullscreen_screen_right = right; + } + + if (shown() && (flags() & Fl_Widget::FULLSCREEN)) + fullscreen_x(); +} + // // End of "$Id: Fl_Window_fullscreen.cxx 9299 2012-03-23 16:47:53Z manolo $". diff -up fltk-1.3.x-r9671/src/Fl_x.cxx.multihead fltk-1.3.x-r9671/src/Fl_x.cxx --- fltk-1.3.x-r9671/src/Fl_x.cxx.multihead 2013-08-21 15:39:12.918459895 -0500 +++ fltk-1.3.x-r9671/src/Fl_x.cxx 2013-08-21 15:39:12.929459782 -0500 @@ -352,6 +352,7 @@ Atom fl_NET_WM_ICON_NAME; // utf8 aware Atom fl_NET_SUPPORTING_WM_CHECK; Atom fl_NET_WM_STATE; Atom fl_NET_WM_STATE_FULLSCREEN; +Atom fl_NET_WM_FULLSCREEN_MONITORS; Atom fl_NET_WORKAREA; Atom fl_NET_WM_ICON; @@ -717,6 +718,7 @@ void fl_open_display(Display* d) { fl_NET_SUPPORTING_WM_CHECK = XInternAtom(d, "_NET_SUPPORTING_WM_CHECK", 0); fl_NET_WM_STATE = XInternAtom(d, "_NET_WM_STATE", 0); fl_NET_WM_STATE_FULLSCREEN = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", 0); + fl_NET_WM_FULLSCREEN_MONITORS = XInternAtom(d, "_NET_WM_FULLSCREEN_MONITORS", 0); fl_NET_WORKAREA = XInternAtom(d, "_NET_WORKAREA", 0); fl_NET_WM_ICON = XInternAtom(d, "_NET_WM_ICON", 0); @@ -1870,22 +1872,30 @@ void Fl_Window::resize(int X,int Y,int W #define _NET_WM_STATE_ADD 1 /* add/set property */ #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ -static void send_wm_state_event(Window wnd, int add, Atom prop) { +static void send_wm_event(Window wnd, Atom message, + unsigned long d0, unsigned long d1=0, + unsigned long d2=0, unsigned long d3=0, + unsigned long d4=0) { XEvent e; e.xany.type = ClientMessage; e.xany.window = wnd; - e.xclient.message_type = fl_NET_WM_STATE; + e.xclient.message_type = message; e.xclient.format = 32; - e.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; - e.xclient.data.l[1] = prop; - e.xclient.data.l[2] = 0; - e.xclient.data.l[3] = 0; - e.xclient.data.l[4] = 0; + e.xclient.data.l[0] = d0; + e.xclient.data.l[1] = d1; + e.xclient.data.l[2] = d2; + e.xclient.data.l[3] = d3; + e.xclient.data.l[4] = d4; XSendEvent(fl_display, RootWindow(fl_display, fl_screen), 0, SubstructureNotifyMask | SubstructureRedirectMask, &e); } +static void send_wm_state_event(Window wnd, int add, Atom prop) { + send_wm_event(wnd, fl_NET_WM_STATE, + add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE, prop); +} + int Fl_X::ewmh_supported() { static int result = -1; @@ -1909,6 +1919,22 @@ int Fl_X::ewmh_supported() { /* Change an existing window to fullscreen */ void Fl_Window::fullscreen_x() { if (Fl_X::ewmh_supported()) { + int top, bottom, left, right; + + top = fullscreen_screen_top; + bottom = fullscreen_screen_bottom; + left = fullscreen_screen_left; + right = fullscreen_screen_right; + + if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) { + top = Fl::screen_num(x(), y(), w(), h()); + bottom = top; + left = top; + right = top; + } + + send_wm_event(fl_xid(this), fl_NET_WM_FULLSCREEN_MONITORS, + top, bottom, left, right); send_wm_state_event(fl_xid(this), 1, fl_NET_WM_STATE_FULLSCREEN); } else { _set_fullscreen(); @@ -1995,7 +2021,7 @@ void Fl_X::make_xid(Fl_Window* win, XVis // force the window to be on-screen. Usually the X window manager // does this, but a few don't, so we do it here for consistency: int scr_x, scr_y, scr_w, scr_h; - Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y); + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y, W, H); if (win->border()) { // ensure border is on screen: @@ -2024,6 +2050,23 @@ void Fl_X::make_xid(Fl_Window* win, XVis return; } + // Compute which screen(s) we should be on if we want to go fullscreen + int fullscreen_top, fullscreen_bottom, fullscreen_left, fullscreen_right; + + fullscreen_top = win->fullscreen_screen_top; + fullscreen_bottom = win->fullscreen_screen_bottom; + fullscreen_left = win->fullscreen_screen_left; + fullscreen_right = win->fullscreen_screen_right; + + if ((fullscreen_top < 0) || (fullscreen_bottom < 0) || + (fullscreen_left < 0) || (fullscreen_right < 0)) { + fullscreen_top = Fl::screen_num(X, Y, W, H); + fullscreen_bottom = fullscreen_top; + fullscreen_left = fullscreen_top; + fullscreen_right = fullscreen_top; + } + + ulong root = win->parent() ? fl_xid(win->window()) : RootWindow(fl_display, fl_screen); @@ -2047,9 +2090,17 @@ void Fl_X::make_xid(Fl_Window* win, XVis // border, and cannot grab without an existing window. Besides, // there is no clear_override(). if (win->flags() & Fl_Widget::FULLSCREEN && !Fl_X::ewmh_supported()) { + int sx, sy, sw, sh; attr.override_redirect = 1; mask |= CWOverrideRedirect; - Fl::screen_xywh(X, Y, W, H, X, Y, W, H); + Fl::screen_xywh(sx, sy, sw, sh, fullscreen_left); + X = sx; + Fl::screen_xywh(sx, sy, sw, sh, fullscreen_right); + W = sx + sw - X; + Fl::screen_xywh(sx, sy, sw, sh, fullscreen_top); + Y = sy; + Fl::screen_xywh(sx, sy, sw, sh, fullscreen_bottom); + H = sy + sh - Y; } if (fl_background_pixel >= 0) { @@ -2120,6 +2171,13 @@ void Fl_X::make_xid(Fl_Window* win, XVis // If asked for, create fullscreen if (win->flags() & Fl_Widget::FULLSCREEN && Fl_X::ewmh_supported()) { + unsigned long data[4]; + data[0] = fullscreen_top; + data[1] = fullscreen_bottom; + data[2] = fullscreen_left; + data[3] = fullscreen_right; + XChangeProperty (fl_display, xp->xid, fl_NET_WM_FULLSCREEN_MONITORS, XA_ATOM, 32, + PropModeReplace, (unsigned char*) data, 4); XChangeProperty (fl_display, xp->xid, fl_NET_WM_STATE, XA_ATOM, 32, PropModeAppend, (unsigned char*) &fl_NET_WM_STATE_FULLSCREEN, 1); } diff -up fltk-1.3.x-r9671/test/fullscreen.cxx.multihead fltk-1.3.x-r9671/test/fullscreen.cxx --- fltk-1.3.x-r9671/test/fullscreen.cxx.multihead 2012-06-14 10:09:46.000000000 -0500 +++ fltk-1.3.x-r9671/test/fullscreen.cxx 2013-08-21 15:39:12.929459782 -0500 @@ -127,7 +127,7 @@ class fullscreen_window : public Fl_Sing fullscreen_window(int W, int H, const char *t=0); int handle (int e); Fl_Toggle_Light_Button *b3; - + Fl_Toggle_Light_Button *b4; }; fullscreen_window::fullscreen_window(int W, int H, const char *t) : Fl_Single_Window(W, H, t) { @@ -170,23 +170,54 @@ void border_cb(Fl_Widget *o, void *p) { #endif } -int px,py,pw,ph; Fl_Button *border_button; void fullscreen_cb(Fl_Widget *o, void *p) { Fl_Window *w = (Fl_Window *)p; int d = ((Fl_Button *)o)->value(); if (d) { - px = w->x(); - py = w->y(); - pw = w->w(); - ph = w->h(); + if (((fullscreen_window*)w)->b4->value()) { + int top, bottom, left, right; + int top_y, bottom_y, left_x, right_x; + + int sx, sy, sw, sh; + + top = bottom = left = right = 0; + + Fl::screen_xywh(sx, sy, sw, sh, 0); + top_y = sy; + bottom_y = sy + sh; + left_x = sx; + right_x = sx + sw; + + for (int i = 1;i < Fl::screen_count();i++) { + Fl::screen_xywh(sx, sy, sw, sh, i); + if (sy < top_y) { + top = i; + top_y = sy; + } + if ((sy + sh) > bottom_y) { + bottom = i; + bottom_y = sy + sh; + } + if (sx < left_x) { + left = i; + left_x = sx; + } + if ((sx + sw) > right_x) { + right = i; + right_x = sx + sw; + } + } + + w->fullscreen_screens(top, bottom, left, right); + } else { + w->fullscreen_screens(-1, -1, -1, -1); + } w->fullscreen(); - w->override(); #ifndef WIN32 // update our border state in case border was turned off border_button->value(w->border()); #endif } else { - //w->fullscreen_off(px,py,pw,ph); w->fullscreen_off(); } } @@ -219,7 +250,7 @@ void exit_cb(Fl_Widget *, void *) { exit(0); } -#define NUMB 7 +#define NUMB 8 int twowindow = 0; int initfull = 0; @@ -284,6 +315,9 @@ int main(int argc, char **argv) { window.b3->callback(fullscreen_cb,w); y+=30; + window.b4 = new Fl_Toggle_Light_Button(50,y,window.w()-60,30,"All Screens"); + y+=30; + Fl_Button eb(50,y,window.w()-60,30,"Exit"); eb.callback(exit_cb); y+=30;