Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3584 sourcerer 1
/*
2
 * Copyright 2009 Vincent Sanders 
3
 *
4
 * This file is part of libnsfb, http://www.netsurf-browser.org/
5
 * Licenced under the MIT License,
6
 *                http://www.opensource.org/licenses/mit-license.php
7
 */
8
 
9
#define _XOPEN_SOURCE 500
10
 
11
#include 
12
#include 
13
#include 
14
#include 
15
 
16
#include 
17
#include 
18
 
19
#include 
20
#include 
21
#include 
22
#include 
23
#include 
24
#include 
25
 
26
#include "libnsfb.h"
27
#include "libnsfb_event.h"
28
#include "libnsfb_plot.h"
29
#include "libnsfb_plot_util.h"
30
 
31
#include "nsfb.h"
32
#include "surface.h"
33
#include "plot.h"
34
#include "cursor.h"
35
 
36
#if defined(NSFB_NEED_HINTS_ALLOC)
37
static xcb_size_hints_t *
38
xcb_alloc_size_hints(void)
39
{
40
    return calloc(1, sizeof(xcb_size_hints_t));
41
}
42
 
43
static void
44
xcb_free_size_hints(xcb_size_hints_t *hints)
45
{
46
    free(hints);
47
}
48
#endif
49
 
50
#if defined(NSFB_NEED_ICCCM_API_PREFIX)
51
#define xcb_size_hints_set_max_size xcb_icccm_size_hints_set_max_size
52
#define xcb_size_hints_set_min_size xcb_icccm_size_hints_set_min_size
53
#define xcb_set_wm_size_hints       xcb_icccm_set_wm_size_hints
54
#endif
55
 
56
#if (NSFB_XCBPROTO_MAJOR_VERSION > 1) || \
57
    (NSFB_XCBPROTO_MAJOR_VERSION == 1 && NSFB_XCBPROTO_MINOR_VERSION >= 6)
58
#define WM_NORMAL_HINTS XCB_ATOM_WM_NORMAL_HINTS
59
#endif
60
 
61
#define X_BUTTON_LEFT 1
62
#define X_BUTTON_MIDDLE 2
63
#define X_BUTTON_RIGHT 3
64
#define X_BUTTON_WHEELUP 4
65
#define X_BUTTON_WHEELDOWN 5
66
 
67
typedef struct xstate_s {
68
    xcb_connection_t *connection; /* The x server connection */
69
    xcb_screen_t *screen; /* The screen to put the window on */
70
    xcb_key_symbols_t *keysymbols; /* keysym mappings */
71
 
72
    xcb_shm_segment_info_t shminfo;
73
 
74
    xcb_image_t *image; /* The X image buffer */
75
 
76
    xcb_window_t window; /* The handle to the window */
77
    xcb_pixmap_t pmap; /* The handle to the backing pixmap */
78
    xcb_gcontext_t gc; /* The handle to the pixmap plotting graphics context */
79
    xcb_shm_seg_t segment; /* The handle to the image shared memory */
80
} xstate_t;
81
 
82
/* X keyboard codepage to nsfb mapping*/
83
enum nsfb_key_code_e XCSKeyboardMap[256] = {
84
    NSFB_KEY_UNKNOWN, /* */
85
    NSFB_KEY_UNKNOWN, /* */
86
    NSFB_KEY_UNKNOWN, /* */
87
    NSFB_KEY_UNKNOWN, /* */
88
    NSFB_KEY_UNKNOWN, /* */
89
    NSFB_KEY_UNKNOWN, /* */
90
    NSFB_KEY_UNKNOWN, /* */
91
    NSFB_KEY_UNKNOWN, /* */
92
    NSFB_KEY_BACKSPACE, /* XK_BackSpace */
93
    NSFB_KEY_TAB, /* XK_Tab */
94
    NSFB_KEY_UNKNOWN, /* XK_Linefeed */
95
    NSFB_KEY_CLEAR, /* XK_Clear */
96
    NSFB_KEY_UNKNOWN, /* */
97
    NSFB_KEY_RETURN, /* XK_Return */
98
    NSFB_KEY_UNKNOWN, /* */
99
    NSFB_KEY_UNKNOWN, /* */
100
    /* 0x10 */
101
    NSFB_KEY_UNKNOWN, /* */
102
    NSFB_KEY_UNKNOWN, /* */
103
    NSFB_KEY_UNKNOWN, /* */
104
    NSFB_KEY_PAUSE, /* XK_Pause */
105
    NSFB_KEY_UNKNOWN, /* XK_Scroll_Lock */
106
    NSFB_KEY_UNKNOWN, /* XK_Sys_Req */
107
    NSFB_KEY_UNKNOWN, /* */
108
    NSFB_KEY_UNKNOWN, /* */
109
    NSFB_KEY_UNKNOWN, /* */
110
    NSFB_KEY_UNKNOWN, /* */
111
    NSFB_KEY_UNKNOWN, /* */
112
    NSFB_KEY_ESCAPE, /* XK_Escape */
113
    NSFB_KEY_UNKNOWN, /* */
114
    NSFB_KEY_UNKNOWN, /* */
115
    NSFB_KEY_UNKNOWN, /* */
116
    NSFB_KEY_UNKNOWN, /* */
117
    /* 0x20 */
118
    NSFB_KEY_UNKNOWN, /* XK_Multi_key */
119
    NSFB_KEY_UNKNOWN, /* XK_Kanji */
120
    NSFB_KEY_UNKNOWN, /* XK_Muhenkan */
121
    NSFB_KEY_UNKNOWN, /* XK_Henkan_Mode */
122
    NSFB_KEY_UNKNOWN, /* XK_Henkan */
123
    NSFB_KEY_UNKNOWN, /* XK_Romaji */
124
    NSFB_KEY_UNKNOWN, /* XK_Hiragana*/
125
    NSFB_KEY_UNKNOWN, /* */
126
    NSFB_KEY_UNKNOWN, /* */
127
    NSFB_KEY_UNKNOWN, /* */
128
    NSFB_KEY_UNKNOWN, /* */
129
    NSFB_KEY_UNKNOWN, /* */
130
    NSFB_KEY_UNKNOWN, /* */
131
    NSFB_KEY_UNKNOWN, /* */
132
    NSFB_KEY_UNKNOWN, /* */
133
    NSFB_KEY_UNKNOWN, /* */
134
    /* 0x30 */
135
    NSFB_KEY_UNKNOWN, /* XK_Eisu_toggle */
136
    NSFB_KEY_UNKNOWN, /* */
137
    NSFB_KEY_UNKNOWN, /* */
138
    NSFB_KEY_UNKNOWN, /* */
139
    NSFB_KEY_UNKNOWN, /* */
140
    NSFB_KEY_UNKNOWN, /* */
141
    NSFB_KEY_UNKNOWN, /* */
142
    NSFB_KEY_UNKNOWN, /* XK_Codeinput */
143
    NSFB_KEY_UNKNOWN, /* */
144
    NSFB_KEY_UNKNOWN, /* */
145
    NSFB_KEY_UNKNOWN, /* */
146
    NSFB_KEY_UNKNOWN, /* */
147
    NSFB_KEY_UNKNOWN, /* XK_SingleCandidate */
148
    NSFB_KEY_UNKNOWN, /* XK_MultipleCandidate */
149
    NSFB_KEY_UNKNOWN, /* XK_PreviousCandidate */
150
    NSFB_KEY_UNKNOWN, /* */
151
    /* 0x40 */
152
    NSFB_KEY_UNKNOWN, /* */
153
    NSFB_KEY_UNKNOWN, /* */
154
    NSFB_KEY_UNKNOWN, /* */
155
    NSFB_KEY_UNKNOWN, /* */
156
    NSFB_KEY_UNKNOWN, /* */
157
    NSFB_KEY_UNKNOWN, /* */
158
    NSFB_KEY_UNKNOWN, /* */
159
    NSFB_KEY_UNKNOWN, /* */
160
    NSFB_KEY_UNKNOWN, /* */
161
    NSFB_KEY_UNKNOWN, /* */
162
    NSFB_KEY_UNKNOWN, /* */
163
    NSFB_KEY_UNKNOWN, /* */
164
    NSFB_KEY_UNKNOWN, /* */
165
    NSFB_KEY_UNKNOWN, /* */
166
    NSFB_KEY_UNKNOWN, /* */
167
    NSFB_KEY_UNKNOWN, /* */
168
    /* 0x50 */
169
    NSFB_KEY_HOME, /* XK_Home */
170
    NSFB_KEY_LEFT, /* XK_Left */
171
    NSFB_KEY_UP, /* XK_Up */
172
    NSFB_KEY_RIGHT, /* XK_Right */
173
    NSFB_KEY_DOWN, /* XK_Down */
174
    NSFB_KEY_PAGEUP, /* XK_Page_Up */
175
    NSFB_KEY_PAGEDOWN, /* XK_Page_Down */
176
    NSFB_KEY_END, /* XK_End */
177
    NSFB_KEY_UNKNOWN, /* XK_Begin */
178
    NSFB_KEY_UNKNOWN, /* */
179
    NSFB_KEY_UNKNOWN, /* */
180
    NSFB_KEY_UNKNOWN, /* */
181
    NSFB_KEY_UNKNOWN, /* */
182
    NSFB_KEY_UNKNOWN, /* */
183
    NSFB_KEY_UNKNOWN, /* */
184
    NSFB_KEY_UNKNOWN, /* */
185
    /* 0x60 */
186
    NSFB_KEY_UNKNOWN, /* XK_Select */
187
    NSFB_KEY_UNKNOWN, /* XK_Print*/
188
    NSFB_KEY_UNKNOWN, /* XK_Execute*/
189
    NSFB_KEY_UNKNOWN, /* XK_Insert*/
190
    NSFB_KEY_UNKNOWN, /* */
191
    NSFB_KEY_UNKNOWN, /* XK_Undo*/
192
    NSFB_KEY_UNKNOWN, /* XK_Redo */
193
    NSFB_KEY_UNKNOWN, /* XK_Menu */
194
    NSFB_KEY_UNKNOWN, /* XK_Find */
195
    NSFB_KEY_UNKNOWN, /* XK_Cancel */
196
    NSFB_KEY_UNKNOWN, /* XK_Help */
197
    NSFB_KEY_UNKNOWN, /* XK_Break*/
198
    NSFB_KEY_UNKNOWN, /* */
199
    NSFB_KEY_UNKNOWN, /* */
200
    NSFB_KEY_UNKNOWN, /* */
201
    NSFB_KEY_UNKNOWN, /* */
202
    /* 0x70 */
203
    NSFB_KEY_UNKNOWN, /* */
204
    NSFB_KEY_UNKNOWN, /* */
205
    NSFB_KEY_UNKNOWN, /* */
206
    NSFB_KEY_UNKNOWN, /* */
207
    NSFB_KEY_UNKNOWN, /* */
208
    NSFB_KEY_UNKNOWN, /* */
209
    NSFB_KEY_UNKNOWN, /* */
210
    NSFB_KEY_UNKNOWN, /* */
211
    NSFB_KEY_UNKNOWN, /* */
212
    NSFB_KEY_UNKNOWN, /* */
213
    NSFB_KEY_UNKNOWN, /* */
214
    NSFB_KEY_UNKNOWN, /* */
215
    NSFB_KEY_UNKNOWN, /* */
216
    NSFB_KEY_UNKNOWN, /* */
217
    NSFB_KEY_UNKNOWN, /* XK_Mode_switch */
218
    NSFB_KEY_UNKNOWN, /* XK_Num_Lock */
219
    /* 0x80 */
220
    NSFB_KEY_UNKNOWN, /* XK_KP_Space */
221
    NSFB_KEY_UNKNOWN, /* */
222
    NSFB_KEY_UNKNOWN, /* */
223
    NSFB_KEY_UNKNOWN, /* */
224
    NSFB_KEY_UNKNOWN, /* */
225
    NSFB_KEY_UNKNOWN, /* */
226
    NSFB_KEY_UNKNOWN, /* */
227
    NSFB_KEY_UNKNOWN, /* */
228
    NSFB_KEY_UNKNOWN, /* */
229
    NSFB_KEY_UNKNOWN, /* XK_KP_Tab */
230
    NSFB_KEY_UNKNOWN, /* */
231
    NSFB_KEY_UNKNOWN, /* */
232
    NSFB_KEY_UNKNOWN, /* */
233
    NSFB_KEY_UNKNOWN, /* XK_KP_Enter */
234
    NSFB_KEY_UNKNOWN, /* */
235
    NSFB_KEY_UNKNOWN, /* */
236
    /* 0x90 */
237
    NSFB_KEY_UNKNOWN, /* */
238
    NSFB_KEY_UNKNOWN, /* XK_KP_F1*/
239
    NSFB_KEY_UNKNOWN, /* XK_KP_F2*/
240
    NSFB_KEY_UNKNOWN, /* XK_KP_F3*/
241
    NSFB_KEY_UNKNOWN, /* XK_KP_F4*/
242
    NSFB_KEY_UNKNOWN, /* XK_KP_Home*/
243
    NSFB_KEY_UNKNOWN, /* XK_KP_Left*/
244
    NSFB_KEY_UNKNOWN, /* XK_KP_Up*/
245
    NSFB_KEY_UNKNOWN, /* XK_KP_Right*/
246
    NSFB_KEY_UNKNOWN, /* XK_KP_Down*/
247
    NSFB_KEY_UNKNOWN, /* XK_KP_Page_Up*/
248
    NSFB_KEY_UNKNOWN, /* XK_KP_Page_Down*/
249
    NSFB_KEY_UNKNOWN, /* XK_KP_End*/
250
    NSFB_KEY_UNKNOWN, /* XK_KP_Begin*/
251
    NSFB_KEY_UNKNOWN, /* XK_KP_Insert*/
252
    NSFB_KEY_UNKNOWN, /* XK_KP_Delete*/
253
    /* 0xa0 */
254
    NSFB_KEY_UNKNOWN, /* */
255
    NSFB_KEY_UNKNOWN, /* */
256
    NSFB_KEY_UNKNOWN, /* */
257
    NSFB_KEY_UNKNOWN, /* */
258
    NSFB_KEY_UNKNOWN, /* */
259
    NSFB_KEY_UNKNOWN, /* */
260
    NSFB_KEY_UNKNOWN, /* */
261
    NSFB_KEY_UNKNOWN, /* */
262
    NSFB_KEY_UNKNOWN, /* */
263
    NSFB_KEY_UNKNOWN, /* */
264
    NSFB_KEY_UNKNOWN, /* XK_KP_Multiply*/
265
    NSFB_KEY_UNKNOWN, /* XK_KP_Add*/
266
    NSFB_KEY_UNKNOWN, /* XK_KP_Separator*/
267
    NSFB_KEY_UNKNOWN, /* XK_KP_Subtract*/
268
    NSFB_KEY_UNKNOWN, /* XK_KP_Decimal*/
269
    NSFB_KEY_UNKNOWN, /* XK_KP_Divide*/
270
    /* 0xb0 */
271
    NSFB_KEY_UNKNOWN, /* XK_KP_0 */
272
    NSFB_KEY_UNKNOWN, /* XK_KP_1 */
273
    NSFB_KEY_UNKNOWN, /* XK_KP_2 */
274
    NSFB_KEY_UNKNOWN, /* XK_KP_3 */
275
    NSFB_KEY_UNKNOWN, /* XK_KP_4 */
276
    NSFB_KEY_UNKNOWN, /* XK_KP_5 */
277
    NSFB_KEY_UNKNOWN, /* XK_KP_6 */
278
    NSFB_KEY_UNKNOWN, /* XK_KP_7 */
279
    NSFB_KEY_UNKNOWN, /* XK_KP_8 */
280
    NSFB_KEY_UNKNOWN, /* XK_KP_9 */
281
    NSFB_KEY_UNKNOWN, /* */
282
    NSFB_KEY_F1, /* XK_F1 */
283
    NSFB_KEY_UNKNOWN, /* */
284
    NSFB_KEY_UNKNOWN, /* XK_KP_Equal */
285
    NSFB_KEY_UNKNOWN, /* */
286
    NSFB_KEY_F2, /* XK_F2 */
287
    /* 0xc0 */
288
    NSFB_KEY_F3, /* XK_F3*/
289
    NSFB_KEY_F4, /* XK_F4*/
290
    NSFB_KEY_F5, /* XK_F5*/
291
    NSFB_KEY_F6, /* XK_F6*/
292
    NSFB_KEY_F7, /* XK_F7*/
293
    NSFB_KEY_F8, /* XK_F8*/
294
    NSFB_KEY_F9, /* XK_F9*/
295
    NSFB_KEY_F10, /* XK_F10*/
296
    NSFB_KEY_F11, /* XK_F11*/
297
    NSFB_KEY_F12, /* XK_F12*/
298
    NSFB_KEY_F13, /* XK_F13 */
299
    NSFB_KEY_F14, /* XK_F14 */
300
    NSFB_KEY_F15, /* XK_F15 */
301
    NSFB_KEY_UNKNOWN, /* XK_F16 */
302
    NSFB_KEY_UNKNOWN, /* XK_F17 */
303
    NSFB_KEY_UNKNOWN, /* XK_F18*/
304
    /* 0xd0 */
305
    NSFB_KEY_UNKNOWN, /* */
306
    NSFB_KEY_UNKNOWN, /* */
307
    NSFB_KEY_UNKNOWN, /* */
308
    NSFB_KEY_UNKNOWN, /* */
309
    NSFB_KEY_UNKNOWN, /* */
310
    NSFB_KEY_UNKNOWN, /* */
311
    NSFB_KEY_UNKNOWN, /* */
312
    NSFB_KEY_UNKNOWN, /* */
313
    NSFB_KEY_UNKNOWN, /* */
314
    NSFB_KEY_UNKNOWN, /* */
315
    NSFB_KEY_UNKNOWN, /* */
316
    NSFB_KEY_UNKNOWN, /* */
317
    NSFB_KEY_UNKNOWN, /* */
318
    NSFB_KEY_UNKNOWN, /* */
319
    NSFB_KEY_UNKNOWN, /* */
320
    NSFB_KEY_UNKNOWN, /* */
321
    /* 0xe0 */
322
    NSFB_KEY_UNKNOWN, /* */
323
    NSFB_KEY_LSHIFT, /* XK_Shift_L*/
324
    NSFB_KEY_RSHIFT, /* XK_Shift_R*/
325
    NSFB_KEY_UNKNOWN, /* XK_Control_L*/
326
    NSFB_KEY_UNKNOWN, /* XK_Control_R*/
327
    NSFB_KEY_UNKNOWN, /* XK_Caps_Lock*/
328
    NSFB_KEY_UNKNOWN, /* XK_Shift_Lock*/
329
    NSFB_KEY_UNKNOWN, /* XK_Meta_L*/
330
    NSFB_KEY_UNKNOWN, /* XK_Meta_R*/
331
    NSFB_KEY_UNKNOWN, /* XK_Alt_L */
332
    NSFB_KEY_UNKNOWN, /* XK_Alt_R*/
333
    NSFB_KEY_UNKNOWN, /* XK_Super_L*/
334
    NSFB_KEY_UNKNOWN, /* XK_Super_R*/
335
    NSFB_KEY_UNKNOWN, /* XK_Hyper_L*/
336
    NSFB_KEY_UNKNOWN, /* XK_Hyper_R*/
337
    NSFB_KEY_UNKNOWN, /* */
338
    /* 0xf0 */
339
    NSFB_KEY_UNKNOWN, /* */
340
    NSFB_KEY_UNKNOWN, /* */
341
    NSFB_KEY_UNKNOWN, /* */
342
    NSFB_KEY_UNKNOWN, /* */
343
    NSFB_KEY_UNKNOWN, /* */
344
    NSFB_KEY_UNKNOWN, /* */
345
    NSFB_KEY_UNKNOWN, /* */
346
    NSFB_KEY_UNKNOWN, /* */
347
    NSFB_KEY_UNKNOWN, /* */
348
    NSFB_KEY_UNKNOWN, /* */
349
    NSFB_KEY_UNKNOWN, /* */
350
    NSFB_KEY_UNKNOWN, /* */
351
    NSFB_KEY_UNKNOWN, /* */
352
    NSFB_KEY_UNKNOWN, /* */
353
    NSFB_KEY_UNKNOWN, /* */
354
    NSFB_KEY_UNKNOWN, /* */
355
};
356
 
357
/* Convert an X keysym into a nsfb key code.
358
 *
359
 * Our approach is primarily to assume both codings are roughly ascii like.
360
 *
361
 * The Keysyms are defined in X11/keysymdef.h and our mapping for the
362
 * "keyboard" keys i.e. those from code set 255 is from there
363
 */
364
static enum nsfb_key_code_e
365
xkeysym_to_nsfbkeycode(xcb_keysym_t ks)
366
{
367
    enum nsfb_key_code_e nsfb_key = NSFB_KEY_UNKNOWN;
368
    uint8_t codeset = (ks & 0xFF00) >> 8;
369
    uint8_t chrcode = ks & 0xFF;
370
 
371
    if (ks != XCB_NO_SYMBOL) {
372
 
373
        switch (codeset) {
374
        case 0x00: /* Latin 1 */
375
        case 0x01: /* Latin 2 */
376
        case 0x02: /* Latin 3 */
377
        case 0x03: /* Latin 4 */
378
        case 0x04: /* Katakana */
379
        case 0x05: /* Arabic */
380
        case 0x06: /* Cyrillic */
381
        case 0x07: /* Greek */
382
        case 0x08: /* Technical */
383
        case 0x0A: /* Publishing */
384
        case 0x0C: /* Hebrew */
385
        case 0x0D: /* Thai */
386
            /* this is somewhat incomplete, but the nsfb codes are lined up on
387
             * the ascii codes and x seems to have done similar
388
             */
389
            nsfb_key = (enum nsfb_key_code_e)chrcode;
390
            break;
391
 
392
        case 0xFF: /* Keyboard */
393
            nsfb_key = XCSKeyboardMap[chrcode];
394
            break;
395
        }
396
    }
397
 
398
    return nsfb_key;
399
}
400
/*
401
  static void
402
  set_palette(nsfb_t *nsfb)
403
  {
404
  X_Surface *x_screen = nsfb->surface_priv;
405
  X_Color palette[256];
406
  int rloop, gloop, bloop;
407
  int loop = 0;
408
 
409
  // build a linear R:3 G:3 B:2 colour cube palette.
410
  for (rloop = 0; rloop < 8; rloop++) {
411
  for (gloop = 0; gloop < 8; gloop++) {
412
  for (bloop = 0; bloop < 4; bloop++) {
413
  palette[loop].r = (rloop << 5) | (rloop << 2) | (rloop >> 1);
414
  palette[loop].g = (gloop << 5) | (gloop << 2) | (gloop >> 1);
415
  palette[loop].b = (bloop << 6) | (bloop << 4) | (bloop << 2) | (bloop);
416
  nsfb->palette[loop] = palette[loop].r |
417
  palette[loop].g << 8 |
418
  palette[loop].b << 16;
419
  loop++;
420
  }
421
  }
422
  }
423
 
424
  // Set palette
425
  //X_SetColors(x_screen, palette, 0, 256);
426
 
427
  }
428
*/
429
static int
430
update_pixmap(xstate_t *xstate, int x, int y, int width, int height)
431
{
432
    if (xstate->shminfo.shmseg == 0) {
433
        /* not using shared memory */
434
        xcb_put_image(xstate->connection,
435
                      xstate->image->format,
436
                      xstate->pmap,
437
                      xstate->gc,
438
                      xstate->image->width,
439
                      height,
440
                      0,
441
                      y,
442
                      0,
443
                      xstate->image->depth,
444
                      (height) * xstate->image->stride,
445
                      xstate->image->data + (y * xstate->image->stride));
446
    } else {
447
        /* shared memory */
448
        xcb_image_shm_put(xstate->connection,
449
                          xstate->pmap,
450
                          xstate->gc,
451
                          xstate->image,
452
                          xstate->shminfo,
453
                          x,y,
454
                          x,y,
455
                          width,height,0);
456
    }
457
 
458
    return 0;
459
}
460
 
461
static int
462
update_and_redraw_pixmap(xstate_t *xstate, int x, int y, int width, int height)
463
{
464
    update_pixmap(xstate, x, y, width, height);
465
 
466
    xcb_copy_area(xstate->connection,
467
                  xstate->pmap,
468
                  xstate->window,
469
                  xstate->gc,
470
                  x, y,
471
                  x, y,
472
                  width, height);
473
 
474
    xcb_flush(xstate->connection);
475
 
476
    return 0;
477
}
478
 
479
 
480
static bool
481
xcopy(nsfb_t *nsfb, nsfb_bbox_t *srcbox, nsfb_bbox_t *dstbox)
482
{
483
    xstate_t *xstate = nsfb->surface_priv;
484
    nsfb_bbox_t allbox;
485
    struct nsfb_cursor_s *cursor = nsfb->cursor;
486
    uint8_t *srcptr;
487
    uint8_t *dstptr;
488
    int srcx = srcbox->x0;
489
    int srcy = srcbox->y0;
490
    int dstx = dstbox->x0;
491
    int dsty = dstbox->y0;
492
    int width = dstbox->x1 - dstbox->x0;
493
    int height = dstbox->y1 - dstbox->y0;
494
    int hloop;
495
 
496
    nsfb_plot_add_rect(srcbox, dstbox, &allbox);
497
 
498
    /* clear the cursor if its within the region to be altered */
499
    if ((cursor != NULL) &&
500
        (cursor->plotted == true) &&
501
        (nsfb_plot_bbox_intersect(&allbox, &cursor->loc))) {
502
 
503
        nsfb_cursor_clear(nsfb, cursor);
504
        update_pixmap(xstate,
505
                      cursor->savloc.x0,
506
                      cursor->savloc.y0,
507
                      cursor->savloc.x1 - cursor->savloc.x0,
508
                      cursor->savloc.y1 - cursor->savloc.y0);
509
 
510
        /* must sync here or local framebuffer and remote pixmap will not be
511
         * consistant
512
         */
513
        xcb_aux_sync(xstate->connection);
514
 
515
    }
516
 
517
    /* copy the area on the server */
518
    xcb_copy_area(xstate->connection,
519
                  xstate->pmap,
520
                  xstate->pmap,
521
                  xstate->gc,
522
                  srcbox->x0,
523
                  srcbox->y0,
524
                  dstbox->x0,
525
                  dstbox->y0,
526
                  srcbox->x1 - srcbox->x0,
527
                  srcbox->y1 - srcbox->y0);
528
 
529
    /* do the copy in the local memory too */
530
    srcptr = (nsfb->ptr +
531
              (srcy * nsfb->linelen) +
532
              ((srcx * nsfb->bpp) / 8));
533
 
534
    dstptr = (nsfb->ptr +
535
              (dsty * nsfb->linelen) +
536
              ((dstx * nsfb->bpp) / 8));
537
 
538
    if (width == nsfb->width) {
539
        /* take shortcut and use memmove */
540
        memmove(dstptr, srcptr, (width * height * nsfb->bpp) / 8);
541
    } else {
542
        if (srcy > dsty) {
543
            for (hloop = height; hloop > 0; hloop--) {
544
                memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
545
                srcptr += nsfb->linelen;
546
                dstptr += nsfb->linelen;
547
            }
548
        } else {
549
            srcptr += height * nsfb->linelen;
550
            dstptr += height * nsfb->linelen;
551
            for (hloop = height; hloop > 0; hloop--) {
552
                srcptr -= nsfb->linelen;
553
                dstptr -= nsfb->linelen;
554
                memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
555
            }
556
        }
557
    }
558
 
559
    if ((cursor != NULL) &&
560
        (cursor->plotted == false)) {
561
        nsfb_cursor_plot(nsfb, cursor);
562
    }
563
 
564
    /* update the x window */
565
    xcb_copy_area(xstate->connection,
566
                  xstate->pmap,
567
                  xstate->window,
568
                  xstate->gc,
569
                  dstx, dsty,
570
                  dstx, dsty,
571
                  width, height);
572
 
573
    return true;
574
 
575
}
576
 
577
 
578
static int
579
x_set_geometry(nsfb_t *nsfb, int width, int height, enum nsfb_format_e format)
580
{
581
    if (nsfb->surface_priv != NULL)
582
        return -1; /* if were already initialised fail */
583
 
584
    nsfb->width = width;
585
    nsfb->height = height;
586
    nsfb->format = format;
587
 
588
    /* select default sw plotters for format */
589
    select_plotters(nsfb);
590
 
591
    nsfb->plotter_fns->copy = xcopy;
592
 
593
    return 0;
594
}
595
 
596
 
597
static xcb_format_t *
598
find_format(xcb_connection_t * c, uint8_t depth, uint8_t bpp)
599
{
600
    const xcb_setup_t *setup = xcb_get_setup(c);
601
    xcb_format_t *fmt = xcb_setup_pixmap_formats(setup);
602
    xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(setup);
603
 
604
    for(; fmt != fmtend; ++fmt) {
605
        if((fmt->depth == depth) && (fmt->bits_per_pixel == bpp)) {
606
            return fmt;
607
        }
608
    }
609
    return 0;
610
}
611
 
612
static xcb_image_t *
613
create_shm_image(xstate_t *xstate, int width, int height, int bpp)
614
{
615
    const xcb_setup_t *setup = xcb_get_setup(xstate->connection);
616
    unsigned char *image_data;
617
    xcb_format_t *fmt;
618
    int depth = bpp;
619
    uint32_t image_size;
620
    int shmid;
621
 
622
    xcb_shm_query_version_reply_t *rep;
623
    xcb_shm_query_version_cookie_t ck;
624
    xcb_void_cookie_t shm_attach_cookie;
625
    xcb_generic_error_t *generic_error;
626
 
627
    ck = xcb_shm_query_version(xstate->connection);
628
    rep = xcb_shm_query_version_reply(xstate->connection, ck , NULL);
629
    if (!rep) {
630
        fprintf (stderr, "Server has no shm support.\n");
631
        return NULL;
632
    }
633
 
634
    if ((rep->major_version < 1) ||
635
        (rep->major_version == 1 && rep->minor_version == 0)) {
636
        fprintf(stderr, "server SHM support is insufficient.\n");
637
        free(rep);
638
        return NULL;
639
    }
640
    free(rep);
641
 
642
    if (bpp == 32)
643
        depth = 24;
644
 
645
    fmt = find_format(xstate->connection, depth, bpp);
646
    if (fmt == NULL)
647
        return NULL;
648
 
649
    /* doing it this way ensures we deal with bpp smaller than 8 */
650
    image_size = (bpp * width * height) >> 3;
651
 
652
    /* get the shared memory segment */
653
    shmid = shmget(IPC_PRIVATE, image_size, IPC_CREAT|0777);
654
    if (shmid == -1)
655
        return NULL;
656
 
657
    xstate->shminfo.shmid = shmid;
658
 
659
    xstate->shminfo.shmaddr = shmat(xstate->shminfo.shmid, 0, 0);
660
    image_data = xstate->shminfo.shmaddr;
661
 
662
    xstate->shminfo.shmseg = xcb_generate_id(xstate->connection);
663
    shm_attach_cookie = xcb_shm_attach_checked(xstate->connection,
664
					       xstate->shminfo.shmseg,
665
					       xstate->shminfo.shmid,
666
					       0);
667
    generic_error = xcb_request_check(xstate->connection, shm_attach_cookie);
668
 
669
    /* either there is an error and the shm us no longer needed, or it now
670
     * belongs to the x server - regardless release local reference to shared
671
     * memory segment
672
     */
673
    shmctl(xstate->shminfo.shmid, IPC_RMID, 0);
674
 
675
    if (generic_error != NULL) {
676
        /* unable to attach shm */
677
        xstate->shminfo.shmseg = 0;
678
 
679
        free(generic_error);
680
        return NULL;
681
    }
682
 
683
 
684
    return xcb_image_create(width,
685
                            height,
686
                            XCB_IMAGE_FORMAT_Z_PIXMAP,
687
                            fmt->scanline_pad,
688
                            fmt->depth,
689
                            fmt->bits_per_pixel,
690
                            0,
691
                            setup->image_byte_order,
692
                            XCB_IMAGE_ORDER_LSB_FIRST,
693
                            image_data,
694
                            image_size,
695
                            image_data);
696
}
697
 
698
 
699
static xcb_image_t *
700
create_image(xcb_connection_t *c, int width, int height, int bpp)
701
{
702
    const xcb_setup_t *setup = xcb_get_setup(c);
703
    unsigned char *image_data;
704
    xcb_format_t *fmt;
705
    int depth = bpp;
706
    uint32_t image_size;
707
 
708
    if (bpp == 32)
709
        depth = 24;
710
 
711
    fmt = find_format(c, depth, bpp);
712
    if (fmt == NULL)
713
        return NULL;
714
 
715
    /* doing it this way ensures we deal with bpp smaller than 8 */
716
    image_size = (bpp * width * height) >> 3;
717
 
718
    image_data = calloc(1, image_size);
719
    if (image_data == NULL)
720
        return NULL;
721
 
722
    return xcb_image_create(width,
723
                            height,
724
                            XCB_IMAGE_FORMAT_Z_PIXMAP,
725
                            fmt->scanline_pad,
726
                            fmt->depth,
727
                            fmt->bits_per_pixel,
728
                            0,
729
                            setup->image_byte_order,
730
                            XCB_IMAGE_ORDER_LSB_FIRST,
731
                            image_data,
732
                            image_size,
733
                            image_data);
734
}
735
 
736
/**
737
 * Create a blank cursor.
738
 * The empty pixmaps is leaked.
739
 *
740
 * @param conn xcb connection
741
 * @param scr xcb XCB screen
742
 */
743
static xcb_cursor_t
744
create_blank_cursor(xcb_connection_t *conn, const xcb_screen_t *scr)
745
{
746
    xcb_cursor_t cur = xcb_generate_id(conn);
747
    xcb_pixmap_t pix = xcb_generate_id(conn);
748
    xcb_void_cookie_t ck;
749
    xcb_generic_error_t *err;
750
 
751
    ck = xcb_create_pixmap_checked (conn, 1, pix, scr->root, 1, 1);
752
    err = xcb_request_check (conn, ck);
753
    if (err) {
754
        fprintf (stderr, "Cannot create pixmap: %d", err->error_code);
755
        free (err);
756
    }
757
    ck = xcb_create_cursor_checked (conn, cur, pix, pix, 0, 0, 0, 0, 0, 0, 0, 0);
758
    err = xcb_request_check (conn, ck);
759
    if (err) {
760
        fprintf (stderr, "Cannot create cursor: %d", err->error_code);
761
        free (err);
762
    }
763
    return cur;
764
}
765
 
766
 
767
static int x_initialise(nsfb_t *nsfb)
768
{
769
    uint32_t mask;
770
    uint32_t values[3];
771
    xcb_size_hints_t *hints;
772
    xstate_t *xstate = nsfb->surface_priv;
773
    xcb_cursor_t blank_cursor;
774
 
775
    if (xstate != NULL)
776
        return -1; /* already initialised */
777
 
778
    /* sanity check bpp. */
779
    if ((nsfb->bpp != 32) && (nsfb->bpp != 16) && (nsfb->bpp != 8))
780
        return -1;
781
 
782
    xstate = calloc(1, sizeof(xstate_t));
783
    if (xstate == NULL)
784
        return -1; /* no memory */
785
 
786
    /* open connection with the server */
787
    xstate->connection = xcb_connect(NULL, NULL);
788
    if (xstate->connection == NULL) {
789
        fprintf(stderr, "Memory error opening display\n");
790
        free(xstate);
791
        return -1; /* no memory */
792
    }
793
 
794
    if (xcb_connection_has_error(xstate->connection) != 0) {
795
        fprintf(stderr, "Error opening display\n");
796
        free(xstate);
797
        return -1; /* no memory */
798
    }
799
 
800
    /* get screen */
801
    xstate->screen = xcb_setup_roots_iterator(xcb_get_setup(xstate->connection)).data;
802
 
803
    /* create image */
804
    xstate->image = create_shm_image(xstate, nsfb->width, nsfb->height, nsfb->bpp);
805
 
806
    if (xstate->image == NULL)
807
        xstate->image = create_image(xstate->connection, nsfb->width, nsfb->height, nsfb->bpp);
808
 
809
    if (xstate->image == NULL) {
810
        fprintf(stderr, "Unable to create image\n");
811
        free(xstate);
812
        xcb_disconnect(xstate->connection);
813
        return -1;
814
    }
815
 
816
    /* ensure plotting information is stored */
817
    nsfb->surface_priv = xstate;
818
    nsfb->ptr = xstate->image->data;
819
    nsfb->linelen = xstate->image->stride;
820
 
821
    /* get blank cursor */
822
    blank_cursor = create_blank_cursor(xstate->connection, xstate->screen);
823
 
824
    /* get keysymbol maps */
825
    xstate->keysymbols = xcb_key_symbols_alloc(xstate->connection);
826
 
827
    /* create window */
828
    mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
829
    values[0] = xstate->screen->white_pixel;
830
    values[1] = XCB_EVENT_MASK_EXPOSURE |
831
		XCB_EVENT_MASK_KEY_PRESS |
832
		XCB_EVENT_MASK_KEY_RELEASE |
833
		XCB_EVENT_MASK_BUTTON_PRESS |
834
                XCB_EVENT_MASK_BUTTON_RELEASE |
835
                XCB_EVENT_MASK_POINTER_MOTION;
836
    values[2] = blank_cursor;
837
 
838
    xstate->window = xcb_generate_id(xstate->connection);
839
    xcb_create_window (xstate->connection,
840
                       XCB_COPY_FROM_PARENT,
841
                       xstate->window,
842
                       xstate->screen->root,
843
                       0, 0, xstate->image->width, xstate->image->height, 1,
844
                       XCB_WINDOW_CLASS_INPUT_OUTPUT,
845
                       xstate->screen->root_visual,
846
                       mask, values);
847
    /* set size hits on window */
848
    hints = xcb_alloc_size_hints();
849
    xcb_size_hints_set_max_size(hints, xstate->image->width, xstate->image->height);
850
    xcb_size_hints_set_min_size(hints, xstate->image->width, xstate->image->height);
851
    xcb_set_wm_size_hints(xstate->connection, xstate->window, WM_NORMAL_HINTS, hints);
852
    xcb_free_size_hints(hints);
853
 
854
    /* create backing pixmap */
855
    xstate->pmap = xcb_generate_id(xstate->connection);
856
    xcb_create_pixmap(xstate->connection, 24, xstate->pmap, xstate->window, xstate->image->width, xstate->image->height);
857
 
858
    /* create pixmap plot gc */
859
    mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
860
    values[0] = xstate->screen->black_pixel;
861
    values[1] = 0xffffff;
862
 
863
    xstate->gc = xcb_generate_id (xstate->connection);
864
    xcb_create_gc(xstate->connection, xstate->gc, xstate->pmap, mask, values);
865
 
866
    /*    if (nsfb->bpp == 8)
867
          set_palette(nsfb);
868
    */
869
 
870
    /* put the image into the pixmap */
871
    update_and_redraw_pixmap(xstate, 0, 0, xstate->image->width, xstate->image->height);
872
 
873
 
874
    /* show the window */
875
    xcb_map_window (xstate->connection, xstate->window);
876
    xcb_flush(xstate->connection);
877
 
878
    return 0;
879
}
880
 
881
static int x_finalise(nsfb_t *nsfb)
882
{
883
    xstate_t *xstate = nsfb->surface_priv;
884
    if (xstate == NULL)
885
        return 0;
886
 
887
    xcb_key_symbols_free(xstate->keysymbols);
888
 
889
    /* free pixmap */
890
    xcb_free_pixmap(xstate->connection, xstate->pmap);
891
 
892
    /* close connection to server */
893
    xcb_disconnect(xstate->connection);
894
 
895
    return 0;
896
}
897
 
898
static bool x_input(nsfb_t *nsfb, nsfb_event_t *event, int timeout)
899
{
900
    xcb_generic_event_t *e;
901
    xcb_expose_event_t *ee;
902
    xcb_motion_notify_event_t *emn;
903
    xcb_button_press_event_t *ebp;
904
    xcb_key_press_event_t *ekp;
905
    xcb_key_press_event_t *ekr;
906
    xstate_t *xstate = nsfb->surface_priv;
907
 
908
    if (xstate == NULL)
909
        return false;
910
 
911
    xcb_flush(xstate->connection);
912
 
913
    /* try and retrive an event immediately */
914
    e = xcb_poll_for_event(xstate->connection);
915
 
916
    if ((e == NULL) && (timeout != 0)) {
917
        if (timeout > 0) {
918
            int confd;
919
            fd_set rfds;
920
            struct timeval tv;
921
            int retval;
922
 
923
            confd = xcb_get_file_descriptor(xstate->connection);
924
            FD_ZERO(&rfds);
925
            FD_SET(confd, &rfds);
926
 
927
            tv.tv_sec = timeout / 1000;
928
            tv.tv_usec = timeout % 1000;
929
 
930
            retval = select(confd + 1, &rfds, NULL, NULL, &tv);
931
            if (retval == 0) {
932
		    /* timeout, nothing happened */
933
		    event->type = NSFB_EVENT_CONTROL;
934
		    event->value.controlcode = NSFB_CONTROL_TIMEOUT;
935
		    return true;
936
            }
937
        }
938
        e = xcb_wait_for_event(xstate->connection);
939
    }
940
 
941
    if (e == NULL) {
942
        if (xcb_connection_has_error(xstate->connection) != 0) {
943
            /* connection closed quiting time */
944
            event->type = NSFB_EVENT_CONTROL;
945
            event->value.controlcode = NSFB_CONTROL_QUIT;
946
            return true;
947
        } else {
948
            return false; /* no event */
949
        }
950
    }
951
 
952
    event->type = NSFB_EVENT_NONE;
953
 
954
    switch (e->response_type) {
955
    case XCB_EXPOSE:
956
        ee = (xcb_expose_event_t *)e;
957
        xcb_copy_area(xstate->connection,
958
                      xstate->pmap,
959
                      xstate->window,
960
                      xstate->gc,
961
                      ee->x, ee->y,
962
                      ee->x, ee->y,
963
                      ee->width, ee->height);
964
        xcb_flush (xstate->connection);
965
        break;
966
 
967
    case XCB_MOTION_NOTIFY:
968
        emn = (xcb_motion_notify_event_t *)e;
969
        event->type = NSFB_EVENT_MOVE_ABSOLUTE;
970
        event->value.vector.x = emn->event_x;
971
        event->value.vector.y = emn->event_y;
972
        event->value.vector.z = 0;
973
        break;
974
 
975
 
976
    case XCB_BUTTON_PRESS:
977
        ebp = (xcb_button_press_event_t *)e;
978
        event->type = NSFB_EVENT_KEY_DOWN;
979
 
980
        switch (ebp->detail) {
981
 
982
        case X_BUTTON_LEFT:
983
            event->value.keycode = NSFB_KEY_MOUSE_1;
984
            break;
985
 
986
        case X_BUTTON_MIDDLE:
987
            event->value.keycode = NSFB_KEY_MOUSE_2;
988
            break;
989
 
990
        case X_BUTTON_RIGHT:
991
            event->value.keycode = NSFB_KEY_MOUSE_3;
992
            break;
993
 
994
        case X_BUTTON_WHEELUP:
995
            event->value.keycode = NSFB_KEY_MOUSE_4;
996
            break;
997
 
998
        case X_BUTTON_WHEELDOWN:
999
            event->value.keycode = NSFB_KEY_MOUSE_5;
1000
            break;
1001
        }
1002
        break;
1003
 
1004
    case XCB_BUTTON_RELEASE:
1005
        ebp = (xcb_button_press_event_t *)e;
1006
        event->type = NSFB_EVENT_KEY_UP;
1007
 
1008
        switch (ebp->detail) {
1009
 
1010
        case X_BUTTON_LEFT:
1011
            event->value.keycode = NSFB_KEY_MOUSE_1;
1012
            break;
1013
 
1014
        case X_BUTTON_MIDDLE:
1015
            event->value.keycode = NSFB_KEY_MOUSE_2;
1016
            break;
1017
 
1018
        case X_BUTTON_RIGHT:
1019
            event->value.keycode = NSFB_KEY_MOUSE_3;
1020
            break;
1021
 
1022
        case X_BUTTON_WHEELUP:
1023
            event->value.keycode = NSFB_KEY_MOUSE_4;
1024
            break;
1025
 
1026
        case X_BUTTON_WHEELDOWN:
1027
            event->value.keycode = NSFB_KEY_MOUSE_5;
1028
            break;
1029
        }
1030
        break;
1031
 
1032
 
1033
    case XCB_KEY_PRESS:
1034
        ekp = (xcb_key_press_event_t *)e;
1035
        event->type = NSFB_EVENT_KEY_DOWN;
1036
        event->value.keycode = xkeysym_to_nsfbkeycode(xcb_key_symbols_get_keysym(xstate->keysymbols, ekp->detail, 0));
1037
        break;
1038
 
1039
    case XCB_KEY_RELEASE:
1040
        ekr = (xcb_key_release_event_t *)e;
1041
        event->type = NSFB_EVENT_KEY_UP;
1042
        event->value.keycode = xkeysym_to_nsfbkeycode(xcb_key_symbols_get_keysym(xstate->keysymbols, ekr->detail, 0));
1043
        break;
1044
 
1045
    }
1046
 
1047
    free(e);
1048
 
1049
    return true;
1050
}
1051
 
1052
static int x_claim(nsfb_t *nsfb, nsfb_bbox_t *box)
1053
{
1054
    struct nsfb_cursor_s *cursor = nsfb->cursor;
1055
 
1056
    if ((cursor != NULL) &&
1057
        (cursor->plotted == true) &&
1058
        (nsfb_plot_bbox_intersect(box, &cursor->loc))) {
1059
        nsfb_cursor_clear(nsfb, cursor);
1060
    }
1061
    return 0;
1062
}
1063
 
1064
 
1065
 
1066
static int
1067
x_cursor(nsfb_t *nsfb, struct nsfb_cursor_s *cursor)
1068
{
1069
    xstate_t *xstate = nsfb->surface_priv;
1070
    nsfb_bbox_t redraw;
1071
    nsfb_bbox_t fbarea;
1072
 
1073
    if ((cursor != NULL) && (cursor->plotted == true)) {
1074
 
1075
        nsfb_plot_add_rect(&cursor->savloc, &cursor->loc, &redraw);
1076
 
1077
        /* screen area */
1078
        fbarea.x0 = 0;
1079
        fbarea.y0 = 0;
1080
        fbarea.x1 = nsfb->width;
1081
        fbarea.y1 = nsfb->height;
1082
 
1083
        nsfb_plot_clip(&fbarea, &redraw);
1084
 
1085
        nsfb_cursor_clear(nsfb, cursor);
1086
 
1087
        nsfb_cursor_plot(nsfb, cursor);
1088
 
1089
        /* TODO: This is hediously ineficient - should keep the pointer image
1090
         * as a pixmap and plot server side
1091
         */
1092
        update_and_redraw_pixmap(xstate, redraw.x0, redraw.y0, redraw.x1 - redraw.x0, redraw.y1 - redraw.y0);
1093
 
1094
    }
1095
    return true;
1096
}
1097
 
1098
 
1099
static int x_update(nsfb_t *nsfb, nsfb_bbox_t *box)
1100
{
1101
    xstate_t *xstate = nsfb->surface_priv;
1102
    struct nsfb_cursor_s *cursor = nsfb->cursor;
1103
 
1104
    if ((cursor != NULL) &&
1105
	(cursor->plotted == false)) {
1106
        nsfb_cursor_plot(nsfb, cursor);
1107
    }
1108
 
1109
    update_and_redraw_pixmap(xstate, box->x0, box->y0, box->x1 - box->x0, box->y1 - box->y0);
1110
 
1111
    return 0;
1112
}
1113
 
1114
const nsfb_surface_rtns_t x_rtns = {
1115
    .initialise = x_initialise,
1116
    .finalise = x_finalise,
1117
    .input = x_input,
1118
    .claim = x_claim,
1119
    .update = x_update,
1120
    .cursor = x_cursor,
1121
    .geometry = x_set_geometry,
1122
};
1123
 
1124
NSFB_SURFACE_DEF(x, NSFB_SURFACE_X, &x_rtns)
1125
 
1126
/*
1127
 * Local variables:
1128
 *  c-basic-offset: 4
1129
 *  tab-width: 8
1130
 * End:
1131
 */