Window.cpp (6932B)
1 #include <blt/syscall.h> 2 #include <blt/os.h> 3 #include <stdio.h> 4 #include <win/Event.h> 5 #include "assert.h" 6 #include "Window.h" 7 8 Window::Window(int id, int eventPort, Renderer *renderer) 9 : fID(id), 10 fNextSibling(0), 11 fPreviousSibling(0), 12 fChildList(0), 13 fParent(0), 14 fIsVisible(false), 15 fEventPort(eventPort), 16 fPaintMsgSent(false), 17 fColor(0) 18 { 19 if (renderer) { 20 // I am being attached directly to a renderer. My clip 21 // region is the bounds of the renderer. 22 fGC.SetRenderer(renderer); 23 fFrame = renderer->Bounds(); 24 fVisibleRegion.Clear(); 25 fVisibleRegion.Include(fFrame); 26 fClipRegion = fVisibleRegion; 27 fGC.SetClipRegion(fClipRegion); 28 } 29 } 30 31 Window::~Window() 32 { 33 if (fParent) 34 fParent->RemoveChild(this); 35 } 36 37 Window* Window::ChildAtPoint(int x, int y) 38 { 39 // See what child is covering me at this point 40 for (Window *child = fChildList; child; child = child->fNextSibling) { 41 if (child->Frame().Contains(x, y)) 42 return child->ChildAtPoint(x - child->Frame().left, y - child->Frame().top); 43 } 44 45 return this; // I guess that's me! 46 } 47 48 void Window::UpdateClipRegion() 49 { 50 Region newClipRegion = fVisibleRegion; 51 Rect myScreenFrame = LocalToScreen(Bounds()); 52 53 // Walk the child list. It is ordered from front to back. 54 for (Window *child = fChildList; child; child = child->fNextSibling) { 55 // Ship hidden children (and effectively all their descendents). 56 if (!child->IsVisible()) { 57 Region empty; 58 child->SetVisibleRegion(empty); 59 continue; 60 } 61 62 // My children are obscured both by my siblings and theirs. 63 // Create a new region. Note that fClipRegion is initialized as 64 // my visible region (that is, parts of me that aren't clipped by 65 // my siblings). With iteration, each child window is excluded 66 // from it, so this clips my children against each other. 67 Region childClipRegion = newClipRegion; 68 Rect childScreenFrame = LocalToScreen(child->Frame()); 69 childClipRegion.ConstrainTo(childScreenFrame); 70 child->SetVisibleRegion(childClipRegion); 71 72 // I am obscured by my child windows, remove them from my clip 73 // region. 74 newClipRegion.Exclude(childScreenFrame); 75 } 76 77 // Handle exposures. 78 // 1. Invert the old clipping region to find 79 // which parts of the window were previously hidden. 80 // 2. Intersect that with the new clipping region to find areas 81 // that have become visible. 82 Region exposedRegion = fClipRegion; 83 exposedRegion.Invert(); 84 exposedRegion.Intersect(newClipRegion); 85 86 if (exposedRegion.Valid()) 87 Invalidate(exposedRegion); 88 89 // Now set the new clip region for this window. 90 fClipRegion = newClipRegion; 91 fGC.SetClipRegion(fClipRegion); 92 fGC.SetOrigin(myScreenFrame.left, myScreenFrame.top); 93 } 94 95 void Window::AddChild(const Rect &frame, Window *child) 96 { 97 child->fFrame = frame; 98 child->fGC.SetRenderer(fGC.GetRenderer()); 99 100 child->fNextSibling = fChildList; 101 child->fPreviousSibling = &fChildList; 102 if (fChildList) 103 fChildList->fPreviousSibling = &child->fNextSibling; 104 105 fChildList = child; 106 child->fParent = this; 107 if (child->IsVisible()) 108 UpdateClipRegion(); 109 } 110 111 void Window::RemoveChild(Window *window) 112 { 113 ASSERT(window->parent == this); 114 ASSERT(window->fPreviousSibling); 115 116 *window->fPreviousSibling = window->fNextSibling; 117 fParent = 0; 118 119 // Should remove all of its children 120 121 UpdateClipRegion(); 122 } 123 124 void Window::MoveToFront() 125 { 126 fParent->RemoveChild(this); 127 fParent->AddChild(fFrame, this); 128 UpdateClipRegion(); 129 } 130 131 void Window::SetVisibleRegion(const Region ®ion) 132 { 133 fVisibleRegion = region; 134 UpdateClipRegion(); 135 136 if (fInRedraw) { 137 Region drawRegion = fCurrentRedrawRegion; 138 drawRegion.Intersect(fClipRegion); 139 fGC.SetClipRegion(drawRegion); 140 } else 141 fGC.SetClipRegion(fClipRegion); 142 } 143 144 const Region& Window::ClipRegion() const 145 { 146 return fClipRegion; 147 } 148 149 void Window::MoveTo(long x, long y) 150 { 151 fFrame.OffsetTo(x, y); 152 UpdateClipRegion(); 153 } 154 155 void Window::ResizeTo(long width, long height) 156 { 157 fFrame.right = fFrame.left + width; 158 fFrame.bottom = fFrame.top + height; 159 UpdateClipRegion(); 160 } 161 162 void Window::Invalidate(const Region ®ion) 163 { 164 // Erase background 165 for (int rect = 0; rect < region.CountRects(); rect++) { 166 const Rect &clipRect = region.RectAt(rect); 167 fGC.GetRenderer()->FillRect(clipRect.left, clipRect.top, clipRect.right, 168 clipRect.bottom, Color()); 169 } 170 171 fInvalidRegion.Include(region); 172 if (!fPaintMsgSent) { 173 Event paintEvent; 174 paintEvent.what = EVT_PAINT; 175 PostEvent(&paintEvent); 176 fPaintMsgSent = true; 177 } 178 } 179 180 void Window::Invalidate(const Rect &rect) 181 { 182 Rect screenRect(LocalToScreen(rect)); 183 184 // Erase background 185 Region eraseRegion(fVisibleRegion); 186 Region invalRegion; 187 invalRegion.Include(screenRect); 188 eraseRegion.Intersect(invalRegion); 189 for (int index = 0; index < eraseRegion.CountRects(); index++) { 190 const Rect &clipRect = eraseRegion.RectAt(index); 191 fGC.GetRenderer()->FillRect(clipRect.left, clipRect.top, clipRect.right, 192 clipRect.bottom, Color()); 193 } 194 195 // The rect is assumed to be in window coordinates 196 fInvalidRegion.Include(screenRect); 197 if (!fPaintMsgSent) { 198 Event paintEvent; 199 paintEvent.what = EVT_PAINT; 200 PostEvent(&paintEvent); 201 fPaintMsgSent = true; 202 } 203 } 204 205 GraphicsContext& Window::GC() 206 { 207 return fGC; 208 } 209 210 void Window::BeginPaint(Rect &out_invalidRect) 211 { 212 fPaintMsgSent = false; 213 fInRedraw = true; 214 fCurrentRedrawRegion = fInvalidRegion; 215 fInvalidRegion.Clear(); 216 217 Region drawRegion = fCurrentRedrawRegion; 218 drawRegion.Intersect(fClipRegion); 219 out_invalidRect = ScreenToLocal(drawRegion.Bounds()); 220 fGC.SetClipRegion(drawRegion); 221 } 222 223 void Window::EndPaint() 224 { 225 fInRedraw = false; 226 } 227 228 bool Window::IsVisible() const 229 { 230 return fIsVisible; 231 } 232 233 char Window::Color() const 234 { 235 return fColor; 236 } 237 238 void Window::SetColor(char c) 239 { 240 fColor = c; 241 } 242 243 void Window::Show() 244 { 245 if (!fIsVisible) { 246 fIsVisible = true; 247 if (fParent) 248 fParent->UpdateClipRegion(); 249 } 250 } 251 252 void Window::Hide() 253 { 254 if (fIsVisible) { 255 fIsVisible = false; 256 if (fParent) 257 fParent->UpdateClipRegion(); 258 } 259 } 260 261 void Window::PostEvent(Event *event) 262 { 263 event->target = fID; 264 265 msg_hdr_t header; 266 header.src = fEventPort; // May break someday 267 header.dst = fEventPort; 268 header.data = event; 269 header.size = sizeof(Event); 270 old_port_send(&header); 271 } 272 273 Rect Window::LocalToScreen(const Rect &inRect) const 274 { 275 Rect outRect = inRect; 276 for (const Window *window = this; window; window = window->fParent) 277 outRect.OffsetBy(window->fFrame.left, window->fFrame.top); 278 279 return outRect; 280 } 281 282 Rect Window::ScreenToLocal(const Rect &inRect) const 283 { 284 Rect outRect = inRect; 285 for (const Window *window = this; window; window = window->fParent) 286 outRect.OffsetBy(-window->fFrame.left, -window->fFrame.top); 287 288 return outRect; 289 } 290 291 void Window::DumpChildList(int level) 292 { 293 for (int i = 0; i < level; i++) 294 printf(" | "); 295 296 Rect frame = Frame(); 297 printf(" + %d %d %d %d\n", frame.left, frame.top, frame.right, frame.bottom); 298 for (Window *child = fChildList; child; child = child->fNextSibling) 299 child->DumpChildList(level + 1); 300 } 301 302 303