Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15309415
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: 嵌入式

2009-07-08 13:13:40

浅析minigui-1.6.10粘贴板-clipboard

  粘贴板是一个在各个独立的进程之间共享数据的IPC通信机制,
对于编译为非lite版本,即threads版本的minigui来说,粘贴板的IPC意义就没有那么明显了,
因为threads是一个只有一个进程,包含多个threads线程,即便不使用粘贴板,
数据仍然可以通过全局量的方式来共享(其实trheads中cbs[]粘贴板管理区数组就是一个全局量了).

InitGUI==>InitMisc==>InitClipBoard()
void InitClipBoard (void)
{
#ifndef _LITE_VERSION // 我们在pc上直接编译的为非lite版本,即没有mginit服务进程的版本[luther.gliethttp].
    sem_init (&cb_lock, 0, 1); // 锁信号初始化
#endif

#if defined(_LITE_VERSION) && !defined(_STAND_ALONE)
    if (mgIsServer)
#endif
        // minigui.h
        // #define CBNAME_TEXT             ("text")
        create_clip_board (CBNAME_TEXT, 1024); // 创建一个名字为,大小为1024字节粘贴板

}

// 定义管理粘贴板的专用数组,该数组中包含每个粘贴板的所有信息:大小,名字,它自己的缓冲区等[luther.gliethttp]
// minigui.h
// #define NR_CLIPBOARDS           4
static CLIPBOARD cbs [NR_CLIPBOARDS];

static int create_clip_board (const char* cb_name, size_t size)
{
    int i;
    int empty = -1;

    if (size <= 0)
        return -1;

    for (i = 0; i < NR_CLIPBOARDS; i++) {
        if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
            // 该名字粘贴板已经有了[luther.gliethttp]
            fprintf (stderr, "create clip board error: already existed name.\n");
            return CBERR_BADNAME;
        }
        if (empty < 0 && cbs [i].name [0] == '\0') {
            empty = i;
// 之所以这里不break出去,因为后面可能有与cb_name相同的粘贴板了,所以需要继续遍历剩下的所有NR_CLIPBOARDS个粘贴板管理区
        }
    }

    if (empty == NR_CLIPBOARDS)
        return CBERR_NOMEM;
// ok, 可以安全创建粘贴板
    if (empty >= 0) {
        if ((cbs [empty].buff = malloc (size)) == NULL) { // 申请size大小内存
            return CBERR_NOMEM;
        }
        strncpy (cbs [empty].name, cb_name, LEN_CLIPBOARD_NAME); // 拷贝粘贴板名称
        cbs[empty].name[LEN_CLIPBOARD_NAME] = 0; // 追加字符串结尾0
        cbs [empty].buff_len = size; // 粘贴板大小
        cbs [empty].data_len = 0; // 当前粘贴板包含数据大小[luther.gliethttp]
    }

    return CBERR_OK;
}

// 释放粘贴板
int GUIAPI DestroyClipBoard (const char* cb_name)
{
    int ret;

    sem_wait (&cb_lock);
    ret = destroy_clip_board (cb_name);
    sem_post (&cb_lock);

    return ret;
}

int GUIAPI destroy_clip_board (const char* cb_name)
{
    int i;

    for (i = 0; i < NR_CLIPBOARDS; i++) {
        if (strcmp (cb_name, cbs [i].name) == 0) {
            // 在cbs[]管理区数组中找到注册了的名为cb_name的粘贴板
            free (cbs [i].buff); // 释放注册时malloc到的数据存储内存
            cbs [i].name [0] = '\0'; // 管理区名字字符串清0
            cbs [i].buff = NULL; // 标识无内存指向[luther.gliethttp]
            cbs [i].buff_len = 0;
            cbs [i].data_len = 0;

            return CBERR_OK;
        }
    }

    return CBERR_BADNAME;
}

// 粘贴板创建和销毁都已经说了,来看看怎么使用粘贴板中的数据
1.发送数据到粘贴板
int GUIAPI SetClipBoardData (const char* cb_name, void* data, size_t n, int cbop)
{
    int ret;

    sem_wait (&cb_lock);
    ret = set_clip_board_data (cb_name, data, n, cbop);
    sem_post (&cb_lock);

    return ret;
}

static int set_clip_board_data (const char* cb_name, void* data, size_t n, int cbop)
{
    int i;
    CLIPBOARD* cb = NULL;
    int dataLen;

    for (i = 0; i < NR_CLIPBOARDS; i++) {
        if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
            cb = cbs + i;
            // ok, 向cb_name粘贴板发送数据初步检验通过,cb_name粘贴板已注册.
            break;
        }
    }

    if (cb == NULL)
        return CBERR_BADNAME;

    if (cbop == CBOP_APPEND) { // 将数据追加到粘贴板以后数据之后
        dataLen = MIN (n, cb->buff_len - cb->data_len);
        memcpy (cb->buff + cb->data_len, data, dataLen);
        cb->data_len += dataLen;
    }
    else {
        // 覆盖粘贴板原有数据,本次操作数据独占该粘贴板[luther.gliethttp]
        cb->data_len = MIN (n, cb->buff_len);
        if (data && cb->data_len > 0)
            memcpy (cb->buff, data, cb->data_len);
    }

    return CBERR_OK;
}
举例说明:
比如libminigui-1.6.10/src/control/edit.c

RegisterSLEditControl==>WndClass.WinProc = SLEditCtrlProc==>SLEditCtrlProc==>sleKeyDown()
#ifdef _CLIPBOARD_SUPPORT
    case SCANCODE_C:
    case SCANCODE_X:
    {
        if ((lParam & KS_CTRL) && (sled->selEnd - sled->selStart > 0)) {
            // 将edit中选中数据送到粘贴板[luther.gliethttp]
            SetClipBoardData (CBNAME_TEXT, sled->content.string + sled->selStart,
                        sled->selEnd - sled->selStart, CBOP_NORMAL);
            if (wParam == SCANCODE_X && !(GetWindowStyle(hWnd) & ES_READONLY)) {
                sleInsertText (hWnd, sled, NULL, 0);
            }
        }
        return 0;
    }
2.获取粘贴板所有数据
首先获取粘贴板包含数据字节数
size_t GUIAPI GetClipBoardDataLen (const char* cb_name)
{
    int ret;

    sem_wait (&cb_lock);
    ret = get_clip_board_data_len (cb_name);
    sem_post (&cb_lock);

    return ret;
}

static size_t get_clip_board_data_len (const char* cb_name)
{
    int i;
    CLIPBOARD* cb = NULL;

    for (i = 0; i < NR_CLIPBOARDS; i++) {
        if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
            cb = cbs + i;
            break;
        }
    }

    if (cb)
        return cb->data_len;
    return 0;
}
获取粘贴板数据
size_t GUIAPI GetClipBoardData (const char* cb_name, void* data, size_t n)
{
    int ret;

    sem_wait (&cb_lock);
    ret = get_clip_board_data (cb_name, data, n);
    sem_post (&cb_lock);

    return ret;
}

static size_t get_clip_board_data (const char* cb_name, void* data, size_t n)
{
    int i;
    CLIPBOARD* cb = NULL;
    int copied_len = 0;

    if (!data || n <= 0)
        return -1;

    for (i = 0; i < NR_CLIPBOARDS; i++) {
        if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
            cb = cbs + i;
            break;
        }
    }

    if (cb) {
        copied_len = MIN (n, cb->data_len);
        if (copied_len > 0) {
            memcpy (data, cb->buff, copied_len); // 拷贝粘贴板数据
        }
    }

    return copied_len;
}

举例说明:
比如libminigui-1.6.10/src/control/edit.c
RegisterSLEditControl==>WndClass.WinProc = SLEditCtrlProc==>SLEditCtrlProc==>sleKeyDown()==>sleInsertCbText
static int sleInsertCbText (HWND hWnd, PSLEDITDATA sled)
{
    int  inserting;
    unsigned char *txtBuffer;

    if (GetWindowStyle(hWnd) & ES_READONLY) {
        return 0;
    }

    inserting = GetClipBoardDataLen (CBNAME_TEXT);// 获取"text"粘贴板包含数据字节数
    txtBuffer = ALLOCATE_LOCAL (inserting); // malloc和粘贴板中字节数一致的内存
    GetClipBoardData (CBNAME_TEXT, txtBuffer, inserting); // 将粘贴板中数据拷贝到上面malloc到的内存空间[luther.gliethttp]
    sleInsertText (hWnd, sled, (char *)txtBuffer, inserting); // 显示粘贴板中数据
    DEALLOCATE_LOCAL(txtBuffer); // 释放malloc到的内存空间

    return 0;
}
3.获取粘贴板中第x个数据
int GUIAPI GetClipBoardByte (const char* cb_name, int index, unsigned char* byte)
{
    int ret;

    sem_wait (&cb_lock);
    ret = get_clip_board_byte (cb_name, index, byte);
    sem_post (&cb_lock);

    return ret;
}

static int get_clip_board_byte (const char* cb_name, int index, unsigned char* byte)
{
    int i;
    CLIPBOARD* cb = NULL;

    for (i = 0; i < NR_CLIPBOARDS; i++) {
        if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
            cb = cbs + i;
            break;
        }
    }

    if (cb) {
        if (index < 0 || index >= cb->data_len) {
            return CBERR_NOMEM;
        }
        *byte = cb->buff [index]; // 读取第index偏移处的字节
    }
    else
        return CBERR_BADNAME;

    return CBERR_OK;
}

举例说明: 没有发现该用法的实例[luther.gliethttp]

阅读(1526) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~