Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Copyright 2009 Vincent Sanders <vince@simtec.co.uk>
  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 <stdbool.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15.  
  16. #include <sys/ipc.h>
  17. #include <sys/shm.h>
  18.  
  19. #include <xcb/xcb.h>
  20. #include <xcb/xcb_image.h>
  21. #include <xcb/xcb_atom.h>
  22. #include <xcb/xcb_icccm.h>
  23. #include <xcb/xcb_aux.h>
  24. #include <xcb/xcb_keysyms.h>
  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.  */
  1132.