blob: 5a3d09a0fcf0027bd2391e5d984d9f48f0d71b8c [file] [log] [blame]
/*
* Twin - A Tiny Window System
* Copyright © 2004 Keith Packard <keithp@keithp.com>
* All rights reserved.
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the Twin Library; see the file COPYING. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "twin_x11.h"
#include "twinint.h"
static void
_twin_x11_put_begin (twin_coord_t left,
twin_coord_t top,
twin_coord_t right,
twin_coord_t bottom,
void *closure)
{
twin_x11_t *tx = closure;
twin_coord_t width = right - left;
twin_coord_t height = bottom - top;
tx->image_y = top;
tx->image = XCreateImage (tx->dpy, tx->visual, tx->depth, ZPixmap,
0, 0, width, height, 32, 0);
if (tx->image)
{
tx->image->data = malloc (4 * width * height);
if (!tx->image->data)
{
XDestroyImage (tx->image);
tx->image = 0;
}
}
}
static void
_twin_x11_put_span (twin_coord_t left,
twin_coord_t top,
twin_coord_t right,
twin_argb32_t *pixels,
void *closure)
{
twin_x11_t *tx = closure;
twin_coord_t width = right - left;
twin_coord_t ix;
twin_coord_t iy = top - tx->image_y;
if (!tx->image)
return;
for (ix = 0; ix < width; ix++)
{
twin_argb32_t pixel = *pixels++;
if (tx->depth == 16)
pixel = twin_argb32_to_rgb16 (pixel);
XPutPixel (tx->image, ix, iy, pixel);
}
if ((top + 1 - tx->image_y) == tx->image->height)
{
XPutImage (tx->dpy, tx->win, tx->gc, tx->image, 0, 0,
left, tx->image_y, tx->image->width, tx->image->height);
XDestroyImage (tx->image);
tx->image = 0;
}
}
static twin_bool_t
twin_x11_read_events (int maybe_unused file,
twin_file_op_t maybe_unused ops,
void *closure)
{
twin_x11_t *tx = closure;
while (XEventsQueued (tx->dpy, QueuedAfterReading))
{
XEvent ev;
twin_event_t tev;
XNextEvent (tx->dpy, &ev);
switch (ev.type) {
case Expose:
twin_x11_damage (tx, (XExposeEvent *) &ev);
break;
case DestroyNotify:
return 0;
case ButtonPress:
case ButtonRelease:
tev.u.pointer.screen_x = ev.xbutton.x;
tev.u.pointer.screen_y = ev.xbutton.y;
tev.u.pointer.button = ((ev.xbutton.state >> 8) |
(1 << (ev.xbutton.button-1)));
tev.kind = ((ev.type == ButtonPress) ?
TwinEventButtonDown : TwinEventButtonUp);
twin_screen_dispatch (tx->screen, &tev);
break;
case KeyPress:
case KeyRelease:
tev.u.key.key = XLookupKeysym(&ev.xkey, 0);
tev.kind = ((ev.xkey.type == KeyPress) ? TwinEventKeyDown
: TwinEventKeyUp);
twin_screen_dispatch (tx->screen, &tev);
break;
case MotionNotify:
tev.u.pointer.screen_x = ev.xmotion.x;
tev.u.pointer.screen_y = ev.xmotion.y;
tev.kind = TwinEventMotion;
tev.u.pointer.button = ev.xbutton.state >> 8;
twin_screen_dispatch (tx->screen, &tev);
break;
}
}
return TWIN_TRUE;
}
static twin_bool_t
twin_x11_work (void *closure)
{
twin_x11_t *tx = closure;
if (twin_screen_damaged (tx->screen))
{
twin_x11_update (tx);
XFlush (tx->dpy);
}
return TWIN_TRUE;
}
twin_x11_t *
twin_x11_create_ext (Display *dpy, int width, int height, int handle_events)
{
twin_x11_t *tx;
int scr = DefaultScreen (dpy);
XSetWindowAttributes wa;
XTextProperty wm_name, icon_name;
XSizeHints sizeHints;
XWMHints wmHints;
XClassHint classHints;
Atom wm_delete_window;
static char *argv[] = { "xtwin", 0 };
static int argc = 1;
tx = malloc (sizeof (twin_x11_t));
if (!tx)
return 0;
tx->dpy = dpy;
tx->visual = DefaultVisual (dpy, scr);
tx->depth = DefaultDepth (dpy, scr);
if (handle_events)
twin_set_file (twin_x11_read_events,
ConnectionNumber (dpy),
TWIN_READ,
tx);
twin_set_work (twin_x11_work, TWIN_WORK_REDISPLAY, tx);
wa.background_pixmap = None;
wa.event_mask = (KeyPressMask|
KeyReleaseMask|
ButtonPressMask|
ButtonReleaseMask|
PointerMotionMask|
ExposureMask|
StructureNotifyMask);
wm_name.value = (unsigned char *) argv[0];
wm_name.encoding = XA_STRING;
wm_name.format = 8;
wm_name.nitems = strlen ((char *)wm_name.value) + 1;
icon_name = wm_name;
tx->win = XCreateWindow (dpy, RootWindow (dpy, scr),
0, 0, width, height, 0,
tx->depth, InputOutput,
tx->visual, CWBackPixmap|CWEventMask, &wa);
sizeHints.flags = 0;
wmHints.flags = InputHint;
wmHints.input = True;
classHints.res_name = argv[0];
classHints.res_class = argv[0];
XSetWMProperties (dpy, tx->win,
&wm_name, &icon_name,
argv, argc,
&sizeHints, &wmHints, 0);
XSetWMProtocols (dpy, tx->win, &wm_delete_window, 1);
tx->gc = XCreateGC (dpy, tx->win, 0, 0);
tx->screen = twin_screen_create (width, height, _twin_x11_put_begin,
_twin_x11_put_span, tx);
XMapWindow (dpy, tx->win);
return tx;
}
void
twin_x11_destroy (twin_x11_t *tx)
{
XDestroyWindow (tx->dpy, tx->win);
tx->win = 0;
twin_screen_destroy (tx->screen);
}
void
twin_x11_damage (twin_x11_t *tx, XExposeEvent *ev)
{
twin_screen_damage (tx->screen,
ev->x, ev->y, ev->x + ev->width, ev->y + ev->height);
}
void
twin_x11_configure (twin_x11_t *tx, XConfigureEvent *ev)
{
twin_screen_resize (tx->screen, ev->width, ev->height);
}
void
twin_x11_update (twin_x11_t *tx)
{
twin_screen_update (tx->screen);
}
twin_bool_t
twin_x11_process_events (twin_x11_t *tx)
{
twin_bool_t result;
_twin_run_work();
result = twin_x11_read_events(ConnectionNumber(tx->dpy), 0, tx);
_twin_run_work();
return result;
}