#include "mywin_inc.h" // 定义基本窗口类型字符串 #define WIN_WINDOW_TYPE "WIN_WindowStruct" // 窗口环境变量 static WIN_Struct g_win_struct = {0}; int WIN_Init(void) { // 配置初始化 WIN_InitCfg(); // 屏幕初始化 WIN_GetWinStruct()->lcd->Init(); // 基础窗口初始化 WIN_GetWinStruct()->baseWin.x = 0; WIN_GetWinStruct()->baseWin.y = 0; WIN_GetWinStruct()->baseWin.x_size = WIN_GetWinStruct()->lcd->getLcdSizeX(); WIN_GetWinStruct()->baseWin.y_size = WIN_GetWinStruct()->lcd->getLcdSizeY(); WIN_GetWinStruct()->baseWin.baseWin = 0; WIN_GetWinStruct()->baseWin.chidWinMaxSize = WIN_CHIDWIN_MAXNUM; WIN_GetWinStruct()->baseWin.id = WIN_GetWinStruct()->winId++; WIN_GetWinStruct()->baseWin.winType = WIN_WINDOW_TYPE; // 基本窗口类型 u16 color = WIN_GetWinStruct()->lcd->getLcdBkColor(); WIN_GetWinStruct()->baseWin.color = COLOR565TO888(color); color = WIN_GetWinStruct()->lcd->getLcdBkColor(); WIN_GetWinStruct()->baseWin.bkcolor = COLOR565TO888(color); WIN_GetWinStruct()->baseWin.msgLoop = WIN_DefaultMsgLoop; // 主窗口的消息队列初始化 QUEUE_Init(&WIN_GetWinStruct()->baseWin.winMsgQueue, sizeof(WIN_MsgStruct), 50); WIN_MsgStruct msg = {0}; msg.msg = WIN_MSG_INIT; WIN_SendMsg(0, &WIN_GetWinStruct()->baseWin, &msg); // 键盘,触摸队列初始化 QUEUE_Init(&WIN_GetWinStruct()->touchQueue, sizeof(WIN_TouchStruct), 50); QUEUE_Init(&WIN_GetWinStruct()->keyQueue, sizeof(WIN_KeyStruct), 50); // 显示基础窗口 WIN_ShowWindow(&WIN_GetWinStruct()->baseWin); return 0; } // 返回窗口环境变量 WIN_Struct *WIN_GetWinStruct(void) { return &g_win_struct; } // 设置窗口运行回调函数 void *WIN_SetRunCallBack(void (*callback)(void)) { void *ret = g_win_struct.runCallBack; if (callback) g_win_struct.runCallBack = callback; return ret; } // 获取外部数据指针,这个函数在窗口应用中调用, // 获取之后要释放g_win_struct.ExtData 指向的内存 void *WIN_GetExtData(u32 *datasize) { WIN_IRQ_DISABLE(); void *ret = g_win_struct.ExtData; *datasize = g_win_struct.ExtDataSize; g_win_struct.ExtData = 0; g_win_struct.ExtDataSize = 0; WIN_IRQ_ENABLE(); return ret; } // 放置外部数据到窗口,这个函数在其他线程或中断中调用 int WIN_PlaceExtData(void *data, u32 size) { int ret = -1; void *buff = mymalloc(size); mymemcpy(buff, data, size); WIN_IRQ_DISABLE(); if (g_win_struct.ExtData == 0) { g_win_struct.ExtData = buff; g_win_struct.ExtDataSize = size; ret = 0; } else { ret = -1; myfree(buff); } WIN_IRQ_ENABLE(); return ret; } // 设置在指定窗口运行的函数,返回0,成功 // 这个函数用于在窗口线程之外通知窗口调用函数 int WIN_RunInWindow(const char *title, void (*fun)(void *ptr), void *ptr) { int ret = -1; WIN_IRQ_DISABLE(); WIN_WindowStruct *win = WIN_GetWinByTitle(0, (char *)title); if (win) { WIN_MsgStruct msg = {0}; msg.msg = WIN_MSG_RUN; msg.data.p = fun; msg.data2.p = ptr; ret = WIN_SendMsg(0, win, &msg); } WIN_IRQ_ENABLE(); return ret; } // 运行消息中的函数 ,返回0,成功 // 这个函数在窗口消息循环中接收到运行消息后调用 int WIN_RunMsgFunction(WIN_MsgStruct *msg) { int ret = -1; if (msg->msg == WIN_MSG_RUN) { if (msg->data.p) { ((void (*)(void *t))msg->data.p)(msg->data2.p); ret = 0; } } return ret; } // 在堆中创建一个窗口,返回窗口的指针 WIN_WindowStruct *WIN_CreatWindow(WIN_WindowStruct *base, void (*msgLoop)(struct _WIN_WindowStruct *win, WIN_MsgStruct *msg), int x, int y, int x_size, int y_size) { if (base == 0) base = WIN_GetBaseWindow(); // 没有父窗口,默认父窗口 WIN_WindowStruct *ret = mymalloc(sizeof(WIN_WindowStruct)); mymemset(ret, 0, sizeof(WIN_WindowStruct)); u16 color = WIN_GetWinStruct()->lcd->getLcdBkColor(); ret->bkcolor = COLOR565TO888(color); color = WIN_GetWinStruct()->lcd->getLcdColor(); ret->color = COLOR565TO888(color); ret->chidWinMaxSize = WIN_CHIDWIN_MAXNUM; ret->x = x; ret->y = y; ret->x_size = x_size; ret->y_size = y_size; ret->id = WIN_GetWinStruct()->winId++; // 设置窗口唯一ID ret->winType = WIN_WINDOW_TYPE; // 基本窗口类型 ret->baseWin = base; // 注册父窗口 if (msgLoop) ret->msgLoop = msgLoop; // 设置消息处理函数 else ret->msgLoop = WIN_DefaultMsgLoop; // 设置默认消息处理函数 ret->deleteWindow = WIN_DeleteWindow; // 设置销毁函数 if (WIN_AddToChidList(base, ret) == 0) { QUEUE_Init(&ret->winMsgQueue, sizeof(WIN_MsgStruct), 50); WIN_MsgStruct msg = {0}; msg.msg = WIN_MSG_INIT; WIN_SendMsg(0, ret, &msg); return ret; } else { myfree(ret); return 0; } } // 创建已经实例化的窗口,返回1,创建成功 int WIN_CreatWindowExt(WIN_WindowStruct *win, WIN_WindowStruct *base, void (*msgLoop)(struct _WIN_WindowStruct *win, WIN_MsgStruct *msg), int x, int y, int x_size, int y_size) { if (base == 0) base = WIN_GetBaseWindow(); // 没有父窗口,默认父窗口 mymemset(win, 0, sizeof(WIN_WindowStruct)); u16 color = WIN_GetWinStruct()->lcd->getLcdBkColor(); win->bkcolor = COLOR565TO888(color); color = WIN_GetWinStruct()->lcd->getLcdColor(); win->color = COLOR565TO888(color); win->chidWinMaxSize = WIN_CHIDWIN_MAXNUM; win->x = x; win->y = y; win->x_size = x_size; win->y_size = y_size; win->id = WIN_GetWinStruct()->winId++; // 设置窗口唯一ID win->winType = WIN_WINDOW_TYPE; // 基本窗口类型 win->baseWin = base; // 注册父窗口 if (msgLoop) win->msgLoop = msgLoop; // 设置消息处理函数 else win->msgLoop = WIN_DefaultMsgLoop; // 设置默认消息处理函数 win->deleteWindow = WIN_DeleteWindow; // 设置销毁函数 if (WIN_AddToChidList(base, win) == 0) { QUEUE_Init(&win->winMsgQueue, sizeof(WIN_MsgStruct), 50); WIN_MsgStruct msg = {0}; msg.msg = WIN_MSG_INIT; WIN_SendMsg(0, win, &msg); return 1; } else { return 0; } } // 销毁一个窗口,资源回收 void WIN_DeleteWindow(WIN_WindowStruct *win) { // 调用子窗口的销毁函数 while (win->chidWinNum) { (win->chid)->deleteWindow(win->chid); } // 在父窗口的窗口列表中删除 WIN_DelFromChidList(win->baseWin, win); WIN_MsgStruct msg = {0}; // 告知父窗口,子窗口已删除 msg.msg = WIN_MSG_CHID; msg.data.v = CHID_DELETE; msg.data2.v = win->id; WIN_SendMsg(win, win->baseWin, &msg); // 清空消息队列 WIN_ClearMsgQueue(win); // 发送delete消息 msg.msg = WIN_MSG_DELETE; WIN_SendMsg(0, win, &msg); // 通过运行一遍消息循环让窗口处理善后工作 WIN_Working(win); // 父窗口需要重绘 WIN_SetInvalidRect(win->baseWin, win->x, win->y, win->x_size, win->y_size); // 删除创建的定时器 WIN_WinDeleteTimer(win); // 取消置顶 WIN_ResetAsTopWin(win); // 销毁队列 QUEUE_Delete(&win->winMsgQueue); // 当前在阻塞运行本窗口,返回 if (g_win_struct.BlockWin[0] == win) { WIN_SetBlockWinReturn(-1, 0, 0); } // 清除窗口无效标志 if (win->invald) { win->invald = 0; g_win_struct.numOfWindowToPrint--; } // printf ("deleteWin:%s\r\n",win->winType); // 删除窗口,如果当前还在窗口的消息循环里,则不能立即释放内存 if (win->msgLoopEnter) { win->memFree = myfree; } else { myfree(win); } } // 将指定窗口设置为置顶,返回1添加成功 int WIN_SetAsTopWin(WIN_WindowStruct *win) { int i = 0; // for (i=0;g_win_struct.TopWin[i];i++); i = g_win_struct.TopWinNum; if (i < WIN_TOP_MAXNUM) { g_win_struct.TopWin[i] = win; g_win_struct.TopWinNum++; return 1; } else { return 0; } } // 窗口取消置顶,返回1成功 int WIN_ResetAsTopWin(WIN_WindowStruct *win) { int i = 0; for (i = 0; i < g_win_struct.TopWinNum; i++) { if (g_win_struct.TopWin[i] == win) { g_win_struct.TopWin[i] = 0; // 后面的窗口向前移 g_win_struct.TopWinNum--; for (; i < g_win_struct.TopWinNum; i++) { g_win_struct.TopWin[i] = g_win_struct.TopWin[i + 1]; } return 1; } } return 0; } // 根据指定id号获取窗口指针 WIN_WindowStruct *WIN_GetWindowStructById(WIN_WindowStruct *win, u32 id) { WIN_WindowStruct *ret = 0; if (win == 0) win = WIN_GetBaseWindow(); if (win->id == id) { return win; } else { WIN_WindowStruct *prev = WIN_GetLastChidWin(win); for (int i = win->chidWinNum; i > 0; i--) { if (ret = WIN_GetWindowStructById(prev, id), ret) { return ret; } prev = prev->prev; } } return ret; } // 从子窗口列表中删除指定窗口 int WIN_DelFromChidList(WIN_WindowStruct *win, WIN_WindowStruct *chidWin) { WIN_WindowStruct *next = win->chid; for (int i = 0; i < win->chidWinNum; i++) { if (next == chidWin) { if(next != win->chid) { next->prev->next = next->next; } else { win->chid = next->next; } if(next->next){ next->next->prev = next->prev; }else{ win->chid->prev = next->prev; } win->chidWinNum--; // 子窗口个数减一 return 0; } next = next->next; } return -1; } // 把指定子窗口设置为最高 int WIN_SetChidWinTop(WIN_WindowStruct *win, WIN_WindowStruct *chidWin) { WIN_WindowStruct *t = 0; WIN_WindowStruct *next = win->chid; for (int i = 0; i < win->chidWinNum; i++) { if (next == chidWin) { t = next; if(next != win->chid) { next->prev->next = next->next; } else { win->chid = next->next; } if(next->next){ next->next->prev = next->prev; }else{ win->chid->prev = next->prev; } t->next = 0; t->prev = win->chid->prev; win->chid->prev->next = t; win->chid->prev = t; return 0; } next = next->next; } return -1; } // 添加窗口到子窗口列表中 int WIN_AddToChidList(WIN_WindowStruct *win, WIN_WindowStruct *chidWin) { if (win->chidWinNum < win->chidWinMaxSize) { chidWin->next = 0; if(win->chid == 0){ win->chid = chidWin; }else{ chidWin->prev = win->chid->prev; win->chid->prev->next = chidWin; } win->chid->prev = chidWin; win->chidWinNum++; return 0; } else { return -1; } } // 判断目标窗口是不是子窗口,是返回1 int WIN_CheckChidWin(WIN_WindowStruct *win, WIN_WindowStruct *chid) { WIN_WindowStruct *next = win->chid; for (int i = 0; i < win->chidWinNum; i++) { if (next == chid) return 1; next = next->next; } return 0; } // 找到指定窗口在屏幕上的坐标和大小 void WIN_GetWinPosOnLcd(WIN_WindowStruct *win, int *x, int *y, int *x_size, int *y_size) { *x = 0; *y = 0; *x_size = win->x_size; *y_size = win->y_size; // 遍历父窗口获得窗口的实际屏幕坐标 WIN_WindowStruct *t = win; do { *x += t->x; *y += t->y; t = t->baseWin; } while (t); } // 阻塞窗口运行结束时设置返回值 void WIN_SetBlockWinReturn(int ret, void *data, int datasize) { g_win_struct.BlockWinReturn = ret; // 上个阻塞窗口的数据没有读取,这里丢弃掉 if (g_win_struct.BlockWinData) myfree(g_win_struct.BlockWinData); if (data && datasize) { g_win_struct.BlockWinData = mymalloc(datasize); mymemcpy(g_win_struct.BlockWinData, data, datasize); g_win_struct.BlockWinDataSize = datasize; } else { g_win_struct.BlockWinData = 0; g_win_struct.BlockWinDataSize = 0; } // 调用了这个函数之后窗口返回 // 这里执行窗口栈出栈 if (g_win_struct.BlockWinNum) { g_win_struct.BlockWinNum--; for (int i = 0; i < g_win_struct.BlockWinNum; i++) { g_win_struct.BlockWin[i] = g_win_struct.BlockWin[i + 1]; } g_win_struct.BlockWin[g_win_struct.BlockWinNum] = 0; } } // 获取阻塞窗口的数据 int WIN_GetBlockWinReturn(int *ret, void *buff, int buffsize) { int size = buffsize; if (size > g_win_struct.BlockWinDataSize) size = g_win_struct.BlockWinDataSize; *ret = g_win_struct.BlockWinReturn; if (g_win_struct.BlockWinData) { mymemcpy(buff, g_win_struct.BlockWinData, size); myfree(g_win_struct.BlockWinData); // 解决free(g_win_struct.BlockWinData)之后在函数WIN_SetBlockWinReturn再次free的bug // 2020.8.3 g_win_struct.BlockWinData = 0; } return size; } // 返回基础窗口指针 WIN_WindowStruct *WIN_GetBaseWindow(void) { return &WIN_GetWinStruct()->baseWin; } // 返回最后一次运行的窗口 WIN_WindowStruct *WIN_GetCurrentWindow(void) { return WIN_GetWinStruct()->winCurrent; } // 找到顶端可控窗口 WIN_WindowStruct *WIN_FindTopWin(WIN_WindowStruct *win) { WIN_WindowStruct *ret = 0; WIN_WindowStruct *prev = WIN_GetLastChidWin(win); if (win && (win->chidWinNum)) { for (int i = win->chidWinNum; i > 0; i--) { ret = WIN_FindTopWin(prev); if (ret) return ret; prev = prev->prev; } } // 本窗口接受消息处理并且不是子窗口 if (win && (win->keyShield == 0) && (win->keyChid == 0)) return win; else return 0; } // 查找win是否被遮挡,是,返回1 int WIN_FindBlock(WIN_WindowStruct *win) { RECT_Struct r1 = {0}; RECT_Struct r2 = {0}; WIN_WindowStruct *top = 0; WIN_WindowStruct *base = win->baseWin; WIN_WindowStruct *next = win->chid; WIN_WindowStruct *prev; // 该窗口被遮挡只可能是其子窗口和其同辈父辈窗口 for (int i = 0; i < win->chidWinNum; i++) { top = next; if ((top->keyShield == 1) || (top->keyChid == 1)) continue; r1.x = 0; r1.y = 0; r1.x_size = win->x_size; r1.y_size = win->y_size; r2.x = top->x; r2.y = top->y; r2.x_size = top->x_size; r2.y_size = top->y_size; if (POS_RectIntersection(&r1, &r1, &r2)) { return 1; } next = next->next; } while (base) { prev = WIN_GetLastChidWin(base); for (int i = base->chidWinNum; i > 0; i--) { top = prev; if (top == win) { // 只比较在此窗口之前的窗口 // 若没有被遮挡,则继续判断其父窗口是否被遮挡 win = base; break; } WIN_GetWinPosOnLcd(top, &r1.x, &r1.y, &r1.x_size, &r1.y_size); WIN_GetWinPosOnLcd(win, &r2.x, &r2.y, &r2.x_size, &r2.y_size); if (POS_RectIntersection(&r1, &r1, &r2)) { return 1; } prev = prev->prev; } base = base->baseWin; } return 0; } // 屏蔽和接触屏蔽子窗口的按键和键盘消息 int WIN_SetChildWinkeyShield(WIN_WindowStruct *win, int power) { WIN_WindowStruct *prev = WIN_GetLastChidWin(win); for (int i = win->chidWinNum - 1; i >= 0; i--) { prev->keyShield = power; prev = prev->prev; } return 1; } // 通过指定的坐标找到顶端可控的窗口,没找到返回0 WIN_WindowStruct *WIN_FindTopWinByPos(WIN_WindowStruct *win, int x, int y) { WIN_WindowStruct *ret = win; int win_x_s = 0; int win_y_s = 0; int x_size = win->x_size; int y_size = win->y_size; WIN_WindowStruct *prev = WIN_GetLastChidWin(win); WIN_GetWinPosOnLcd(win, &win_x_s, &win_y_s, &x_size, &y_size); WIN_WindowStruct *t = 0; if (((x >= win_x_s) && (x < win_x_s + x_size)) && ((y >= win_y_s) && (y < win_y_s + y_size)) && (win->keyShield == 0)) { // 在本窗口内,查找是否有子窗口 // 从最后开始查找,因为越最后的显示在越前面 for (int i = win->chidWinNum - 1; i >= 0; i--) { t = WIN_FindTopWinByPos(prev, x, y); if (t) { ret = t; // 找到了最前面的窗口 break; } prev = prev->prev; } } else { // 指定点不在本窗口之类 ret = 0; } return ret; } // 返回两个窗口的共同父窗口,没有共同父窗口返回0 WIN_WindowStruct *WIN_FindPrent(WIN_WindowStruct *win1, WIN_WindowStruct *win2) { while ((win1) && (win2)) { if (win1 == win2) return win1; win1 = win1->baseWin; win2 = win2->baseWin; } return 0; } // 设置窗口标题 void WIN_SetWinTitle(WIN_WindowStruct *win, char *title) { int len = strlen(title); if (len > WIN_WINTITLE_MAXLEN - 1) { len = WIN_WINTITLE_MAXLEN - 1; } mymemcpy(win->winTitle, title, len); win->winTitle[len] = 0; } // 根据窗口标题找到窗口指针 // 深度优先搜索 WIN_WindowStruct *WIN_GetWinByTitle(WIN_WindowStruct *win, char *title) { WIN_WindowStruct *ret = 0; if (win == 0) win = WIN_GetBaseWindow(); WIN_WindowStruct *next = win->chid; if (strcmp(win->winTitle, title) == 0) { ret = win; } else { for (int i = 0; i < win->chidWinNum; i++) { if (ret = WIN_GetWinByTitle(next, title), ret) break; next = next->next; } } return ret; } // 根据窗口坐标设置LCD的活动窗口,所有绘制操作都在这个窗口之内 void WIN_EnterPaint(WIN_WindowStruct *win) { int x = 0; int y = 0; int x_size = win->x_size; int y_size = win->y_size; WIN_GetWinPosOnLcd(win, &x, &y, &x_size, &y_size); WIN_GetWinStruct()->lcd->setWindow(x, y, x_size, y_size); } // 设置无效区矩形,此矩形会被限制在窗口无效区之内 void WIN_SetWinInvalidRect(WIN_WindowStruct *win, RECT_Struct *r) { if (r == 0) r = &win->invaldRect; RECT_Struct out = {0}; POS_RectIntersection(&out, r, &win->invaldRect); int x = out.x; int y = out.y; int x_size = out.x_size; int y_size = out.y_size; g_win_struct.Invalid_x = x; g_win_struct.Invalid_y = y; g_win_struct.Invalid_x_size = x_size; g_win_struct.Invalid_y_size = y_size; } // 获取窗口无效区矩形 void WIN_GetWinInvalidRect(WIN_WindowStruct *win, RECT_Struct *r) { r->x = g_win_struct.Invalid_x; r->y = g_win_struct.Invalid_y; r->x_size = g_win_struct.Invalid_x_size; r->y_size = g_win_struct.Invalid_y_size; } // 在窗口绘制时,判断需不需要绘制顶端窗口 void WIN_TopWinPaint(WIN_WindowStruct *win) { RECT_Struct r1 = {0}; RECT_Struct r2 = {0}; RECT_Struct rout = {0}; WIN_GetWinPosOnLcd(win, &r1.x, &r1.y, &r1.x_size, &r1.y_size); for (int i = 0; i < g_win_struct.TopWinNum; i++) { WIN_GetWinPosOnLcd(g_win_struct.TopWin[i], &r2.x, &r2.y, &r2.x_size, &r2.y_size); if (POS_RectIntersection(&rout, &r1, &r2) == 1) { // 需要刷新顶端窗口 WIN_SetInvalidRect(g_win_struct.TopWin[i], rout.x - r2.x, rout.y - r2.y, rout.x_size, rout.y_size); } } } // 窗口默认的绘制函数 void WIN_DefaultPaint(WIN_WindowStruct *win) { WIN_PaintBackGround(win); // WIN_SetLcdColor (win->color); // WIN_Clear(); // WIN_DrawHLine(0,0,LCD_GetWindowSizeX()-1); // WIN_DrawVLine(0,0,LCD_GetWindowSizeY()-1); // WIN_DrawHLine(0,LCD_GetWindowSizeY()-1,LCD_GetWindowSizeX()-1); // WIN_DrawVLine(LCD_GetWindowSizeX()-1,0,LCD_GetWindowSizeY()-1); } // 显示窗口 void WIN_ShowWindow(WIN_WindowStruct *win) { // 把窗口设置为无效, WIN_SetInvalid(win); // 通过运行一遍消息循环来显示 // WIN_Working (win); } // 绘制背景 void WIN_PaintBackGround(WIN_WindowStruct *win) { // 如果有图片就显示图片 WIN_SetLcdBkColor(win->bkcolor); WIN_PicStruct *pic = 0; if (win->drawBackPic) { win->drawBackPic(); } else if (pic = WIN_GetPicNoAlpha(win->pic_path), pic) { WIN_DrawPic(pic, 0, 0, ((WIN_WindowStruct *)win)->x_size, ((WIN_WindowStruct *)win)->y_size); } else if (WIN_DrawPic(&win->pic, 0, 0, ((WIN_WindowStruct *)win)->x_size, ((WIN_WindowStruct *)win)->y_size)) { } else { WIN_Clear(); } } void WIN_SetColor(WIN_WindowStruct *win, u32 color) { win->color = color; } void WIN_SetBkColor(WIN_WindowStruct *win, u32 bkcolor) { win->bkcolor = bkcolor; } // 设置页面的背景图片路径 void WIN_SetBackPicPath(WIN_WindowStruct *win, char *path) { if (path) { int len = strlen(path); if (len + 1 > WIN_FILE_PATH_MAXLEN) printf("%s:err,pic path too long\r\n", __func__); mymemcpy(&win->pic_path, path, len + 1); WIN_PicStruct *pic = WIN_GetPic(win->pic_path); if (pic) mymemcpy(&win->pic, pic, sizeof(WIN_PicStruct)); } else { int len = strlen(path); mymemset(&win->pic_path, 0, len + 1); } } // 设置页面的背景图片 void WIN_SetBackPic(WIN_WindowStruct *win) { WIN_PicStruct pic = {0}; WIN_WindowStruct *base = win->baseWin; WIN_PicStruct *pic_base = WIN_GetPic(base->pic_path); if (pic_base) { int x = win->x; int y = win->y; if ((y < pic_base->ysize) && (x < pic_base->xsize)) { pic.data = pic_base->data + pic_base->xsize * y + x; pic.xsize = pic_base->xsize; pic.ysize = pic_base->ysize - y - 1; } mymemcpy(&win->pic, &pic, sizeof(WIN_PicStruct)); } else { mymemset(&win->pic, 0, sizeof(WIN_PicStruct)); } } // 设置页面的画背景函数 void *WIN_SetBackFun(WIN_WindowStruct *win, void (*fun)(void)) { void *ret = win->drawBackPic; if (fun) { win->drawBackPic = fun; } return ret; }