mirror of https://github.com/adamdruppe/arsd.git
new requestAttention function
This commit is contained in:
parent
4c1a38525b
commit
fbfb579875
144
simpledisplay.d
144
simpledisplay.d
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
106
xwindows.d
106
xwindows.d
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue