mirror of
https://github.com/gnustep/libs-back.git
synced 2025-04-22 15:31:14 +00:00
Revise detection of window miniaturization and deminiaturization based
on the ICCCM WM_STATE property and use _NET_WM_STATE only to avoid generating bogus miniaturize events when using an emwh compliant window manager. This makes the code more portable and allows generating reliable window deminiaturize events. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@29283 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
e210cbd8b7
commit
d7553ab584
5 changed files with 141 additions and 79 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2010-01-14 Wolfgang Lux <wolfgang.lux@gmail.com>
|
||||
|
||||
* Source/x11/XGServerEvent.m (-processEvent:):
|
||||
* Source/x11/XGServerWindow.m (-_wm_state:, -_ewmh_state, -_checkStyle,
|
||||
-_rootWindowForScreen:, -window::::, -nativeWindow:::::): Revise
|
||||
detection of window miniaturization and deminiaturization based on
|
||||
ICCCM WM_STATE property.
|
||||
* Source/x11/XGServerWindow.m (-miniwindow:): Add special case for
|
||||
metacity window manager to avoid miniaturizing shaded windows.
|
||||
|
||||
2010-01-14 05:41-EST Gregory John Casamento <greg.casamento@gmail.com>
|
||||
|
||||
* Headers/win32/WIN32Server.h: Added decodeWM_MOUSEACTIVATE:..
|
||||
|
|
|
@ -103,6 +103,7 @@ struct XGGeneric {
|
|||
Atom protocols_atom;
|
||||
Atom delete_win_atom;
|
||||
Atom take_focus_atom;
|
||||
Atom wm_state_atom;
|
||||
Atom net_wm_ping_atom;
|
||||
Atom miniaturize_atom;
|
||||
Atom win_decor_atom;
|
||||
|
|
|
@ -90,6 +90,7 @@ typedef struct _gswindow_device_t {
|
|||
unsigned int border; /* Border size */
|
||||
int map_state; /* X map state */
|
||||
int visibility; /* X visibility */
|
||||
int wm_state; /* X WM state */
|
||||
NSBackingStoreType type; /* Backing type */
|
||||
NSRect xframe; /* Window frame */
|
||||
|
||||
|
@ -130,7 +131,8 @@ typedef struct _gswindow_device_t {
|
|||
/* This needs to go in GSDisplayServer */
|
||||
- (void) _DPSsetcursor: (Cursor)c : (BOOL)set;
|
||||
|
||||
- (BOOL) _ewmh_isMinimized: (Window) win;
|
||||
- (int) _wm_state: (Window) win;
|
||||
- (BOOL) _ewmh_isHidden: (Window) win;
|
||||
@end
|
||||
|
||||
extern Pixmap
|
||||
|
|
|
@ -68,8 +68,6 @@
|
|||
|
||||
#define cWin ((gswindow_device_t*)generic.cachedWindow)
|
||||
|
||||
extern Atom WM_STATE;
|
||||
|
||||
// NumLock's mask (it depends on the keyboard mapping)
|
||||
static unsigned int _num_lock_mask;
|
||||
// Modifier state
|
||||
|
@ -595,6 +593,7 @@ posixFileDescriptor: (NSPosixFileDescriptor*)fileDescriptor
|
|||
else if ((Atom)xEvent.xclient.data.l[0]
|
||||
== generic.miniaturize_atom)
|
||||
{
|
||||
NSDebugLLog(@"Miniaturize", @"%d miniaturized", cWin->number);
|
||||
eventLocation = NSMakePoint(0,0);
|
||||
e = [NSEvent otherEventWithType: NSAppKitDefined
|
||||
location: eventLocation
|
||||
|
@ -1388,61 +1387,85 @@ posixFileDescriptor: (NSPosixFileDescriptor*)fileDescriptor
|
|||
NSDebugLLog(@"NSEvent", @"%d PropertyNotify - '%s'\n",
|
||||
xEvent.xproperty.window,
|
||||
XGetAtomName(dpy, xEvent.xproperty.atom));
|
||||
{
|
||||
/* Note: Don't rely on _NET_STATE_WM_HIDDEN with Window Maker,
|
||||
* since it is impossible to distinguish miniaturized and hidden
|
||||
* windows by their window properties. Fortunately, Window Maker
|
||||
* will send us client message when a window is miniaturized.
|
||||
*/
|
||||
if ((generic.wm & XGWM_WINDOWMAKER) == 0
|
||||
&& xEvent.xproperty.atom == generic.netstates.net_wm_state_atom
|
||||
&& xEvent.xproperty.state == PropertyNewValue)
|
||||
{
|
||||
if (cWin == 0 || xEvent.xproperty.window != cWin->ident)
|
||||
{
|
||||
generic.cachedWindow
|
||||
= [XGServer _windowForXWindow: xEvent.xproperty.window];
|
||||
}
|
||||
if (cWin != 0)
|
||||
{
|
||||
/*
|
||||
* FIXME: we really should detect when the state changes from
|
||||
* unminimized to minimized, or vice versa
|
||||
*/
|
||||
if ([self _ewmh_isMinimized: xEvent.xproperty.window])
|
||||
{
|
||||
// Same event as when we get ClientMessage with the atom
|
||||
// equal to generic.miniaturize_atom
|
||||
eventLocation = NSMakePoint(0,0);
|
||||
e = [NSEvent otherEventWithType: NSAppKitDefined
|
||||
location: eventLocation
|
||||
modifierFlags: 0
|
||||
timestamp: xEvent.xproperty.time / 1000
|
||||
windowNumber: cWin->number
|
||||
context: gcontext
|
||||
subtype: GSAppKitWindowMiniaturize
|
||||
data1: 0
|
||||
data2: 0];
|
||||
}
|
||||
else if ([GSWindowWithNumber(cWin->number) isMiniaturized])
|
||||
{
|
||||
/* A miniaturised window is now visible ... send event
|
||||
* to let the gui know it deminiaturised.
|
||||
*/
|
||||
eventLocation = NSMakePoint(0,0);
|
||||
e = [NSEvent otherEventWithType: NSAppKitDefined
|
||||
location: eventLocation
|
||||
modifierFlags: 0
|
||||
timestamp: xEvent.xproperty.time / 1000
|
||||
windowNumber: cWin->number
|
||||
context: gcontext
|
||||
subtype: GSAppKitWindowDeminiaturize
|
||||
data1: 0
|
||||
data2: 0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xEvent.xproperty.atom == generic.wm_state_atom)
|
||||
{
|
||||
if (cWin == 0 || xEvent.xproperty.window != cWin->ident)
|
||||
{
|
||||
generic.cachedWindow
|
||||
= [XGServer _windowForXWindow: xEvent.xproperty.window];
|
||||
}
|
||||
if (cWin != 0)
|
||||
{
|
||||
int new_state;
|
||||
|
||||
/* Get the new window state */
|
||||
if (xEvent.xproperty.state == PropertyNewValue)
|
||||
new_state = [self _wm_state: xEvent.xproperty.window];
|
||||
else
|
||||
new_state = WithdrawnState;
|
||||
|
||||
switch (new_state)
|
||||
{
|
||||
case IconicState:
|
||||
/* Post miniaturize event upon transition from NormalState
|
||||
to IconicState. If the window manager supports the ewmh
|
||||
specification, also check that the _NET_WM_STATE
|
||||
property includes _NET_WM_STATE_HIDDEN. */
|
||||
/* Note: Don't rely on WM_STATE (nor on _NET_WM_STATE) with
|
||||
Window Maker, since it is impossible to distinguish
|
||||
miniaturized windows from hidden windows by their window
|
||||
properties. Fortunately, Window Maker sends us a client
|
||||
message when a window is miniaturized. */
|
||||
if ((generic.wm & XGWM_WINDOWMAKER) == 0 &&
|
||||
cWin->wm_state == NormalState &&
|
||||
((generic.wm & XGWM_EWMH) == 0 ||
|
||||
[self _ewmh_isHidden: xEvent.xproperty.window] == YES))
|
||||
{
|
||||
/* Same event as when we get ClientMessage with the
|
||||
* atom equal to generic.miniaturize_atom
|
||||
*/
|
||||
NSDebugLLog(@"Miniaturize", @"%d miniaturized",
|
||||
cWin->number);
|
||||
eventLocation = NSMakePoint(0,0);
|
||||
e = [NSEvent otherEventWithType: NSAppKitDefined
|
||||
location: eventLocation
|
||||
modifierFlags: 0
|
||||
timestamp: xEvent.xproperty.time / 1000
|
||||
windowNumber: cWin->number
|
||||
context: gcontext
|
||||
subtype: GSAppKitWindowMiniaturize
|
||||
data1: 0
|
||||
data2: 0];
|
||||
}
|
||||
break;
|
||||
|
||||
case NormalState:
|
||||
/* Post deminiaturize event upon transition from IconicState
|
||||
to NormalState, but only if our window is actually
|
||||
miniaturized. */
|
||||
if (cWin->wm_state == IconicState &&
|
||||
[GSWindowWithNumber(cWin->number) isMiniaturized])
|
||||
{
|
||||
NSDebugLLog(@"Miniaturize", @"%d deminiaturized",
|
||||
cWin->number);
|
||||
eventLocation = NSMakePoint(0,0);
|
||||
e = [NSEvent otherEventWithType: NSAppKitDefined
|
||||
location: eventLocation
|
||||
modifierFlags: 0
|
||||
timestamp: xEvent.xproperty.time / 1000
|
||||
windowNumber: cWin->number
|
||||
context: gcontext
|
||||
subtype: GSAppKitWindowDeminiaturize
|
||||
data1: 0
|
||||
data2: 0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* save the new state */
|
||||
cWin->wm_state = new_state;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// a client successfully reparents a window
|
||||
|
|
|
@ -750,6 +750,7 @@ _get_next_prop_new_event(Display *display, XEvent *event, char *arg)
|
|||
|
||||
window->map_state = IsUnmapped;
|
||||
window->visibility = 2;
|
||||
window->wm_state = WithdrawnState;
|
||||
|
||||
// Create an X GC for the content view set it's colors
|
||||
values.foreground = window->xwn_attrs.background_pixel;
|
||||
|
@ -1266,6 +1267,7 @@ _get_next_prop_new_event(Display *display, XEvent *event, char *arg)
|
|||
window->number = -screen;
|
||||
window->map_state = IsViewable;
|
||||
window->visibility = -1;
|
||||
window->wm_state = NormalState;
|
||||
if (window->ident)
|
||||
XGetGeometry(dpy, window->ident, &window->root,
|
||||
&x, &y, &width, &height,
|
||||
|
@ -1416,6 +1418,7 @@ _get_next_prop_new_event(Display *display, XEvent *event, char *arg)
|
|||
generic.protocols_atom = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
||||
generic.take_focus_atom = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
|
||||
generic.delete_win_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
||||
generic.wm_state_atom = XInternAtom(dpy, "WM_STATE", False);
|
||||
generic.net_wm_ping_atom = XInternAtom(dpy, "_NET_WM_PING", False);
|
||||
generic.miniaturize_atom
|
||||
= XInternAtom(dpy, "_GNUSTEP_WM_MINIATURIZE_WINDOW", False);
|
||||
|
@ -1939,6 +1942,7 @@ _get_next_prop_new_event(Display *display, XEvent *event, char *arg)
|
|||
|
||||
window->map_state = IsUnmapped;
|
||||
window->visibility = -1;
|
||||
window->wm_state = WithdrawnState;
|
||||
|
||||
// Create an X GC for the content view set it's colors
|
||||
values.foreground = window->xwn_attrs.background_pixel;
|
||||
|
@ -1960,8 +1964,8 @@ _get_next_prop_new_event(Display *display, XEvent *event, char *arg)
|
|||
| EnterWindowMask
|
||||
| LeaveWindowMask
|
||||
| FocusChangeMask
|
||||
// enable property notifications under ewmh to detect window minimizing
|
||||
| (generic.wm & XGWM_EWMH ? PropertyChangeMask : 0)
|
||||
/* enable property notifications to detect window (de)miniaturization */
|
||||
| PropertyChangeMask
|
||||
// | ColormapChangeMask
|
||||
| KeymapStateMask
|
||||
| VisibilityChangeMask
|
||||
|
@ -2100,6 +2104,7 @@ _get_next_prop_new_event(Display *display, XEvent *event, char *arg)
|
|||
window->xwn_attrs.border_pixel = context->black;
|
||||
window->xwn_attrs.background_pixel = context->white;
|
||||
window->visibility = -1;
|
||||
window->wm_state = [self _wm_state: windowRef];
|
||||
|
||||
// Create an X GC for the content view set it's colors
|
||||
values.foreground = window->xwn_attrs.background_pixel;
|
||||
|
@ -2577,17 +2582,20 @@ NSLog(@"styleoffsets ... guessing offsets\n");
|
|||
XSync(dpy, False);
|
||||
while (XCheckWindowEvent(dpy, window->ident, 0xffffffff, &e) == True) ;
|
||||
|
||||
/*
|
||||
* When the application owns the mini window, we withdraw the window itself
|
||||
* during miniaturization and put up the mini window instead. However, this
|
||||
* does not work for WindowMaker, which unmaps the mini window, too, when
|
||||
* the actual window is withdrawn. Fortunately, miniaturizing the actual
|
||||
* window does already the right thing on WindowMaker.
|
||||
*/
|
||||
if (!generic.flags.appOwnsMiniwindow || (generic.wm & XGWM_WINDOWMAKER))
|
||||
XIconifyWindow(dpy, window->ident, window->screen);
|
||||
else
|
||||
/* When the application owns the mini window, we withdraw the window itself
|
||||
during miniaturization and put up the mini window instead. However, this
|
||||
does not work for WindowMaker, which unmaps the mini window, too, when
|
||||
the actual window is withdrawn. Fortunately, miniaturizing the actual
|
||||
window does already the right thing on WindowMaker. */
|
||||
/* Note: The wm_state != IconicState check is there to avoid iconifying a
|
||||
window when -miniwindow: is called as a consequence of processing a
|
||||
GSAppKitWindowMiniaturize event. This avoids iconifying shaded windows
|
||||
under metacity, which sets _NET_WM_STATE for shaded windows to both
|
||||
_NET_WM_STATE_SHADED and _NET_WM_STATE_HIDDEN. */
|
||||
if (generic.flags.appOwnsMiniwindow && !(generic.wm & XGWM_WINDOWMAKER))
|
||||
XWithdrawWindow(dpy, window->ident, window->screen);
|
||||
else if (window->wm_state != IconicState)
|
||||
XIconifyWindow(dpy, window->ident, window->screen);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4636,11 +4644,34 @@ _computeDepth(int class, int bpp)
|
|||
}
|
||||
|
||||
/*
|
||||
* Check whether the window is miniaturized according to the EWMH window state
|
||||
* property. We map the EWMH _NET_WM_STATE_HIDDEN state to GNUstep's
|
||||
* miniaturized state.
|
||||
* Check whether the window is miniaturized according to the ICCCM window
|
||||
* state property.
|
||||
*/
|
||||
- (BOOL) _ewmh_isMinimized: (Window)win
|
||||
- (int) _wm_state: (Window)win
|
||||
{
|
||||
long *data;
|
||||
long state;
|
||||
|
||||
data = (long *)PropGetCheckProperty(dpy, win, generic.wm_state_atom,
|
||||
generic.wm_state_atom, 32, -1, NULL);
|
||||
|
||||
if (data)
|
||||
{
|
||||
state = *data;
|
||||
XFree(data);
|
||||
}
|
||||
else
|
||||
state = WithdrawnState;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the EWMH window state includes the _NET_WM_STATE_HIDDEN
|
||||
* state. On EWMH, a window is iconified if it is iconic state and the
|
||||
* _NET_WM_STATE_HIDDEN is present.
|
||||
*/
|
||||
- (BOOL) _ewmh_isHidden: (Window)win
|
||||
{
|
||||
Atom *data;
|
||||
int count;
|
||||
|
@ -4656,11 +4687,6 @@ _computeDepth(int class, int bpp)
|
|||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (data[i] != 0)
|
||||
{
|
||||
NSDebugLLog(@"NSEvent", @"%d PropertyNotify detail - '%s'\n",
|
||||
win, XGetAtomName(dpy, data[i]));
|
||||
}
|
||||
if (data[i] == generic.netstates.net_wm_state_hidden_atom)
|
||||
{
|
||||
XFree(data);
|
||||
|
|
Loading…
Reference in a new issue