static bool wxQueryWMspecSupport(Display *display, Window rootWnd, Atom feature) { wxMAKE_ATOM(_NET_SUPPORTING_WM_CHECK, display); wxMAKE_ATOM(_NET_SUPPORTED, display); // FIXME: We may want to cache these checks. Note that we can't simply // remember the results in global variable because the WM may go // away and be replaced by another one! One possible approach // would be invalidate the case every 15 seconds or so. Since this // code is currently only used by wxTopLevelWindow::ShowFullScreen, // it is not important that it is not optimized. // // If the WM supports ICCCM (i.e. the root window has // _NET_SUPPORTING_WM_CHECK property that points to a WM-owned // window), we could watch for DestroyNotify event on the window // and invalidate our cache when the windows goes away (= WM // is replaced by another one). This is what GTK+ 2 does. // Let's do it only if it is needed, it requires changes to // the event loop. Atom type; Window *wins; Atom *atoms; int format; unsigned long after; unsigned long nwins, natoms; // Is the WM ICCCM supporting? XGetWindowProperty(display, rootWnd, _NET_SUPPORTING_WM_CHECK, 0, LONG_MAX, False, XA_WINDOW, &type, &format, &nwins, &after, (unsigned char **)&wins); if ( type != XA_WINDOW || nwins <= 0 || wins[0] == None ) return false; XFree(wins); // Query for supported features: XGetWindowProperty(display, rootWnd, _NET_SUPPORTED, 0, LONG_MAX, False, XA_ATOM, &type, &format, &natoms, &after, (unsigned char **)&atoms); if ( type != XA_ATOM || atoms == NULL ) return false; // Lookup the feature we want: for (unsigned i = 0; i < natoms; i++) { if ( atoms[i] == feature ) { XFree(atoms); return true; } } XFree(atoms); return false; }
wxX11FullScreenMethod wxGetFullScreenMethodX11(WXDisplay* display, WXWindow rootWindow) { Window root = WindowCast(rootWindow); Display *disp = (Display*)display; // if WM supports _NET_WM_STATE_FULLSCREEN from wm-spec 1.2, use it: wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN, disp); if (wxQueryWMspecSupport(disp, root, _NET_WM_STATE_FULLSCREEN)) { wxLogTrace(wxT("fullscreen"), wxT("detected _NET_WM_STATE_FULLSCREEN support")); return wxX11_FS_WMSPEC; } // if the user is running KDE's kwin WM, use a legacy hack because // kwin doesn't understand any other method: if (wxKwinRunning(disp, root)) { wxLogTrace(wxT("fullscreen"), wxT("detected kwin")); return wxX11_FS_KDE; } // finally, fall back to ICCCM heuristic method: wxLogTrace(wxT("fullscreen"), wxT("unknown WM, using _WIN_LAYER")); return wxX11_FS_GENERIC; }
static void wxWMspecSetState(Display *display, Window rootWnd, Window window, int operation, Atom state) { wxMAKE_ATOM(_NET_WM_STATE, display); if ( IsMapped(display, window) ) { XEvent xev; xev.type = ClientMessage; xev.xclient.type = ClientMessage; xev.xclient.serial = 0; xev.xclient.send_event = True; xev.xclient.display = display; xev.xclient.window = window; xev.xclient.message_type = _NET_WM_STATE; xev.xclient.format = 32; xev.xclient.data.l[0] = operation; xev.xclient.data.l[1] = state; xev.xclient.data.l[2] = None; XSendEvent(display, rootWnd, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } // FIXME - must modify _NET_WM_STATE property list if the window // wasn't mapped! }
static void wxWinHintsSetLayer(Display *display, Window rootWnd, Window window, int layer) { wxX11ErrorsSuspender noerrors(display); XEvent xev; wxMAKE_ATOM( _WIN_LAYER, display ); if (IsMapped(display, window)) { xev.type = ClientMessage; xev.xclient.type = ClientMessage; xev.xclient.window = window; xev.xclient.message_type = _WIN_LAYER; xev.xclient.format = 32; xev.xclient.data.l[0] = (long)layer; xev.xclient.data.l[1] = CurrentTime; XSendEvent(display, rootWnd, False, SubstructureNotifyMask, (XEvent*) &xev); } else { long data[1]; data[0] = layer; XChangeProperty(display, window, _WIN_LAYER, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); } }
static void wxWMspecSetFullscreen(Display *display, Window rootWnd, Window window, bool fullscreen) { wxMAKE_ATOM(_NET_WM_STATE_FULLSCREEN, display); wxWMspecSetState(display, rootWnd, window, fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE, _NET_WM_STATE_FULLSCREEN); }
// Is the user running KDE's kwin window manager? At least kwin from KDE 3 // sets KWIN_RUNNING property on the root window. static bool wxKwinRunning(Display *display, Window rootWnd) { wxMAKE_ATOM(KWIN_RUNNING, display); unsigned char* data; Atom type; int format; unsigned long nitems, after; if (XGetWindowProperty(display, rootWnd, KWIN_RUNNING, 0, 1, False, KWIN_RUNNING, &type, &format, &nitems, &after, &data) != Success) { return false; } bool retval = (type == KWIN_RUNNING && nitems == 1 && data && ((long*)data)[0] == 1); XFree(data); return retval; }
// KDE's kwin is Qt-centric so much than no normal method of fullscreen // mode will work with it. We have to carefully emulate the Qt way. static void wxSetKDEFullscreen(Display *display, Window rootWnd, Window w, bool fullscreen, wxRect *origRect) { long data[2]; unsigned lng; wxMAKE_ATOM(_NET_WM_WINDOW_TYPE, display); wxMAKE_ATOM(_NET_WM_WINDOW_TYPE_NORMAL, display); wxMAKE_ATOM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE, display); wxMAKE_ATOM(_NET_WM_STATE_STAYS_ON_TOP, display); if (fullscreen) { data[0] = _KDE_NET_WM_WINDOW_TYPE_OVERRIDE; data[1] = _NET_WM_WINDOW_TYPE_NORMAL; lng = 2; } else { data[0] = _NET_WM_WINDOW_TYPE_NORMAL; data[1] = None; lng = 1; } // it is necessary to unmap the window, otherwise kwin will ignore us: XSync(display, False); bool wasMapped = IsMapped(display, w); if (wasMapped) { XUnmapWindow(display, w); XSync(display, False); } XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, (unsigned char *) &data[0], lng); XSync(display, False); if (wasMapped) { XMapRaised(display, w); XSync(display, False); } wxWMspecSetState(display, rootWnd, w, fullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE, _NET_WM_STATE_STAYS_ON_TOP); XSync(display, False); if (!fullscreen) { // NB: like many other WMs, kwin ignores the first request for a window // position change after the window was mapped. This additional // move+resize event will ensure that the window is restored in // exactly the same position as before it was made fullscreen // (because wxTopLevelWindow::ShowFullScreen will call SetSize, thus // setting the position for the second time). XMoveResizeWindow(display, w, origRect->x, origRect->y, origRect->width, origRect->height); XSync(display, False); } }
void wxSetIconsX11(WXDisplay* display, WXWindow window, const wxIconBundle& ib) { size_t size = 0; const size_t numIcons = ib.GetIconCount(); for ( size_t i = 0; i < numIcons; ++i ) { const wxIcon icon = ib.GetIconByIndex(i); size += 2 + icon.GetWidth() * icon.GetHeight(); } wxMAKE_ATOM(_NET_WM_ICON, (Display*)display); if ( size > 0 ) { unsigned long* data = new unsigned long[size]; unsigned long* ptr = data; for ( size_t i = 0; i < numIcons; ++i ) { const wxImage image = ib.GetIconByIndex(i).ConvertToImage(); int width = image.GetWidth(), height = image.GetHeight(); unsigned char* imageData = image.GetData(); unsigned char* imageDataEnd = imageData + ( width * height * 3 ); bool hasMask = image.HasMask(); unsigned char rMask, gMask, bMask; unsigned char r, g, b, a; if( hasMask ) { rMask = image.GetMaskRed(); gMask = image.GetMaskGreen(); bMask = image.GetMaskBlue(); } else // no mask, but still init the variables to avoid warnings { rMask = gMask = bMask = 0; } *ptr++ = width; *ptr++ = height; while ( imageData < imageDataEnd ) { r = imageData[0]; g = imageData[1]; b = imageData[2]; if( hasMask && r == rMask && g == gMask && b == bMask ) a = 0; else a = 255; *ptr++ = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b; imageData += 3; } } XChangeProperty( (Display*)display, WindowCast(window), _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)data, size ); delete[] data; } else { XDeleteProperty( (Display*)display, WindowCast(window), _NET_WM_ICON ); } }
void wxSetIconsX11( WXDisplay* display, WXWindow window, const wxIconBundle& ib ) { #if !wxUSE_NANOX size_t size = 0; size_t i, max = ib.m_icons.GetCount(); for( i = 0; i < max; ++i ) if( ib.m_icons[i].Ok() ) size += 2 + ib.m_icons[i].GetWidth() * ib.m_icons[i].GetHeight(); wxMAKE_ATOM(_NET_WM_ICON, (Display*)display); if( size > 0 ) { // The code below is correct for 64-bit machines also. // wxUint32* data = new wxUint32[size]; // wxUint32* ptr = data; unsigned long* data = new unsigned long[size]; unsigned long* ptr = data; for( i = 0; i < max; ++i ) { const wxImage image = ib.m_icons[i].ConvertToImage(); int width = image.GetWidth(), height = image.GetHeight(); unsigned char* imageData = image.GetData(); unsigned char* imageDataEnd = imageData + ( width * height * 3 ); bool hasMask = image.HasMask(); unsigned char rMask, gMask, bMask; unsigned char r, g, b, a; if( hasMask ) { rMask = image.GetMaskRed(); gMask = image.GetMaskGreen(); bMask = image.GetMaskBlue(); } else // no mask, but still init the variables to avoid warnings { rMask = gMask = bMask = 0; } *ptr++ = width; *ptr++ = height; while( imageData < imageDataEnd ) { r = imageData[0]; g = imageData[1]; b = imageData[2]; if( hasMask && r == rMask && g == gMask && b == bMask ) a = 0; else a = 255; *ptr++ = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b; imageData += 3; } } XChangeProperty( (Display*)display, WindowCast(window), _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)data, size ); delete[] data; } else { XDeleteProperty( (Display*)display, WindowCast(window), _NET_WM_ICON ); } #endif // !wxUSE_NANOX }