Fix STR#2641: true fullscreen windows that cover all their screen including menu bar, task bar, dock.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@9299 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2012-03-23 16:47:53 +00:00
parent 8cd98f5236
commit 08ce2e07d3
16 changed files with 460 additions and 99 deletions

View File

@ -3,7 +3,7 @@
//
// Enumerations for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2011 by Bill Spitzak and others.
// Copyright 1998-2012 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
@ -293,7 +293,10 @@ enum Fl_Event { // events
/** The screen configuration (number, positions) was changed.
Use Fl::add_handler() to be notified of this event.
*/
FL_SCREEN_CONFIGURATION_CHANGED = 24
FL_SCREEN_CONFIGURATION_CHANGED = 24,
/** The fullscreen state of the window has changed
*/
FL_FULLSCREEN = 25
};
/** \name When Conditions */

View File

@ -3,7 +3,7 @@
//
// Widget header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2010 by Bill Spitzak and others.
// Copyright 1998-2012 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
@ -170,6 +170,7 @@ protected:
NO_OVERLAY = 1<<15, ///< window not using a hardware overlay plane (Fl_Menu_Window)
GROUP_RELATIVE = 1<<16, ///< position this widget relative to the parent group, not to the window
COPIED_TOOLTIP = 1<<17, ///< the widget tooltip is internally copied, its destruction is handled by the widget
FULLSCREEN = 1<<18, ///< a fullscreen window (Fl_Window)
// (space for more flags)
USERFLAG3 = 1<<29, ///< reserved for 3rd party extensions
USERFLAG2 = 1<<30, ///< reserved for 3rd party extensions
@ -843,6 +844,9 @@ public:
static unsigned int label_shortcut(const char *t);
/* Internal use only. */
static int test_shortcut(const char*, const bool require_alt = false);
/* Internal use only. */
void _set_fullscreen() {flags_ |= FULLSCREEN;}
void _clear_fullscreen() {flags_ &= ~FULLSCREEN;}
/** Checks if w is a child of this widget.
\param[in] w potential child widget

View File

@ -3,7 +3,7 @@
//
// Window header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2010 by Bill Spitzak and others.
// Copyright 1998-2012 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
@ -49,6 +49,10 @@ class Fl_X;
class FL_EXPORT Fl_Window : public Fl_Group {
static char *default_xclass_;
#if FLTK_ABI_VERSION < 10302
static // when these members are static, ABI compatibility with 1.3.0 is respected
#endif
int no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h;
friend class Fl_X;
Fl_X *i; // points at the system-specific stuff
@ -65,6 +69,8 @@ class FL_EXPORT Fl_Window : public Fl_Group {
Fl_Color cursor_fg, cursor_bg;
void size_range_();
void _Fl_Window(); // constructor innards
void fullscreen_x(); // platform-specific part of sending a window to full screen
void fullscreen_off_x(int X, int Y, int W, int H);// platform-specific part of leaving full screen
// unimplemented copy ctor and assignment operator
Fl_Window(const Fl_Window&);
@ -375,14 +381,26 @@ public:
/**
Makes the window completely fill the screen, without any window
manager border visible. You must use fullscreen_off() to undo
this. This may not work with all window managers.
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.
*/
void fullscreen();
/**
Turns off any side effects of fullscreen()
*/
void fullscreen_off();
/**
Turns off any side effects of fullscreen() and does
resize(x,y,w,h).
*/
void fullscreen_off(int,int,int,int);
/**
Returns non zero if FULLSCREEN flag is set, 0 otherwise.
*/
unsigned int fullscreen_active() const { return flags() & FULLSCREEN; }
/**
Iconifies the window. If you call this when shown() is false
it will show() it as an icon. If the window is already

View File

@ -67,6 +67,7 @@ const char * const fl_eventnames[] =
"FL_DND_LEAVE",
"FL_DND_RELEASE",
"FL_SCREEN_CONFIGURATION_CHANGED",
"FL_FULLSCREEN"
};
/**

1
FL/x.H
View File

@ -160,6 +160,7 @@ public:
void flush() {w->flush();}
static void x(Fl_Window* wi, int X) {wi->x(X);}
static void y(Fl_Window* wi, int Y) {wi->y(Y);}
static int ewmh_supported();
};
extern FL_EXPORT char fl_override_redirect; // hack into Fl_X::make_xid()

View File

@ -27,7 +27,7 @@ The FLTK version number is stored in a number of compile-time constants:
\section enumerations_events Events
Events are identified by an \p Fl_Event enumeration value. The
Events are identified by an \ref Fl_Event enumeration value. The
following events are currently defined:
\li FL_NO_EVENT - No event (or an event fltk does not
@ -57,6 +57,8 @@ following events are currently defined:
\li FL_DND_LEAVE - The mouse pointer left a widget still dragging
data.
\li FL_DND_RELEASE - Dragged data is about to be dropped.
\li FL_SCREEN_CONFIGURATION_CHANGED - The screen configuration (number, positions) was changed.
\li FL_FULLSCREEN - The fullscreen state of the window has changed.
\section enumerations_when Callback "When" Conditions

View File

@ -300,6 +300,20 @@ The user has released the mouse button dropping data into
the widget. If the widget returns 1, it will receive the data in
the immediately following \p FL_PASTE event.
\section events_fl_misc Other events
\subsection events_fl_screen_config FL_SCREEN_CONFIGURATION_CHANGED
Sent whenever the screen configuration changes (a screen is added/removed,
a screen resolution is changed, screens are moved).
Use Fl::add_handler() to be notified of this event.
\subsection events_fl_fullscreen FL_FULLSCREEN
The application window has been changed from normal to fullscreen, or
from fullscreen to normal. If you are using a X window manager which
supports Extended Window Manager Hints, this event will not be
delivered until the change has actually happened.
\section events_event_xxx Fl::event_*() methods

View File

@ -781,6 +781,8 @@ static handler_link *handlers = 0;
- \ref FL_SCREEN_CONFIGURATION_CHANGED events.
Under X11, this event requires the libXrandr.so shared library to be
loadable at run-time and the X server to implement the RandR extension.
- \ref FL_FULLSCREEN events sent to a window that enters of leaves
fullscreen mode.
- System events that FLTK does not recognize. See fl_xevent.
- \e Some other events when the widget FLTK selected returns
zero from its handle() method. Exactly which ones may change

View File

@ -50,6 +50,12 @@ void Fl_Window::_Fl_Window() {
resizable(0);
size_range_set = 0;
minw = maxw = minh = maxh = 0;
#if FLTK_ABI_VERSION >= 10302
no_fullscreen_x = 0;
no_fullscreen_y = 0;
no_fullscreen_w = w();
no_fullscreen_h = h();
#endif
callback((Fl_Callback*)default_callback);
}

View File

@ -31,6 +31,13 @@
#include <config.h>
#if FLTK_ABI_VERSION < 10302
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;
#endif
void Fl_Window::border(int b) {
if (b) {
if (border()) return;
@ -51,39 +58,44 @@ void Fl_Window::border(int b) {
#endif
}
/* Note: The previous implementation toggled border(). With this new
implementation this is not necessary. Additionally, if we do that,
the application may lose focus when switching out of fullscreen
mode with some window managers. Besides, the API does not say that
the FLTK border state should be toggled; it only says that the
borders should not be *visible*.
*/
void Fl_Window::fullscreen() {
#ifndef WIN32
//this would clobber the fake wm, since it relies on the border flags to
//determine its thickness
border(0);
#endif
#if defined(__APPLE__) || defined(WIN32) || defined(USE_X11)
int sx, sy, sw, sh;
Fl::screen_xywh(sx, sy, sw, sh, x(), y(), w(), h());
// if we are on the main screen, we will leave the system menu bar unobstructed
if (Fl::x()>=sx && Fl::y()>=sy && Fl::x()+Fl::w()<=sx+sw && Fl::y()+Fl::h()<=sy+sh) {
sx = Fl::x(); sy = Fl::y();
sw = Fl::w(); sh = Fl::h();
no_fullscreen_x = x();
no_fullscreen_y = y();
no_fullscreen_w = w();
no_fullscreen_h = h();
if (shown() && !(flags() & Fl_Widget::FULLSCREEN)) {
fullscreen_x();
} else {
set_flag(FULLSCREEN);
}
if (x()==sx) x(sx+1); // make sure that we actually execute the resize
#if defined(USE_X11)
resize(0, 0, w(), h()); // work around some quirks in X11
#endif
resize(sx, sy, sw, sh);
#else
if (!x()) x(1); // make sure that we actually execute the resize
resize(0,0,Fl::w(),Fl::h());
#endif
}
void Fl_Window::fullscreen_off(int X,int Y,int W,int H) {
// this order produces less blinking on IRIX:
resize(X,Y,W,H);
#ifndef WIN32
border(1);
#endif
if (shown() && (flags() & Fl_Widget::FULLSCREEN)) {
fullscreen_off_x(X, Y, W, H);
} else {
clear_flag(FULLSCREEN);
}
no_fullscreen_x = no_fullscreen_y = no_fullscreen_w = no_fullscreen_h = 0;
}
void Fl_Window::fullscreen_off() {
if (!no_fullscreen_x && !no_fullscreen_y) {
// Window was initially created fullscreen - default to current monitor
no_fullscreen_x = x();
no_fullscreen_y = y();
}
fullscreen_off(no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h);
}
//
// End of "$Id$".
//

View File

@ -931,6 +931,10 @@ void fl_open_callback(void (*cb)(const char *)) {
fl_lock_function();
FLWindow *nsw = (FLWindow*)[notif object];
Fl_Window *window = [nsw getFl_Window];
/* Fullscreen windows obscure all other windows so we need to return
to a "normal" level when the user switches to another window */
if (window->fullscreen_active())
[nsw setLevel:NSNormalWindowLevel];
Fl::handle( FL_UNFOCUS, window);
fl_unlock_function();
}
@ -939,6 +943,9 @@ void fl_open_callback(void (*cb)(const char *)) {
fl_lock_function();
FLWindow *nsw = (FLWindow*)[notif object];
Fl_Window *w = [nsw getFl_Window];
/* Restore previous fullscreen level */
if (w->fullscreen_active())
[nsw setLevel:NSStatusWindowLevel];
if ( w->border() || (!w->modal() && !w->tooltip_window()) ) Fl::handle( FL_FOCUS, w);
fl_unlock_function();
}
@ -1914,6 +1921,22 @@ static void q_set_window_title(NSWindow *nsw, const char * name, const char *mi
@end
void Fl_Window::fullscreen_x() {
_set_fullscreen();
/* On OS X < 10.6, it is necessary to recreate the window. This is done
with hide+show. */
hide();
show();
Fl::handle(FL_FULLSCREEN, this);
}
void Fl_Window::fullscreen_off_x(int X, int Y, int W, int H) {
_clear_fullscreen();
hide();
resize(X, Y, W, H);
show();
Fl::handle(FL_FULLSCREEN, this);
}
/*
* go ahead, create that (sub)window
@ -2030,6 +2053,13 @@ void Fl_X::make(Fl_Window* w)
x->gc = 0;
NSRect crect;
if (w->flags() & Fl_Widget::FULLSCREEN) {
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);
winstyle = NSBorderlessWindowMask;
winlevel = NSStatusWindowLevel;
}
crect.origin.x = w->x();
crect.origin.y = main_screen_height - (w->y() + w->h());
crect.size.width=w->w();

View File

@ -42,6 +42,15 @@ extern void *fl_capture;
#endif
void Fl::grab(Fl_Window* win) {
#if USE_X11
Fl_Window *fullscreen_win = NULL;
for (Fl_Window *W = Fl::first_window(); W; W = Fl::next_window(W)) {
if (W->fullscreen_active()) {
fullscreen_win = W;
break;
}
}
#endif
if (win) {
if (!grab_) {
#ifdef WIN32
@ -51,8 +60,9 @@ void Fl::grab(Fl_Window* win) {
fl_capture = Fl_X::i(first_window())->xid;
Fl_X::i(first_window())->set_key_window();
#else
Window xid = fullscreen_win ? fl_xid(fullscreen_win) : fl_xid(first_window());
XGrabPointer(fl_display,
fl_xid(first_window()),
xid,
1,
ButtonPressMask|ButtonReleaseMask|
ButtonMotionMask|PointerMotionMask,
@ -62,7 +72,7 @@ void Fl::grab(Fl_Window* win) {
0,
fl_event_time);
XGrabKeyboard(fl_display,
fl_xid(first_window()),
xid,
1,
GrabModeAsync,
GrabModeAsync,
@ -78,7 +88,10 @@ void Fl::grab(Fl_Window* win) {
#elif defined(__APPLE__)
fl_capture = 0;
#else
// We must keep the grab in the non-EWMH fullscreen case
if (!fullscreen_win || Fl_X::ewmh_supported()) {
XUngrabKeyboard(fl_display, fl_event_time);
}
XUngrabPointer(fl_display, fl_event_time);
// this flush is done in case the picked menu item goes into
// an infinite loop, so we don't leave the X server locked up:

View File

@ -1315,6 +1315,11 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
X+=xoff;
Y+=yoff;
if (w->flags() & Fl_Widget::FULLSCREEN) {
X = Y = 0;
bx = by = bt = 0;
}
return ret;
}
@ -1365,6 +1370,58 @@ 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) {
int sx, sy, sw, sh;
Fl::screen_xywh(sx, sy, sw, sh, X, Y, W, H);
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);
}
void Fl_Window::fullscreen_x() {
_set_fullscreen();
make_fullscreen(this, fl_xid(this), x(), y(), w(), h());
Fl::handle(FL_FULLSCREEN, this);
}
void Fl_Window::fullscreen_off_x(int X, int Y, int W, int H) {
_clear_fullscreen();
DWORD style = GetWindowLong(fl_xid(this), GWL_STYLE);
// Remove the xid temporarily so that Fl_X::fake_X_wm() behaves like it
// does in Fl_X::make().
HWND xid = fl_xid(this);
Fl_X::i(this)->xid = NULL;
int wx, wy, bt, bx, by;
switch (Fl_X::fake_X_wm(this, wx, wy, bt, bx, by)) {
case 0:
break;
case 1:
style |= WS_CAPTION;
break;
case 2:
if (border()) {
style |= WS_THICKFRAME | WS_CAPTION;
}
break;
}
Fl_X::i(this)->xid = xid;
// Adjust for decorations (but not if that puts the decorations
// outside the screen)
if ((X != x()) || (Y != y())) {
X -= bx;
Y -= by+bt;
}
W += bx*2;
H += by*2+bt;
SetWindowLong(fl_xid(this), GWL_STYLE, style);
SetWindowPos(fl_xid(this), 0, X, Y, W, H,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
Fl::handle(FL_FULLSCREEN, this);
}
////////////////////////////////////////////////////////////////
/*
@ -1494,18 +1551,26 @@ Fl_X* Fl_X::make(Fl_Window* w) {
int xwm = xp , ywm = yp , bt, bx, by;
switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) {
// No border (used for menus)
case 0: style |= WS_POPUP;
styleEx |= WS_EX_TOOLWINDOW;
case 0:
style |= WS_POPUP;
styleEx |= WS_EX_TOOLWINDOW;
break;
// Thin border and title bar
case 1: style |= WS_DLGFRAME | WS_CAPTION; break;
case 1:
style |= WS_DLGFRAME | WS_CAPTION;
if (!w->modal())
style |= WS_SYSMENU | WS_MINIMIZEBOX;
break;
// Thick, resizable border and title bar, with maximize button
case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break;
case 2:
style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION;
if (!w->modal())
style |= WS_MINIMIZEBOX;
break;
}
if (by+bt) {
if (!w->modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX;
wp += 2*bx;
hp += 2*by+bt;
}
@ -1561,6 +1626,18 @@ Fl_X* Fl_X::make(Fl_Window* w) {
);
if (lab) free(lab);
if (w->flags() & Fl_Widget::FULLSCREEN) {
/* We need to make sure that the fullscreen is created on the
default monitor, ie the desktop where the shortcut is located
etc. This requires that CreateWindow is called with CW_USEDEFAULT
for x and y. We can then use GetWindowRect to determine which
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->next = Fl_X::first;
Fl_X::first = x;
@ -1576,7 +1653,7 @@ Fl_X* Fl_X::make(Fl_Window* w) {
// If we've captured the mouse, we dont want to activate any
// other windows from the code, or we lose the capture.
ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE :
(Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
(Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
// Register all windows for potential drag'n'drop operations
fl_OleInitialize();

View File

@ -325,6 +325,9 @@ Atom fl_XaUtf8String;
Atom fl_XaTextUriList;
Atom fl_NET_WM_NAME; // utf8 aware window label
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;
/*
X defines 32-bit-entities to have a format value of max. 32,
@ -623,6 +626,9 @@ void fl_open_display(Display* d) {
fl_XaTextUriList = XInternAtom(d, "text/uri-list", 0);
fl_NET_WM_NAME = XInternAtom(d, "_NET_WM_NAME", 0);
fl_NET_WM_ICON_NAME = XInternAtom(d, "_NET_WM_ICON_NAME", 0);
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);
if (sizeof(Atom) < 4)
atom_bits = sizeof(Atom) * 8;
@ -784,6 +790,31 @@ void fl_sendClientMessage(Window window, Atom message,
XSendEvent(fl_display, window, 0, 0, &e);
}
/*
Get window property value (32 bit format)
Returns zero on success, -1 on error
*/
static int get_xwinprop(Window wnd, Atom prop, long max_length,
unsigned long *nitems, unsigned long **data) {
Atom actual;
int format;
unsigned long bytes_after;
if (Success != XGetWindowProperty(fl_display, wnd, prop, 0, max_length,
False, AnyPropertyType, &actual, &format,
nitems, &bytes_after, (unsigned char**)data)) {
return -1;
}
if (actual == None || format != 32) {
return -1;
}
return 0;
}
////////////////////////////////////////////////////////////////
// Code for copying to clipboard and DnD out of the program:
@ -1480,6 +1511,31 @@ int fl_handle(const XEvent& thisevent)
in_a_window = true;
break;
case PropertyNotify:
if (xevent.xproperty.atom == fl_NET_WM_STATE) {
int fullscreen_state = 0;
if (xevent.xproperty.state != PropertyDelete) {
unsigned long nitems;
unsigned long *words = 0;
if (0 == get_xwinprop(xid, fl_NET_WM_STATE, 64, &nitems, &words) ) {
for (unsigned long item = 0; item < nitems; item++) {
if (words[item] == fl_NET_WM_STATE_FULLSCREEN) {
fullscreen_state = 1;
}
}
}
}
if (window->fullscreen_active() && !fullscreen_state) {
window->_clear_fullscreen();
event = FL_FULLSCREEN;
}
if (!window->fullscreen_active() && fullscreen_state) {
window->_set_fullscreen();
event = FL_FULLSCREEN;
}
}
break;
case MotionNotify:
set_event_xy();
# if CONSOLIDATE_MOTION
@ -1619,6 +1675,75 @@ void Fl_Window::resize(int X,int Y,int W,int H) {
////////////////////////////////////////////////////////////////
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#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) {
XEvent e;
e.xany.type = ClientMessage;
e.xany.window = wnd;
e.xclient.message_type = fl_NET_WM_STATE;
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;
XSendEvent(fl_display, RootWindow(fl_display, fl_screen),
0, SubstructureNotifyMask | SubstructureRedirectMask,
&e);
}
int Fl_X::ewmh_supported() {
static int result = -1;
if (result == -1) {
result = 0;
unsigned long nitems;
unsigned long *words = 0;
if (0 == get_xwinprop(XRootWindow(fl_display, fl_screen), fl_NET_SUPPORTING_WM_CHECK, 64,
&nitems, &words) && nitems == 1) {
Window child = words[0];
if (0 == get_xwinprop(child, fl_NET_SUPPORTING_WM_CHECK, 64,
&nitems, &words) && nitems == 1) {
result = (child == words[0]);
}
}
}
return result;
}
/* Change an existing window to fullscreen */
void Fl_Window::fullscreen_x() {
if (Fl_X::ewmh_supported()) {
send_wm_state_event(fl_xid(this), 1, fl_NET_WM_STATE_FULLSCREEN);
} else {
_set_fullscreen();
hide();
show();
/* We want to grab the window, not a widget, so we cannot use Fl::grab */
XGrabKeyboard(fl_display, fl_xid(this), 1, GrabModeAsync, GrabModeAsync, fl_event_time);
Fl::handle(FL_FULLSCREEN, this);
}
}
void Fl_Window::fullscreen_off_x(int X, int Y, int W, int H) {
if (Fl_X::ewmh_supported()) {
send_wm_state_event(fl_xid(this), 0, fl_NET_WM_STATE_FULLSCREEN);
} else {
_clear_fullscreen();
/* The grab will be lost when the window is destroyed */
hide();
resize(X,Y,W,H);
show();
Fl::handle(FL_FULLSCREEN, this);
}
}
////////////////////////////////////////////////////////////////
// A subclass of Fl_Window may call this to associate an X window it
// creates with the Fl_Window:
@ -1654,6 +1779,7 @@ ExposureMask|StructureNotifyMask
|KeyPressMask|KeyReleaseMask|KeymapStateMask|FocusChangeMask
|ButtonPressMask|ButtonReleaseMask
|EnterWindowMask|LeaveWindowMask
|PropertyChangeMask
|PointerMotionMask;
void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
@ -1725,6 +1851,16 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
attr.save_under = 1; mask |= CWSaveUnder;
if (!win->border()) {attr.override_redirect = 1; mask |= CWOverrideRedirect;}
}
// For the non-EWMH fullscreen case, we cannot use the code above,
// since we do not want save_under, do not want to turn off the
// border, and cannot grab without an existing window. Besides,
// there is no clear_override().
if (win->flags() & Fl_Widget::FULLSCREEN && !Fl_X::ewmh_supported()) {
attr.override_redirect = 1;
mask |= CWOverrideRedirect;
Fl::screen_xywh(X, Y, W, H, X, Y, W, H);
}
if (fl_background_pixel >= 0) {
attr.background_pixel = fl_background_pixel;
fl_background_pixel = -1;
@ -1785,6 +1921,12 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
PropModeAppend, (unsigned char*) &net_wm_state_skip_taskbar, 1);
}
// If asked for, create fullscreen
if (win->flags() & Fl_Widget::FULLSCREEN && Fl_X::ewmh_supported()) {
XChangeProperty (fl_display, xp->xid, fl_NET_WM_STATE, XA_ATOM, 32,
PropModeAppend, (unsigned char*) &fl_NET_WM_STATE_FULLSCREEN, 1);
}
// Make it receptive to DnD:
long version = 4;
XChangeProperty(fl_display, xp->xid, fl_XdndAware,
@ -1822,6 +1964,12 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
Fl::e_number = old_event;
win->redraw();
}
// non-EWMH fullscreen case, need grab
if (win->flags() & Fl_Widget::FULLSCREEN && !Fl_X::ewmh_supported()) {
XGrabKeyboard(fl_display, xp->xid, 1, GrabModeAsync, GrabModeAsync, fl_event_time);
}
}
////////////////////////////////////////////////////////////////

View File

@ -21,6 +21,7 @@
#include <FL/x.H>
#include <config.h>
#define MAX_SCREENS 16
// Number of screens returned by multi monitor aware API; -1 before init
static int num_screens = -1;
@ -142,47 +143,61 @@ static void screen_init() {
num_screens = count;
}
#elif HAVE_XINERAMA
# include <X11/extensions/Xinerama.h>
#else
// Screen data...
static XineramaScreenInfo *screens;
static float dpi[16][2];
#if HAVE_XINERAMA
# include <X11/extensions/Xinerama.h>
#endif
typedef struct {
short x_org;
short y_org;
short width;
short height;
} FLScreenInfo;
static FLScreenInfo screens[MAX_SCREENS];
static float dpi[MAX_SCREENS][2];
static void screen_init() {
if (!fl_display) fl_open_display();
// FIXME: Rewrite using RandR instead
#if HAVE_XINERAMA
if (XineramaIsActive(fl_display)) {
screens = XineramaQueryScreens(fl_display, &num_screens);
int i;
// Xlib and Xinerama may disagree on the screen count. Sigh...
// Use the minimum of the reported counts.
// Use the previous screen's info for non-existent ones.
int sc = ScreenCount(fl_display); // Xlib screen count
for (i=0; i<num_screens; i++) {
int mm = (i < sc) ? DisplayWidthMM(fl_display, i) : 0;
dpi[i][0] = mm ? screens[i].width*25.4f/mm : (i > 0) ? dpi[i-1][0] : 0.0f;
mm = (i < sc) ? DisplayHeightMM(fl_display, i) : 0;
dpi[i][1] = mm ? screens[i].height*25.4f/mm : (i > 0) ? dpi[i-1][1] : 0.0f;
XineramaScreenInfo *xsi = XineramaQueryScreens(fl_display, &num_screens);
if (num_screens > MAX_SCREENS) num_screens = MAX_SCREENS;
/* There's no way to use different DPI for different Xinerama screens. */
for (int i=0; i<num_screens; i++) {
screens[i].x_org = xsi[i].x_org;
screens[i].y_org = xsi[i].y_org;
screens[i].width = xsi[i].width;
screens[i].height = xsi[i].height;
int mm = DisplayWidthMM(fl_display, fl_screen);
dpi[i][0] = mm ? screens[i].width*25.4f/mm : 0.0f;
mm = DisplayHeightMM(fl_display, fl_screen);
dpi[i][1] = mm ? screens[i].height*25.4f/mm : 0.0f;
}
if (xsi) XFree(xsi);
} else
#endif
{ // ! XineramaIsActive()
num_screens = ScreenCount(fl_display);
if (num_screens > MAX_SCREENS) num_screens = MAX_SCREENS;
for (int i=0; i<num_screens; i++) {
screens[i].x_org = 0;
screens[i].y_org = 0;
screens[i].width = DisplayWidth(fl_display, i);
screens[i].height = DisplayHeight(fl_display, i);
int mm = DisplayWidthMM(fl_display, i);
dpi[i][0] = mm ? DisplayWidth(fl_display, i)*25.4f/mm : 0.0f;
mm = DisplayHeightMM(fl_display, i);
dpi[i][1] = mm ? DisplayHeight(fl_display, i)*25.4f/mm : 0.0f;
}
} else { // ! XineramaIsActive()
num_screens = 1;
int mm = DisplayWidthMM(fl_display, fl_screen);
dpi[0][0] = mm ? Fl::w()*25.4f/mm : 0.0f;
mm = DisplayHeightMM(fl_display, fl_screen);
dpi[0][1] = mm ? Fl::h()*25.4f/mm : dpi[0][0];
}
}
#else
static float dpi[2];
static void screen_init() {
num_screens = 1;
if (!fl_display) fl_open_display();
int mm = DisplayWidthMM(fl_display, fl_screen);
dpi[0] = mm ? Fl::w()*25.4f/mm : 0.0f;
mm = DisplayHeightMM(fl_display, fl_screen);
dpi[1] = mm ? Fl::h()*25.4f/mm : dpi[0];
}
#endif // WIN32
#ifndef FL_DOXYGEN
@ -297,20 +312,11 @@ void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int n) {
W = screens[n].width;
H = screens[n].height;
#else
#if HAVE_XINERAMA
if (num_screens > 0 && screens) {
if (num_screens > 0) {
X = screens[n].x_org;
Y = screens[n].y_org;
W = screens[n].width;
H = screens[n].height;
} else
#endif // HAVE_XINERAMA
{
/* Fallback if something is broken (or no Xinerama)... */
X = 0;
Y = 0;
W = DisplayWidth(fl_display, fl_screen);
H = DisplayHeight(fl_display, fl_screen);
}
#endif // WIN32
}
@ -372,16 +378,11 @@ void Fl::screen_dpi(float &h, float &v, int n)
h = dpi_h[n];
v = dpi_v[n];
}
#elif HAVE_XINERAMA
#else
if (n >= 0 && n < num_screens) {
h = dpi[n][0];
v = dpi[n][1];
}
#else
if (n >= 0 && n < num_screens) {
h = dpi[0];
v = dpi[1];
}
#endif // WIN32
}

View File

@ -54,8 +54,11 @@
#include <FL/Fl.H>
#include <FL/Fl_Single_Window.H>
#include <FL/Fl_Hor_Slider.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Menu_Button.H>
#include <FL/Fl_Toggle_Light_Button.H>
#include <FL/math.h>
#include <FL/fl_ask.H>
#include <stdio.h>
#if HAVE_GL
@ -118,6 +121,27 @@ void shape_window::draw() {
#endif
class fullscreen_window : public Fl_Single_Window {
public:
fullscreen_window(int W, int H, const char *t=0);
int handle (int e);
Fl_Toggle_Light_Button *b3;
};
fullscreen_window::fullscreen_window(int W, int H, const char *t) : Fl_Single_Window(W, H, t) {
}
int fullscreen_window::handle(int e) {
if (e == FL_FULLSCREEN) {
printf("Received FL_FULLSCREEN event\n");
b3->value(fullscreen_active());
}
if (Fl_Single_Window::handle(e)) return 1;
return 0;
}
void sides_cb(Fl_Widget *o, void *p) {
shape_window *sw = (shape_window *)p;
sw->sides = int(((Fl_Slider *)o)->value());
@ -155,13 +179,14 @@ void fullscreen_cb(Fl_Widget *o, void *p) {
py = w->y();
pw = w->w();
ph = w->h();
#ifndef WIN32//necessary because fullscreen removes border
border_button->value(0);
border_button->do_callback();
#endif
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(px,py,pw,ph);
w->fullscreen_off();
}
}
@ -171,7 +196,7 @@ void exit_cb(Fl_Widget *, void *) {
exit(0);
}
#define NUMB 5
#define NUMB 6
int twowindow = 0;
int initfull = 0;
@ -187,9 +212,10 @@ int main(int argc, char **argv) {
if (Fl::args(argc,argv,i,arg) < argc)
Fl::fatal("Options are:\n -2 = 2 windows\n -f = startup fullscreen\n%s",Fl::help);
Fl_Single_Window window(300,300+30*NUMB); window.end();
fullscreen_window window(300,300+30*NUMB); window.end();
shape_window sw(10,10,window.w()-20,window.h()-30*NUMB-20);
#if HAVE_GL
sw.mode(FL_RGB);
#endif
@ -222,21 +248,24 @@ int main(int argc, char **argv) {
b1.callback(double_cb,&sw);
y+=30;
Fl_Input i1(50,y,window.w()-60,30, "Input");
y+=30;
Fl_Toggle_Light_Button b2(50,y,window.w()-60,30,"Border");
b2.callback(border_cb,w);
b2.set();
border_button = &b2;
y+=30;
Fl_Toggle_Light_Button b3(50,y,window.w()-60,30,"FullScreen");
b3.callback(fullscreen_cb,w);
window.b3 = new Fl_Toggle_Light_Button(50,y,window.w()-60,30,"FullScreen");
window.b3->callback(fullscreen_cb,w);
y+=30;
Fl_Button eb(50,y,window.w()-60,30,"Exit");
eb.callback(exit_cb);
y+=30;
if (initfull) {b3.set(); b3.do_callback();}
if (initfull) {window.b3->set(); window.b3->do_callback();}
window.end();
window.show(argc,argv);