/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2018 Thomas Bernard Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ #include #include #include #include #include #include "screen.h" #include "gfx2surface.h" #include "loadsave.h" Display * X11_display = NULL; static Window X11_window = 0; static XImage * X11_image = NULL; static char * image_pixels = NULL; static XTextProperty windowName; static GC X11_gc = 0; static T_GFX2_Surface * screen = NULL; static T_GFX2_Surface * icon = NULL; void GFX2_Set_mode(int *width, int *height, int fullscreen) { int s; int depth; unsigned long white, black; char * winName[] = { "GrafX2" }; Visual * visual; if (X11_display == NULL) X11_display = XOpenDisplay(NULL);// NULL is equivalent to getenv("DISPLAY") if (X11_display == NULL) { fprintf(stderr, "X11: cannot open display\n"); exit(1); } s = DefaultScreen(X11_display); black = BlackPixel(X11_display, s); white = WhitePixel(X11_display, s); visual = DefaultVisual(X11_display, s); { int i; int count = 0; int * depths = XListDepths(X11_display, s, &count); printf("DefaultDepth = %d, DisplayPlanes = %d\n", DefaultDepth(X11_display, s), DisplayPlanes(X11_display, s)); if (depths != NULL) { for (i = 0; i < count; i++) printf(" %d", depths[i]); printf("\n"); XFree(depths); } } depth = DisplayPlanes(X11_display, s); if (X11_window == 0) { static const char blank_data[1] = { 0 }; Pixmap blank; Cursor cursor; XColor dummy; Atom wmDelete; XWMHints* hints; X11_window = XCreateSimpleWindow(X11_display, RootWindow(X11_display, s), 0, 0, *width, *height, 0, white, black); // create blank 1x1 pixmap to make a 1x1 transparent cursor blank = XCreateBitmapFromData(X11_display, X11_window, blank_data, 1, 1); cursor = XCreatePixmapCursor(X11_display, blank, blank, &dummy, &dummy, 0, 0); //cursor = XCreateFontCursor(X11_display, 130 /*XC_tcross*/); XDefineCursor(X11_display, X11_window, cursor); XFreePixmap(X11_display, blank); XFreeCursor(X11_display, cursor); X11_gc = XCreateGC(X11_display, X11_window, 0, NULL); //XSetFunction(X11_display, X11_gc, GXcopy); XStringListToTextProperty(winName, 1, &windowName); XSetWMName(X11_display, X11_window, &windowName); // set icon if (icon != NULL) { XImage * icon_image = XCreateImage(X11_display, visual, depth, ZPixmap, 0, malloc(icon->w * icon->h * 4), icon->w, icon->h, 32, 0/**width * 4*/); if (icon_image != NULL) { char * transp_data; int x, y; Pixmap icon_mask; Pixmap icon_pixmap = XCreatePixmap(X11_display, X11_window, icon->w, icon->h, 24); transp_data = calloc(1, ((icon->w + 7) >> 3) * icon->h); for (y = 0; y < icon->h; y++) { for (x = 0; x < icon->w; x++) { byte v = icon->pixels[x + y * icon->w]; if (v != 0) // assume 0 is transparent transp_data[(x >> 3) + ((icon->w + 7) >> 3) * y] |= (1 << (x & 7)); XPutPixel(icon_image, x, y, (unsigned)icon->palette[v].R << 16 | (unsigned)icon->palette[v].G << 8 | (unsigned)icon->palette[v].B); } } // Transfer icon_image to the icon_pixmap XPutImage(X11_display, icon_pixmap, X11_gc, icon_image, 0, 0, 0, 0, icon->w, icon->h); icon_mask = XCreateBitmapFromData(X11_display, X11_window, transp_data, icon->w, icon->h); hints = XAllocWMHints(); if (hints != NULL) { hints->flags = IconPixmapHint | IconMaskHint; hints->icon_pixmap = icon_pixmap; hints->icon_mask = icon_mask; XSetWMHints(X11_display, X11_window, hints); XFree(hints); } free(transp_data); } XDestroyImage(icon_image); } XSelectInput(X11_display, X11_window, PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | ExposureMask | StructureNotifyMask); wmDelete = XInternAtom(X11_display, "WM_DELETE_WINDOW", True); XSetWMProtocols(X11_display, X11_window, &wmDelete, 1); XMapWindow(X11_display, X11_window); } if (screen == NULL) { screen = New_GFX2_Surface(*width, *height); memset(screen->pixels, 0, *width * *height); } else if (*width > screen->w || *height > screen->h) { screen->pixels = realloc(screen->pixels, *width * *height); screen->w = *width; screen->h = *height; XDestroyImage(X11_image); X11_image = NULL; image_pixels = NULL; } if (image_pixels == NULL) { image_pixels = malloc(*height * *width * 4); memset(image_pixels, 64, *height * *width * 4); } if (X11_image == NULL) { X11_image = XCreateImage(X11_display, visual, depth, ZPixmap, 0, image_pixels, *width, *height, 32, 0/**width * 4*/); if(X11_image == NULL) { fprintf(stderr, "XCreateImage failed\n"); exit(1); } } XFlush(X11_display); } byte Get_Screen_pixel(int x, int y) { if(screen == NULL) return 0; return screen->pixels[x + y * screen->w]; } void Set_Screen_pixel(int x, int y, byte value) { if(screen == NULL) return; screen->pixels[x + y * screen->w] = value; } byte* Get_Screen_pixel_ptr(int x, int y) { if(screen == NULL) return NULL; return screen->pixels + x + y * screen->w; } void Screen_FillRect(int x, int y, int w, int h, byte color) { int i; byte * ptr; if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } if (x > screen->w || y > screen->h) return; if ((x + w) > screen->w) w = screen->w - x; if ((y + h) > screen->h) h = screen->h - y; if (w <= 0 || h <= 0) return; for (i = 0; i < h; i++) { ptr = Get_Screen_pixel_ptr(x, y + i); memset(ptr, color, w); } } int SetPalette(const T_Components * colors, int firstcolor, int ncolors) { if (screen == NULL) return 0; memcpy(screen->palette + firstcolor, colors, ncolors * sizeof(T_Components)); return 1; } void Update_rect(short x, short y, unsigned short width, unsigned short height) { int line, i; if (screen == NULL || X11_image == NULL) return; x *= Pixel_width; width *= Pixel_width; y *= Pixel_height; height *= Pixel_height; //printf("Update_rect(%d %d %d %d) %d %d\n", x, y, width, height, screen->w, screen->h); if (y >= screen->h || x >= screen->w) return; if (y + height > screen->h) height = screen->h - y; if (x + width > screen->w) width = screen->w - x; for (line = y; line < y + height; line++) { #if 0 const byte * src = Get_Screen_pixel_ptr(x, line); byte * dest = image_pixels + line * X11_image->bytes_per_line + x * 4, i = width; do { dest[0] = screen->palette[*src].B; dest[1] = screen->palette[*src].G; dest[2] = screen->palette[*src].R; dest[3] = 0; src++; dest += 4; } while(--i > 0); #else for (i = 0; i < width; i++) { byte v = Get_Screen_pixel(x + i, line); XPutPixel(X11_image, x + i, line, (unsigned)screen->palette[v].R << 16 | (unsigned)screen->palette[v].G << 8 | (unsigned)screen->palette[v].B); } #endif } XPutImage(X11_display, X11_window, X11_gc, X11_image, x, y, x, y, width, height); //XPutImage(X11_display, X11_window, X11_gc, X11_image, // 0, 0, 0, 0, X11_image->width, X11_image->height); //XSync(X11_display, False); } void Flush_update(void) { if (X11_display != NULL) XFlush(X11_display); } void Update_status_line(short char_pos, short width) { Update_rect((18+char_pos*8)*Menu_factor_X*Pixel_width, Menu_status_Y*Pixel_height, width*8*Menu_factor_X*Pixel_width, 8*Menu_factor_Y*Pixel_height); } void Clear_border(byte color) { (void)color;//TODO } volatile int Allow_colorcycling = 0; /// Activates or desactivates file drag-dropping in program window. void Allow_drag_and_drop(int flag) { (void)flag; } void Define_icon(void) { char icon_path[MAX_PATH_CHARACTERS]; snprintf(icon_path, sizeof(icon_path), "%s%s", Data_directory, "gfx2.png"); // 48x48 icon = Load_surface(icon_path, NULL); }