/* pmshell.c * PMShell graphics driver * (c) 2002 Mikulas Patocka * This file is a part of the Links program, released under GPL. */ #include "cfg.h" #if 0 #define debug_call(x) printf x; fflush(stdout); #else #define debug_call(x) #endif #ifdef GRDRV_PMSHELL #include "links.h" extern struct graphics_driver pmshell_driver; #define INCL_DOS #define INCL_GPI #define INCL_WIN #include #include #include #include _fmutex pm_mutex; #define pm_lock_init _fmutex_create(&pm_mutex, 0) #define pm_lock _fmutex_request(&pm_mutex, _FMR_IGNINT) #define pm_unlock _fmutex_release(&pm_mutex) unsigned char *pm_class_name = "links"; unsigned char *pm_msg_class_name = "links.msg"; ULONG pm_frame = (FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER | FCF_MINMAX | FCF_SHELLPOSITION | FCF_TASKLIST); ULONG pm_msg_frame = 0; #define E_KEY 1 #define E_MOUSE 2 #define E_REDRAW 3 #define E_RESIZE 4 struct pm_event { struct pm_event *next; struct pm_event *prev; int type; int x1, y1, x2, y2; }; struct pm_window { struct pm_window *next; struct pm_window *prev; int x, y; int in; struct pm_window *nxt; struct pm_window **prv; HPS ps; HWND h; HWND hc; struct graphics_device *dev; int button; unsigned lastpos; struct list_head queue; }; #define WIN_HASH 64 struct pm_window *pm_windows[WIN_HASH]; void pm_hash_window(struct pm_window *win) { int pos = win->hc & (WIN_HASH - 1); win->prv = &pm_windows[pos]; if ((win->nxt = pm_windows[pos])) pm_windows[pos]->prv = &win->nxt; pm_windows[pos] = win; } void pm_unhash_window(struct pm_window *win) { if (win->nxt) win->nxt->prv = win->prv; *win->prv = win->nxt; } static inline struct pm_window *pm_lookup_window(HWND h) { struct pm_window *win; for (win = pm_windows[h & (WIN_HASH - 1)]; win && win->hc != h; win = win->nxt) ; return win; } #define pm_win(dev) ((struct pm_window *)dev->driver_data) int pm_pipe[2]; HEV pm_sem; ULONG pm_sem_dummy; #define pm_wait do { \ DosWaitEventSem(pm_sem, SEM_INDEFINITE_WAIT); \ DosResetEventSem(pm_sem, &pm_sem_dummy); \ } while (0) #define pm_signal DosPostEventSem(pm_sem) unsigned char *pm_not_ses = "Not in a pmshell session.\n"; unsigned char *pm_status; HAB hab_disp; HAB hab; HMQ hmq; HWND hwnd_msg; HPS hps_msg; HDC hdc_mem; HPS hps_mem; int pm_cp; struct list_head pm_event_windows = { &pm_event_windows, &pm_event_windows }; void pm_send_event(struct pm_window *win, int t, int x1, int y1, int x2, int y2) { /* must be called with pm_lock */ struct pm_event *ev; if ((ev = malloc(sizeof(struct pm_event)))) { ev->type = t; ev->x1 = x1, ev->y1 = y1; ev->x2 = x2, ev->y2 = y2; if (!win->in) { if (list_empty(pm_event_windows)) write(pm_pipe[1], "x", 1); add_to_list(pm_event_windows, win); win->in = 1; } add_to_list(win->queue, ev); } } void pm_send_mouse_event(struct pm_window *win, int x1, int y1, int b) { if (!list_empty(win->queue)) { struct pm_event *last = win->queue.next; if (last->type == E_MOUSE && last->x2 == b) { last->x1 = x1; last->y1 = y1; return; } } pm_send_event(win, E_MOUSE, x1, y1, b, 0); } void pm_cancel_event(struct pm_window *win, int t, struct pm_event **pev) { struct pm_event *ev; if (pev) *pev = NULL; foreachback(ev, win->queue) if (ev->type == t) { if (pev) *pev = ev; else { del_from_list(ev); free(ev); } return; } } void pm_resize(struct pm_window *win, RECTL *r) { struct pm_event *ev; win->x = r->xRight; win->y = r->yTop; pm_cancel_event(win, E_REDRAW, NULL); pm_cancel_event(win, E_RESIZE, &ev); if (ev) { ev->x2 = r->xRight; ev->y2 = r->yTop; } else pm_send_event(win, E_RESIZE, 0, 0, r->xRight, r->yTop); } void pm_redraw(struct pm_window *win, RECTL *r) { struct pm_event *ev; pm_cancel_event(win, E_RESIZE, &ev); if (ev) return; pm_cancel_event(win, E_REDRAW, &ev); if (ev) { if (r->xLeft < ev->x1) ev->x1 = r->xLeft; if (r->xRight > ev->x2) ev->x2 = r->xRight; if (win->y - r->yTop < ev->y1) ev->y1 = win->y - r->yTop; if (win->y - r->yBottom > ev->y2) ev->y2 = win->y - r->yBottom; return; } pm_send_event(win, E_REDRAW, r->xLeft, win->y - r->yTop, r->xRight, win->y - r->yBottom); } #define N_VK 0x42 struct os2_key pm_vk_table[N_VK] = { 0, 0, 0, 0, 0, 0, 0, 0, KBD_CTRL_C, 0, KBD_BS, 0, KBD_TAB, 0, KBD_TAB, KBD_SHIFT, KBD_ENTER, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KBD_ESC, 0, ' ', 0, KBD_PAGE_UP, 0, KBD_PAGE_DOWN, 0, KBD_END, 0, KBD_HOME, 0, KBD_LEFT, 0, KBD_UP, 0, KBD_RIGHT, 0, KBD_DOWN, 0, 0, 0, KBD_INS, 0, KBD_DEL, 0, 0, 0, 0, 0, KBD_ENTER, 0, 0, 0, KBD_F1, 0, KBD_F2, 0, KBD_F3, 0, KBD_F4, 0, KBD_F5, 0, KBD_F6, 0, KBD_F7, 0, KBD_F8, 0, KBD_F9, 0, KBD_F10, 0, KBD_F11, 0, KBD_F12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KBD_DEL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; MRESULT EXPENTRY pm_window_proc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { int k_usch, k_usvk, k_fsflags; int key, flags; struct pm_window *win; RECTL wr, ur; /*fprintf(stderr, "%08x %08x %08x\n", (int)msg, (int)mp1, (int)mp2);*/ switch (msg) { case WM_PAINT: pm_lock; WinQueryUpdateRect(hwnd, &ur); WinQueryWindowRect(hwnd, &wr); WinValidateRect(hwnd, &ur, FALSE); if (!(win = pm_lookup_window(hwnd))) { pm_unlock; return 0; } if (wr.xRight != win->x || wr.yTop != win->y) pm_resize(win, &wr); else pm_redraw(win, &ur); pm_unlock; return 0; case WM_CLOSE: case WM_QUIT: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; return 0; } pm_send_event(win, E_KEY, KBD_CTRL_C, 0, 0, 0); pm_unlock; return 0; case WM_CHAR: k_fsflags = (int)mp1; if (k_fsflags & (KC_KEYUP | KC_DEADKEY | KC_INVALIDCOMP)) return 0; k_usch = (int)mp2 & 0xffff; k_usvk = ((int)mp2 >> 16) & 0xffff; /*printf("%08x, %08x\n", mp1, mp2);fflush(stdout);*/ flags = (k_fsflags & KC_SHIFT ? KBD_SHIFT : 0) | (k_fsflags & KC_CTRL ? KBD_CTRL : 0) | (k_fsflags & KC_ALT ? KBD_ALT : 0); if (k_fsflags & KC_VIRTUALKEY) { if (k_usvk < N_VK && (key = pm_vk_table[k_usvk].x)) { flags |= pm_vk_table[k_usvk].y; if (key == KBD_CTRL_C) flags &= ~KBD_CTRL; goto s; } } if (k_usch & 0xff) { key = k_usch & 0xff; if (!(flags & KBD_CTRL)) { if (key == 0x0d) key = KBD_ENTER; if (key == 0x08) key = KBD_BS; if (key == 0x09) key = KBD_TAB; if (key == 0x1b) key = KBD_ESC; } if (key < ' ') key += '@', flags |= KBD_CTRL; } else key = os2xtd[k_usch >> 8].x, flags |= os2xtd[k_usch >> 8].y; if ((key & 0xdf) == 'C' && (flags & KBD_CTRL)) key = KBD_CTRL_C, flags &= ~KBD_CTRL; s: if (!key) return 0; if (key >= 0) flags &= ~KBD_SHIFT; if (key >= 0x80 && pm_cp) { if ((key = cp2u(key, pm_cp)) < 0) return 0; } pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; return 0; } pm_send_event(win, E_KEY, key, flags, 0, 0); pm_unlock; return 0; case WM_BUTTON1DOWN: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } win->button |= 1 << B_LEFT; win->lastpos = (unsigned)mp1; pm_send_event(win, E_MOUSE, (unsigned)mp1 & 0xffff, win->y - ((unsigned)mp1 >> 16), B_DOWN | B_LEFT, 0); pm_unlock; break; case WM_BUTTON2DOWN: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } win->button |= 1 << B_RIGHT; win->lastpos = (unsigned)mp1; pm_send_event(win, E_MOUSE, (unsigned)mp1 & 0xffff, win->y - ((unsigned)mp1 >> 16), B_DOWN | B_RIGHT, 0); pm_unlock; break; case WM_BUTTON3DOWN: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } win->button |= 1 << B_MIDDLE; win->lastpos = (unsigned)mp1; pm_send_event(win, E_MOUSE, (unsigned)mp1 & 0xffff, win->y - ((unsigned)mp1 >> 16), B_DOWN | B_MIDDLE, 0); pm_unlock; break; case WM_BUTTON1UP: case WM_BUTTON1MOTIONEND: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } if (win->button & (1 << B_LEFT)) pm_send_event(win, E_MOUSE, (unsigned)mp1 & 0xffff, win->y - ((unsigned)mp1 >> 16), B_UP | B_LEFT, 0); win->button &= ~(1 << B_LEFT); win->lastpos = (unsigned)mp1; pm_unlock; break; case WM_BUTTON2UP: case WM_BUTTON2MOTIONEND: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } if (win->button & (1 << B_RIGHT)) pm_send_event(win, E_MOUSE, (unsigned)mp1 & 0xffff, win->y - ((unsigned)mp1 >> 16), B_UP | B_RIGHT, 0); win->button &= ~(1 << B_RIGHT); win->lastpos = (unsigned)mp1; pm_unlock; break; case WM_BUTTON3UP: case WM_BUTTON3MOTIONEND: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } if (win->button & (1 << B_MIDDLE)) pm_send_event(win, E_MOUSE, (unsigned)mp1 & 0xffff, win->y - ((unsigned)mp1 >> 16), B_UP | B_MIDDLE, 0); win->button &= ~(1 << B_MIDDLE); win->lastpos = (unsigned)mp1; pm_unlock; break; case WM_MOUSEMOVE: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } win->lastpos = (unsigned)mp1; pm_send_mouse_event(win, (unsigned)mp1 & 0xffff, win->y - ((unsigned)mp1 >> 16), (win->button ? B_DRAG : B_MOVE) | (win->button & (1 << B_LEFT) ? B_LEFT : win->button & (1 << B_MIDDLE) ? B_MIDDLE : win->button & (1 << B_RIGHT) ? B_RIGHT : 0)); pm_unlock; break; case WM_VSCROLL: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } if ((unsigned)mp2 == SB_LINEUP << 16 || (unsigned)mp2 == SB_LINEDOWN << 16) pm_send_event(win, E_MOUSE, win->lastpos & 0xffff, win->y - (win->lastpos >> 16), ((unsigned)mp2 == SB_LINEUP << 16 ? B_WHEELUP1 : B_WHEELDOWN1) | B_MOVE, 0); pm_unlock; break; case WM_HSCROLL: pm_lock; if (!(win = pm_lookup_window(hwnd))) { pm_unlock; break; } if ((unsigned)mp2 == SB_LINELEFT << 16 || (unsigned)mp2 == SB_LINERIGHT << 16) pm_send_event(win, E_MOUSE, win->lastpos & 0xffff, win->y - (win->lastpos >> 16), ((unsigned)mp2 == SB_LINELEFT << 16 ? B_WHEELLEFT1 : B_WHEELRIGHT1) | B_MOVE, 0); pm_unlock; break; } return WinDefWindowProc(hwnd, msg, mp1, mp2); } int pm_thread_shutdown; #define MSG_CREATE_WINDOW 1 #define MSG_DELETE_WINDOW 2 #define MSG_SET_WINDOW_TITLE 3 #define MSG_SHUTDOWN_THREAD 4 struct title_set { struct pm_window *win; unsigned char *text; }; MRESULT EXPENTRY pm_msg_proc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { struct title_set *w; if (msg == WM_USER) switch ((int)mp1) { struct pm_window *win; case MSG_CREATE_WINDOW: win = mp2; win->h = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &pm_frame, pm_class_name, "Links", 0, 0, 0, &win->hc); WinSetWindowPos(win->h, 0, 0, 0, 0, 0, SWP_ACTIVATE); pm_lock; pm_signal; return 0; case MSG_DELETE_WINDOW: win = mp2; WinDestroyWindow(win->h); pm_lock; pm_signal; return 0; case MSG_SET_WINDOW_TITLE: w = mp2; WinSetWindowText(w->win->h, w->text); pm_lock; pm_signal; return 0; case MSG_SHUTDOWN_THREAD: pm_thread_shutdown = 1; return 0; } return WinDefWindowProc(hwnd, msg, mp1, mp2); } void pm_send_msg(int msg, void *param) { WinPostMsg(hwnd_msg, WM_USER, (MPARAM)msg, (MPARAM)param); pm_wait; } void pm_dispatcher(void *p) { QMSG msg; pm_status = NULL; /*DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 1, 0);*/ DosSetPriority(PRTYS_THREAD, PRTYC_NOCHANGE, 1, 0); if ((hab_disp = WinInitialize(0)) == NULLHANDLE) { pm_status = "WinInitialize failed in pm thread.\n"; goto fail; } if ((hmq = WinCreateMsgQueue(hab_disp, 0)) == NULLHANDLE) { ERRORID e = WinGetLastError(hab_disp); if ((e & 0xffff) == PMERR_NOT_IN_A_PM_SESSION) pm_status = pm_not_ses; else pm_status = "WinCreateMsgQueue failed in pm thread.\n"; goto fail1; } if ((pm_cp = WinQueryCp(hmq))) { unsigned char a[64]; snprint(a, 64, pm_cp); if ((pm_cp = get_cp_index(a)) < 0 || is_cp_special(pm_cp)) pm_cp = 0; } /*{ ULONG cp_list[100]; int n, i; debug("WinQueryCp: %d", WinQueryCp(hmq)); n = WinQueryCpList(hab_disp, 100, cp_list); debug("%d", n); for (i = 0; i < n; i++) fprintf(stderr, "%d, ", cp_list[i]); }*/ if (WinRegisterClass(hab_disp, pm_class_name, pm_window_proc, CS_SIZEREDRAW, 0) == FALSE) { pm_status = "WinRegisterClass failed for window.\n"; goto fail2; } if (WinRegisterClass(hab_disp, pm_msg_class_name, pm_msg_proc, 0, 0) == FALSE) { pm_status = "WinRegisterClass failed for msg window.\n"; goto fail3; } if ((hwnd_msg = WinCreateStdWindow(HWND_DESKTOP, 0, &pm_msg_frame, pm_msg_class_name, NULL, 0, 0, 0, NULL)) == NULLHANDLE) { pm_status = "Could not create msg window.\n"; goto fail4; } if ((hps_msg = WinGetPS(hwnd_msg)) == NULLHANDLE) { pm_status = "Could not get msg window ps.\n"; goto fail5; } pm_signal; while (!pm_thread_shutdown) { WinGetMsg(hab_disp, &msg, 0L, 0, 0); WinDispatchMsg(hab_disp, &msg); } WinReleasePS(hps_msg); fail5: WinDestroyWindow(hwnd_msg); fail4: fail3: fail2: WinDestroyMsgQueue(hmq); fail1: WinTerminate(hab); fail: pm_signal; return; } void pm_pipe_error(void *p) { error("exception on pm pipe"); set_handlers(pm_pipe[0], NULL, NULL, NULL, NULL); } void pm_handler(void *p) { unsigned char c; struct pm_window *win = NULL; struct pm_event *ev = NULL; pm_lock; if (!list_empty(pm_event_windows)) { win = pm_event_windows.prev; if (!list_empty(win->queue)) { ev = win->queue.prev; del_from_list(ev); } if (list_empty(win->queue)) { del_from_list(win); win->in = 0; } } if (list_empty(pm_event_windows)) { if (read(pm_pipe[0], &c, 1) != 1) pm_pipe_error(NULL); } pm_unlock; if (!ev) return; switch (ev->type) { struct rect r; case E_KEY: if (win->dev->keyboard_handler) win->dev->keyboard_handler(win->dev, ev->x1, ev->y1); break; case E_MOUSE: if (win->dev->mouse_handler) win->dev->mouse_handler(win->dev, ev->x1, ev->y1, ev->x2); break; case E_REDRAW: if (win->dev->redraw_handler) { r.x1 = ev->x1; r.y1 = ev->y1; r.x2 = ev->x2; r.y2 = ev->y2; win->dev->redraw_handler(win->dev, &r); } break; case E_RESIZE: win->dev->size.x2 = ev->x2; win->dev->size.y2 = ev->y2; if (win->dev->resize_handler) { win->dev->resize_handler(win->dev); } } free(ev); } BITMAPINFO *pm_bitmapinfo; int pm_bitmap_count; int pm_child_pid; void pm_sigcld(void *p) { int st; int w; if (!(w = waitpid(pm_child_pid, &st, WNOHANG))) return; if (w > 0) exit(st); else exit(1); } int pm_sin, pm_sout, pm_serr, pm_ip[2], pm_op[2], pm_ep[2]; int pm_cons_ok = 0; void pm_setup_console() { if (pm_cons_ok) goto fail9; if ((pm_sin = dup(0)) < 0) goto fail; if ((pm_sout = dup(1)) < 0) goto fail1; if ((pm_serr = dup(2)) < 0) goto fail2; if (c_pipe(pm_ip)) goto fail3; if (c_pipe(pm_op)) goto fail4; if (c_pipe(pm_ep)) goto fail5; if (dup2(pm_ip[0], 0) != 0) goto fail6; if (dup2(pm_op[1], 1) != 1) goto fail7; if (dup2(pm_ep[1], 2) != 2) goto fail8; close(pm_ip[0]); close(pm_op[1]); close(pm_ep[1]); pm_cons_ok = 1; return; fail9: dup2(pm_serr, 2); fail8: dup2(pm_sout, 1); fail7: dup2(pm_sin, 0); fail6: close(pm_ep[0]); close(pm_ep[1]); fail5: close(pm_op[0]); close(pm_op[1]); fail4: close(pm_ip[0]); close(pm_ip[1]); fail3: close(pm_serr); fail2: close(pm_sout); fail1: close(pm_sin); fail: pm_cons_ok = 0; } void pm_do_console() { #define CONS_BUF 20 unsigned char buffer[CONS_BUF]; fd_set s; int m = pm_op[0] > pm_ep[0] ? pm_op[0] : pm_ep[0]; if (pm_sin > m) m = pm_sin; m++; if (!pm_cons_ok) return; while (1) { int r, w; FD_ZERO(&s); /*FD_SET(pm_sin, &s);*/ FD_SET(pm_op[0], &s); FD_SET(pm_ep[0], &s); if (select(m, &s, NULL, NULL, NULL) <= 0) goto br; #define SEL_CHK(ih, oh) \ if (FD_ISSET(ih, &s)) { \ if ((r = read(ih, buffer, CONS_BUF)) <= 0) goto br; \ do { \ if ((w = write(oh, buffer, r)) <= 0) goto br; \ r -= w; \ } while (r > 0); \ } /*SEL_CHK(pm_sin, pm_ip[1]);*/ SEL_CHK(pm_op[0], pm_sout); SEL_CHK(pm_ep[0], pm_serr); } br:; } unsigned char *pm_get_driver_param(void) { return NULL; } unsigned char *pm_init_driver(unsigned char *param, unsigned char *display) { unsigned char *s; pm_bitmap_count = 0; if ((hab = WinInitialize(0)) == 0) { s = "WinInitialize failed.\n"; goto r1; } if (DosCreateEventSem(NULL, &pm_sem, 0, 0)) { s = "Could not create event semaphore.\n"; goto r2; } if (c_pipe(pm_pipe)) { s = "Could not create pipe.\n"; goto r3; } fcntl(pm_pipe[1], F_SETFL, O_NONBLOCK); memset(pm_windows, 0, sizeof(struct pm_window *) * WIN_HASH); pm_lock_init; pm_thread_shutdown = 0; if (_beginthread(pm_dispatcher, NULL, 65536, NULL) == -1) { s = "Could not start thread.\n"; goto r4; } pm_wait; if (pm_status) { int pid; char **arg; if (pm_status != pm_not_ses) goto f; if (!(arg = mem_alloc((g_argc + 1) * sizeof(char *)))) goto f; memcpy(arg, g_argv, g_argc * sizeof(char *)); arg[g_argc] = NULL; pm_child_pid = -1; install_signal_handler(SIGCLD, pm_sigcld, NULL, 1); pm_setup_console(); pm_child_pid = pid = spawnvp(P_PM, path_to_exe, arg); mem_free(arg); if (pid < 0) { pm_setup_console(); goto f; } pm_do_console(); pm_setup_console(); while (1) select(1, NULL, NULL, NULL, NULL); f: s = pm_status; goto r4; } { #define N_FORMATS 100 int i, pm_bitcount; LONG formats[N_FORMATS]; memset(formats, 0, N_FORMATS * sizeof(LONG)); if (GpiQueryDeviceBitmapFormats(hps_msg, N_FORMATS, formats) == FALSE) goto std_form; for (i = 0; i + 1 < N_FORMATS; i += 2) if (formats[i] == 1) switch (formats[i+1]) { /* !!! FIXME: tady by se mely pridat dalsi formaty, ale neznam je */ /* case 15: pmshell_driver.depth = 0x7a; pm_bitcount = 15; goto e; */ case 16: pmshell_driver.depth = 0x82; pm_bitcount = 16; goto e; case 24: std_form: pmshell_driver.depth = 0xc3; pm_bitcount = 24; goto e; } goto std_form; e:; if ((pm_bitmapinfo = mem_calloc(sizeof(BITMAPINFOHEADER)))) { pm_bitmapinfo->cbFix = sizeof(BITMAPINFOHEADER); pm_bitmapinfo->cPlanes = 1; pm_bitmapinfo->cBitCount = pm_bitcount; } } { SIZEL sizl = { 0, 0 }; PSZ data[4] = { "DISPLAY", NULL, NULL, NULL }; hdc_mem = DevOpenDC(hab, OD_MEMORY, "*", 4L, (PDEVOPENDATA)data, NULLHANDLE); hps_mem = GpiCreatePS(hab, hdc_mem, &sizl, GPIA_ASSOC | PU_PELS | GPIT_MICRO); } set_handlers(pm_pipe[0], pm_handler, NULL, pm_pipe_error, NULL); return NULL; r4: close(pm_pipe[0]); close(pm_pipe[1]); r3: DosCloseEventSem(pm_sem); r2: WinTerminate(hab); r1: return stracpy(s); } struct graphics_device *pm_init_device() { RECTL rect; struct graphics_device *dev; struct pm_window *win; if (!(win = mem_alloc(sizeof(struct pm_window)))) goto r1; win->button = 0; init_list(win->queue); win->in = 0; pm_send_msg(MSG_CREATE_WINDOW, win); if (win->h == NULLHANDLE) goto r2; if ((win->ps = WinGetPS(win->hc)) == NULLHANDLE) goto r3; if (!(dev = mem_calloc(sizeof(struct graphics_device)))) goto r4; dev->driver_data = win; win->dev = dev; if (WinQueryWindowRect(win->hc, &rect) == TRUE) { win->x = dev->size.x2 = rect.xRight; win->y = dev->size.y2 = rect.yTop; } else dev->size.x2 = dev->size.y2 = 0; dev->clip.x1 = dev->clip.y1 = 0; dev->clip.x2 = dev->size.x2; dev->clip.y2 = dev->size.y2; dev->drv = &pmshell_driver; GpiCreateLogColorTable(win->ps, 0, LCOLF_RGB, 0, 0, NULL); pm_hash_window(win); pm_unlock; return dev; r4: WinReleasePS(win->ps); r3: pm_unlock; pm_send_msg(MSG_DELETE_WINDOW, win); r2: if (win->in) del_from_list(win); pm_unlock; mem_free(win); r1: return NULL; } void pm_shutdown_device(struct graphics_device *dev) { struct pm_window *win = pm_win(dev); WinReleasePS(win->ps); pm_send_msg(MSG_DELETE_WINDOW, win); pm_unhash_window(win); if (win->in) del_from_list(win); pm_unlock; while (!list_empty(win->queue)) { struct pm_event *ev = win->queue.next; del_from_list(ev); free(ev); } mem_free(win); mem_free(dev); } void pm_shutdown_driver() { pm_send_msg(MSG_SHUTDOWN_THREAD, NULL); GpiDestroyPS(hps_mem); DevCloseDC(hdc_mem); if (pm_bitmapinfo) mem_free(pm_bitmapinfo); set_handlers(pm_pipe[0], NULL, NULL, NULL, NULL); close(pm_pipe[0]); close(pm_pipe[1]); DosCloseEventSem(pm_sem); WinTerminate(hab); if (pm_bitmap_count) internal("pm_shutdown_driver: %d bitmaps leaked", pm_bitmap_count); } void pm_set_window_title(struct graphics_device *dev, unsigned char *title) { static int idx = -1; struct conv_table *ct = get_translation_table(idx >= 0 ? idx : (idx = get_cp_index("utf-8")), pm_cp); struct title_set w; w.win = pm_win(dev); w.text = convert_string(ct, title, strlen(title), NULL); pm_send_msg(MSG_SET_WINDOW_TITLE, &w); pm_unlock; mem_free(w.text); } int pm_get_filled_bitmap(struct bitmap *bmp, long color) { /* Mikulas jestlize plati ze get_color u pmshell nic nedela (jen oanduje * 0xffffff), tak tady zavolej (*get_color_fn)(color) z dither.c a ta * vrati long a, a ty udelas (void *)(&a) a budes mit ty bajty co chces */ internal("nedopsano"); return 0; } int pm_get_empty_bitmap(struct bitmap *bmp) { debug_call(("get_empty_bitmap (%dx%d)\n", bmp->x, bmp->y)); bmp->skip = -((bmp->x * (pmshell_driver.depth & 7) + 3) & ~3); bmp->data = (char *)(bmp->flags = mem_alloc(-bmp->skip * bmp->y)) - bmp->skip * (bmp->y - 1); debug_call(("done\n")); return 1; } void pm_register_bitmap(struct bitmap *bmp) { HBITMAP hbm; debug_call(("register_bitmap (%dx%d)\n", bmp->x, bmp->y)); pm_bitmap_count++; pm_bitmapinfo->cx = bmp->x; pm_bitmapinfo->cy = bmp->y; hbm = GpiCreateBitmap(hps_msg, (PBITMAPINFOHEADER2)pm_bitmapinfo, CBM_INIT, bmp->flags, (PBITMAPINFO2)pm_bitmapinfo); mem_free(bmp->flags); bmp->flags = (void *)hbm; debug_call(("done\n")); } void *pm_prepare_strip(struct bitmap *bmp, int top, int lines) { bmp->data = mem_alloc(-bmp->skip * lines); return (char *)bmp->data - bmp->skip * (lines - 1); } void pm_commit_strip(struct bitmap *bmp, int top, int lines) { LONG s; HBITMAP old; old = GpiSetBitmap(hps_mem, (HBITMAP)bmp->flags); pm_bitmapinfo->cx = bmp->x; pm_bitmapinfo->cy = bmp->y; s = GpiSetBitmapBits(hps_mem, bmp->y - top - lines, lines, bmp->data, (PBITMAPINFO2)pm_bitmapinfo); GpiSetBitmap(hps_mem, old); mem_free(bmp->data); } void pm_unregister_bitmap(struct bitmap *bmp) { debug_call(("unregister_bitmap (%dx%d)\n", bmp->x, bmp->y)); pm_bitmap_count--; GpiDeleteBitmap((HBITMAP)bmp->flags); debug_call(("done\n")); } void pm_draw_bitmap(struct graphics_device *dev, struct bitmap *bmp, int x, int y) { POINTL p; debug_call(("draw_bitmap (%dx%d -> %x,%x)\n", bmp->x, bmp->y, x, y)); p.x = x; p.y = pm_win(dev)->y - y - bmp->y; WinDrawBitmap(pm_win(dev)->ps, (HBITMAP)bmp->flags, NULL, &p, 0, 1, DBM_NORMAL); debug_call(("done\n")); } void pm_draw_bitmaps(struct graphics_device *dev, struct bitmap **bmp, int n, int x, int y) { HPS ps = pm_win(dev)->ps; POINTL p; debug_call(("draw_bitmaps\n")); p.x = x; p.y = pm_win(dev)->y - y - (*bmp)->y; while (n--) { WinDrawBitmap(ps, (HBITMAP)(*bmp)->flags, NULL, &p, 0xffffffff, 0, DBM_NORMAL); p.x += (*bmp++)->x; } debug_call(("done\n")); } long pm_get_color(int rgb) { return rgb & 0xffffff; } void pm_fill_area(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color) { RECTL r; debug_call(("fill_area (%d,%d)->(%d,%d)\n", x1, y1, x2, y2)); r.xLeft = x1; r.yBottom = pm_win(dev)->y - y2; r.xRight = x2; r.yTop = pm_win(dev)->y - y1; WinFillRect(pm_win(dev)->ps, &r, color); debug_call(("done\n")); } void pm_draw_hline(struct graphics_device *dev, int x1, int y, int x2, long color) { HPS ps = pm_win(dev)->ps; POINTL p; debug_call(("draw_hline (%d,%d)->(%d)\n", x1, y, x2)); if (x1 >= x2) { debug_call(("done\n")); return; } GpiSetColor(ps, color); p.x = x1; p.y = pm_win(dev)->y - y - 1; GpiMove(ps, &p); p.x = x2 - 1; GpiLine(ps, &p); debug_call(("done\n")); } void pm_draw_vline(struct graphics_device *dev, int x, int y1, int y2, long color) { HPS ps = pm_win(dev)->ps; POINTL p; debug_call(("draw_vline (%d,%d)->(%d)\n", x, y1, y2)); if (y1 >= y2) { debug_call(("done\n")); return; } GpiSetColor(ps, color); p.x = x; p.y = pm_win(dev)->y - y1 - 1; GpiMove(ps, &p); p.y = pm_win(dev)->y - y2; GpiLine(ps, &p); debug_call(("done\n")); } void pm_hscroll_redraws(struct pm_window *win, struct rect *r, int dir) { struct pm_event *e; pm_cancel_event(win, E_REDRAW, &e); if (!e) return; if (dir > 0) { if (e->x2 > r->x1 && e->x2 < r->x2) { e->x2 += dir; if (e->x2 > r->x2) e->x2 = r->x2; } } else if (dir < 0) { if (e->x1 > r->x1 && e->x1 < r->x2) { e->x1 += dir; if (e->x1 < r->x1) e->x1 = r->x1; } } } int pm_hscroll(struct graphics_device *dev, struct rect_set **ignore, int sc) { RECTL r; debug_call(("hscroll (%d)\n", sc)); ignore=NULL; r.xLeft = dev->clip.x1; r.yBottom = pm_win(dev)->y - dev->clip.y2; r.xRight = dev->clip.x2; r.yTop = pm_win(dev)->y - dev->clip.y1; pm_lock; WinScrollWindow(pm_win(dev)->hc, sc, 0, &r, &r, NULLHANDLE, NULL, SW_INVALIDATERGN); pm_hscroll_redraws(pm_win(dev), &dev->clip, sc); pm_unlock; debug_call(("done\n")); return 0; } void pm_vscroll_redraws(struct pm_window *win, struct rect *r, int dir) { struct pm_event *e; pm_cancel_event(win, E_REDRAW, &e); if (!e) return; if (dir > 0) { if (e->y2 > r->y1 && e->y2 < r->y2) { e->y2 += dir; if (e->y2 > r->y2) e->y2 = r->y2; } } else if (dir < 0) { if (e->y1 > r->y1 && e->y1 < r->y2) { e->y1 += dir; if (e->y1 < r->y1) e->y1 = r->y1; } } } int pm_vscroll(struct graphics_device *dev, struct rect_set **ignore, int sc) { RECTL r; debug_call(("vscroll (%d)\n", sc)); ignore=NULL; r.xLeft = dev->clip.x1; r.yBottom = pm_win(dev)->y - dev->clip.y2; r.xRight = dev->clip.x2; r.yTop = pm_win(dev)->y - dev->clip.y1; pm_lock; WinScrollWindow(pm_win(dev)->hc, 0, -sc, &r, &r, NULLHANDLE, NULL, SW_INVALIDATERGN); pm_vscroll_redraws(pm_win(dev), &dev->clip, sc); pm_unlock; debug_call(("done\n")); return 0; } void pm_set_clip_area(struct graphics_device *dev, struct rect *rr) { HPS ps = pm_win(dev)->ps; HRGN rg, org; RECTL r; debug_call(("set_clip_area (%d,%d)x(%d,%d)\n", rr->x1, rr->y1, rr->x2, rr->y2)); memcpy(&dev->clip, rr, sizeof(struct rect)); if (dev->clip.x1 >= dev->clip.x2 || dev->clip.y1 >= dev->clip.y2) dev->clip.x1 = dev->clip.x2 = dev->clip.y1 = dev->clip.y2 = 0; r.xLeft = dev->clip.x1; r.yBottom = pm_win(dev)->y - dev->clip.y2; r.xRight = dev->clip.x2; r.yTop = pm_win(dev)->y - dev->clip.y1; if ((rg = GpiCreateRegion(ps, 1, &r)) == RGN_ERROR) return; if (GpiSetClipRegion(ps, rg, &org) == RGN_ERROR) org = rg; GpiDestroyRegion(ps, org); debug_call(("done\n")); } struct graphics_driver pmshell_driver = { "pmshell", pm_init_driver, pm_init_device, pm_shutdown_device, pm_shutdown_driver, pm_get_driver_param, pm_get_empty_bitmap, pm_get_filled_bitmap, pm_register_bitmap, pm_prepare_strip, pm_commit_strip, pm_unregister_bitmap, pm_draw_bitmap, pm_draw_bitmaps, pm_get_color, pm_fill_area, pm_draw_hline, pm_draw_vline, pm_hscroll, pm_vscroll, pm_set_clip_area, dummy_block, dummy_unblock, pm_set_window_title, 0, /* depth */ 0, 0, /* x, y */ 0, /* flags */ }; #endif