@@ -4354,6 +4354,379 @@ static nxagentScreenBoxes* nxagentGenerateScreenCrtcs(nxagentScreenSplits *split
4354
4354
return (ret );
4355
4355
}
4356
4356
4357
+ /*
4358
+ * Helper returning true of a given box intersects with a given screen,
4359
+ * otherwise and on error false.
4360
+ */
4361
+ static Bool nxagentScreenBoxIntersectsScreen (const nxagentScreenBoxesElem * box , const XineramaScreenInfo * screen_info ) {
4362
+ Bool ret = FALSE;
4363
+
4364
+ if ((!(box )) || (!(box -> box )) || (!(screen_info ))) {
4365
+ return (ret );
4366
+ }
4367
+
4368
+ /* Find out if this box has intersections with display. */
4369
+ INT32 box_width = (box -> box -> x2 - box -> box -> x1 ),
4370
+ box_height = (box -> box -> y2 - box -> box -> y1 );
4371
+ ret = intersect (box -> box -> x1 , box -> box -> y1 ,
4372
+ box_width , box_height ,
4373
+ screen_info -> x_org , screen_info -> y_org ,
4374
+ screen_info -> width , screen_info -> height ,
4375
+ NULL , NULL , NULL , NULL );
4376
+
4377
+ return (ret );
4378
+ }
4379
+
4380
+ /* Helper printing out a single screen box. */
4381
+ static char * nxagentPrintScreenBoxElem (const nxagentScreenBoxesElem * box ) {
4382
+ char * ret = NULL ;
4383
+
4384
+ BoxPtr box_data = box -> box ;
4385
+ if ((!(box )) || (!(box_data ))) {
4386
+ return (ret );
4387
+ }
4388
+
4389
+ char * construct = NULL ;
4390
+ if (-1 == asprintf (& construct , "[(%d, %d), (%d, %d)]" , box_data -> x1 , box_data -> y1 , box_data -> x2 , box_data -> y2 )) {
4391
+ return (ret );
4392
+ }
4393
+
4394
+ ret = construct ;
4395
+
4396
+ return (ret );
4397
+ }
4398
+
4399
+ /*
4400
+ * Helper comparing two box elements.
4401
+ * Returns true if both data sections match, false otherwise or on error.
4402
+ */
4403
+ static Bool nxagentCompareScreenBoxData (const BoxPtr lhs , const BoxPtr rhs ) {
4404
+ Bool ret = FALSE;
4405
+
4406
+ if ((!(lhs )) || (!(rhs ))) {
4407
+ return (ret );
4408
+ }
4409
+
4410
+ if ((lhs -> x1 == rhs -> x1 ) && (lhs -> x2 == rhs -> x2 ) && (lhs -> y1 == rhs -> y1 ) && (lhs -> y2 == rhs -> y2 )) {
4411
+ ret = TRUE;
4412
+ }
4413
+
4414
+ return (ret );
4415
+ }
4416
+
4417
+ /*
4418
+ * Helper merging boxes on a low level.
4419
+ * Returns true if merging succeeded, otherwise or on error false.
4420
+ *
4421
+ * If merging succeded, the merge_boxes list shall contain only one element:
4422
+ * the extended box representing a screen.
4423
+ *
4424
+ * In case of errors, the original list may or may not be modified.
4425
+ * Assume that the data is invalid.
4426
+ */
4427
+ static Bool nxagentMergeBoxes (nxagentScreenBoxes * all_boxes , nxagentScreenBoxes * merge_boxes ) {
4428
+ Bool ret = FALSE;
4429
+
4430
+ if ((!(all_boxes )) || (!(merge_boxes ))) {
4431
+ return (ret );
4432
+ }
4433
+
4434
+ /* Naïve approach: merge of all boxes is the bounding box. */
4435
+ BoxRec bounding_box = { 0 };
4436
+ nxagentScreenBoxesElem * cur = NULL ;
4437
+ Bool init = FALSE;
4438
+ size_t merge_boxes_count = 0 ;
4439
+ xorg_list_for_each_entry (cur , merge_boxes , entry ) {
4440
+ if (!(cur -> box )) {
4441
+ return (ret );
4442
+ }
4443
+
4444
+ if (!(init )) {
4445
+ bounding_box .x1 = cur -> box -> x1 ;
4446
+ bounding_box .x2 = cur -> box -> x2 ;
4447
+ bounding_box .y1 = cur -> box -> y1 ;
4448
+ bounding_box .y2 = cur -> box -> y2 ;
4449
+
4450
+ init = TRUE;
4451
+
4452
+ ++ merge_boxes_count ;
4453
+
4454
+ continue ;
4455
+ }
4456
+
4457
+ bounding_box .x1 = MIN (cur -> box -> x1 , bounding_box .x1 );
4458
+ bounding_box .x2 = MAX (cur -> box -> x2 , bounding_box .x2 );
4459
+ bounding_box .y1 = MIN (cur -> box -> y1 , bounding_box .y1 );
4460
+ bounding_box .y2 = MAX (cur -> box -> y2 , bounding_box .y2 );
4461
+
4462
+ ++ merge_boxes_count ;
4463
+ }
4464
+
4465
+ if (1 >= merge_boxes_count ) {
4466
+ /* Special case: empty or one-element merge list. */
4467
+ ret = TRUE;
4468
+ return (ret );
4469
+ }
4470
+
4471
+ /* Try to find a suitable merge pair. */
4472
+ cur = NULL ;
4473
+ nxagentScreenBoxesElem * merge_rhs = NULL ;
4474
+ Bool restart = TRUE;
4475
+ while (restart ) {
4476
+ restart = FALSE;
4477
+
4478
+ xorg_list_for_each_entry (cur , merge_boxes , entry ) {
4479
+ if (!(cur -> box )) {
4480
+ return (ret );
4481
+ }
4482
+
4483
+ xorg_list_for_each_entry (merge_rhs , & (cur -> entry ), entry ) {
4484
+ if (!(merge_rhs -> box )) {
4485
+ return (ret );
4486
+ }
4487
+
4488
+ if (& (merge_rhs -> entry ) == merge_boxes ) {
4489
+ /* Reached end of list. */
4490
+ merge_rhs = NULL ;
4491
+ break ;
4492
+ }
4493
+
4494
+ /* Check adjacency. */
4495
+ /* left side right side */
4496
+ if ((cur -> box -> x1 == merge_rhs -> box -> x2 ) || (cur -> box -> x2 == merge_rhs -> box -> x1 )) {
4497
+ /* Check starting y position and height. */
4498
+ if ((cur -> box -> y1 == merge_rhs -> box -> y1 ) && (cur -> box -> y2 == merge_rhs -> box -> y2 )) {
4499
+ break ;
4500
+ }
4501
+ }
4502
+
4503
+ /* top side bottom side */
4504
+ if ((cur -> box -> y1 == merge_rhs -> box -> y2 ) || (cur -> box -> y2 == merge_rhs -> box -> y1 )) {
4505
+ /* Check starting x position and width. */
4506
+ if ((cur -> box -> x1 == merge_rhs -> box -> x1 ) && (cur -> box -> x2 == merge_rhs -> box -> x2 )) {
4507
+ break ;
4508
+ }
4509
+ }
4510
+ }
4511
+
4512
+ /* cur and merge_rhs are mergeable. */
4513
+ if (merge_rhs ) {
4514
+ #ifdef DEBUG
4515
+ {
4516
+ char * box_left_str = nxagentPrintScreenBoxElem (cur );
4517
+ char * box_right_str = nxagentPrintScreenBoxElem (merge_rhs );
4518
+
4519
+ fprintf (stderr , "%s: mergeable boxes found: " , __func__ );
4520
+ if (!(box_left_str )) {
4521
+ fprintf (stderr , "box with invalid data [%p]\n" , cur );
4522
+ }
4523
+ else {
4524
+ fprintf (stderr , "%s\n" , box_left_str );
4525
+ }
4526
+
4527
+ if (!(box_right_str )) {
4528
+ fprintf (stderr , ", box with invalid data [%p]\n" , merge_rhs );
4529
+ }
4530
+ else {
4531
+ fprintf (stderr , ", %s\n" , box_right_str );
4532
+ }
4533
+
4534
+ SAFE_FREE (box_left_str );
4535
+ SAFE_FREE (box_right_str );
4536
+ }
4537
+ #endif
4538
+ cur -> box -> x1 = MIN (cur -> box -> x1 , merge_rhs -> box -> x1 );
4539
+ cur -> box -> x2 = MAX (cur -> box -> x2 , merge_rhs -> box -> x2 );
4540
+ cur -> box -> y1 = MIN (cur -> box -> y1 , merge_rhs -> box -> y1 );
4541
+ cur -> box -> y2 = MAX (cur -> box -> y2 , merge_rhs -> box -> y2 );
4542
+
4543
+ /* Delete merge_rhs box out of merge list ... */
4544
+ xorg_list_del (& (merge_rhs -> entry ));
4545
+
4546
+ /*
4547
+ * ... and mark an equivalent box in the all boxes list as obsolete.
4548
+ *
4549
+ * Note that it is not an error condition if no such box exists in the
4550
+ * all boxes list. More likely we tried to mark a box obsolete that
4551
+ * has already been merged with a different one (and now covers more
4552
+ * than one entry in the all boxes list).
4553
+ */
4554
+ if (merge_rhs -> obsolete ) {
4555
+ nxagentScreenBoxesElem * cur_obsolete = NULL ;
4556
+ xorg_list_for_each_entry (cur_obsolete , all_boxes , entry ) {
4557
+ if (nxagentCompareScreenBoxData (cur_obsolete -> box , merge_rhs -> box )) {
4558
+ cur_obsolete -> obsolete = TRUE;
4559
+
4560
+ /*
4561
+ * Set iterator to NULL and break out, this condition marks that
4562
+ * a box has been deleted out of the bigger array.
4563
+ */
4564
+ cur_obsolete = NULL ;
4565
+
4566
+ break ;
4567
+ }
4568
+ }
4569
+
4570
+ if (cur_obsolete ) {
4571
+ /* Non-NULL means that we haven't found a box to mark obsolete. */
4572
+ #ifdef WARNING
4573
+ fprintf (stderr , "%s: merged boxes from merge list, but couldn't find right-hand box in original list - box has likely already been merged into a different one.\n" , __func__ );
4574
+ #endif
4575
+ }
4576
+ }
4577
+
4578
+ /*
4579
+ * Remove merge_rhs's internal box data.
4580
+ * Since it's a deep copy, only this element will be affected.
4581
+ */
4582
+ SAFE_FREE (merge_rhs -> box );
4583
+
4584
+ /*
4585
+ * At this point, merge_rhs's data has been free()d and the box
4586
+ * element is not part of the merge_boxes lists.
4587
+ * Delete the box element.
4588
+ */
4589
+ SAFE_FREE (merge_rhs );
4590
+
4591
+ restart = TRUE;
4592
+
4593
+ break ;
4594
+ }
4595
+ else {
4596
+ #ifdef DEBUG
4597
+ char * box_str = nxagentPrintScreenBoxElem (cur );
4598
+
4599
+ fprintf (stderr , "%s: no mergeable box found for " , __func__ );
4600
+ if (box_str ) {
4601
+ fprintf (stderr , " current box %s\n" , box_str );
4602
+ }
4603
+ else {
4604
+ fprintf (stderr , " box with invalid data [%p]\n" , cur );
4605
+ }
4606
+
4607
+ SAFE_FREE (box_str );
4608
+ #endif
4609
+ }
4610
+ }
4611
+ }
4612
+
4613
+ /* All boxes merged, we should only have one left. */
4614
+ merge_boxes_count = 0 ;
4615
+ xorg_list_for_each_entry (cur , merge_boxes , entry ) {
4616
+ if (!(cur -> box )) {
4617
+ return (ret );
4618
+ }
4619
+
4620
+ ++ merge_boxes_count ;
4621
+ }
4622
+
4623
+ if (1 < merge_boxes_count ) {
4624
+ #ifdef WARNING
4625
+ fprintf (stderr , "%s: WARNING: box merge operation produced more than one box - initial merge list was not a rectangle!\n" , __func__ );
4626
+ #endif
4627
+ }
4628
+ else if (0 == merge_boxes_count ) {
4629
+ #ifdef WARNING
4630
+ fprintf (stderr , "%s: WARNING: box merge operation produced a merged box count of 0!\n" , __func__ );
4631
+ #endif
4632
+ }
4633
+ else {
4634
+ cur = NULL ;
4635
+ xorg_list_for_each_entry (cur , merge_boxes , entry ) {
4636
+ /* Just break out here directly, there should only be one box. */
4637
+ break ;
4638
+ }
4639
+
4640
+ if (nxagentCompareScreenBoxData (& bounding_box , cur -> box )) {
4641
+ #ifdef DEBUG
4642
+ fprintf ("%s: merging operations result is equal to bounding box, could have avoided complex calculations.\n" , __func__ );
4643
+ #endif
4644
+ ret = TRUE;
4645
+ }
4646
+ }
4647
+
4648
+ return (ret );
4649
+ }
4650
+
4651
+ /* Helper merging boxes that pertain to specific screen.
4652
+ *
4653
+ * In case of errors, the original list may or may not be modified.
4654
+ * Assume that the data is invalid.
4655
+ */
4656
+ static Bool nxagentMergeScreenBoxes (nxagentScreenBoxes * all_boxes , nxagentScreenBoxes * screen_boxes , const XineramaScreenInfo * screen_info , const size_t screen_count ) {
4657
+ Bool ret = FALSE;
4658
+
4659
+ if ((!(all_boxes )) || (!(screen_boxes )) || (!(screen_info )) || (!(screen_count ))) {
4660
+ return (ret );
4661
+ }
4662
+
4663
+ for (size_t i = 0 ; i < screen_count ; ++ i ) {
4664
+ /*
4665
+ * Structure holding the box elements intersecting with
4666
+ * the current screen.
4667
+ */
4668
+ nxagentScreenBoxes * cur_screen_boxes = (screen_boxes + i );
4669
+ xorg_list_init (& cur_screen_boxes );
4670
+
4671
+ nxagentScreenBoxesElem * cur_box = NULL ;
4672
+ xorg_list_for_each_entry (cur_box , all_boxes , entry ) {
4673
+ Bool cur_intersect = nxagentScreenBoxIntersectsScreen (cur_box , & (screen_info [i ]));
4674
+
4675
+ if (cur_intersect ) {
4676
+ /*
4677
+ * If a screen intersects the current box, we must:
4678
+ * - create a deep copy of this box
4679
+ * - add the copy to the screen boxes list
4680
+ * - set the obsolete flag appropriately
4681
+ * - start the low-level merge operation on the screen boxes list
4682
+ *
4683
+ * After this, assuming no error happened, the screen boxes list will
4684
+ * contain only one element: a box containing the screen area.
4685
+ */
4686
+ nxagentScreenBoxesElem * box_copy = calloc (sizeof (nxagentScreenBoxesElem ), 1 );
4687
+
4688
+ if (!(box_copy )) {
4689
+ nxagentFreeScreenBoxes (all_boxes , TRUE);
4690
+ return (ret );
4691
+ }
4692
+
4693
+ /* Create new low-level BoxRec. */
4694
+ box_copy -> box = calloc (sizeof (BoxRec ), 1 );
4695
+
4696
+ if (!(box_copy -> box )) {
4697
+ nxagentFreeScreenBoxes (cur_box , TRUE);
4698
+ nxagentFreeScreenBoxes (all_boxes , TRUE);
4699
+ return (ret );
4700
+ }
4701
+
4702
+ /* Copy BoxRec contents. */
4703
+ memmove (box_copy -> box , cur_box -> box , sizeof (BoxRec ));
4704
+
4705
+ box_copy -> obsolete = TRUE;
4706
+
4707
+ for (size_t y = (i + 1 ); y < screen_count ; ++ y ) {
4708
+ if (nxagentScreenBoxIntersectsScreen (cur_box , & (screen_info [y ]))) {
4709
+ /* Protect box, if still needed later on after merging this set. */
4710
+ box_copy -> obsolete = FALSE;
4711
+ break ;
4712
+ }
4713
+ }
4714
+
4715
+ xorg_list_append (& (box_copy -> entry ), cur_screen_boxes );
4716
+ }
4717
+ }
4718
+
4719
+ /* Actually merge the boxes. */
4720
+ if (!(nxagentMergeBoxes (all_boxes , cur_screen_boxes ))) {
4721
+ return (ret );
4722
+ }
4723
+ }
4724
+
4725
+ ret = TRUE;
4726
+
4727
+ return (ret );
4728
+ }
4729
+
4357
4730
/*
4358
4731
Destroy an output after removing it from any crtc that might reference it
4359
4732
*/
0 commit comments