@ -87,7 +87,11 @@ static void transaction_destroy(struct sway_transaction *transaction) {
static void copy_output_state ( struct sway_output * output ,
static void copy_output_state ( struct sway_output * output ,
struct sway_transaction_instruction * instruction ) {
struct sway_transaction_instruction * instruction ) {
struct sway_output_state * state = & instruction - > output_state ;
struct sway_output_state * state = & instruction - > output_state ;
if ( state - > workspaces ) {
state - > workspaces - > length = 0 ;
} else {
state - > workspaces = create_list ( ) ;
state - > workspaces = create_list ( ) ;
}
list_cat ( state - > workspaces , output - > workspaces ) ;
list_cat ( state - > workspaces , output - > workspaces ) ;
state - > active_workspace = output_get_active_workspace ( output ) ;
state - > active_workspace = output_get_active_workspace ( output ) ;
@ -105,8 +109,16 @@ static void copy_workspace_state(struct sway_workspace *ws,
state - > layout = ws - > layout ;
state - > layout = ws - > layout ;
state - > output = ws - > output ;
state - > output = ws - > output ;
if ( state - > floating ) {
state - > floating - > length = 0 ;
} else {
state - > floating = create_list ( ) ;
state - > floating = create_list ( ) ;
}
if ( state - > tiling ) {
state - > tiling - > length = 0 ;
} else {
state - > tiling = create_list ( ) ;
state - > tiling = create_list ( ) ;
}
list_cat ( state - > floating , ws - > floating ) ;
list_cat ( state - > floating , ws - > floating ) ;
list_cat ( state - > tiling , ws - > tiling ) ;
list_cat ( state - > tiling , ws - > tiling ) ;
@ -147,7 +159,11 @@ static void copy_container_state(struct sway_container *container,
state - > content_height = container - > content_height ;
state - > content_height = container - > content_height ;
if ( ! container - > view ) {
if ( ! container - > view ) {
if ( state - > children ) {
state - > children - > length = 0 ;
} else {
state - > children = create_list ( ) ;
state - > children = create_list ( ) ;
}
list_cat ( state - > children , container - > children ) ;
list_cat ( state - > children , container - > children ) ;
}
}
@ -163,14 +179,33 @@ static void copy_container_state(struct sway_container *container,
static void transaction_add_node ( struct sway_transaction * transaction ,
static void transaction_add_node ( struct sway_transaction * transaction ,
struct sway_node * node ) {
struct sway_node * node ) {
struct sway_transaction_instruction * instruction =
struct sway_transaction_instruction * instruction = NULL ;
calloc ( 1 , sizeof ( struct sway_transaction_instruction ) ) ;
// Check if we have an instruction for this node already, in which case we
// update that instead of creating a new one.
if ( node - > ntxnrefs > 0 ) {
for ( int idx = 0 ; idx < transaction - > instructions - > length ; idx + + ) {
struct sway_transaction_instruction * other =
transaction - > instructions - > items [ idx ] ;
if ( other - > node = = node ) {
instruction = other ;
break ;
}
}
}
if ( ! instruction ) {
instruction = calloc ( 1 , sizeof ( struct sway_transaction_instruction ) ) ;
if ( ! sway_assert ( instruction , " Unable to allocate instruction " ) ) {
if ( ! sway_assert ( instruction , " Unable to allocate instruction " ) ) {
return ;
return ;
}
}
instruction - > transaction = transaction ;
instruction - > transaction = transaction ;
instruction - > node = node ;
instruction - > node = node ;
list_add ( transaction - > instructions , instruction ) ;
node - > ntxnrefs + + ;
}
switch ( node - > type ) {
switch ( node - > type ) {
case N_ROOT :
case N_ROOT :
break ;
break ;
@ -184,9 +219,6 @@ static void transaction_add_node(struct sway_transaction *transaction,
copy_container_state ( node - > sway_container , instruction ) ;
copy_container_state ( node - > sway_container , instruction ) ;
break ;
break ;
}
}
list_add ( transaction - > instructions , instruction ) ;
node - > ntxnrefs + + ;
}
}
static void apply_output_state ( struct sway_output * output ,
static void apply_output_state ( struct sway_output * output ,
@ -307,70 +339,25 @@ static void transaction_apply(struct sway_transaction *transaction) {
cursor_rebase_all ( ) ;
cursor_rebase_all ( ) ;
}
}
static void transaction_commit ( struct sway_transaction * transaction ) ;
static void transaction_commit_pending ( void ) ;
// Return true if both transactions operate on the same nodes
static bool transaction_same_nodes ( struct sway_transaction * a ,
struct sway_transaction * b ) {
if ( a - > instructions - > length ! = b - > instructions - > length ) {
return false ;
}
for ( int i = 0 ; i < a - > instructions - > length ; + + i ) {
struct sway_transaction_instruction * a_inst = a - > instructions - > items [ i ] ;
struct sway_transaction_instruction * b_inst = b - > instructions - > items [ i ] ;
if ( a_inst - > node ! = b_inst - > node ) {
return false ;
}
}
return true ;
}
static void transaction_progress _queue ( void ) {
static void transaction_progress ( void ) {
if ( ! server . transactions- > length ) {
if ( ! server . queued_transaction ) {
return ;
return ;
}
}
// Only the first transaction in the queue is committed, so that's the one
if ( server . queued_transaction - > num_waiting > 0 ) {
// we try to process.
struct sway_transaction * transaction = server . transactions - > items [ 0 ] ;
if ( transaction - > num_waiting ) {
return ;
return ;
}
}
transaction_apply ( transaction) ;
transaction_apply ( server . queued_transaction ) ;
transaction_destroy ( transaction) ;
transaction_destroy ( server . queued_transaction ) ;
list_del ( server . transactions , 0 ) ;
server . queued_transaction = NULL ;
if ( server . transactions - > length = = 0 ) {
if ( ! server . pending_transaction ) {
// The transaction queue is empty, so we're done.
sway_idle_inhibit_v1_check_active ( server . idle_inhibit_manager_v1 ) ;
sway_idle_inhibit_v1_check_active ( server . idle_inhibit_manager_v1 ) ;
return ;
return ;
}
}
// If there's a bunch of consecutive transactions which all apply to the
transaction_commit_pending ( ) ;
// same views, skip all except the last one.
while ( server . transactions - > length > = 2 ) {
struct sway_transaction * txn = server . transactions - > items [ 0 ] ;
struct sway_transaction * dup = NULL ;
for ( int i = 1 ; i < server . transactions - > length ; i + + ) {
struct sway_transaction * maybe_dup = server . transactions - > items [ i ] ;
if ( transaction_same_nodes ( txn , maybe_dup ) ) {
dup = maybe_dup ;
break ;
}
}
if ( dup ) {
list_del ( server . transactions , 0 ) ;
transaction_destroy ( txn ) ;
} else {
break ;
}
}
// We again commit the first transaction in the queue to process it.
transaction = server . transactions - > items [ 0 ] ;
transaction_commit ( transaction ) ;
transaction_progress_queue ( ) ;
}
}
static int handle_timeout ( void * data ) {
static int handle_timeout ( void * data ) {
@ -378,7 +365,7 @@ static int handle_timeout(void *data) {
sway_log ( SWAY_DEBUG , " Transaction %p timed out (%zi waiting) " ,
sway_log ( SWAY_DEBUG , " Transaction %p timed out (%zi waiting) " ,
transaction , transaction - > num_waiting ) ;
transaction , transaction - > num_waiting ) ;
transaction - > num_waiting = 0 ;
transaction - > num_waiting = 0 ;
transaction_progress _queue ( ) ;
transaction_progress ( ) ;
return 0 ;
return 0 ;
}
}
@ -479,6 +466,17 @@ static void transaction_commit(struct sway_transaction *transaction) {
}
}
}
}
static void transaction_commit_pending ( void ) {
if ( server . queued_transaction ) {
return ;
}
struct sway_transaction * transaction = server . pending_transaction ;
server . pending_transaction = NULL ;
server . queued_transaction = transaction ;
transaction_commit ( transaction ) ;
transaction_progress ( ) ;
}
static void set_instruction_ready (
static void set_instruction_ready (
struct sway_transaction_instruction * instruction ) {
struct sway_transaction_instruction * instruction ) {
struct sway_transaction * transaction = instruction - > transaction ;
struct sway_transaction * transaction = instruction - > transaction ;
@ -504,7 +502,7 @@ static void set_instruction_ready(
}
}
instruction - > node - > instruction = NULL ;
instruction - > node - > instruction = NULL ;
transaction_progress _queue ( ) ;
transaction_progress ( ) ;
}
}
void transaction_notify_view_ready_by_serial ( struct sway_view * view ,
void transaction_notify_view_ready_by_serial ( struct sway_view * view ,
@ -541,24 +539,20 @@ void transaction_commit_dirty(void) {
if ( ! server . dirty_nodes - > length ) {
if ( ! server . dirty_nodes - > length ) {
return ;
return ;
}
}
struct sway_transaction * transaction = transaction_create ( ) ;
if ( ! transaction ) {
if ( ! server . pending_transaction ) {
server . pending_transaction = transaction_create ( ) ;
if ( ! server . pending_transaction ) {
return ;
return ;
}
}
}
for ( int i = 0 ; i < server . dirty_nodes - > length ; + + i ) {
for ( int i = 0 ; i < server . dirty_nodes - > length ; + + i ) {
struct sway_node * node = server . dirty_nodes - > items [ i ] ;
struct sway_node * node = server . dirty_nodes - > items [ i ] ;
transaction_add_node ( transaction, node ) ;
transaction_add_node ( server. pending_ transaction, node ) ;
node - > dirty = false ;
node - > dirty = false ;
}
}
server . dirty_nodes - > length = 0 ;
server . dirty_nodes - > length = 0 ;
list_add ( server . transactions , transaction ) ;
transaction_commit_pending ( ) ;
// We only commit the first transaction added to the queue.
if ( server . transactions - > length = = 1 ) {
transaction_commit ( transaction ) ;
// Attempting to progress the queue here is useful
// if the transaction has nothing to wait for.
transaction_progress_queue ( ) ;
}
}
}