Support for full screen over multiple monitors.
The API follows that of EWMH, which gives you a good control over which monitors to use. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10189 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
f27bde8316
commit
0cfc2554c6
@ -49,7 +49,7 @@ class Fl_X;
|
||||
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 < 10301
|
||||
@ -68,6 +68,22 @@ class FL_EXPORT Fl_Window : public Fl_Group {
|
||||
static // when these members are static, ABI compatibility with 1.3.0 is respected
|
||||
#endif
|
||||
int no_fullscreen_h;
|
||||
#if FLTK_ABI_VERSION < 10303
|
||||
static // when these members are static, ABI compatibility with 1.3.2 is respected
|
||||
#endif
|
||||
int fullscreen_screen_top;
|
||||
#if FLTK_ABI_VERSION < 10303
|
||||
static // when these members are static, ABI compatibility with 1.3.2 is respected
|
||||
#endif
|
||||
int fullscreen_screen_bottom;
|
||||
#if FLTK_ABI_VERSION < 10303
|
||||
static // when these members are static, ABI compatibility with 1.3.2 is respected
|
||||
#endif
|
||||
int fullscreen_screen_left;
|
||||
#if FLTK_ABI_VERSION < 10303
|
||||
static // when these members are static, ABI compatibility with 1.3.2 is respected
|
||||
#endif
|
||||
int fullscreen_screen_right;
|
||||
|
||||
friend class Fl_X;
|
||||
Fl_X *i; // points at the system-specific stuff
|
||||
@ -402,13 +418,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();
|
||||
/**
|
||||
@ -424,6 +442,17 @@ public:
|
||||
Returns non zero if FULLSCREEN flag is set, 0 otherwise.
|
||||
*/
|
||||
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
|
||||
|
@ -79,6 +79,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);
|
||||
|
@ -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() && fullscreen_active())
|
||||
fullscreen_x();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// End of "$Id$".
|
||||
|
@ -2394,9 +2394,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;
|
||||
}
|
||||
|
@ -1483,7 +1483,6 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
|
||||
Y+=yoff;
|
||||
|
||||
if (w->fullscreen_active()) {
|
||||
X = Y = 0;
|
||||
bx = by = bt = 0;
|
||||
}
|
||||
|
||||
@ -1537,19 +1536,42 @@ void Fl_Window::resize(int X,int Y,int W,int H) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1802,8 +1824,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;
|
||||
|
76
src/Fl_x.cxx
76
src/Fl_x.cxx
@ -345,6 +345,7 @@ Atom fl_NET_WM_ICON_NAME; // utf8 aware window icon name
|
||||
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;
|
||||
|
||||
/*
|
||||
@ -654,6 +655,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);
|
||||
|
||||
if (sizeof(Atom) < 4)
|
||||
@ -2147,22 +2149,30 @@ void Fl_Window::resize(int X,int Y,int W,int H) {
|
||||
#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;
|
||||
|
||||
@ -2188,6 +2198,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();
|
||||
@ -2274,7 +2300,7 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
|
||||
// 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:
|
||||
@ -2303,6 +2329,23 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
|
||||
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);
|
||||
|
||||
@ -2326,9 +2369,17 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
|
||||
// border, and cannot grab without an existing window. Besides,
|
||||
// there is no clear_override().
|
||||
if (win->fullscreen_active() && !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) {
|
||||
@ -2393,6 +2444,13 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
|
||||
|
||||
// If asked for, create fullscreen
|
||||
if (win->fullscreen_active() && 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);
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ class fullscreen_window : public Fl_Single_Window {
|
||||
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,27 +170,63 @@ 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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void allscreens_cb(Fl_Widget *o, void *p) {
|
||||
Fl_Window *w = (Fl_Window *)p;
|
||||
int d = ((Fl_Button *)o)->value();
|
||||
if (d) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void update_screeninfo(Fl_Widget *b, void *p) {
|
||||
Fl_Browser *browser = (Fl_Browser *)p;
|
||||
int x, y, w, h;
|
||||
@ -219,7 +255,7 @@ void exit_cb(Fl_Widget *, void *) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#define NUMB 7
|
||||
#define NUMB 8
|
||||
|
||||
int twowindow = 0;
|
||||
int initfull = 0;
|
||||
@ -284,6 +320,10 @@ 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");
|
||||
window.b4->callback(allscreens_cb,w);
|
||||
y+=30;
|
||||
|
||||
Fl_Button eb(50,y,window.w()-60,30,"Exit");
|
||||
eb.callback(exit_cb);
|
||||
y+=30;
|
||||
|
Loading…
Reference in New Issue
Block a user