@@ -4354,6 +4354,379 @@ static nxagentScreenBoxes* nxagentGenerateScreenCrtcs(nxagentScreenSplits *split
43544354 return (ret );
43554355}
43564356
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+
43574730/*
43584731 Destroy an output after removing it from any crtc that might reference it
43594732 */
0 commit comments