diff --git a/src/include/gif_load/gif_load.h b/src/include/gif_load/gif_load.h new file mode 100644 index 0000000..12cc402 --- /dev/null +++ b/src/include/gif_load/gif_load.h @@ -0,0 +1,299 @@ +#ifndef GIF_LOAD_H +#define GIF_LOAD_H + +/** gif_load: A slim, fast and header-only GIF loader written in C. + Original author: hidefromkgb (hidefromkgb@gmail.com) + _________________________________________________________________________ + + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + _________________________________________________________________________ +**/ + +#ifdef __cplusplus +extern "C" { +#endif +#include /** imports uint8_t, uint16_t and uint32_t **/ +#ifndef GIF_MGET + #include + #define GIF_MGET(m,s,a,c) m = (uint8_t*)realloc((c)? 0 : m, (c)? s : 0UL); +#endif +#ifndef GIF_BIGE + #define GIF_BIGE 0 +#endif +#ifndef GIF_EXTR + #define GIF_EXTR static +#endif +#define _GIF_SWAP(h) ((GIF_BIGE)? ((uint16_t)(h << 8) | (h >> 8)) : h) + +#pragma pack(push, 1) +struct GIF_WHDR { /** ======== frame writer info: ======== **/ + long xdim, ydim, clrs, /** global dimensions, palette size **/ + bkgd, tran, /** background index, transparent index **/ + intr, mode, /** interlace flag, frame blending mode **/ + frxd, fryd, frxo, fryo, /** current frame dimensions and offset **/ + time, ifrm, nfrm; /** delay, frame number, frame count **/ + uint8_t *bptr; /** frame pixel indices or metadata **/ + struct { /** [==== GIF RGB palette element: ====] **/ + uint8_t R, G, B; /** [color values - red, green, blue ] **/ + } *cpal; /** current palette **/ +}; +#pragma pack(pop) + +enum {GIF_NONE = 0, GIF_CURR = 1, GIF_BKGD = 2, GIF_PREV = 3}; + +/** [ internal function, do not use ] **/ +static long _GIF_SkipChunk(uint8_t **buff, long size) { + long skip; + + for (skip = 2, ++size, ++(*buff); ((size -= skip) > 0) && (skip > 1); + *buff += (skip = 1 + **buff)); + return size; +} + +/** [ internal function, do not use ] **/ +static long _GIF_LoadHeader(unsigned gflg, uint8_t **buff, void **rpal, + unsigned fflg, long *size, long flen) { + if (flen && (!(*buff += flen) || ((*size -= flen) <= 0))) + return -2; /** v--[ 0x80: "palette is present" flag ]--, **/ + if (flen && (fflg & 0x80)) { /** local palette has priority | **/ + *rpal = *buff; /** [ 3L: 3 uint8_t color channels ]--, | **/ + *buff += (flen = 2 << (fflg & 7)) * 3L; /** <--| | **/ + return ((*size -= flen * 3L) > 0)? flen : -1; /** <--' | **/ + } /** no local palette found, checking for the global one | **/ + return (gflg & 0x80)? (2 << (gflg & 7)) : 0; /** <-----' **/ +} + +/** [ internal function, do not use ] **/ +static long _GIF_LoadFrame(uint8_t **buff, long *size, + uint8_t *bptr, uint8_t *blen) { + typedef uint16_t GIF_H; + const long GIF_HLEN = sizeof(GIF_H), /** to rid the scope of sizeof **/ + GIF_CLEN = 1 << 12; /** code table length: 4096 items **/ + GIF_H accu, mask; /** bit accumulator / bit mask **/ + long ctbl, iter, /** last code table index / index string iterator **/ + prev, curr, /** codes from the stream: previous / current **/ + ctsz, ccsz, /** code table bit sizes: min LZW / current **/ + bseq, bszc; /** counters: block sequence / bit size **/ + uint32_t *code = (uint32_t*)bptr - GIF_CLEN; /** code table pointer **/ + + /** preparing initial values **/ + if ((--(*size) <= GIF_HLEN) || !*++(*buff)) + return -4; /** unexpected end of the stream: insufficient size **/ + mask = (GIF_H)((1 << (ccsz = (ctsz = *(*buff - 1)) + 1)) - 1); + if ((ctsz < 2) || (ctsz > 8)) + return -3; /** min LZW size is out of its nominal [2; 8] bounds **/ + if ((ctbl = (1L << ctsz)) != (mask & _GIF_SWAP(*(GIF_H*)(*buff + 1)))) + return -2; /** initial code is not equal to min LZW size **/ + for (curr = ++ctbl; curr; code[--curr] = 0); /** actual color codes **/ + + /** getting codes from stream (--size makes up for end-of-stream mark) **/ + for (--(*size), bszc = -ccsz, prev = curr = 0; + ((*size -= (bseq = *(*buff)++) + 1) >= 0) && bseq; *buff += bseq) + for (; bseq > 0; bseq -= GIF_HLEN, *buff += GIF_HLEN) + for (accu = (GIF_H)(_GIF_SWAP(*(GIF_H*)*buff) + & ((bseq < GIF_HLEN)? ((1U << (8 * bseq)) - 1U) : ~0U)), + curr |= accu << (ccsz + bszc), accu = (GIF_H)(accu >> -bszc), + bszc += 8 * ((bseq < GIF_HLEN)? bseq : GIF_HLEN); + bszc >= 0; bszc -= ccsz, prev = curr, curr = accu, + accu = (GIF_H)(accu >> ccsz)) + if (((curr &= mask) & ~1L) == (1L << ctsz)) { + if (~(ctbl = curr + 1) & 1) /** end-of-data code (ED). **/ + /** -1: no end-of-stream mark after ED; 1: decoded **/ + return (*((*buff += bseq + 1) - 1))? -1 : 1; + mask = (GIF_H)((1 << (ccsz = ctsz + 1)) - 1); + } /** ^- table drop code (TD). TD = 1 << ctsz, ED = TD + 1 **/ + else { /** single-pixel (SP) or multi-pixel (MP) code. **/ + if (ctbl < GIF_CLEN) { /** is the code table full? **/ + if ((ctbl == mask) && (ctbl < GIF_CLEN - 1)) { + mask = (GIF_H)(mask + mask + 1); + ccsz++; /** yes; extending **/ + } /** prev = TD? => curr < ctbl = prev **/ + code[ctbl] = (uint32_t)prev + (code[prev] & 0xFFF000); + } /** appending SP / MP decoded pixels to the frame **/ + prev = (long)code[iter = (ctbl > curr)? curr : prev]; + if ((bptr += (prev = (prev >> 12) & 0xFFF)) > blen) + continue; /** skipping pixels above frame capacity **/ + for (prev++; (iter &= 0xFFF) >> ctsz; + *bptr-- = (uint8_t)((iter = (long)code[iter]) >> 24)); + (bptr += prev)[-prev] = (uint8_t)iter; + if (ctbl < GIF_CLEN) { /** appending the code table **/ + if (ctbl == curr) + *bptr++ = (uint8_t)iter; + else if (ctbl < curr) + return -5; /** wrong code in the stream **/ + code[ctbl++] += ((uint32_t)iter << 24) + 0x1000; + } + } /** 0: no ED before end-of-stream mark; -4: see above **/ + return (++(*size) >= 0)? 0 : -4; /** ^- N.B.: 0 error is recoverable **/ +} + +/** _________________________________________________________________________ + The main loading function. Returns the total number of frames if the data + includes proper GIF ending, and otherwise it returns the number of frames + loaded per current call, multiplied by -1. So, the data may be incomplete + and in this case the function can be called again when more data arrives, + just remember to keep SKIP up to date. + _________________________________________________________________________ + DATA: raw data chunk, may be partial + SIZE: size of the data chunk that`s currently present + GWFR: frame writer function, MANDATORY + EAMF: metadata reader function, set to 0 if not needed + ANIM: implementation-specific data (e.g. a structure or a pointer to it) + SKIP: number of frames to skip before resuming + **/ +GIF_EXTR long GIF_Load(void *data, long size, + void (*gwfr)(void*, struct GIF_WHDR*), + void (*eamf)(void*, struct GIF_WHDR*), + void *anim, long skip) { + const long GIF_BLEN = (1 << 12) * sizeof(uint32_t); + const uint8_t GIF_EHDM = 0x21, /** extension header mark **/ + GIF_FHDM = 0x2C, /** frame header mark **/ + GIF_EOFM = 0x3B, /** end-of-file mark **/ + GIF_EGCM = 0xF9, /** extension: graphics control mark **/ + GIF_EAMM = 0xFF; /** extension: app metadata mark **/ + #pragma pack(push, 1) + struct GIF_GHDR { /** ========== GLOBAL GIF HEADER: ========== **/ + uint8_t head[6]; /** 'GIF87a' / 'GIF89a' header signature **/ + uint16_t xdim, ydim; /** total image width, total image height **/ + uint8_t flgs; /** FLAGS: + GlobalPlt bit 7 1: global palette exists + 0: local in each frame + ClrRes bit 6-4 bits/channel = ClrRes+1 + [reserved] bit 3 0 + PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits + **/ + uint8_t bkgd, aspr; /** background color index, aspect ratio **/ + } *ghdr = (struct GIF_GHDR*)data; + struct GIF_FHDR { /** ======= GIF FRAME MASTER HEADER: ======= **/ + uint16_t frxo, fryo; /** offset of this frame in a "full" image **/ + uint16_t frxd, fryd; /** frame width, frame height **/ + uint8_t flgs; /** FLAGS: + LocalPlt bit 7 1: local palette exists + 0: global is used + Interlaced bit 6 1: interlaced frame + 0: non-interlaced frame + Sorted bit 5 usually 0 + [reserved] bit 4-3 [undefined] + PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits + **/ + } *fhdr; + struct GIF_EGCH { /** ==== [EXT] GRAPHICS CONTROL HEADER: ==== **/ + uint8_t flgs; /** FLAGS: + [reserved] bit 7-5 [undefined] + BlendMode bit 4-2 000: not set; static GIF + 001: leave result as is + 010: restore background + 011: restore previous + 1--: [undefined] + UserInput bit 1 1: show frame till input + 0: default; ~99% of GIFs + TransColor bit 0 1: got transparent color + 0: frame is fully opaque + **/ + uint16_t time; /** delay in GIF time units; 1 unit = 10 ms **/ + uint8_t tran; /** transparent color index **/ + } *egch = 0; + #pragma pack(pop) + struct GIF_WHDR wtmp, whdr = {0}; + long desc, blen; + uint8_t *buff; + + /** checking if the stream is not empty and has a 'GIF8[79]a' signature, + the data has sufficient size and frameskip value is non-negative **/ + if (!ghdr || (size <= (long)sizeof(*ghdr)) || (*(buff = ghdr->head) != 71) + || (buff[1] != 73) || (buff[2] != 70) || (buff[3] != 56) || (skip < 0) + || ((buff[4] != 55) && (buff[4] != 57)) || (buff[5] != 97) || !gwfr) + return 0; + + buff = (uint8_t*)(ghdr + 1) /** skipping the global header and palette **/ + + _GIF_LoadHeader(ghdr->flgs, 0, 0, 0, 0, 0L) * 3L; + if ((size -= buff - (uint8_t*)ghdr) <= 0) + return 0; + + whdr.xdim = _GIF_SWAP(ghdr->xdim); + whdr.ydim = _GIF_SWAP(ghdr->ydim); + for (whdr.bptr = buff, whdr.bkgd = ghdr->bkgd, blen = --size; + (blen >= 0) && ((desc = *whdr.bptr++) != GIF_EOFM); /** sic: '>= 0' **/ + blen = _GIF_SkipChunk(&whdr.bptr, blen) - 1) /** count all frames **/ + if (desc == GIF_FHDM) { + fhdr = (struct GIF_FHDR*)whdr.bptr; + if (_GIF_LoadHeader(ghdr->flgs, &whdr.bptr, (void**)&whdr.cpal, + fhdr->flgs, &blen, sizeof(*fhdr)) <= 0) + break; + whdr.frxd = _GIF_SWAP(fhdr->frxd); + whdr.fryd = _GIF_SWAP(fhdr->fryd); + whdr.frxo = (whdr.frxd > whdr.frxo)? whdr.frxd : whdr.frxo; + whdr.fryo = (whdr.fryd > whdr.fryo)? whdr.fryd : whdr.fryo; + whdr.ifrm++; + } + blen = whdr.frxo * whdr.fryo * (long)sizeof(*whdr.bptr); + GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 1) + whdr.nfrm = (desc != GIF_EOFM)? -whdr.ifrm : whdr.ifrm; + for (whdr.bptr += GIF_BLEN, whdr.ifrm = -1; blen /** load all frames **/ + && (skip < ((whdr.nfrm < 0)? -whdr.nfrm : whdr.nfrm)) && (size >= 0); + size = (desc != GIF_EOFM)? ((desc != GIF_FHDM) || (skip > whdr.ifrm))? + _GIF_SkipChunk(&buff, size) - 1 : size - 1 : -1) + if ((desc = *buff++) == GIF_FHDM) { /** found a frame **/ + whdr.intr = !!((fhdr = (struct GIF_FHDR*)buff)->flgs & 0x40); + *(void**)&whdr.cpal = (void*)(ghdr + 1); /** interlaced? -^ **/ + whdr.clrs = _GIF_LoadHeader(ghdr->flgs, &buff, (void**)&whdr.cpal, + fhdr->flgs, &size, sizeof(*fhdr)); + if ((skip <= ++whdr.ifrm) && ((whdr.clrs <= 0) + || (_GIF_LoadFrame(&buff, &size, + whdr.bptr, whdr.bptr + blen) < 0))) + size = -(whdr.ifrm--) - 1; /** failed to load the frame **/ + else if (skip <= whdr.ifrm) { + whdr.frxd = _GIF_SWAP(fhdr->frxd); + whdr.fryd = _GIF_SWAP(fhdr->fryd); + whdr.frxo = _GIF_SWAP(fhdr->frxo); + whdr.fryo = _GIF_SWAP(fhdr->fryo); + whdr.time = (egch)? _GIF_SWAP(egch->time) : 0; + whdr.tran = (egch && (egch->flgs & 0x01))? egch->tran : -1; + whdr.time = (egch && (egch->flgs & 0x02))? -whdr.time - 1 + : whdr.time; + whdr.mode = (egch && !(egch->flgs & 0x10))? + (egch->flgs & 0x0C) >> 2 : GIF_NONE; + egch = 0; + wtmp = whdr; + gwfr(anim, &wtmp); /** passing the frame to the caller **/ + } + } + else if (desc == GIF_EHDM) { /** found an extension **/ + if (*buff == GIF_EGCM) /** graphics control ext. **/ + egch = (struct GIF_EGCH*)(buff + 1 + 1); + else if ((*buff == GIF_EAMM) && eamf) { /** app metadata ext. **/ + wtmp = whdr; + wtmp.bptr = buff + 1 + 1; /** just passing the raw chunk **/ + eamf(anim, &wtmp); + } + } + whdr.bptr -= GIF_BLEN; /** for excess pixel codes ----v (here & above) **/ + GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 0) + return (whdr.nfrm < 0)? (skip - whdr.ifrm - 1) : (whdr.ifrm + 1); +} + +#undef _GIF_SWAP +#ifdef __cplusplus +} +#endif +#endif /** GIF_LOAD_H **/ diff --git a/src/lpc_launcher/cef_manager/cef_core.c b/src/lpc_launcher/cef_manager/cef_core.c index 9cd3cfd..5df8f00 100644 --- a/src/lpc_launcher/cef_manager/cef_core.c +++ b/src/lpc_launcher/cef_manager/cef_core.c @@ -93,6 +93,27 @@ void create_browser(const char* espec_url, } } + +/* + + +*/ +void redirect_browser(cef_browser_t* browser, const char* new_url) +{ + cef_frame_t* frame; + cef_string_t url_str = {0}; + + if (!browser || !new_url) return; + + frame = browser->get_main_frame(browser); + if (!frame) return; + + + cef_string_utf8_to_utf16(new_url, strlen(new_url), &url_str); + frame->load_url(frame, &url_str); + cef_string_clear(&url_str); // libera memória +} + int cef_setup_pre_display(void* platformConnection, int argc, char** argv, cef_app_t* app) { cef_main_args_t main_args = {0}; diff --git a/src/lpc_launcher/cef_manager/cef_core.h b/src/lpc_launcher/cef_manager/cef_core.h index 8800579..7808ca5 100644 --- a/src/lpc_launcher/cef_manager/cef_core.h +++ b/src/lpc_launcher/cef_manager/cef_core.h @@ -15,6 +15,13 @@ typedef struct cef_life_span_handler_t handler; } MyLifeSpanHandler; +typedef struct +{ + cef_browser_t* browser; + cef_client_t client; + // outros campos +} BrowserContext; + void CEF_CALLBACK on_after_created(struct _cef_life_span_handler_t* self, struct _cef_browser_t* browser); @@ -30,6 +37,8 @@ void create_browser(const char* espec_url, int width, int height); +void redirect_browser(cef_browser_t* browser, const char* new_url); + int cef_setup_pre_display(void* platformConnection, int argc, char** argv, cef_app_t* app); int cef_setup_post_display(void* platformConnection, int argc, char** argv, cef_app_t* app); diff --git a/src/lpc_launcher/display_manager/display_manager.h b/src/lpc_launcher/display_manager/display_manager.h index f2f4423..897b57d 100644 --- a/src/lpc_launcher/display_manager/display_manager.h +++ b/src/lpc_launcher/display_manager/display_manager.h @@ -52,6 +52,8 @@ void setWindowSize(LE_Display *display, int width, int height); void getWindowSize(LE_Display *display, int *width, int *height); +void setWindowCentered(LE_Display *display); + void engineSetWindowTitle(LE_Display *display, const char* format, ...); void engineSetWindowIcon(LE_Display *display, const char* iconPath); @@ -61,5 +63,32 @@ void windowBorderless(LE_Display *display, int mode, ...); + +// tests drag region + +typedef struct +{ + int x, y, width, height; + int enabled; + int hover; +} DragRegion; + +DragRegion* createDragRegion(int x, int y, int width, int height); + +void updateDragRegion(DragRegion* region, int x, int y, int width, int height); + +void deleteDragRegion(DragRegion* region); + +int isInsideRegion(const DragRegion* r, int x, int y); + +void checkDragRegion(LE_Display* udisplay, DragRegion* region); + + + + + + + + #endif /*_WINDOW_MANAGER_H_ */ diff --git a/src/lpc_launcher/display_manager/display_manager_linux.c b/src/lpc_launcher/display_manager/display_manager_linux.c index 410abb3..c80f443 100644 --- a/src/lpc_launcher/display_manager/display_manager_linux.c +++ b/src/lpc_launcher/display_manager/display_manager_linux.c @@ -3,11 +3,16 @@ 2025 - OGBattlegrouds */ -#include -#include + #include #include #include +#include + +#include +#include +#include +#include #include"display_manager.h" @@ -276,6 +281,31 @@ void getWindowSize(LE_Display *window, int *width, int *height) } } +void setWindowCentered(LE_Display *display) +{ + Display *dpy = (Display *)display->platformConnection; + Window win = (Window)display->platformHandle; + Screen *screen; + int screenWidth, screenHeight; + int posX, posY; + + if (!dpy || !win) + return; + + screen = DefaultScreenOfDisplay(dpy); + screenWidth = screen->width; + screenHeight = screen->height; + + posX = (screenWidth - display->width) / 2; + posY = (screenHeight - display->height) / 2; + + XMoveWindow(dpy, win, posX, posY); + XFlush(dpy); + + display->windowPosX = posX; + display->windowPosY = posY; +} + void engineSetWindowTitle(LE_Display *window, const char *format, ...) { Display *display; /* Gets the Display from the rendering context */ @@ -308,59 +338,159 @@ void engineSetWindowIcon(LE_Display *window, const char* iconPath) } -void windowBorderless(LE_Display *window, int mode, ...) /* FIXME */ +void windowBorderless(LE_Display *display, int mode, ...) { - Display *display; - Window win = (Window)window->platformHandle; - XSetWindowAttributes attributes; - XWindowChanges changes; - int screen = DefaultScreen(display); - va_list args; - int windowWidth = window->width; - int windowHeight = window->height; + Display *dpy = (Display *)display->platformConnection; + Window win = (Window)display->platformHandle; - display = (Display *)window->platformConnection; + int windowWidth = display->width; + int windowHeight = display->height; + va_list args; va_start(args, mode); - if (mode == 2) - { /* Fullscreen */ - /* Gets the dimensions of the screen */ - Window root = RootWindow(display, screen); - XWindowAttributes root_attrs; - XGetWindowAttributes(display, root, &root_attrs); - - windowWidth = root_attrs.width; - windowHeight = root_attrs.height; - - /* Sets the window to full screen mode */ - attributes.override_redirect = True; - XChangeWindowAttributes(display, win, CWOverrideRedirect, &attributes); - } - else if (mode == 1) - { /* Borderless with specified size */ - windowWidth = va_arg(args, int); + if (mode == 2) + { + Screen *screen = DefaultScreenOfDisplay(dpy); + windowWidth = screen->width; + windowHeight = screen->height; + } + else if (mode == 1) + { + windowWidth = va_arg(args, int); windowHeight = va_arg(args, int); - /* Remove borders and decorations */ - attributes.border_pixel = BlackPixel(display, screen); - XChangeWindowAttributes(display, win, CWBorderPixel, &attributes); - XSetWindowBorderWidth(display, win, 0); - } - else if (mode == 0) - { /* Normal window with borders */ - /* Set border attributes if needed */ - attributes.border_pixel = WhitePixel(display, screen); - XChangeWindowAttributes(display, win, CWBorderPixel, &attributes); - XSetWindowBorderWidth(display, win, 1); } - /* Updates window position and size */ - XMoveResizeWindow(display, win, 0, 0, windowWidth, windowHeight); - - /* Map the window to make sure it is visible */ - XMapWindow(display, win); - XFlush(display); - va_end(args); + + if (mode == 0) + { + // Re-add borders: depends on Window Manager, so it is limited + // You can just try to "uncheck" the remove decorations hint + Atom wm_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); + long hints[5] = {2, 0, 0, 0, 0}; // without flags = with borders + XChangeProperty(dpy, win, wm_hints, wm_hints, 32, PropModeReplace, (unsigned char*)hints, 5); + } + else + { + // Remove the edges + Atom wm_hints = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); + long hints[5] = {2, 0, 0, 0, 0}; // flags = 2, functions = 0 (no decorations) + XChangeProperty(dpy, win, wm_hints, wm_hints, 32, PropModeReplace, (unsigned char*)hints, 5); + } + + XMoveResizeWindow(dpy, win, 0, 0, windowWidth, windowHeight); + XMapRaised(dpy, win); + XFlush(dpy); } +// window drag box + +/* Creates a new drag region */ +DragRegion* createDragRegion(int x, int y, int width, int height) +{ + DragRegion* r = (DragRegion*)malloc(sizeof(DragRegion)); + if(!r) return 0; + + r->x = x; + r->y = y; + r->width = width; + r->height = height; + r->enabled = 1; + r->hover = 0; + + return r; +} + +/* Updates the values of an existing region */ +void updateDragRegion(DragRegion* region, int x, int y, int width, int height) +{ + if(!region) return; + + region->x = x; + region->y = y; + region->width = width; + region->height = height; +} + +/* Release a region */ +void deleteDragRegion(DragRegion* region) +{ + if(!region) return; + region->enabled = 0; + free(region); +} + +/* Check if the mouse is within the region */ +int isInsideRegion(const DragRegion* r, int x, int y) +{ + return r->enabled && + x >= r->x && x < (r->x + r->width) && + y >= r->y && y < (r->y + r->height); +} + +/* Checks region status and initiates window movement if necessary */ +void checkDragRegion(LE_Display* display, DragRegion* region) /* FIXME! extremely broken */ +{ + if (!region || !region->enabled || !display) + return; + + Display* dpy = (Display*)display->platformConnection; + Window win = (Window)display->platformHandle; + + Window root, child; + int rootX, rootY; + int winX, winY; + unsigned int mask; + + if (!XQueryPointer(dpy, win, &root, &child, &rootX, &rootY, &winX, &winY, &mask)) + return; + + // Checks if the mouse is within the defined area + int inside = isInsideRegion(region, winX, winY); + + if (inside) + { + // Sets cursor if not already active + if (!region->hover) + { + Cursor cursor = XCreateFontCursor(dpy, XC_fleur); + XDefineCursor(dpy, win, cursor); + XFreeCursor(dpy, cursor); + region->hover = 1; + } + + // Sends move event if button is pressed + if ((mask & Button1Mask) && region->hover) + { + Atom moveresize = XInternAtom(dpy, "_NET_WM_MOVERESIZE", False); + XEvent ev; + memset(&ev, 0, sizeof(ev)); + ev.xclient.type = ClientMessage; + ev.xclient.message_type = moveresize; + ev.xclient.display = dpy; + ev.xclient.window = win; + ev.xclient.format = 32; + ev.xclient.data.l[0] = rootX; + ev.xclient.data.l[1] = rootY; + ev.xclient.data.l[2] = 8; // _NET_WM_MOVERESIZE_MOVE + ev.xclient.data.l[3] = Button1; + ev.xclient.data.l[4] = 0; + + XUngrabPointer(dpy, CurrentTime); + XSendEvent(dpy, DefaultRootWindow(dpy), False, + SubstructureRedirectMask | SubstructureNotifyMask, &ev); + } + } + else + { + // Remove cursor if it leaves the region + if (region->hover) + { + XUndefineCursor(dpy, win); + region->hover = 0; + } + } + + XFlush(dpy); +} diff --git a/src/lpc_launcher/display_manager/display_manager_nt.c b/src/lpc_launcher/display_manager/display_manager_nt.c index ccef515..85ee55e 100644 --- a/src/lpc_launcher/display_manager/display_manager_nt.c +++ b/src/lpc_launcher/display_manager/display_manager_nt.c @@ -29,7 +29,8 @@ LRESULT CALLBACK LPARAM lParam) { int i; - + + for(i = 0; i < windowCount; i++) { if(windows[i]->platformHandle == hWnd) @@ -53,6 +54,10 @@ LRESULT CALLBACK { } break; + case WM_LBUTTONDOWN: + { + } + break; case WM_PAINT: { @@ -353,6 +358,39 @@ void getWindowSize(LE_Display *display, int *width, int *height) *height = clientRect.bottom - clientRect.top; } +void engineSetWindowPos(HWND hwnd, int x, int y, int width, int height) +{ + SetWindowPos(hwnd, HWND_TOP, x, y, width, height, SWP_SHOWWINDOW | SWP_FRAMECHANGED); +} + +void setWindowCentered(LE_Display *display) +{ + HWND hwnd = (HWND)display->platformHandle; + RECT rect; + int screenWidth, screenHeight; + int windowWidth, windowHeight; + int posX, posY; + + if (!GetWindowRect(hwnd, &rect)) + return; + + windowWidth = rect.right - rect.left; + windowHeight = rect.bottom - rect.top; + + screenWidth = GetSystemMetrics(SM_CXSCREEN); + screenHeight = GetSystemMetrics(SM_CYSCREEN); + + posX = (screenWidth - windowWidth) / 2; + posY = (screenHeight - windowHeight) / 2; + + SetWindowPos(hwnd, HWND_TOP, posX, posY, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + /* Atualiza os campos da struct */ + display->windowPosX = posX; + display->windowPosY = posY; +} + void engineSetWindowTitle(LE_Display *display, const char *format, ...) { char title[256]; @@ -454,3 +492,87 @@ void windowBorderless(LE_Display *display, int mode, ...) va_end(args); } + +// window drag box + +DragRegion* createDragRegion(int x, int y, int width, int height) +{ + DragRegion* r = (DragRegion*)malloc(sizeof(DragRegion)); + if(!r) return 0; + + r->x = x; + r->y = y; + r->width = width; + r->height = height; + r->enabled = 1; + r->hover = 0; + + return r; +} + + +void updateDragRegion(DragRegion* region, int x, int y, int width, int height) +{ + if(!region) return; + + region->x = x; + region->y = y; + region->width = width; + region->height = height; +} + + +void deleteDragRegion(DragRegion* region) +{ + if(!region) return; + region->enabled = 0; + free(region); +} + + + +int isInsideRegion(const DragRegion* r, int x, int y) +{ + return r->enabled && + x >= r->x && x < (r->x + r->width) && + y >= r->y && y < (r->y + r->height); +} + +void checkDragRegion(LE_Display* udisplay, DragRegion* region) +{ + + POINT pt; + int mouseX = 0; + int mouseY = 0; + int mousePressed = 0; + + if (!region || !region->enabled || !udisplay) return; + + GetCursorPos(&pt); + ScreenToClient((HWND)udisplay->platformHandle, &pt); + + mouseX = pt.x; + mouseY = pt.y; + mousePressed = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) ? 1 : 0; + + if(isInsideRegion(region, mouseX, mouseY)) + { + SetCursor(LoadCursor(NULL, IDC_SIZEALL)); /* Muda cursor */ + region->hover = 1; + + if(mousePressed) + { + ReleaseCapture(); + SendMessage((HWND)udisplay->platformHandle, WM_NCLBUTTONDOWN, HTCAPTION, 0); + } + } + else + { + if(region->hover) + { + SetCursor(LoadCursor(NULL, IDC_ARROW)); /* Reset cursor se saiu da região */ + region->hover = 0; + } + } + +} diff --git a/src/lpc_launcher/main.c b/src/lpc_launcher/main.c index 8ce4c10..dd5effa 100644 --- a/src/lpc_launcher/main.c +++ b/src/lpc_launcher/main.c @@ -89,6 +89,8 @@ #include"cef_manager/cef_core.h" +//#include"fukAnimatedGif/fukAnimatedGif.h" + int programLoop = 1; // This is the main loop of the program, if you reset it the program will close @@ -96,8 +98,16 @@ LE_Display *progDisplay; // defined structure of the window handler component int cefInitialized = 0; -int displayWindowWidth = 417; -int displayWindowHeight = 670; + + +int LoginWindowWidth = 400; +int LoginWindowHeight = 630; + +int MainWindowWidth = 1280; +int MainWindowHeight = 760; + + + // X11 error handlers #ifdef __linux__ @@ -114,18 +124,32 @@ int displayWindowHeight = 670; // Handler and client cef_app_t g_app = {0}; -cef_client_t g_client = {0}; +//cef_client_t g_client = {0}; + +BrowserContext g_client; MyLifeSpanHandler g_lifeSpanHandler; + + + + +// 346x30 ou 500x40 + +DragRegion *progDragRegion; + + + void progLoop() { cef_do_message_loop_work(); // process CEF events //usleep(1000); // avoid 100% CPU usage + checkDragRegion(progDisplay, progDragRegion); + } int main(int argc, char** argv) @@ -142,9 +166,12 @@ int main(int argc, char** argv) //http://127.0.0.1/oidc/interaction/login - progDisplay = engineCreateDisplay("MainWindow", - displayWindowWidth, - displayWindowHeight); // create Program Display/Window + progDisplay = engineCreateDisplay("PUBG LITE Launcher", + LoginWindowWidth, + LoginWindowHeight); // create Program Display/Window + + windowBorderless(progDisplay, 1, LoginWindowWidth, LoginWindowHeight); + setWindowCentered(progDisplay); result = cef_setup_post_display(progDisplay->platformConnection, argc, argv, &g_app); if (result != 0) @@ -152,6 +179,7 @@ int main(int argc, char** argv) return result; } + progDragRegion = createDragRegion(0, 0, 346, 30); // X11: configurar handlers de erro @@ -160,12 +188,14 @@ int main(int argc, char** argv) #endif setup_lifespan_handler(&g_lifeSpanHandler); - setup_client(&g_client); + setup_client(&g_client.client); create_browser("http://127.0.0.1/oidc/interaction/login", - &g_client, + &g_client.client, progDisplay->platformHandle, - displayWindowWidth, - displayWindowHeight); + LoginWindowWidth, + LoginWindowHeight); + + //redirect_browser(g_client.browser, "https://google.com"); engineSetLoop(progDisplay, &programLoop, progLoop); @@ -173,5 +203,7 @@ int main(int argc, char** argv) cef_quit_message_loop(); cef_shutdown(); + deleteDragRegion(progDragRegion); + return 0; }