--- sourceforge.net/trunk/rdesktop/xwin.c 2005/02/28 01:15:45 821 +++ sourceforge.net/trunk/rdesktop/xwin.c 2005/08/25 20:27:45 988 @@ -1,7 +1,7 @@ /* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. User interface services - X Window System - Copyright (C) Matthew Chapman 1999-2002 + Copyright (C) Matthew Chapman 1999-2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ extern int g_height; extern int g_xpos; extern int g_ypos; +extern int g_pos; extern BOOL g_sendmotion; extern BOOL g_fullscreen; extern BOOL g_grab_keyboard; @@ -119,6 +120,31 @@ XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \ } +#define FILL_POLYGON(p,np)\ +{ \ + XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \ + if (g_ownbackstore) \ + XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \ +} + +#define DRAW_ELLIPSE(x,y,cx,cy,m)\ +{ \ + switch (m) \ + { \ + case 0: /* Outline */ \ + XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \ + if (g_ownbackstore) \ + XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \ + break; \ + case 1: /* Filled */ \ + XFillArc(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, \ + cx, cy, 0, 360*64); \ + if (g_ownbackstore) \ + XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); \ + break; \ + } \ +} + /* colour maps */ extern BOOL g_owncolmap; static Colormap g_xcolmap; @@ -662,6 +688,7 @@ } else { + while (out < end) { pixel = *(data++); SPLITCOLOUR16(pixel, pc); @@ -764,19 +791,22 @@ if (g_arch_match) { /* *INDENT-OFF* */ +#ifdef NEED_ALIGN REPEAT4 ( -#ifdef NEED_ALIGN *(out++) = *(data++); *(out++) = *(data++); *(out++) = *(data++); *(out++) = 0; + ) #else + REPEAT4 + ( *((uint32 *) out) = *((uint32 *) data); out += 4; data += 3; -#endif ) +#endif /* *INDENT-ON* */ } else if (g_xserver_be) @@ -1134,6 +1164,12 @@ wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width; wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height; + /* Handle -x-y portion of geometry string */ + if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2))) + g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width; + if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4))) + g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height; + attribs.background_pixel = BlackPixelOfScreen(g_screen); attribs.border_pixel = WhitePixelOfScreen(g_screen); attribs.backing_store = g_ownbackstore ? NotUseful : Always; @@ -1177,6 +1213,8 @@ if (sizehints) { sizehints->flags = PMinSize | PMaxSize; + if (g_pos) + sizehints->flags |= PPosition; sizehints->min_width = sizehints->max_width = g_width; sizehints->min_height = sizehints->max_height = g_height; XSetWMNormalHints(g_display, g_wnd, sizehints); @@ -1189,7 +1227,7 @@ } input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | - VisibilityChangeMask | FocusChangeMask; + VisibilityChangeMask | FocusChangeMask | StructureNotifyMask; if (g_sendmotion) input_mask |= PointerMotionMask; @@ -1303,20 +1341,91 @@ } } -/* Process all events in Xlib queue +static void +handle_button_event(XEvent xevent, BOOL down) +{ + uint16 button, flags = 0; + g_last_gesturetime = xevent.xbutton.time; + button = xkeymap_translate_button(xevent.xbutton.button); + if (button == 0) + return; + + if (down) + flags = MOUSE_FLAG_DOWN; + + /* Stop moving window when button is released, regardless of cursor position */ + if (g_moving_wnd && (xevent.type == ButtonRelease)) + g_moving_wnd = False; + + /* If win_button_size is nonzero, enable single app mode */ + if (xevent.xbutton.y < g_win_button_size) + { + /* Check from right to left: */ + if (xevent.xbutton.x >= g_width - g_win_button_size) + { + /* The close button, continue */ + ; + } + else if (xevent.xbutton.x >= g_width - g_win_button_size * 2) + { + /* The maximize/restore button. Do not send to + server. It might be a good idea to change the + cursor or give some other visible indication + that rdesktop inhibited this click */ + if (xevent.type == ButtonPress) + return; + } + else if (xevent.xbutton.x >= g_width - g_win_button_size * 3) + { + /* The minimize button. Iconify window. */ + if (xevent.type == ButtonRelease) + { + /* Release the mouse button outside the minimize button, to prevent the + actual minimazation to happen */ + rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1); + XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display)); + return; + } + } + else if (xevent.xbutton.x <= g_win_button_size) + { + /* The system menu. Ignore. */ + if (xevent.type == ButtonPress) + return; + } + else + { + /* The title bar. */ + if (xevent.type == ButtonPress) + { + if (!g_fullscreen && g_hide_decorations) + { + g_moving_wnd = True; + g_move_x_offset = xevent.xbutton.x; + g_move_y_offset = xevent.xbutton.y; + } + return; + } + } + } + + rdp_send_input(time(NULL), RDP_INPUT_MOUSE, + flags | button, xevent.xbutton.x, xevent.xbutton.y); +} + +/* Process events in Xlib queue Returns 0 after user quit, 1 otherwise */ static int xwin_process_events(void) { XEvent xevent; KeySym keysym; - uint16 button, flags; uint32 ev_time; - key_translation tr; char str[256]; Status status; + int events = 0; - while (XPending(g_display) > 0) + while ((XPending(g_display) > 0) && events++ < 20) { XNextEvent(g_display, &xevent); @@ -1326,8 +1435,6 @@ continue; } - flags = 0; - switch (xevent.type) { case VisibilityNotify: @@ -1364,24 +1471,15 @@ str, sizeof(str), &keysym, NULL); } - DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym, + DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym, get_ksname(keysym))); ev_time = time(NULL); if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True)) break; - tr = xkeymap_translate_key(keysym, - xevent.xkey.keycode, xevent.xkey.state); - - if (tr.scancode == 0) - break; - - save_remote_modifiers(tr.scancode); - ensure_remote_modifiers(ev_time, tr); - rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode); - restore_remote_modifiers(ev_time, tr.scancode); - + xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state, + ev_time, True, 0); break; case KeyRelease: @@ -1389,85 +1487,23 @@ XLookupString((XKeyEvent *) & xevent, str, sizeof(str), &keysym, NULL); - DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym, + DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym, get_ksname(keysym))); ev_time = time(NULL); if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False)) break; - tr = xkeymap_translate_key(keysym, - xevent.xkey.keycode, xevent.xkey.state); - - if (tr.scancode == 0) - break; - - rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode); + xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state, + ev_time, False, 0); break; case ButtonPress: - flags = MOUSE_FLAG_DOWN; - /* fall through */ + handle_button_event(xevent, True); + break; case ButtonRelease: - g_last_gesturetime = xevent.xbutton.time; - button = xkeymap_translate_button(xevent.xbutton.button); - if (button == 0) - break; - - /* If win_button_size is nonzero, enable single app mode */ - if (xevent.xbutton.y < g_win_button_size) - { - /* Stop moving window when button is released, regardless of cursor position */ - if (g_moving_wnd && (xevent.type == ButtonRelease)) - g_moving_wnd = False; - - /* Check from right to left: */ - - if (xevent.xbutton.x >= g_width - g_win_button_size) - { - /* The close button, continue */ - ; - } - else if (xevent.xbutton.x >= - g_width - g_win_button_size * 2) - { - /* The maximize/restore button. Do not send to - server. It might be a good idea to change the - cursor or give some other visible indication - that rdesktop inhibited this click */ - break; - } - else if (xevent.xbutton.x >= - g_width - g_win_button_size * 3) - { - /* The minimize button. Iconify window. */ - XIconifyWindow(g_display, g_wnd, - DefaultScreen(g_display)); - break; - } - else if (xevent.xbutton.x <= g_win_button_size) - { - /* The system menu. Ignore. */ - break; - } - else - { - /* The title bar. */ - if ((xevent.type == ButtonPress) && !g_fullscreen - && g_hide_decorations) - { - g_moving_wnd = True; - g_move_x_offset = xevent.xbutton.x; - g_move_y_offset = xevent.xbutton.y; - } - break; - - } - } - - rdp_send_input(time(NULL), RDP_INPUT_MOUSE, - flags | button, xevent.xbutton.x, xevent.xbutton.y); + handle_button_event(xevent, False); break; case MotionNotify: @@ -1560,6 +1596,12 @@ case PropertyNotify: xclip_handle_PropertyNotify(&xevent.xproperty); break; + case MapNotify: + rdp_send_client_window_status(1); + break; + case UnmapNotify: + rdp_send_client_window_status(0); + break; } } /* Keep going */ @@ -2162,6 +2204,151 @@ FILL_RECTANGLE(x, y, cx, cy); } +void +ui_polygon(uint8 opcode, + /* mode */ uint8 fillmode, + /* dest */ POINT * point, int npoints, + /* brush */ BRUSH * brush, int bgcolour, int fgcolour) +{ + uint8 style, i, ipattern[8]; + Pixmap fill; + + SET_FUNCTION(opcode); + + switch (fillmode) + { + case ALTERNATE: + XSetFillRule(g_display, g_gc, EvenOddRule); + break; + case WINDING: + XSetFillRule(g_display, g_gc, WindingRule); + break; + default: + unimpl("fill mode %d\n", fillmode); + } + + if (brush) + style = brush->style; + else + style = 0; + + switch (style) + { + case 0: /* Solid */ + SET_FOREGROUND(fgcolour); + FILL_POLYGON((XPoint *) point, npoints); + break; + + case 2: /* Hatch */ + fill = (Pixmap) ui_create_glyph(8, 8, + hatch_patterns + brush->pattern[0] * 8); + SET_FOREGROUND(fgcolour); + SET_BACKGROUND(bgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + FILL_POLYGON((XPoint *) point, npoints); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((HGLYPH) fill); + break; + + case 3: /* Pattern */ + for (i = 0; i != 8; i++) + ipattern[7 - i] = brush->pattern[i]; + fill = (Pixmap) ui_create_glyph(8, 8, ipattern); + SET_FOREGROUND(bgcolour); + SET_BACKGROUND(fgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + FILL_POLYGON((XPoint *) point, npoints); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((HGLYPH) fill); + break; + + default: + unimpl("brush %d\n", brush->style); + } + + RESET_FUNCTION(opcode); +} + +void +ui_polyline(uint8 opcode, + /* dest */ POINT * points, int npoints, + /* pen */ PEN * pen) +{ + /* TODO: set join style */ + SET_FUNCTION(opcode); + SET_FOREGROUND(pen->colour); + XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious); + if (g_ownbackstore) + XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints, + CoordModePrevious); + RESET_FUNCTION(opcode); +} + +void +ui_ellipse(uint8 opcode, + /* mode */ uint8 fillmode, + /* dest */ int x, int y, int cx, int cy, + /* brush */ BRUSH * brush, int bgcolour, int fgcolour) +{ + uint8 style, i, ipattern[8]; + Pixmap fill; + + SET_FUNCTION(opcode); + + if (brush) + style = brush->style; + else + style = 0; + + switch (style) + { + case 0: /* Solid */ + SET_FOREGROUND(fgcolour); + DRAW_ELLIPSE(x, y, cx, cy, fillmode); + break; + + case 2: /* Hatch */ + fill = (Pixmap) ui_create_glyph(8, 8, + hatch_patterns + brush->pattern[0] * 8); + SET_FOREGROUND(fgcolour); + SET_BACKGROUND(bgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + DRAW_ELLIPSE(x, y, cx, cy, fillmode); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((HGLYPH) fill); + break; + + case 3: /* Pattern */ + for (i = 0; i != 8; i++) + ipattern[7 - i] = brush->pattern[i]; + fill = (Pixmap) ui_create_glyph(8, 8, ipattern); + SET_FOREGROUND(bgcolour); + SET_BACKGROUND(fgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + DRAW_ELLIPSE(x, y, cx, cy, fillmode); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((HGLYPH) fill); + break; + + default: + unimpl("brush %d\n", brush->style); + } + + RESET_FUNCTION(opcode); +} + /* warning, this function only draws on wnd or backstore, not both */ void ui_draw_glyph(int mixmode, @@ -2217,11 +2404,13 @@ } void -ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y, +ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y, int clipx, int clipy, int clipcx, int clipcy, - int boxx, int boxy, int boxcx, int boxcy, int bgcolour, - int fgcolour, uint8 * text, uint8 length) + int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush, + int bgcolour, int fgcolour, uint8 * text, uint8 length) { + /* TODO: use brush appropriately */ + FONTGLYPH *glyph; int i, j, xyoffset, x1, y1; DATABLOB *entry;