1 /* -*- c-basic-offset: 8 -*- 2 rdesktop: A Remote Desktop Protocol client. 3 User interface services - X Window System 4 Copyright (C) Matthew Chapman 1999-2005 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License along 17 with this program; if not, write to the Free Software Foundation, Inc., 18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include <X11/Xlib.h> 22 #include <X11/Xutil.h> 23 #include <unistd.h> 24 #include <sys/time.h> 25 #include <time.h> 26 #include <errno.h> 27 #include <strings.h> 28 #include "rdesktop.h" 29 #include "xproto.h" 30 31 /* We can't include Xproto.h because of conflicting defines for BOOL */ 32 #define X_ConfigureWindow 12 33 34 /* MWM decorations */ 35 #define MWM_HINTS_DECORATIONS (1L << 1) 36 #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 37 typedef struct 38 { 39 unsigned long flags; 40 unsigned long functions; 41 unsigned long decorations; 42 long inputMode; 43 unsigned long status; 44 } 45 PropMotifWmHints; 46 47 typedef struct 48 { 49 uint32 red; 50 uint32 green; 51 uint32 blue; 52 } 53 PixelColour; 54 55 #define ON_ALL_SEAMLESS_WINDOWS(func, args) \ 56 do { \ 57 seamless_window *sw; \ 58 XRectangle rect; \ 59 if (!This->xwin.seamless_windows) break; \ 60 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) { \ 61 rect.x = This->xwin.clip_rectangle.x - sw->xoffset; \ 62 rect.y = This->xwin.clip_rectangle.y - sw->yoffset; \ 63 rect.width = This->xwin.clip_rectangle.width; \ 64 rect.height = This->xwin.clip_rectangle.height; \ 65 XSetClipRectangles(This->display, This->xwin.gc, 0, 0, &rect, 1, YXBanded); \ 66 func args; \ 67 } \ 68 XSetClipRectangles(This->display, This->xwin.gc, 0, 0, &This->xwin.clip_rectangle, 1, YXBanded); \ 69 } while (0) 70 71 static void 72 seamless_XFillPolygon(RDPCLIENT * This, Drawable d, XPoint * points, int npoints, int xoffset, int yoffset) 73 { 74 points[0].x -= xoffset; 75 points[0].y -= yoffset; 76 XFillPolygon(This->display, d, This->xwin.gc, points, npoints, Complex, CoordModePrevious); 77 points[0].x += xoffset; 78 points[0].y += yoffset; 79 } 80 81 static void 82 seamless_XDrawLines(RDPCLIENT * This, Drawable d, XPoint * points, int npoints, int xoffset, int yoffset) 83 { 84 points[0].x -= xoffset; 85 points[0].y -= yoffset; 86 XDrawLines(This->display, d, This->xwin.gc, points, npoints, CoordModePrevious); 87 points[0].x += xoffset; 88 points[0].y += yoffset; 89 } 90 91 #define FILL_RECTANGLE(x,y,cx,cy)\ 92 { \ 93 XFillRectangle(This->display, This->wnd, This->xwin.gc, x, y, cx, cy); \ 94 ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (This->display, sw->wnd, This->xwin.gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \ 95 if (This->ownbackstore) \ 96 XFillRectangle(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy); \ 97 } 98 99 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\ 100 { \ 101 XFillRectangle(This->display, This->ownbackstore ? This->xwin.backstore : This->wnd, This->xwin.gc, x, y, cx, cy); \ 102 } 103 104 #define FILL_POLYGON(p,np)\ 105 { \ 106 XFillPolygon(This->display, This->wnd, This->xwin.gc, p, np, Complex, CoordModePrevious); \ 107 if (This->ownbackstore) \ 108 XFillPolygon(This->display, This->xwin.backstore, This->xwin.gc, p, np, Complex, CoordModePrevious); \ 109 ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (This, sw->wnd, p, np, sw->xoffset, sw->yoffset)); \ 110 } 111 112 #define DRAW_ELLIPSE(x,y,cx,cy,m)\ 113 { \ 114 switch (m) \ 115 { \ 116 case 0: /* Outline */ \ 117 XDrawArc(This->display, This->wnd, This->xwin.gc, x, y, cx, cy, 0, 360*64); \ 118 ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (This->display, sw->wnd, This->xwin.gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \ 119 if (This->ownbackstore) \ 120 XDrawArc(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy, 0, 360*64); \ 121 break; \ 122 case 1: /* Filled */ \ 123 XFillArc(This->display, This->wnd, This->xwin.gc, x, y, cx, cy, 0, 360*64); \ 124 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (This->display, This->ownbackstore ? This->xwin.backstore : This->wnd, sw->wnd, This->xwin.gc, \ 125 x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \ 126 if (This->ownbackstore) \ 127 XFillArc(This->display, This->xwin.backstore, This->xwin.gc, x, y, cx, cy, 0, 360*64); \ 128 break; \ 129 } \ 130 } 131 132 #define TRANSLATE(col) ( This->server_depth != 8 ? translate_colour(This, col) : This->owncolmap ? col : This->xwin.colmap[col] ) 133 #define SET_FOREGROUND(col) XSetForeground(This->display, This->xwin.gc, TRANSLATE(col)); 134 #define SET_BACKGROUND(col) XSetBackground(This->display, This->xwin.gc, TRANSLATE(col)); 135 136 static const int rop2_map[] = { 137 GXclear, /* 0 */ 138 GXnor, /* DPon */ 139 GXandInverted, /* DPna */ 140 GXcopyInverted, /* Pn */ 141 GXandReverse, /* PDna */ 142 GXinvert, /* Dn */ 143 GXxor, /* DPx */ 144 GXnand, /* DPan */ 145 GXand, /* DPa */ 146 GXequiv, /* DPxn */ 147 GXnoop, /* D */ 148 GXorInverted, /* DPno */ 149 GXcopy, /* P */ 150 GXorReverse, /* PDno */ 151 GXor, /* DPo */ 152 GXset /* 1 */ 153 }; 154 155 #define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(This->display, This->xwin.gc, rop2_map[rop2]); } 156 #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(This->display, This->xwin.gc, GXcopy); } 157 158 static seamless_window * 159 sw_get_window_by_id(RDPCLIENT * This, unsigned long id) 160 { 161 seamless_window *sw; 162 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) 163 { 164 if (sw->id == id) 165 return sw; 166 } 167 return NULL; 168 } 169 170 171 static seamless_window * 172 sw_get_window_by_wnd(RDPCLIENT * This, Window wnd) 173 { 174 seamless_window *sw; 175 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) 176 { 177 if (sw->wnd == wnd) 178 return sw; 179 } 180 return NULL; 181 } 182 183 184 static void 185 sw_remove_window(RDPCLIENT * This, seamless_window * win) 186 { 187 seamless_window *sw, **prevnext = &This->xwin.seamless_windows; 188 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) 189 { 190 if (sw == win) 191 { 192 *prevnext = sw->next; 193 sw->group->refcnt--; 194 if (sw->group->refcnt == 0) 195 { 196 XDestroyWindow(This->display, sw->group->wnd); 197 xfree(sw->group); 198 } 199 xfree(sw->position_timer); 200 xfree(sw); 201 return; 202 } 203 prevnext = &sw->next; 204 } 205 return; 206 } 207 208 209 /* Move all windows except wnd to new desktop */ 210 static void 211 sw_all_to_desktop(RDPCLIENT * This, Window wnd, unsigned int desktop) 212 { 213 seamless_window *sw; 214 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) 215 { 216 if (sw->wnd == wnd) 217 continue; 218 if (sw->desktop != desktop) 219 { 220 ewmh_move_to_desktop(This, sw->wnd, desktop); 221 sw->desktop = desktop; 222 } 223 } 224 } 225 226 227 /* Send our position */ 228 static void 229 sw_update_position(RDPCLIENT * This, seamless_window * sw) 230 { 231 XWindowAttributes wa; 232 int x, y; 233 Window child_return; 234 unsigned int serial; 235 236 XGetWindowAttributes(This->display, sw->wnd, &wa); 237 XTranslateCoordinates(This->display, sw->wnd, wa.root, 238 -wa.border_width, -wa.border_width, &x, &y, &child_return); 239 240 serial = seamless_send_position(This, sw->id, x, y, wa.width, wa.height, 0); 241 242 sw->outstanding_position = True; 243 sw->outpos_serial = serial; 244 245 sw->outpos_xoffset = x; 246 sw->outpos_yoffset = y; 247 sw->outpos_width = wa.width; 248 sw->outpos_height = wa.height; 249 } 250 251 252 /* Check if it's time to send our position */ 253 static void 254 sw_check_timers(RDPCLIENT * This) 255 { 256 seamless_window *sw; 257 struct timeval now; 258 259 gettimeofday(&now, NULL); 260 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) 261 { 262 if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <)) 263 { 264 timerclear(sw->position_timer); 265 sw_update_position(This, sw); 266 } 267 } 268 } 269 270 271 static void 272 sw_restack_window(RDPCLIENT * This, seamless_window * sw, unsigned long behind) 273 { 274 seamless_window *sw_above; 275 276 /* Remove window from stack */ 277 for (sw_above = This->xwin.seamless_windows; sw_above; sw_above = sw_above->next) 278 { 279 if (sw_above->behind == sw->id) 280 break; 281 } 282 283 if (sw_above) 284 sw_above->behind = sw->behind; 285 286 /* And then add it at the new position */ 287 for (sw_above = This->xwin.seamless_windows; sw_above; sw_above = sw_above->next) 288 { 289 if (sw_above->behind == behind) 290 break; 291 } 292 293 if (sw_above) 294 sw_above->behind = sw->id; 295 296 sw->behind = behind; 297 } 298 299 300 static void 301 sw_handle_restack(RDPCLIENT * This, seamless_window * sw) 302 { 303 Status status; 304 Window root, parent, *children; 305 unsigned int nchildren, i; 306 seamless_window *sw_below; 307 308 status = XQueryTree(This->display, RootWindowOfScreen(This->xwin.screen), 309 &root, &parent, &children, &nchildren); 310 if (!status || !nchildren) 311 return; 312 313 sw_below = NULL; 314 315 i = 0; 316 while (children[i] != sw->wnd) 317 { 318 i++; 319 if (i >= nchildren) 320 goto end; 321 } 322 323 for (i++; i < nchildren; i++) 324 { 325 sw_below = sw_get_window_by_wnd(This, children[i]); 326 if (sw_below) 327 break; 328 } 329 330 if (!sw_below && !sw->behind) 331 goto end; 332 if (sw_below && (sw_below->id == sw->behind)) 333 goto end; 334 335 if (sw_below) 336 { 337 seamless_send_zchange(This, sw->id, sw_below->id, 0); 338 sw_restack_window(This, sw, sw_below->id); 339 } 340 else 341 { 342 seamless_send_zchange(This, sw->id, 0, 0); 343 sw_restack_window(This, sw, 0); 344 } 345 346 end: 347 XFree(children); 348 } 349 350 351 static seamless_group * 352 sw_find_group(RDPCLIENT * This, unsigned long id, BOOL dont_create) 353 { 354 seamless_window *sw; 355 seamless_group *sg; 356 XSetWindowAttributes attribs; 357 358 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) 359 { 360 if (sw->group->id == id) 361 return sw->group; 362 } 363 364 if (dont_create) 365 return NULL; 366 367 sg = xmalloc(sizeof(seamless_group)); 368 369 sg->wnd = 370 XCreateWindow(This->display, RootWindowOfScreen(This->xwin.screen), -1, -1, 1, 1, 0, 371 CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs); 372 373 sg->id = id; 374 sg->refcnt = 0; 375 376 return sg; 377 } 378 379 380 static void 381 mwm_hide_decorations(RDPCLIENT * This, Window wnd) 382 { 383 PropMotifWmHints motif_hints; 384 Atom hintsatom; 385 386 /* setup the property */ 387 motif_hints.flags = MWM_HINTS_DECORATIONS; 388 motif_hints.decorations = 0; 389 390 /* get the atom for the property */ 391 hintsatom = XInternAtom(This->display, "_MOTIF_WM_HINTS", False); 392 if (!hintsatom) 393 { 394 warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n"); 395 return; 396 } 397 398 XChangeProperty(This->display, wnd, hintsatom, hintsatom, 32, PropModeReplace, 399 (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS); 400 401 } 402 403 #define SPLITCOLOUR15(colour, rv) \ 404 { \ 405 rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \ 406 rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \ 407 rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \ 408 } 409 410 #define SPLITCOLOUR16(colour, rv) \ 411 { \ 412 rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \ 413 rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \ 414 rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \ 415 } \ 416 417 #define SPLITCOLOUR24(colour, rv) \ 418 { \ 419 rv.blue = (colour & 0xff0000) >> 16; \ 420 rv.green = (colour & 0x00ff00) >> 8; \ 421 rv.red = (colour & 0x0000ff); \ 422 } 423 424 #define MAKECOLOUR(pc) \ 425 ((pc.red >> This->xwin.red_shift_r) << This->xwin.red_shift_l) \ 426 | ((pc.green >> This->xwin.green_shift_r) << This->xwin.green_shift_l) \ 427 | ((pc.blue >> This->xwin.blue_shift_r) << This->xwin.blue_shift_l) \ 428 429 #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); } 430 #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); } 431 #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \ 432 x = (x << 16) | (x >> 16); } 433 434 /* The following macros output the same octet sequences 435 on both BE and LE hosts: */ 436 437 #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; } 438 #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; } 439 #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; } 440 #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; } 441 #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; } 442 #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; } 443 444 static uint32 445 translate_colour(RDPCLIENT * This, uint32 colour) 446 { 447 PixelColour pc; 448 switch (This->server_depth) 449 { 450 case 15: 451 SPLITCOLOUR15(colour, pc); 452 break; 453 case 16: 454 SPLITCOLOUR16(colour, pc); 455 break; 456 case 24: 457 SPLITCOLOUR24(colour, pc); 458 break; 459 default: 460 /* Avoid warning */ 461 pc.red = 0; 462 pc.green = 0; 463 pc.blue = 0; 464 break; 465 } 466 return MAKECOLOUR(pc); 467 } 468 469 /* indent is confused by UNROLL8 */ 470 /* *INDENT-OFF* */ 471 472 /* repeat and unroll, similar to bitmap.c */ 473 /* potentialy any of the following translate */ 474 /* functions can use repeat but just doing */ 475 /* the most common ones */ 476 477 #define UNROLL8(stm) { stm stm stm stm stm stm stm stm } 478 /* 2 byte output repeat */ 479 #define REPEAT2(stm) \ 480 { \ 481 while (out <= end - 8 * 2) \ 482 UNROLL8(stm) \ 483 while (out < end) \ 484 { stm } \ 485 } 486 /* 3 byte output repeat */ 487 #define REPEAT3(stm) \ 488 { \ 489 while (out <= end - 8 * 3) \ 490 UNROLL8(stm) \ 491 while (out < end) \ 492 { stm } \ 493 } 494 /* 4 byte output repeat */ 495 #define REPEAT4(stm) \ 496 { \ 497 while (out <= end - 8 * 4) \ 498 UNROLL8(stm) \ 499 while (out < end) \ 500 { stm } \ 501 } 502 /* *INDENT-ON* */ 503 504 static void 505 translate8to8(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end) 506 { 507 while (out < end) 508 *(out++) = (uint8) This->xwin.colmap[*(data++)]; 509 } 510 511 static void 512 translate8to16(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end) 513 { 514 uint16 value; 515 516 if (This->xwin.compatible_arch) 517 { 518 /* *INDENT-OFF* */ 519 REPEAT2 520 ( 521 *((uint16 *) out) = This->xwin.colmap[*(data++)]; 522 out += 2; 523 ) 524 /* *INDENT-ON* */ 525 } 526 else if (This->xwin.xserver_be) 527 { 528 while (out < end) 529 { 530 value = (uint16) This->xwin.colmap[*(data++)]; 531 BOUT16(out, value); 532 } 533 } 534 else 535 { 536 while (out < end) 537 { 538 value = (uint16) This->xwin.colmap[*(data++)]; 539 LOUT16(out, value); 540 } 541 } 542 } 543 544 /* little endian - conversion happens when colourmap is built */ 545 static void 546 translate8to24(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end) 547 { 548 uint32 value; 549 550 if (This->xwin.compatible_arch) 551 { 552 while (out < end) 553 { 554 value = This->xwin.colmap[*(data++)]; 555 BOUT24(out, value); 556 } 557 } 558 else 559 { 560 while (out < end) 561 { 562 value = This->xwin.colmap[*(data++)]; 563 LOUT24(out, value); 564 } 565 } 566 } 567 568 static void 569 translate8to32(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end) 570 { 571 uint32 value; 572 573 if (This->xwin.compatible_arch) 574 { 575 /* *INDENT-OFF* */ 576 REPEAT4 577 ( 578 *((uint32 *) out) = This->xwin.colmap[*(data++)]; 579 out += 4; 580 ) 581 /* *INDENT-ON* */ 582 } 583 else if (This->xwin.xserver_be) 584 { 585 while (out < end) 586 { 587 value = This->xwin.colmap[*(data++)]; 588 BOUT32(out, value); 589 } 590 } 591 else 592 { 593 while (out < end) 594 { 595 value = This->xwin.colmap[*(data++)]; 596 LOUT32(out, value); 597 } 598 } 599 } 600 601 static void 602 translate15to16(RDPCLIENT * This, const uint16 * data, uint8 * out, uint8 * end) 603 { 604 uint16 pixel; 605 uint16 value; 606 PixelColour pc; 607 608 if (This->xwin.xserver_be) 609 { 610 while (out < end) 611 { 612 pixel = *(data++); 613 if (This->xwin.host_be) 614 { 615 BSWAP16(pixel); 616 } 617 SPLITCOLOUR15(pixel, pc); 618 value = MAKECOLOUR(pc); 619 BOUT16(out, value); 620 } 621 } 622 else 623 { 624 while (out < end) 625 { 626 pixel = *(data++); 627 if (This->xwin.host_be) 628 { 629 BSWAP16(pixel); 630 } 631 SPLITCOLOUR15(pixel, pc); 632 value = MAKECOLOUR(pc); 633 LOUT16(out, value); 634 } 635 } 636 } 637 638 static void 639 translate15to24(RDPCLIENT * This, const uint16 * data, uint8 * out, uint8 * end) 640 { 641 uint32 value; 642 uint16 pixel; 643 PixelColour pc; 644 645 if (This->xwin.compatible_arch) 646 { 647 /* *INDENT-OFF* */ 648 REPEAT3 649 ( 650 pixel = *(data++); 651 SPLITCOLOUR15(pixel, pc); 652 *(out++) = pc.blue; 653 *(out++) = pc.green; 654 *(out++) = pc.red; 655 ) 656 /* *INDENT-ON* */ 657 } 658 else if (This->xwin.xserver_be) 659 { 660 while (out < end) 661 { 662 pixel = *(data++); 663 if (This->xwin.host_be) 664 { 665 BSWAP16(pixel); 666 } 667 SPLITCOLOUR15(pixel, pc); 668 value = MAKECOLOUR(pc); 669 BOUT24(out, value); 670 } 671 } 672 else 673 { 674 while (out < end) 675 { 676 pixel = *(data++); 677 if (This->xwin.host_be) 678 { 679 BSWAP16(pixel); 680 } 681 SPLITCOLOUR15(pixel, pc); 682 value = MAKECOLOUR(pc); 683 LOUT24(out, value); 684 } 685 } 686 } 687 688 static void 689 translate15to32(RDPCLIENT * This, const uint16 * data, uint8 * out, uint8 * end) 690 { 691 uint16 pixel; 692 uint32 value; 693 PixelColour pc; 694 695 if (This->xwin.compatible_arch) 696 { 697 /* *INDENT-OFF* */ 698 REPEAT4 699 ( 700 pixel = *(data++); 701 SPLITCOLOUR15(pixel, pc); 702 *(out++) = pc.blue; 703 *(out++) = pc.green; 704 *(out++) = pc.red; 705 *(out++) = 0; 706 ) 707 /* *INDENT-ON* */ 708 } 709 else if (This->xwin.xserver_be) 710 { 711 while (out < end) 712 { 713 pixel = *(data++); 714 if (This->xwin.host_be) 715 { 716 BSWAP16(pixel); 717 } 718 SPLITCOLOUR15(pixel, pc); 719 value = MAKECOLOUR(pc); 720 BOUT32(out, value); 721 } 722 } 723 else 724 { 725 while (out < end) 726 { 727 pixel = *(data++); 728 if (This->xwin.host_be) 729 { 730 BSWAP16(pixel); 731 } 732 SPLITCOLOUR15(pixel, pc); 733 value = MAKECOLOUR(pc); 734 LOUT32(out, value); 735 } 736 } 737 } 738 739 static void 740 translate16to16(RDPCLIENT * This, const uint16 * data, uint8 * out, uint8 * end) 741 { 742 uint16 pixel; 743 uint16 value; 744 PixelColour pc; 745 746 if (This->xwin.xserver_be) 747 { 748 if (This->xwin.host_be) 749 { 750 while (out < end) 751 { 752 pixel = *(data++); 753 BSWAP16(pixel); 754 SPLITCOLOUR16(pixel, pc); 755 value = MAKECOLOUR(pc); 756 BOUT16(out, value); 757 } 758 } 759 else 760 { 761 while (out < end) 762 { 763 pixel = *(data++); 764 SPLITCOLOUR16(pixel, pc); 765 value = MAKECOLOUR(pc); 766 BOUT16(out, value); 767 } 768 } 769 } 770 else 771 { 772 if (This->xwin.host_be) 773 { 774 while (out < end) 775 { 776 pixel = *(data++); 777 BSWAP16(pixel); 778 SPLITCOLOUR16(pixel, pc); 779 value = MAKECOLOUR(pc); 780 LOUT16(out, value); 781 } 782 } 783 else 784 { 785 while (out < end) 786 { 787 pixel = *(data++); 788 SPLITCOLOUR16(pixel, pc); 789 value = MAKECOLOUR(pc); 790 LOUT16(out, value); 791 } 792 } 793 } 794 } 795 796 static void 797 translate16to24(RDPCLIENT * This, const uint16 * data, uint8 * out, uint8 * end) 798 { 799 uint32 value; 800 uint16 pixel; 801 PixelColour pc; 802 803 if (This->xwin.compatible_arch) 804 { 805 /* *INDENT-OFF* */ 806 REPEAT3 807 ( 808 pixel = *(data++); 809 SPLITCOLOUR16(pixel, pc); 810 *(out++) = pc.blue; 811 *(out++) = pc.green; 812 *(out++) = pc.red; 813 ) 814 /* *INDENT-ON* */ 815 } 816 else if (This->xwin.xserver_be) 817 { 818 if (This->xwin.host_be) 819 { 820 while (out < end) 821 { 822 pixel = *(data++); 823 BSWAP16(pixel); 824 SPLITCOLOUR16(pixel, pc); 825 value = MAKECOLOUR(pc); 826 BOUT24(out, value); 827 } 828 } 829 else 830 { 831 while (out < end) 832 { 833 pixel = *(data++); 834 SPLITCOLOUR16(pixel, pc); 835 value = MAKECOLOUR(pc); 836 BOUT24(out, value); 837 } 838 } 839 } 840 else 841 { 842 if (This->xwin.host_be) 843 { 844 while (out < end) 845 { 846 pixel = *(data++); 847 BSWAP16(pixel); 848 SPLITCOLOUR16(pixel, pc); 849 value = MAKECOLOUR(pc); 850 LOUT24(out, value); 851 } 852 } 853 else 854 { 855 while (out < end) 856 { 857 pixel = *(data++); 858 SPLITCOLOUR16(pixel, pc); 859 value = MAKECOLOUR(pc); 860 LOUT24(out, value); 861 } 862 } 863 } 864 } 865 866 static void 867 translate16to32(RDPCLIENT * This, const uint16 * data, uint8 * out, uint8 * end) 868 { 869 uint16 pixel; 870 uint32 value; 871 PixelColour pc; 872 873 if (This->xwin.compatible_arch) 874 { 875 /* *INDENT-OFF* */ 876 REPEAT4 877 ( 878 pixel = *(data++); 879 SPLITCOLOUR16(pixel, pc); 880 *(out++) = pc.blue; 881 *(out++) = pc.green; 882 *(out++) = pc.red; 883 *(out++) = 0; 884 ) 885 /* *INDENT-ON* */ 886 } 887 else if (This->xwin.xserver_be) 888 { 889 if (This->xwin.host_be) 890 { 891 while (out < end) 892 { 893 pixel = *(data++); 894 BSWAP16(pixel); 895 SPLITCOLOUR16(pixel, pc); 896 value = MAKECOLOUR(pc); 897 BOUT32(out, value); 898 } 899 } 900 else 901 { 902 while (out < end) 903 { 904 pixel = *(data++); 905 SPLITCOLOUR16(pixel, pc); 906 value = MAKECOLOUR(pc); 907 BOUT32(out, value); 908 } 909 } 910 } 911 else 912 { 913 if (This->xwin.host_be) 914 { 915 while (out < end) 916 { 917 pixel = *(data++); 918 BSWAP16(pixel); 919 SPLITCOLOUR16(pixel, pc); 920 value = MAKECOLOUR(pc); 921 LOUT32(out, value); 922 } 923 } 924 else 925 { 926 while (out < end) 927 { 928 pixel = *(data++); 929 SPLITCOLOUR16(pixel, pc); 930 value = MAKECOLOUR(pc); 931 LOUT32(out, value); 932 } 933 } 934 } 935 } 936 937 static void 938 translate24to16(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end) 939 { 940 uint32 pixel = 0; 941 uint16 value; 942 PixelColour pc; 943 944 while (out < end) 945 { 946 pixel = *(data++) << 16; 947 pixel |= *(data++) << 8; 948 pixel |= *(data++); 949 SPLITCOLOUR24(pixel, pc); 950 value = MAKECOLOUR(pc); 951 if (This->xwin.xserver_be) 952 { 953 BOUT16(out, value); 954 } 955 else 956 { 957 LOUT16(out, value); 958 } 959 } 960 } 961 962 static void 963 translate24to24(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end) 964 { 965 uint32 pixel; 966 uint32 value; 967 PixelColour pc; 968 969 if (This->xwin.xserver_be) 970 { 971 while (out < end) 972 { 973 pixel = *(data++) << 16; 974 pixel |= *(data++) << 8; 975 pixel |= *(data++); 976 SPLITCOLOUR24(pixel, pc); 977 value = MAKECOLOUR(pc); 978 BOUT24(out, value); 979 } 980 } 981 else 982 { 983 while (out < end) 984 { 985 pixel = *(data++) << 16; 986 pixel |= *(data++) << 8; 987 pixel |= *(data++); 988 SPLITCOLOUR24(pixel, pc); 989 value = MAKECOLOUR(pc); 990 LOUT24(out, value); 991 } 992 } 993 } 994 995 static void 996 translate24to32(RDPCLIENT * This, const uint8 * data, uint8 * out, uint8 * end) 997 { 998 uint32 pixel; 999 uint32 value; 1000 PixelColour pc; 1001 1002 if (This->xwin.compatible_arch) 1003 { 1004 /* *INDENT-OFF* */ 1005 #ifdef NEED_ALIGN 1006 REPEAT4 1007 ( 1008 *(out++) = *(data++); 1009 *(out++) = *(data++); 1010 *(out++) = *(data++); 1011 *(out++) = 0; 1012 ) 1013 #else 1014 REPEAT4 1015 ( 1016 /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */ 1017 *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16); 1018 out += 4; 1019 data += 3; 1020 ) 1021 #endif 1022 /* *INDENT-ON* */ 1023 } 1024 else if (This->xwin.xserver_be) 1025 { 1026 while (out < end) 1027 { 1028 pixel = *(data++) << 16; 1029 pixel |= *(data++) << 8; 1030 pixel |= *(data++); 1031 SPLITCOLOUR24(pixel, pc); 1032 value = MAKECOLOUR(pc); 1033 BOUT32(out, value); 1034 } 1035 } 1036 else 1037 { 1038 while (out < end) 1039 { 1040 pixel = *(data++) << 16; 1041 pixel |= *(data++) << 8; 1042 pixel |= *(data++); 1043 SPLITCOLOUR24(pixel, pc); 1044 value = MAKECOLOUR(pc); 1045 LOUT32(out, value); 1046 } 1047 } 1048 } 1049 1050 static uint8 * 1051 translate_image(RDPCLIENT * This, int width, int height, uint8 * data) 1052 { 1053 int size; 1054 uint8 *out; 1055 uint8 *end; 1056 1057 /* 1058 If RDP depth and X Visual depths match, 1059 and arch(endian) matches, no need to translate: 1060 just return data. 1061 Note: select_visual should've already ensured g_no_translate 1062 is only set for compatible depths, but the RDP depth might've 1063 changed during connection negotiations. 1064 */ 1065 if (This->xwin.no_translate_image) 1066 { 1067 if ((This->xwin.depth == 15 && This->server_depth == 15) || 1068 (This->xwin.depth == 16 && This->server_depth == 16) || 1069 (This->xwin.depth == 24 && This->server_depth == 24)) 1070 return data; 1071 } 1072 1073 size = width * height * (This->xwin.bpp / 8); 1074 out = (uint8 *) xmalloc(size); 1075 end = out + size; 1076 1077 switch (This->server_depth) 1078 { 1079 case 24: 1080 switch (This->xwin.bpp) 1081 { 1082 case 32: 1083 translate24to32(This, data, out, end); 1084 break; 1085 case 24: 1086 translate24to24(This, data, out, end); 1087 break; 1088 case 16: 1089 translate24to16(This, data, out, end); 1090 break; 1091 } 1092 break; 1093 case 16: 1094 switch (This->xwin.bpp) 1095 { 1096 case 32: 1097 translate16to32(This, (uint16 *) data, out, end); 1098 break; 1099 case 24: 1100 translate16to24(This, (uint16 *) data, out, end); 1101 break; 1102 case 16: 1103 translate16to16(This, (uint16 *) data, out, end); 1104 break; 1105 } 1106 break; 1107 case 15: 1108 switch (This->xwin.bpp) 1109 { 1110 case 32: 1111 translate15to32(This, (uint16 *) data, out, end); 1112 break; 1113 case 24: 1114 translate15to24(This, (uint16 *) data, out, end); 1115 break; 1116 case 16: 1117 translate15to16(This, (uint16 *) data, out, end); 1118 break; 1119 } 1120 break; 1121 case 8: 1122 switch (This->xwin.bpp) 1123 { 1124 case 8: 1125 translate8to8(This, data, out, end); 1126 break; 1127 case 16: 1128 translate8to16(This, data, out, end); 1129 break; 1130 case 24: 1131 translate8to24(This, data, out, end); 1132 break; 1133 case 32: 1134 translate8to32(This, data, out, end); 1135 break; 1136 } 1137 break; 1138 } 1139 return out; 1140 } 1141 1142 BOOL 1143 get_key_state(RDPCLIENT * This, unsigned int state, uint32 keysym) 1144 { 1145 int modifierpos, key, keysymMask = 0; 1146 int offset; 1147 1148 KeyCode keycode = XKeysymToKeycode(This->display, keysym); 1149 1150 if (keycode == NoSymbol) 1151 return False; 1152 1153 for (modifierpos = 0; modifierpos < 8; modifierpos++) 1154 { 1155 offset = This->xwin.mod_map->max_keypermod * modifierpos; 1156 1157 for (key = 0; key < This->xwin.mod_map->max_keypermod; key++) 1158 { 1159 if (This->xwin.mod_map->modifiermap[offset + key] == keycode) 1160 keysymMask |= 1 << modifierpos; 1161 } 1162 } 1163 1164 return (state & keysymMask) ? True : False; 1165 } 1166 1167 static void 1168 calculate_shifts(uint32 mask, int *shift_r, int *shift_l) 1169 { 1170 *shift_l = ffs(mask) - 1; 1171 mask >>= *shift_l; 1172 *shift_r = 8 - ffs(mask & ~(mask >> 1)); 1173 } 1174 1175 /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask), 1176 calculates the bits-per-pixel of this channel (a.k.a. colour weight). 1177 */ 1178 static unsigned 1179 calculate_mask_weight(uint32 mask) 1180 { 1181 unsigned weight = 0; 1182 do 1183 { 1184 weight += (mask & 1); 1185 } 1186 while (mask >>= 1); 1187 return weight; 1188 } 1189 1190 static BOOL 1191 select_visual(RDPCLIENT * This) 1192 { 1193 XPixmapFormatValues *pfm; 1194 int pixmap_formats_count, visuals_count; 1195 XVisualInfo *vmatches = NULL; 1196 XVisualInfo template; 1197 int i; 1198 unsigned red_weight, blue_weight, green_weight; 1199 1200 red_weight = blue_weight = green_weight = 0; 1201 1202 if (This->server_depth == -1) 1203 { 1204 This->server_depth = DisplayPlanes(This->display, DefaultScreen(This->display)); 1205 } 1206 1207 pfm = XListPixmapFormats(This->display, &pixmap_formats_count); 1208 if (pfm == NULL) 1209 { 1210 error("Unable to get list of pixmap formats from display.\n"); 1211 XCloseDisplay(This->display); 1212 return False; 1213 } 1214 1215 /* Search for best TrueColor visual */ 1216 template.class = TrueColor; 1217 vmatches = XGetVisualInfo(This->display, VisualClassMask, &template, &visuals_count); 1218 This->xwin.visual = NULL; 1219 This->xwin.no_translate_image = False; 1220 This->xwin.compatible_arch = False; 1221 if (vmatches != NULL) 1222 { 1223 for (i = 0; i < visuals_count; ++i) 1224 { 1225 XVisualInfo *visual_info = &vmatches[i]; 1226 BOOL can_translate_to_bpp = False; 1227 int j; 1228 1229 /* Try to find a no-translation visual that'll 1230 allow us to use RDP bitmaps directly as ZPixmaps. */ 1231 if (!This->xwin.xserver_be && (((visual_info->depth == 15) && 1232 /* R5G5B5 */ 1233 (visual_info->red_mask == 0x7c00) && 1234 (visual_info->green_mask == 0x3e0) && 1235 (visual_info->blue_mask == 0x1f)) || 1236 ((visual_info->depth == 16) && 1237 /* R5G6B5 */ 1238 (visual_info->red_mask == 0xf800) && 1239 (visual_info->green_mask == 0x7e0) && 1240 (visual_info->blue_mask == 0x1f)) || 1241 ((visual_info->depth == 24) && 1242 /* R8G8B8 */ 1243 (visual_info->red_mask == 0xff0000) && 1244 (visual_info->green_mask == 0xff00) && 1245 (visual_info->blue_mask == 0xff)))) 1246 { 1247 This->xwin.visual = visual_info->visual; 1248 This->xwin.depth = visual_info->depth; 1249 This->xwin.compatible_arch = !This->xwin.host_be; 1250 This->xwin.no_translate_image = (visual_info->depth == This->server_depth); 1251 if (This->xwin.no_translate_image) 1252 /* We found the best visual */ 1253 break; 1254 } 1255 else 1256 { 1257 This->xwin.compatible_arch = False; 1258 } 1259 1260 if (visual_info->depth > 24) 1261 { 1262 /* Avoid 32-bit visuals and likes like the plague. 1263 They're either untested or proven to work bad 1264 (e.g. nvidia's Composite 32-bit visual). 1265 Most implementation offer a 24-bit visual anyway. */ 1266 continue; 1267 } 1268 1269 /* Only care for visuals, for whose BPPs (not depths!) 1270 we have a translateXtoY function. */ 1271 for (j = 0; j < pixmap_formats_count; ++j) 1272 { 1273 if (pfm[j].depth == visual_info->depth) 1274 { 1275 if ((pfm[j].bits_per_pixel == 16) || 1276 (pfm[j].bits_per_pixel == 24) || 1277 (pfm[j].bits_per_pixel == 32)) 1278 { 1279 can_translate_to_bpp = True; 1280 } 1281 break; 1282 } 1283 } 1284 1285 /* Prefer formats which have the most colour depth. 1286 We're being truly aristocratic here, minding each 1287 weight on its own. */ 1288 if (can_translate_to_bpp) 1289 { 1290 unsigned vis_red_weight = 1291 calculate_mask_weight(visual_info->red_mask); 1292 unsigned vis_green_weight = 1293 calculate_mask_weight(visual_info->green_mask); 1294 unsigned vis_blue_weight = 1295 calculate_mask_weight(visual_info->blue_mask); 1296 if ((vis_red_weight >= red_weight) 1297 && (vis_green_weight >= green_weight) 1298 && (vis_blue_weight >= blue_weight)) 1299 { 1300 red_weight = vis_red_weight; 1301 green_weight = vis_green_weight; 1302 blue_weight = vis_blue_weight; 1303 This->xwin.visual = visual_info->visual; 1304 This->xwin.depth = visual_info->depth; 1305 } 1306 } 1307 } 1308 XFree(vmatches); 1309 } 1310 1311 if (This->xwin.visual != NULL) 1312 { 1313 This->owncolmap = False; 1314 calculate_shifts(This->xwin.visual->red_mask, &This->xwin.red_shift_r, &This->xwin.red_shift_l); 1315 calculate_shifts(This->xwin.visual->green_mask, &This->xwin.green_shift_r, &This->xwin.green_shift_l); 1316 calculate_shifts(This->xwin.visual->blue_mask, &This->xwin.blue_shift_r, &This->xwin.blue_shift_l); 1317 } 1318 else 1319 { 1320 template.class = PseudoColor; 1321 template.depth = 8; 1322 template.colormap_size = 256; 1323 vmatches = 1324 XGetVisualInfo(This->display, 1325 VisualClassMask | VisualDepthMask | VisualColormapSizeMask, 1326 &template, &visuals_count); 1327 if (vmatches == NULL) 1328 { 1329 error("No usable TrueColor or PseudoColor visuals on this display.\n"); 1330 XCloseDisplay(This->display); 1331 XFree(pfm); 1332 return False; 1333 } 1334 1335 /* we use a colourmap, so the default visual should do */ 1336 This->owncolmap = True; 1337 This->xwin.visual = vmatches[0].visual; 1338 This->xwin.depth = vmatches[0].depth; 1339 } 1340 1341 This->xwin.bpp = 0; 1342 for (i = 0; i < pixmap_formats_count; ++i) 1343 { 1344 XPixmapFormatValues *pf = &pfm[i]; 1345 if (pf->depth == This->xwin.depth) 1346 { 1347 This->xwin.bpp = pf->bits_per_pixel; 1348 1349 if (This->xwin.no_translate_image) 1350 { 1351 switch (This->server_depth) 1352 { 1353 case 15: 1354 case 16: 1355 if (This->xwin.bpp != 16) 1356 This->xwin.no_translate_image = False; 1357 break; 1358 case 24: 1359 /* Yes, this will force image translation 1360 on most modern servers which use 32 bits 1361 for R8G8B8. */ 1362 if (This->xwin.bpp != 24) 1363 This->xwin.no_translate_image = False; 1364 break; 1365 default: 1366 This->xwin.no_translate_image = False; 1367 break; 1368 } 1369 } 1370 1371 /* Pixmap formats list is a depth-to-bpp mapping -- 1372 there's just a single entry for every depth, 1373 so we can safely break here */ 1374 break; 1375 } 1376 } 1377 XFree(pfm); 1378 pfm = NULL; 1379 return True; 1380 } 1381 1382 /* 1383 static int 1384 error_handler(RDPCLIENT * This, Display * dpy, XErrorEvent * eev) 1385 { 1386 if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow)) 1387 { 1388 fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n"); 1389 fprintf(stderr, 1390 "This is most likely caused by a broken window manager (commonly KWin).\n"); 1391 return 0; 1392 } 1393 1394 return This->xwin.old_error_handler(dpy, eev); 1395 } 1396 */ 1397 1398 BOOL 1399 ui_init(RDPCLIENT * This) 1400 { 1401 int screen_num; 1402 1403 This->display = XOpenDisplay(NULL); 1404 if (This->display == NULL) 1405 { 1406 error("Failed to open display: %s\n", XDisplayName(NULL)); 1407 return False; 1408 } 1409 1410 { 1411 uint16 endianess_test = 1; 1412 This->xwin.host_be = !(BOOL) (*(uint8 *) (&endianess_test)); 1413 } 1414 1415 /*This->xwin.old_error_handler = XSetErrorHandler(error_handler);*/ 1416 This->xwin.xserver_be = (ImageByteOrder(This->display) == MSBFirst); 1417 screen_num = DefaultScreen(This->display); 1418 This->xwin.x_socket = ConnectionNumber(This->display); 1419 This->xwin.screen = ScreenOfDisplay(This->display, screen_num); 1420 This->xwin.depth = DefaultDepthOfScreen(This->xwin.screen); 1421 1422 if (!select_visual(This)) 1423 return False; 1424 1425 if (This->xwin.no_translate_image) 1426 { 1427 DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n")); 1428 } 1429 1430 if (This->server_depth > This->xwin.bpp) 1431 { 1432 warning("Remote desktop colour depth %d higher than display colour depth %d.\n", 1433 This->server_depth, This->xwin.bpp); 1434 } 1435 1436 DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n", 1437 This->server_depth, This->xwin.depth, This->xwin.bpp, This->xwin.xserver_be, This->xwin.host_be)); 1438 1439 if (!This->owncolmap) 1440 { 1441 This->xwin.xcolmap = 1442 XCreateColormap(This->display, RootWindowOfScreen(This->xwin.screen), This->xwin.visual, 1443 AllocNone); 1444 if (This->xwin.depth <= 8) 1445 warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", This->xwin.depth); 1446 } 1447 1448 if ((!This->ownbackstore) && (DoesBackingStore(This->xwin.screen) != Always)) 1449 { 1450 warning("External BackingStore not available. Using internal.\n"); 1451 This->ownbackstore = True; 1452 } 1453 1454 /* 1455 * Determine desktop size 1456 */ 1457 if (This->fullscreen) 1458 { 1459 This->width = WidthOfScreen(This->xwin.screen); 1460 This->height = HeightOfScreen(This->xwin.screen); 1461 This->xwin.using_full_workarea = True; 1462 } 1463 else if (This->width < 0) 1464 { 1465 /* Percent of screen */ 1466 if (-This->width >= 100) 1467 This->xwin.using_full_workarea = True; 1468 This->height = HeightOfScreen(This->xwin.screen) * (-This->width) / 100; 1469 This->width = WidthOfScreen(This->xwin.screen) * (-This->width) / 100; 1470 } 1471 else if (This->width == 0) 1472 { 1473 /* Fetch geometry from _NET_WORKAREA */ 1474 uint32 x, y, cx, cy; 1475 if (get_current_workarea(This, &x, &y, &cx, &cy) == 0) 1476 { 1477 This->width = cx; 1478 This->height = cy; 1479 This->xwin.using_full_workarea = True; 1480 } 1481 else 1482 { 1483 warning("Failed to get workarea: probably your window manager does not support extended hints\n"); 1484 This->width = WidthOfScreen(This->xwin.screen); 1485 This->height = HeightOfScreen(This->xwin.screen); 1486 } 1487 } 1488 1489 /* make sure width is a multiple of 4 */ 1490 This->width = (This->width + 3) & ~3; 1491 1492 This->xwin.mod_map = XGetModifierMapping(This->display); 1493 1494 xkeymap_init(This); 1495 1496 if (This->enable_compose) 1497 This->xwin.IM = XOpenIM(This->display, NULL, NULL, NULL); 1498 1499 xclip_init(This); 1500 ewmh_init(This); 1501 if (This->seamless_rdp) 1502 seamless_init(This); 1503 1504 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", This->server_depth, This->xwin.bpp, This->xwin.depth)); 1505 1506 return True; 1507 } 1508 1509 void 1510 ui_deinit(RDPCLIENT * This) 1511 { 1512 while (This->xwin.seamless_windows) 1513 { 1514 XDestroyWindow(This->display, This->xwin.seamless_windows->wnd); 1515 sw_remove_window(This, This->xwin.seamless_windows); 1516 } 1517 1518 xclip_deinit(This); 1519 1520 if (This->xwin.IM != NULL) 1521 XCloseIM(This->xwin.IM); 1522 1523 if (This->xwin.null_cursor != NULL) 1524 ui_destroy_cursor(This, This->xwin.null_cursor); 1525 1526 XFreeModifiermap(This->xwin.mod_map); 1527 1528 if (This->ownbackstore) 1529 XFreePixmap(This->display, This->xwin.backstore); 1530 1531 XFreeGC(This->display, This->xwin.gc); 1532 XCloseDisplay(This->display); 1533 This->display = NULL; 1534 } 1535 1536 1537 static void 1538 get_window_attribs(RDPCLIENT * This, XSetWindowAttributes * attribs) 1539 { 1540 attribs->background_pixel = BlackPixelOfScreen(This->xwin.screen); 1541 attribs->background_pixel = WhitePixelOfScreen(This->xwin.screen); 1542 attribs->border_pixel = WhitePixelOfScreen(This->xwin.screen); 1543 attribs->backing_store = This->ownbackstore ? NotUseful : Always; 1544 attribs->override_redirect = This->fullscreen; 1545 attribs->colormap = This->xwin.xcolmap; 1546 } 1547 1548 static void 1549 get_input_mask(RDPCLIENT * This, long *input_mask) 1550 { 1551 *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | 1552 VisibilityChangeMask | FocusChangeMask | StructureNotifyMask; 1553 1554 if (This->sendmotion) 1555 *input_mask |= PointerMotionMask; 1556 if (This->ownbackstore) 1557 *input_mask |= ExposureMask; 1558 if (This->fullscreen || This->grab_keyboard) 1559 *input_mask |= EnterWindowMask; 1560 if (This->grab_keyboard) 1561 *input_mask |= LeaveWindowMask; 1562 } 1563 1564 BOOL 1565 ui_create_window(RDPCLIENT * This) 1566 { 1567 uint8 null_pointer_mask[1] = { 0x80 }; 1568 uint8 null_pointer_data[24] = { 0x00 }; 1569 1570 XSetWindowAttributes attribs; 1571 XClassHint *classhints; 1572 XSizeHints *sizehints; 1573 int wndwidth, wndheight; 1574 long input_mask, ic_input_mask; 1575 XEvent xevent; 1576 1577 wndwidth = This->fullscreen ? WidthOfScreen(This->xwin.screen) : This->width; 1578 wndheight = This->fullscreen ? HeightOfScreen(This->xwin.screen) : This->height; 1579 1580 /* Handle -x-y portion of geometry string */ 1581 if (This->xpos < 0 || (This->xpos == 0 && (This->pos & 2))) 1582 This->xpos = WidthOfScreen(This->xwin.screen) + This->xpos - This->width; 1583 if (This->ypos < 0 || (This->ypos == 0 && (This->pos & 4))) 1584 This->ypos = HeightOfScreen(This->xwin.screen) + This->ypos - This->height; 1585 1586 get_window_attribs(This, &attribs); 1587 1588 This->wnd = XCreateWindow(This->display, RootWindowOfScreen(This->xwin.screen), This->xpos, This->ypos, wndwidth, 1589 wndheight, 0, This->xwin.depth, InputOutput, This->xwin.visual, 1590 CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | 1591 CWBorderPixel, &attribs); 1592 1593 if (This->xwin.gc == NULL) 1594 { 1595 This->xwin.gc = XCreateGC(This->display, This->wnd, 0, NULL); 1596 ui_reset_clip(This); 1597 } 1598 1599 if (This->xwin.create_bitmap_gc == NULL) 1600 This->xwin.create_bitmap_gc = XCreateGC(This->display, This->wnd, 0, NULL); 1601 1602 if ((This->ownbackstore) && (This->xwin.backstore == 0)) 1603 { 1604 This->xwin.backstore = XCreatePixmap(This->display, This->wnd, This->width, This->height, This->xwin.depth); 1605 1606 /* clear to prevent rubbish being exposed at startup */ 1607 XSetForeground(This->display, This->xwin.gc, BlackPixelOfScreen(This->xwin.screen)); 1608 XFillRectangle(This->display, This->xwin.backstore, This->xwin.gc, 0, 0, This->width, This->height); 1609 } 1610 1611 XStoreName(This->display, This->wnd, This->title); 1612 1613 if (This->hide_decorations) 1614 mwm_hide_decorations(This, This->wnd); 1615 1616 classhints = XAllocClassHint(); 1617 if (classhints != NULL) 1618 { 1619 classhints->res_name = classhints->res_class = "rdesktop"; 1620 XSetClassHint(This->display, This->wnd, classhints); 1621 XFree(classhints); 1622 } 1623 1624 sizehints = XAllocSizeHints(); 1625 if (sizehints) 1626 { 1627 sizehints->flags = PMinSize | PMaxSize; 1628 if (This->pos) 1629 sizehints->flags |= PPosition; 1630 sizehints->min_width = sizehints->max_width = This->width; 1631 sizehints->min_height = sizehints->max_height = This->height; 1632 XSetWMNormalHints(This->display, This->wnd, sizehints); 1633 XFree(sizehints); 1634 } 1635 1636 if (This->embed_wnd) 1637 { 1638 XReparentWindow(This->display, This->wnd, (Window) This->embed_wnd, 0, 0); 1639 } 1640 1641 get_input_mask(This, &input_mask); 1642 1643 if (This->xwin.IM != NULL) 1644 { 1645 This->xwin.IC = XCreateIC(This->xwin.IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), 1646 XNClientWindow, This->wnd, XNFocusWindow, This->wnd, NULL); 1647 1648 if ((This->xwin.IC != NULL) 1649 && (XGetICValues(This->xwin.IC, XNFilterEvents, &ic_input_mask, NULL) == NULL)) 1650 input_mask |= ic_input_mask; 1651 } 1652 1653 XSelectInput(This->display, This->wnd, input_mask); 1654 XMapWindow(This->display, This->wnd); 1655 1656 /* wait for VisibilityNotify */ 1657 do 1658 { 1659 XMaskEvent(This->display, VisibilityChangeMask, &xevent); 1660 } 1661 while (xevent.type != VisibilityNotify); 1662 This->Unobscured = xevent.xvisibility.state == VisibilityUnobscured; 1663 1664 This->xwin.focused = False; 1665 This->xwin.mouse_in_wnd = False; 1666 1667 /* handle the WM_DELETE_WINDOW protocol */ 1668 This->xwin.protocol_atom = XInternAtom(This->display, "WM_PROTOCOLS", True); 1669 This->xwin.kill_atom = XInternAtom(This->display, "WM_DELETE_WINDOW", True); 1670 XSetWMProtocols(This->display, This->wnd, &This->xwin.kill_atom, 1); 1671 1672 /* create invisible 1x1 cursor to be used as null cursor */ 1673 if (This->xwin.null_cursor == NULL) 1674 This->xwin.null_cursor = ui_create_cursor(This, 0, 0, 1, 1, null_pointer_mask, null_pointer_data); 1675 1676 return True; 1677 } 1678 1679 void 1680 ui_resize_window(RDPCLIENT * This) 1681 { 1682 XSizeHints *sizehints; 1683 Pixmap bs; 1684 1685 sizehints = XAllocSizeHints(); 1686 if (sizehints) 1687 { 1688 sizehints->flags = PMinSize | PMaxSize; 1689 sizehints->min_width = sizehints->max_width = This->width; 1690 sizehints->min_height = sizehints->max_height = This->height; 1691 XSetWMNormalHints(This->display, This->wnd, sizehints); 1692 XFree(sizehints); 1693 } 1694 1695 if (!(This->fullscreen || This->embed_wnd)) 1696 { 1697 XResizeWindow(This->display, This->wnd, This->width, This->height); 1698 } 1699 1700 /* create new backstore pixmap */ 1701 if (This->xwin.backstore != 0) 1702 { 1703 bs = XCreatePixmap(This->display, This->wnd, This->width, This->height, This->xwin.depth); 1704 XSetForeground(This->display, This->xwin.gc, BlackPixelOfScreen(This->xwin.screen)); 1705 XFillRectangle(This->display, bs, This->xwin.gc, 0, 0, This->width, This->height); 1706 XCopyArea(This->display, This->xwin.backstore, bs, This->xwin.gc, 0, 0, This->width, This->height, 0, 0); 1707 XFreePixmap(This->display, This->xwin.backstore); 1708 This->xwin.backstore = bs; 1709 } 1710 } 1711 1712 void 1713 ui_destroy_window(RDPCLIENT * This) 1714 { 1715 if (This->xwin.IC != NULL) 1716 XDestroyIC(This->xwin.IC); 1717 1718 XDestroyWindow(This->display, This->wnd); 1719 } 1720 1721 void 1722 xwin_toggle_fullscreen(RDPCLIENT * This) 1723 { 1724 Pixmap contents = 0; 1725 1726 if (This->xwin.seamless_active) 1727 /* Turn off SeamlessRDP mode */ 1728 ui_seamless_toggle(This); 1729 1730 if (!This->ownbackstore) 1731 { 1732 /* need to save contents of window */ 1733 contents = XCreatePixmap(This->display, This->wnd, This->width, This->height, This->xwin.depth); 1734 XCopyArea(This->display, This->wnd, contents, This->xwin.gc, 0, 0, This->width, This->height, 0, 0); 1735 } 1736 1737 ui_destroy_window(This); 1738 This->fullscreen = !This->fullscreen; 1739 ui_create_window(This); 1740 1741 XDefineCursor(This->display, This->wnd, This->xwin.current_cursor); 1742 1743 if (!This->ownbackstore) 1744 { 1745 XCopyArea(This->display, contents, This->wnd, This->xwin.gc, 0, 0, This->width, This->height, 0, 0); 1746 XFreePixmap(This->display, contents); 1747 } 1748 } 1749 1750 static void 1751 handle_button_event(RDPCLIENT * This, XEvent xevent, BOOL down) 1752 { 1753 uint16 button, flags = 0; 1754 This->last_gesturetime = xevent.xbutton.time; 1755 button = xkeymap_translate_button(xevent.xbutton.button); 1756 if (button == 0) 1757 return; 1758 1759 if (down) 1760 flags = MOUSE_FLAG_DOWN; 1761 1762 /* Stop moving window when button is released, regardless of cursor position */ 1763 if (This->xwin.moving_wnd && (xevent.type == ButtonRelease)) 1764 This->xwin.moving_wnd = False; 1765 1766 /* If win_button_sizee is nonzero, enable single app mode */ 1767 if (xevent.xbutton.y < This->win_button_size) 1768 { 1769 /* Check from right to left: */ 1770 if (xevent.xbutton.x >= This->width - This->win_button_size) 1771 { 1772 /* The close button, continue */ 1773 ; 1774 } 1775 else if (xevent.xbutton.x >= This->width - This->win_button_size * 2) 1776 { 1777 /* The maximize/restore button. Do not send to 1778 server. It might be a good idea to change the 1779 cursor or give some other visible indication 1780 that rdesktop inhibited this click */ 1781 if (xevent.type == ButtonPress) 1782 return; 1783 } 1784 else if (xevent.xbutton.x >= This->width - This->win_button_size * 3) 1785 { 1786 /* The minimize button. Iconify window. */ 1787 if (xevent.type == ButtonRelease) 1788 { 1789 /* Release the mouse button outside the minimize button, to prevent the 1790 actual minimazation to happen */ 1791 rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE, button, 1, 1); 1792 XIconifyWindow(This->display, This->wnd, DefaultScreen(This->display)); 1793 return; 1794 } 1795 } 1796 else if (xevent.xbutton.x <= This->win_button_size) 1797 { 1798 /* The system menu. Ignore. */ 1799 if (xevent.type == ButtonPress) 1800 return; 1801 } 1802 else 1803 { 1804 /* The title bar. */ 1805 if (xevent.type == ButtonPress) 1806 { 1807 if (!This->fullscreen && This->hide_decorations && !This->xwin.using_full_workarea) 1808 { 1809 This->xwin.moving_wnd = True; 1810 This->xwin.move_x_offset = xevent.xbutton.x; 1811 This->xwin.move_y_offset = xevent.xbutton.y; 1812 } 1813 return; 1814 } 1815 } 1816 } 1817 1818 if (xevent.xmotion.window == This->wnd) 1819 { 1820 rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE, 1821 flags | button, xevent.xbutton.x, xevent.xbutton.y); 1822 } 1823 else 1824 { 1825 /* SeamlessRDP */ 1826 rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE, 1827 flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root); 1828 } 1829 } 1830 1831 1832 /* Process events in Xlib queue 1833 Returns 0 after user quit, 1 otherwise */ 1834 static int 1835 xwin_process_events(RDPCLIENT * This) 1836 { 1837 XEvent xevent; 1838 KeySym keysym; 1839 uint32 ev_time; 1840 char str[256]; 1841 Status status; 1842 int events = 0; 1843 seamless_window *sw; 1844 1845 while ((XPending(This->display) > 0) && events++ < 20) 1846 { 1847 XNextEvent(This->display, &xevent); 1848 1849 if ((This->xwin.IC != NULL) && (XFilterEvent(&xevent, None) == True)) 1850 { 1851 DEBUG_KBD(("Filtering event\n")); 1852 continue; 1853 } 1854 1855 switch (xevent.type) 1856 { 1857 case VisibilityNotify: 1858 if (xevent.xvisibility.window == This->wnd) 1859 This->Unobscured = 1860 xevent.xvisibility.state == VisibilityUnobscured; 1861 1862 break; 1863 case ClientMessage: 1864 /* the window manager told us to quit */ 1865 if ((xevent.xclient.message_type == This->xwin.protocol_atom) 1866 && ((Atom) xevent.xclient.data.l[0] == This->xwin.kill_atom)) 1867 /* Quit */ 1868 return 0; 1869 break; 1870 1871 case KeyPress: 1872 This->last_gesturetime = xevent.xkey.time; 1873 if (This->xwin.IC != NULL) 1874 /* Multi_key compatible version */ 1875 { 1876 XmbLookupString(This->xwin.IC, 1877 &xevent.xkey, str, sizeof(str), &keysym, 1878 &status); 1879 if (!((status == XLookupKeySym) || (status == XLookupBoth))) 1880 { 1881 error("XmbLookupString failed with status 0x%x\n", 1882 status); 1883 break; 1884 } 1885 } 1886 else 1887 { 1888 /* Plain old XLookupString */ 1889 DEBUG_KBD(("\nNo input context, using XLookupString\n")); 1890 XLookupString((XKeyEvent *) & xevent, 1891 str, sizeof(str), &keysym, NULL); 1892 } 1893 1894 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym, 1895 get_ksname(keysym))); 1896 1897 ev_time = time(NULL); 1898 if (handle_special_keys(This, keysym, xevent.xkey.state, ev_time, True)) 1899 break; 1900 1901 xkeymap_send_keys(This, keysym, xevent.xkey.keycode, xevent.xkey.state, 1902 ev_time, True, 0); 1903 break; 1904 1905 case KeyRelease: 1906 This->last_gesturetime = xevent.xkey.time; 1907 XLookupString((XKeyEvent *) & xevent, str, 1908 sizeof(str), &keysym, NULL); 1909 1910 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym, 1911 get_ksname(keysym))); 1912 1913 ev_time = time(NULL); 1914 if (handle_special_keys(This, keysym, xevent.xkey.state, ev_time, False)) 1915 break; 1916 1917 xkeymap_send_keys(This, keysym, xevent.xkey.keycode, xevent.xkey.state, 1918 ev_time, False, 0); 1919 break; 1920 1921 case ButtonPress: 1922 handle_button_event(This, xevent, True); 1923 break; 1924 1925 case ButtonRelease: 1926 handle_button_event(This, xevent, False); 1927 break; 1928 1929 case MotionNotify: 1930 if (This->xwin.moving_wnd) 1931 { 1932 XMoveWindow(This->display, This->wnd, 1933 xevent.xmotion.x_root - This->xwin.move_x_offset, 1934 xevent.xmotion.y_root - This->xwin.move_y_offset); 1935 break; 1936 } 1937 1938 if (This->fullscreen && !This->xwin.focused) 1939 XSetInputFocus(This->display, This->wnd, RevertToPointerRoot, 1940 CurrentTime); 1941 1942 if (xevent.xmotion.window == This->wnd) 1943 { 1944 rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, 1945 xevent.xmotion.x, xevent.xmotion.y); 1946 } 1947 else 1948 { 1949 /* SeamlessRDP */ 1950 rdp_send_input(This, time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, 1951 xevent.xmotion.x_root, 1952 xevent.xmotion.y_root); 1953 } 1954 break; 1955 1956 case FocusIn: 1957 if (xevent.xfocus.mode == NotifyGrab) 1958 break; 1959 This->xwin.focused = True; 1960 reset_modifier_keys(This); 1961 if (This->grab_keyboard && This->xwin.mouse_in_wnd) 1962 XGrabKeyboard(This->display, This->wnd, True, 1963 GrabModeAsync, GrabModeAsync, CurrentTime); 1964 1965 sw = sw_get_window_by_wnd(This, xevent.xfocus.window); 1966 if (!sw) 1967 break; 1968 1969 if (sw->id != This->xwin.seamless_focused) 1970 { 1971 seamless_send_focus(This, sw->id, 0); 1972 This->xwin.seamless_focused = sw->id; 1973 } 1974 break; 1975 1976 case FocusOut: 1977 if (xevent.xfocus.mode == NotifyUngrab) 1978 break; 1979 This->xwin.focused = False; 1980 if (xevent.xfocus.mode == NotifyWhileGrabbed) 1981 XUngrabKeyboard(This->display, CurrentTime); 1982 break; 1983 1984 case EnterNotify: 1985 /* we only register for this event when in fullscreen mode */ 1986 /* or grab_keyboard */ 1987 This->xwin.mouse_in_wnd = True; 1988 if (This->fullscreen) 1989 { 1990 XSetInputFocus(This->display, This->wnd, RevertToPointerRoot, 1991 CurrentTime); 1992 break; 1993 } 1994 if (This->xwin.focused) 1995 XGrabKeyboard(This->display, This->wnd, True, 1996 GrabModeAsync, GrabModeAsync, CurrentTime); 1997 break; 1998 1999 case LeaveNotify: 2000 /* we only register for this event when grab_keyboard */ 2001 This->xwin.mouse_in_wnd = False; 2002 XUngrabKeyboard(This->display, CurrentTime); 2003 break; 2004 2005 case Expose: 2006 if (xevent.xexpose.window == This->wnd) 2007 { 2008 XCopyArea(This->display, This->xwin.backstore, xevent.xexpose.window, 2009 This->xwin.gc, 2010 xevent.xexpose.x, xevent.xexpose.y, 2011 xevent.xexpose.width, xevent.xexpose.height, 2012 xevent.xexpose.x, xevent.xexpose.y); 2013 } 2014 else 2015 { 2016 sw = sw_get_window_by_wnd(This, xevent.xexpose.window); 2017 if (!sw) 2018 break; 2019 XCopyArea(This->display, This->xwin.backstore, 2020 xevent.xexpose.window, This->xwin.gc, 2021 xevent.xexpose.x + sw->xoffset, 2022 xevent.xexpose.y + sw->yoffset, 2023 xevent.xexpose.width, 2024 xevent.xexpose.height, xevent.xexpose.x, 2025 xevent.xexpose.y); 2026 } 2027 2028 break; 2029 2030 case MappingNotify: 2031 /* Refresh keyboard mapping if it has changed. This is important for 2032 Xvnc, since it allocates keycodes dynamically */ 2033 if (xevent.xmapping.request == MappingKeyboard 2034 || xevent.xmapping.request == MappingModifier) 2035 XRefreshKeyboardMapping(&xevent.xmapping); 2036 2037 if (xevent.xmapping.request == MappingModifier) 2038 { 2039 XFreeModifiermap(This->xwin.mod_map); 2040 This->xwin.mod_map = XGetModifierMapping(This->display); 2041 } 2042 break; 2043 2044 /* clipboard stuff */ 2045 case SelectionNotify: 2046 xclip_handle_SelectionNotify(This, &xevent.xselection); 2047 break; 2048 case SelectionRequest: 2049 xclip_handle_SelectionRequest(This, &xevent.xselectionrequest); 2050 break; 2051 case SelectionClear: 2052 xclip_handle_SelectionClear(This); 2053 break; 2054 case PropertyNotify: 2055 xclip_handle_PropertyNotify(This, &xevent.xproperty); 2056 if (xevent.xproperty.window == This->wnd) 2057 break; 2058 if (xevent.xproperty.window == DefaultRootWindow(This->display)) 2059 break; 2060 2061 /* seamless */ 2062 sw = sw_get_window_by_wnd(This, xevent.xproperty.window); 2063 if (!sw) 2064 break; 2065 2066 if ((xevent.xproperty.atom == This->net_wm_state_atom) 2067 && (xevent.xproperty.state == PropertyNewValue)) 2068 { 2069 sw->state = ewmh_get_window_state(This, sw->wnd); 2070 seamless_send_state(This, sw->id, sw->state, 0); 2071 } 2072 2073 if ((xevent.xproperty.atom == This->net_wm_desktop_atom) 2074 && (xevent.xproperty.state == PropertyNewValue)) 2075 { 2076 sw->desktop = ewmh_get_window_desktop(This, sw->wnd); 2077 sw_all_to_desktop(This, sw->wnd, sw->desktop); 2078 } 2079 2080 break; 2081 case MapNotify: 2082 if (!This->xwin.seamless_active) 2083 rdp_send_client_window_status(This, 1); 2084 break; 2085 case UnmapNotify: 2086 if (!This->xwin.seamless_active) 2087 rdp_send_client_window_status(This, 0); 2088 break; 2089 case ConfigureNotify: 2090 if (!This->xwin.seamless_active) 2091 break; 2092 2093 sw = sw_get_window_by_wnd(This, xevent.xconfigure.window); 2094 if (!sw) 2095 break; 2096 2097 gettimeofday(sw->position_timer, NULL); 2098 if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >= 2099 1000000) 2100 { 2101 sw->position_timer->tv_usec += 2102 SEAMLESSRDP_POSITION_TIMER - 1000000; 2103 sw->position_timer->tv_sec += 1; 2104 } 2105 else 2106 { 2107 sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER; 2108 } 2109 2110 sw_handle_restack(This, sw); 2111 break; 2112 } 2113 } 2114 /* Keep going */ 2115 return 1; 2116 } 2117 2118 /* Returns 0 after user quit, 1 otherwise */ 2119 int 2120 ui_select(RDPCLIENT * This, int rdp_socket) 2121 { 2122 int n; 2123 fd_set rfds, wfds; 2124 struct timeval tv; 2125 BOOL s_timeout = False; 2126 2127 while (True) 2128 { 2129 n = (rdp_socket > This->xwin.x_socket) ? rdp_socket : This->xwin.x_socket; 2130 /* Process any events already waiting */ 2131 if (!xwin_process_events(This)) 2132 /* User quit */ 2133 return 0; 2134 2135 if (This->xwin.seamless_active) 2136 sw_check_timers(This); 2137 2138 FD_ZERO(&rfds); 2139 FD_ZERO(&wfds); 2140 FD_SET(rdp_socket, &rfds); 2141 FD_SET(This->xwin.x_socket, &rfds); 2142 2143 #ifdef WITH_RDPSND 2144 /* FIXME: there should be an API for registering fds */ 2145 if (This->dsp_busy) 2146 { 2147 FD_SET(This->dsp_fd, &wfds); 2148 n = (This->dsp_fd > n) ? This->dsp_fd : n; 2149 } 2150 #endif 2151 /* default timeout */ 2152 tv.tv_sec = 60; 2153 tv.tv_usec = 0; 2154 2155 /* add redirection handles */ 2156 rdpdr_add_fds(This, &n, &rfds, &wfds, &tv, &s_timeout); 2157 seamless_select_timeout(This, &tv); 2158 2159 n++; 2160 2161 switch (select(n, &rfds, &wfds, NULL, &tv)) 2162 { 2163 case -1: 2164 error("select: %s\n", strerror(errno)); 2165 2166 case 0: 2167 /* Abort serial read calls */ 2168 if (s_timeout) 2169 rdpdr_check_fds(This, &rfds, &wfds, (BOOL) True); 2170 continue; 2171 } 2172 2173 rdpdr_check_fds(This, &rfds, &wfds, (BOOL) False); 2174 2175 if (FD_ISSET(rdp_socket, &rfds)) 2176 return 1; 2177 2178 #ifdef WITH_RDPSND 2179 if (This->dsp_busy && FD_ISSET(This->dsp_fd, &wfds)) 2180 wave_out_play(); 2181 #endif 2182 } 2183 } 2184 2185 void 2186 ui_move_pointer(RDPCLIENT * This, int x, int y) 2187 { 2188 XWarpPointer(This->display, This->wnd, This->wnd, 0, 0, 0, 0, x, y); 2189 } 2190 2191 HBITMAP 2192 ui_create_bitmap(RDPCLIENT * This, int width, int height, uint8 * data) 2193 { 2194 XImage *image; 2195 Pixmap bitmap; 2196 uint8 *tdata; 2197 int bitmap_pad; 2198 2199 if (This->server_depth == 8) 2200 { 2201 bitmap_pad = 8; 2202 } 2203 else 2204 { 2205 bitmap_pad = This->xwin.bpp; 2206 2207 if (This->xwin.bpp == 24) 2208 bitmap_pad = 32; 2209 } 2210 2211 tdata = (This->owncolmap ? data : translate_image(This, width, height, data)); 2212 bitmap = XCreatePixmap(This->display, This->wnd, width, height, This->xwin.depth); 2213 image = XCreateImage(This->display, This->xwin.visual, This->xwin.depth, ZPixmap, 0, 2214 (char *) tdata, width, height, bitmap_pad, 0); 2215 2216 XPutImage(This->display, bitmap, This->xwin.create_bitmap_gc, image, 0, 0, 0, 0, width, height); 2217 2218 XFree(image); 2219 if (tdata != data) 2220 xfree(tdata); 2221 return (HBITMAP) bitmap; 2222 } 2223 2224 void 2225 ui_paint_bitmap(RDPCLIENT * This, int x, int y, int cx, int cy, int width, int height, uint8 * data) 2226 { 2227 XImage *image; 2228 uint8 *tdata; 2229 int bitmap_pad; 2230 2231 if (This->server_depth == 8) 2232 { 2233 bitmap_pad = 8; 2234 } 2235 else 2236 { 2237 bitmap_pad = This->xwin.bpp; 2238 2239 if (This->xwin.bpp == 24) 2240 bitmap_pad = 32; 2241 } 2242 2243 tdata = (This->owncolmap ? data : translate_image(This, width, height, data)); 2244 image = XCreateImage(This->display, This->xwin.visual, This->xwin.depth, ZPixmap, 0, 2245 (char *) tdata, width, height, bitmap_pad, 0); 2246 2247 if (This->ownbackstore) 2248 { 2249 XPutImage(This->display, This->xwin.backstore, This->xwin.gc, image, 0, 0, x, y, cx, cy); 2250 XCopyArea(This->display, This->xwin.backstore, This->wnd, This->xwin.gc, x, y, cx, cy, x, y); 2251 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 2252 (This->display, This->xwin.backstore, sw->wnd, This->xwin.gc, x, y, cx, cy, 2253 x - sw->xoffset, y - sw->yoffset)); 2254 } 2255 else 2256 { 2257 XPutImage(This->display, This->wnd, This->xwin.gc, image, 0, 0, x, y, cx, cy); 2258 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 2259 (This->display, This->wnd, sw->wnd, This->xwin.gc, x, y, cx, cy, 2260 x - sw->xoffset, y - sw->yoffset)); 2261 } 2262 2263 XFree(image); 2264 if (tdata != data) 2265 xfree(tdata); 2266 } 2267 2268 void 2269 ui_destroy_bitmap(RDPCLIENT * This, HBITMAP bmp) 2270 { 2271 XFreePixmap(This->display, (Pixmap) bmp); 2272 } 2273 2274 HGLYPH 2275 ui_create_glyph(RDPCLIENT * This, int width, int height, const uint8 * data) 2276 { 2277 XImage *image; 2278 Pixmap bitmap; 2279 int scanline; 2280 2281 scanline = (width + 7) / 8; 2282 2283 bitmap = XCreatePixmap(This->display, This->wnd, width, height, 1); 2284 if (This->xwin.create_glyph_gc == 0) 2285 This->xwin.create_glyph_gc = XCreateGC(This->display, bitmap, 0, NULL); 2286 2287 image = XCreateImage(This->display, This->xwin.visual, 1, ZPixmap, 0, (char *) data, 2288 width, height, 8, scanline); 2289 image->byte_order = MSBFirst; 2290 image->bitmap_bit_order = MSBFirst; 2291 XInitImage(image); 2292 2293 XPutImage(This->display, bitmap, This->xwin.create_glyph_gc, image, 0, 0, 0, 0, width, height); 2294 2295 XFree(image); 2296 return (HGLYPH) bitmap; 2297 } 2298 2299 void 2300 ui_destroy_glyph(RDPCLIENT * This, HGLYPH glyph) 2301 { 2302 XFreePixmap(This->display, (Pixmap) glyph); 2303 } 2304 2305 HCURSOR 2306 ui_create_cursor(RDPCLIENT * This, unsigned int x, unsigned int y, int width, int height, 2307 uint8 * andmask, uint8 * xormask) 2308 { 2309 HGLYPH maskglyph, cursorglyph; 2310 XColor bg, fg; 2311 Cursor xcursor; 2312 uint8 *cursor, *pcursor; 2313 uint8 *mask, *pmask; 2314 uint8 nextbit; 2315 int scanline, offset; 2316 int i, j; 2317 2318 scanline = (width + 7) / 8; 2319 offset = scanline * height; 2320 2321 cursor = (uint8 *) xmalloc(offset); 2322 memset(cursor, 0, offset); 2323 2324 mask = (uint8 *) xmalloc(offset); 2325 memset(mask, 0, offset); 2326 2327 /* approximate AND and XOR masks with a monochrome X pointer */ 2328 for (i = 0; i < height; i++) 2329 { 2330 offset -= scanline; 2331 pcursor = &cursor[offset]; 2332 pmask = &mask[offset]; 2333 2334 for (j = 0; j < scanline; j++) 2335 { 2336 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1) 2337 { 2338 if (xormask[0] || xormask[1] || xormask[2]) 2339 { 2340 *pcursor |= (~(*andmask) & nextbit); 2341 *pmask |= nextbit; 2342 } 2343 else 2344 { 2345 *pcursor |= ((*andmask) & nextbit); 2346 *pmask |= (~(*andmask) & nextbit); 2347 } 2348 2349 xormask += 3; 2350 } 2351 2352 andmask++; 2353 pcursor++; 2354 pmask++; 2355 } 2356 } 2357 2358 fg.red = fg.blue = fg.green = 0xffff; 2359 bg.red = bg.blue = bg.green = 0x0000; 2360 fg.flags = bg.flags = DoRed | DoBlue | DoGreen; 2361 2362 cursorglyph = ui_create_glyph(This, width, height, cursor); 2363 maskglyph = ui_create_glyph(This, width, height, mask); 2364 2365 xcursor = 2366 XCreatePixmapCursor(This->display, (Pixmap) cursorglyph, 2367 (Pixmap) maskglyph, &fg, &bg, x, y); 2368 2369 ui_destroy_glyph(This, maskglyph); 2370 ui_destroy_glyph(This, cursorglyph); 2371 xfree(mask); 2372 xfree(cursor); 2373 return (HCURSOR) xcursor; 2374 } 2375 2376 void 2377 ui_set_cursor(RDPCLIENT * This, HCURSOR cursor) 2378 { 2379 This->xwin.current_cursor = (Cursor) cursor; 2380 XDefineCursor(This->display, This->wnd, This->xwin.current_cursor); 2381 ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (This->display, sw->wnd, This->xwin.current_cursor)); 2382 } 2383 2384 void 2385 ui_destroy_cursor(RDPCLIENT * This, HCURSOR cursor) 2386 { 2387 XFreeCursor(This->display, (Cursor) cursor); 2388 } 2389 2390 void 2391 ui_set_null_cursor(RDPCLIENT * This) 2392 { 2393 ui_set_cursor(This, This->xwin.null_cursor); 2394 } 2395 2396 #define MAKE_XCOLOR(xc,c) \ 2397 (xc)->red = ((c)->red << 8) | (c)->red; \ 2398 (xc)->green = ((c)->green << 8) | (c)->green; \ 2399 (xc)->blue = ((c)->blue << 8) | (c)->blue; \ 2400 (xc)->flags = DoRed | DoGreen | DoBlue; 2401 2402 2403 HCOLOURMAP 2404 ui_create_colourmap(RDPCLIENT * This, COLOURMAP * colours) 2405 { 2406 COLOURENTRY *entry; 2407 int i, ncolours = colours->ncolours; 2408 if (!This->owncolmap) 2409 { 2410 uint32 *map = (uint32 *) xmalloc(sizeof(*This->xwin.colmap) * ncolours); 2411 XColor xentry; 2412 XColor xc_cache[256]; 2413 uint32 colour; 2414 int colLookup = 256; 2415 for (i = 0; i < ncolours; i++) 2416 { 2417 entry = &colours->colours[i]; 2418 MAKE_XCOLOR(&xentry, entry); 2419 2420 if (XAllocColor(This->display, This->xwin.xcolmap, &xentry) == 0) 2421 { 2422 /* Allocation failed, find closest match. */ 2423 int j = 256; 2424 int nMinDist = 3 * 256 * 256; 2425 long nDist = nMinDist; 2426 2427 /* only get the colors once */ 2428 while (colLookup--) 2429 { 2430 xc_cache[colLookup].pixel = colLookup; 2431 xc_cache[colLookup].red = xc_cache[colLookup].green = 2432 xc_cache[colLookup].blue = 0; 2433 xc_cache[colLookup].flags = 0; 2434 XQueryColor(This->display, 2435 DefaultColormap(This->display, 2436 DefaultScreen(This->display)), 2437 &xc_cache[colLookup]); 2438 } 2439 colLookup = 0; 2440 2441 /* approximate the pixel */ 2442 while (j--) 2443 { 2444 if (xc_cache[j].flags) 2445 { 2446 nDist = ((long) (xc_cache[j].red >> 8) - 2447 (long) (xentry.red >> 8)) * 2448 ((long) (xc_cache[j].red >> 8) - 2449 (long) (xentry.red >> 8)) + 2450 ((long) (xc_cache[j].green >> 8) - 2451 (long) (xentry.green >> 8)) * 2452 ((long) (xc_cache[j].green >> 8) - 2453 (long) (xentry.green >> 8)) + 2454 ((long) (xc_cache[j].blue >> 8) - 2455 (long) (xentry.blue >> 8)) * 2456 ((long) (xc_cache[j].blue >> 8) - 2457 (long) (xentry.blue >> 8)); 2458 } 2459 if (nDist < nMinDist) 2460 { 2461 nMinDist = nDist; 2462 xentry.pixel = j; 2463 } 2464 } 2465 } 2466 colour = xentry.pixel; 2467 2468 /* update our cache */ 2469 if (xentry.pixel < 256) 2470 { 2471 xc_cache[xentry.pixel].red = xentry.red; 2472 xc_cache[xentry.pixel].green = xentry.green; 2473 xc_cache[xentry.pixel].blue = xentry.blue; 2474 2475 } 2476 2477 map[i] = colour; 2478 } 2479 return map; 2480 } 2481 else 2482 { 2483 XColor *xcolours, *xentry; 2484 Colormap map; 2485 2486 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours); 2487 for (i = 0; i < ncolours; i++) 2488 { 2489 entry = &colours->colours[i]; 2490 xentry = &xcolours[i]; 2491 xentry->pixel = i; 2492 MAKE_XCOLOR(xentry, entry); 2493 } 2494 2495 map = XCreateColormap(This->display, This->wnd, This->xwin.visual, AllocAll); 2496 XStoreColors(This->display, map, xcolours, ncolours); 2497 2498 xfree(xcolours); 2499 return (HCOLOURMAP) map; 2500 } 2501 } 2502 2503 void 2504 ui_destroy_colourmap(RDPCLIENT * This, HCOLOURMAP map) 2505 { 2506 if (!This->owncolmap) 2507 xfree(map); 2508 else 2509 XFreeColormap(This->display, (Colormap) map); 2510 } 2511 2512 void 2513 ui_set_colourmap(RDPCLIENT * This, HCOLOURMAP map) 2514 { 2515 if (!This->owncolmap) 2516 { 2517 if (This->xwin.colmap) 2518 xfree(This->xwin.colmap); 2519 2520 This->xwin.colmap = (uint32 *) map; 2521 } 2522 else 2523 { 2524 XSetWindowColormap(This->display, This->wnd, (Colormap) map); 2525 ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (This->display, sw->wnd, (Colormap) map)); 2526 } 2527 } 2528 2529 void 2530 ui_set_clip(RDPCLIENT * This, int x, int y, int cx, int cy) 2531 { 2532 This->xwin.clip_rectangle.x = x; 2533 This->xwin.clip_rectangle.y = y; 2534 This->xwin.clip_rectangle.width = cx; 2535 This->xwin.clip_rectangle.height = cy; 2536 XSetClipRectangles(This->display, This->xwin.gc, 0, 0, &This->xwin.clip_rectangle, 1, YXBanded); 2537 } 2538 2539 void 2540 ui_reset_clip(RDPCLIENT * This) 2541 { 2542 This->xwin.clip_rectangle.x = 0; 2543 This->xwin.clip_rectangle.y = 0; 2544 This->xwin.clip_rectangle.width = This->width; 2545 This->xwin.clip_rectangle.height = This->height; 2546 XSetClipRectangles(This->display, This->xwin.gc, 0, 0, &This->xwin.clip_rectangle, 1, YXBanded); 2547 } 2548 2549 void 2550 ui_bell(RDPCLIENT * This) 2551 { 2552 XBell(This->display, 0); 2553 } 2554 2555 void 2556 ui_destblt(RDPCLIENT * This, uint8 opcode, 2557 /* dest */ int x, int y, int cx, int cy) 2558 { 2559 SET_FUNCTION(opcode); 2560 FILL_RECTANGLE(x, y, cx, cy); 2561 RESET_FUNCTION(opcode); 2562 } 2563 2564 static const uint8 hatch_patterns[] = { 2565 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */ 2566 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */ 2567 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */ 2568 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */ 2569 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */ 2570 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */ 2571 }; 2572 2573 void 2574 ui_patblt(RDPCLIENT * This, uint8 opcode, 2575 /* dest */ int x, int y, int cx, int cy, 2576 /* brush */ BRUSH * brush, int bgcolour, int fgcolour) 2577 { 2578 Pixmap fill; 2579 uint8 i, ipattern[8]; 2580 2581 SET_FUNCTION(opcode); 2582 2583 switch (brush->style) 2584 { 2585 case 0: /* Solid */ 2586 SET_FOREGROUND(fgcolour); 2587 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); 2588 break; 2589 2590 case 2: /* Hatch */ 2591 fill = (Pixmap) ui_create_glyph(This, 8, 8, 2592 hatch_patterns + brush->pattern[0] * 8); 2593 SET_FOREGROUND(fgcolour); 2594 SET_BACKGROUND(bgcolour); 2595 XSetFillStyle(This->display, This->xwin.gc, FillOpaqueStippled); 2596 XSetStipple(This->display, This->xwin.gc, fill); 2597 XSetTSOrigin(This->display, This->xwin.gc, brush->xorigin, brush->yorigin); 2598 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); 2599 XSetFillStyle(This->display, This->xwin.gc, FillSolid); 2600 XSetTSOrigin(This->display, This->xwin.gc, 0, 0); 2601 ui_destroy_glyph(This, (HGLYPH) fill); 2602 break; 2603 2604 case 3: /* Pattern */ 2605 for (i = 0; i != 8; i++) 2606 ipattern[7 - i] = brush->pattern[i]; 2607 fill = (Pixmap) ui_create_glyph(This, 8, 8, ipattern); 2608 SET_FOREGROUND(bgcolour); 2609 SET_BACKGROUND(fgcolour); 2610 XSetFillStyle(This->display, This->xwin.gc, FillOpaqueStippled); 2611 XSetStipple(This->display, This->xwin.gc, fill); 2612 XSetTSOrigin(This->display, This->xwin.gc, brush->xorigin, brush->yorigin); 2613 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); 2614 XSetFillStyle(This->display, This->xwin.gc, FillSolid); 2615 XSetTSOrigin(This->display, This->xwin.gc, 0, 0); 2616 ui_destroy_glyph(This, (HGLYPH) fill); 2617 break; 2618 2619 default: 2620 unimpl("brush %d\n", brush->style); 2621 } 2622 2623 RESET_FUNCTION(opcode); 2624 2625 if (This->ownbackstore) 2626 XCopyArea(This->display, This->xwin.backstore, This->wnd, This->xwin.gc, x, y, cx, cy, x, y); 2627 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 2628 (This->display, This->ownbackstore ? This->xwin.backstore : This->wnd, sw->wnd, This->xwin.gc, 2629 x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); 2630 } 2631 2632 void 2633 ui_screenblt(RDPCLIENT * This, uint8 opcode, 2634 /* dest */ int x, int y, int cx, int cy, 2635 /* src */ int srcx, int srcy) 2636 { 2637 SET_FUNCTION(opcode); 2638 if (This->ownbackstore) 2639 { 2640 XCopyArea(This->display, This->Unobscured ? This->wnd : This->xwin.backstore, 2641 This->wnd, This->xwin.gc, srcx, srcy, cx, cy, x, y); 2642 XCopyArea(This->display, This->xwin.backstore, This->xwin.backstore, This->xwin.gc, srcx, srcy, cx, cy, x, y); 2643 } 2644 else 2645 { 2646 XCopyArea(This->display, This->wnd, This->wnd, This->xwin.gc, srcx, srcy, cx, cy, x, y); 2647 } 2648 2649 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 2650 (This->display, This->ownbackstore ? This->xwin.backstore : This->wnd, 2651 sw->wnd, This->xwin.gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); 2652 2653 RESET_FUNCTION(opcode); 2654 } 2655 2656 void 2657 ui_memblt(RDPCLIENT * This, uint8 opcode, 2658 /* dest */ int x, int y, int cx, int cy, 2659 /* src */ HBITMAP src, int srcx, int srcy) 2660 { 2661 SET_FUNCTION(opcode); 2662 XCopyArea(This->display, (Pixmap) src, This->wnd, This->xwin.gc, srcx, srcy, cx, cy, x, y); 2663 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 2664 (This->display, (Pixmap) src, sw->wnd, This->xwin.gc, 2665 srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset)); 2666 if (This->ownbackstore) 2667 XCopyArea(This->display, (Pixmap) src, This->xwin.backstore, This->xwin.gc, srcx, srcy, cx, cy, x, y); 2668 RESET_FUNCTION(opcode); 2669 } 2670 2671 void 2672 ui_triblt(RDPCLIENT * This, uint8 opcode, 2673 /* dest */ int x, int y, int cx, int cy, 2674 /* src */ HBITMAP src, int srcx, int srcy, 2675 /* brush */ BRUSH * brush, int bgcolour, int fgcolour) 2676 { 2677 /* This is potentially difficult to do in general. Until someone 2678 comes up with a more efficient way of doing it I am using cases. */ 2679 2680 switch (opcode) 2681 { 2682 case 0x69: /* PDSxxn */ 2683 ui_memblt(This, ROP2_XOR, x, y, cx, cy, src, srcx, srcy); 2684 ui_patblt(This, ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour); 2685 break; 2686 2687 case 0xb8: /* PSDPxax */ 2688 ui_patblt(This, ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); 2689 ui_memblt(This, ROP2_AND, x, y, cx, cy, src, srcx, srcy); 2690 ui_patblt(This, ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour); 2691 break; 2692 2693 case 0xc0: /* PSa */ 2694 ui_memblt(This, ROP2_COPY, x, y, cx, cy, src, srcx, srcy); 2695 ui_patblt(This, ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour); 2696 break; 2697 2698 default: 2699 unimpl("triblt 0x%x\n", opcode); 2700 ui_memblt(This, ROP2_COPY, x, y, cx, cy, src, srcx, srcy); 2701 } 2702 } 2703 2704 void 2705 ui_line(RDPCLIENT * This, uint8 opcode, 2706 /* dest */ int startx, int starty, int endx, int endy, 2707 /* pen */ PEN * pen) 2708 { 2709 SET_FUNCTION(opcode); 2710 SET_FOREGROUND(pen->colour); 2711 XDrawLine(This->display, This->wnd, This->xwin.gc, startx, starty, endx, endy); 2712 ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (This->display, sw->wnd, This->xwin.gc, 2713 startx - sw->xoffset, starty - sw->yoffset, 2714 endx - sw->xoffset, endy - sw->yoffset)); 2715 if (This->ownbackstore) 2716 XDrawLine(This->display, This->xwin.backstore, This->xwin.gc, startx, starty, endx, endy); 2717 RESET_FUNCTION(opcode); 2718 } 2719 2720 void 2721 ui_rect(RDPCLIENT * This, 2722 /* dest */ int x, int y, int cx, int cy, 2723 /* brush */ int colour) 2724 { 2725 SET_FOREGROUND(colour); 2726 FILL_RECTANGLE(x, y, cx, cy); 2727 } 2728 2729 void 2730 ui_polygon(RDPCLIENT * This, uint8 opcode, 2731 /* mode */ uint8 fillmode, 2732 /* dest */ POINT * point, int npoints, 2733 /* brush */ BRUSH * brush, int bgcolour, int fgcolour) 2734 { 2735 uint8 style, i, ipattern[8]; 2736 Pixmap fill; 2737 2738 SET_FUNCTION(opcode); 2739 2740 switch (fillmode) 2741 { 2742 case ALTERNATE: 2743 XSetFillRule(This->display, This->xwin.gc, EvenOddRule); 2744 break; 2745 case WINDING: 2746 XSetFillRule(This->display, This->xwin.gc, WindingRule); 2747 break; 2748 default: 2749 unimpl("fill mode %d\n", fillmode); 2750 } 2751 2752 if (brush) 2753 style = brush->style; 2754 else 2755 style = 0; 2756 2757 switch (style) 2758 { 2759 case 0: /* Solid */ 2760 SET_FOREGROUND(fgcolour); 2761 FILL_POLYGON((XPoint *) point, npoints); 2762 break; 2763 2764 case 2: /* Hatch */ 2765 fill = (Pixmap) ui_create_glyph(This, 8, 8, 2766 hatch_patterns + brush->pattern[0] * 8); 2767 SET_FOREGROUND(fgcolour); 2768 SET_BACKGROUND(bgcolour); 2769 XSetFillStyle(This->display, This->xwin.gc, FillOpaqueStippled); 2770 XSetStipple(This->display, This->xwin.gc, fill); 2771 XSetTSOrigin(This->display, This->xwin.gc, brush->xorigin, brush->yorigin); 2772 FILL_POLYGON((XPoint *) point, npoints); 2773 XSetFillStyle(This->display, This->xwin.gc, FillSolid); 2774 XSetTSOrigin(This->display, This->xwin.gc, 0, 0); 2775 ui_destroy_glyph(This, (HGLYPH) fill); 2776 break; 2777 2778 case 3: /* Pattern */ 2779 for (i = 0; i != 8; i++) 2780 ipattern[7 - i] = brush->pattern[i]; 2781 fill = (Pixmap) ui_create_glyph(This, 8, 8, ipattern); 2782 SET_FOREGROUND(bgcolour); 2783 SET_BACKGROUND(fgcolour); 2784 XSetFillStyle(This->display, This->xwin.gc, FillOpaqueStippled); 2785 XSetStipple(This->display, This->xwin.gc, fill); 2786 XSetTSOrigin(This->display, This->xwin.gc, brush->xorigin, brush->yorigin); 2787 FILL_POLYGON((XPoint *) point, npoints); 2788 XSetFillStyle(This->display, This->xwin.gc, FillSolid); 2789 XSetTSOrigin(This->display, This->xwin.gc, 0, 0); 2790 ui_destroy_glyph(This, (HGLYPH) fill); 2791 break; 2792 2793 default: 2794 unimpl("brush %d\n", brush->style); 2795 } 2796 2797 RESET_FUNCTION(opcode); 2798 } 2799 2800 void 2801 ui_polyline(RDPCLIENT * This, uint8 opcode, 2802 /* dest */ POINT * points, int npoints, 2803 /* pen */ PEN * pen) 2804 { 2805 /* TODO: set join style */ 2806 SET_FUNCTION(opcode); 2807 SET_FOREGROUND(pen->colour); 2808 XDrawLines(This->display, This->wnd, This->xwin.gc, (XPoint *) points, npoints, CoordModePrevious); 2809 if (This->ownbackstore) 2810 XDrawLines(This->display, This->xwin.backstore, This->xwin.gc, (XPoint *) points, npoints, 2811 CoordModePrevious); 2812 2813 ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines, 2814 (This, sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset)); 2815 2816 RESET_FUNCTION(opcode); 2817 } 2818 2819 void 2820 ui_ellipse(RDPCLIENT * This, uint8 opcode, 2821 /* mode */ uint8 fillmode, 2822 /* dest */ int x, int y, int cx, int cy, 2823 /* brush */ BRUSH * brush, int bgcolour, int fgcolour) 2824 { 2825 uint8 style, i, ipattern[8]; 2826 Pixmap fill; 2827 2828 SET_FUNCTION(opcode); 2829 2830 if (brush) 2831 style = brush->style; 2832 else 2833 style = 0; 2834 2835 switch (style) 2836 { 2837 case 0: /* Solid */ 2838 SET_FOREGROUND(fgcolour); 2839 DRAW_ELLIPSE(x, y, cx, cy, fillmode); 2840 break; 2841 2842 case 2: /* Hatch */ 2843 fill = (Pixmap) ui_create_glyph(This, 8, 8, 2844 hatch_patterns + brush->pattern[0] * 8); 2845 SET_FOREGROUND(fgcolour); 2846 SET_BACKGROUND(bgcolour); 2847 XSetFillStyle(This->display, This->xwin.gc, FillOpaqueStippled); 2848 XSetStipple(This->display, This->xwin.gc, fill); 2849 XSetTSOrigin(This->display, This->xwin.gc, brush->xorigin, brush->yorigin); 2850 DRAW_ELLIPSE(x, y, cx, cy, fillmode); 2851 XSetFillStyle(This->display, This->xwin.gc, FillSolid); 2852 XSetTSOrigin(This->display, This->xwin.gc, 0, 0); 2853 ui_destroy_glyph(This, (HGLYPH) fill); 2854 break; 2855 2856 case 3: /* Pattern */ 2857 for (i = 0; i != 8; i++) 2858 ipattern[7 - i] = brush->pattern[i]; 2859 fill = (Pixmap) ui_create_glyph(This, 8, 8, ipattern); 2860 SET_FOREGROUND(bgcolour); 2861 SET_BACKGROUND(fgcolour); 2862 XSetFillStyle(This->display, This->xwin.gc, FillOpaqueStippled); 2863 XSetStipple(This->display, This->xwin.gc, fill); 2864 XSetTSOrigin(This->display, This->xwin.gc, brush->xorigin, brush->yorigin); 2865 DRAW_ELLIPSE(x, y, cx, cy, fillmode); 2866 XSetFillStyle(This->display, This->xwin.gc, FillSolid); 2867 XSetTSOrigin(This->display, This->xwin.gc, 0, 0); 2868 ui_destroy_glyph(This, (HGLYPH) fill); 2869 break; 2870 2871 default: 2872 unimpl("brush %d\n", brush->style); 2873 } 2874 2875 RESET_FUNCTION(opcode); 2876 } 2877 2878 /* warning, this function only draws on wnd or backstore, not both */ 2879 void 2880 ui_draw_glyph(RDPCLIENT * This, int mixmode, 2881 /* dest */ int x, int y, int cx, int cy, 2882 /* src */ HGLYPH glyph, int srcx, int srcy, 2883 int bgcolour, int fgcolour) 2884 { 2885 SET_FOREGROUND(fgcolour); 2886 SET_BACKGROUND(bgcolour); 2887 2888 XSetFillStyle(This->display, This->xwin.gc, 2889 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled); 2890 XSetStipple(This->display, This->xwin.gc, (Pixmap) glyph); 2891 XSetTSOrigin(This->display, This->xwin.gc, x, y); 2892 2893 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); 2894 2895 XSetFillStyle(This->display, This->xwin.gc, FillSolid); 2896 } 2897 2898 #define DO_GLYPH(ttext,idx) \ 2899 {\ 2900 glyph = cache_get_font (This, font, ttext[idx]);\ 2901 if (!(flags & TEXT2_IMPLICIT_X))\ 2902 {\ 2903 xyoffset = ttext[++idx];\ 2904 if ((xyoffset & 0x80))\ 2905 {\ 2906 if (flags & TEXT2_VERTICAL)\ 2907 y += ttext[idx+1] | (ttext[idx+2] << 8);\ 2908 else\ 2909 x += ttext[idx+1] | (ttext[idx+2] << 8);\ 2910 idx += 2;\ 2911 }\ 2912 else\ 2913 {\ 2914 if (flags & TEXT2_VERTICAL)\ 2915 y += xyoffset;\ 2916 else\ 2917 x += xyoffset;\ 2918 }\ 2919 }\ 2920 if (glyph != NULL)\ 2921 {\ 2922 x1 = x + glyph->offset;\ 2923 y1 = y + glyph->baseline;\ 2924 XSetStipple(This->display, This->xwin.gc, (Pixmap) glyph->pixmap);\ 2925 XSetTSOrigin(This->display, This->xwin.gc, x1, y1);\ 2926 FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\ 2927 if (flags & TEXT2_IMPLICIT_X)\ 2928 x += glyph->width;\ 2929 }\ 2930 } 2931 2932 void 2933 ui_draw_text(RDPCLIENT * This, uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y, 2934 int clipx, int clipy, int clipcx, int clipcy, 2935 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush, 2936 int bgcolour, int fgcolour, uint8 * text, uint8 length) 2937 { 2938 /* TODO: use brush appropriately */ 2939 2940 FONTGLYPH *glyph; 2941 int i, j, xyoffset, x1, y1; 2942 DATABLOB *entry; 2943 2944 SET_FOREGROUND(bgcolour); 2945 2946 /* Sometimes, the boxcx value is something really large, like 2947 32691. This makes XCopyArea fail with Xvnc. The code below 2948 is a quick fix. */ 2949 if (boxx + boxcx > This->width) 2950 boxcx = This->width - boxx; 2951 2952 if (boxcx > 1) 2953 { 2954 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy); 2955 } 2956 else if (mixmode == MIX_OPAQUE) 2957 { 2958 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy); 2959 } 2960 2961 SET_FOREGROUND(fgcolour); 2962 SET_BACKGROUND(bgcolour); 2963 XSetFillStyle(This->display, This->xwin.gc, FillStippled); 2964 2965 /* Paint text, character by character */ 2966 for (i = 0; i < length;) 2967 { 2968 switch (text[i]) 2969 { 2970 case 0xff: 2971 /* At least two bytes needs to follow */ 2972 if (i + 3 > length) 2973 { 2974 warning("Skipping short 0xff command:"); 2975 for (j = 0; j < length; j++) 2976 fprintf(stderr, "%02x ", text[j]); 2977 fprintf(stderr, "\n"); 2978 i = length = 0; 2979 break; 2980 } 2981 cache_put_text(This, text[i + 1], text, text[i + 2]); 2982 i += 3; 2983 length -= i; 2984 /* this will move pointer from start to first character after FF command */ 2985 text = &(text[i]); 2986 i = 0; 2987 break; 2988 2989 case 0xfe: 2990 /* At least one byte needs to follow */ 2991 if (i + 2 > length) 2992 { 2993 warning("Skipping short 0xfe command:"); 2994 for (j = 0; j < length; j++) 2995 fprintf(stderr, "%02x ", text[j]); 2996 fprintf(stderr, "\n"); 2997 i = length = 0; 2998 break; 2999 } 3000 entry = cache_get_text(This, text[i + 1]); 3001 if (entry->data != NULL) 3002 { 3003 if ((((uint8 *) (entry->data))[1] == 0) 3004 && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length)) 3005 { 3006 if (flags & TEXT2_VERTICAL) 3007 y += text[i + 2]; 3008 else 3009 x += text[i + 2]; 3010 } 3011 for (j = 0; j < entry->size; j++) 3012 DO_GLYPH(((uint8 *) (entry->data)), j); 3013 } 3014 if (i + 2 < length) 3015 i += 3; 3016 else 3017 i += 2; 3018 length -= i; 3019 /* this will move pointer from start to first character after FE command */ 3020 text = &(text[i]); 3021 i = 0; 3022 break; 3023 3024 default: 3025 DO_GLYPH(text, i); 3026 i++; 3027 break; 3028 } 3029 } 3030 3031 XSetFillStyle(This->display, This->xwin.gc, FillSolid); 3032 3033 if (This->ownbackstore) 3034 { 3035 if (boxcx > 1) 3036 { 3037 XCopyArea(This->display, This->xwin.backstore, This->wnd, This->xwin.gc, boxx, 3038 boxy, boxcx, boxcy, boxx, boxy); 3039 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 3040 (This->display, This->xwin.backstore, sw->wnd, This->xwin.gc, 3041 boxx, boxy, 3042 boxcx, boxcy, 3043 boxx - sw->xoffset, boxy - sw->yoffset)); 3044 } 3045 else 3046 { 3047 XCopyArea(This->display, This->xwin.backstore, This->wnd, This->xwin.gc, clipx, 3048 clipy, clipcx, clipcy, clipx, clipy); 3049 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 3050 (This->display, This->xwin.backstore, sw->wnd, This->xwin.gc, 3051 clipx, clipy, 3052 clipcx, clipcy, clipx - sw->xoffset, 3053 clipy - sw->yoffset)); 3054 } 3055 } 3056 } 3057 3058 void 3059 ui_desktop_save(RDPCLIENT * This, uint32 offset, int x, int y, int cx, int cy) 3060 { 3061 Pixmap pix; 3062 XImage *image; 3063 3064 if (This->ownbackstore) 3065 { 3066 image = XGetImage(This->display, This->xwin.backstore, x, y, cx, cy, AllPlanes, ZPixmap); 3067 } 3068 else 3069 { 3070 pix = XCreatePixmap(This->display, This->wnd, cx, cy, This->xwin.depth); 3071 XCopyArea(This->display, This->wnd, pix, This->xwin.gc, x, y, cx, cy, 0, 0); 3072 image = XGetImage(This->display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap); 3073 XFreePixmap(This->display, pix); 3074 } 3075 3076 offset *= This->xwin.bpp / 8; 3077 cache_put_desktop(This, offset, cx, cy, image->bytes_per_line, This->xwin.bpp / 8, (uint8 *) image->data); 3078 3079 XDestroyImage(image); 3080 } 3081 3082 void 3083 ui_desktop_restore(RDPCLIENT * This, uint32 offset, int x, int y, int cx, int cy) 3084 { 3085 XImage *image; 3086 uint8 *data; 3087 3088 offset *= This->xwin.bpp / 8; 3089 data = cache_get_desktop(This, offset, cx, cy, This->xwin.bpp / 8); 3090 if (data == NULL) 3091 return; 3092 3093 image = XCreateImage(This->display, This->xwin.visual, This->xwin.depth, ZPixmap, 0, 3094 (char *) data, cx, cy, BitmapPad(This->display), cx * This->xwin.bpp / 8); 3095 3096 if (This->ownbackstore) 3097 { 3098 XPutImage(This->display, This->xwin.backstore, This->xwin.gc, image, 0, 0, x, y, cx, cy); 3099 XCopyArea(This->display, This->xwin.backstore, This->wnd, This->xwin.gc, x, y, cx, cy, x, y); 3100 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 3101 (This->display, This->xwin.backstore, sw->wnd, This->xwin.gc, 3102 x, y, cx, cy, x - sw->xoffset, y - sw->yoffset)); 3103 } 3104 else 3105 { 3106 XPutImage(This->display, This->wnd, This->xwin.gc, image, 0, 0, x, y, cx, cy); 3107 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, 3108 (This->display, This->wnd, sw->wnd, This->xwin.gc, x, y, cx, cy, 3109 x - sw->xoffset, y - sw->yoffset)); 3110 } 3111 3112 XFree(image); 3113 } 3114 3115 /* these do nothing here but are used in uiports */ 3116 void 3117 ui_begin_update(RDPCLIENT * This) 3118 { 3119 } 3120 3121 void 3122 ui_end_update(RDPCLIENT * This) 3123 { 3124 } 3125 3126 3127 void 3128 ui_seamless_begin(RDPCLIENT * This, BOOL hidden) 3129 { 3130 if (!This->seamless_rdp) 3131 return; 3132 3133 if (This->xwin.seamless_started) 3134 return; 3135 3136 This->xwin.seamless_started = True; 3137 This->xwin.seamless_hidden = hidden; 3138 3139 if (!hidden) 3140 ui_seamless_toggle(This); 3141 } 3142 3143 3144 void 3145 ui_seamless_hide_desktop(RDPCLIENT * This) 3146 { 3147 if (!This->seamless_rdp) 3148 return; 3149 3150 if (!This->xwin.seamless_started) 3151 return; 3152 3153 if (This->xwin.seamless_active) 3154 ui_seamless_toggle(This); 3155 3156 This->xwin.seamless_hidden = True; 3157 } 3158 3159 3160 void 3161 ui_seamless_unhide_desktop(RDPCLIENT * This) 3162 { 3163 if (!This->seamless_rdp) 3164 return; 3165 3166 if (!This->xwin.seamless_started) 3167 return; 3168 3169 This->xwin.seamless_hidden = False; 3170 3171 ui_seamless_toggle(This); 3172 } 3173 3174 3175 void 3176 ui_seamless_toggle(RDPCLIENT * This) 3177 { 3178 if (!This->seamless_rdp) 3179 return; 3180 3181 if (!This->xwin.seamless_started) 3182 return; 3183 3184 if (This->xwin.seamless_hidden) 3185 return; 3186 3187 if (This->xwin.seamless_active) 3188 { 3189 /* Deactivate */ 3190 while (This->xwin.seamless_windows) 3191 { 3192 XDestroyWindow(This->display, This->xwin.seamless_windows->wnd); 3193 sw_remove_window(This, This->xwin.seamless_windows); 3194 } 3195 XMapWindow(This->display, This->wnd); 3196 } 3197 else 3198 { 3199 /* Activate */ 3200 XUnmapWindow(This->display, This->wnd); 3201 seamless_send_sync(This); 3202 } 3203 3204 This->xwin.seamless_active = !This->xwin.seamless_active; 3205 } 3206 3207 3208 void 3209 ui_seamless_create_window(RDPCLIENT * This, unsigned long id, unsigned long group, unsigned long parent, 3210 unsigned long flags) 3211 { 3212 Window wnd; 3213 XSetWindowAttributes attribs; 3214 XClassHint *classhints; 3215 XSizeHints *sizehints; 3216 XWMHints *wmhints; 3217 long input_mask; 3218 seamless_window *sw, *sw_parent; 3219 3220 if (!This->xwin.seamless_active) 3221 return; 3222 3223 /* Ignore CREATEs for existing windows */ 3224 sw = sw_get_window_by_id(This, id); 3225 if (sw) 3226 return; 3227 3228 get_window_attribs(This, &attribs); 3229 wnd = XCreateWindow(This->display, RootWindowOfScreen(This->xwin.screen), -1, -1, 1, 1, 0, This->xwin.depth, 3230 InputOutput, This->xwin.visual, 3231 CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs); 3232 3233 XStoreName(This->display, wnd, "SeamlessRDP"); 3234 ewmh_set_wm_name(This, wnd, "SeamlessRDP"); 3235 3236 mwm_hide_decorations(This, wnd); 3237 3238 classhints = XAllocClassHint(); 3239 if (classhints != NULL) 3240 { 3241 classhints->res_name = "rdesktop"; 3242 classhints->res_class = "SeamlessRDP"; 3243 XSetClassHint(This->display, wnd, classhints); 3244 XFree(classhints); 3245 } 3246 3247 /* WM_NORMAL_HINTS */ 3248 sizehints = XAllocSizeHints(); 3249 if (sizehints != NULL) 3250 { 3251 sizehints->flags = USPosition; 3252 XSetWMNormalHints(This->display, wnd, sizehints); 3253 XFree(sizehints); 3254 } 3255 3256 /* Parent-less transient windows */ 3257 if (parent == 0xFFFFFFFF) 3258 { 3259 XSetTransientForHint(This->display, wnd, RootWindowOfScreen(This->xwin.screen)); 3260 /* Some buggy wm:s (kwin) do not handle the above, so fake it 3261 using some other hints. */ 3262 ewmh_set_window_popup(This, wnd); 3263 } 3264 /* Normal transient windows */ 3265 else if (parent != 0x00000000) 3266 { 3267 sw_parent = sw_get_window_by_id(This, parent); 3268 if (sw_parent) 3269 XSetTransientForHint(This->display, wnd, sw_parent->wnd); 3270 else 3271 warning("ui_seamless_create_window: No parent window 0x%lx\n", parent); 3272 } 3273 3274 if (flags & SEAMLESSRDP_CREATE_MODAL) 3275 { 3276 /* We do this to support buggy wm:s (*cough* metacity *cough*) 3277 somewhat at least */ 3278 if (parent == 0x00000000) 3279 XSetTransientForHint(This->display, wnd, RootWindowOfScreen(This->xwin.screen)); 3280 ewmh_set_window_modal(This, wnd); 3281 } 3282 3283 /* FIXME: Support for Input Context:s */ 3284 3285 get_input_mask(This, &input_mask); 3286 input_mask |= PropertyChangeMask; 3287 3288 XSelectInput(This->display, wnd, input_mask); 3289 3290 /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a 3291 seamless window, we could try to close the window on the 3292 serverside, instead of terminating rdesktop */ 3293 XSetWMProtocols(This->display, wnd, &This->xwin.kill_atom, 1); 3294 3295 sw = xmalloc(sizeof(seamless_window)); 3296 sw->wnd = wnd; 3297 sw->id = id; 3298 sw->behind = 0; 3299 sw->group = sw_find_group(This, group, False); 3300 sw->group->refcnt++; 3301 sw->xoffset = 0; 3302 sw->yoffset = 0; 3303 sw->width = 0; 3304 sw->height = 0; 3305 sw->state = SEAMLESSRDP_NOTYETMAPPED; 3306 sw->desktop = 0; 3307 sw->position_timer = xmalloc(sizeof(struct timeval)); 3308 timerclear(sw->position_timer); 3309 3310 sw->outstanding_position = False; 3311 sw->outpos_serial = 0; 3312 sw->outpos_xoffset = sw->outpos_yoffset = 0; 3313 sw->outpos_width = sw->outpos_height = 0; 3314 3315 sw->next = This->xwin.seamless_windows; 3316 This->xwin.seamless_windows = sw; 3317 3318 /* WM_HINTS */ 3319 wmhints = XAllocWMHints(); 3320 if (wmhints) 3321 { 3322 wmhints->flags = WindowGroupHint; 3323 wmhints->window_group = sw->group->wnd; 3324 XSetWMHints(This->display, sw->wnd, wmhints); 3325 XFree(wmhints); 3326 } 3327 } 3328 3329 3330 void 3331 ui_seamless_destroy_window(RDPCLIENT * This, unsigned long id, unsigned long flags) 3332 { 3333 seamless_window *sw; 3334 3335 if (!This->xwin.seamless_active) 3336 return; 3337 3338 sw = sw_get_window_by_id(This, id); 3339 if (!sw) 3340 { 3341 warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id); 3342 return; 3343 } 3344 3345 XDestroyWindow(This->display, sw->wnd); 3346 sw_remove_window(This, sw); 3347 } 3348 3349 3350 void 3351 ui_seamless_destroy_group(RDPCLIENT * This, unsigned long id, unsigned long flags) 3352 { 3353 seamless_window *sw, *sw_next; 3354 3355 if (!This->xwin.seamless_active) 3356 return; 3357 3358 for (sw = This->xwin.seamless_windows; sw; sw = sw_next) 3359 { 3360 sw_next = sw->next; 3361 3362 if (sw->group->id == id) 3363 { 3364 XDestroyWindow(This->display, sw->wnd); 3365 sw_remove_window(This, sw); 3366 } 3367 } 3368 } 3369 3370 3371 void 3372 ui_seamless_move_window(RDPCLIENT * This, unsigned long id, int x, int y, int width, int height, unsigned long flags) 3373 { 3374 seamless_window *sw; 3375 3376 if (!This->xwin.seamless_active) 3377 return; 3378 3379 sw = sw_get_window_by_id(This, id); 3380 if (!sw) 3381 { 3382 warning("ui_seamless_move_window: No information for window 0x%lx\n", id); 3383 return; 3384 } 3385 3386 /* We ignore server updates until it has handled our request. */ 3387 if (sw->outstanding_position) 3388 return; 3389 3390 if (!width || !height) 3391 /* X11 windows must be at least 1x1 */ 3392 return; 3393 3394 sw->xoffset = x; 3395 sw->yoffset = y; 3396 sw->width = width; 3397 sw->height = height; 3398 3399 /* If we move the window in a maximized state, then KDE won't 3400 accept restoration */ 3401 switch (sw->state) 3402 { 3403 case SEAMLESSRDP_MINIMIZED: 3404 case SEAMLESSRDP_MAXIMIZED: 3405 return; 3406 } 3407 3408 /* FIXME: Perhaps use ewmh_net_moveresize_window instead */ 3409 XMoveResizeWindow(This->display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height); 3410 } 3411 3412 3413 void 3414 ui_seamless_restack_window(RDPCLIENT * This, unsigned long id, unsigned long behind, unsigned long flags) 3415 { 3416 seamless_window *sw; 3417 3418 if (!This->xwin.seamless_active) 3419 return; 3420 3421 sw = sw_get_window_by_id(This, id); 3422 if (!sw) 3423 { 3424 warning("ui_seamless_restack_window: No information for window 0x%lx\n", id); 3425 return; 3426 } 3427 3428 if (behind) 3429 { 3430 seamless_window *sw_behind; 3431 Window wnds[2]; 3432 3433 sw_behind = sw_get_window_by_id(This, behind); 3434 if (!sw_behind) 3435 { 3436 warning("ui_seamless_restack_window: No information for window 0x%lx\n", 3437 behind); 3438 return; 3439 } 3440 3441 wnds[1] = sw_behind->wnd; 3442 wnds[0] = sw->wnd; 3443 3444 XRestackWindows(This->display, wnds, 2); 3445 } 3446 else 3447 { 3448 XRaiseWindow(This->display, sw->wnd); 3449 } 3450 3451 sw_restack_window(This, sw, behind); 3452 } 3453 3454 3455 void 3456 ui_seamless_settitle(RDPCLIENT * This, unsigned long id, const char *title, unsigned long flags) 3457 { 3458 seamless_window *sw; 3459 3460 if (!This->xwin.seamless_active) 3461 return; 3462 3463 sw = sw_get_window_by_id(This, id); 3464 if (!sw) 3465 { 3466 warning("ui_seamless_settitle: No information for window 0x%lx\n", id); 3467 return; 3468 } 3469 3470 /* FIXME: Might want to convert the name for non-EWMH WMs */ 3471 XStoreName(This->display, sw->wnd, title); 3472 ewmh_set_wm_name(This, sw->wnd, title); 3473 } 3474 3475 3476 void 3477 ui_seamless_setstate(RDPCLIENT * This, unsigned long id, unsigned int state, unsigned long flags) 3478 { 3479 seamless_window *sw; 3480 3481 if (!This->xwin.seamless_active) 3482 return; 3483 3484 sw = sw_get_window_by_id(This, id); 3485 if (!sw) 3486 { 3487 warning("ui_seamless_setstate: No information for window 0x%lx\n", id); 3488 return; 3489 } 3490 3491 switch (state) 3492 { 3493 case SEAMLESSRDP_NORMAL: 3494 case SEAMLESSRDP_MAXIMIZED: 3495 ewmh_change_state(This, sw->wnd, state); 3496 XMapWindow(This->display, sw->wnd); 3497 break; 3498 case SEAMLESSRDP_MINIMIZED: 3499 /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN 3500 the Window Manager should probably just ignore the request, since 3501 _NET_WM_STATE_HIDDEN is a function of some other aspect of the window 3502 such as minimization, rather than an independent state." Besides, 3503 XIconifyWindow is easier. */ 3504 if (sw->state == SEAMLESSRDP_NOTYETMAPPED) 3505 { 3506 XWMHints *hints; 3507 hints = XGetWMHints(This->display, sw->wnd); 3508 if (hints) 3509 { 3510 hints->flags |= StateHint; 3511 hints->initial_state = IconicState; 3512 XSetWMHints(This->display, sw->wnd, hints); 3513 XFree(hints); 3514 } 3515 XMapWindow(This->display, sw->wnd); 3516 } 3517 else 3518 XIconifyWindow(This->display, sw->wnd, DefaultScreen(This->display)); 3519 break; 3520 default: 3521 warning("SeamlessRDP: Invalid state %d\n", state); 3522 break; 3523 } 3524 3525 sw->state = state; 3526 } 3527 3528 3529 void 3530 ui_seamless_syncbegin(RDPCLIENT * This, unsigned long flags) 3531 { 3532 if (!This->xwin.seamless_active) 3533 return; 3534 3535 /* Destroy all seamless windows */ 3536 while (This->xwin.seamless_windows) 3537 { 3538 XDestroyWindow(This->display, This->xwin.seamless_windows->wnd); 3539 sw_remove_window(This, This->xwin.seamless_windows); 3540 } 3541 } 3542 3543 3544 void 3545 ui_seamless_ack(RDPCLIENT * This, unsigned int serial) 3546 { 3547 seamless_window *sw; 3548 for (sw = This->xwin.seamless_windows; sw; sw = sw->next) 3549 { 3550 if (sw->outstanding_position && (sw->outpos_serial == serial)) 3551 { 3552 sw->xoffset = sw->outpos_xoffset; 3553 sw->yoffset = sw->outpos_yoffset; 3554 sw->width = sw->outpos_width; 3555 sw->height = sw->outpos_height; 3556 sw->outstanding_position = False; 3557 3558 /* Do a complete redraw of the window as part of the 3559 completion of the move. This is to remove any 3560 artifacts caused by our lack of synchronization. */ 3561 XCopyArea(This->display, This->xwin.backstore, 3562 sw->wnd, This->xwin.gc, 3563 sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0); 3564 3565 break; 3566 } 3567 } 3568 } 3569