quinn-os/gui.c
2017-10-08 16:39:06 +10:00

794 lines
22 KiB
C

#include "multiboot.h"
#include "font.h"
#include "pointer.xpm"
#include "minimize.xpm"
#include "close.xpm"
#include "defaulticon.xpm"
#include "keyboard.h"
#include "gui.h"
#include "schedule.h"
#include "mouse.h"
#include "string.h"
#include "memory.h"
#include "console.h"
extern struct task_t *current_task;
extern const struct bitmap_font font;
#define WIN_REQ_FLAG_NO_TITLE 0x01
#define BochsBreak() outportw(0x8A00,0x8A00); outportw(0x8A00,0x08AE0);
#define BochsConsolePrintChar(c) outportb(0xe9, c)
void render(unsigned char* dest, unsigned char* src, unsigned int src_width, unsigned int src_height, int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height, unsigned int src_depth);
void gui_pagemap();
struct ModeInfoBlock {
unsigned short attributes;
unsigned char winA,winB;
unsigned short granularity;
unsigned short winsize;
unsigned short segmentA, segmentB;
unsigned int winFuncPointer;
unsigned short pitch; // bytes per scanline
unsigned short Xres, Yres;
unsigned char Wchar, Ychar, planes, bpp, banks;
unsigned char memory_model, bank_size, image_pages;
unsigned char reserved0;
unsigned char red_mask, red_position;
unsigned char green_mask, green_position;
unsigned char blue_mask, blue_position;
unsigned char rsv_mask, rsv_position;
unsigned char directcolor_attributes;
unsigned int physbase; // your LFB (Linear Framebuffer) address ;)
unsigned int reserved1;
unsigned short reserved2;
} __attribute__((packed));
unsigned char *defaulticon;
unsigned char *mouseptr;
unsigned char *backbuffer;
unsigned char vidmode;
unsigned char *framebuffer;
unsigned short width, height, depth, bytesPerLine;
unsigned char *minimizebtn;
unsigned char *closebtn;
unsigned char *wallpaper;
unsigned int window_count = 0;
struct window_t **windows;
extern int mouse_pos_x;
extern int mouse_pos_y;
extern char middle_btn;
extern char left_btn;
extern char right_btn;
unsigned int serialnos;
int wallpaper_lock;
struct ModeInfoBlock *modeinfo;
void gui_convert_xpm(char **xpm, unsigned char **buffer);
void init_gui(multiboot_info_t *mbinfo) {
if (mbinfo->flags & 1 << 11) {
serialnos = 0;
vidmode = 1;
modeinfo = (struct ModeInfoBlock *)mbinfo->vbe_mode_info;
framebuffer = (unsigned char *)modeinfo->physbase;
bytesPerLine = modeinfo->pitch;
width = modeinfo->Xres;
height = modeinfo->Yres;
depth = modeinfo->bpp / 8;
gui_pagemap();
backbuffer = (unsigned char *)malloc(width * height * depth);
memset(backbuffer, 0, width * height * depth);
windows = (void *)0;
//closebtn = (char *)malloc(16 * 16 * 3);
//memset(closebtn, 0, 16 * 16 * 3);
gui_convert_xpm(close_xpm, &closebtn);
gui_convert_xpm(pointer_xpm, &mouseptr);
//mouseptr = (char *)malloc(32 * 32 * 3);
//memset(mouseptr, 0, 32 * 32 * 3);
gui_convert_xpm(minimize_xpm, &minimizebtn);
//minimizebtn = (char *)malloc(16 * 16 * 3);
//memset(minimizebtn, 0, 16 * 16 * 3);
gui_convert_xpm(defaulticon_xpm, &defaulticon);
//defaulticon = (char *)malloc(64 * 64 * 3);
//memset(defaulticon, 0, 64 * 64 * 3);
wallpaper = (void *)0;
wallpaper_lock = 0;
} else {
vidmode = 0;
}
}
void fill_rect(unsigned char *buffer, unsigned int dest_width, unsigned int dest_height, int sx, int sy, int w, int h, unsigned int colour) {
int j;
int k;
unsigned int where;
if (sy < 0) {
h = h + sy;
sy = 0;
}
if (sx < 0) {
w = w + sx;
sx = 0;
}
if (sx + w >= dest_width) {
w = dest_width - sx;
}
if (sy + h >= dest_height) {
h = dest_height - sy;
}
where = (sy * (dest_width * depth)) + (sx * depth);
for (j=0;j<h;j++) {
for (k=0;k<w;k++) {
buffer[where + k*depth] = colour & 255;
buffer[where + k*depth + 1] = (colour >> 8) & 255;
buffer[where + k*depth + 2] = (colour >> 16) & 255;
}
where += (dest_width) * depth;
}
}
void gui_putpixel(unsigned char *buffer, unsigned int dest_width, unsigned int dest_height, int x, int y, unsigned int color) {
if (x >= dest_width || y >= dest_height) {
return;
}
if (x < 0 || y < 0) {
return;
}
int where = (x * depth) + (y * dest_width * depth);
buffer[where] = color & 255; // BLUE
buffer[where + 1] = (color >> 8) & 255; // GREEN
buffer[where + 2] = (color >> 16) & 255; // RED
}
int char_to_hex(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
} else {
return (c - 'A') + 10;
}
}
void gui_convert_xpm(char **xpm, unsigned char **buffer) {
unsigned int bwidth;
unsigned int bheight;
unsigned int colours;
unsigned int charsperpixel;
int offset = 0;
bwidth = 0;
while (xpm[0][offset] != ' ') {
bwidth = bwidth * 10 + (xpm[0][offset] - '0');
offset++;
}
offset++;
bheight = 0;
while (xpm[0][offset] != ' ') {
bheight = bheight * 10 + (xpm[0][offset] - '0');
offset++;
}
offset++;
colours = 0;
while (xpm[0][offset] != ' ') {
colours = colours * 10 + (xpm[0][offset] - '0');
offset++;
}
offset++;
charsperpixel = 0;
while (xpm[0][offset] != ' ' && xpm[0][offset] != '\0') {
charsperpixel = charsperpixel * 10 + (xpm[0][offset] - '0');
offset++;
}
// do colours
unsigned int *theColours = (unsigned int *)malloc(sizeof(unsigned int) * colours);
char **theKeys = (char**)malloc(colours * sizeof(char *));
int i,j,k,l;
for (i=0;i<colours;i++) {
theKeys[i] = (char *)malloc(charsperpixel);
for (j=0;j<charsperpixel;j++) {
theKeys[i][j] = xpm[i+1][j];
}
offset = 3 + charsperpixel;
if (xpm[i+1][offset] == '#') {
theColours[i] = 0;
offset++;
theColours[i] = theColours[i] | (char_to_hex(xpm[i+1][offset]) << 20);
offset++;
theColours[i] = theColours[i] | (char_to_hex(xpm[i+1][offset]) << 16);
offset++;
theColours[i] = theColours[i] | (char_to_hex(xpm[i+1][offset]) << 12);
offset++;
theColours[i] = theColours[i] | (char_to_hex(xpm[i+1][offset]) << 8);
offset++;
theColours[i] = theColours[i] | (char_to_hex(xpm[i+1][offset]) << 4);
offset++;
theColours[i] = theColours[i] | char_to_hex(xpm[i+1][offset]);
} else {
theColours[i] = 0xff000000;
}
}
unsigned char *ptr = (unsigned char *)malloc(bwidth * bheight * 3);
*buffer = ptr;
memset(ptr, 0, bwidth * bheight * 3);
int boffset = 0;
int match;
for (i=0;i<bheight;i++) {
for (j=0;j<bwidth;j++) {
for (k=0;k<colours;k++) {
match = 1;
for (l=0;l<charsperpixel;l++) {
if (theKeys[k][l] != xpm[i+colours+1][j * charsperpixel + l]){
match = 0;
}
}
if (match == 1) {
if (theColours[k] != 0xff000000) {
ptr[boffset] = theColours[k] & 255; // BLUE
ptr[boffset + 1] = (theColours[k] >> 8) & 255; // GREEN
ptr[boffset + 2] = (theColours[k] >> 16) & 255; // RED
}
boffset+=3;
break;
}
}
}
}
free(theColours);
for (i=0;i<colours;i++) {
free(theKeys[i]);
}
free(theKeys);
}
void gui_display_pointer() {
render(backbuffer, mouseptr, 32, 32, mouse_pos_x, mouse_pos_y, width, height, 3);
}
void gui_draw_char(unsigned char *buffer, unsigned int dest_width, unsigned int dest_height, unsigned int x, unsigned int y, char c, unsigned int colour) {
int i;
for (i=0;i<font.Chars;i++) {
if (font.Index[i] == c) break;
}
const char *font_char = &font.Bitmap[i * font.Height];
int cx,cy;
//int mask[8]={1,2,4,8,16,32,64,128};
int mask[8]={128,64,32,16,8,4,2,1};
for(cy=0;cy<16;cy++){
for(cx=0;cx<8;cx++){
if(font_char[cy]&mask[cx]) gui_putpixel(buffer, dest_width, dest_height, x+cx,y+cy, colour);
}
}
}
void draw_text(unsigned char *buffer, unsigned int dest_width, unsigned int dest_height, int sx, int sy, unsigned int colour, char *text) {
int i;
for (i=0;i<strlen(text);i++) {
gui_draw_char(buffer, dest_width, dest_height, sx + (i * 8), sy, text[i], colour);
}
}
void gui_keyboard_in(unsigned char scancode, unsigned char state) {
// add a keyboard message
if (windows[window_count-1]->event_msg_count < 99) {
struct event_msg_t *new_msg = (struct event_msg_t *)malloc(sizeof(struct event_msg_t));
new_msg->type = 1;
new_msg->code = scancode;
new_msg->state = state;
windows[window_count-1]->event_msgs[windows[window_count-1]->event_msg_count++] = new_msg;
}
}
extern int gui_change_window_caption(int serialno, char *cap) {
int i;
for (i=0;i<window_count;i++) {
if (windows[i]->serialno == serialno) {
strncpy(windows[i]->name, cap, 128);
return 0;
}
}
return -1;
}
int gui_add_window(unsigned char *contents, char *name, int x, int y, int w, int h, unsigned char *icon, unsigned int flags, void (*keyboard_d)(char c)) {
struct window_t *new_window;
int i;
if (window_count == 0) {
windows = (struct window_t **)malloc(sizeof(struct window_t *));
} else {
windows = (struct window_t **)realloc(windows, sizeof(struct window_t *) * (window_count + 1));
}
new_window = (struct window_t *)malloc(sizeof(struct window_t));
new_window->serialno = ++serialnos;
new_window->posx = x;
new_window->posy = y;
new_window->width = w;
new_window->height = h;
new_window->minimized = 0;
new_window->iconx = 0;
new_window->icony = 0;
new_window->close_req = 0;
new_window->lclick = 0;
new_window->rclick = 0;
new_window->mclick = 0;
new_window->flags = flags;
new_window->event_msg_count = 0;
if (contents == (void *)0) {
new_window->contents = (unsigned char *)malloc(w * h * depth);
memset(new_window->contents, 0, w * h * depth);
} else {
new_window->contents = contents;
}
if (keyboard_d == (void *)0) {
new_window->keyboard_dest = gui_keyboard_in;
} else {
new_window->keyboard_dest = keyboard_d;
}
if (icon == (void *)0) {
new_window->icon = (unsigned char *)malloc(64 * 64 * 3);
memcpy(new_window->icon, defaulticon, 64 * 64 * 3);
} else {
new_window->icon = (unsigned char *)malloc(64 * 64 * 3);
memcpy(new_window->icon, icon, 64 * 64 * 3);
}
strncpy(new_window->name, name, 128);
new_window->zorder = window_count;
windows[window_count] = new_window;
window_count++;
keyboard_set_handler(new_window->keyboard_dest);
if (current_task->window_count == 0) {
current_task->window_list = (struct window_t **)malloc(sizeof(struct window_t *));
} else {
current_task->window_list = (struct window_t **)realloc(current_task->window_list, sizeof(struct window_t *) * (current_task->window_count + 1));
}
current_task->window_list[current_task->window_count] = new_window;
current_task->window_count++;
return new_window->serialno;
}
void gui_destroy_window(int serialno, struct task_t *task) {
struct window_t *window;
int i, j, k;
for (i=0;i<window_count;i++) {
if (windows[i]->serialno == serialno) {
window = windows[i];
for (k=0;k<task->window_count;k++) {
if (task->window_list[k] == window) {
for (j=k;j<task->window_count-1;j++) {
task->window_list[j] = task->window_list[j+1];
}
task->window_count--;
if (task->window_count == 0) {
free(task->window_list);
task->window_list = (void *)0;
} else {
task->window_list = (struct window_t **)realloc(task->window_list, sizeof(struct window_t *) * task->window_count);
}
break;
}
}
for (j=i;j<window_count-1;j++) {
windows[j] = windows[j+1];
}
window_count--;
windows = (struct window_t **)realloc(windows, sizeof(struct window_t *) * window_count);
keyboard_set_handler(windows[window_count-1]->keyboard_dest);
free(window->icon);
free(window->contents);
free(window);
return;
}
}
kprintf("Window not found %d\n", serialno);
}
void gui_drawtitlebar(unsigned char *buffer, unsigned int dest_width, unsigned int dest_height, struct window_t *window) {
fill_rect(buffer, dest_width, dest_height, window->posx, window->posy - 25, window->width, 25, 0xf182f8);
draw_text(buffer, dest_width, dest_height, window->posx + 25 + 4, window->posy - 25 + 4, 0xffffff, window->name);
render(buffer, minimizebtn, 16, 16, window->posx + window->width - 20, window->posy - 20, dest_width, dest_height, 3);
render(buffer, closebtn, 16, 16, window->posx + 5, window->posy - 20, dest_width, dest_height, 3);
}
void gui_pagemap() {
framebuffer = mem_map_framebuffer((unsigned int)framebuffer, bytesPerLine * height);
}
void gui_find_icon_space(struct window_t *window) {
int i,j;
int x, y;
int foundspot;
i = 0;
while (1) {
y = height - (((i / (width / 96)) + 1) * 96);
x = (i % (width / 96)) * 96 + 16;
foundspot = 1;
for (j=0;j<window_count;j++) {
if (!(windows[j]->iconx == 0 && windows[j]->icony == 0)) {
if (!(x > windows[j]->iconx && x < windows[j]->iconx + 96 && y > windows[j]->icony && y < windows[j]->icony + 96) && !(windows[j]->icony == y && windows[j]->iconx == x)) {
foundspot = 1;
} else {
foundspot = 0;
break;
}
}
}
if (foundspot || i == 80) {
window->iconx = x;
window->icony = y;
return;
}
i++;
}
}
int gui_blit(int wh, int x, int y, int w, int h, unsigned char *bmp) {
struct window_t *win = (void *)0;
int i;
for (i=0;i<window_count;i++) {
if (windows[i]->serialno == wh) {
win = windows[i];
break;
}
}
if (win == (void *)0) {
return 0;
}
render(win->contents, bmp, w, h, x, y, win->width, win->height, 3);
return 1;
}
int gui_req_input(int wh, struct window_update_req *req) {
struct window_t *win = (void *)0;
int i;
for (i=0;i<window_count;i++) {
if (windows[i]->serialno == wh) {
win = windows[i];
break;
}
}
if (win == (void *)0) {
return 0;
}
req->close_req = win->close_req;
req->event_msgs_count = win->event_msg_count;
for (i=0;i<req->event_msgs_count;i++) {
memcpy(&req->event_msgs[i], win->event_msgs[i], sizeof(struct event_msg_t));
free(win->event_msgs[i]);
}
win->event_msg_count = 0;
req->mousex = mouse_pos_x - win->posx;
req->mousey = mouse_pos_y - win->posy;
req->x = win->posx;
req->y = win->posy;
win->close_req = 0;
return 1;
}
void gui_flip() {
int i, c, d;
struct window_t *swap;
// do click
if (mouse_get_click(0) == 1) {
for (i=window_count-1;i>=0;i--) {
if (!(windows[i]->minimized)) {
if (mouse_pos_x > windows[i]->posx && mouse_pos_x < windows[i]->posx + windows[i]->width && mouse_pos_y > windows[i]->posy - 25 && mouse_pos_y < windows[i]->posy + windows[i]->height) {
// send mouse click to client
if (mouse_pos_x > windows[i]->posx + windows[i]->width - 25 && mouse_pos_x < windows[i]->posx + windows[i]->width && mouse_pos_y > windows[i]->posy - 25 && mouse_pos_y < windows[i]->posy) {
// minimize
windows[i]->minimized = 1;
if (windows[i]->iconx == 0 && windows[i]->icony == 0) {
gui_find_icon_space(windows[i]);
}
} else if (mouse_pos_x > windows[i]->posx && mouse_pos_x < windows[i]->posx + 25 && mouse_pos_y > windows[i]->posy - 25 && mouse_pos_y < windows[i]->posy) {
windows[i]->close_req = 1;
} else if (windows[i]->zorder != window_count -1) {
windows[window_count-1]->zorder = windows[i]->zorder;
windows[i]->zorder = window_count - 1;
keyboard_set_handler(windows[i]->keyboard_dest);
}
break;
}
}
}
for (i=window_count-1;i>=0;i--) {
if (windows[i]->minimized) {
if (mouse_pos_x > windows[i]->iconx -16 && mouse_pos_x < windows[i]->iconx + 72 && mouse_pos_y > windows[i]->icony -16 && mouse_pos_y < windows[i]->icony + 72) {
windows[i]->minimized = 0;
break;
}
}
}
}
// process mouse down / up events
for (i=window_count-1;i>=0;i--) {
if (!windows[i]->minimized) {
if (mouse_pos_x > windows[i]->posx && mouse_pos_x < windows[i]->posx + windows[i]->width && mouse_pos_y > windows[i]->posy && mouse_pos_y < windows[i]->posy + windows[i]->height) {
if (windows[i]->lclick != left_btn) {
if (windows[i]->event_msg_count < 99) {
struct event_msg_t *new_event = (struct event_msg_t *)malloc(sizeof(struct event_msg_t));
new_event->type = 2;
new_event->code = 1;
new_event->state = left_btn;
new_event->x = mouse_pos_x - windows[i]->posx;
new_event->y = mouse_pos_y - windows[i]->posy;
windows[i]->event_msgs[windows[i]->event_msg_count++] = new_event;
}
windows[i]->lclick = left_btn;
}
if (windows[i]->mclick != middle_btn) {
if (windows[i]->event_msg_count < 99) {
struct event_msg_t *new_event = (struct event_msg_t *)malloc(sizeof(struct event_msg_t));
new_event->type = 2;
new_event->code = 2;
new_event->state = middle_btn;
new_event->x = mouse_pos_x - windows[i]->posx;
new_event->y = mouse_pos_y - windows[i]->posy;
windows[i]->event_msgs[windows[i]->event_msg_count++] = new_event;
}
windows[i]->mclick = middle_btn;
}
if (windows[i]->rclick != right_btn) {
if (windows[i]->event_msg_count < 99) {
struct event_msg_t *new_event = (struct event_msg_t *)malloc(sizeof(struct event_msg_t));
new_event->type = 2;
new_event->code = 3;
new_event->state = right_btn;
new_event->x = mouse_pos_x - windows[i]->posx;
new_event->y = mouse_pos_y - windows[i]->posy;
windows[i]->event_msgs[windows[i]->event_msg_count++] = new_event;
}
windows[i]->rclick =right_btn;
}
}
}
}
int handled_drag = 0;
if (mouse_is_dragging(0)) {
for (i=window_count-1;i>=0;i--) {
if (!(windows[i]->minimized)) {
if (windows[i]->drag_start_x > -1) {
int xoffset = mouse_pos_x - windows[i]->drag_start_x;
int yoffset = mouse_pos_y - windows[i]->drag_start_y;
windows[i]->posx += xoffset;
windows[i]->posy += yoffset;
}
if (mouse_pos_x > windows[i]->posx && mouse_pos_x < windows[i]->posx + windows[i]->width && mouse_pos_y > windows[i]->posy - 25 && mouse_pos_y < windows[i]->posy) {
windows[i]->drag_start_x = mouse_pos_x;
windows[i]->drag_start_y = mouse_pos_y;
handled_drag = 1;
break;
}
}
}
if (!handled_drag) {
for (i=window_count-1;i>=0;i--) {
if (windows[i]->minimized) {
if (windows[i]->drag_start_x > -1) {
int xoffset = mouse_pos_x - windows[i]->drag_start_x;
int yoffset = mouse_pos_y - windows[i]->drag_start_y;
windows[i]->iconx += xoffset;
windows[i]->icony += yoffset;
}
if (mouse_pos_x > windows[i]->iconx -16 && mouse_pos_x < windows[i]->iconx + 72 && mouse_pos_y > windows[i]->icony -16 && mouse_pos_y < windows[i]->icony + 72) {
windows[i]->drag_start_x = mouse_pos_x;
windows[i]->drag_start_y = mouse_pos_y;
}
}
}
}
} else {
for (i=window_count-1;i>=0;i--) {
windows[i]->drag_start_x = -1;
windows[i]->drag_start_y = -1;
}
}
// sort windows
for (c = 0 ; c < ( window_count - 1 ); c++) {
for (d = 0 ; d < window_count - c - 1; d++) {
if (windows[d]->zorder > windows[d+1]->zorder) {
swap = windows[d];
windows[d] = windows[d+1];
windows[d+1] = swap;
}
}
}
// draw desktop
if (wallpaper == (void *)0 || wallpaper_lock == 1) {
fill_rect(backbuffer, width, height, 0, 0, width, height, 0xfeccff);
} else {
render(backbuffer, wallpaper, 1024, 768, 0, 0, width, height, 3);
}
// draw icons
for (i=0;i<window_count;i++) {
if (windows[i]->minimized == 1) {
render(backbuffer, windows[i]->icon, 64, 64, windows[i]->iconx, windows[i]->icony, width, height, 3);
fill_rect(backbuffer, width, height, (48 - (strlen(windows[i]->name) * 8 / 2)) + (windows[i]->iconx - 16), windows[i]->icony + 74, strlen(windows[i]->name) * 8, 16, 0xf9c5ff);
draw_text(backbuffer, width, height, (48 - (strlen(windows[i]->name) * 8 / 2)) + (windows[i]->iconx - 16), windows[i]->icony + 74, 0, windows[i]->name);
}
}
// draw windows
for (i=0;i<window_count;i++) {
if (windows[i]->minimized == 0) {
if (!(windows[i]->flags & WIN_REQ_FLAG_NO_TITLE)) {
fill_rect(backbuffer, width, height, windows[i]->posx - 1, windows[i]->posy - 26, windows[i]->width + 2, windows[i]->height + 27, 0);
gui_drawtitlebar(backbuffer, width, height, windows[i]);
} else {
fill_rect(backbuffer, width, height, windows[i]->posx - 1, windows[i]->posy - 1, windows[i]->width + 2, windows[i]->height + 2, 0);
}
render(backbuffer, windows[i]->contents, windows[i]->width, windows[i]->height, windows[i]->posx, windows[i]->posy, width, height, depth);
}
}
// draw mouse
gui_display_pointer();
// flip
memcpy(framebuffer, backbuffer, bytesPerLine * height);
}
void render(unsigned char* dest, unsigned char* src, unsigned int src_width, unsigned int src_height, int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height, unsigned int src_depth) {
int i;
int pitch = dest_width * depth;
int src_off_x = 0;
int src_off_y = 0;
int index;
int dindex;
if (dest_x < 0) {
src_off_x = -dest_x;
dest_x = 0;
if (src_off_x >= src_width) {
return;
}
}
if (dest_y < 0) {
src_off_y = -dest_y;
dest_y = 0;
if (src_off_y >= src_height) {
return;
}
}
for (i=src_off_y;i<src_height;i++) {
unsigned int offset = (dest_x * depth) + (pitch * (dest_y + i));
unsigned char *pdest = (unsigned char *)(dest + offset);
unsigned char *psrc = (unsigned char *)(src + (src_width * src_depth * i));
int size = (src_width - src_off_x) * src_depth;
if (dest_y + i >= dest_height) {
break;
}
for (index = 0,dindex=0; index < size; index += src_depth,dindex+=depth) {
if (dest_x + (dindex / depth) > dest_width) {
break;
}
if (psrc[index] == 0xFF && psrc[index + 1] == 0x00 && psrc[index + 2] == 0xFF) continue;
pdest[dindex] = psrc[index + (src_off_x * src_depth)];
pdest[dindex+1] = psrc[index + (src_off_x * src_depth) + 1];
pdest[dindex+2] = psrc[index + (src_off_x * src_depth) + 2];
}
}
}
int gui_set_wallpaper(char *data, int len) {
wallpaper_lock = 1;
if (wallpaper != (void *)0) {
free(wallpaper);
}
wallpaper = (char *)dbmalloc(len, "gui_set_wallpaper");
if (!wallpaper) {
wallpaper_lock = 0;
return 0;
}
memcpy(wallpaper, data, len);
wallpaper_lock = 0;
return 1;
}