OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
9 #include <X11/Xatom.h> | 9 #include <X11/Xatom.h> |
10 #include <X11/XKBlib.h> | 10 #include <X11/XKBlib.h> |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 0, 0, // x, y | 142 0, 0, // x, y |
143 WIDTH, HEIGHT, | 143 WIDTH, HEIGHT, |
144 0, // border width | 144 0, // border width |
145 0, // border value | 145 0, // border value |
146 0); // background value | 146 0); // background value |
147 } | 147 } |
148 this->mapWindowAndWait(); | 148 this->mapWindowAndWait(); |
149 fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL); | 149 fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL); |
150 } | 150 } |
151 | 151 |
152 | |
153 void SkOSWindow::post_linuxevent() { | |
154 // Put an event in the X queue to fire an SkEvent. | |
155 if (NULL == fUnixWindow.fDisplay) { | |
156 return; | |
157 } | |
158 XClientMessageEvent event; | |
159 event.type = ClientMessage; | |
160 Atom myAtom(0); | |
161 event.message_type = myAtom; | |
162 event.format = 32; | |
163 event.data.l[0] = 0; | |
164 XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0, | |
165 (XEvent*) &event); | |
166 XFlush(fUnixWindow.fDisplay); | |
167 } | |
168 | |
169 static unsigned getModi(const XEvent& evt) { | 152 static unsigned getModi(const XEvent& evt) { |
170 static const struct { | 153 static const struct { |
171 unsigned fXMask; | 154 unsigned fXMask; |
172 unsigned fSkMask; | 155 unsigned fSkMask; |
173 } gModi[] = { | 156 } gModi[] = { |
174 // X values found by experiment. Is there a better way? | 157 // X values found by experiment. Is there a better way? |
175 { 1, kShift_SkModifierKey }, | 158 { 1, kShift_SkModifierKey }, |
176 { 4, kControl_SkModifierKey }, | 159 { 4, kControl_SkModifierKey }, |
177 { 8, kOption_SkModifierKey }, | 160 { 8, kOption_SkModifierKey }, |
178 }; | 161 }; |
179 | 162 |
180 unsigned modi = 0; | 163 unsigned modi = 0; |
181 for (size_t i = 0; i < SK_ARRAY_COUNT(gModi); ++i) { | 164 for (size_t i = 0; i < SK_ARRAY_COUNT(gModi); ++i) { |
182 if (evt.xkey.state & gModi[i].fXMask) { | 165 if (evt.xkey.state & gModi[i].fXMask) { |
183 modi |= gModi[i].fSkMask; | 166 modi |= gModi[i].fSkMask; |
184 } | 167 } |
185 } | 168 } |
186 return modi; | 169 return modi; |
187 } | 170 } |
188 | 171 |
| 172 static SkMSec gTimerDelay; |
| 173 |
| 174 static void MyXNextEventWithDelay(Display* dsp, XEvent* evt) { |
| 175 SkMSec ms = gTimerDelay; |
| 176 if (ms > 0) { |
| 177 int x11_fd = ConnectionNumber(dsp); |
| 178 fd_set input_fds; |
| 179 FD_ZERO(&input_fds); |
| 180 FD_SET(x11_fd, &input_fds); |
| 181 |
| 182 timeval tv; |
| 183 tv.tv_sec = ms / 1000; // seconds |
| 184 tv.tv_usec = (ms % 1000) * 1000; // microseconds |
| 185 |
| 186 (void)select(x11_fd + 1, &input_fds, NULL, NULL, &tv); |
| 187 } |
| 188 |
| 189 if (XPending(dsp)) { |
| 190 XNextEvent(dsp, evt); |
| 191 } |
| 192 } |
| 193 |
| 194 SkOSWindow::NextXEventResult SkOSWindow::nextXEvent() { |
| 195 XEvent evt; |
| 196 Display* dsp = fUnixWindow.fDisplay; |
| 197 |
| 198 MyXNextEventWithDelay(fUnixWindow.fDisplay, &evt); |
| 199 |
| 200 switch (evt.type) { |
| 201 case Expose: |
| 202 if (0 == evt.xexpose.count) { |
| 203 return kPaintRequest_NextXEventResult; |
| 204 } |
| 205 break; |
| 206 case ConfigureNotify: |
| 207 this->resize(evt.xconfigure.width, evt.xconfigure.height); |
| 208 break; |
| 209 case ButtonPress: |
| 210 if (evt.xbutton.button == Button1) |
| 211 this->handleClick(evt.xbutton.x, evt.xbutton.y, |
| 212 SkView::Click::kDown_State, NULL, getModi(evt)); |
| 213 break; |
| 214 case ButtonRelease: |
| 215 if (evt.xbutton.button == Button1) |
| 216 this->handleClick(evt.xbutton.x, evt.xbutton.y, |
| 217 SkView::Click::kUp_State, NULL, getModi(evt)); |
| 218 break; |
| 219 case MotionNotify: |
| 220 this->handleClick(evt.xmotion.x, evt.xmotion.y, |
| 221 SkView::Click::kMoved_State, NULL, getModi(evt)); |
| 222 break; |
| 223 case KeyPress: { |
| 224 int shiftLevel = (evt.xkey.keycode & ShiftMask) ? 1 : 0; |
| 225 KeySym keysym = XkbKeycodeToKeysym(dsp, evt.xkey.keycode, |
| 226 0, shiftLevel); |
| 227 if (keysym == XK_Escape) { |
| 228 return kQuitRequest_NextXEventResult; |
| 229 } |
| 230 this->handleKey(XKeyToSkKey(keysym)); |
| 231 long uni = keysym2ucs(keysym); |
| 232 if (uni != -1) { |
| 233 this->handleChar((SkUnichar) uni); |
| 234 } |
| 235 break; |
| 236 } |
| 237 case KeyRelease: |
| 238 this->handleKeyUp(XKeyToSkKey(XkbKeycodeToKeysym(dsp, evt.xkey.keyco
de, 0, 0))); |
| 239 break; |
| 240 default: |
| 241 // Do nothing for other events |
| 242 break; |
| 243 } |
| 244 return kContinue_NextXEventResult; |
| 245 } |
| 246 |
189 void SkOSWindow::loop() { | 247 void SkOSWindow::loop() { |
190 Display* dsp = fUnixWindow.fDisplay; | 248 Display* dsp = fUnixWindow.fDisplay; |
191 if (NULL == dsp) { | 249 if (NULL == dsp) { |
192 return; | 250 return; |
193 } | 251 } |
194 XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK); | 252 XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK); |
195 | 253 |
196 bool loop = true; | 254 bool needPaint = false; |
197 XEvent evt; | 255 |
198 while (loop) { | 256 for (;;) { |
199 XNextEvent(dsp, &evt); | 257 if (this->isDirty()) { |
200 switch (evt.type) { | 258 this->update(NULL); |
201 case Expose: | 259 needPaint = true; |
202 if (evt.xexpose.count == 0) | 260 } |
203 this->inval(NULL); | 261 if (needPaint) { |
204 break; | 262 this->doPaint(); |
205 case ConfigureNotify: | 263 needPaint = false; |
206 this->resize(evt.xconfigure.width, evt.xconfigure.height); | 264 } |
207 break; | 265 if (gTimerDelay) { |
208 case ButtonPress: | 266 SkEvent::ServiceQueueTimer(); |
209 if (evt.xbutton.button == Button1) | 267 } |
210 this->handleClick(evt.xbutton.x, evt.xbutton.y, | 268 bool moreToDo = SkEvent::ProcessEvent() || needPaint || this->isDirty(); |
211 SkView::Click::kDown_State, NULL, getModi(evt)); | 269 if (XPending(dsp) || !moreToDo) { |
212 break; | 270 switch (this->nextXEvent()) { |
213 case ButtonRelease: | 271 case kContinue_NextXEventResult: |
214 if (evt.xbutton.button == Button1) | |
215 this->handleClick(evt.xbutton.x, evt.xbutton.y, | |
216 SkView::Click::kUp_State, NULL, getModi(evt)); | |
217 break; | |
218 case MotionNotify: | |
219 this->handleClick(evt.xmotion.x, evt.xmotion.y, | |
220 SkView::Click::kMoved_State, NULL, getModi(evt)); | |
221 break; | |
222 case KeyPress: { | |
223 KeySym keysym = XkbKeycodeToKeysym(dsp, evt.xkey.keycode, 0, 0); | |
224 //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, X
KeycodeToKeysym(dsp, evt.xkey.keycode, 0)); | |
225 if (keysym == XK_Escape) { | |
226 loop = false; | |
227 break; | 272 break; |
228 } | 273 case kPaintRequest_NextXEventResult: |
229 this->handleKey(XKeyToSkKey(keysym)); | 274 needPaint = true; |
230 long uni = keysym2ucs(keysym); | 275 break; |
231 if (uni != -1) { | 276 case kQuitRequest_NextXEventResult: |
232 this->handleChar((SkUnichar) uni); | 277 return; |
233 } | |
234 break; | |
235 } | 278 } |
236 case KeyRelease: | |
237 //SkDebugf("released key %i\n", evt.xkey.keycode); | |
238 this->handleKeyUp(XKeyToSkKey(XkbKeycodeToKeysym(dsp, evt.xkey.k
eycode, 0, 0))); | |
239 break; | |
240 case ClientMessage: | |
241 if (SkEvent::ProcessEvent()) { | |
242 this->post_linuxevent(); | |
243 } | |
244 break; | |
245 default: | |
246 // Do nothing for other events | |
247 break; | |
248 } | 279 } |
249 } | 280 } |
250 } | 281 } |
251 | 282 |
252 void SkOSWindow::mapWindowAndWait() { | 283 void SkOSWindow::mapWindowAndWait() { |
253 SkASSERT(NULL != fUnixWindow.fDisplay); | 284 SkASSERT(NULL != fUnixWindow.fDisplay); |
254 Display* dsp = fUnixWindow.fDisplay; | 285 Display* dsp = fUnixWindow.fDisplay; |
255 Window win = fUnixWindow.fWin; | 286 Window win = fUnixWindow.fWin; |
256 XMapWindow(dsp, win); | 287 XMapWindow(dsp, win); |
257 | 288 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 return; | 345 return; |
315 } | 346 } |
316 XTextProperty textProp; | 347 XTextProperty textProp; |
317 textProp.value = (unsigned char*)title; | 348 textProp.value = (unsigned char*)title; |
318 textProp.format = 8; | 349 textProp.format = 8; |
319 textProp.nitems = strlen((char*)textProp.value); | 350 textProp.nitems = strlen((char*)textProp.value); |
320 textProp.encoding = XA_STRING; | 351 textProp.encoding = XA_STRING; |
321 XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp); | 352 XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp); |
322 } | 353 } |
323 | 354 |
324 void SkOSWindow::onHandleInval(const SkIRect&) { | |
325 (new SkEvent("inval-imageview", this->getSinkID()))->post(); | |
326 } | |
327 | |
328 bool SkOSWindow::onEvent(const SkEvent& evt) { | |
329 if (evt.isType("inval-imageview")) { | |
330 update(NULL); | |
331 if (NULL == fUnixWindow.fGLContext) | |
332 this->doPaint(); | |
333 return true; | |
334 } | |
335 return INHERITED::onEvent(evt); | |
336 } | |
337 | |
338 static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) { | 355 static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) { |
339 sk_bzero(&image, sizeof(image)); | 356 sk_bzero(&image, sizeof(image)); |
340 | 357 |
341 int bitsPerPixel = bitmap.bytesPerPixel() * 8; | 358 int bitsPerPixel = bitmap.bytesPerPixel() * 8; |
342 image.width = bitmap.width(); | 359 image.width = bitmap.width(); |
343 image.height = bitmap.height(); | 360 image.height = bitmap.height(); |
344 image.format = ZPixmap; | 361 image.format = ZPixmap; |
345 image.data = (char*) bitmap.getPixels(); | 362 image.data = (char*) bitmap.getPixels(); |
346 image.byte_order = LSBFirst; | 363 image.byte_order = LSBFirst; |
347 image.bitmap_unit = bitsPerPixel; | 364 image.bitmap_unit = bitsPerPixel; |
348 image.bitmap_bit_order = LSBFirst; | 365 image.bitmap_bit_order = LSBFirst; |
349 image.bitmap_pad = bitsPerPixel; | 366 image.bitmap_pad = bitsPerPixel; |
350 image.depth = 24; | 367 image.depth = 24; |
351 image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * bitmap.bytesPerP
ixel(); | 368 image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * 4; |
352 image.bits_per_pixel = bitsPerPixel; | 369 image.bits_per_pixel = bitsPerPixel; |
353 return XInitImage(&image); | 370 return XInitImage(&image); |
354 } | 371 } |
355 | 372 |
356 void SkOSWindow::doPaint() { | 373 void SkOSWindow::doPaint() { |
357 if (NULL == fUnixWindow.fDisplay) { | 374 if (NULL == fUnixWindow.fDisplay) { |
358 return; | 375 return; |
359 } | 376 } |
360 // Draw the bitmap to the screen. | 377 // Draw the bitmap to the screen. |
361 const SkBitmap& bitmap = getBitmap(); | 378 const SkBitmap& bitmap = getBitmap(); |
362 int width = bitmap.width(); | 379 int width = bitmap.width(); |
363 int height = bitmap.height(); | 380 int height = bitmap.height(); |
364 | 381 |
365 XImage image; | 382 XImage image; |
366 if (!convertBitmapToXImage(image, bitmap)) { | 383 if (!convertBitmapToXImage(image, bitmap)) { |
367 return; | 384 return; |
368 } | 385 } |
369 | 386 |
370 XPutImage(fUnixWindow.fDisplay, | 387 XPutImage(fUnixWindow.fDisplay, |
371 fUnixWindow.fWin, | 388 fUnixWindow.fWin, |
372 fUnixWindow.fGc, | 389 fUnixWindow.fGc, |
373 &image, | 390 &image, |
374 0, 0, // src x,y | 391 0, 0, // src x,y |
375 0, 0, // dst x,y | 392 0, 0, // dst x,y |
376 width, height); | 393 width, height); |
377 } | 394 } |
378 | 395 |
379 bool SkOSWindow::onHandleChar(SkUnichar) { | 396 /////////////////////////////////////////////////////////////////////////////// |
380 return false; | 397 |
| 398 void SkEvent::SignalNonEmptyQueue() { |
| 399 // nothing to do, since we spin on our event-queue, polling for XPending |
381 } | 400 } |
382 | 401 |
383 bool SkOSWindow::onHandleKey(SkKey) { | 402 void SkEvent::SignalQueueTimer(SkMSec delay) { |
384 return false; | 403 // just need to record the delay time. We handle waking up for it in |
| 404 // MyXNextEventWithDelay() |
| 405 gTimerDelay = delay; |
385 } | 406 } |
386 | 407 |
387 bool SkOSWindow::onHandleKeyUp(SkKey) { | |
388 return false; | |
389 } | |
OLD | NEW |