3021 lines
77 KiB
C
3021 lines
77 KiB
C
/* x.c
|
|
* (c) 2002 Petr 'Brain' Kulhavy
|
|
* This file is a part of the Links program, released under GPL.
|
|
*/
|
|
|
|
/* Takovej mensi problemek se scrollovanim:
|
|
*
|
|
* Mikulas a Xy zpusobili, ze scrollovani a prekreslovani je asynchronni. To znamena, ze
|
|
* je v tom peknej bordylek. Kdyz BFU scrollne s oknem, tak se zavola funkce scroll. Ta
|
|
* posle Xum XCopyArea (prekopiruje prislusny kus okna) a vygeneruje eventu
|
|
* (GraphicsExpose) na postizenou (odkrytou) oblast. Funkce XCopyArea pripadne vygeneruje
|
|
* dalsi GraphicsExpose eventu na postizenou oblast, ktera se muze objevit, kdyz je
|
|
* linksove okno prekryto jinym oknem.
|
|
*
|
|
* Funkce scroll skonci. V event handleru se nekdy v budoucnosti (treba za tyden)
|
|
* zpracuji eventy od Xu, mezi nimi i GraphicsExpose - tedy prekreslovani postizenych
|
|
* oblasti.
|
|
*
|
|
* Problem je v tom, ze v okamziku, kdy scroll skonci, neni obrazovka prekreslena do
|
|
* konzistentniho stavu (misty je garbaz) a navic se muze volat dalsi scroll. Tedy
|
|
* XCopyArea muze posunout garbaz nekam do cudu a az se dostane na radu prekreslovani
|
|
* postizenych oblasti, garbaz se uz nikdy neprekresli.
|
|
*
|
|
* Ja jsem navrhoval udelat scrollovani synchronni, to znamena, ze v okamziku, kdy scroll
|
|
* skonci, bude okno v konzistentnim stavu. To by znamenalo volat ze scrollu zpracovavani
|
|
* eventu (alespon GraphicsExpose). To by ovsem nepomohlo, protoze prekreslovaci funkce
|
|
* neprekresluje, ale registruje si bottom halfy a podobny ptakoviny a prekresluje az
|
|
* nekdy v budoucnosti. Navic Mikulas rikal, ze prekreslovaci funkce muze generovat dalsi
|
|
* prekreslovani (sice jsem nepochopil jak, ale hlavne, ze je vecirek), takze by to
|
|
* neslo.
|
|
*
|
|
* Proto Mikulas vymyslel genialni tah - takzvany "genitah". Ve funkci scroll se projede
|
|
* fronta eventu od Xserveru a vyberou se GraphicsExp(l)ose eventy a ulozi se do zvlastni
|
|
* fronty. Ve funkci na zpracovani Xovych eventu se zpracuji eventy z teto fronty. Na
|
|
* zacatku scrollovaci funkce se projedou vsechny eventy ve zvlastni fronte a updatuji se
|
|
* jim souradnice podle prislusneho scrollu.
|
|
*
|
|
* Na to jsem ja vymyslel uzasnou vymluvu: co kdyz 1. scroll vyrobi nejake postizene
|
|
* oblasti a 2. scroll bude mit jinou clipovaci oblast, ktera bude tu postizenou oblast
|
|
* zasahovat z casti. Tak to se bude jako ta postizena oblast stipat na casti a ty casti
|
|
* se posunou podle toho, jestli jsou zasazene tim 2. scrollem? Tim jsem ho utrel, jak
|
|
* zpoceny celo.
|
|
*
|
|
* Takze se to nakonec udela tak, ze ze scrollu vratim hromadu rectanglu, ktere se maji
|
|
* prekreslit, a Mikulas si s tim udela, co bude chtit. Podobne jako ve svgalib, kde se
|
|
* vrati 1 a Mikulas si prislusnou odkrytou oblast prekresli sam. Doufam jen, ze to je
|
|
* posledni verze a ze nevzniknou dalsi problemy.
|
|
*
|
|
* Ve funkci scroll tedy pribude argument struct rect_set **.
|
|
*/
|
|
|
|
|
|
/* Data od XImage se alokujou pomoci malloc. get_links_icon musi alokovat taky
|
|
* pomoci malloc.
|
|
*/
|
|
|
|
/* Pozor: po kazdem XSync nebo XFlush se musi dat
|
|
* X_SCHEDULE_PROCESS_EVENTS
|
|
* jinak to bude cekat na filedescriptoru, i kdyz to ma eventy uz ve fronte.
|
|
* -- mikulas
|
|
*/
|
|
|
|
|
|
#include "cfg.h"
|
|
|
|
#ifdef GRDRV_X
|
|
|
|
/* #define X_DEBUG */
|
|
/* #define SC_DEBUG */
|
|
|
|
#if defined(X_DEBUG) || defined(SC_DEBUG)
|
|
#define MESSAGE(a) fprintf(stderr,"%s",a);
|
|
#endif
|
|
|
|
#include "links.h"
|
|
|
|
/* Mikulas je PRASE: definuje makro "format" a navrch to jeste nechce vopravit */
|
|
#ifdef format
|
|
#undef format
|
|
#endif
|
|
|
|
#if defined(HAVE_XOPENIM) && defined(HAVE_XCLOSEIM) && defined(HAVE_XCREATEIC) && defined(HAVE_XDESTROYIC) && (defined(HAVE_XWCLOOKUPSTRING) || defined(HAVE_XUTF8LOOKUPSTRING))
|
|
#define X_INPUT_METHOD
|
|
#endif
|
|
|
|
typedef void *void_p64;
|
|
|
|
#ifdef OPENVMS_64BIT
|
|
#pragma __pointer_size 32
|
|
#endif
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xatom.h>
|
|
#include <X11/Xproto.h>
|
|
#if defined(HAVE_X11_XLOCALE_H) && defined(HAVE_XSETLOCALE)
|
|
#ifdef OPENVMS
|
|
#undef LC_ALL
|
|
#undef LC_COLLATE
|
|
#undef LC_CTYPE
|
|
#undef LC_MONETARY
|
|
#undef LC_NUMERIC
|
|
#undef LC_TIME
|
|
#endif
|
|
#include <X11/Xlocale.h>
|
|
#else
|
|
#ifdef HAVE_SETLOCALE
|
|
#undef HAVE_SETLOCALE
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifndef XK_MISCELLANY
|
|
#define XK_MISCELLANY
|
|
#endif
|
|
|
|
#ifndef XK_LATIN1
|
|
#define XK_LATIN1
|
|
#endif
|
|
#include <X11/keysymdef.h>
|
|
|
|
static void *x_malloc(size_t len, int mayfail)
|
|
{
|
|
void *p;
|
|
if (len > MAX_SIZE_T) {
|
|
if (mayfail) return NULL;
|
|
overalloc();
|
|
}
|
|
do
|
|
#ifdef OPENVMS_64BIT
|
|
p = _malloc32(len);
|
|
#else
|
|
p = malloc(len);
|
|
#endif
|
|
while (!p && out_of_memory(0, !mayfail ? cast_uchar "x_malloc" : NULL, 0));
|
|
return p;
|
|
}
|
|
|
|
static void *x_dup(void_p64 src, size_t len)
|
|
{
|
|
void *r = x_malloc(len, 0);
|
|
return memcpy(r, src, len);
|
|
}
|
|
|
|
typedef unsigned char *unsigned_char_p;
|
|
typedef char *char_p;
|
|
typedef void *void_p;
|
|
typedef XImage *XImage_p;
|
|
typedef XPixmapFormatValues *XPixmapFormatValues_p;
|
|
typedef XEvent *XEvent_p;
|
|
typedef XKeyEvent *XKeyEvent_p;
|
|
typedef XColor *XColor_p;
|
|
|
|
#ifdef OPENVMS_64BIT
|
|
#pragma __pointer_size 64
|
|
#endif
|
|
|
|
#ifdef HAVE_LANGINFO_H
|
|
#include <langinfo.h>
|
|
#endif
|
|
|
|
#define X_HASH_TABLE_SIZE 64
|
|
|
|
#define X_MAX_CLIPBOARD_SIZE (15*1024*1024)
|
|
|
|
#define SELECTION_NOTIFY_TIMEOUT 10000
|
|
|
|
static int x_default_window_width;
|
|
static int x_default_window_height;
|
|
|
|
static long (*x_get_color_function)(int);
|
|
|
|
static void x_translate_colors(unsigned char *data, int x, int y, ssize_t skip);
|
|
static void x_convert_to_216(unsigned char *data, int x, int y, ssize_t skip);
|
|
static void selection_request(XEvent *event);
|
|
|
|
#ifdef OPENVMS_64BIT
|
|
#pragma __pointer_size 32
|
|
#endif
|
|
static Display *x_display = NULL; /* display */
|
|
static Visual *x_default_visual;
|
|
static XVisualInfo vinfo;
|
|
#ifdef OPENVMS_64BIT
|
|
#pragma __pointer_size 64
|
|
#endif
|
|
|
|
static int x_fd = -1; /* x socket */
|
|
static unsigned char *x_display_string = NULL;
|
|
static int x_screen; /* screen */
|
|
static int x_display_height, x_display_width; /* screen dimensions */
|
|
static unsigned long x_black_pixel; /* black pixel */
|
|
static int x_depth, x_bitmap_bpp; /* bits per pixel and bytes per pixel */
|
|
static int x_bitmap_scanline_pad; /* bitmap scanline_padding in bytes */
|
|
static int x_input_encoding; /* locales encoding */
|
|
static int x_bitmap_bit_order;
|
|
|
|
static XColor_p static_color_map = NULL;
|
|
static unsigned char x_have_palette;
|
|
static unsigned char x_use_static_color_table;
|
|
static unsigned char *static_color_table = NULL;
|
|
struct {
|
|
unsigned char failure;
|
|
unsigned char extra_allocated;
|
|
unsigned short alloc_count;
|
|
} *static_color_struct = NULL;
|
|
|
|
#define X_STATIC_COLORS (x_depth < 8 ? 8 : 216)
|
|
#define X_STATIC_CODE (x_depth < 8 ? 801 : 833)
|
|
|
|
static unsigned short *color_map_16bit = NULL;
|
|
static unsigned *color_map_24bit = NULL;
|
|
|
|
static Window x_root_window, fake_window;
|
|
static int fake_window_initialized = 0;
|
|
static GC x_normal_gc = 0, x_copy_gc = 0, x_drawbitmap_gc = 0, x_scroll_gc = 0;
|
|
static long x_normal_gc_color;
|
|
static struct rect x_scroll_gc_rect;
|
|
static Colormap x_default_colormap, x_colormap;
|
|
static Atom x_delete_window_atom, x_wm_protocols_atom, x_sel_atom, x_targets_atom, x_utf8_string_atom;
|
|
static Pixmap x_icon = 0;
|
|
|
|
#ifdef X_INPUT_METHOD
|
|
static XIM xim = NULL;
|
|
#endif
|
|
|
|
extern struct graphics_driver x_driver;
|
|
|
|
static unsigned char *x_driver_param = NULL;
|
|
static int n_wins = 0; /* number of windows */
|
|
|
|
static struct list_head bitmaps = { &bitmaps, &bitmaps };
|
|
|
|
#define XPIXMAPP(a) ((struct x_pixmapa *)(a))
|
|
|
|
#define X_TYPE_NOTHING 0
|
|
#define X_TYPE_PIXMAP 1
|
|
#define X_TYPE_IMAGE 2
|
|
|
|
struct x_pixmapa {
|
|
unsigned char type;
|
|
union {
|
|
XImage_p image;
|
|
Pixmap pixmap;
|
|
} data;
|
|
list_entry_1st
|
|
list_entry_last
|
|
};
|
|
|
|
|
|
static struct {
|
|
unsigned char count;
|
|
struct graphics_device **pointer;
|
|
} x_hash_table[X_HASH_TABLE_SIZE];
|
|
|
|
/* string in clipboard is in UTF-8 */
|
|
static unsigned char *x_my_clipboard = NULL;
|
|
|
|
struct window_info {
|
|
#ifdef X_INPUT_METHOD
|
|
XIC xic;
|
|
#endif
|
|
Window window;
|
|
};
|
|
|
|
static inline struct window_info *get_window_info(struct graphics_device *dev)
|
|
{
|
|
return dev->driver_data;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
/* Tyhle opicarny tu jsou pro zvyseni rychlosti. Flush se nedela pri kazde operaci, ale
|
|
* rekne se, ze je potreba udelat flush, a zaregistruje se bottom-half, ktery flush
|
|
* provede. Takze jakmile se vrati rizeni do select smycky, tak se provede flush.
|
|
*/
|
|
|
|
static int x_wait_for_event(int sec)
|
|
{
|
|
return can_read_timeout(x_fd, sec);
|
|
}
|
|
|
|
static void x_process_events(void *data);
|
|
|
|
static unsigned char flush_in_progress = 0;
|
|
static unsigned char process_events_in_progress = 0;
|
|
|
|
static inline void X_SCHEDULE_PROCESS_EVENTS(void)
|
|
{
|
|
if (!process_events_in_progress) {
|
|
register_bottom_half(x_process_events, NULL);
|
|
process_events_in_progress = 1;
|
|
}
|
|
}
|
|
|
|
static void x_do_flush(void *ignore)
|
|
{
|
|
flush_in_progress = 0;
|
|
XFlush(x_display);
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
}
|
|
|
|
static inline void X_FLUSH(void)
|
|
{
|
|
#ifdef INTERIX
|
|
/*
|
|
* Interix has some bug, it locks up in _XWaitForWritable.
|
|
* As a workaround, do synchronous flushes.
|
|
*/
|
|
x_do_flush(NULL);
|
|
#else
|
|
if (!flush_in_progress) {
|
|
register_bottom_half(x_do_flush, NULL);
|
|
flush_in_progress = 1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static void x_pixmap_failed(void *ignore);
|
|
|
|
#ifdef OPENVMS_64BIT
|
|
#pragma __pointer_size 32
|
|
#endif
|
|
|
|
static int (*original_error_handler)(Display *, XErrorEvent *) = NULL;
|
|
static unsigned char pixmap_mode = 0;
|
|
|
|
static int pixmap_handler(Display *d, XErrorEvent *e)
|
|
{
|
|
if (pixmap_mode == 2) {
|
|
if (e->request_code == X_CreatePixmap) {
|
|
pixmap_mode = 1;
|
|
register_bottom_half(x_pixmap_failed, NULL);
|
|
return 0;
|
|
}
|
|
}
|
|
if (pixmap_mode == 1) {
|
|
if (e->request_code == X_CreatePixmap ||
|
|
e->request_code == X_PutImage ||
|
|
e->request_code == X_CopyArea ||
|
|
e->request_code == X_FreePixmap) {
|
|
return 0;
|
|
}
|
|
}
|
|
return original_error_handler(d, e);
|
|
}
|
|
|
|
#ifdef OPENVMS_64BIT
|
|
#pragma __pointer_size 64
|
|
#endif
|
|
|
|
static void x_pixmap_failed(void *no_reinit)
|
|
{
|
|
struct x_pixmapa *p;
|
|
struct list_head *lp;
|
|
|
|
foreach(struct x_pixmapa, p, lp, bitmaps) {
|
|
if (p->type == X_TYPE_PIXMAP) {
|
|
XFreePixmap(x_display, p->data.pixmap);
|
|
p->type = X_TYPE_NOTHING;
|
|
}
|
|
}
|
|
|
|
XSync(x_display, False);
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
|
|
XSetErrorHandler(original_error_handler);
|
|
original_error_handler = NULL;
|
|
pixmap_mode = 0;
|
|
|
|
if (!no_reinit)
|
|
flush_bitmaps(1, 1, 1);
|
|
}
|
|
|
|
static void setup_pixmap_handler(void)
|
|
{
|
|
original_error_handler = XSetErrorHandler(pixmap_handler);
|
|
pixmap_mode = 2;
|
|
}
|
|
|
|
static void undo_pixmap_handler(void)
|
|
{
|
|
if (pixmap_mode == 2) {
|
|
XSetErrorHandler(original_error_handler);
|
|
original_error_handler = NULL;
|
|
pixmap_mode = 0;
|
|
}
|
|
if (pixmap_mode == 1) {
|
|
x_pixmap_failed(DUMMY);
|
|
}
|
|
unregister_bottom_half(x_pixmap_failed, NULL);
|
|
}
|
|
|
|
|
|
#ifdef OPENVMS_64BIT
|
|
#pragma __pointer_size 32
|
|
#endif
|
|
|
|
static int (*old_error_handler)(Display *, XErrorEvent *) = NULL;
|
|
static unsigned char failure_happened;
|
|
static unsigned char test_request_code;
|
|
|
|
static int failure_handler(Display *d, XErrorEvent *e)
|
|
{
|
|
if (e->request_code != test_request_code)
|
|
return old_error_handler(d, e);
|
|
failure_happened = 1;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef OPENVMS_64BIT
|
|
#pragma __pointer_size 64
|
|
#endif
|
|
|
|
static void x_prepare_for_failure(unsigned char code)
|
|
{
|
|
if (old_error_handler)
|
|
internal_error("x_prepare_for_failure: double call");
|
|
failure_happened = 0;
|
|
test_request_code = code;
|
|
old_error_handler = XSetErrorHandler(failure_handler);
|
|
}
|
|
|
|
static int x_test_for_failure(void)
|
|
{
|
|
XSync(x_display, False);
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
XSetErrorHandler(old_error_handler);
|
|
old_error_handler = NULL;
|
|
return failure_happened;
|
|
}
|
|
|
|
/* suppose l<h */
|
|
static void x_clip_number(int *n, int l, int h)
|
|
{
|
|
if (*n > h) *n = h;
|
|
if (*n < l) *n = l;
|
|
}
|
|
|
|
|
|
static const unsigned char alloc_sequence_216[216] = { 0, 215, 30, 185, 5, 35, 180, 210, 86, 203, 23, 98, 192, 119, 126, 43, 173, 12, 74, 140, 188, 161, 27, 54, 95, 204, 17, 114, 198, 11, 107, 113, 60, 65, 68, 81, 102, 108, 120, 132, 146, 164, 20, 89, 92, 158, 170, 191, 6, 37, 40, 46, 49, 52, 57, 123, 129, 135, 151, 154, 175, 178, 195, 207, 24, 71, 77, 78, 101, 143, 149, 167, 2, 8, 14, 18, 29, 32, 59, 62, 66, 72, 83, 84, 90, 96, 104, 110, 116, 125, 131, 137, 138, 144, 156, 162, 168, 182, 186, 197, 200, 209, 212, 1, 3, 4, 7, 9, 10, 13, 15, 16, 19, 21, 22, 25, 26, 28, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, 53, 55, 56, 58, 61, 63, 64, 67, 69, 70, 73, 75, 76, 79, 80, 82, 85, 87, 88, 91, 93, 94, 97, 99, 100, 103, 105, 106, 109, 111, 112, 115, 117, 118, 121, 122, 124, 127, 128, 130, 133, 134, 136, 139, 141, 142, 145, 147, 148, 150, 152, 153, 155, 157, 159, 160, 163, 165, 166, 169, 171, 172, 174, 176, 177, 179, 181, 183, 184, 187, 189, 190, 193, 194, 196, 199, 201, 202, 205, 206, 208, 211, 213, 214 };
|
|
|
|
static void x_fill_color_table(XColor colors[256], unsigned q)
|
|
{
|
|
unsigned a;
|
|
unsigned limit = 1U << x_depth;
|
|
|
|
for (a = 0; a < limit; a++) {
|
|
unsigned rgb[3];
|
|
q_palette(q, a, 65535, rgb);
|
|
colors[a].red = rgb[0];
|
|
colors[a].green = rgb[1];
|
|
colors[a].blue = rgb[2];
|
|
colors[a].pixel = a;
|
|
colors[a].flags = DoRed | DoGreen | DoBlue;
|
|
}
|
|
}
|
|
|
|
static double rgb_distance_with_border(int r1, int g1, int b1, int r2, int g2, int b2)
|
|
{
|
|
double distance = rgb_distance(r1, g1, b1, r2, g2, b2);
|
|
if (!r1)
|
|
distance += r2 * 4294967296.;
|
|
if (!g1)
|
|
distance += g2 * 4294967296.;
|
|
if (!b1)
|
|
distance += b2 * 4294967296.;
|
|
if (r1 == 0xffff)
|
|
distance += (0xffff - r2) * 4294967296.;
|
|
if (g1 == 0xffff)
|
|
distance += (0xffff - g2) * 4294967296.;
|
|
if (b1 == 0xffff)
|
|
distance += (0xffff - b2) * 4294967296.;
|
|
return distance;
|
|
}
|
|
|
|
static int get_nearest_color(unsigned rgb[3])
|
|
{
|
|
int j;
|
|
double best_distance = 0;
|
|
int best = -1;
|
|
for (j = 0; j < 1 << x_depth; j++) {
|
|
double distance;
|
|
if (static_color_struct[j].failure)
|
|
continue;
|
|
distance = rgb_distance_with_border(rgb[0], rgb[1], rgb[2], static_color_map[j].red, static_color_map[j].green, static_color_map[j].blue);
|
|
if (best < 0 || distance < best_distance) {
|
|
best = j;
|
|
best_distance = distance;
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
|
|
static int swap_color(int c, XColor_p xc, int test_count, double *distance, unsigned rgb[3])
|
|
{
|
|
unsigned long old_px, new_px;
|
|
double new_distance;
|
|
|
|
/*
|
|
* The manual page on XAllocColor says that it returns the closest
|
|
* color.
|
|
* In reality, it fails if it can't allocate the color.
|
|
*
|
|
* In case there were some other implementations that return the
|
|
* closest color, we check the distance after allocation and we fail if
|
|
* the distance would be increased.
|
|
*/
|
|
if (!XAllocColor(x_display, x_default_colormap, xc)) {
|
|
return -1;
|
|
}
|
|
new_px = xc->pixel;
|
|
new_distance = rgb_distance(xc->red, xc->green, xc->blue, rgb[0], rgb[1], rgb[2]);
|
|
if (new_px >= 256 ||
|
|
(test_count && (static_color_struct[new_px].alloc_count || static_color_struct[new_px].extra_allocated)) ||
|
|
new_distance > *distance) {
|
|
XFreeColors(x_display, x_default_colormap, &xc->pixel, 1, 0);
|
|
return -1;
|
|
}
|
|
|
|
old_px = static_color_table[c];
|
|
static_color_struct[old_px].alloc_count--;
|
|
XFreeColors(x_display, x_default_colormap, &old_px, 1, 0);
|
|
|
|
static_color_map[new_px] = *xc;
|
|
static_color_struct[new_px].alloc_count++;
|
|
static_color_struct[new_px].failure = 0;
|
|
static_color_struct[new_px].extra_allocated = 1;
|
|
static_color_table[c] = (unsigned char)new_px;
|
|
*distance = new_distance;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static unsigned char *x_query_palette(void)
|
|
{
|
|
unsigned rgb[3];
|
|
int i;
|
|
int some_valid;
|
|
int do_alloc = vinfo.class == PseudoColor;
|
|
|
|
retry:
|
|
if ((int)sizeof(XColor) > MAXINT >> x_depth) overalloc();
|
|
if ((int)sizeof(*static_color_struct) > MAXINT >> x_depth) overalloc();
|
|
if (!static_color_map)
|
|
static_color_map = x_malloc(sizeof(XColor) << x_depth, 0);
|
|
if (!static_color_struct)
|
|
static_color_struct = mem_alloc(sizeof(*static_color_struct) << x_depth);
|
|
|
|
some_valid = 0;
|
|
|
|
memset(static_color_map, 0, sizeof(XColor) << x_depth);
|
|
memset(static_color_struct, 0, sizeof(*static_color_struct) << x_depth);
|
|
for (i = 0; i < 1 << x_depth; i++)
|
|
static_color_map[i].pixel = i;
|
|
x_prepare_for_failure(X_QueryColors);
|
|
XQueryColors(x_display, x_default_colormap, static_color_map, 1 << x_depth);
|
|
if (!x_test_for_failure()) {
|
|
for (i = 0; i < 1 << x_depth; i++) {
|
|
if ((static_color_map[i].flags & (DoRed | DoGreen | DoBlue)) == (DoRed | DoGreen | DoBlue))
|
|
some_valid = 1;
|
|
else
|
|
static_color_struct[i].failure = 1;
|
|
}
|
|
}
|
|
|
|
if (!some_valid) {
|
|
memset(static_color_map, 0, sizeof(XColor) << x_depth);
|
|
memset(static_color_struct, 0, sizeof(*static_color_struct) << x_depth);
|
|
for (i = 0; i < 1 << x_depth; i++) {
|
|
static_color_map[i].pixel = i;
|
|
x_prepare_for_failure(X_QueryColors);
|
|
XQueryColor(x_display, x_default_colormap, &static_color_map[i]);
|
|
if (!x_test_for_failure() && (static_color_map[i].flags & (DoRed | DoGreen | DoBlue)) == (DoRed | DoGreen | DoBlue)) {
|
|
some_valid = 1;
|
|
} else {
|
|
static_color_struct[i].failure = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!some_valid) {
|
|
if (vinfo.class == StaticColor) {
|
|
return stracpy(cast_uchar "Could not query static colormap.\n");
|
|
} else {
|
|
x_fill_color_table(static_color_map, X_STATIC_COLORS);
|
|
do_alloc = 0;
|
|
}
|
|
}
|
|
if (!static_color_table)
|
|
static_color_table = mem_alloc(256);
|
|
memset(static_color_table, 0, 256);
|
|
for (i = 0; i < X_STATIC_COLORS; i++) {
|
|
int idx = X_STATIC_COLORS == 216 ? alloc_sequence_216[i] : i;
|
|
int c;
|
|
q_palette(X_STATIC_COLORS, idx, 65535, rgb);
|
|
another_nearest:
|
|
c = get_nearest_color(rgb);
|
|
if (c < 0) {
|
|
do_alloc = 0;
|
|
goto retry;
|
|
}
|
|
if (do_alloc) {
|
|
XColor xc;
|
|
memset(&xc, 0, sizeof xc);
|
|
xc.red = static_color_map[c].red;
|
|
xc.green = static_color_map[c].green;
|
|
xc.blue = static_color_map[c].blue;
|
|
xc.flags = DoRed | DoGreen | DoBlue;
|
|
if (!XAllocColor(x_display, x_default_colormap, &xc)) {
|
|
if (0) {
|
|
allocated_invalid:
|
|
XFreeColors(x_display, x_default_colormap, &xc.pixel, 1, 0);
|
|
}
|
|
static_color_struct[c].failure = 1;
|
|
goto another_nearest;
|
|
} else {
|
|
if (xc.pixel >= 256)
|
|
goto allocated_invalid;
|
|
c = (unsigned char)xc.pixel;
|
|
static_color_map[c] = xc;
|
|
static_color_struct[c].alloc_count++;
|
|
}
|
|
}
|
|
static_color_table[idx] = (unsigned char)c;
|
|
}
|
|
if (do_alloc) {
|
|
double distances[256];
|
|
double max_dist;
|
|
int c;
|
|
for (i = 0; i < X_STATIC_COLORS; i++) {
|
|
unsigned char q = static_color_table[i];
|
|
q_palette(X_STATIC_COLORS, i, 65535, rgb);
|
|
distances[i] = rgb_distance(static_color_map[q].red, static_color_map[q].green, static_color_map[q].blue, rgb[0], rgb[1], rgb[2]);
|
|
}
|
|
try_alloc_another:
|
|
max_dist = 0;
|
|
c = -1;
|
|
for (i = 0; i < X_STATIC_COLORS; i++) {
|
|
int idx = X_STATIC_COLORS == 216 ? alloc_sequence_216[i] : i;
|
|
if (distances[idx] > max_dist) {
|
|
max_dist = distances[idx];
|
|
c = idx;
|
|
}
|
|
}
|
|
if (c >= 0) {
|
|
XColor xc;
|
|
memset(&xc, 0, sizeof xc);
|
|
q_palette(X_STATIC_COLORS, c, 65535, rgb);
|
|
xc.red = rgb[0];
|
|
xc.green = rgb[1];
|
|
xc.blue = rgb[2];
|
|
xc.flags = DoRed | DoGreen | DoBlue;
|
|
if (swap_color(c, &xc, 1, &distances[c], rgb)) {
|
|
/*fprintf(stderr, "no more\n");*/
|
|
goto no_more_alloc;
|
|
}
|
|
/*fprintf(stderr, "allocated %d -> %d (%f)\n", c, (int)xc.pixel, distances[c]);*/
|
|
|
|
for (i = 0; i < X_STATIC_COLORS; i++) {
|
|
double d1, d2;
|
|
unsigned char cidx = static_color_table[i];
|
|
q_palette(X_STATIC_COLORS, i, 65535, rgb);
|
|
d1 = rgb_distance_with_border(rgb[0], rgb[1], rgb[2], static_color_map[cidx].red, static_color_map[cidx].green, static_color_map[cidx].blue);
|
|
d2 = rgb_distance_with_border(rgb[0], rgb[1], rgb[2], xc.red, xc.green, xc.blue);
|
|
if (d2 < d1) {
|
|
/*double old_d = distances[i];*/
|
|
if (distances[i] < rgb_distance(xc.red, xc.green, xc.blue, rgb[0], rgb[1], rgb[2]))
|
|
continue;
|
|
if (swap_color(i, &xc, 0, &distances[i], rgb)) {
|
|
/*fprintf(stderr, "no more 2\n");*/
|
|
goto no_more_alloc;
|
|
}
|
|
/*fprintf(stderr, "extra swap: %d -> %d (%f -> %f)\n", i, (int)xc.pixel, old_d, distances[i]);*/
|
|
}
|
|
}
|
|
|
|
goto try_alloc_another;
|
|
}
|
|
}
|
|
no_more_alloc:
|
|
return NULL;
|
|
}
|
|
|
|
static void x_free_colors(void)
|
|
{
|
|
unsigned long pixels[256];
|
|
int n_pixels = 0;
|
|
int i;
|
|
if (!static_color_struct)
|
|
return;
|
|
for (i = 0; i < 1 << x_depth; i++) {
|
|
while (static_color_struct[i].alloc_count) {
|
|
static_color_struct[i].alloc_count--;
|
|
pixels[n_pixels++] = i;
|
|
}
|
|
}
|
|
if (n_pixels) {
|
|
XFreeColors(x_display, x_default_colormap, pixels, n_pixels, 0);
|
|
}
|
|
}
|
|
|
|
static void x_set_palette(void)
|
|
{
|
|
unsigned limit = 1U << x_depth;
|
|
|
|
x_free_colors();
|
|
|
|
if (x_use_static_color_table) {
|
|
unsigned char *m;
|
|
m = x_query_palette();
|
|
if (m) mem_free(m); /* shut up coverity warning */
|
|
XStoreColors(x_display, x_colormap, static_color_map, (int)limit);
|
|
} else {
|
|
XColor colors[256];
|
|
x_fill_color_table(colors, limit);
|
|
XStoreColors(x_display, x_colormap, colors, (int)limit);
|
|
}
|
|
|
|
X_FLUSH();
|
|
}
|
|
|
|
|
|
static void mask_to_bitfield(unsigned long mask, int bitfield[8])
|
|
{
|
|
int i;
|
|
int bit = 0;
|
|
for (i = sizeof(unsigned long) * 8 - 1; i >= 0; i--) {
|
|
if (mask & 1UL << i) {
|
|
/*fprintf(stderr, "mask %lx, bitfield[%d] = %d\n", mask, bit, i);*/
|
|
bitfield[bit++] = i;
|
|
if (bit >= 8)
|
|
return;
|
|
}
|
|
}
|
|
while (bit < 8)
|
|
bitfield[bit++] = -1;
|
|
}
|
|
|
|
static unsigned long apply_bitfield(int bitfield[8], int bits, unsigned value)
|
|
{
|
|
unsigned long result = 0;
|
|
int bf_index = 0;
|
|
while (bits-- && bf_index < 8) {
|
|
if (value & 1 << bits) {
|
|
if (bitfield[bf_index] >= 0) {
|
|
result |= 1UL << bitfield[bf_index];
|
|
}
|
|
}
|
|
bf_index++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int create_16bit_mapping(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask)
|
|
{
|
|
int i;
|
|
int red_bitfield[8];
|
|
int green_bitfield[8];
|
|
int blue_bitfield[8];
|
|
|
|
if ((red_mask | green_mask | blue_mask) >= 0x10000)
|
|
return 0;
|
|
if (!red_mask || !green_mask || !blue_mask)
|
|
return 0;
|
|
|
|
mask_to_bitfield(red_mask, red_bitfield);
|
|
mask_to_bitfield(green_mask, green_bitfield);
|
|
mask_to_bitfield(blue_mask, blue_bitfield);
|
|
|
|
color_map_16bit = mem_calloc(256 * 2 * sizeof(unsigned short));
|
|
for (i = 0; i < 256; i++) {
|
|
unsigned g, b;
|
|
unsigned short ag, ab, result;
|
|
|
|
g = i >> 5;
|
|
b = i & 31;
|
|
|
|
ag = (unsigned short)apply_bitfield(green_bitfield, x_depth - 10, g);
|
|
ab = (unsigned short)apply_bitfield(blue_bitfield, 5, b);
|
|
|
|
result = ag | ab;
|
|
|
|
color_map_16bit[i + (x_bitmap_bit_order == MSBFirst) * 256] = (unsigned short)result;
|
|
}
|
|
for (i = 0; i < (x_depth == 15 ? 128 : 256); i++) {
|
|
unsigned r, g;
|
|
unsigned short ar, ag, result;
|
|
|
|
r = i >> (x_depth - 13);
|
|
g = (i << (x_depth - 13)) & ((1 << (x_depth - 10)) - 1);
|
|
|
|
ar = (unsigned short)apply_bitfield(red_bitfield, 5, r);
|
|
ag = (unsigned short)apply_bitfield(green_bitfield, x_depth - 10, g);
|
|
|
|
result = ar | ag;
|
|
|
|
color_map_16bit[i + (x_bitmap_bit_order == LSBFirst) * 256] = (unsigned short)result;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void create_24bit_component_mapping(unsigned long mask, unsigned *ptr)
|
|
{
|
|
int i;
|
|
int bitfield[8];
|
|
|
|
mask_to_bitfield(mask, bitfield);
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
unsigned result = (unsigned)apply_bitfield(bitfield, 8, i);
|
|
if (x_bitmap_bit_order == MSBFirst && x_bitmap_bpp == 4) {
|
|
result = (result >> 24) | ((result & 0xff0000) >> 8) | ((result & 0xff00) << 8) | ((result & 0xff) << 24);
|
|
}
|
|
ptr[i] = result;
|
|
}
|
|
}
|
|
|
|
static int create_24bit_mapping(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask)
|
|
{
|
|
if ((red_mask | green_mask | blue_mask) > 0xFFFFFFFFUL)
|
|
return 0;
|
|
if (!red_mask || !green_mask || !blue_mask)
|
|
return 0;
|
|
|
|
color_map_24bit = mem_alloc(256 * 3 * sizeof(unsigned));
|
|
|
|
create_24bit_component_mapping(blue_mask, color_map_24bit);
|
|
create_24bit_component_mapping(green_mask, color_map_24bit + 256);
|
|
create_24bit_component_mapping(red_mask, color_map_24bit + 256 * 2);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static inline int trans_key(unsigned char *str, int table)
|
|
{
|
|
if (table==utf8_table){int a; GET_UTF_8(str,a);return a;}
|
|
if (*str<128)return *str;
|
|
return cp2u(*str,table);
|
|
}
|
|
|
|
|
|
/* translates X keys to links representation */
|
|
/* return value: 1=valid key, 0=nothing */
|
|
static int x_translate_key(struct graphics_device *dev, XKeyEvent_p e, int *key, int *flag)
|
|
{
|
|
KeySym ks = 0;
|
|
static XComposeStatus comp = { NULL, 0 };
|
|
static char str[16];
|
|
#define str_size ((int)(sizeof(str) - 1))
|
|
int table = x_input_encoding < 0 ? g_kbd_codepage(&x_driver) : x_input_encoding;
|
|
int len;
|
|
|
|
#ifdef X_INPUT_METHOD
|
|
if (get_window_info(dev)->xic) {
|
|
Status status;
|
|
#ifndef HAVE_XUTF8LOOKUPSTRING
|
|
{
|
|
wchar_t wc;
|
|
len = XwcLookupString(get_window_info(dev)->xic, e, &wc, 1, &ks, &status);
|
|
if (len == 1) {
|
|
strcpy(str, cast_const_char encode_utf_8(wc));
|
|
len = strlen(str);
|
|
} else
|
|
len = 0;
|
|
}
|
|
#else
|
|
{
|
|
len = Xutf8LookupString(get_window_info(dev)->xic, e, str, str_size, &ks, &status);
|
|
}
|
|
#endif
|
|
table = utf8_table;
|
|
/*fprintf(stderr, "len: %d, ks %ld, status %d\n", len, ks, status);*/
|
|
} else
|
|
#endif
|
|
|
|
{
|
|
len = XLookupString(e, str, str_size, &ks, &comp);
|
|
}
|
|
str[len > str_size ? str_size : len] = 0;
|
|
if (!len) str[0] = (char)ks, str[1] = 0;
|
|
*flag = 0;
|
|
*key = 0;
|
|
|
|
/* alt, control, shift ... */
|
|
if (e->state & ShiftMask) *flag |= KBD_SHIFT;
|
|
if (e->state & ControlMask) *flag |= KBD_CTRL;
|
|
if (e->state & Mod1Mask) *flag |= KBD_ALT;
|
|
|
|
/* alt-f4 */
|
|
if (*flag & KBD_ALT && ks == XK_F4) { *key = KBD_CTRL_C; *flag = 0; return 1; }
|
|
|
|
/* ctrl-c */
|
|
if (*flag & KBD_CTRL && (ks == XK_c || ks == XK_C)) {*key = KBD_CTRL_C; *flag = 0; return 1; }
|
|
|
|
if (ks == NoSymbol) { return 0;
|
|
} else if (ks == XK_Return) { *key = KBD_ENTER;
|
|
} else if (ks == XK_BackSpace) { *key = KBD_BS;
|
|
} else if (ks == XK_Tab
|
|
#ifdef XK_KP_Tab
|
|
|| ks == XK_KP_Tab
|
|
#endif
|
|
) { *key = KBD_TAB;
|
|
} else if (ks == XK_Escape) {
|
|
*key = KBD_ESC;
|
|
} else if (ks == XK_Left
|
|
#ifdef XK_KP_Left
|
|
|| ks == XK_KP_Left
|
|
#endif
|
|
) { *key = KBD_LEFT;
|
|
} else if (ks == XK_Right
|
|
#ifdef XK_KP_Right
|
|
|| ks == XK_KP_Right
|
|
#endif
|
|
) { *key = KBD_RIGHT;
|
|
} else if (ks == XK_Up
|
|
#ifdef XK_KP_Up
|
|
|| ks == XK_KP_Up
|
|
#endif
|
|
) { *key = KBD_UP;
|
|
} else if (ks == XK_Down
|
|
#ifdef XK_KP_Down
|
|
|| ks == XK_KP_Down
|
|
#endif
|
|
) { *key = KBD_DOWN;
|
|
} else if (ks == XK_Insert
|
|
#ifdef XK_KP_Insert
|
|
|| ks == XK_KP_Insert
|
|
#endif
|
|
) { *key = KBD_INS;
|
|
#ifdef OPENVMS
|
|
} else if (ks == XK_Delete) { *key = KBD_BS;
|
|
#endif
|
|
} else if (ks == XK_Delete
|
|
#ifdef XK_KP_Delete
|
|
|| ks == XK_KP_Delete
|
|
#endif
|
|
) { *key = KBD_DEL;
|
|
} else if (ks == XK_Home
|
|
#ifdef XK_KP_Home
|
|
|| ks == XK_KP_Home
|
|
#endif
|
|
) { *key = KBD_HOME;
|
|
} else if (ks == XK_End
|
|
#ifdef XK_KP_End
|
|
|| ks == XK_KP_End
|
|
#endif
|
|
) { *key = KBD_END;
|
|
} else if (0
|
|
#ifdef XK_KP_Page_Up
|
|
|| ks == XK_KP_Page_Up
|
|
#endif
|
|
#ifdef XK_Page_Up
|
|
|| ks == XK_Page_Up
|
|
#endif
|
|
) { *key = KBD_PAGE_UP;
|
|
} else if (0
|
|
#ifdef XK_KP_Page_Down
|
|
|| ks == XK_KP_Page_Down
|
|
#endif
|
|
#ifdef XK_Page_Down
|
|
|| ks == XK_Page_Down
|
|
#endif
|
|
) { *key = KBD_PAGE_DOWN;
|
|
} else if (ks == XK_F1
|
|
#ifdef XK_KP_F1
|
|
|| ks == XK_KP_F1
|
|
#endif
|
|
) { *key = KBD_F1;
|
|
} else if (ks == XK_F2
|
|
#ifdef XK_KP_F2
|
|
|| ks == XK_KP_F2
|
|
#endif
|
|
) { *key = KBD_F2;
|
|
} else if (ks == XK_F3
|
|
#ifdef XK_KP_F3
|
|
|| ks == XK_KP_F3
|
|
#endif
|
|
) { *key = KBD_F3;
|
|
} else if (ks == XK_F4
|
|
#ifdef XK_KP_F4
|
|
|| ks == XK_KP_F4
|
|
#endif
|
|
) { *key = KBD_F4;
|
|
} else if (ks == XK_F5) { *key = KBD_F5;
|
|
} else if (ks == XK_F6) { *key = KBD_F6;
|
|
} else if (ks == XK_F7) { *key = KBD_F7;
|
|
} else if (ks == XK_F8) { *key = KBD_F8;
|
|
} else if (ks == XK_F9) { *key = KBD_F9;
|
|
} else if (ks == XK_F10) { *key = KBD_F10;
|
|
#ifdef OPENVMS
|
|
} else if (ks == XK_F11) { *key = KBD_ESC;
|
|
#else
|
|
} else if (ks == XK_F11) { *key = KBD_F11;
|
|
#endif
|
|
} else if (ks == XK_F12) { *key = KBD_F12;
|
|
} else if (ks == XK_KP_Subtract) { *key = '-';
|
|
} else if (ks == XK_KP_Decimal) { *key = '.';
|
|
} else if (ks == XK_KP_Divide) { *key = '/';
|
|
} else if (ks == XK_KP_Space) { *key = ' ';
|
|
} else if (ks == XK_KP_Enter) { *key = KBD_ENTER;
|
|
} else if (ks == XK_KP_Equal) { *key = '=';
|
|
} else if (ks == XK_KP_Multiply) { *key = '*';
|
|
} else if (ks == XK_KP_Add) { *key = '+';
|
|
} else if (ks == XK_KP_0) { *key = '0';
|
|
} else if (ks == XK_KP_1) { *key = '1';
|
|
} else if (ks == XK_KP_2) { *key = '2';
|
|
} else if (ks == XK_KP_3) { *key = '3';
|
|
} else if (ks == XK_KP_4) { *key = '4';
|
|
} else if (ks == XK_KP_5) { *key = '5';
|
|
} else if (ks == XK_KP_6) { *key = '6';
|
|
} else if (ks == XK_KP_7) { *key = '7';
|
|
} else if (ks == XK_KP_8) { *key = '8';
|
|
} else if (ks == XK_KP_9) { *key = '9';
|
|
#ifdef XK_Select
|
|
} else if (ks == XK_Select) { *key = KBD_SELECT;
|
|
#endif
|
|
#ifdef XK_Undo
|
|
} else if (ks == XK_Undo) { *key = KBD_UNDO;
|
|
#endif
|
|
#ifdef XK_Redo
|
|
} else if (ks == XK_Redo) { *key = KBD_REDO;
|
|
#endif
|
|
#ifdef XK_Menu
|
|
} else if (ks == XK_Menu) { *key = KBD_MENU;
|
|
#endif
|
|
#ifdef XK_Find
|
|
} else if (ks == XK_Find) { *key = KBD_FIND;
|
|
#endif
|
|
#ifdef XK_Cancel
|
|
} else if (ks == XK_Cancel) { *key = KBD_STOP;
|
|
#endif
|
|
#ifdef XK_Help
|
|
} else if (ks == XK_Help) { *key = KBD_HELP;
|
|
#endif
|
|
} else if (ks & 0x8000) {
|
|
unsigned char *str = (unsigned char *)XKeysymToString(ks);
|
|
if (str) {
|
|
if (!casestrcmp(str, cast_uchar "XF86Copy")) { *key = KBD_COPY; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Paste")) { *key = KBD_PASTE; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Cut")) { *key = KBD_CUT; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "SunProps")) { *key = KBD_PROPS; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "SunFront")) { *key = KBD_FRONT; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "SunOpen")) { *key = KBD_OPEN; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Search")) { *key = KBD_FIND; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Favorites")) { *key = KBD_BOOKMARKS; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Reload")) { *key = KBD_RELOAD; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Stop")) { *key = KBD_STOP; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Forward")) { *key = KBD_FORWARD; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Back")) { *key = KBD_BACK; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86Open")) { *key = KBD_OPEN; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "XF86OpenURL")) { *key = KBD_OPEN; return 1; }
|
|
if (!casestrcmp(str, cast_uchar "apLineDel")) { *key = KBD_DEL; return 1; }
|
|
}
|
|
return 0;
|
|
} else {
|
|
*key = *flag & KBD_CTRL ? (int)ks & 255 : trans_key(cast_uchar str, table);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void x_init_hash_table(void)
|
|
{
|
|
int a;
|
|
|
|
for (a = 0; a < X_HASH_TABLE_SIZE; a++) {
|
|
x_hash_table[a].count = 0;
|
|
x_hash_table[a].pointer = DUMMY;
|
|
}
|
|
}
|
|
|
|
static void x_clear_clipboard(void);
|
|
|
|
static void x_free_hash_table(void)
|
|
{
|
|
int a;
|
|
|
|
for (a = 0; a < X_HASH_TABLE_SIZE; a++) {
|
|
if (x_hash_table[a].count)
|
|
internal_error("x_free_hash_table: the table is not empty");
|
|
mem_free(x_hash_table[a].pointer);
|
|
}
|
|
|
|
x_clear_clipboard();
|
|
|
|
x_free_colors();
|
|
|
|
if (static_color_map) free(static_color_map), static_color_map = NULL;
|
|
if (static_color_table) mem_free(static_color_table), static_color_table = NULL;
|
|
if (static_color_struct) mem_free(static_color_struct), static_color_struct = NULL;
|
|
if (color_map_16bit) mem_free(color_map_16bit), color_map_16bit = NULL;
|
|
if (color_map_24bit) mem_free(color_map_24bit), color_map_24bit = NULL;
|
|
|
|
if (x_display) {
|
|
if (x_icon) XFreePixmap(x_display, x_icon), x_icon = 0;
|
|
if (fake_window_initialized) XDestroyWindow(x_display,fake_window), fake_window_initialized = 0;
|
|
if (x_normal_gc) XFreeGC(x_display,x_normal_gc), x_normal_gc = 0;
|
|
if (x_copy_gc) XFreeGC(x_display,x_copy_gc), x_copy_gc = 0;
|
|
if (x_drawbitmap_gc) XFreeGC(x_display,x_drawbitmap_gc), x_drawbitmap_gc = 0;
|
|
if (x_scroll_gc) XFreeGC(x_display,x_scroll_gc), x_scroll_gc = 0;
|
|
#ifdef X_INPUT_METHOD
|
|
if (xim) XCloseIM(xim), xim = NULL;
|
|
#endif
|
|
XCloseDisplay(x_display), x_display = NULL;
|
|
}
|
|
|
|
if (x_driver_param) mem_free(x_driver_param), x_driver_param = NULL;
|
|
if (x_display_string) mem_free(x_display_string), x_display_string = NULL;
|
|
|
|
undo_pixmap_handler();
|
|
|
|
process_events_in_progress = 0;
|
|
flush_in_progress = 0;
|
|
unregister_bottom_half(x_process_events, NULL);
|
|
unregister_bottom_half(x_do_flush, NULL);
|
|
}
|
|
|
|
/* returns graphics device structure which belonging to the window */
|
|
static struct graphics_device *x_find_gd(Window win)
|
|
{
|
|
int a, b;
|
|
|
|
a=(int)win & (X_HASH_TABLE_SIZE - 1);
|
|
for (b = 0; b < x_hash_table[a].count; b++) {
|
|
if (get_window_info(x_hash_table[a].pointer[b])->window == win)
|
|
return x_hash_table[a].pointer[b];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* adds graphics device to hash table */
|
|
static void x_add_to_table(struct graphics_device *dev)
|
|
{
|
|
int a = (int)get_window_info(dev)->window & (X_HASH_TABLE_SIZE - 1);
|
|
int c = x_hash_table[a].count;
|
|
|
|
if ((unsigned)c > MAXINT / sizeof(struct graphics_device *) - 1) overalloc();
|
|
x_hash_table[a].pointer = mem_realloc(x_hash_table[a].pointer, (c + 1) * sizeof(struct graphics_device *));
|
|
|
|
x_hash_table[a].pointer[c] = dev;
|
|
x_hash_table[a].count++;
|
|
}
|
|
|
|
/* removes graphics device from table */
|
|
static void x_remove_from_table(Window win)
|
|
{
|
|
int a = (int)win & (X_HASH_TABLE_SIZE - 1);
|
|
int b;
|
|
|
|
for (b = 0; b < x_hash_table[a].count; b++) {
|
|
if (get_window_info(x_hash_table[a].pointer[b])->window == win) {
|
|
memmove(x_hash_table[a].pointer + b, x_hash_table[a].pointer + b + 1, (x_hash_table[a].count - b - 1) * sizeof(struct graphics_device *));
|
|
x_hash_table[a].count--;
|
|
x_hash_table[a].pointer = mem_realloc(x_hash_table[a].pointer, x_hash_table[a].count * sizeof(struct graphics_device *));
|
|
return;
|
|
}
|
|
}
|
|
|
|
internal_error("x_remove_from_table: window not found");
|
|
}
|
|
|
|
|
|
static void x_clear_clipboard(void)
|
|
{
|
|
if (x_my_clipboard) {
|
|
mem_free(x_my_clipboard);
|
|
x_my_clipboard = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
static void x_update_driver_param(int w, int h)
|
|
{
|
|
int l=0;
|
|
|
|
if (n_wins != 1) return;
|
|
|
|
x_default_window_width = w;
|
|
x_default_window_height = h;
|
|
|
|
if (x_driver_param) mem_free(x_driver_param);
|
|
x_driver_param = init_str();
|
|
add_num_to_str(&x_driver_param, &l, x_default_window_width);
|
|
add_chr_to_str(&x_driver_param, &l, 'x');
|
|
add_num_to_str(&x_driver_param, &l, x_default_window_height);
|
|
}
|
|
|
|
|
|
static int x_decode_button(int b)
|
|
{
|
|
switch (b) {
|
|
case 1: return B_LEFT;
|
|
case 2: return B_MIDDLE;
|
|
case 3: return B_RIGHT;
|
|
case 4: return B_WHEELUP;
|
|
case 5: return B_WHEELDOWN;
|
|
case 6: return B_WHEELLEFT;
|
|
case 7: return B_WHEELRIGHT;
|
|
case 8: return B_FOURTH;
|
|
case 9: return B_FIFTH;
|
|
case 10: return B_SIXTH;
|
|
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void x_process_events(void *data)
|
|
{
|
|
XEvent event;
|
|
XEvent last_event;
|
|
struct graphics_device *dev;
|
|
int last_was_mouse;
|
|
int replay_event = 0;
|
|
|
|
#ifdef OPENVMS
|
|
clear_events(x_fd, 0);
|
|
#endif
|
|
|
|
process_events_in_progress = 0;
|
|
|
|
#ifdef SC_DEBUG
|
|
MESSAGE("x_process_event\n");
|
|
#endif
|
|
memset(&last_event, 0, sizeof last_event); /* against warning */
|
|
last_was_mouse=0;
|
|
while (XPending(x_display) || replay_event)
|
|
{
|
|
if (replay_event) replay_event = 0;
|
|
else XNextEvent(x_display, &event);
|
|
if (last_was_mouse&&(event.type==ButtonPress||event.type==ButtonRelease)) /* this is end of mouse move block --- call mouse handler */
|
|
{
|
|
int a,b;
|
|
|
|
last_was_mouse=0;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(MotionNotify event)\n");
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"x=%d y=%d\n",last_event.xmotion.x,last_event.xmotion.y);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
dev = x_find_gd(last_event.xmotion.window);
|
|
if (!dev) break;
|
|
a=B_LEFT;
|
|
b=B_MOVE;
|
|
if ((last_event.xmotion.state)&Button1Mask)
|
|
{
|
|
a=B_LEFT;
|
|
b=B_DRAG;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("left button/drag\n");
|
|
#endif
|
|
}
|
|
if ((last_event.xmotion.state)&Button2Mask)
|
|
{
|
|
a=B_MIDDLE;
|
|
b=B_DRAG;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("middle button/drag\n");
|
|
#endif
|
|
}
|
|
if ((last_event.xmotion.state)&Button3Mask)
|
|
{
|
|
a=B_RIGHT;
|
|
b=B_DRAG;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("right button/drag\n");
|
|
#endif
|
|
}
|
|
x_clip_number(&last_event.xmotion.x, dev->size.x1, dev->size.x2 - 1);
|
|
x_clip_number(&last_event.xmotion.y, dev->size.y1, dev->size.y2 - 1);
|
|
dev->mouse_handler(dev, last_event.xmotion.x, last_event.xmotion.y, a | b);
|
|
}
|
|
|
|
switch(event.type)
|
|
{
|
|
case GraphicsExpose: /* redraw uncovered area during scroll */
|
|
{
|
|
struct rect r;
|
|
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(GraphicsExpose event)\n");
|
|
#endif
|
|
dev = x_find_gd(event.xgraphicsexpose.drawable);
|
|
if (!dev) break;
|
|
r.x1=event.xgraphicsexpose.x;
|
|
r.y1=event.xgraphicsexpose.y;
|
|
r.x2=event.xgraphicsexpose.x+event.xgraphicsexpose.width;
|
|
r.y2=event.xgraphicsexpose.y+event.xgraphicsexpose.height;
|
|
dev->redraw_handler(dev,&r);
|
|
}
|
|
break;
|
|
|
|
case Expose: /* redraw part of the window */
|
|
{
|
|
struct rect r;
|
|
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(Expose event)\n");
|
|
#endif
|
|
|
|
dev = x_find_gd(event.xexpose.window);
|
|
if (!dev) break;
|
|
r.x1=event.xexpose.x;
|
|
r.y1=event.xexpose.y;
|
|
r.x2=event.xexpose.x+event.xexpose.width;
|
|
r.y2=event.xexpose.y+event.xexpose.height;
|
|
dev->redraw_handler(dev,&r);
|
|
}
|
|
break;
|
|
|
|
case ConfigureNotify: /* resize window */
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(ConfigureNotify event)\n");
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"width=%d height=%d\n",event.xconfigure.width,event.xconfigure.height);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
dev = x_find_gd(event.xconfigure.window);
|
|
if (!dev) break;
|
|
/* when window only moved and size is the same, do nothing */
|
|
if (dev->size.x2==event.xconfigure.width&&dev->size.y2==event.xconfigure.height)break;
|
|
configure_notify_again:
|
|
dev->size.x2=event.xconfigure.width;
|
|
dev->size.y2=event.xconfigure.height;
|
|
x_update_driver_param(event.xconfigure.width, event.xconfigure.height);
|
|
while (XCheckWindowEvent(x_display,get_window_info(dev)->window,ExposureMask,&event)==True)
|
|
;
|
|
if (XCheckWindowEvent(x_display,get_window_info(dev)->window,StructureNotifyMask,&event)==True) {
|
|
if (event.type==ConfigureNotify) goto configure_notify_again;
|
|
replay_event=1;
|
|
}
|
|
dev->resize_handler(dev);
|
|
break;
|
|
|
|
case KeyPress: /* a key was pressed */
|
|
{
|
|
int f,k;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(KeyPress event)\n");
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"keycode=%d state=%d\n",event.xkey.keycode,event.xkey.state);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
#ifdef X_INPUT_METHOD
|
|
if (XFilterEvent(&event, None))
|
|
break;
|
|
#endif
|
|
dev = x_find_gd(event.xkey.window);
|
|
if (!dev) break;
|
|
if (x_translate_key(dev, (XKeyEvent_p)&event, &k, &f))
|
|
dev->keyboard_handler(dev, k, f);
|
|
}
|
|
break;
|
|
|
|
case ClientMessage:
|
|
if (
|
|
event.xclient.format!=32||
|
|
event.xclient.message_type!=x_wm_protocols_atom||
|
|
(Atom)event.xclient.data.l[0]!=x_delete_window_atom
|
|
)break;
|
|
/*-fallthrough*/
|
|
|
|
/* This event is destroy window event from window manager */
|
|
|
|
case DestroyNotify:
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(DestroyNotify event)\n");
|
|
#endif
|
|
dev = x_find_gd(event.xkey.window);
|
|
if (!dev) break;
|
|
|
|
dev->keyboard_handler(dev,KBD_CLOSE,0);
|
|
break;
|
|
|
|
case ButtonRelease: /* mouse button was released */
|
|
{
|
|
int a;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(ButtonRelease event)\n");
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"x=%d y=%d buttons=%d mask=%d\n",event.xbutton.x,event.xbutton.y,event.xbutton.button,event.xbutton.state);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
dev = x_find_gd(event.xbutton.window);
|
|
if (!dev) break;
|
|
last_was_mouse = 0;
|
|
if ((a = x_decode_button(event.xbutton.button)) >= 0 && !BM_IS_WHEEL(a)) {
|
|
x_clip_number(&event.xmotion.x, dev->size.x1, dev->size.x2 - 1);
|
|
x_clip_number(&event.xmotion.y, dev->size.y1, dev->size.y2 - 1);
|
|
dev->mouse_handler(dev, event.xbutton.x, event.xbutton.y, a | B_UP);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ButtonPress: /* mouse button was pressed */
|
|
{
|
|
int a;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(ButtonPress event)\n");
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"x=%d y=%d buttons=%d mask=%d\n",event.xbutton.x,event.xbutton.y,event.xbutton.button,event.xbutton.state);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
dev = x_find_gd(event.xbutton.window);
|
|
if (!dev) break;
|
|
last_was_mouse = 0;
|
|
if ((a = x_decode_button(event.xbutton.button)) >= 0) {
|
|
x_clip_number(&(event.xmotion.x), dev->size.x1, dev->size.x2 - 1);
|
|
x_clip_number(&(event.xmotion.y), dev->size.y1, dev->size.y2 - 1);
|
|
dev->mouse_handler(dev, event.xbutton.x, event.xbutton.y, a | (!BM_IS_WHEEL(a) ? B_DOWN : B_MOVE));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MotionNotify: /* pointer moved */
|
|
{
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(MotionNotify event)\n");
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"x=%d y=%d\n",event.xmotion.x,event.xmotion.y);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
/* just sign, that this was mouse event */
|
|
last_was_mouse=1;
|
|
last_event=event;
|
|
/* fix lag when using remote X and dragging over some text */
|
|
XSync(x_display, False);
|
|
}
|
|
break;
|
|
|
|
/* read clipboard */
|
|
case SelectionNotify:
|
|
#ifdef X_DEBUG
|
|
MESSAGE("xselectionnotify\n");
|
|
#endif
|
|
/* handled in x_get_clipboard_text */
|
|
break;
|
|
|
|
/* This long code must be here in order to implement copying of stuff into the clipboard */
|
|
case SelectionRequest:
|
|
{
|
|
selection_request(&event);
|
|
}
|
|
break;
|
|
|
|
case MapNotify:
|
|
XFlush (x_display);
|
|
break;
|
|
|
|
default:
|
|
#ifdef X_DEBUG
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"event=%d\n",event.type);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (last_was_mouse) /* that was end of mouse move block --- call mouse handler */
|
|
{
|
|
int a,b;
|
|
|
|
last_was_mouse=0;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("(MotionNotify event)\n");
|
|
/*
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"x=%d y=%d\n",last_event.xmotion.x,last_event.xmotion.y);
|
|
MESSAGE(txt);
|
|
}
|
|
*/
|
|
#endif
|
|
dev = x_find_gd(last_event.xmotion.window);
|
|
if (!dev) goto ret;
|
|
a=B_LEFT;
|
|
b=B_MOVE;
|
|
if ((last_event.xmotion.state)&Button1Mask)
|
|
{
|
|
a=B_LEFT;
|
|
b=B_DRAG;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("left button/drag\n");
|
|
#endif
|
|
}
|
|
if ((last_event.xmotion.state)&Button2Mask)
|
|
{
|
|
a=B_MIDDLE;
|
|
b=B_DRAG;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("middle button/drag\n");
|
|
#endif
|
|
}
|
|
if ((last_event.xmotion.state)&Button3Mask)
|
|
{
|
|
a=B_RIGHT;
|
|
b=B_DRAG;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("right button/drag\n");
|
|
#endif
|
|
}
|
|
x_clip_number(&last_event.xmotion.x, dev->size.x1, dev->size.x2 - 1);
|
|
x_clip_number(&last_event.xmotion.y, dev->size.y1, dev->size.y2 - 1);
|
|
dev->mouse_handler(dev,last_event.xmotion.x,last_event.xmotion.y,a|b);
|
|
}
|
|
ret:;
|
|
#ifdef SC_DEBUG
|
|
MESSAGE("x_process_event end\n");
|
|
#endif
|
|
}
|
|
|
|
|
|
static void x_after_fork(void)
|
|
{
|
|
int rs;
|
|
if (x_fd != -1) {
|
|
EINTRLOOP(rs, close(x_fd));
|
|
x_fd = -1;
|
|
}
|
|
}
|
|
|
|
/* returns pointer to string with driver parameter or NULL */
|
|
static unsigned char *x_get_driver_param(void)
|
|
{
|
|
return x_driver_param;
|
|
}
|
|
|
|
static unsigned char *x_get_af_unix_name(void)
|
|
{
|
|
return x_display_string;
|
|
}
|
|
|
|
#ifdef X_INPUT_METHOD
|
|
static XIC x_open_xic(Window w);
|
|
#endif
|
|
|
|
/* initiate connection with X server */
|
|
static unsigned char *x_init_driver(unsigned char *param, unsigned char *display)
|
|
{
|
|
unsigned char *err;
|
|
int l;
|
|
|
|
XGCValues gcv;
|
|
XSetWindowAttributes win_attr;
|
|
int misordered = -1;
|
|
|
|
x_init_hash_table();
|
|
|
|
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
|
|
setlocale(LC_CTYPE, "");
|
|
#endif
|
|
#ifdef X_DEBUG
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"x_init_driver(%s, %s)\n", param, display);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
x_input_encoding=-1;
|
|
#if defined(HAVE_NL_LANGINFO) && defined(HAVE_LANGINFO_H) && defined(CODESET) && !defined(WIN) && !defined(INTERIX)
|
|
{
|
|
unsigned char *cp;
|
|
cp = cast_uchar nl_langinfo(CODESET);
|
|
x_input_encoding=get_cp_index(cp);
|
|
}
|
|
#endif
|
|
if (!display || !(*display)) display = NULL;
|
|
|
|
/*
|
|
X documentation says on XOpenDisplay(display_name) :
|
|
|
|
display_name
|
|
Specifies the hardware display name, which determines the dis-
|
|
play and communications domain to be used. On a POSIX-confor-
|
|
mant system, if the display_name is NULL, it defaults to the
|
|
value of the DISPLAY environment variable.
|
|
|
|
But OS/2 has problems when display_name is NULL ...
|
|
|
|
*/
|
|
if (!display) display = cast_uchar getenv("DISPLAY");
|
|
#if !defined(__linux__) && !defined(OPENVMS)
|
|
/* on Linux, do not assume XWINDOW present if $DISPLAY is not set
|
|
--- rather open links on svgalib or framebuffer console */
|
|
if (!display) display = cast_uchar ":0.0"; /* needed for MacOS X */
|
|
#endif
|
|
x_display_string = stracpy(display ? display : cast_uchar "");
|
|
|
|
if (display) {
|
|
char_p xx_display = x_dup(display, strlen(cast_const_char display) + 1);
|
|
x_display = XOpenDisplay(xx_display);
|
|
free(xx_display);
|
|
} else {
|
|
x_display = XOpenDisplay(NULL);
|
|
}
|
|
if (!x_display) {
|
|
err = init_str();
|
|
l = 0;
|
|
if (display) {
|
|
add_to_str(&err, &l, cast_uchar "Can't open display \"");
|
|
add_to_str(&err, &l, display);
|
|
add_to_str(&err, &l, cast_uchar "\"\n");
|
|
} else {
|
|
add_to_str(&err, &l, cast_uchar "Can't open default display\n");
|
|
}
|
|
goto ret_err;
|
|
}
|
|
|
|
x_bitmap_bit_order = BitmapBitOrder(x_display);
|
|
x_screen = DefaultScreen(x_display);
|
|
x_display_height = DisplayHeight(x_display, x_screen);
|
|
x_display_width = DisplayWidth(x_display, x_screen);
|
|
x_root_window = RootWindow(x_display, x_screen);
|
|
x_default_colormap = XDefaultColormap(x_display, x_screen);
|
|
|
|
x_default_window_width = x_display_width;
|
|
if (x_default_window_width >= 100)
|
|
x_default_window_width -= 50;
|
|
x_default_window_height = x_display_height;
|
|
if (x_default_window_height >= 150)
|
|
x_default_window_height -= 75;
|
|
|
|
x_driver_param = NULL;
|
|
|
|
if (param && *param) {
|
|
unsigned char *e;
|
|
char *end_c;
|
|
unsigned long w, h;
|
|
|
|
x_driver_param = stracpy(param);
|
|
|
|
if (*x_driver_param < '0' || *x_driver_param > '9') {
|
|
invalid_param:
|
|
err = stracpy(cast_uchar "Invalid parameter.\n");
|
|
goto ret_err;
|
|
}
|
|
w = strtoul(cast_const_char x_driver_param, &end_c, 10);
|
|
e = cast_uchar end_c;
|
|
if (upcase(*e) != 'X') goto invalid_param;
|
|
e++;
|
|
if (*e < '0' || *e > '9') goto invalid_param;
|
|
h = strtoul(cast_const_char e, &end_c, 10);
|
|
e = cast_uchar end_c;
|
|
if (*e) goto invalid_param;
|
|
if (w && h && w <= 30000 && h <= 30000) {
|
|
x_default_window_width=(int)w;
|
|
x_default_window_height=(int)h;
|
|
}
|
|
}
|
|
|
|
/* find best visual */
|
|
{
|
|
static_const unsigned char depths[] = {24, 16, 15, 8, 4};
|
|
static_const int classes[] = {TrueColor, PseudoColor, StaticColor}; /* FIXME: dodelat DirectColor */
|
|
unsigned a, b;
|
|
|
|
for (a = 0; a < array_elements(depths); a++) for (b = 0; b < array_elements(classes); b++) {
|
|
if ((classes[b] == PseudoColor || classes[b] == StaticColor) && depths[a] > 8)
|
|
continue;
|
|
if (classes[b] == TrueColor && depths[a] <= 8)
|
|
continue;
|
|
|
|
if (XMatchVisualInfo(x_display, x_screen, depths[a], classes[b], &vinfo)) {
|
|
XPixmapFormatValues_p pfm;
|
|
int n, i;
|
|
|
|
x_default_visual = vinfo.visual;
|
|
x_depth = vinfo.depth;
|
|
|
|
/* determine bytes per pixel */
|
|
pfm = XListPixmapFormats(x_display, &n);
|
|
for (i = 0; i < n; i++)
|
|
if (pfm[i].depth == x_depth) {
|
|
x_bitmap_bpp = pfm[i].bits_per_pixel < 8 ? 1 : pfm[i].bits_per_pixel >> 3;
|
|
x_bitmap_scanline_pad = pfm[i].scanline_pad >> 3;
|
|
XFree(pfm);
|
|
goto bytes_per_pixel_found;
|
|
}
|
|
if (n) XFree(pfm);
|
|
continue;
|
|
|
|
bytes_per_pixel_found:
|
|
/* test misordered flag */
|
|
/*debug("x_depth %d, x_bitmap_bpp %d %lx %lx %lx %s", x_depth, x_bitmap_bpp, vinfo.red_mask, vinfo.green_mask, vinfo.blue_mask, x_bitmap_bit_order == MSBFirst ? "MSBFirst" : "LSBFirst");*/
|
|
switch (x_depth) {
|
|
case 4:
|
|
case 8:
|
|
if (x_bitmap_bpp != 1)
|
|
break;
|
|
if (vinfo.class == StaticColor || vinfo.class == PseudoColor) {
|
|
misordered = 0;
|
|
goto visual_found;
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
if (x_bitmap_bpp != 2)
|
|
break;
|
|
|
|
if (x_depth == 16 && vinfo.red_mask == 0xf800 && vinfo.green_mask == 0x7e0 && vinfo.blue_mask == 0x1f) {
|
|
misordered = x_bitmap_bit_order == MSBFirst ? 256 : 0;
|
|
goto visual_found;
|
|
}
|
|
|
|
if (x_depth == 15 && vinfo.red_mask == 0x7c00 && vinfo.green_mask == 0x3e0 && vinfo.blue_mask == 0x1f) {
|
|
misordered = x_bitmap_bit_order == MSBFirst ? 256 : 0;
|
|
goto visual_found;
|
|
}
|
|
|
|
if (create_16bit_mapping(vinfo.red_mask, vinfo.green_mask, vinfo.blue_mask)) {
|
|
misordered = 0;
|
|
goto visual_found;
|
|
}
|
|
|
|
break;
|
|
|
|
case 24:
|
|
if (x_bitmap_bpp != 3 && x_bitmap_bpp != 4)
|
|
break;
|
|
|
|
if (vinfo.red_mask == 0xff0000 && vinfo.green_mask == 0xff00 && vinfo.blue_mask == 0xff) {
|
|
misordered = x_bitmap_bpp == 4 && x_bitmap_bit_order == MSBFirst ? 512 : 0;
|
|
goto visual_found;
|
|
}
|
|
|
|
if (create_24bit_mapping(vinfo.red_mask, vinfo.green_mask, vinfo.blue_mask)) {
|
|
misordered = 0;
|
|
goto visual_found;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
err = stracpy(cast_uchar "No supported color depth found.\n");
|
|
goto ret_err;
|
|
}
|
|
visual_found:
|
|
|
|
x_driver.flags &= ~GD_SWITCH_PALETTE;
|
|
x_have_palette = 0;
|
|
x_use_static_color_table = 0;
|
|
if (vinfo.class == StaticColor) {
|
|
if (x_depth > 8)
|
|
return stracpy(cast_uchar "Static color supported for up to 8-bit depth.\n");
|
|
if ((err = x_query_palette()))
|
|
goto ret_err;
|
|
x_use_static_color_table = 1;
|
|
}
|
|
if (vinfo.class == PseudoColor) {
|
|
if (x_depth > 8)
|
|
return stracpy(cast_uchar "Static color supported for up to 8-bit depth.\n");
|
|
x_use_static_color_table = !x_driver.param->palette_mode;
|
|
x_have_palette = 1;
|
|
x_colormap = XCreateColormap(x_display, x_root_window, x_default_visual, AllocAll);
|
|
x_set_palette();
|
|
x_driver.flags |= GD_SWITCH_PALETTE;
|
|
}
|
|
|
|
x_driver.depth = 0;
|
|
x_driver.depth |= x_bitmap_bpp;
|
|
x_driver.depth |= x_depth << 3;
|
|
x_driver.depth |= misordered;
|
|
|
|
/* check if depth is sane */
|
|
if (x_use_static_color_table) x_driver.depth = X_STATIC_CODE;
|
|
|
|
#ifdef X_DEBUG
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"x_driver.depth=%d\n",x_driver.depth);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
|
|
x_get_color_function = get_color_fn(x_driver.depth);
|
|
if (!x_get_color_function) {
|
|
unsigned char nevidim_te_ani_te_neslysim_ale_smrdis_jako_lejno[MAX_STR_LEN];
|
|
|
|
snprintf(cast_char nevidim_te_ani_te_neslysim_ale_smrdis_jako_lejno, MAX_STR_LEN,
|
|
"Unsupported graphics mode: x_depth=%d, bits_per_pixel=%d, bytes_per_pixel=%d\n",x_driver.depth, x_depth, x_bitmap_bpp);
|
|
err = stracpy(nevidim_te_ani_te_neslysim_ale_smrdis_jako_lejno);
|
|
goto ret_err;
|
|
}
|
|
|
|
x_black_pixel = BlackPixel(x_display, x_screen);
|
|
|
|
gcv.function = GXcopy;
|
|
gcv.graphics_exposures = True; /* we want to receive GraphicsExpose events when uninitialized area is discovered during scroll */
|
|
gcv.fill_style = FillSolid;
|
|
gcv.background = x_black_pixel;
|
|
|
|
x_delete_window_atom = XInternAtom(x_display,"WM_DELETE_WINDOW", False);
|
|
x_wm_protocols_atom = XInternAtom(x_display,"WM_PROTOCOLS", False);
|
|
x_sel_atom = XInternAtom(x_display, "SEL_PROP", False);
|
|
x_targets_atom = XInternAtom(x_display, "TARGETS", False);
|
|
x_utf8_string_atom = XInternAtom(x_display, "UTF8_STRING", False);
|
|
|
|
if (x_have_palette) win_attr.colormap = x_colormap;
|
|
else win_attr.colormap = x_default_colormap;
|
|
|
|
fake_window = XCreateWindow(
|
|
x_display,
|
|
x_root_window,
|
|
0,
|
|
0,
|
|
10,
|
|
10,
|
|
0,
|
|
x_depth,
|
|
CopyFromParent,
|
|
x_default_visual,
|
|
CWColormap,
|
|
&win_attr
|
|
);
|
|
|
|
fake_window_initialized = 1;
|
|
|
|
x_normal_gc = XCreateGC(x_display, fake_window, GCFillStyle|GCBackground, &gcv);
|
|
if (!x_normal_gc) {
|
|
err = stracpy(cast_uchar "Cannot create graphic context.\n");
|
|
goto ret_err;
|
|
}
|
|
x_normal_gc_color = 0;
|
|
XSetForeground(x_display, x_normal_gc, x_normal_gc_color);
|
|
XSetLineAttributes(x_display, x_normal_gc, 1, LineSolid, CapRound, JoinRound);
|
|
|
|
x_copy_gc = XCreateGC(x_display, fake_window, GCFunction, &gcv);
|
|
if (!x_copy_gc) {
|
|
err = stracpy(cast_uchar "Cannot create graphic context.\n");
|
|
goto ret_err;
|
|
}
|
|
|
|
x_drawbitmap_gc = XCreateGC(x_display, fake_window, GCFunction, &gcv);
|
|
if (!x_drawbitmap_gc) {
|
|
err = stracpy(cast_uchar "Cannot create graphic context.\n");
|
|
goto ret_err;
|
|
}
|
|
|
|
x_scroll_gc = XCreateGC(x_display, fake_window, GCGraphicsExposures|GCBackground, &gcv);
|
|
if (!x_scroll_gc) {
|
|
err = stracpy(cast_uchar "Cannot create graphic context.\n");
|
|
goto ret_err;
|
|
}
|
|
x_scroll_gc_rect.x1 = x_scroll_gc_rect.x2 = x_scroll_gc_rect.y1 = x_scroll_gc_rect.y2 = -1;
|
|
|
|
#ifdef X_INPUT_METHOD
|
|
{
|
|
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
|
|
/*
|
|
* Unfortunatelly, dead keys are translated according to
|
|
* current locale, even if we use Xutf8LookupString.
|
|
* So, try to set locale to utf8 for the input method.
|
|
*/
|
|
unsigned char *l;
|
|
int len;
|
|
l = cast_uchar setlocale(LC_CTYPE, "");
|
|
len = l ? (int)strlen(cast_const_char l) : 0;
|
|
if (l &&
|
|
!(len >= 5 && !casestrcmp(l + len - 5, cast_uchar ".utf8")) &&
|
|
!(len >= 6 && !casestrcmp(l + len - 6, cast_uchar ".utf-8"))
|
|
) {
|
|
unsigned char *m = memacpy(l, strcspn(cast_const_char l, "."));
|
|
add_to_strn(&m, cast_uchar ".UTF-8");
|
|
l = cast_uchar setlocale(LC_CTYPE, cast_const_char m);
|
|
mem_free(m);
|
|
}
|
|
if (!l) {
|
|
l = cast_uchar setlocale(LC_CTYPE, "en_US.UTF-8");
|
|
if (!l) l = cast_uchar setlocale(LC_CTYPE, "C.UTF-8");
|
|
}
|
|
#endif
|
|
xim = XOpenIM(x_display, NULL, NULL, NULL);
|
|
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
|
|
if (!xim) {
|
|
l = cast_uchar setlocale(LC_CTYPE, "en_US.UTF-8");
|
|
if (!l) l = cast_uchar setlocale(LC_CTYPE, "C.UTF-8");
|
|
xim = XOpenIM(x_display, NULL, NULL, NULL);
|
|
}
|
|
#endif
|
|
if (xim) {
|
|
XIC xic = x_open_xic(fake_window);
|
|
if (xic) {
|
|
XDestroyIC(xic);
|
|
} else {
|
|
XCloseIM(xim), xim = NULL;
|
|
}
|
|
}
|
|
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
|
|
setlocale(LC_CTYPE, "");
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
if (x_input_encoding < 0
|
|
#ifdef X_INPUT_METHOD
|
|
&& !xim
|
|
#endif
|
|
) x_driver.flags|=GD_NEED_CODEPAGE;
|
|
|
|
x_fd = XConnectionNumber(x_display);
|
|
#ifdef OPENVMS
|
|
x_fd = vms_x11_fd(x_fd);
|
|
#endif
|
|
set_handlers(x_fd, x_process_events, NULL, NULL);
|
|
|
|
setup_pixmap_handler();
|
|
|
|
XSync(x_display, False);
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
return NULL;
|
|
|
|
ret_err:
|
|
x_free_hash_table();
|
|
return err;
|
|
}
|
|
|
|
|
|
/* close connection with the X server */
|
|
static void x_shutdown_driver(void)
|
|
{
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_shutdown_driver\n");
|
|
#endif
|
|
set_handlers(x_fd, NULL, NULL, NULL);
|
|
x_free_hash_table();
|
|
}
|
|
|
|
#ifdef X_INPUT_METHOD
|
|
static XIC x_open_xic(Window w)
|
|
{
|
|
return XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, w, XNFocusWindow, w, NULL);
|
|
}
|
|
#endif
|
|
|
|
/* create new window */
|
|
static struct graphics_device *x_init_device(void)
|
|
{
|
|
struct graphics_device *dev;
|
|
XWMHints wm_hints;
|
|
XClassHint class_hints;
|
|
XTextProperty windowName;
|
|
char_p links_name = "Links";
|
|
XSetWindowAttributes win_attr;
|
|
struct window_info *wi;
|
|
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_init_device\n");
|
|
#endif
|
|
dev = mem_alloc(sizeof(struct graphics_device));
|
|
|
|
wi = mem_calloc(sizeof(struct window_info));
|
|
|
|
dev->size.x1 = 0;
|
|
dev->size.y1 = 0;
|
|
dev->size.x2 = x_default_window_width;
|
|
dev->size.y2 = x_default_window_height;
|
|
|
|
if (x_have_palette) win_attr.colormap = x_colormap;
|
|
else win_attr.colormap = x_default_colormap;
|
|
win_attr.border_pixel = x_black_pixel;
|
|
|
|
x_prepare_for_failure(X_CreateWindow);
|
|
wi->window = XCreateWindow(
|
|
x_display,
|
|
x_root_window,
|
|
dev->size.x1,
|
|
dev->size.y1,
|
|
dev->size.x2,
|
|
dev->size.y2,
|
|
0,
|
|
x_depth,
|
|
InputOutput,
|
|
x_default_visual,
|
|
CWColormap | CWBorderPixel,
|
|
&win_attr
|
|
);
|
|
if (x_test_for_failure()) {
|
|
x_prepare_for_failure(X_DestroyWindow);
|
|
XDestroyWindow(x_display, wi->window);
|
|
x_test_for_failure();
|
|
mem_free(dev);
|
|
mem_free(wi);
|
|
return NULL;
|
|
}
|
|
|
|
if (!x_icon) {
|
|
XImage_p img;
|
|
unsigned char *data;
|
|
char_p xx_data;
|
|
int w, h;
|
|
ssize_t skip;
|
|
|
|
get_links_icon(&data, &w, &h, &skip, x_bitmap_scanline_pad);
|
|
x_convert_to_216(data, w, h, skip);
|
|
|
|
xx_data = x_dup(data, h * skip);
|
|
mem_free(data);
|
|
|
|
retry:
|
|
img = XCreateImage(x_display, x_default_visual, x_depth, ZPixmap, 0, xx_data, w, h, x_bitmap_scanline_pad << 3, (int)skip);
|
|
if (!img) {
|
|
if (out_of_memory(0, NULL, 0))
|
|
goto retry;
|
|
free(xx_data);
|
|
x_icon = 0;
|
|
goto nic_nebude_bobankove;
|
|
}
|
|
XSync(x_display, False);
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
x_prepare_for_failure(X_CreatePixmap);
|
|
x_icon = XCreatePixmap(x_display, wi->window, w, h, x_depth);
|
|
if (x_test_for_failure()) {
|
|
x_prepare_for_failure(X_FreePixmap);
|
|
XFreePixmap(x_display, x_icon);
|
|
x_test_for_failure();
|
|
x_icon = 0;
|
|
}
|
|
if (!x_icon) {
|
|
XDestroyImage(img);
|
|
x_icon = 0;
|
|
goto nic_nebude_bobankove;
|
|
}
|
|
|
|
XPutImage(x_display, x_icon, x_copy_gc, img, 0, 0, 0, 0, w, h);
|
|
XDestroyImage(img);
|
|
nic_nebude_bobankove:;
|
|
}
|
|
|
|
wm_hints.flags=InputHint;
|
|
wm_hints.input=True;
|
|
if (x_icon)
|
|
{
|
|
wm_hints.flags=InputHint|IconPixmapHint;
|
|
wm_hints.icon_pixmap=x_icon;
|
|
}
|
|
|
|
XSetWMHints(x_display, wi->window, &wm_hints);
|
|
class_hints.res_name = links_name;
|
|
class_hints.res_class = links_name;
|
|
XSetClassHint(x_display, wi->window, &class_hints);
|
|
XStringListToTextProperty(&links_name, 1, &windowName);
|
|
XSetWMName(x_display, wi->window, &windowName);
|
|
XStoreName(x_display, wi->window, links_name);
|
|
XSetWMIconName(x_display, wi->window, &windowName);
|
|
XFree(windowName.value);
|
|
|
|
XMapWindow(x_display,wi->window);
|
|
|
|
dev->clip.x1=dev->size.x1;
|
|
dev->clip.y1=dev->size.y1;
|
|
dev->clip.x2=dev->size.x2;
|
|
dev->clip.y2=dev->size.y2;
|
|
dev->driver_data=wi;
|
|
dev->user_data=0;
|
|
|
|
XSetWindowBackgroundPixmap(x_display, wi->window, None);
|
|
x_add_to_table(dev);
|
|
|
|
XSetWMProtocols(x_display,wi->window,&x_delete_window_atom,1);
|
|
|
|
XSelectInput(x_display,wi->window,
|
|
ExposureMask|
|
|
KeyPressMask|
|
|
ButtonPressMask|
|
|
ButtonReleaseMask|
|
|
PointerMotionMask|
|
|
ButtonMotionMask|
|
|
StructureNotifyMask|
|
|
0
|
|
);
|
|
|
|
#ifdef X_INPUT_METHOD
|
|
if (xim) {
|
|
wi->xic = x_open_xic(wi->window);
|
|
}
|
|
#endif
|
|
|
|
XSync(x_display, False);
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
n_wins++;
|
|
return dev;
|
|
}
|
|
|
|
|
|
/* close window */
|
|
static void x_shutdown_device(struct graphics_device *dev)
|
|
{
|
|
struct window_info *wi = get_window_info(dev);
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_shutdown_device\n");
|
|
#endif
|
|
|
|
n_wins--;
|
|
XDestroyWindow(x_display, wi->window);
|
|
#ifdef X_INPUT_METHOD
|
|
if (wi->xic) {
|
|
XDestroyIC(wi->xic);
|
|
}
|
|
#endif
|
|
XSync(x_display, False);
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
|
|
x_remove_from_table(wi->window);
|
|
mem_free(wi);
|
|
mem_free(dev);
|
|
}
|
|
|
|
static void x_update_palette(void)
|
|
{
|
|
if (x_use_static_color_table == !x_driver.param->palette_mode)
|
|
return;
|
|
|
|
x_use_static_color_table = !x_driver.param->palette_mode;
|
|
|
|
if (x_use_static_color_table)
|
|
x_driver.depth = X_STATIC_CODE;
|
|
else
|
|
x_driver.depth = x_bitmap_bpp | (x_depth << 3);
|
|
|
|
x_get_color_function = get_color_fn(x_driver.depth);
|
|
if (!x_get_color_function)
|
|
internal_error("x: unsupported depth %d", x_driver.depth);
|
|
|
|
x_set_palette();
|
|
}
|
|
|
|
static unsigned short *x_get_real_colors(void)
|
|
{
|
|
int perfect = 1;
|
|
int i;
|
|
unsigned short *v;
|
|
if (!x_use_static_color_table)
|
|
return NULL;
|
|
v = mem_calloc(256 * 3 * sizeof(unsigned short));
|
|
for (i = 0; i < X_STATIC_COLORS; i++) {
|
|
unsigned idx = static_color_table[i];
|
|
v[i * 3 + 0] = static_color_map[idx].red;
|
|
v[i * 3 + 1] = static_color_map[idx].green;
|
|
v[i * 3 + 2] = static_color_map[idx].blue;
|
|
if (perfect) {
|
|
unsigned rgb[256];
|
|
q_palette(X_STATIC_COLORS, i, 65535, rgb);
|
|
if (static_color_map[idx].red != rgb[0] ||
|
|
static_color_map[idx].green != rgb[1] ||
|
|
static_color_map[idx].blue != rgb[2]) {
|
|
/*fprintf(stderr, "imperfect %d: %04x,%04x,%04x - %04x,%04x,%04x\n", i, rgb[0], rgb[1], rgb[2], static_color_map[idx].red, static_color_map[idx].green, static_color_map[idx].blue);*/
|
|
perfect = 0;
|
|
}
|
|
}
|
|
}
|
|
if (perfect) {
|
|
mem_free(v);
|
|
return NULL;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
static void x_translate_colors(unsigned char *data, int x, int y, ssize_t skip)
|
|
{
|
|
int i, j;
|
|
|
|
if (color_map_16bit) {
|
|
for (j = 0; j < y; j++) {
|
|
for (i = 0; i < x; i++) {
|
|
unsigned short s = color_map_16bit[data[2*i]] |
|
|
color_map_16bit[data[2*i + 1] + 256];
|
|
data[2*i] = (unsigned char)s;
|
|
data[2*i + 1] = (unsigned char)(s >> 8);
|
|
}
|
|
data += skip;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (color_map_24bit && x_bitmap_bpp == 3) {
|
|
for (j = 0; j < y; j++) {
|
|
for (i = 0; i < x; i++) {
|
|
unsigned s = color_map_24bit[data[3*i]] |
|
|
color_map_24bit[data[3*i + 1] + 256] |
|
|
color_map_24bit[data[3*i + 2] + 256 * 2];
|
|
data[3*i] = (unsigned char)s;
|
|
data[3*i + 1] = (unsigned char)(s >> 8);
|
|
data[3*i + 2] = (unsigned char)(s >> 16);
|
|
}
|
|
data += skip;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (color_map_24bit && x_bitmap_bpp == 4) {
|
|
for (j = 0; j < y; j++) {
|
|
for (i = 0; i < x; i++) {
|
|
unsigned s = color_map_24bit[data[4*i]] |
|
|
color_map_24bit[data[4*i + 1] + 256] |
|
|
color_map_24bit[data[4*i + 2] + 256 * 2];
|
|
data[4*i] = (unsigned char)s;
|
|
data[4*i + 1] = (unsigned char)(s >> 8);
|
|
data[4*i + 2] = (unsigned char)(s >> 16);
|
|
data[4*i + 3] = (unsigned char)(s >> 24);
|
|
}
|
|
data += skip;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (x_use_static_color_table) {
|
|
for (j = 0; j < y; j++) {
|
|
for (i = 0; i < x; i++)
|
|
data[i] = static_color_table[data[i]];
|
|
data += skip;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void x_convert_to_216(unsigned char *data, int x, int y, ssize_t skip)
|
|
{
|
|
unsigned char color_table[256];
|
|
int i, j;
|
|
|
|
if (!static_color_table)
|
|
return;
|
|
if (x_use_static_color_table) {
|
|
x_translate_colors(data, x, y, skip);
|
|
return;
|
|
}
|
|
|
|
memset(color_table, 255, sizeof color_table);
|
|
|
|
for (j = 0; j < y; j++) {
|
|
for (i = 0; i < x; i++) {
|
|
unsigned char a = data[i];
|
|
unsigned char result;
|
|
if (color_table[a] != 255) {
|
|
result = color_table[a];
|
|
} else {
|
|
unsigned rgb[3];
|
|
q_palette(256, a, 65535, rgb);
|
|
result = (unsigned char)get_nearest_color(rgb);
|
|
color_table[a] = result;
|
|
}
|
|
data[i] = result;
|
|
}
|
|
data += skip;
|
|
}
|
|
}
|
|
|
|
static int x_get_empty_bitmap(struct bitmap *bmp)
|
|
{
|
|
struct x_pixmapa *p;
|
|
int pad;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_get_empty_bitmap\n");
|
|
#endif
|
|
p = mem_alloc(sizeof(struct x_pixmapa));
|
|
p->type = X_TYPE_NOTHING;
|
|
add_to_list(bitmaps, p);
|
|
bmp->data = NULL;
|
|
bmp->flags = p;
|
|
if (bmp->x > (MAXINT - x_bitmap_scanline_pad) / x_bitmap_bpp)
|
|
return -1;
|
|
pad = x_bitmap_scanline_pad - ((bmp->x * x_bitmap_bpp) % x_bitmap_scanline_pad);
|
|
if (pad == x_bitmap_scanline_pad) pad = 0;
|
|
bmp->skip = (ssize_t)bmp->x * x_bitmap_bpp + pad;
|
|
if (bmp->skip > MAXINT / bmp->y)
|
|
return -1;
|
|
bmp->data = x_malloc(bmp->skip * bmp->y, 1);
|
|
if (!bmp->data)
|
|
return -1;
|
|
/* on error bmp->data should point to NULL */
|
|
return 0;
|
|
}
|
|
|
|
static void x_register_bitmap(struct bitmap *bmp)
|
|
{
|
|
struct x_pixmapa *p;
|
|
XImage_p image;
|
|
Pixmap pixmap = 0; /* shut up warning */
|
|
int can_create_pixmap;
|
|
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_register_bitmap\n");
|
|
#endif
|
|
|
|
if (!bmp->data || !bmp->x || !bmp->y) goto cant_create;
|
|
|
|
x_translate_colors(bmp->data, bmp->x, bmp->y, bmp->skip);
|
|
|
|
/* alloc XImage in client's memory */
|
|
retry:
|
|
image = XCreateImage(x_display, x_default_visual, x_depth, ZPixmap, 0, (char_p)bmp->data, bmp->x, bmp->y, x_bitmap_scanline_pad << 3, (int)bmp->skip);
|
|
if (!image) {
|
|
if (out_of_memory(0, NULL, 0))
|
|
goto retry;
|
|
goto cant_create;
|
|
}
|
|
|
|
/* try to alloc XPixmap in server's memory */
|
|
can_create_pixmap = 1;
|
|
|
|
if (bmp->x >= 32768 || bmp->y >= 32768) {
|
|
can_create_pixmap = 0;
|
|
goto no_pixmap;
|
|
}
|
|
|
|
if (!pixmap_mode) x_prepare_for_failure(X_CreatePixmap);
|
|
pixmap = XCreatePixmap(x_display, fake_window, bmp->x, bmp->y /*+ !(random() % 200) * 32768*/, x_depth);
|
|
if (!pixmap_mode && x_test_for_failure()) {
|
|
if (pixmap) {
|
|
x_prepare_for_failure(X_FreePixmap);
|
|
XFreePixmap(x_display, pixmap);
|
|
x_test_for_failure();
|
|
pixmap = 0;
|
|
}
|
|
}
|
|
if (!pixmap) {
|
|
can_create_pixmap = 0;
|
|
}
|
|
|
|
no_pixmap:
|
|
|
|
p = XPIXMAPP(bmp->flags);
|
|
|
|
if (can_create_pixmap) {
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_register_bitmap: creating pixmap\n");
|
|
#endif
|
|
XPutImage(x_display, pixmap, x_copy_gc, image, 0, 0, 0, 0, bmp->x, bmp->y);
|
|
XDestroyImage(image);
|
|
p->type = X_TYPE_PIXMAP;
|
|
p->data.pixmap = pixmap;
|
|
} else {
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_register_bitmap: creating image\n");
|
|
#endif
|
|
p->type = X_TYPE_IMAGE;
|
|
p->data.image = image;
|
|
}
|
|
bmp->data = NULL;
|
|
return;
|
|
|
|
cant_create:
|
|
if (bmp->data) free(bmp->data), bmp->data = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
static void x_unregister_bitmap(struct bitmap *bmp)
|
|
{
|
|
struct x_pixmapa *p = XPIXMAPP(bmp->flags);
|
|
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_unregister_bitmap\n");
|
|
#endif
|
|
switch (p->type) {
|
|
case X_TYPE_NOTHING:
|
|
break;
|
|
|
|
case X_TYPE_PIXMAP:
|
|
XFreePixmap(x_display, p->data.pixmap); /* free XPixmap from server's memory */
|
|
break;
|
|
|
|
case X_TYPE_IMAGE:
|
|
XDestroyImage(p->data.image); /* free XImage from client's memory */
|
|
break;
|
|
|
|
default:
|
|
internal_error("invalid pixmap type %d", (int)p->type);
|
|
}
|
|
del_from_list(p);
|
|
mem_free(p); /* struct x_pixmap */
|
|
}
|
|
|
|
static long x_get_color(int rgb)
|
|
{
|
|
long block;
|
|
unsigned char *b;
|
|
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_get_color\n");
|
|
#endif
|
|
block = x_get_color_function(rgb);
|
|
b = (unsigned char *)█
|
|
|
|
x_translate_colors(b, 1, 1, 0);
|
|
|
|
/*fprintf(stderr, "bitmap bpp %d\n", x_bitmap_bpp);*/
|
|
switch (x_bitmap_bpp) {
|
|
case 1: return b[0];
|
|
case 2: if (x_bitmap_bit_order == LSBFirst)
|
|
return (unsigned)b[0] | ((unsigned)b[1] << 8);
|
|
else
|
|
return (unsigned)b[1] | ((unsigned)b[0] << 8);
|
|
case 3:
|
|
if (x_bitmap_bit_order == LSBFirst)
|
|
return (unsigned)b[0] | ((unsigned)b[1] << 8) | ((unsigned)b[2] << 16);
|
|
else
|
|
return (unsigned)b[2] | ((unsigned)b[1] << 8) | ((unsigned)b[0] << 16);
|
|
default: if (x_bitmap_bit_order == LSBFirst)
|
|
return (unsigned)b[0] | ((unsigned)b[1] << 8) | ((unsigned)b[2] << 16) | ((unsigned)b[3] << 24);
|
|
else
|
|
return (unsigned)b[3] | ((unsigned)b[2] << 8) | ((unsigned)b[1] << 16) | ((unsigned)b[0] << 24);
|
|
}
|
|
}
|
|
|
|
|
|
static inline void x_set_color(long color)
|
|
{
|
|
if (color != x_normal_gc_color) {
|
|
x_normal_gc_color = color;
|
|
XSetForeground(x_display, x_normal_gc, color);
|
|
}
|
|
}
|
|
|
|
|
|
static void x_fill_area(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
|
|
{
|
|
#ifdef X_DEBUG
|
|
{
|
|
char txt[256];
|
|
sprintf(txt,"x_fill_area (x1=%d y1=%d x2=%d y2=%d)\n",x1,y1,x2,y2);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
|
|
CLIP_FILL_AREA
|
|
|
|
x_set_color(color);
|
|
XFillRectangle(
|
|
x_display,
|
|
get_window_info(dev)->window,
|
|
x_normal_gc,
|
|
x1,
|
|
y1,
|
|
x2 - x1,
|
|
y2 - y1
|
|
);
|
|
X_FLUSH();
|
|
}
|
|
|
|
|
|
static void x_draw_hline(struct graphics_device *dev, int x1, int y, int x2, long color)
|
|
{
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_draw_hline\n");
|
|
#endif
|
|
|
|
CLIP_DRAW_HLINE
|
|
|
|
x_set_color(color);
|
|
XDrawLine(
|
|
x_display,
|
|
get_window_info(dev)->window,
|
|
x_normal_gc,
|
|
x1,
|
|
y,
|
|
x2 - 1,
|
|
y
|
|
);
|
|
X_FLUSH();
|
|
}
|
|
|
|
|
|
static void x_draw_vline(struct graphics_device *dev, int x, int y1, int y2, long color)
|
|
{
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_draw_vline\n");
|
|
#endif
|
|
|
|
CLIP_DRAW_VLINE
|
|
|
|
x_set_color(color);
|
|
XDrawLine(
|
|
x_display,
|
|
get_window_info(dev)->window,
|
|
x_normal_gc,
|
|
x,
|
|
y1,
|
|
x,
|
|
y2 - 1
|
|
);
|
|
X_FLUSH();
|
|
}
|
|
|
|
|
|
static void x_draw_bitmap(struct graphics_device *dev, struct bitmap *bmp, int x, int y)
|
|
{
|
|
struct x_pixmapa *p;
|
|
int bmp_off_x, bmp_off_y, bmp_size_x, bmp_size_y;
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_draw_bitmap\n");
|
|
#endif
|
|
CLIP_DRAW_BITMAP
|
|
|
|
bmp_off_x = 0;
|
|
bmp_off_y = 0;
|
|
bmp_size_x = bmp->x;
|
|
bmp_size_y = bmp->y;
|
|
if (x < dev->clip.x1) {
|
|
bmp_off_x = dev->clip.x1 - x;
|
|
bmp_size_x -= dev->clip.x1 - x;
|
|
x = dev->clip.x1;
|
|
}
|
|
if (x + bmp_size_x > dev->clip.x2) {
|
|
bmp_size_x = dev->clip.x2 - x;
|
|
}
|
|
if (y < dev->clip.y1) {
|
|
bmp_off_y = dev->clip.y1 - y;
|
|
bmp_size_y -= dev->clip.y1 - y;
|
|
y = dev->clip.y1;
|
|
}
|
|
if (y + bmp_size_y > dev->clip.y2) {
|
|
bmp_size_y = dev->clip.y2 - y;
|
|
}
|
|
|
|
p = XPIXMAPP(bmp->flags);
|
|
|
|
switch (p->type) {
|
|
case X_TYPE_NOTHING:
|
|
break;
|
|
|
|
case X_TYPE_PIXMAP:
|
|
XCopyArea(x_display, p->data.pixmap, get_window_info(dev)->window, x_drawbitmap_gc, bmp_off_x, bmp_off_y, bmp_size_x, bmp_size_y, x, y);
|
|
break;
|
|
|
|
case X_TYPE_IMAGE:
|
|
XPutImage(x_display, get_window_info(dev)->window, x_drawbitmap_gc, p->data.image, bmp_off_x, bmp_off_y, x, y, bmp_size_x, bmp_size_y);
|
|
break;
|
|
|
|
default:
|
|
internal_error("invalid pixmap type %d", (int)p->type);
|
|
}
|
|
X_FLUSH();
|
|
}
|
|
|
|
|
|
static void *x_prepare_strip(struct bitmap *bmp, int top, int lines)
|
|
{
|
|
struct x_pixmapa *p = XPIXMAPP(bmp->flags);
|
|
XImage *image;
|
|
void_p x_data;
|
|
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_prepare_strip\n");
|
|
#endif
|
|
|
|
bmp->data = NULL;
|
|
|
|
switch (p->type) {
|
|
case X_TYPE_NOTHING:
|
|
return NULL;
|
|
|
|
case X_TYPE_PIXMAP:
|
|
x_data = x_malloc(bmp->skip * lines, 1);
|
|
if (!x_data) {
|
|
return NULL;
|
|
}
|
|
|
|
retry2:
|
|
image = XCreateImage(x_display, x_default_visual, x_depth, ZPixmap, 0, x_data, bmp->x, lines, x_bitmap_scanline_pad << 3, (int)bmp->skip);
|
|
if (!image) {
|
|
if (out_of_memory(0, NULL, 0))
|
|
goto retry2;
|
|
free(x_data);
|
|
return NULL;
|
|
}
|
|
bmp->data = image;
|
|
return image->data;
|
|
|
|
case X_TYPE_IMAGE:
|
|
return p->data.image->data+(bmp->skip*top);
|
|
}
|
|
internal_error("invalid pixmap type %d", (int)p->type);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static void x_commit_strip(struct bitmap *bmp, int top, int lines)
|
|
{
|
|
struct x_pixmapa *p = XPIXMAPP(bmp->flags);
|
|
|
|
#ifdef X_DEBUG
|
|
MESSAGE("x_commit_strip\n");
|
|
#endif
|
|
switch (p->type) {
|
|
case X_TYPE_NOTHING:
|
|
return;
|
|
|
|
case X_TYPE_PIXMAP:
|
|
/* send image to pixmap in xserver */
|
|
if (!bmp->data) return;
|
|
x_translate_colors((unsigned char *)((XImage *)bmp->data)->data, bmp->x, lines, bmp->skip);
|
|
XPutImage(x_display, p->data.pixmap, x_copy_gc, (XImage_p)bmp->data, 0, 0, 0, top, bmp->x, lines);
|
|
XDestroyImage((XImage_p)bmp->data);
|
|
return;
|
|
|
|
case X_TYPE_IMAGE:
|
|
x_translate_colors((unsigned char *)p->data.image->data + (bmp->skip * top), bmp->x, lines, bmp->skip);
|
|
/* everything has been done by user */
|
|
return;
|
|
}
|
|
|
|
internal_error("invalid pixmap type %d", (int)p->type);
|
|
}
|
|
|
|
|
|
static int x_scroll(struct graphics_device *dev, struct rect_set **set, int scx, int scy)
|
|
{
|
|
XEvent ev;
|
|
struct rect r;
|
|
|
|
if (memcmp(&dev->clip, &x_scroll_gc_rect, sizeof(struct rect))) {
|
|
XRectangle xr;
|
|
|
|
memcpy(&x_scroll_gc_rect, &dev->clip, sizeof(struct rect));
|
|
|
|
xr.x = dev->clip.x1;
|
|
xr.y = dev->clip.y1;
|
|
xr.width = dev->clip.x2 - dev->clip.x1;
|
|
xr.height = dev->clip.y2 - dev->clip.y1;
|
|
|
|
XSetClipRectangles(x_display, x_scroll_gc, 0, 0, &xr, 1, Unsorted);
|
|
}
|
|
|
|
XCopyArea(
|
|
x_display,
|
|
get_window_info(dev)->window,
|
|
get_window_info(dev)->window,
|
|
x_scroll_gc,
|
|
dev->clip.x1,
|
|
dev->clip.y1,
|
|
dev->clip.x2 - dev->clip.x1,
|
|
dev->clip.y2 - dev->clip.y1,
|
|
dev->clip.x1 + scx,
|
|
dev->clip.y1 + scy
|
|
);
|
|
XSync(x_display, False);
|
|
/* ten sync tady musi byt, protoze potrebuju zarucit, aby vsechny
|
|
* graphics-expose vyvolane timto scrollem byly vraceny v rect-set */
|
|
|
|
/* take all graphics expose events for this window and put them into the rect set */
|
|
while (XCheckWindowEvent(x_display, get_window_info(dev)->window, ExposureMask, &ev) == True) {
|
|
switch(ev.type) {
|
|
case GraphicsExpose:
|
|
r.x1 = ev.xgraphicsexpose.x;
|
|
r.y1 = ev.xgraphicsexpose.y;
|
|
r.x2 = ev.xgraphicsexpose.x + ev.xgraphicsexpose.width;
|
|
r.y2 = ev.xgraphicsexpose.y + ev.xgraphicsexpose.height;
|
|
break;
|
|
|
|
case Expose:
|
|
r.x1 = ev.xexpose.x;
|
|
r.y1 = ev.xexpose.y;
|
|
r.x2 = ev.xexpose.x + ev.xexpose.width;
|
|
r.y2 = ev.xexpose.y + ev.xexpose.height;
|
|
break;
|
|
|
|
default:
|
|
continue;
|
|
}
|
|
if (r.x1 < dev->clip.x1 || r.x2 > dev->clip.x2 ||
|
|
r.y1 < dev->clip.y1 || r.y2 > dev->clip.y2) {
|
|
/*fprintf(stderr, "rect out of scoll area: (%d,%d,%d,%d) - (%d,%d,%d,%d)\n", r.x1, r.x2, r.y1, r.y2, dev->clip.x1, dev->clip.x2, dev->clip.y1, dev->clip.y2);*/
|
|
switch(ev.type) {
|
|
case GraphicsExpose:
|
|
ev.xgraphicsexpose.x = 0;
|
|
ev.xgraphicsexpose.y = 0;
|
|
ev.xgraphicsexpose.width = dev->size.x2;
|
|
ev.xgraphicsexpose.height = dev->size.y2;
|
|
break;
|
|
|
|
case Expose:
|
|
ev.xexpose.x = 0;
|
|
ev.xexpose.y = 0;
|
|
ev.xexpose.width = dev->size.x2;
|
|
ev.xexpose.height = dev->size.y2;
|
|
break;
|
|
}
|
|
XPutBackEvent(x_display, &ev);
|
|
mem_free(*set);
|
|
*set = init_rect_set();
|
|
break;
|
|
}
|
|
add_to_rect_set(set, &r);
|
|
}
|
|
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
|
|
#ifdef SC_DEBUG
|
|
MESSAGE("hscroll\n");
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void x_flush(struct graphics_device *dev)
|
|
{
|
|
unregister_bottom_half(x_do_flush, NULL);
|
|
x_do_flush(NULL);
|
|
}
|
|
|
|
|
|
static void x_set_window_title(struct graphics_device *dev, unsigned char *title)
|
|
{
|
|
unsigned char *t;
|
|
char_p xx_str;
|
|
XTextProperty windowName;
|
|
int output_encoding;
|
|
Status ret;
|
|
|
|
#if defined(HAVE_XSUPPORTSLOCALE) && defined(HAVE_XMBTEXTLISTTOTEXTPROPERTY)
|
|
if (XSupportsLocale()) {
|
|
output_encoding = x_input_encoding >= 0 ? x_input_encoding : 0;
|
|
} else
|
|
retry_encode_ascii:
|
|
#endif
|
|
{
|
|
output_encoding = 0;
|
|
}
|
|
|
|
if (!dev)internal_error("x_set_window_title called with NULL graphics_device pointer.\n");
|
|
t = convert(utf8_table, output_encoding, title, NULL);
|
|
clr_white(t);
|
|
/*XStoreName(x_display,get_window_info(dev)->window,"blabla");*/
|
|
|
|
xx_str = x_dup(t, strlen(cast_const_char t) + 1);
|
|
mem_free(t);
|
|
|
|
#if defined(HAVE_XSUPPORTSLOCALE) && defined(HAVE_XMBTEXTLISTTOTEXTPROPERTY)
|
|
if (XSupportsLocale()) {
|
|
ret = XmbTextListToTextProperty(x_display, &xx_str, 1, XStdICCTextStyle, &windowName);
|
|
#ifdef X_HAVE_UTF8_STRING
|
|
if (ret > 0) {
|
|
XFree(windowName.value);
|
|
ret = XmbTextListToTextProperty(x_display, &xx_str, 1, XUTF8StringStyle, &windowName);
|
|
if (ret < 0) {
|
|
ret = XmbTextListToTextProperty(x_display, &xx_str, 1, XStdICCTextStyle, &windowName);
|
|
}
|
|
}
|
|
#endif
|
|
if (ret < 0) {
|
|
if (output_encoding) {
|
|
free(xx_str);
|
|
goto retry_encode_ascii;
|
|
} else {
|
|
goto retry_print_ascii;
|
|
}
|
|
}
|
|
} else
|
|
retry_print_ascii:
|
|
#endif
|
|
{
|
|
ret = XStringListToTextProperty(&xx_str, 1, &windowName);
|
|
if (!ret) {
|
|
free(xx_str);
|
|
return;
|
|
}
|
|
}
|
|
free(xx_str);
|
|
XSetWMName(x_display, get_window_info(dev)->window, &windowName);
|
|
XSetWMIconName(x_display, get_window_info(dev)->window, &windowName);
|
|
XFree(windowName.value);
|
|
X_FLUSH();
|
|
}
|
|
|
|
/* gets string in UTF8 */
|
|
static void x_set_clipboard_text(unsigned char *text)
|
|
{
|
|
x_clear_clipboard();
|
|
if (text) {
|
|
x_my_clipboard = stracpy(text);
|
|
|
|
XSetSelectionOwner(x_display, XA_PRIMARY, fake_window, CurrentTime);
|
|
XFlush (x_display);
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
}
|
|
}
|
|
|
|
static void selection_request(XEvent *event)
|
|
{
|
|
XSelectionRequestEvent *req;
|
|
XSelectionEvent sel;
|
|
size_t l;
|
|
unsigned_char_p xx_str;
|
|
|
|
req = &(event->xselectionrequest);
|
|
sel.type = SelectionNotify;
|
|
sel.requestor = req->requestor;
|
|
sel.selection = XA_PRIMARY;
|
|
sel.target = req->target;
|
|
sel.property = req->property;
|
|
sel.time = req->time;
|
|
sel.display = req->display;
|
|
#ifdef X_DEBUG
|
|
{
|
|
char txt[256];
|
|
sprintf (txt,"xselectionrequest from %i\n",(int)event->xselection.requestor);
|
|
MESSAGE(txt);
|
|
sprintf (txt,"property:%i target:%i selection:%i\n", req->property,req->target, req->selection);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
x_prepare_for_failure(X_ChangeProperty);
|
|
if (req->target == XA_STRING) {
|
|
unsigned char *str, *p;
|
|
if (!x_my_clipboard) str = stracpy(cast_uchar "");
|
|
else str = convert(utf8_table, get_cp_index(cast_uchar "iso-8859-1"), x_my_clipboard, NULL);
|
|
for (p = cast_uchar strchr(cast_const_char str, 1); p; p = cast_uchar strchr(cast_const_char(str + 1), 1)) *p = 0xa0;
|
|
l = strlen(cast_const_char str);
|
|
if (l > X_MAX_CLIPBOARD_SIZE) l = X_MAX_CLIPBOARD_SIZE;
|
|
xx_str = x_dup(str, l);
|
|
XChangeProperty (x_display,
|
|
sel.requestor,
|
|
sel.property,
|
|
XA_STRING,
|
|
8,
|
|
PropModeReplace,
|
|
xx_str,
|
|
(int)l
|
|
);
|
|
mem_free(str);
|
|
free(xx_str);
|
|
} else if (req->target == x_utf8_string_atom) {
|
|
l = x_my_clipboard ? strlen(cast_const_char x_my_clipboard) : 0;
|
|
if (l > X_MAX_CLIPBOARD_SIZE) l = X_MAX_CLIPBOARD_SIZE;
|
|
xx_str = x_dup(x_my_clipboard, l);
|
|
XChangeProperty (x_display,
|
|
sel.requestor,
|
|
sel.property,
|
|
x_utf8_string_atom,
|
|
8,
|
|
PropModeReplace,
|
|
xx_str,
|
|
(int)l
|
|
);
|
|
free(xx_str);
|
|
} else if (req->target == x_targets_atom) {
|
|
unsigned tgt_atoms[3];
|
|
tgt_atoms[0] = (unsigned)x_targets_atom;
|
|
tgt_atoms[1] = XA_STRING;
|
|
tgt_atoms[2] = (unsigned)x_utf8_string_atom;
|
|
XChangeProperty (x_display,
|
|
sel.requestor,
|
|
sel.property,
|
|
XA_ATOM,
|
|
32,
|
|
PropModeReplace,
|
|
(unsigned_char_p)&tgt_atoms,
|
|
3
|
|
);
|
|
} else {
|
|
#ifdef X_DEBUG
|
|
{
|
|
char txt[256];
|
|
sprintf (txt,"Non-String wanted: %i\n",(int)req->target);
|
|
MESSAGE(txt);
|
|
}
|
|
#endif
|
|
sel.property = None;
|
|
}
|
|
if (x_test_for_failure())
|
|
return;
|
|
x_prepare_for_failure(X_SendEvent);
|
|
XSendEvent(x_display, sel.requestor, 0, 0, (XEvent_p)&sel);
|
|
x_test_for_failure();
|
|
}
|
|
|
|
static unsigned char *x_get_clipboard_text(void)
|
|
{
|
|
XEvent event;
|
|
Atom type_atom = x_utf8_string_atom;
|
|
uttime t;
|
|
|
|
retry:
|
|
XConvertSelection(x_display, XA_PRIMARY, type_atom, x_sel_atom, fake_window, CurrentTime);
|
|
|
|
t = get_time();
|
|
|
|
while (1) {
|
|
uttime tt;
|
|
int w;
|
|
XSync(x_display, False);
|
|
if (XCheckTypedEvent(x_display,SelectionRequest, &event)) {
|
|
selection_request(&event);
|
|
continue;
|
|
}
|
|
if (XCheckTypedEvent(x_display,SelectionNotify, &event)) break;
|
|
tt = get_time() - t;
|
|
if (tt > SELECTION_NOTIFY_TIMEOUT)
|
|
w = 0;
|
|
else
|
|
w = (SELECTION_NOTIFY_TIMEOUT - (unsigned)tt + 999) / 1000;
|
|
if (!x_wait_for_event(w))
|
|
goto no_new_sel;
|
|
}
|
|
if (event.xselection.property) {
|
|
unsigned_char_p buffer;
|
|
unsigned long pty_size, pty_items;
|
|
int pty_format, ret;
|
|
Atom pty_type;
|
|
|
|
if (event.xselection.target != type_atom) goto no_new_sel;
|
|
if (event.xselection.property != x_sel_atom) goto no_new_sel;
|
|
|
|
|
|
/* Get size and type of property */
|
|
ret = XGetWindowProperty(
|
|
x_display,
|
|
fake_window,
|
|
event.xselection.property,
|
|
0,
|
|
0,
|
|
False,
|
|
AnyPropertyType,
|
|
&pty_type,
|
|
&pty_format,
|
|
&pty_items,
|
|
&pty_size,
|
|
&buffer);
|
|
if (ret != Success) goto no_new_sel;
|
|
XFree(buffer);
|
|
|
|
ret = XGetWindowProperty(
|
|
x_display,
|
|
fake_window,
|
|
event.xselection.property,
|
|
0,
|
|
(long)pty_size,
|
|
True,
|
|
AnyPropertyType,
|
|
&pty_type,
|
|
&pty_format,
|
|
&pty_items,
|
|
&pty_size,
|
|
&buffer
|
|
);
|
|
if (ret != Success) goto no_new_sel;
|
|
|
|
pty_size = (pty_format>>3) * pty_items;
|
|
|
|
x_clear_clipboard();
|
|
if (type_atom == x_utf8_string_atom) {
|
|
x_my_clipboard = stracpy(buffer);
|
|
} else {
|
|
x_my_clipboard = convert(get_cp_index(cast_uchar "iso-8859-1"), utf8_table, buffer, NULL);
|
|
}
|
|
XFree(buffer);
|
|
} else {
|
|
if (type_atom == x_utf8_string_atom) {
|
|
type_atom = XA_STRING;
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
no_new_sel:
|
|
X_SCHEDULE_PROCESS_EVENTS();
|
|
if (!x_my_clipboard) return NULL;
|
|
return stracpy(x_my_clipboard);
|
|
}
|
|
|
|
struct graphics_driver x_driver = {
|
|
cast_uchar "x",
|
|
x_init_driver,
|
|
x_init_device,
|
|
x_shutdown_device,
|
|
x_shutdown_driver,
|
|
NULL,
|
|
x_after_fork,
|
|
x_get_driver_param,
|
|
x_get_af_unix_name,
|
|
NULL,
|
|
NULL,
|
|
x_get_empty_bitmap,
|
|
x_register_bitmap,
|
|
x_prepare_strip,
|
|
x_commit_strip,
|
|
x_unregister_bitmap,
|
|
x_draw_bitmap,
|
|
x_get_color,
|
|
x_fill_area,
|
|
x_draw_hline,
|
|
x_draw_vline,
|
|
x_scroll,
|
|
NULL,
|
|
x_flush,
|
|
NULL, /* block */
|
|
NULL, /* unblock */
|
|
x_update_palette,
|
|
x_get_real_colors,
|
|
x_set_window_title,
|
|
x_exec,
|
|
x_set_clipboard_text,
|
|
x_get_clipboard_text,
|
|
0, /* depth (filled in x_init_driver function) */
|
|
0, 0, /* size (in X is empty) */
|
|
GD_UNICODE_KEYS, /* flags */
|
|
NULL, /* param */
|
|
};
|
|
|
|
#endif /* GRDRV_X */
|