1# Xlib.xobject.drawable -- drawable objects (window and pixmap) 2# 3# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se> 4# 5# This library is free software; you can redistribute it and/or 6# modify it under the terms of the GNU Lesser General Public License 7# as published by the Free Software Foundation; either version 2.1 8# of the License, or (at your option) any later version. 9# 10# This library is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13# See the GNU Lesser General Public License for more details. 14# 15# You should have received a copy of the GNU Lesser General Public 16# License along with this library; if not, write to the 17# Free Software Foundation, Inc., 18# 59 Temple Place, 19# Suite 330, 20# Boston, MA 02111-1307 USA 21 22from Xlib import X, Xatom, Xutil 23from Xlib.protocol import request, rq 24 25# Other X resource objects 26from . import resource 27from . import colormap 28from . import cursor 29from . import fontable 30 31# Inter-client communication conventions 32from . import icccm 33 34class Drawable(resource.Resource): 35 __drawable__ = resource.Resource.__resource__ 36 37 def get_geometry(self): 38 return request.GetGeometry(display = self.display, 39 drawable = self) 40 41 def create_pixmap(self, width, height, depth): 42 pid = self.display.allocate_resource_id() 43 request.CreatePixmap(display = self.display, 44 depth = depth, 45 pid = pid, 46 drawable = self.id, 47 width = width, 48 height = height) 49 50 cls = self.display.get_resource_class('pixmap', Pixmap) 51 return cls(self.display, pid, owner = 1) 52 53 def create_gc(self, **keys): 54 cid = self.display.allocate_resource_id() 55 request.CreateGC(display = self.display, 56 cid = cid, 57 drawable = self.id, 58 attrs = keys) 59 60 cls = self.display.get_resource_class('gc', fontable.GC) 61 return cls(self.display, cid, owner = 1) 62 63 def copy_area(self, gc, src_drawable, src_x, src_y, width, height, dst_x, dst_y, onerror = None): 64 request.CopyArea(display = self.display, 65 onerror = onerror, 66 src_drawable = src_drawable, 67 dst_drawable = self.id, 68 gc = gc, 69 src_x = src_x, 70 src_y = src_y, 71 dst_x = dst_x, 72 dst_y = dst_y, 73 width = width, 74 height = height) 75 76 def copy_plane(self, gc, src_drawable, src_x, src_y, width, height, 77 dst_x, dst_y, bit_plane, onerror = None): 78 request.CopyPlane(display = self.display, 79 onerror = onerror, 80 src_drawable = src_drawable, 81 dst_drawable = self.id, 82 gc = gc, 83 src_x = src_x, 84 src_y = src_y, 85 dst_x = dst_x, 86 dst_y = dst_y, 87 width = width, 88 height = height, 89 bit_plane = bit_plane) 90 91 def poly_point(self, gc, coord_mode, points, onerror = None): 92 request.PolyPoint(display = self.display, 93 onerror = onerror, 94 coord_mode = coord_mode, 95 drawable = self.id, 96 gc = gc, 97 points = points) 98 99 def point(self, gc, x, y, onerror = None): 100 request.PolyPoint(display = self.display, 101 onerror = onerror, 102 coord_mode = X.CoordModeOrigin, 103 drawable = self.id, 104 gc = gc, 105 points = [(x, y)]) 106 107 def poly_line(self, gc, coord_mode, points, onerror = None): 108 request.PolyLine(display = self.display, 109 onerror = onerror, 110 coord_mode = coord_mode, 111 drawable = self.id, 112 gc = gc, 113 points = points) 114 115 def line(self, gc, x1, y1, x2, y2, onerror = None): 116 request.PolySegment(display = self.display, 117 onerror = onerror, 118 drawable = self.id, 119 gc = gc, 120 segments = [(x1, y1, x2, y2)]) 121 122 def poly_segment(self, gc, segments, onerror = None): 123 request.PolySegment(display = self.display, 124 onerror = onerror, 125 drawable = self.id, 126 gc = gc, 127 segments = segments) 128 129 def poly_rectangle(self, gc, rectangles, onerror = None): 130 request.PolyRectangle(display = self.display, 131 onerror = onerror, 132 drawable = self.id, 133 gc = gc, 134 rectangles = rectangles) 135 136 def rectangle(self, gc, x, y, width, height, onerror = None): 137 request.PolyRectangle(display = self.display, 138 onerror = onerror, 139 drawable = self.id, 140 gc = gc, 141 rectangles = [(x, y, width, height)]) 142 143 144 def poly_arc(self, gc, arcs, onerror = None): 145 request.PolyArc(display = self.display, 146 onerror = onerror, 147 drawable = self.id, 148 gc = gc, 149 arcs = arcs) 150 151 def arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): 152 request.PolyArc(display = self.display, 153 onerror = onerror, 154 drawable = self.id, 155 gc = gc, 156 arcs = [(x, y, width, height, angle1, angle2)]) 157 158 def fill_poly(self, gc, shape, coord_mode, points, onerror = None): 159 request.FillPoly(display = self.display, 160 onerror = onerror, 161 shape = shape, 162 coord_mode = coord_mode, 163 drawable = self.id, 164 gc = gc, 165 points = points) 166 167 def poly_fill_rectangle(self, gc, rectangles, onerror = None): 168 request.PolyFillRectangle(display = self.display, 169 onerror = onerror, 170 drawable = self.id, 171 gc = gc, 172 rectangles = rectangles) 173 174 def fill_rectangle(self, gc, x, y, width, height, onerror = None): 175 request.PolyFillRectangle(display = self.display, 176 onerror = onerror, 177 drawable = self.id, 178 gc = gc, 179 rectangles = [(x, y, width, height)]) 180 181 def poly_fill_arc(self, gc, arcs, onerror = None): 182 request.PolyFillArc(display = self.display, 183 onerror = onerror, 184 drawable = self.id, 185 gc = gc, 186 arcs = arcs) 187 188 def fill_arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): 189 request.PolyFillArc(display = self.display, 190 onerror = onerror, 191 drawable = self.id, 192 gc = gc, 193 arcs = [(x, y, width, height, angle1, angle2)]) 194 195 196 def put_image(self, gc, x, y, width, height, format, 197 depth, left_pad, data, onerror = None): 198 request.PutImage(display = self.display, 199 onerror = onerror, 200 format = format, 201 drawable = self.id, 202 gc = gc, 203 width = width, 204 height = height, 205 dst_x = x, 206 dst_y = y, 207 left_pad = left_pad, 208 depth = depth, 209 data = data) 210 211 # Trivial little method for putting PIL images. Will break on anything 212 # but depth 1 or 24... 213 def put_pil_image(self, gc, x, y, image, onerror = None): 214 width, height = image.size 215 if image.mode == '1': 216 format = X.XYBitmap 217 depth = 1 218 if self.display.info.bitmap_format_bit_order == 0: 219 rawmode = '1;R' 220 else: 221 rawmode = '1' 222 pad = self.display.info.bitmap_format_scanline_pad 223 stride = roundup(width, pad) >> 3 224 elif image.mode == 'RGB': 225 format = X.ZPixmap 226 depth = 24 227 if self.display.info.image_byte_order == 0: 228 rawmode = 'BGRX' 229 else: 230 rawmode = 'RGBX' 231 pad = self.display.info.bitmap_format_scanline_pad 232 unit = self.display.info.bitmap_format_scanline_unit 233 stride = roundup(width * unit, pad) >> 3 234 else: 235 raise ValueError('Unknown data format') 236 237 maxlen = (self.display.info.max_request_length << 2) \ 238 - request.PutImage._request.static_size 239 split = maxlen // stride 240 241 x1 = 0 242 x2 = width 243 y1 = 0 244 245 while y1 < height: 246 h = min(height, split) 247 if h < height: 248 subimage = image.crop((x1, y1, x2, y1 + h)) 249 else: 250 subimage = image 251 w, h = subimage.size 252 data = subimage.tobytes("raw", rawmode, stride, 0) 253 self.put_image(gc, x, y, w, h, format, depth, 0, data) 254 y1 = y1 + h 255 y = y + h 256 257 258 def get_image(self, x, y, width, height, format, plane_mask): 259 return request.GetImage(display = self.display, 260 format = format, 261 drawable = self.id, 262 x = x, 263 y = y, 264 width = width, 265 height = height, 266 plane_mask = plane_mask) 267 268 def draw_text(self, gc, x, y, text, onerror = None): 269 request.PolyText8(display = self.display, 270 onerror = onerror, 271 drawable = self.id, 272 gc = gc, 273 x = x, 274 y = y, 275 items = [text]) 276 277 def poly_text(self, gc, x, y, items, onerror = None): 278 request.PolyText8(display = self.display, 279 onerror = onerror, 280 drawable = self.id, 281 gc = gc, 282 x = x, 283 y = y, 284 items = items) 285 286 def poly_text_16(self, gc, x, y, items, onerror = None): 287 request.PolyText16(display = self.display, 288 onerror = onerror, 289 drawable = self.id, 290 gc = gc, 291 x = x, 292 y = y, 293 items = items) 294 295 def image_text(self, gc, x, y, string, onerror = None): 296 request.ImageText8(display = self.display, 297 onerror = onerror, 298 drawable = self.id, 299 gc = gc, 300 x = x, 301 y = y, 302 string = string) 303 304 def image_text_16(self, gc, x, y, string, onerror = None): 305 request.ImageText16(display = self.display, 306 onerror = onerror, 307 drawable = self.id, 308 gc = gc, 309 x = x, 310 y = y, 311 string = string) 312 313 def query_best_size(self, item_class, width, height): 314 return request.QueryBestSize(display = self.display, 315 item_class = item_class, 316 drawable = self.id, 317 width = width, 318 height = height) 319 320class Window(Drawable): 321 __window__ = resource.Resource.__resource__ 322 323 _STRING_ENCODING = 'ISO-8859-1' 324 _UTF8_STRING_ENCODING = 'UTF-8' 325 326 def create_window(self, x, y, width, height, border_width, depth, 327 window_class = X.CopyFromParent, 328 visual = X.CopyFromParent, 329 onerror = None, 330 **keys): 331 332 wid = self.display.allocate_resource_id() 333 request.CreateWindow(display = self.display, 334 onerror = onerror, 335 depth = depth, 336 wid = wid, 337 parent = self.id, 338 x = x, 339 y = y, 340 width = width, 341 height = height, 342 border_width = border_width, 343 window_class = window_class, 344 visual = visual, 345 attrs = keys) 346 347 cls = self.display.get_resource_class('window', Window) 348 return cls(self.display, wid, owner = 1) 349 350 def change_attributes(self, onerror = None, **keys): 351 request.ChangeWindowAttributes(display = self.display, 352 onerror = onerror, 353 window = self.id, 354 attrs = keys) 355 356 def get_attributes(self): 357 return request.GetWindowAttributes(display = self.display, 358 window = self.id) 359 360 def destroy(self, onerror = None): 361 request.DestroyWindow(display = self.display, 362 onerror = onerror, 363 window = self.id) 364 365 self.display.free_resource_id(self.id) 366 367 def destroy_sub_windows(self, onerror = None): 368 request.DestroySubWindows(display = self.display, 369 onerror = onerror, 370 window = self.id) 371 372 373 def change_save_set(self, mode, onerror = None): 374 request.ChangeSaveSet(display = self.display, 375 onerror = onerror, 376 mode = mode, 377 window = self.id) 378 379 def reparent(self, parent, x, y, onerror = None): 380 request.ReparentWindow(display = self.display, 381 onerror = onerror, 382 window = self.id, 383 parent = parent, 384 x = x, 385 y = y) 386 387 def map(self, onerror = None): 388 request.MapWindow(display = self.display, 389 onerror = onerror, 390 window = self.id) 391 392 def map_sub_windows(self, onerror = None): 393 request.MapSubwindows(display = self.display, 394 onerror = onerror, 395 window = self.id) 396 397 def unmap(self, onerror = None): 398 request.UnmapWindow(display = self.display, 399 onerror = onerror, 400 window = self.id) 401 402 def unmap_sub_windows(self, onerror = None): 403 request.UnmapSubwindows(display = self.display, 404 onerror = onerror, 405 window = self.id) 406 407 def configure(self, onerror = None, **keys): 408 request.ConfigureWindow(display = self.display, 409 onerror = onerror, 410 window = self.id, 411 attrs = keys) 412 413 def circulate(self, direction, onerror = None): 414 request.CirculateWindow(display = self.display, 415 onerror = onerror, 416 direction = direction, 417 window = self.id) 418 419 def raise_window(self, onerror = None): 420 """alias for raising the window to the top - as in XRaiseWindow""" 421 self.configure(onerror, stack_mode = X.Above) 422 423 def query_tree(self): 424 return request.QueryTree(display = self.display, 425 window = self.id) 426 427 def change_property(self, property, property_type, format, data, 428 mode = X.PropModeReplace, onerror = None): 429 430 request.ChangeProperty(display = self.display, 431 onerror = onerror, 432 mode = mode, 433 window = self.id, 434 property = property, 435 type = property_type, 436 data = (format, data)) 437 438 def change_text_property(self, property, property_type, data, 439 mode = X.PropModeReplace, onerror = None): 440 if not isinstance(data, bytes): 441 if property_type == Xatom.STRING: 442 data = data.encode(self._STRING_ENCODING) 443 elif property_type == self.display.get_atom('UTF8_STRING'): 444 data = data.encode(self._UTF8_STRING_ENCODING) 445 self.change_property(property, property_type, 8, data, 446 mode=mode, onerror=onerror) 447 448 def delete_property(self, property, onerror = None): 449 request.DeleteProperty(display = self.display, 450 onerror = onerror, 451 window = self.id, 452 property = property) 453 454 def get_property(self, property, property_type, offset, length, delete = 0): 455 r = request.GetProperty(display = self.display, 456 delete = delete, 457 window = self.id, 458 property = property, 459 type = property_type, 460 long_offset = offset, 461 long_length = length) 462 463 if r.property_type: 464 fmt, value = r.value 465 r.format = fmt 466 r.value = value 467 return r 468 else: 469 return None 470 471 def get_full_property(self, property, property_type, sizehint = 10): 472 prop = self.get_property(property, property_type, 0, sizehint) 473 if prop: 474 val = prop.value 475 if prop.bytes_after: 476 prop = self.get_property(property, property_type, sizehint, 477 prop.bytes_after // 4 + 1) 478 val = val + prop.value 479 480 prop.value = val 481 return prop 482 else: 483 return None 484 485 def get_full_text_property(self, property, property_type=X.AnyPropertyType, sizehint = 10): 486 prop = self.get_full_property(property, property_type, 487 sizehint=sizehint) 488 if prop is None or prop.format != 8: 489 return None 490 if prop.property_type == Xatom.STRING: 491 prop.value = prop.value.decode(self._STRING_ENCODING) 492 elif prop.property_type == self.display.get_atom('UTF8_STRING'): 493 prop.value = prop.value.decode(self._UTF8_STRING_ENCODING) 494 # FIXME: at least basic support for compound text would be nice. 495 # elif prop.property_type == self.display.get_atom('COMPOUND_TEXT'): 496 return prop.value 497 498 def list_properties(self): 499 r = request.ListProperties(display = self.display, 500 window = self.id) 501 return r.atoms 502 503 def set_selection_owner(self, selection, time, onerror = None): 504 request.SetSelectionOwner(display = self.display, 505 onerror = onerror, 506 window = self.id, 507 selection = selection, 508 time = time) 509 510 def convert_selection(self, selection, target, property, time, onerror = None): 511 request.ConvertSelection(display = self.display, 512 onerror = onerror, 513 requestor = self.id, 514 selection = selection, 515 target = target, 516 property = property, 517 time = time) 518 519 def send_event(self, event, event_mask = 0, propagate = 0, onerror = None): 520 request.SendEvent(display = self.display, 521 onerror = onerror, 522 propagate = propagate, 523 destination = self.id, 524 event_mask = event_mask, 525 event = event) 526 527 def grab_pointer(self, owner_events, event_mask, 528 pointer_mode, keyboard_mode, 529 confine_to, cursor, time): 530 531 r = request.GrabPointer(display = self.display, 532 owner_events = owner_events, 533 grab_window = self.id, 534 event_mask = event_mask, 535 pointer_mode = pointer_mode, 536 keyboard_mode = keyboard_mode, 537 confine_to = confine_to, 538 cursor = cursor, 539 time = time) 540 return r.status 541 542 def grab_button(self, button, modifiers, owner_events, event_mask, 543 pointer_mode, keyboard_mode, 544 confine_to, cursor, onerror = None): 545 546 request.GrabButton(display = self.display, 547 onerror = onerror, 548 owner_events = owner_events, 549 grab_window = self.id, 550 event_mask = event_mask, 551 pointer_mode = pointer_mode, 552 keyboard_mode = keyboard_mode, 553 confine_to = confine_to, 554 cursor = cursor, 555 button = button, 556 modifiers = modifiers) 557 558 def ungrab_button(self, button, modifiers, onerror = None): 559 request.UngrabButton(display = self.display, 560 onerror = onerror, 561 button = button, 562 grab_window = self.id, 563 modifiers = modifiers) 564 565 566 def grab_keyboard(self, owner_events, pointer_mode, keyboard_mode, time): 567 r = request.GrabKeyboard(display = self.display, 568 owner_events = owner_events, 569 grab_window = self.id, 570 time = time, 571 pointer_mode = pointer_mode, 572 keyboard_mode = keyboard_mode) 573 574 return r.status 575 576 def grab_key(self, key, modifiers, owner_events, pointer_mode, keyboard_mode, onerror = None): 577 request.GrabKey(display = self.display, 578 onerror = onerror, 579 owner_events = owner_events, 580 grab_window = self.id, 581 modifiers = modifiers, 582 key = key, 583 pointer_mode = pointer_mode, 584 keyboard_mode = keyboard_mode) 585 586 def ungrab_key(self, key, modifiers, onerror = None): 587 request.UngrabKey(display = self.display, 588 onerror = onerror, 589 key = key, 590 grab_window = self.id, 591 modifiers = modifiers) 592 593 def query_pointer(self): 594 return request.QueryPointer(display = self.display, 595 window = self.id) 596 597 def get_motion_events(self, start, stop): 598 r = request.GetMotionEvents(display = self.display, 599 window = self.id, 600 start = start, 601 stop = stop) 602 return r.events 603 604 def translate_coords(self, src_window, src_x, src_y): 605 return request.TranslateCoords(display = self.display, 606 src_wid = src_window, 607 dst_wid = self.id, 608 src_x = src_x, 609 src_y = src_y) 610 611 def warp_pointer(self, x, y, src_window = 0, src_x = 0, src_y = 0, 612 src_width = 0, src_height = 0, onerror = None): 613 614 request.WarpPointer(display = self.display, 615 onerror = onerror, 616 src_window = src_window, 617 dst_window = self.id, 618 src_x = src_x, 619 src_y = src_y, 620 src_width = src_width, 621 src_height = src_height, 622 dst_x = x, 623 dst_y = y) 624 625 def set_input_focus(self, revert_to, time, onerror = None): 626 request.SetInputFocus(display = self.display, 627 onerror = onerror, 628 revert_to = revert_to, 629 focus = self.id, 630 time = time) 631 632 def clear_area(self, x = 0, y = 0, width = 0, height = 0, exposures = 0, onerror = None): 633 request.ClearArea(display = self.display, 634 onerror = onerror, 635 exposures = exposures, 636 window = self.id, 637 x = x, 638 y = y, 639 width = width, 640 height = height) 641 642 def create_colormap(self, visual, alloc): 643 mid = self.display.allocate_resource_id() 644 request.CreateColormap(display = self.display, 645 alloc = alloc, 646 mid = mid, 647 window = self.id, 648 visual = visual) 649 cls = self.display.get_resource_class('colormap', colormap.Colormap) 650 return cls(self.display, mid, owner = 1) 651 652 def list_installed_colormaps(self): 653 r = request.ListInstalledColormaps(display = self.display, 654 window = self.id) 655 return r.cmaps 656 657 def rotate_properties(self, properties, delta, onerror = None): 658 request.RotateProperties(display = self.display, 659 onerror = onerror, 660 window = self.id, 661 delta = delta, 662 properties = properties) 663 664 def set_wm_name(self, name, onerror = None): 665 self.change_text_property(Xatom.WM_NAME, Xatom.STRING, name, 666 onerror = onerror) 667 668 def get_wm_name(self): 669 return self.get_full_text_property(Xatom.WM_NAME, Xatom.STRING) 670 671 def set_wm_icon_name(self, name, onerror = None): 672 self.change_text_property(Xatom.WM_ICON_NAME, Xatom.STRING, name, 673 onerror = onerror) 674 675 def get_wm_icon_name(self): 676 return self.get_full_text_property(Xatom.WM_ICON_NAME, Xatom.STRING) 677 678 def set_wm_class(self, inst, cls, onerror = None): 679 self.change_text_property(Xatom.WM_CLASS, Xatom.STRING, 680 '%s\0%s\0' % (inst, cls), 681 onerror = onerror) 682 683 def get_wm_class(self): 684 value = self.get_full_text_property(Xatom.WM_CLASS, Xatom.STRING) 685 if value is None: 686 return None 687 parts = value.split('\0') 688 if len(parts) < 2: 689 return None 690 else: 691 return parts[0], parts[1] 692 693 def set_wm_transient_for(self, window, onerror = None): 694 self.change_property(Xatom.WM_TRANSIENT_FOR, Xatom.WINDOW, 695 32, [window.id], 696 onerror = onerror) 697 698 def get_wm_transient_for(self): 699 d = self.get_property(Xatom.WM_TRANSIENT_FOR, Xatom.WINDOW, 0, 1) 700 if d is None or d.format != 32 or len(d.value) < 1: 701 return None 702 else: 703 cls = self.display.get_resource_class('window', Window) 704 return cls(self.display, d.value[0]) 705 706 707 def set_wm_protocols(self, protocols, onerror = None): 708 self.change_property(self.display.get_atom('WM_PROTOCOLS'), 709 Xatom.ATOM, 32, protocols, 710 onerror = onerror) 711 712 def get_wm_protocols(self): 713 d = self.get_full_property(self.display.get_atom('WM_PROTOCOLS'), Xatom.ATOM) 714 if d is None or d.format != 32: 715 return [] 716 else: 717 return d.value 718 719 def set_wm_colormap_windows(self, windows, onerror = None): 720 self.change_property(self.display.get_atom('WM_COLORMAP_WINDOWS'), 721 Xatom.WINDOW, 32, 722 map(lambda w: w.id, windows), 723 onerror = onerror) 724 725 def get_wm_colormap_windows(self): 726 d = self.get_full_property(self.display.get_atom('WM_COLORMAP_WINDOWS'), 727 Xatom.WINDOW) 728 if d is None or d.format != 32: 729 return [] 730 else: 731 cls = self.display.get_resource_class('window', Window) 732 return map(lambda i, d = self.display, c = cls: c(d, i), 733 d.value) 734 735 736 def set_wm_client_machine(self, name, onerror = None): 737 self.change_text_property(Xatom.WM_CLIENT_MACHINE, Xatom.STRING, name, 738 onerror = onerror) 739 740 def get_wm_client_machine(self): 741 return self.get_full_text_property(Xatom.WM_CLIENT_MACHINE, Xatom.STRING) 742 743 def set_wm_normal_hints(self, hints = {}, onerror = None, **keys): 744 self._set_struct_prop(Xatom.WM_NORMAL_HINTS, Xatom.WM_SIZE_HINTS, 745 icccm.WMNormalHints, hints, keys, onerror) 746 747 def get_wm_normal_hints(self): 748 return self._get_struct_prop(Xatom.WM_NORMAL_HINTS, Xatom.WM_SIZE_HINTS, 749 icccm.WMNormalHints) 750 751 def set_wm_hints(self, hints = {}, onerror = None, **keys): 752 self._set_struct_prop(Xatom.WM_HINTS, Xatom.WM_HINTS, 753 icccm.WMHints, hints, keys, onerror) 754 755 def get_wm_hints(self): 756 return self._get_struct_prop(Xatom.WM_HINTS, Xatom.WM_HINTS, 757 icccm.WMHints) 758 759 def set_wm_state(self, hints = {}, onerror = None, **keys): 760 atom = self.display.get_atom('WM_STATE') 761 self._set_struct_prop(atom, atom, icccm.WMState, hints, keys, onerror) 762 763 def get_wm_state(self): 764 atom = self.display.get_atom('WM_STATE') 765 return self._get_struct_prop(atom, atom, icccm.WMState) 766 767 def set_wm_icon_size(self, hints = {}, onerror = None, **keys): 768 self._set_struct_prop(Xatom.WM_ICON_SIZE, Xatom.WM_ICON_SIZE, 769 icccm.WMIconSize, hints, keys, onerror) 770 771 def get_wm_icon_size(self): 772 return self._get_struct_prop(Xatom.WM_ICON_SIZE, Xatom.WM_ICON_SIZE, 773 icccm.WMIconSize) 774 775 # Helper function for getting structured properties. 776 # pname and ptype are atoms, and pstruct is a Struct object. 777 # Returns a DictWrapper, or None 778 779 def _get_struct_prop(self, pname, ptype, pstruct): 780 r = self.get_property(pname, ptype, 0, pstruct.static_size // 4) 781 if r and r.format == 32: 782 value = r.value.tostring() 783 if len(value) == pstruct.static_size: 784 return pstruct.parse_binary(value, self.display)[0] 785 786 return None 787 788 # Helper function for setting structured properties. 789 # pname and ptype are atoms, and pstruct is a Struct object. 790 # hints is a mapping or a DictWrapper, keys is a mapping. keys 791 # will be modified. onerror is the error handler. 792 793 def _set_struct_prop(self, pname, ptype, pstruct, hints, keys, onerror): 794 if isinstance(hints, rq.DictWrapper): 795 keys.update(hints._data) 796 else: 797 keys.update(hints) 798 799 value = pstruct.to_binary(*(), **keys) 800 801 self.change_property(pname, ptype, 32, value, onerror = onerror) 802 803 804class Pixmap(Drawable): 805 __pixmap__ = resource.Resource.__resource__ 806 807 def free(self, onerror = None): 808 request.FreePixmap(display = self.display, 809 onerror = onerror, 810 pixmap = self.id) 811 812 self.display.free_resource_id(self.id) 813 814 def create_cursor(self, mask, foreground, background, x, y): 815 fore_red, fore_green, fore_blue = foreground 816 back_red, back_green, back_blue = background 817 cid = self.display.allocate_resource_id() 818 request.CreateCursor(display = self.display, 819 cid = cid, 820 source = self.id, 821 mask = mask, 822 fore_red = fore_red, 823 fore_green = fore_green, 824 fore_blue = fore_blue, 825 back_red = back_red, 826 back_green = back_green, 827 back_blue = back_blue, 828 x = x, 829 y = y) 830 cls = self.display.get_resource_class('cursor', cursor.Cursor) 831 return cls(self.display, cid, owner = 1) 832 833 834def roundup(value, unit): 835 return (value + (unit - 1)) & ~(unit - 1) 836