summaryrefslogtreecommitdiff
path: root/recordmydesktop/src/rmd_rectinsert.c
diff options
context:
space:
mode:
authorenselic <enselic@f606c939-3180-4ac9-a4b8-4b8779d57d0a>2008-09-14 13:06:20 +0000
committerenselic <enselic@f606c939-3180-4ac9-a4b8-4b8779d57d0a>2008-09-14 13:06:20 +0000
commite5cdc6d4fbec00a52d06414ca243664bb8b40942 (patch)
tree60f4145527722c135e72cbe451b63f7499dd32a5 /recordmydesktop/src/rmd_rectinsert.c
parent187945d42050c99c614ccf76099944b338461a19 (diff)
src/*.[ch]: Rename files so that the name becomes
rmd_some_file.[ch]. The exceptions are recordmydesktop.c which is the main file and skeleton.[ch] which are external files. src/Makefile.am: Adapt. git-svn-id: https://recordmydesktop.svn.sourceforge.net/svnroot/recordmydesktop/trunk@546 f606c939-3180-4ac9-a4b8-4b8779d57d0a
Diffstat (limited to 'recordmydesktop/src/rmd_rectinsert.c')
-rw-r--r--recordmydesktop/src/rmd_rectinsert.c535
1 files changed, 535 insertions, 0 deletions
diff --git a/recordmydesktop/src/rmd_rectinsert.c b/recordmydesktop/src/rmd_rectinsert.c
new file mode 100644
index 0000000..df43e15
--- /dev/null
+++ b/recordmydesktop/src/rmd_rectinsert.c
@@ -0,0 +1,535 @@
+/******************************************************************************
+* recordMyDesktop *
+*******************************************************************************
+* *
+* Copyright (C) 2006,2007,2008 John Varouhakis *
+* *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
+* *
+* *
+* *
+* For further information contact me at johnvarouhakis@gmail.com *
+******************************************************************************/
+
+#include "config.h"
+
+#include "rmd_rectinsert.h"
+#include "rmd_types.h"
+
+
+/**
+* Collide two rectangles and dictate most sane action for insertion,
+* as well as provide the updated rectangle(s)
+* \param wgeom1 resident rectangle
+*
+* \param wgeom2 New rectangle
+*
+* \param wgeom_return Pointer to rectangles to be inserted
+*
+* \param ngeoms number of entries in wgeom_return
+*
+* \retval 0 No collision
+*
+* \retval 1 wgeom1 is covered by wgeom2
+*
+* \retval 2 wgeom2 is covered by wgeom1
+*
+* \retval -1 wgeom1 was broken (new is picked up in wgeom_return)
+*
+* \retval -2 wgeom2 was broken (new is picked up in wgeom_return)
+*
+* \retval -10 Grouping the two geoms is possible
+*
+*/
+static int CollideRects(WGeometry *wgeom1,
+ WGeometry *wgeom2,
+ WGeometry **wgeom_return,
+ int *ngeoms) {
+ //1 fits in 2
+ if((wgeom1->x>=wgeom2->x)&&
+ (wgeom1->x+wgeom1->width<=wgeom2->x+wgeom2->width)&&
+ (wgeom1->y>=wgeom2->y)&&
+ (wgeom1->y+wgeom1->height<=wgeom2->y+wgeom2->height)){
+ *ngeoms=0;
+ return 1;
+ }
+ //2 fits in 1
+ else if((wgeom2->x>=wgeom1->x)&&
+ (wgeom2->x+wgeom2->width<=wgeom1->x+wgeom1->width)&&
+ (wgeom2->y>=wgeom1->y)&&
+ (wgeom2->y+wgeom2->height<=wgeom1->y+wgeom1->height)){
+ *ngeoms=0;
+ return 2;
+ }
+ //no collision
+ else if((wgeom1->x+wgeom1->width<wgeom2->x)||
+ (wgeom2->x+wgeom2->width<wgeom1->x)||
+ (wgeom1->y+wgeom1->height<wgeom2->y)||
+ (wgeom2->y+wgeom2->height<wgeom1->y)){
+ *ngeoms=0;
+ return 0;
+ }
+ else{
+//overlapping points are considered enclosed
+//this happens because libxdamage may generate many events for one change
+//and some of them may be in the the exact same region
+//so identical rects would be considered not colliding
+//in order though to avoid endless recursion on the RectInsert
+//function should always start at the next element(which is logical since
+//if any rect makes it to a points none of it's part collides with previous
+//nodes on the list, too)
+ int x1[2]={wgeom1->x,wgeom1->x+wgeom1->width};
+ int y1[2]={wgeom1->y,wgeom1->y+wgeom1->height};
+ int x2[2]={wgeom2->x,wgeom2->x+wgeom2->width};
+ int y2[2]={wgeom2->y,wgeom2->y+wgeom2->height};
+ int enclosed[2][4],tot1,tot2;
+ enclosed[0][0]=(((x1[0]>=x2[0])&&(x1[0]<=x2[1])&&
+ (y1[0]>=y2[0])&&(y1[0]<=y2[1]))?1:0);
+ enclosed[0][1]=(((x1[1]>=x2[0])&&(x1[1]<=x2[1])&&
+ (y1[0]>=y2[0])&&(y1[0]<=y2[1]))?1:0);
+ enclosed[0][2]=(((x1[0]>=x2[0])&&(x1[0]<=x2[1])&&
+ (y1[1]>=y2[0])&&(y1[1]<=y2[1]))?1:0);
+ enclosed[0][3]=(((x1[1]>=x2[0])&&(x1[1]<=x2[1])&&
+ (y1[1]>=y2[0])&&(y1[1]<=y2[1]))?1:0);
+ enclosed[1][0]=(((x2[0]>=x1[0])&&(x2[0]<=x1[1])&&
+ (y2[0]>=y1[0])&&(y2[0]<=y1[1]))?1:0);
+ enclosed[1][1]=(((x2[1]>=x1[0])&&(x2[1]<=x1[1])&&
+ (y2[0]>=y1[0])&&(y2[0]<=y1[1]))?1:0);
+ enclosed[1][2]=(((x2[0]>=x1[0])&&(x2[0]<=x1[1])&&
+ (y2[1]>=y1[0])&&(y2[1]<=y1[1]))?1:0);
+ enclosed[1][3]=(((x2[1]>=x1[0])&&(x2[1]<=x1[1])&&
+ (y2[1]>=y1[0])&&(y2[1]<=y1[1]))?1:0);
+ tot1=enclosed[0][0]+enclosed[0][1]+enclosed[0][2]+enclosed[0][3];
+ tot2=enclosed[1][0]+enclosed[1][1]+enclosed[1][2]+enclosed[1][3];
+ if((tot1==2)&&(tot2==2)){//same width or height, which is the best case
+ //group
+ if((enclosed[1][0]&&enclosed[1][1])&&
+ (wgeom1->width==wgeom2->width)){
+ wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ *ngeoms=1;
+ wgeom_return[0]->x=wgeom1->x;
+ wgeom_return[0]->y=wgeom1->y;
+ wgeom_return[0]->width=wgeom1->width;
+ wgeom_return[0]->height=wgeom2->height+wgeom2->y-wgeom1->y;
+ return -10;
+ }
+ else if((enclosed[1][0]&&enclosed[1][2])&&
+ (wgeom1->height==wgeom2->height)){
+ *ngeoms=1;
+ wgeom_return[0]->x=wgeom1->x;
+ wgeom_return[0]->y=wgeom1->y;
+ wgeom_return[0]->width=wgeom2->width+wgeom2->x-wgeom1->x;
+ wgeom_return[0]->height=wgeom1->height;
+ return -10;
+ }
+ else if((enclosed[1][3]&&enclosed[1][1])&&
+ (wgeom1->height==wgeom2->height)){
+ *ngeoms=1;
+ wgeom_return[0]->x=wgeom2->x;
+ wgeom_return[0]->y=wgeom2->y;
+ wgeom_return[0]->width=wgeom1->width+wgeom1->x-wgeom2->x;
+ wgeom_return[0]->height=wgeom2->height;
+ return -10;
+ }
+ else if((enclosed[1][3]&&enclosed[1][2])&&
+ (wgeom1->width==wgeom2->width)){
+ *ngeoms=1;
+ wgeom_return[0]->x=wgeom2->x;
+ wgeom_return[0]->y=wgeom2->y;
+ wgeom_return[0]->width=wgeom2->width;
+ wgeom_return[0]->height=wgeom1->height+wgeom1->y-wgeom2->y;
+ return -10;
+ }
+ //if control reaches here therewasn't a group and we go on
+ }
+ if(tot2==2){
+ //break geom2
+ wgeom_return[0]->x=wgeom2->x;
+ wgeom_return[0]->y=wgeom2->y;
+ wgeom_return[0]->width=wgeom2->width;
+ wgeom_return[0]->height=wgeom2->height;
+ *ngeoms=1;
+ if(enclosed[1][0]&&enclosed[1][1]){
+ wgeom_return[0]->y=y1[1];
+ wgeom_return[0]->height-=y1[1]-y2[0];
+ }
+ else if(enclosed[1][0]&&enclosed[1][2]){
+ wgeom_return[0]->x=x1[1];
+ wgeom_return[0]->width-=x1[1]-x2[0];
+ }
+ else if(enclosed[1][3]&&enclosed[1][1])
+ wgeom_return[0]->width-=x2[1]-x1[0];
+ else if(enclosed[1][3]&&enclosed[1][2])
+ wgeom_return[0]->height-=y2[1]-y1[0];
+ return -2;
+ }
+ else if(tot1==2){
+ //if the first one breaks(which is already inserted)
+ //then we reenter the part that was left and the one
+ //that was to be inserted
+ wgeom_return[1]->x=wgeom2->x;
+ wgeom_return[1]->y=wgeom2->y;
+ wgeom_return[1]->width=wgeom2->width;
+ wgeom_return[1]->height=wgeom2->height;
+ wgeom_return[0]->x=wgeom1->x;
+ wgeom_return[0]->y=wgeom1->y;
+ wgeom_return[0]->width=wgeom1->width;
+ wgeom_return[0]->height=wgeom1->height;
+ *ngeoms=1;
+ if(enclosed[0][0]&&enclosed[0][1]){
+ wgeom_return[0]->y=y2[1];
+ wgeom_return[0]->height-=y2[1]-y1[0];
+ }
+ else if(enclosed[0][0]&&enclosed[0][2]){
+ wgeom_return[0]->x=x2[1];
+ wgeom_return[0]->width-=x2[1]-x1[0];
+ }
+ else if(enclosed[0][3]&&enclosed[0][1])
+ wgeom_return[0]->width-=x1[1]-x2[0];
+ else if(enclosed[0][3]&&enclosed[0][2])
+ wgeom_return[0]->height-=y1[1]-y2[0];
+ return -1;
+
+ }
+ else if(tot2==1){ //in which case there is also tot1==1
+ //but we rather not break that
+ //break geom2 in two
+ *ngeoms=2;
+ if(enclosed[1][0]){
+//first
+ wgeom_return[0]->x=x1[1];
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->width=wgeom2->width-x1[1]+x2[0];
+ wgeom_return[0]->height=wgeom2->height;
+//second
+ wgeom_return[1]->x=x2[0];
+ wgeom_return[1]->y=y1[1];
+ wgeom_return[1]->width=x1[1]-x2[0];
+ wgeom_return[1]->height=wgeom2->height-y1[1]+y2[0];
+ }
+ else if(enclosed[1][1]){
+//first
+ wgeom_return[0]->x=x2[0];
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->width=wgeom2->width-x2[1]+x1[0];
+ wgeom_return[0]->height=wgeom2->height;
+//second
+ wgeom_return[1]->x=x1[0];
+ wgeom_return[1]->y=y1[1];
+ wgeom_return[1]->width=x2[1]-x1[0];
+ wgeom_return[1]->height=wgeom2->height-y1[1]+y2[0];
+ }
+ else if(enclosed[1][2]){
+//first(same as [1][0])
+ wgeom_return[0]->x=x1[1];
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->width=wgeom2->width-x1[1]+x2[0];
+ wgeom_return[0]->height=wgeom2->height;
+//second
+ wgeom_return[1]->x=x2[0];
+ wgeom_return[1]->y=y2[0];
+ wgeom_return[1]->width=x1[1]-x2[0];
+ wgeom_return[1]->height=wgeom2->height-y2[1]+y1[0];
+ }
+ else if(enclosed[1][3]){
+//first(same as [1][1])
+ wgeom_return[0]->x=x2[0];
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->width=wgeom2->width-x2[1]+x1[0];
+ wgeom_return[0]->height=wgeom2->height;
+//second
+ wgeom_return[1]->x=x1[0];
+ wgeom_return[1]->y=y2[0];
+ wgeom_return[1]->width=x2[1]-x1[0];
+ wgeom_return[1]->height=wgeom2->height-y2[1]+y1[0];
+ }
+ return -2;
+ }
+ else{//polygons collide but no point of one is in the other
+ //so we just keep the two parts of geom2 that are outside geom1
+
+ //break geom2 in two
+ //two cases:
+ //geom2 crossing vertically geom1
+ //and geom2 crossing horizontally geom1
+ //The proper one can be found by simply checking x,y positions
+ *ngeoms=2;
+ if(wgeom2->y<wgeom1->y){
+ //common
+ wgeom_return[0]->x=wgeom_return[1]->x=x2[0];
+ wgeom_return[0]->width=wgeom_return[1]->width=wgeom2->width;
+
+ wgeom_return[0]->y=y2[0];
+ wgeom_return[0]->height=wgeom2->height-y2[1]+y1[0];
+ wgeom_return[1]->y=y1[1];
+ wgeom_return[1]->height=y2[1]-y1[1];
+ }
+ else{
+ //common
+ wgeom_return[0]->y=wgeom_return[1]->y=y2[0];
+ wgeom_return[0]->height=wgeom_return[1]->height=wgeom2->height;
+
+ wgeom_return[0]->x=x2[0];
+ wgeom_return[0]->width=wgeom2->width-x2[1]+x1[0];
+ wgeom_return[1]->x=x1[1];
+ wgeom_return[1]->width=x2[1]-x1[1];
+ }
+ return -2;
+ }
+ }
+}
+
+int RectInsert(RectArea **root,WGeometry *wgeom){
+
+ int total_insertions=0;
+ RectArea *temp=NULL,*newnode=(RectArea *)malloc(sizeof(RectArea));
+ //align
+ //we do need to know boundaries
+ wgeom->width+=(wgeom->width%2)|(wgeom->x%2);
+ wgeom->height+=(wgeom->height%2)|(wgeom->y%2);
+ wgeom->width+=(wgeom->width%2);
+ wgeom->height+=(wgeom->height%2);
+ wgeom->x-=wgeom->x%2;
+ wgeom->y-=wgeom->y%2;
+// fprintf(stderr," %d %d %d %d\n",wgeom->x,
+
+ newnode->geom.x=wgeom->x;
+ newnode->geom.y=wgeom->y;
+ newnode->geom.width=wgeom->width;
+ newnode->geom.height=wgeom->height;
+ newnode->prev=newnode->next=NULL;
+ if(*root==NULL){
+ *root=newnode;
+ total_insertions=1;
+ }
+ else{
+ WGeometry *wgeom_return[2];
+ wgeom_return[0]=(WGeometry *)malloc(sizeof(WGeometry));
+ wgeom_return[1]=(WGeometry *)malloc(sizeof(WGeometry));
+
+ int ngeoms=0,insert_ok=1,i=0;
+ temp=*root;
+ while(insert_ok){ //if something is broken list does not procceed
+ //(except on -1 collres case)
+ int collres=CollideRects(&(temp->geom),wgeom,wgeom_return,&ngeoms);
+ if((!collres))
+ insert_ok=1;
+ else{
+ for(i=0;i<ngeoms;i++){
+ wgeom_return[i]->width+=(wgeom_return[i]->width%2)|
+ (wgeom_return[i]->x%2);
+ wgeom_return[i]->height+=(wgeom_return[i]->height%2)|
+ (wgeom_return[i]->y%2);
+ wgeom_return[i]->width+=(wgeom_return[i]->width%2);
+ wgeom_return[i]->height+=(wgeom_return[i]->height%2);
+ wgeom_return[i]->x-=wgeom_return[i]->x%2;
+ wgeom_return[i]->y-=wgeom_return[i]->y%2;
+ }
+ insert_ok=0;
+ switch(collres){
+ case 1://remove current node,reinsert new one
+ total_insertions--;
+ if(temp->prev!=NULL){//no root
+ if(temp->next!=NULL){//
+ RectArea *temp1=temp->next;
+ temp->prev->next=temp->next;
+ temp->next->prev=temp->prev;
+ free(temp);
+ if((wgeom->width>0)&&(wgeom->height>0))
+ total_insertions+=RectInsert(&temp1,wgeom);
+ }
+ else{
+ temp->prev->next=newnode;
+ newnode->prev=temp->prev;
+ total_insertions++;
+ free(temp);
+ }
+ }
+ else{//root
+ if((*root)->next!=NULL){
+ (*root)=(*root)->next;
+ (*root)->prev=NULL;
+ if((wgeom->width>0)&&(wgeom->height>0))
+ total_insertions+=RectInsert(root,wgeom);
+ }
+ else if((wgeom->width>0)&&(wgeom->height>0)){
+ *root=newnode;
+ total_insertions++;
+ }
+ else{
+ *root=NULL;
+ total_insertions++;
+ }
+ free(temp);
+ }
+ break;
+ case 2://done,area is already covered
+ free(newnode);
+ break;
+ case -1://current node is broken and reinserted
+ //(in same pos)
+ //newnode is also reinserted
+ if((wgeom_return[0]->width>0)&&
+ (wgeom_return[0]->height>0)){
+ temp->geom.x=wgeom_return[0]->x;
+ temp->geom.y=wgeom_return[0]->y;
+ temp->geom.width=wgeom_return[0]->width;
+ temp->geom.height=wgeom_return[0]->height;
+ if(temp->next==NULL){
+ temp->next=newnode;
+ newnode->prev=temp;
+ total_insertions++;
+ }
+ else{
+ insert_ok=1;
+ }
+ }
+ else{//it might happen that the old and now broken node
+ //is of zero width or height
+ //(so it isn't reinserted)
+ if((temp->prev==NULL)&&(temp->next!=NULL)){
+ *root=(*root)->next;
+ (*root)->prev=NULL;
+ }
+ else if((temp->next==NULL)&&(temp->prev!=NULL)){
+ temp->prev->next=newnode;
+ newnode->prev=temp->prev;
+ }
+ else if((temp->next==NULL)&&(temp->prev==NULL))
+ (*root)=newnode;
+ else{
+ total_insertions--;
+ temp->next->prev=temp->prev;
+ temp->prev->next=temp->next;
+ total_insertions+=RectInsert(&temp->next,
+ wgeom);
+ }
+ free(temp);
+ }
+ break;
+ case -2://new is broken and reinserted
+ if(temp->next==NULL){
+ total_insertions+=ngeoms;
+ newnode->geom.x=wgeom_return[0]->x;
+ newnode->geom.y=wgeom_return[0]->y;
+ newnode->geom.width=wgeom_return[0]->width;
+ newnode->geom.height=wgeom_return[0]->height;
+ temp->next=newnode;
+ newnode->prev=temp;
+ if(ngeoms>1){
+ RectArea *newnode1=
+ (RectArea *)malloc(sizeof(RectArea));
+
+ newnode1->geom.x=wgeom_return[1]->x;
+ newnode1->geom.y=wgeom_return[1]->y;
+ newnode1->geom.width=wgeom_return[1]->width;
+ newnode1->geom.height=wgeom_return[1]->height;
+ newnode->next=newnode1;
+ newnode1->prev=newnode;
+ newnode1->next=NULL;
+ }
+ }
+ else{
+ for(i=0;i<ngeoms;i++){
+ if((wgeom_return[i]->width>0)&&
+ (wgeom_return[i]->height>0))
+ total_insertions+=
+ RectInsert(&temp->next,wgeom_return[i]);
+ }
+ }
+ break;
+ case -10://grouped
+ if(temp->prev==NULL){
+ if(temp->next==NULL){//empty list
+ newnode->geom.x=wgeom_return[0]->x;
+ newnode->geom.y=wgeom_return[0]->y;
+ newnode->geom.width=wgeom_return[0]->width;
+ newnode->geom.height=
+ wgeom_return[0]->height;
+
+ *root=newnode;
+ free(temp);
+ }
+ else{
+ total_insertions--;
+ *root=temp->next;
+ (*root)->prev=NULL;
+ free(temp);
+ if((wgeom_return[0]->width>0)&&
+ (wgeom_return[0]->height>0))
+ total_insertions+=
+ RectInsert(root,wgeom_return[0]);
+ }
+ }
+ else if(temp->next==NULL){//last, enter anyway
+ newnode->geom.x=wgeom_return[0]->x;
+ newnode->geom.y=wgeom_return[0]->y;
+ newnode->geom.width=wgeom_return[0]->width;
+ newnode->geom.height=wgeom_return[0]->height;
+ temp->prev->next=newnode;
+ newnode->prev=temp->prev;
+ free(temp);
+ }
+ else{//remove node and reinsert, starting where we were
+ total_insertions--;
+ RectArea *temp1=temp->next;
+ temp->prev->next=temp->next;
+ temp->next->prev=temp->prev;
+ free(temp);
+ if((wgeom_return[0]->width>0)&&
+ (wgeom_return[0]->height>0))
+ total_insertions+=
+ RectInsert(&temp1,wgeom_return[0]);
+ }
+ break;
+ }
+ }
+ if(insert_ok){
+ if(temp->next==NULL){
+ temp->next=newnode;
+ newnode->prev=temp;
+ total_insertions++;
+ break;
+ }
+ else{
+ temp=temp->next;
+ }
+ }
+ else{
+ break;
+ }
+ };
+
+ free(wgeom_return[0]);
+ free(wgeom_return[1]);
+ }
+ return total_insertions;
+}
+
+void ClearList(RectArea **root){
+
+ RectArea *temp;
+ temp=*root;
+ if(temp!=NULL){
+ while(temp->next!=NULL){
+ temp=temp->next;
+ free(temp->prev);
+
+ }
+ free(temp);
+ *root=NULL;
+ }
+}
© All Rights Reserved