diff options
author | drewski207 <drewski207@ae50a9b5-8222-0410-bf8d-8a13f76226bf> | 2007-07-19 11:03:39 +0000 |
---|---|---|
committer | drewski207 <drewski207@ae50a9b5-8222-0410-bf8d-8a13f76226bf> | 2007-07-19 11:03:39 +0000 |
commit | 8cc3714242ec4ece8675dd587ce4ccb820443bb8 (patch) | |
tree | 2b40b14688e717220fcd33a3628adf3943e71a2e /prototypes | |
parent | ad172f3f7b147a2aacb29cfd327e3f313406979d (diff) | |
download | fpGUI-8cc3714242ec4ece8675dd587ce4ccb820443bb8.tar.xz |
Added _Netlayer for using _NET wm hints
Diffstat (limited to 'prototypes')
-rw-r--r-- | prototypes/fpgui2/source/core/x11/_netlayer.pas | 999 |
1 files changed, 999 insertions, 0 deletions
diff --git a/prototypes/fpgui2/source/core/x11/_netlayer.pas b/prototypes/fpgui2/source/core/x11/_netlayer.pas new file mode 100644 index 00000000..1b3dde83 --- /dev/null +++ b/prototypes/fpgui2/source/core/x11/_netlayer.pas @@ -0,0 +1,999 @@ +unit _netlayer; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, X, XLib, XUtil, XAtom, ctypes; + +type + TNetMaximizedState = (nmsNone, nmsHorz, nmsVert, nmsBoth); + TNetWindowType = (nwtDesktop, nwtDock, nwtToolBar, nwtMenu, nwtUtility, nwtSplash, + nwtDialog, nwtDropdownMenu, nwtPopupMenu, nwtToolTip, + nwtNotification, nwtCombo, nwtDND, nwtNormal); + TNetWindowTypes = set of TNetWindowType; + + TNetWindowState = (nwsModal, nwsSticky, nwsMaxVert, nwsMaxHorz, nwsShaded, nwsSkipTaskBar, + nwsSkipPager, nwsHidden, nwsFullScreen, nwsAbove, nwsBelow, nwsDemandsAttn); + TNetWindowStates = set of TNetWindowState; + + TNetWindowAction = (nwaMove, nwaResize, nwaMinimize, nwaShade, nwaStick, nwaMaxHorz, + nwaMaxVert, nwaFullscreen, nwaChangeDesktop, nwaClose); + + TNetWindowActions = set of TNetWindowAction; + + PNetAtom = ^TNetAtom; + TNetAtom = TAtom; + + TNetAtomEnum = ( + naSUPPORTED, + naCLIENT_LIST, // array of TWindow + naCLIENT_LIST_STACKING, // array of TWindow (bottom to top) + naNUMBER_OF_DESKTOPS, // cardinal + naDESKTOP_GEOMETRY, // array [0..1] of cardinal (width height) + naDESKTOP_VIEWPORT, // array of cardinal array [0..1] viewports (top left position) + naCURRENT_DESKTOP, // cardinal (index of desktop) + naDESKTOP_NAMES, // array of null terminated UTF8 Strings + naACTIVE_WINDOW, // TWindow + naWORKAREA, // array [0..3] of cardinal (x, y, width, height) + naSUPPORTING_WM_CHECK, // TWindow + naVIRTUAL_ROOTS, // array of TWindow + naDESKTOP_LAYOUT, // array [0..3] of cardinal (orientation, columns, rows, starting_corner) + naSHOWING_DESKTOP, // ca + //Root Window Messages + naCLOSE_WINDOW, + naMOVERESIZE_WINDOW, + naWM_MOVERESIZE, + naRESTACK_WINDOW, + naREQUEST_FRAME_EXTENTS, + //Application Window Properties + naWM_NAME, // UTF8 String + naWM_VISIBLE_NAME, //UTF8 String + naWM_ICON_NAME, // UTF8 String + naWM_VISIBLE_ICON_NAME, // UTF8 String + naWM_DESKTOP, // cardinal (index of the desktop of the window) $FFFFFFFF for all desktops + naWM_WINDOW_TYPE, // TAtom of the different types below + naWM_WINDOW_TYPE_DESKTOP, + naWM_WINDOW_TYPE_DOCK, + naWM_WINDOW_TYPE_TOOLBAR, + naWM_WINDOW_TYPE_MENU, + naWM_WINDOW_TYPE_UTILITY, + naWM_WINDOW_TYPE_SPLASH, + naWM_WINDOW_TYPE_DIALOG, + naWM_WINDOW_TYPE_NORMAL, + naWM_WINDOW_TYPE_DROPDOWN_MENU, + naWM_WINDOW_TYPE_POPUP_MENU, + naWM_WINDOW_TYPE_TOOLTIP, + naWM_WINDOW_TYPE_NOTIFICATION, + naWM_WINDOW_TYPE_COMBO, + naWM_WINDOW_TYPE_DND, + naWM_STATE, // array of TAtoms. Possible members are listed below. others should be ignored + naWM_STATE_MODAL, + naWM_STATE_STICKY, + naWM_STATE_MAXIMIZED_VERT, + naWM_STATE_MAXIMIZED_HORZ, + naWM_STATE_SHADED, + naWM_STATE_SKIP_TASKBAR, + naWM_STATE_SKIP_PAGER, + naWM_STATE_HIDDEN, + naWM_STATE_FULLSCREEN, + naWM_STATE_ABOVE, + naWM_STATE_BELOW, + naWM_STATE_DEMANDS_ATTENTION, + naWM_ALLOWED_ACTIONS, //array of TAtoms below. unknown atoms are ignored + naWM_ACTION_MOVE, + naWM_ACTION_RESIZE, + naWM_ACTION_MINIMIZE, + naWM_ACTION_SHADE, + naWM_ACTION_STICK, + naWM_ACTION_MAXIMIZE_HORZ, + naWM_ACTION_MAXIMIZE_VERT, + naWM_ACTION_FULLSCREEN, + naWM_ACTION_CHANGE_DESKTOP, + naWM_ACTION_CLOSE, + naWM_STRUT, // array [0..3] of cardinal (left right top bottom) + naWM_STRUT_PARTIAL, // array [0..11] of cardinal (left, right, top, bottom, + // left_start_y, left_end_y, right_start_y, right_end_y, + // top_start_x, top_end_x, bottom_start_x, bottom_end_x ) + naWM_ICON_GEOMETRY, // array [0..3] of cardinal (x, y, width, height) + naWM_ICON, // array of cardinal the first two in the array are the width height + // and the rest of the array is the icon data in BGRA order + naWM_PID, // cardinal (process id of the window) + naWM_HANDLED_ICONS, + naWM_USER_TIME, // cardinal (XServer time of last user activity) + + naFRAME_EXTENTS, // array [0..3] of cardinal (left, right, top ,bottom) + + //Window Manager Protocols + naWM_PING, + naWM_SYNC_REQUEST + ); + + TNetAtomsSet = set of TNetAtomEnum; + + { TNETWindowLayer } + + TNETWindowLayer = class + private + FDisplay: PXDisplay; + FRootWindow: TWindow; + FNetAtoms: array[TNetAtomEnum] of TNetAtom; + FAtomSupported: array[TNetAtomEnum] of Boolean; + FTimeStamp: LongInt; + procedure InitNetAtoms; + procedure UpdateSupportedAtoms; + public + // window related functions + function WindowSetName(const AWindow: TWindow; AName: PChar): Boolean; + function WindowGetHidden(const AWindow: TWindow; out AValue: Boolean): Boolean; + function WindowSetHidden(const AWindow: TWindow; const AValue: Boolean): Boolean; + function WindowGetMaximizedState(const AWindow: TWindow; out AValue: TNetMaximizedState): Boolean; + function WindowSetMaximizedState(const AWindow: TWindow; const AValue: TNetMaximizedState): Boolean; + function WindowSetFullscreen(const AWindow: TWindow; const AValue: Boolean): Boolean; + function WindowGetFullscreen(const AWindow: TWindow; out AValue: Boolean): Boolean; + function WindowSetDesktop(const AWindow: TWindow; const ADesktopIndex: Integer): Boolean; + function WindowGetDesktop(const AWindow: TWindow; out ADesktopIndex: Integer): Boolean; + function WindowMoveResize(const AWindow: TWindow; const AX, AY, AWidth, AHeight: Integer): Boolean; + function WindowMove(const AWindow: TWindow; const AX, AY: Integer): Boolean; + function WindowSetSticky(const AWindow: TWindow; const AValue: Boolean): Boolean; + function WindowGetSticky(const AWindow: TWindow; out AValue: Boolean): Boolean; + procedure WindowSetPID(const AWindow: TWindow; const APID: Integer); + function WindowGetFrameExtents(const AWindow: TWindow; out ATopHeight, ALeftWidth, ARightWidth, ABottomHeight: Integer): Boolean; + procedure WindowSetSupportPING(const AWindow: TWindow); + procedure WindowReplyToPING(const AWindow: TWindow; AClientMessage: PXClientMessageEvent); + function WindowGetState(const AWindow: TWindow; out AWindowState: TNetWindowStates): Boolean; + procedure WindowDemandsAttention(const AWindow: TWindow); + procedure WindowSetSkipTaskbar(const AWindow: TWindow; const AValue: Boolean); + procedure WindowSetSkipPager(const AWindow: TWindow; const AValue: Boolean); + function WindowGetType(const AWindow: TWindow; out AWindowType: TNetWindowTypes): Boolean; + procedure WindowSetType(const AWindow: TWindow; const AWindowType: TNetWindowTypes); + procedure WindowAddProtocol(const AWindow: TWindow; AProtocol: TAtom); + function WindowGetAllowedActions(const AWindow: TWindow; var AActions: TNetWindowActions): Boolean; + // windowmanager functions + function ManagerCloseWindow(const AWindow: TWindow): Boolean; + function ManagerGetActiveWindow(out AWindow: TWindow): Boolean; + function ManagerSetActiveWindow(const AWindow: TWindow): Boolean; + function ManagerIsValid: Boolean; + // desktop functions + function DesktopGetSize(out AWidth, AHeight: Integer): Boolean; + function DesktopGetCurrent(out AIndex: Integer): Boolean; + function DesktopSetCurrent(const AIndex: Integer): Boolean; + function DesktopGetCount(out Desktops: Integer): Boolean; + function DesktopIsShowing: Boolean; + // misc + function SendMessage(AWindow: TWindow; APropagate: Boolean; AMask: LongInt; AMessage: PXEvent): TStatus; + procedure SendRootWindowMessage(AMessage: PXEvent); + procedure SendRootWindowClientMessage(AMessage: PXClientMessageEvent); + // property setting and getting routines + function WindowGetPropertyAtom(const AWindow: TWindow; AProperty: TAtom; var Count: Integer; var Atoms: PAtom): Boolean; + procedure WindowSetPropertyAtom(const AWindow: TWindow; AProperty: TAtom; Count: Integer; Atoms: PAtom); + function WindowGetPropertyCardinal(const AWindow: TWindow; AProperty: TAtom; var Count: Integer; var Cards: PLongWord): Boolean; + procedure WindowSetPropertyCardinal(const AWindow: TWindow; AProperty: TAtom; Count: Integer; Cards: PLongInt); + function WindowGetPropertyWindow(const AWindow: TWindow; AProperty: TAtom; var Count: Integer; var Windows: PWindow): Boolean; + procedure WindowSetPropertyWindow(const AWindow: TWindow; AProperty: TAtom; Count: Integer; Windows: PWindow); + + constructor Create(ADisplay: PXDisplay); + destructor Destroy; override; + end; + + const + NetAtomStr: array[TNetAtomEnum] of String = ( + '_NET_SUPPORTED', + '_NET_CLIENT_LIST', + '_NET_CLIENT_LIST_STACKING', + '_NET_NUMBER_OF_DESKTOPS', + '_NET_DESKTOP_GEOMETRY', + '_NET_DESKTOP_VIEWPORT', + '_NET_CURRENT_DESKTOP', + '_NET_DESKTOP_NAMES', + '_NET_ACTIVE_WINDOW', + '_NET_WORKAREA', + '_NET_SUPPORTING_WM_CHECK', + '_NET_VIRTUAL_ROOTS', + '_NET_DESKTOP_LAYOUT', + '_NET_SHOWING_DESKTOP', + '_NET_CLOSE_WINDOW', + '_NET_MOVERESIZE_WINDOW', + '_NET_WM_MOVERESIZE', + '_NET_RESTACK_WINDOW', + '_NET_REQUEST_FRAME_EXTENTS', + '_NET_WM_NAME', + '_NET_WM_VISIBLE_NAME', + '_NET_WM_ICON_NAME', + '_NET_WM_VISIBLE_ICON_NAME', + '_NET_WM_DESKTOP', + '_NET_WM_WINDOW_TYPE', + '_NET_WM_WINDOW_TYPE_DESKTOP', + '_NET_WM_WINDOW_TYPE_DOCK', + '_NET_WM_WINDOW_TYPE_TOOLBAR', + '_NET_WM_WINDOW_TYPE_MENU', + '_NET_WM_WINDOW_TYPE_UTILITY', + '_NET_WM_WINDOW_TYPE_SPLASH', + '_NET_WM_WINDOW_TYPE_DIALOG', + '_NET_WM_WINDOW_TYPE_NORMAL', + '_NET_WM_WINDOW_TYPE_DROPDOWN_MENU', + '_NET_WM_WINDOW_TYPE_POPUP_MENU', + '_NET_WM_WINDOW_TYPE_TOOLTIP', + '_NET_WM_WINDOW_TYPE_NOTIFICATION', + '_NET_WM_WINDOW_TYPE_COMBO', + '_NET_WM_WINDOW_TYPE_DND', + + '_NET_WM_STATE', + '_NET_WM_STATE_MODAL', + '_NET_WM_STATE_STICKY', + '_NET_WM_STATE_MAXIMIZED_VERT', + '_NET_WM_STATE_MAXIMIZED_HORZ', + '_NET_WM_STATE_SHADED', + '_NET_WM_STATE_SKIP_TASKBAR', + '_NET_WM_STATE_SKIP_PAGER', + '_NET_WM_STATE_HIDDEN', + '_NET_WM_STATE_FULLSCREEN', + '_NET_WM_STATE_ABOVE', + '_NET_WM_STATE_BELOW', + '_NET_WM_STATE_DEMANDS_ATTENTION', + + '_NET_WM_ALLOWED_ACTIONS', + '_NET_WM_ACTION_MOVE', + '_NET_WM_ACTION_RESIZE', + '_NET_WM_ACTION_MINIMIZE', + '_NET_WM_ACTION_SHADE', + '_NET_WM_ACTION_STICK', + '_NET_WM_ACTION_MAXIMIZE_HORZ', + '_NET_WM_ACTION_MAXIMIZE_VERT', + '_NET_WM_ACTION_FULLSCREEN', + '_NET_WM_ACTION_CHANGE_DESKTOP', + '_NET_WM_ACTION_CLOSE', + + '_NET_WM_STRUT', + '_NET_WM_STRUT_PARTIAL', + '_NET_WM_ICON_GEOMETRY', + '_NET_WM_ICON', + '_NET_WM_PID', + '_NET_WM_HANDLED_ICONS', + '_NET_WM_USER_TIME', + '_NET_FRAME_EXTENTS', + '_NET_WM_PING', + '_NET_WM_SYNC_REQUEST'); + + _NET_SOURCE_APPLICATION = 1; + _NET_SOURCE_PAGER = 2; + + _NET_WM_STATE_REMOVE = 0; // remove/unset property + _NET_WM_STATE_ADD = 1; // add/set property + _NET_WM_STATE_TOGGLE = 2; // toggle property + + +implementation +{ TNETWindowLayer } + +procedure TNETWindowLayer.InitNetAtoms; +var + NetAtom: TNetAtomEnum; +begin + for NetAtom := Low(TNetAtomEnum) to High(TNetAtomEnum) do begin + FNetAtoms[NetAtom] := XInternAtom(FDisplay, PChar(NetAtomStr[NetAtom]), True) + end; +end; + +procedure TNETWindowLayer.UpdateSupportedAtoms; +var + AtomCount: Integer; + Atoms: PNetAtom; + Data: Pointer; + I: Integer; + NetAtom: TNetAtomEnum; +begin + if WindowGetPropertyAtom(FRootWindow, FNetAtoms[naSUPPORTED], AtomCount, Atoms) = False then;// Exit; + //WriteLn('RootWindow Atom Count = ',AtomCount); + FillChar(FAtomSupported, SizeOf(Boolean) * Length(FAtomSupported), 0);; + for I := 0 to AtomCount-1 do begin + for NetAtom := Low(TNetAtomEnum) to High(TNetAtomEnum) do begin + if Atoms[I] = FNetAtoms[NetAtom] then begin + FAtomSupported[NetAtom] := True; + //WriteLn('Found ', NetAtomStr[NetAtom]); + end; + end; + end; + if AtomCount > 0 then + XFree(Atoms); +end; + +function TNETWindowLayer.WindowSetName(const AWindow: TWindow; AName: PChar + ): Boolean; +begin + +end; + +function TNETWindowLayer.WindowGetHidden(const AWindow: TWindow; out AValue: Boolean + ): Boolean; +var + WinState: TNetWindowStates; +begin + Result := FAtomSupported[naWM_STATE] and FAtomSupported[naWM_STATE_HIDDEN] + and WindowGetState(AWindow, WinState); + if not Result then Exit; + AValue := nwsHidden in WinState; +end; + +function TNETWindowLayer.WindowSetHidden(const AWindow: TWindow; const AValue: Boolean): Boolean; +var + Msg: TXClientMessageEvent; +begin + Result := FAtomSupported[naWM_STATE] and FAtomSupported[naWM_STATE_HIDDEN]; + if Result = False then Exit; + Result := True; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naWM_STATE]; + Msg.window := AWindow; + Msg.data.l[0] := Ord(AValue); + Msg.data.l[1] := FNetAtoms[naWM_STATE_HIDDEN]; + Msg.data.l[3] := _NET_SOURCE_APPLICATION; + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.WindowGetMaximizedState(const AWindow: TWindow; out + AValue: TNetMaximizedState): Boolean; +var + WinState: TNetWindowStates; +begin + Result := WindowGetState(AWindow, WinState); + AValue := nmsNone; + if Result then begin + if nwsMaxHorz in WinState then AValue := nmsHorz; + if (nwsMaxVert in WinState) then begin + if (AValue = nmsHorz) then AValue := nmsBoth + else AValue := nmsVert; + end; + end; +end; + +function TNETWindowLayer.WindowSetMaximizedState(const AWindow: TWindow; + const AValue: TNetMaximizedState): Boolean; +var + Msg: TXClientMessageEvent; +begin + Result := FAtomSupported[naWM_STATE] + and FAtomSupported[naWM_STATE_MAXIMIZED_HORZ] + and FAtomSupported[naWM_STATE_MAXIMIZED_VERT]; + if Result = False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naWM_STATE]; + Msg.window := AWindow; + + if AValue <> nmsNone then begin + Msg.data.l[0] := _NET_WM_STATE_ADD; + Msg.data.l[3] := _NET_SOURCE_APPLICATION; + + if AValue = nmsHorz then Msg.data.l[1] := FNetAtoms[naWM_STATE_MAXIMIZED_HORZ]; + if AValue = nmsVert then Msg.data.l[1] := FNetAtoms[naWM_STATE_MAXIMIZED_VERT]; + if AValue = nmsBoth then begin + Msg.data.l[1] := FNetAtoms[naWM_STATE_MAXIMIZED_VERT]; + Msg.data.l[2] := FNetAtoms[naWM_STATE_MAXIMIZED_HORZ]; + end; + SendRootWindowClientMessage(@Msg); + end; + + if AValue = nmsBoth then Exit; + // now remove properties we dont want + + Msg.data.l[0] := _NET_WM_STATE_REMOVE; + Msg.data.l[1] := 0; + Msg.data.l[2] := 0; + Msg.data.l[3] := _NET_SOURCE_APPLICATION; + + if AValue = nmsHorz then Msg.data.l[1] := FNetAtoms[naWM_STATE_MAXIMIZED_VERT]; + if AValue = nmsVert then Msg.data.l[1] := FNetAtoms[naWM_STATE_MAXIMIZED_HORZ]; + if AValue = nmsNone then begin + Msg.data.l[1] := FNetAtoms[naWM_STATE_MAXIMIZED_HORZ]; + Msg.data.l[2] := FNetAtoms[naWM_STATE_MAXIMIZED_VERT]; + end; + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.WindowSetFullscreen(const AWindow: TWindow; + const AValue: Boolean): Boolean; +var + Msg: TXClientMessageEvent; +begin + Result := FAtomSupported[naWM_STATE] and FAtomSupported[naWM_STATE_FULLSCREEN]; + if Result = False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naWM_STATE]; + Msg.window := AWindow; + Msg.data.l[0] := Ord(AValue); + Msg.data.l[1] := FNetAtoms[naWM_STATE_FULLSCREEN]; + Msg.data.l[3] := _NET_SOURCE_APPLICATION; + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.WindowGetFullscreen(const AWindow: TWindow; out + AValue: Boolean): Boolean; +var + WinState: TNetWindowStates; +begin + Result := WindowGetState(AWindow, WinState); + + if Result then AValue := nwsFullScreen in WinState; +end; + +function TNETWindowLayer.WindowSetDesktop(const AWindow: TWindow; + const ADesktopIndex: Integer): Boolean; +var + Msg: TXClientMessageEvent; +begin + Result := FAtomSupported[naWM_DESKTOP]; + if Result = False then Exit; + + Msg.message_type := FNetAtoms[naWM_DESKTOP]; + Msg.window := AWindow; + Msg.data.l[0] := ADesktopIndex; + Msg.data.l[1] := _NET_SOURCE_APPLICATION; + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.WindowGetDesktop(const AWindow: TWindow; out + ADesktopIndex: Integer): Boolean; +var + Index: PCardinal; + Count: LongInt; +begin + Result := FAtomSupported[naWM_DESKTOP] + and WindowGetPropertyCardinal(FRootWindow, FNetAtoms[naWM_DESKTOP], Count, Index); + if Result = False then Exit; + + ADesktopIndex := Index^; + if Count > 0 then XFree(Index); +end; + +function TNETWindowLayer.WindowMoveResize(const AWindow: TWindow; const AX, AY, + AWidth, AHeight: Integer): Boolean; +var + Msg: TXClientMessageEvent; +const + WSet = 1 shl 7; + HSet = 1 shl 6; + XSet = 1 shl 5; + YSet = 1 shl 4; + + FromPager = 1 shl 1; + FromApp = 1 shl 0; +begin + Result := FAtomSupported[naMOVERESIZE_WINDOW]; + if Result = False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naMOVERESIZE_WINDOW]; + Msg.window := AWindow; + Msg.data.s[0] := WSet or HSet or XSet or YSet or FromApp; // Gravity and flags + Msg.data.l[1] := AX; + Msg.data.l[2] := AY; + Msg.data.l[3] := AWidth; + Msg.data.l[4] := AHeight; + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.WindowMove(const AWindow: TWindow; const AX, AY: Integer): Boolean; +var + Msg: TXClientMessageEvent; +const + WSet = 1 shl 7; + HSet = 1 shl 6; + XSet = 1 shl 5; + YSet = 1 shl 4; + FromApp = 1 shl 0; + FromPager = 1 shl 1; +begin + Result := FAtomSupported[naMOVERESIZE_WINDOW]; + if Result = False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naMOVERESIZE_WINDOW]; + Msg.window := AWindow; + Msg.data.b[0] := 0; // Gravity and flags + Msg.data.b[1] := XSet or YSet or FromApp; + Msg.data.b[2] := 0; + Msg.data.b[3] := 0; // this does nothing + Msg.data.l[1] := AX; + Msg.data.l[2] := AY; + + SendRootWindowClientMessage(@Msg); + +end; + +function TNETWindowLayer.WindowSetSticky(const AWindow: TWindow; + const AValue: Boolean): Boolean; +var + Msg: TXClientMessageEvent; +begin + Result := FAtomSupported[naWM_STATE] and FAtomSupported[naWM_STATE_STICKY]; + if Result = False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.window := AWindow; + Msg.message_type := FNetAtoms[naWM_STATE]; + Msg.data.l[0] := Ord(AValue); + Msg.data.l[1] := FNetAtoms[naWM_STATE_STICKY]; + Msg.data.l[3] := _NET_SOURCE_APPLICATION; + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.WindowGetSticky(const AWindow: TWindow; out AValue: Boolean + ): Boolean; +var + WinState: TNetWindowStates; +begin + Result := WindowGetState(AWindow, WinState); + + if Result then AValue := nwsSticky in WinState; +end; + +procedure TNETWindowLayer.WindowSetPID(const AWindow: TWindow; const APID: Integer); +begin +end; + +function TNETWindowLayer.WindowGetFrameExtents(const AWindow: TWindow; out + ATopHeight, ALeftWidth, ARightWidth, ABottomHeight: Integer): Boolean; +var + Sizes: PCardinal; + Count: LongInt; +begin + Result := FAtomSupported[naFRAME_EXTENTS]; + if Result = False then Exit; + Result := WindowGetPropertyCardinal(FRootWindow, FNetAtoms[naFRAME_EXTENTS], Count, Sizes); + if Count = 4 then begin + ALeftWidth := Sizes[0]; + ARightWidth := Sizes[1]; + ATopHeight := Sizes[2]; + ABottomHeight := Sizes[3]; + end + else Result := False; + if Count > 0 then XFree(Sizes); +end; + +procedure TNETWindowLayer.WindowSetSupportPING(const AWindow: TWindow); +begin + WindowAddProtocol(AWindow, FNetAtoms[naWM_PING]); +end; + +procedure TNETWindowLayer.WindowReplyToPING(const AWindow: TWindow; + AClientMessage: PXClientMessageEvent); +begin + AClientMessage^.window := FRootWindow; + SendRootWindowMessage(PXEvent(AClientMessage)); +end; + +function TNETWindowLayer.ManagerCloseWindow(const AWindow: TWindow): Boolean; +var + Msg: TXClientMessageEvent; +begin + Result := FAtomSupported[naCLOSE_WINDOW]; + if Result =False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.window := AWindow; + Msg.message_type := FNetAtoms[naCLOSE_WINDOW]; + Msg.data.l[0] := FTimeStamp; + Msg.data.l[1] := _NET_SOURCE_APPLICATION; + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.ManagerGetActiveWindow(out AWindow: TWindow): Boolean; +var + ActiveWindow: PWindow; + Count: LongInt; +begin + Result := FAtomSupported[naACTIVE_WINDOW]; + if Result = False then Exit; + Result := WindowGetPropertyWindow(FRootWindow, FNetAtoms[naACTIVE_WINDOW], Count, ActiveWindow); + if Count = 1 then + AWindow := ActiveWindow^; + if Count > 0 then XFree(ActiveWindow); +end; + +function TNETWindowLayer.ManagerSetActiveWindow(const AWindow: TWindow): Boolean; +var + Msg: TXClientMessageEvent; +begin + Result := FAtomSupported[naACTIVE_WINDOW]; + if Result = False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.window := AWindow; + Msg.message_type := FNetAtoms[naACTIVE_WINDOW]; + Msg.data.l[0] := _NET_SOURCE_APPLICATION; + Msg.data.l[1] := FTimeStamp; + Msg.data.l[2] := 0; // our current active window + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.ManagerIsValid: Boolean; +begin + +end; + +procedure TNETWindowLayer.SendRootWindowMessage(AMessage: PXEvent); +begin + SendMessage(FRootWindow, False, SubstructureNotifyMask or SubstructureRedirectMask, AMessage); +end; + +procedure TNETWindowLayer.SendRootWindowClientMessage(AMessage: PXClientMessageEvent + ); +begin + AMessage^.format := 32; + AMessage^._type := ClientMessage; + SendRootWindowMessage(PXEvent(AMessage)); +end; + +function TNETWindowLayer.WindowGetPropertyAtom(const AWindow: TWindow; AProperty: TAtom; + var Count: Integer; var Atoms: PAtom): Boolean; +var + atomtype: TAtom; + format: cint; + nitems: culong; + bytes_after: culong; +begin + Result := False; + XGetWindowProperty (FDisplay, AWindow, AProperty, 0, MaxInt, False, XA_ATOM, @atomtype, @format, @nitems, + @bytes_after, @Atoms); + + if (atomtype = XA_ATOM) and (format = 32) then begin + Result := True; + Count := nitems; + end; +end; + +procedure TNETWindowLayer.WindowSetPropertyAtom(const AWindow: TWindow; + AProperty: TAtom; Count: Integer; Atoms: PAtom); +begin + XChangeProperty(FDisplay, AWindow, AProperty, XA_ATOM, 32, PropModeReplace, Pointer(Atoms), Count); +end; + +procedure TNETWindowLayer.WindowSetPropertyCardinal(const AWindow: TWindow; + AProperty: TAtom; Count: Integer; Cards: PLongInt); +begin + XChangeProperty(FDisplay, AWindow, AProperty, XA_CARDINAL, 32, PropModeReplace, Pointer(Cards), Count); +end; + +function TNETWindowLayer.WindowGetPropertyWindow(const AWindow: TWindow; + AProperty: TAtom; var Count: Integer; var Windows: PWindow): Boolean; +var + atomtype: TAtom; + format: cint; + nitems: culong; + bytes_after: culong; +begin + Result := False; + XGetWindowProperty (FDisplay, AWindow, AProperty, 0, MaxInt, False, XA_ATOM, @atomtype, @format, @nitems, + @bytes_after, @Windows); + + if (atomtype = XA_WINDOW) and (format = 32) then begin + Result := True; + Count := nitems; + end; + +end; + +procedure TNETWindowLayer.WindowSetPropertyWindow(const AWindow: TWindow; + AProperty: TAtom; Count: Integer; Windows: PWindow); +begin + XChangeProperty(FDisplay, AWindow, AProperty, XA_WINDOW, 32, PropModeReplace, Pointer(Windows), Count); +end; + +function TNETWindowLayer.WindowGetPropertyCardinal(const AWindow: TWindow; + AProperty: TAtom; var Count: Integer; var Cards: PLongWord): Boolean; +var + atomtype: TAtom; + format: cint; + nitems: culong; + bytes_after: culong; +begin + Result := False; + XGetWindowProperty (FDisplay, AWindow, AProperty, 0, MaxInt, False, XA_ATOM, @atomtype, @format, @nitems, + @bytes_after, @Cards); + + if (atomtype = XA_CARDINAL) and (format = 32) then begin + Result := True; + Count := nitems; + end; +end; + +procedure TNETWindowLayer.WindowAddProtocol(const AWindow: TWindow; AProtocol: TAtom); +var + Count: cint; + Protocols: PAtom; + NewProtocols: array of TAtom; +begin + XGetWMProtocols(FDisplay, AWindow, @Protocols, @Count); + + SetLength(NewProtocols, Count+1); + Move(Protocols[0], NewProtocols[0], SizeOf(TAtom)* Count); + NewProtocols[Count] := AProtocol; + + if Count > 0 then XFree(Protocols); + + XSetWMProtocols(FDisplay, AWindow, @NewProtocols, Count+1); +end; + +function TNETWindowLayer.WindowGetAllowedActions(const AWindow: TWindow; + var AActions: TNetWindowActions): Boolean; +var + AtomCount: Integer; + ActionAtoms: PAtom; + I: Integer; +begin + Result := FAtomSupported[naWM_ALLOWED_ACTIONS]; + if Result = False then Exit; + if WindowGetPropertyAtom(AWindow, FNetAtoms[naWM_ALLOWED_ACTIONS], AtomCount, ActionAtoms) = False then Exit(False); + AActions := []; + + //WriteLn('Getting Allowed Actions. ', AtomCount); + + for I := 0 to AtomCount-1 do begin + //WriteLn('Allowed ', XGetAtomName(FDisplay,ActionAtoms[I])); + if ActionAtoms[I] = FNetAtoms[naWM_ACTION_MOVE] then Include(AActions, nwaMove) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_RESIZE] then Include(AActions, nwaResize) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_MINIMIZE] then Include(AActions, nwaMinimize) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_SHADE] then Include(AActions, nwaShade) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_STICK] then Include(AActions, nwaStick) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_MAXIMIZE_HORZ] then Include(AActions, nwaMaxHorz) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_MAXIMIZE_VERT] then Include(AActions, nwaMaxVert) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_FULLSCREEN] then Include(AActions, nwaFullscreen) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_CHANGE_DESKTOP] then Include(AActions, nwaChangeDesktop) + else if ActionAtoms[I] = FNetAtoms[naWM_ACTION_CLOSE] then Include(AActions, nwaClose); + end; + if AtomCount > 0 then XFree(ActionAtoms); +end; + +function TNETWindowLayer.WindowGetState(const AWindow: TWindow; out + AWindowState: TNetWindowStates): Boolean; +var + AtomCount: Integer; + StateAtoms: PAtom; + Data: Pointer; + I: Integer; + State: TNetWindowState; +begin + Result := FAtomSupported[naWM_STATE]; + if Result = False then Exit; + if WindowGetPropertyAtom(AWindow, FNetAtoms[naWM_STATE], AtomCount, StateAtoms) = False then + Exit(False); + + AWindowState := []; + + for I := 0 to AtomCount-1 do begin + if StateAtoms[I] = FNetAtoms[naWM_STATE_MODAL] then Include(AWindowState, nwsModal) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_STICKY] then Include(AWindowState, nwsSticky) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_MAXIMIZED_VERT] then Include(AWindowState, nwsMaxVert) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_MAXIMIZED_HORZ] then Include(AWindowState, nwsMaxHorz) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_SHADED] then Include(AWindowState, nwsShaded) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_SKIP_TASKBAR] then Include(AWindowState, nwsSkipTaskBar) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_SKIP_PAGER] then Include(AWindowState, nwsSkipPager) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_HIDDEN] then Include(AWindowState, nwsHidden) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_FULLSCREEN] then Include(AWindowState, nwsFullScreen) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_ABOVE] then Include(AWindowState, nwsAbove) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_BELOW] then Include(AWindowState, nwsBelow) + else if StateAtoms[I] = FNetAtoms[naWM_STATE_DEMANDS_ATTENTION] then Include(AWindowState, nwsDemandsAttn); + end; + if AtomCount > 0 then + XFree(StateAtoms); +end; + +procedure TNETWindowLayer.WindowDemandsAttention(const AWindow: TWindow); +var + Msg: TXClientMessageEvent; +begin + if FAtomSupported[naWM_STATE] and FAtomSupported[naWM_STATE_DEMANDS_ATTENTION] = False then Exit; + + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naWM_STATE]; + Msg.window := AWindow; + Msg.data.l[0] := _NET_WM_STATE_ADD; + Msg.data.l[1] := FNetAtoms[naWM_STATE_DEMANDS_ATTENTION]; + Msg.data.l[3] := _NET_SOURCE_APPLICATION; + + SendRootWindowClientMessage(@Msg); +end; + +procedure TNETWindowLayer.WindowSetSkipTaskbar(const AWindow: TWindow; + const AValue: Boolean); +var + Msg: TXClientMessageEvent; +begin + if FAtomSupported[naWM_STATE] and FAtomSupported[naWM_STATE_SKIP_TASKBAR] = False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naWM_STATE]; + Msg.window := AWindow; + Msg.data.l[0] := Ord(AValue); + Msg.data.l[1] := FNetAtoms[naWM_STATE_SKIP_TASKBAR]; + Msg.data.l[3] := _NET_SOURCE_APPLICATION; + + SendRootWindowClientMessage(@Msg); +end; + +procedure TNETWindowLayer.WindowSetSkipPager(const AWindow: TWindow; + const AValue: Boolean); +var + Msg: TXClientMessageEvent; +begin + if FAtomSupported[naWM_STATE] and FAtomSupported[naWM_STATE_SKIP_PAGER] = False then Exit; + + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naWM_STATE]; + Msg.window := AWindow; + Msg.data.l[0] := Ord(AValue); + Msg.data.l[1] := FNetAtoms[naWM_STATE_SKIP_PAGER]; + Msg.data.l[3] := _NET_SOURCE_APPLICATION; + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.WindowGetType(const AWindow: TWindow; out + AWindowType: TNetWindowTypes): Boolean; +var + WindowTypes: PAtom; + Count: LongInt; + I : Integer; +begin + Result := FAtomSupported[naWM_WINDOW_TYPE] + and WindowGetPropertyAtom(AWindow, FNetAtoms[naWM_WINDOW_TYPE], Count, WindowTypes); + if not Result then Exit; + + AWindowType := []; + for I := 0 to Count -1 do begin + if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_DESKTOP] then Include(AWindowType, nwtDesktop) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_DOCK] then Include(AWindowType, nwtDock) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_TOOLBAR] then Include(AWindowType, nwtToolBar) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_MENU] then Include(AWindowType, nwtMenu) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_UTILITY] then Include(AWindowType, nwtUtility) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_SPLASH] then Include(AWindowType, nwtSplash) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_DIALOG] then Include(AWindowType, nwtDialog) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_NORMAL] then Include(AWindowType, nwtNormal) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_DROPDOWN_MENU] then Include(AWindowType, nwtDropdownMenu) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_POPUP_MENU] then Include(AWindowType, nwtPopupMenu) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_TOOLTIP] then Include(AWindowType, nwtToolTip) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_NOTIFICATION] then Include(AWindowType, nwtNotification) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_COMBO] then Include(AWindowType, nwtCombo) + else if WindowTypes[I] = FNetAtoms[naWM_WINDOW_TYPE_DND] then Include(AWindowType, nwtDND); + end; + + + +end; + +procedure TNETWindowLayer.WindowSetType(const AWindow: TWindow; + const AWindowType: TNetWindowTypes); +var + WindowAtoms: array of TNetAtom; + + procedure AddWindowType(AType: TNetAtom); + var + CurrentLength: Integer; + begin + CurrentLength := Length(WindowAtoms); + SetLength(WindowAtoms, CurrentLength+1); + WindowAtoms[CurrentLength] := AType; + end; +var + WindowType: TNetWindowType; + AtomEnum: TNetAtomEnum; +begin + for WindowType := Low(TNetWindowType) to High(TNetWindowType) do begin + AtomEnum := TNetAtomEnum(Ord(naWM_WINDOW_TYPE_DESKTOP) + Ord(WindowType)); + if WindowType in AWindowType then AddWindowType(FNetAtoms[AtomEnum]); + end; +end; + +function TNETWindowLayer.DesktopGetSize(out AWidth, AHeight: Integer): Boolean; +var + Count : LongInt; + Sizes: PLongWord; +begin + Result := FAtomSupported[naDESKTOP_GEOMETRY] + and WindowGetPropertyCardinal(FRootWindow, FNetAtoms[naDESKTOP_GEOMETRY], Count, Sizes); + if not Result then Exit; + + if Count > 0 then begin + Result := False; + if Count = 2 then begin + AWidth := Sizes[0]; + AHeight := Sizes[1]; + Result := True; + end; + XFree(Sizes); + end; +end; + +function TNETWindowLayer.DesktopGetCurrent(out AIndex: Integer): Boolean; +var + Count : LongInt; + Index: PLongWord; +begin + Result := FAtomSupported[naCURRENT_DESKTOP] + and WindowGetPropertyCardinal(FRootWindow, FNetAtoms[naCURRENT_DESKTOP], Count, Index); + if not Result then Exit; + + AIndex := Index^; + + if Count > 0 then XFree(Index); +end; + +function TNETWindowLayer.DesktopSetCurrent(const AIndex: Integer): Boolean; +var + Msg: TXClientMessageEvent; +begin + Result := FAtomSupported[naCURRENT_DESKTOP]; + if Result = False then Exit; + FillChar(Msg, SizeOf(Msg), 0); + + Msg.message_type := FNetAtoms[naCURRENT_DESKTOP]; + Msg.data.l[0] := AIndex; + Msg.data.l[1] := FTimeStamp; + + SendRootWindowClientMessage(@Msg); +end; + +function TNETWindowLayer.DesktopGetCount(out Desktops: Integer): Boolean; +var + Count : LongInt; + Number: PLongWord; +begin + Result := FAtomSupported[naNUMBER_OF_DESKTOPS] + and WindowGetPropertyCardinal(FRootWindow, FNetAtoms[naNUMBER_OF_DESKTOPS], Count, Number); + if not Result then Exit; + + Desktops := PLongInt(Number)^; + + if Count > 0 then XFree(Number); +end; + +function TNETWindowLayer.DesktopIsShowing: Boolean; +var + Count : LongInt; + Showing: PLongWord; +begin + Result := FAtomSupported[naSHOWING_DESKTOP] + and WindowGetPropertyCardinal(FRootWindow, FNetAtoms[naSHOWING_DESKTOP], Count, Showing); + if not Result then Exit; + + Result := Showing^ = 1; + + if Count > 0 then XFree(Showing); +end; + +function TNETWindowLayer.SendMessage(AWindow: TWindow; APropagate: Boolean; + AMask: LongInt; AMessage: PXEvent): TStatus; +begin + Inc(FTimeStamp); + AMessage^.xany.display := FDisplay; + Result := XSendEvent(FDisplay, AWindow, APropagate, AMask, AMessage); +end; + +constructor TNETWindowLayer.Create(ADisplay: PXDisplay); +begin + FDisplay := ADisplay; + FRootWindow := XDefaultRootWindow(FDisplay); + InitNetAtoms; + UpdateSupportedAtoms; +end; + +destructor TNETWindowLayer.Destroy; +begin + inherited Destroy; +end; + +end. + |