Skip to content

Commit

Permalink
Update to WindowAbstractions 0.8
Browse files Browse the repository at this point in the history
  • Loading branch information
serenity4 committed Nov 19, 2024
1 parent 0fe6aee commit c23f1c9
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 112 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Xorg_xcb_util_jll = "2def613f-5ad1-5310-b15b-b15d46f528f5"
BitMasks = "0.1"
DocStringExtensions = "0.8, 0.9"
Reexport = "1"
WindowAbstractions = "0.7.1"
WindowAbstractions = "0.8.0"
XKeyboard = "0.1"
Xorg_libxcb_jll = "1.13"
Xorg_xcb_util_jll = "0.4"
Expand Down
6 changes: 3 additions & 3 deletions src/connection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ The connection is taken to be the first argument of `expr`. `expr` can be a call
# Examples
```
julia> @macroexpand @flush xcb_unmap_window(win.conn, win.id)
julia> @macroexpand @flush xcb_unmap_window(window.conn, window.id)
quote
xcb_unmap_window(win.conn, win.id)
(flush)(win.conn)
xcb_unmap_window(window.conn, window.id)
(flush)(window.conn)
end
```
"""
Expand Down
78 changes: 39 additions & 39 deletions src/events.jl
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
response_type(event) = Int(event.response_type & 0x7f)

enqueue!(queue, wm, win, event) = !isnothing(win) && push!(queue, Event(wm, win, event, time()))
enqueue!(queue, wm, window, event) = !isnothing(window) && push!(queue, Event(wm, window, event, time()))

function handle_event!(queue, ptr::Ptr{xcb_generic_event_t})
(; wm) = queue
rt = response_type(unsafe_load(ptr))
if rt in (XCB_KEY_PRESS, XCB_KEY_RELEASE)
event = unsafe_load(Ptr{xcb_key_press_event_t}(ptr))
win = get_window(wm, event.event)
enqueue!(queue, wm, win, event)
window = get_window(wm, event.event)
enqueue!(queue, wm, window, event)
elseif rt in (XCB_BUTTON_PRESS, XCB_BUTTON_RELEASE)
event = unsafe_load(Ptr{xcb_button_press_event_t}(ptr))
win = get_window(wm, event.event)
enqueue!(queue, wm, win, event)
window = get_window(wm, event.event)
enqueue!(queue, wm, window, event)
elseif rt in (XCB_ENTER_NOTIFY, XCB_LEAVE_NOTIFY)
event = unsafe_load(Ptr{xcb_enter_notify_event_t}(ptr))
win = get_window(wm, event.event)
enqueue!(queue, wm, win, event)
window = get_window(wm, event.event)
enqueue!(queue, wm, window, event)
elseif rt == XCB_MOTION_NOTIFY
event = unsafe_load(Ptr{xcb_motion_notify_event_t}(ptr))
win = get_window(wm, event.event)
enqueue!(queue, wm, win, event)
window = get_window(wm, event.event)
enqueue!(queue, wm, window, event)
elseif rt == XCB_EXPOSE
event = unsafe_load(Ptr{xcb_expose_event_t}(ptr))
win = get_window(wm, event.window)
enqueue!(queue, wm, win, event)
window = get_window(wm, event.window)
enqueue!(queue, wm, window, event)
elseif rt == XCB_CLIENT_MESSAGE
event = unsafe_load(Ptr{xcb_client_message_event_t}(ptr))
win = get_window(wm, event.window)
!is_delete_request(event, win) && return
enqueue!(queue, wm, win, event)
window = get_window(wm, event.window)
!is_delete_request(event, window) && return
enqueue!(queue, wm, window, event)
elseif rt == XCB_CONFIGURE_NOTIFY
event = unsafe_load(Ptr{xcb_configure_notify_event_t}(ptr))
win = get_window(wm, event.window)
enqueue!(queue, wm, win, event)
window = get_window(wm, event.window)
enqueue!(queue, wm, window, event)
elseif rt in (XCB_FOCUS_IN, XCB_FOCUS_OUT)
event = unsafe_load(Ptr{xcb_focus_in_event_t}(ptr))
win = get_window(wm, event.event)
enqueue!(queue, wm, win, event)
window = get_window(wm, event.event)
enqueue!(queue, wm, window, event)
elseif rt == 85 # very hacky, but response type 85 is emitted instead of XCB_XKB_STATE_NOTIFY...
event = unsafe_load(Ptr{xcb_xkb_state_notify_event_t}(ptr))
xkb_state_update_mask(wm.keymap.state, event.baseMods, event.latchedMods, event.lockedMods, event.baseGroup, event.latchedGroup, event.lockedGroup)
Expand All @@ -57,40 +57,40 @@ location(event::xcb_expose_event_t) = (event.x, event.y)
location(event::xcb_configure_notify_event_t) = (event.x, event.y)
location(::xcb_client_message_event_t) = (0, 0)

location(event, win) = coordinates(location(event), win)
function coordinates((x, y), win)
width, height = extent(win)
location(event, window) = coordinates(location(event), window)
function coordinates((x, y), window)
width, height = extent(window)
x = ifelse(iszero(width), 0.0, x/width)
y = ifelse(iszero(height), 0.0, y/height)
(x, y)
end

function Event(wm::XWindowManager, win::XCBWindow, event::xcb_button_press_event_t, t)
function Event(wm::XWindowManager, window::XCBWindow, event::xcb_button_press_event_t, t)
data = MouseEvent(event)
event_type = response_type(event) == XCB_BUTTON_PRESS ? BUTTON_PRESSED : BUTTON_RELEASED
Event(event_type, data, location(event, win), t, win)
Event(event_type, data, location(event, window), t, window)
end
function Event(wm::XWindowManager, win::XCBWindow, event::xcb_key_press_event_t, t)
function Event(wm::XWindowManager, window::XCBWindow, event::xcb_key_press_event_t, t)
data = KeyEvent(wm, event)
event_type = response_type(event) == XCB_KEY_PRESS ? KEY_PRESSED : KEY_RELEASED
Event(event_type, data, location(event, win), t, win)
Event(event_type, data, location(event, window), t, window)
end
Event(wm::XWindowManager, win::XCBWindow, event::xcb_client_message_event_t, t) =
Event(WINDOW_CLOSED, nothing, location(event, win), t, win)
Event(wm::XWindowManager, win::XCBWindow, event::xcb_enter_notify_event_t, t) =
Event(response_type(event) == XCB_ENTER_NOTIFY ? POINTER_ENTERED : POINTER_EXITED, nothing, location(event, win), t, win)
Event(wm::XWindowManager, win::XCBWindow, event::xcb_motion_notify_event_t, t) =
Event(POINTER_MOVED, PointerState(event), location(event, win), t, win)
Event(wm::XWindowManager, win::XCBWindow, event::xcb_expose_event_t, t) =
Event(WINDOW_EXPOSED, coordinates((event.width, event.height), win), location(event, win), t, win)
Event(wm::XWindowManager, win::XCBWindow, event::xcb_configure_notify_event_t, t) =
Event(WINDOW_RESIZED, Int64.((event.width, event.height)), location(event, win), t, win)
Event(wm::XWindowManager, win::XCBWindow, event::xcb_focus_in_event_t, t) =
Event(response_type(event) == XCB_FOCUS_IN ? WINDOW_GAINED_FOCUS : WINDOW_LOST_FOCUS, nothing, (0.0, 0.0), t, win)
Event(wm::XWindowManager, window::XCBWindow, event::xcb_client_message_event_t, t) =
Event(WINDOW_CLOSED, nothing, location(event, window), t, window)
Event(wm::XWindowManager, window::XCBWindow, event::xcb_enter_notify_event_t, t) =
Event(response_type(event) == XCB_ENTER_NOTIFY ? POINTER_ENTERED : POINTER_EXITED, nothing, location(event, window), t, window)
Event(wm::XWindowManager, window::XCBWindow, event::xcb_motion_notify_event_t, t) =
Event(POINTER_MOVED, PointerState(event), location(event, window), t, window)
Event(wm::XWindowManager, window::XCBWindow, event::xcb_expose_event_t, t) =
Event(WINDOW_EXPOSED, coordinates((event.width, event.height), window), location(event, window), t, window)
Event(wm::XWindowManager, window::XCBWindow, event::xcb_configure_notify_event_t, t) =
Event(WINDOW_RESIZED, Int64.((event.width, event.height)), location(event, window), t, window)
Event(wm::XWindowManager, window::XCBWindow, event::xcb_focus_in_event_t, t) =
Event(response_type(event) == XCB_FOCUS_IN ? WINDOW_GAINED_FOCUS : WINDOW_LOST_FOCUS, nothing, (0.0, 0.0), t, window)

function is_delete_request(event::xcb_client_message_event_t, win::XCBWindow)
function is_delete_request(event::xcb_client_message_event_t, window::XCBWindow)
data = deserialize_delete_request_data(event.data.data8)
data == win.delete_request
data == window.delete_request
end

serialize_delete_request_data(delete_request::xcb_atom_t) = ntuple(i -> i 4 ? UInt8((delete_request << 8(4 - i)) >> 24) : 0x00, 20)
Expand Down
34 changes: 17 additions & 17 deletions src/testing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,33 +72,33 @@ end

function event_xcb(wm::XWindowManager, e::Event)
T = event_type_xcb(e)
wx, wy = extent(e.win)
wx, wy = extent(e.window)
x, y = (wx, wy) .* e.location
x, y = round(Int16, x), round(Int16, y)
T === xcb_expose_event_t && return T(response_type_xcb(e), 0, 0, e.win.id, x, y, wx, wy, 0, (0, 0))
T === xcb_configure_notify_event_t && return T(response_type_xcb(e), 0, 0, e.win.id, e.win.id, 0, x, y, wx, wy, 0, 0, 0)
T === xcb_focus_in_event_t && return T(response_type_xcb(e), detail_xcb(wm, e), 0, e.win.id, 0, (0, 0, 0))
e.type == WINDOW_CLOSED && return T(response_type_xcb(e), 32, 0, e.win.id, 0x00000183, xcb_client_message_data_t(serialize_delete_request_data(e.win.delete_request)))
T(response_type_xcb(e), detail_xcb(wm, e), 0, 0, e.win.screen.root, e.win.id, 0, 0, 0, x, y, state_xcb(e), true, false)
T === xcb_expose_event_t && return T(response_type_xcb(e), 0, 0, e.window.id, x, y, wx, wy, 0, (0, 0))
T === xcb_configure_notify_event_t && return T(response_type_xcb(e), 0, 0, e.window.id, e.window.id, 0, x, y, wx, wy, 0, 0, 0)
T === xcb_focus_in_event_t && return T(response_type_xcb(e), detail_xcb(wm, e), 0, e.window.id, 0, (0, 0, 0))
e.type == WINDOW_CLOSED && return T(response_type_xcb(e), 32, 0, e.window.id, 0x00000183, xcb_client_message_data_t(serialize_delete_request_data(e.window.delete_request)))
T(response_type_xcb(e), detail_xcb(wm, e), 0, 0, e.window.screen.root, e.window.id, 0, 0, 0, x, y, state_xcb(e), true, false)
end

send_event(wm::XWindowManager, e::Event) = send_event(e.win, event_xcb(wm, e))
send_event(wm::XWindowManager, e::Event) = send_event(e.window, event_xcb(wm, e))

function send_event(win::XCBWindow, event)
function send_event(window::XCBWindow, event)
ref = Ref(event)
GC.@preserve ref begin
event_ptr = Ptr{Cchar}(Base.unsafe_convert(Ptr{typeof(event)}, ref))
@flush @check :error xcb_send_event(win.conn, false, win.id, 0, event_ptr)
@flush @check :error xcb_send_event(window.conn, false, window.id, 0, event_ptr)
end
end

hex(x) = "0x$(string(x, base=16))"

function send_event(wm::XWindowManager, win::XCBWindow, event_type::EventType, data = nothing; location = (0.0, 0.0), time = time())
send_event(wm, Event(event_type, data, location, time, win))
function send_event(wm::XWindowManager, window::XCBWindow, event_type::EventType, data = nothing; location = (0.0, 0.0), time = time())
send_event(wm, Event(event_type, data, location, time, window))
end

send_event(wm::XWindowManager, win::XCBWindow) = (event_type, data = nothing; location = (0.0, 0.0), time = time()) -> send_event(wm, win, event_type, data; location, time)
send_event(wm::XWindowManager, window::XCBWindow) = (event_type, data = nothing; location = (0.0, 0.0), time = time()) -> send_event(wm, window, event_type, data; location, time)

struct WindowRef <: AbstractWindow
number::Int64
Expand All @@ -109,8 +109,8 @@ function save_history(wm::XWindowManager, queue::EventQueue{XWindowManager,XCBWi
windows = XCBWindow[]
previous_time = 0.0
for event in queue.history
i = findfirst(==(event.win), windows)
isnothing(i) && push!(windows, event.win)
i = findfirst(==(event.window), windows)
isnothing(i) && push!(windows, event.window)
winref = WindowRef(something(i, lastindex(windows)))
Δt = previous_time == 0 ? 0.0 : event.time - previous_time
previous_time = event.time
Expand All @@ -125,16 +125,16 @@ function replay_history(wm::XWindowManager, events::AbstractVector{Event{WindowR
all_windows = xcb_window_t[]
replay_time = time()
for event in events
win = get!(windows, event.win) do
window = get!(windows, event.window) do
# Assume that window IDs will be ordered chronologically.
union!(all_windows, keys(wm.windows))
@assert issorted(all_windows) "Window IDs do not appear to be sorted chronologically"
i = event.win.number
i = event.window.number
wm.windows[all_windows[i]]
end
Δt = event.time * time_factor
wait_for(Δt)
event = Event(event.type, event.data, event.location, replay_time + Δt, win)
event = Event(event.type, event.data, event.location, replay_time + Δt, window)
send_event(wm, event)
end
end
Expand Down
60 changes: 30 additions & 30 deletions src/window.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ function XCBWindow(conn, screen::xcb_screen_t; depth=XCB_COPY_FROM_PARENT, x=0,
0,
C_NULL,
)
win = XCBWindow(conn, win_id, screen, delete_request(conn, win_id), nothing)
!with_decorations && XCB.hide_decorations(win)
window = XCBWindow(conn, win_id, screen, delete_request(conn, win_id), nothing)
!with_decorations && XCB.hide_decorations(window)

set_event_mask(win, keys(event_type_bits))
set_attributes(win, attributes, values)
set_event_mask(window, keys(event_type_bits))
set_attributes(window, attributes, values)

set_title(win, window_title)
set_title(window, window_title)

icon_title = something(icon_title, window_title)
set_icon_title(win, icon_title)
set_icon_title(window, icon_title)

map && map_window(win)
Base.finalizer(x -> @check(:error, xcb_destroy_window(x.conn, x.id)), win)
map && map_window(window)
Base.finalizer(x -> @check(:error, xcb_destroy_window(x.conn, x.id)), window)
end

"""
Expand All @@ -53,13 +53,13 @@ current_screen(conn) = unsafe_load(xcb_setup_roots_iterator(Setup(conn)).data)

Base.:(==)(x::XCBWindow, y::XCBWindow) = x.id == y.id

Base.hash(win::XCBWindow, h::UInt) = hash(win.id, h)
Base.hash(window::XCBWindow, h::UInt) = hash(window.id, h)

function set_attributes(win::XCBWindow, attributes, values)
function set_attributes(window::XCBWindow, attributes, values)
values = values[sortperm(attributes)]
list = zeros(UInt32, 32)
setindex!.(Ref(list), values, 1:length(values))
@flush @check xcb_change_window_attributes(win.conn, win.id, reduce(|, attributes; init = zero(UInt32)), list)
@flush @check xcb_change_window_attributes(window.conn, window.id, reduce(|, attributes; init = zero(UInt32)), list)
end

function delete_request(conn, win_id)
Expand All @@ -71,31 +71,31 @@ function delete_request(conn, win_id)
unsafe_load(wm_delete_reply).atom
end

function extent(win::XCBWindow)
geometry_cookie = xcb_get_geometry(win.conn, win.id)
geometry_reply = xcb_get_geometry_reply(win.conn, geometry_cookie, C_NULL)
function extent(window::XCBWindow)
geometry_cookie = xcb_get_geometry(window.conn, window.id)
geometry_reply = xcb_get_geometry_reply(window.conn, geometry_cookie, C_NULL)
geometry_reply == C_NULL && return (zero(UInt16), zero(UInt16))
data = unsafe_load(geometry_reply)
data.width, data.height
end

function resize(win::XCBWindow, extent)
@flush @check xcb_configure_window(win.conn, win.id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, UInt32[extent...])
function resize(window::XCBWindow, extent)
@flush @check xcb_configure_window(window.conn, window.id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, UInt32[extent...])
end

map_window(win::XCBWindow) = @flush @check xcb_map_window(win.conn, win.id)
map_window(window::XCBWindow) = @flush @check xcb_map_window(window.conn, window.id)

unmap_window(win::XCBWindow) = @flush @check xcb_unmap_window(win.conn, win.id)
unmap_window(window::XCBWindow) = @flush @check xcb_unmap_window(window.conn, window.id)

function set_title(win::XCBWindow, title)
function set_title(window::XCBWindow, title)
GC.@preserve title begin
@flush @check xcb_change_property(win.conn, XCB_PROP_MODE_REPLACE, win.id, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, length(title), pointer(title))
@flush @check xcb_change_property(window.conn, XCB_PROP_MODE_REPLACE, window.id, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, length(title), pointer(title))
end
end

function set_icon_title(win::XCBWindow, title)
function set_icon_title(window::XCBWindow, title)
title_c = title * "\0"
@flush @check xcb_change_property(win.conn, XCB_PROP_MODE_REPLACE, win.id, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, length(title_c) * 2, pointer(title_c^2))
@flush @check xcb_change_property(window.conn, XCB_PROP_MODE_REPLACE, window.id, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, length(title_c) * 2, pointer(title_c^2))
end

const base_event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_KEYMAP_STATE | XCB_EVENT_MASK_STRUCTURE_NOTIFY
Expand All @@ -117,19 +117,19 @@ const event_type_bits = Dict(
event_bit(event_type::EventType) = event_type_bits[event_type]
event_bits(event_types) = reduce((x, y) -> |(x, event_bit(y)), event_types; init = zero(xcb_event_mask_t))

function set_event_mask(win::XCBWindow, event_types)
function set_event_mask(window::XCBWindow, event_types)
mask = base_event_mask | event_bits(event_types)
set_attributes(win, [XCB_CW_EVENT_MASK], [mask])
set_attributes(window, [XCB_CW_EVENT_MASK], [mask])
end

attach_graphics_context!(win::XCBWindow, gc::GraphicsContext) = setproperty!(win, :gc, gc)
attach_graphics_context!(window::XCBWindow, gc::GraphicsContext) = setproperty!(window, :gc, gc)

GraphicsContext(win::XCBWindow; kwargs...) = GraphicsContext(win.conn, win.id; kwargs...)
GraphicsContext(window::XCBWindow; kwargs...) = GraphicsContext(window.conn, window.id; kwargs...)

function hide_decorations(win::XCBWindow)
function hide_decorations(window::XCBWindow)
name = "_MOTIF_WM_HINTS"
cookie = xcb_intern_atom(win.conn, 0, length(name), "_MOTIF_WM_HINTS" )
reply = unsafe_load(xcb_intern_atom_reply(win.conn, cookie, C_NULL))
cookie = xcb_intern_atom(window.conn, 0, length(name), "_MOTIF_WM_HINTS" )
reply = unsafe_load(xcb_intern_atom_reply(window.conn, cookie, C_NULL))
data = (; flags = UInt32(2), functions = UInt32(0), decorations = UInt32(0), input_mode = Int32(0), status = UInt32(0))
@check xcb_change_property(win.conn, XCB_PROP_MODE_REPLACE, win.id, reply.atom, reply.atom, 32, 5, Ref(data))
@check xcb_change_property(window.conn, XCB_PROP_MODE_REPLACE, window.id, reply.atom, reply.atom, 32, 5, Ref(data))
end
14 changes: 7 additions & 7 deletions src/window_manager.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mutable struct XWindowManager <: AbstractWindowManager
end
XWindowManager(conn::Connection, keymap::Keymap, windows::AbstractDict) = XWindowManager(conn, keymap, windows)
XWindowManager(conn::Connection, windows::AbstractDict) = XWindowManager(conn, Keymap(conn), windows)
XWindowManager(conn::Connection, windows::Vector{XCBWindow} = XCBWindow[]) = XWindowManager(conn, Dict(win.id => win for win in windows))
XWindowManager(conn::Connection, windows::Vector{XCBWindow} = XCBWindow[]) = XWindowManager(conn, Dict(window.id => window for window in windows))
XWindowManager(; display = nothing) = XWindowManager(Connection(; display))

window_type(::XWindowManager) = XCBWindow
Expand All @@ -16,14 +16,14 @@ get_window(wm::XWindowManager, id::Integer) = get(wm.windows, id, nothing)
current_screen(wm::XWindowManager) = current_screen(wm.conn)

function XCBWindow(wm::XWindowManager, title::AbstractString = "Window $(1 + length(wm.windows))"; screen = current_screen(wm), kwargs...)
win = XCBWindow(wm.conn, screen; window_title = title, kwargs...)
wm.windows[win.id] = win
win
window = XCBWindow(wm.conn, screen; window_title = title, kwargs...)
wm.windows[window.id] = window
window
end

function Base.close(wm::XWindowManager, win::XCBWindow)
delete!(wm.windows, win.id)
finalize(win)
function Base.close(wm::XWindowManager, window::XCBWindow)
delete!(wm.windows, window.id)
finalize(window)
end

function Base.show(io::IO, wm::XWindowManager)
Expand Down
Loading

0 comments on commit c23f1c9

Please sign in to comment.