blob: 66b1694dc60c053e87a19ccb2f122c7cedbe7549 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
scroggob7e9aee2011-03-15 15:15:15 +00008#include <X11/Xlib.h>
9#include <X11/Xatom.h>
10#include <X11/keysym.h>
11#include <GL/glx.h>
Scroggo9df214e2011-04-15 14:48:08 +000012#include <GL/gl.h>
13#include <GL/glu.h>
scroggob7e9aee2011-03-15 15:15:15 +000014
15#include "SkWindow.h"
16
17#include "SkBitmap.h"
scroggo08526c02011-03-22 14:03:21 +000018#include "SkCanvas.h"
scroggob7e9aee2011-03-15 15:15:15 +000019#include "SkColor.h"
20#include "SkEvent.h"
Scroggo9df214e2011-04-15 14:48:08 +000021#include "SkKey.h"
22#include "SkWindow.h"
23#include "XkeysToSkKeys.h"
24extern "C" {
25 #include "keysym2ucs.h"
26}
27
Scroggoaed68d92011-06-08 14:26:00 +000028const int WIDTH = 500;
29const int HEIGHT = 500;
Scroggo9df214e2011-04-15 14:48:08 +000030
31// Determine which events to listen for.
32const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask
33 |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask;
scroggob7e9aee2011-03-15 15:15:15 +000034
bsalomon@google.com8108c472012-04-03 19:33:08 +000035SkOSWindow::SkOSWindow(void* unused)
36 : INHERITED()
37 , fVi(0) {
Scroggo9df214e2011-04-15 14:48:08 +000038 fUnixWindow.fDisplay = XOpenDisplay(NULL);
bsalomon@google.com8108c472012-04-03 19:33:08 +000039 fUnixWindow.fGLContext = NULL;
Scroggo9df214e2011-04-15 14:48:08 +000040 Display* dsp = fUnixWindow.fDisplay;
41 if (dsp) {
42 // Attempt to create a window that supports GL
43 GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER,
44 GLX_STENCIL_SIZE, 8, None };
Scroggoaed68d92011-06-08 14:26:00 +000045 fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att);
Scroggo9df214e2011-04-15 14:48:08 +000046 if (fVi) {
Scroggoaed68d92011-06-08 14:26:00 +000047 Colormap colorMap = XCreateColormap(dsp, RootWindow(dsp, fVi->screen),
48 fVi->visual, AllocNone);
Scroggo9df214e2011-04-15 14:48:08 +000049 XSetWindowAttributes swa;
Scroggoaed68d92011-06-08 14:26:00 +000050 swa.colormap = colorMap;
Scroggo9df214e2011-04-15 14:48:08 +000051 swa.event_mask = EVENT_MASK;
Scroggoaed68d92011-06-08 14:26:00 +000052 fUnixWindow.fWin = XCreateWindow(dsp, RootWindow(dsp, fVi->screen),
Scroggo9df214e2011-04-15 14:48:08 +000053 0, 0, WIDTH, HEIGHT, 0, fVi->depth,
Scroggoaed68d92011-06-08 14:26:00 +000054 InputOutput, fVi->visual, CWEventMask | CWColormap, &swa);
Scroggo9df214e2011-04-15 14:48:08 +000055
56 } else {
57 // Create a simple window instead. We will not be able to
58 // show GL
59 fUnixWindow.fWin = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp),
60 0, 0, WIDTH, HEIGHT, 0, 0, 0);
61 }
62 mapWindowAndWait();
63 fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL);
64 }
65 this->resize(WIDTH, HEIGHT);
scroggob7e9aee2011-03-15 15:15:15 +000066}
67
bsalomon@google.com8108c472012-04-03 19:33:08 +000068SkOSWindow::~SkOSWindow() {
69 if (NULL != fUnixWindow.fDisplay) {
70 if (NULL != fUnixWindow.fGLContext) {
Scroggo9df214e2011-04-15 14:48:08 +000071 glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
Scroggo9df214e2011-04-15 14:48:08 +000072 glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext);
bsalomon@google.com8108c472012-04-03 19:33:08 +000073 }
74 XFreeGC(fUnixWindow.fDisplay, fUnixWindow.fGc);
Scroggo9df214e2011-04-15 14:48:08 +000075 XDestroyWindow(fUnixWindow.fDisplay, fUnixWindow.fWin);
76 XCloseDisplay(fUnixWindow.fDisplay);
77 fUnixWindow.fDisplay = 0;
78 }
scroggob7e9aee2011-03-15 15:15:15 +000079}
80
bsalomon@google.com8108c472012-04-03 19:33:08 +000081void SkOSWindow::post_linuxevent() {
Scroggo9df214e2011-04-15 14:48:08 +000082 // Put an event in the X queue to fire an SkEvent.
bsalomon@google.com8108c472012-04-03 19:33:08 +000083 if (!fUnixWindow.fDisplay) {
84 return;
85 }
Scroggo9df214e2011-04-15 14:48:08 +000086 long event_mask = NoEventMask;
87 XClientMessageEvent event;
88 event.type = ClientMessage;
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +000089 Atom myAtom(0);
Scroggo9df214e2011-04-15 14:48:08 +000090 event.message_type = myAtom;
91 event.format = 32;
92 event.data.l[0] = 0;
93 XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0,
94 (XEvent*) &event);
Scroggo5a234242011-06-13 19:17:58 +000095 XFlush(fUnixWindow.fDisplay);
Scroggo9df214e2011-04-15 14:48:08 +000096}
97
bsalomon@google.com8108c472012-04-03 19:33:08 +000098void SkOSWindow::loop() {
Scroggo9df214e2011-04-15 14:48:08 +000099 Display* dsp = fUnixWindow.fDisplay;
100 XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK);
101
102 bool loop = true;
103 XEvent evt;
104 while (loop) {
Scroggo9df214e2011-04-15 14:48:08 +0000105 XNextEvent(dsp, &evt);
106 switch (evt.type) {
107 case Expose:
108 if (evt.xexpose.count == 0)
109 this->inval(NULL);
110 break;
111 case ConfigureNotify:
112 this->resize(evt.xconfigure.width, evt.xconfigure.height);
113 break;
114 case ButtonPress:
115 if (evt.xbutton.button == Button1)
116 this->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kDown_State);
117 break;
118 case ButtonRelease:
119 if (evt.xbutton.button == Button1)
120 this->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kUp_State);
121 break;
122 case MotionNotify:
123 this->handleClick(evt.xmotion.x, evt.xmotion.y, SkView::Click::kMoved_State);
124 break;
bsalomon@google.com8108c472012-04-03 19:33:08 +0000125 case KeyPress: {
Scroggo9df214e2011-04-15 14:48:08 +0000126 KeySym keysym = XKeycodeToKeysym(dsp, evt.xkey.keycode, 0);
127 //SkDebugf("pressed key %i!\n\tKeySym:%i\n", evt.xkey.keycode, XKeycodeToKeysym(dsp, evt.xkey.keycode, 0));
128 if (keysym == XK_Escape) {
129 loop = false;
130 break;
131 }
132 this->handleKey(XKeyToSkKey(keysym));
133 long uni = keysym2ucs(keysym);
134 if (uni != -1) {
135 this->handleChar((SkUnichar) uni);
136 }
137 break;
138 }
139 case KeyRelease:
140 //SkDebugf("released key %i\n", evt.xkey.keycode);
141 this->handleKeyUp(XKeyToSkKey(XKeycodeToKeysym(dsp, evt.xkey.keycode, 0)));
142 break;
143 case ClientMessage:
144 if (SkEvent::ProcessEvent()) {
145 this->post_linuxevent();
146 }
147 break;
148 default:
149 // Do nothing for other events
150 break;
151 }
152 }
153}
154
bsalomon@google.com8108c472012-04-03 19:33:08 +0000155void SkOSWindow::mapWindowAndWait() {
Scroggo9df214e2011-04-15 14:48:08 +0000156 Display* dsp = fUnixWindow.fDisplay;
157 Window win = fUnixWindow.fWin;
158 XMapWindow(dsp, win);
159
160 long eventMask = StructureNotifyMask;
161 XSelectInput(dsp, win, eventMask);
162
163 // Wait until screen is ready.
164 XEvent evt;
165 do {
166 XNextEvent(dsp, &evt);
167 } while(evt.type != MapNotify);
168
scroggob7e9aee2011-03-15 15:15:15 +0000169}
170
bsalomon@google.com8108c472012-04-03 19:33:08 +0000171bool SkOSWindow::attach(SkBackEndTypes /* attachType */) {
172 if (NULL == fUnixWindow.fGLContext) {
173 if (NULL == fUnixWindow.fDisplay || NULL == fVi) {
174 return false;
175 }
Scroggo9df214e2011-04-15 14:48:08 +0000176
bsalomon@google.com8108c472012-04-03 19:33:08 +0000177 fUnixWindow.fGLContext = glXCreateContext(fUnixWindow.fDisplay,
178 fVi,
179 NULL,
180 GL_TRUE);
181 if (NULL == fUnixWindow.fGLContext) {
182 return false;
183 }
Scroggo9df214e2011-04-15 14:48:08 +0000184 }
bsalomon@google.com8108c472012-04-03 19:33:08 +0000185 glXMakeCurrent(fUnixWindow.fDisplay,
186 fUnixWindow.fWin,
187 fUnixWindow.fGLContext);
188 glViewport(0, 0,
189 SkScalarRound(this->width()), SkScalarRound(this->height()));
190 glClearColor(0, 0, 0, 0);
191 glClearStencil(0);
192 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
Scroggo9df214e2011-04-15 14:48:08 +0000193 return true;
scroggob7e9aee2011-03-15 15:15:15 +0000194}
195
bsalomon@google.com8108c472012-04-03 19:33:08 +0000196void SkOSWindow::detach() {
197 if (NULL == fUnixWindow.fDisplay || NULL == fUnixWindow.fGLContext) {
198 return;
199 }
Scroggo9df214e2011-04-15 14:48:08 +0000200 glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
bsalomon@google.com8108c472012-04-03 19:33:08 +0000201 glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext);
202 fUnixWindow.fGLContext = NULL;
scroggob7e9aee2011-03-15 15:15:15 +0000203}
204
bsalomon@google.com8108c472012-04-03 19:33:08 +0000205void SkOSWindow::present() {
206 if (NULL != fUnixWindow.fDisplay && NULL != fUnixWindow.fGLContext) {
Scroggo9df214e2011-04-15 14:48:08 +0000207 glXSwapBuffers(fUnixWindow.fDisplay, fUnixWindow.fWin);
208 }
scroggob7e9aee2011-03-15 15:15:15 +0000209}
210
bsalomon@google.com8108c472012-04-03 19:33:08 +0000211void SkOSWindow::onSetTitle(const char title[]) {
212 if (!fUnixWindow.fDisplay) {
213 return;
214 }
scroggob7e9aee2011-03-15 15:15:15 +0000215 XTextProperty textProp;
216 textProp.value = (unsigned char*)title;
217 textProp.format = 8;
218 textProp.nitems = strlen((char*)textProp.value);
219 textProp.encoding = XA_STRING;
220 XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp);
221}
222
reed@google.comf2164b22011-08-04 13:57:56 +0000223void SkOSWindow::onHandleInval(const SkIRect&) {
224 (new SkEvent("inval-imageview", this->getSinkID()))->post();
scroggob7e9aee2011-03-15 15:15:15 +0000225}
226
bsalomon@google.com8108c472012-04-03 19:33:08 +0000227bool SkOSWindow::onEvent(const SkEvent& evt) {
scroggob7e9aee2011-03-15 15:15:15 +0000228 if (evt.isType("inval-imageview")) {
229 update(NULL);
bsalomon@google.com8108c472012-04-03 19:33:08 +0000230 if (NULL == fUnixWindow.fGLContext)
231 this->doPaint();
scroggob7e9aee2011-03-15 15:15:15 +0000232 return true;
233 }
234 return INHERITED::onEvent(evt);
235}
236
bsalomon@google.com8108c472012-04-03 19:33:08 +0000237static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap) {
scroggob66365f2011-03-18 21:43:03 +0000238 sk_bzero(&image, sizeof(image));
239
240 int bitsPerPixel = bitmap.bytesPerPixel() * 8;
241 image.width = bitmap.width();
242 image.height = bitmap.height();
243 image.format = ZPixmap;
244 image.data = (char*) bitmap.getPixels();
245 image.byte_order = LSBFirst;
246 image.bitmap_unit = bitsPerPixel;
247 image.bitmap_bit_order = LSBFirst;
248 image.bitmap_pad = bitsPerPixel;
249 image.depth = 24;
250 image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * bitmap.bytesPerPixel();
251 image.bits_per_pixel = bitsPerPixel;
scroggo08526c02011-03-22 14:03:21 +0000252 return XInitImage(&image);
253}
254
scroggo08526c02011-03-22 14:03:21 +0000255void SkOSWindow::doPaint() {
256 if (!fUnixWindow.fDisplay) return;
257 // Draw the bitmap to the screen.
258 const SkBitmap& bitmap = getBitmap();
259 int width = bitmap.width();
260 int height = bitmap.height();
261
Scroggo0f185c22011-03-24 18:35:50 +0000262 XImage image;
263 if (!convertBitmapToXImage(image, bitmap)) return;
scroggo08526c02011-03-22 14:03:21 +0000264
Scroggo0f185c22011-03-24 18:35:50 +0000265 XPutImage(fUnixWindow.fDisplay, fUnixWindow.fWin, fUnixWindow.fGc, &image, 0, 0, 0, 0, width, height);
scroggob7e9aee2011-03-15 15:15:15 +0000266}
267
bsalomon@google.com8108c472012-04-03 19:33:08 +0000268bool SkOSWindow::onHandleChar(SkUnichar) {
scroggob7e9aee2011-03-15 15:15:15 +0000269 return false;
270}
271
bsalomon@google.com8108c472012-04-03 19:33:08 +0000272bool SkOSWindow::onHandleKey(SkKey key) {
scroggob7e9aee2011-03-15 15:15:15 +0000273 return false;
274}
275
bsalomon@google.com8108c472012-04-03 19:33:08 +0000276bool SkOSWindow::onHandleKeyUp(SkKey key) {
scroggob7e9aee2011-03-15 15:15:15 +0000277 return false;
278}