new requestAttention function

This commit is contained in:
Adam D. Ruppe 2016-03-12 10:02:02 -05:00
parent 4c1a38525b
commit fbfb579875
2 changed files with 157 additions and 93 deletions

View File

@ -807,6 +807,52 @@ class SimpleWindow : CapableOfHandlingNativeEvent {
_suppressDestruction = true; // so it doesn't try to close
}
/++
Requests attention from the user for this window.
The typical result of this function is to change the color
of the taskbar icon, though it may be tweaked on specific
platforms.
It is meant to unobtrusively tell the user that something
relevant to them happened in the background and they should
check the window when they get a chance. Upon receiving the
keyboard focus, the window will automatically return to its
natural state.
If the window already has the keyboard focus, this function
may do nothing, because the user is presumed to already be
giving the window attention.
Implementation_note:
`requestAttention` uses the _NET_WM_STATE_DEMANDS_ATTENTION
atom on X11 and the FlashWindow function on Windows.
+/
void requestAttention() {
if(focused)
return;
version(Windows) {
FLASHWINFO info;
info.cbSize = info.sizeof;
info.hwnd = impl.hwnd;
info.dwFlags = FLASHW_TRAY;
info.uCount = 1;
FlashWindowEx(&info);
} else version(X11) {
demandingAttention = true;
demandAttention(this, true);
} else static assert(0);
}
private bool focused; // FIXME:I might make a getter for this public later
version(X11) private bool demandingAttention;
/// This will be called when WM wants to close your window (i.e. user clicked "close" icon, for example).
/// You'll have to call `close()` manually if you set this delegate.
version(X11) void delegate () closeQuery;
@ -3683,6 +3729,7 @@ version(Windows) {
break;
case WM_SETFOCUS:
case WM_KILLFOCUS:
wind.focused = msg == WM_SETFOCUS;
if(wind.onFocusChange)
wind.onFocusChange(msg == WM_SETFOCUS);
break;
@ -5207,10 +5254,16 @@ version(X11) {
case EventType.FocusIn:
case EventType.FocusOut:
if(auto win = e.xfocus.window in SimpleWindow.nativeMapping) {
if (win.xic !is null) {
//{ import core.stdc.stdio : printf; printf("XIC focus change!\n"); }
if (e.type == EventType.FocusIn) XSetICFocus(win.xic); else XUnsetICFocus(win.xic);
}
if (win.xic !is null) {
//{ import core.stdc.stdio : printf; printf("XIC focus change!\n"); }
if (e.type == EventType.FocusIn) XSetICFocus(win.xic); else XUnsetICFocus(win.xic);
}
win.focused = e.type == EventType.FocusIn;
if(win.demandingAttention)
demandAttention(*win, false);
if(win.onFocusChange) {
XUnlockDisplay(display);
scope(exit) XLockDisplay(display);
@ -8710,3 +8763,86 @@ mixin template ExperimentalTextComponent() {
}
}
static if(UsingSimpledisplayX11) {
enum _NET_WM_STATE_ADD = 1;
enum _NET_WM_STATE_REMOVE = 0;
enum _NET_WM_STATE_TOGGLE = 2;
/// X-specific
void demandAttention(SimpleWindow window, bool needs = true) {
auto display = XDisplayConnection.get();
auto atom = GetAtom!"_NET_WM_STATE_DEMANDS_ATTENTION"(display);
//auto atom2 = GetAtom!"_NET_WM_STATE_SHADED"(display);
XClientMessageEvent xclient;
xclient.type = EventType.ClientMessage;
xclient.window = window.impl.window;
xclient.message_type = GetAtom!"_NET_WM_STATE"(display);
xclient.format = 32;
xclient.data.l[0] = needs ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
xclient.data.l[1] = atom;
//xclient.data.l[2] = atom2;
// [2] == a second property
// [3] == source. 0 == unknown, 1 == app, 2 == else
XSendEvent(
display,
RootWindow(display, DefaultScreen(display)),
false,
EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask,
cast(XEvent*) &xclient
);
/+
XChangeProperty(
display,
window.impl.window,
GetAtom!"_NET_WM_STATE"(display),
XA_ATOM,
32 /* bits */,
PropModeAppend,
&atom,
1);
+/
}
/// X-specific
TrueColorImage getWindowNetWmIcon(Window window) {
auto display = XDisplayConnection.get;
auto data = cast(arch_ulong[]) getX11PropertyData (window, GetAtom!"_NET_WM_ICON"(display), XA_CARDINAL);
if (data.length > 2) {
// these are an array of rgba images that we have to convert into pixmaps ourself
int width = cast(int) data[0];
int height = cast(int) data[1];
data = data[2 .. 2 + width * height];
auto bytes = cast(ubyte[]) data;
// this returns ARGB. Remember it is little-endian so
// we have BGRA
// our thing uses RGBA, which in little endian, is ABGR
for(int idx = 0; idx < bytes.length; idx += 4) {
auto r = bytes[idx + 2];
auto g = bytes[idx + 1];
auto b = bytes[idx + 0];
auto a = bytes[idx + 3];
bytes[idx + 0] = r;
bytes[idx + 1] = g;
bytes[idx + 2] = b;
bytes[idx + 3] = a;
}
return new TrueColorImage(width, height, bytes);
}
return null;
}
}

View File

@ -1,92 +1,20 @@
/// This module is a bunch of helper functions for dealing with X11
/// windows on top of simpledisplay.d
///
/// It is mostly about the atoms that communicate stuff to things like
/// window managers and taskbars.
///
/// The eventual goal is for this to be useful for writing those and for
/// writing plain applications.
/**
This module is obsolete. Its functionality has been merged
into simpledisplay.d. You can use it instead and abandon this.
Old stuff follows:
This module is a bunch of helper functions for dealing with X11
windows on top of simpledisplay.d
It is mostly about the atoms that communicate stuff to things like
window managers and taskbars.
The eventual goal is for this to be useful for writing those and for
writing plain applications.
*/
module arsd.xwindows;
import simpledisplay;
public import simpledisplay;
static if(UsingSimpledisplayX11) {
enum _NET_WM_STATE_ADD = 1;
enum _NET_WM_STATE_REMOVE = 0;
enum _NET_WM_STATE_TOGGLE = 2;
void demandAttention(SimpleWindow window, bool needs = true) {
auto display = XDisplayConnection.get();
auto atom = GetAtom!"_NET_WM_STATE_DEMANDS_ATTENTION"(display);
//auto atom2 = GetAtom!"_NET_WM_STATE_SHADED"(display);
XClientMessageEvent xclient;
xclient.type = EventType.ClientMessage;
xclient.window = window.impl.window;
xclient.message_type = GetAtom!"_NET_WM_STATE"(display);
xclient.format = 32;
xclient.data.l[0] = needs ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
xclient.data.l[1] = atom;
//xclient.data.l[2] = atom2;
// [2] == a second property
// [3] == source. 0 == unknown, 1 == app, 2 == else
XSendEvent(
display,
RootWindow(display, DefaultScreen(display)),
false,
EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask,
cast(XEvent*) &xclient
);
/+
XChangeProperty(
display,
window.impl.window,
GetAtom!"_NET_WM_STATE"(display),
XA_ATOM,
32 /* bits */,
PropModeAppend,
&atom,
1);
+/
}
TrueColorImage getWindowNetWmIcon(Window window) {
auto display = XDisplayConnection.get;
auto data = cast(arch_ulong[]) getX11PropertyData (window, GetAtom!"_NET_WM_ICON"(display), XA_CARDINAL);
if (data.length > 2) {
// these are an array of rgba images that we have to convert into pixmaps ourself
int width = cast(int) data[0];
int height = cast(int) data[1];
data = data[2 .. 2 + width * height];
auto bytes = cast(ubyte[]) data;
// this returns ARGB. Remember it is little-endian so
// we have BGRA
// our thing uses RGBA, which in little endian, is ABGR
for(int idx = 0; idx < bytes.length; idx += 4) {
auto r = bytes[idx + 2];
auto g = bytes[idx + 1];
auto b = bytes[idx + 0];
auto a = bytes[idx + 3];
bytes[idx + 0] = r;
bytes[idx + 1] = g;
bytes[idx + 2] = b;
bytes[idx + 3] = a;
}
return new TrueColorImage(width, height, bytes);
}
return null;
}
}