jcs ratpoison hax
at master 1012 lines 27 kB view raw
1/* Ratpoison X events 2 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca> 3 * 4 * This file is part of ratpoison. 5 * 6 * ratpoison 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, or (at your option) 9 * any later version. 10 * 11 * ratpoison 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 17 * along with this software; see the file COPYING. If not, write to 18 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 19 * Boston, MA 02111-1307 USA 20 */ 21 22#include <X11/X.h> 23#include <X11/Xlib.h> 24#include <X11/Xutil.h> 25#include <X11/Xatom.h> 26#include <X11/keysym.h> 27#include <X11/Xmd.h> /* for CARD32. */ 28 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <strings.h> 33#include <signal.h> 34#include <errno.h> 35#include <unistd.h> 36#include <sys/time.h> 37#include <sys/wait.h> 38 39#include "ratpoison.h" 40 41/* The event currently being processed. Mostly used in functions from 42 action.c which need to forward events to other windows. */ 43XEvent rp_current_event; 44 45/* RAISED is non zero if a raised message should be used 0 for a map message. */ 46void 47show_rudeness_msg (rp_window *win, int raised) 48{ 49 rp_group *g = groups_find_group_by_window (win); 50 rp_window_elem *elem = group_find_window (&g->mapped_windows, win); 51 if (g == rp_current_group) 52 { 53 if (win->transient) 54 marked_message_printf (0, 0, raised ? MESSAGE_RAISE_TRANSIENT:MESSAGE_MAP_TRANSIENT, 55 elem->number, window_name (win)); 56 else 57 marked_message_printf (0, 0, raised ? MESSAGE_RAISE_WINDOW:MESSAGE_MAP_WINDOW, 58 elem->number, window_name (win)); 59 } 60 else 61 { 62 if (win->transient) 63 marked_message_printf (0, 0, raised ? MESSAGE_RAISE_TRANSIENT_GROUP:MESSAGE_MAP_TRANSIENT_GROUP, 64 elem->number, window_name (win), g->name); 65 else 66 marked_message_printf (0, 0, raised ? MESSAGE_RAISE_WINDOW_GROUP:MESSAGE_MAP_WINDOW_GROUP, 67 elem->number, window_name (win), g->name); 68 } 69} 70 71static void 72new_window (XCreateWindowEvent *e) 73{ 74 rp_window *win; 75 rp_screen *s; 76 77 if (e->override_redirect) 78 return; 79 80 win = find_window (e->window); 81 82 /* New windows belong to the current screen */ 83 s = rp_current_screen; 84 85 if (is_rp_window (e->window)) return; 86 87 if (s && win == NULL 88 && e->window != s->key_window 89 && e->window != s->bar_window 90 && e->window != s->input_window 91 && e->window != s->frame_window 92 && e->window != s->help_window) 93 { 94 win = add_to_window_list (s, e->window); 95 update_window_information (win); 96 } 97} 98 99static void 100unmap_notify (XEvent *ev) 101{ 102 rp_frame *frame; 103 rp_window *win; 104 105 /* ignore SubstructureNotify unmaps. */ 106 if(ev->xunmap.event != ev->xunmap.window 107 && ev->xunmap.send_event != True) 108 return; 109 110 /* FIXME: Should we only look in the mapped window list? */ 111 win = find_window_in_list (ev->xunmap.window, &rp_mapped_window); 112 113 if (win == NULL) 114 return; 115 116 switch (win->state) 117 { 118 case IconicState: 119 PRINT_DEBUG (("Withdrawing iconized window '%s'\n", window_name (win))); 120 if (ev->xunmap.send_event) withdraw_window (win); 121 break; 122 case NormalState: 123 PRINT_DEBUG (("Withdrawing normal window '%s'\n", window_name (win))); 124 /* If the window was inside a frame, fill the frame with another 125 window. */ 126 frame = find_windows_frame (win); 127 if (frame) 128 { 129 cleanup_frame (frame); 130 if (frame->number == win->scr->current_frame 131 && rp_current_screen == win->scr) 132 set_active_frame (frame, 0); 133 /* Since we may have switched windows, call the hook. */ 134 if (frame->win_number != EMPTY) 135 hook_run (&rp_switch_win_hook); 136 } 137 138 withdraw_window (win); 139 break; 140 } 141 142 update_window_names (win->scr, defaults.window_fmt); 143} 144 145static void 146map_request (XEvent *ev) 147{ 148 rp_window *win; 149 150 win = find_window (ev->xmap.window); 151 if (win == NULL) 152 { 153 PRINT_DEBUG (("Map request from an unknown window.\n")); 154 XMapWindow (dpy, ev->xmap.window); 155 return; 156 } 157 158 PRINT_DEBUG (("Map request from a managed window\n")); 159 160 switch (win->state) 161 { 162 case WithdrawnState: 163 if (unmanaged_window (win->w)) 164 { 165 PRINT_DEBUG (("Mapping Unmanaged Window\n")); 166 XMapWindow (dpy, win->w); 167 break; 168 } 169 else 170 { 171 PRINT_DEBUG (("Mapping Withdrawn Window\n")); 172 map_window (win); 173 break; 174 } 175 break; 176 case IconicState: 177 PRINT_DEBUG (("Mapping Iconic window\n")); 178 if (win->last_access == 0) 179 { 180 /* Depending on the rudeness level, actually map the 181 window. */ 182 if ((rp_honour_transient_map && win->transient) 183 || (rp_honour_normal_map && !win->transient)) 184 set_active_window (win); 185 } 186 else 187 { 188 /* Depending on the rudeness level, actually map the 189 window. */ 190 if ((rp_honour_transient_raise && win->transient) 191 || (rp_honour_normal_raise && !win->transient)) 192 set_active_window (win); 193 else 194 show_rudeness_msg (win, 1); 195 } 196 break; 197 } 198} 199 200static void 201destroy_window (XDestroyWindowEvent *ev) 202{ 203 rp_window *win; 204 205 win = find_window (ev->window); 206 if (win == NULL) return; 207 208 ignore_badwindow++; 209 210 /* If, somehow, the window is not withdrawn before it is destroyed, 211 perform the necessary steps to withdraw the window before it is 212 unmanaged. */ 213 if (win->state == IconicState) 214 { 215 PRINT_DEBUG (("Destroying Iconic Window (%s)\n", window_name (win))); 216 withdraw_window (win); 217 } 218 else if (win->state == NormalState) 219 { 220 rp_frame *frame; 221 222 PRINT_DEBUG (("Destroying Normal Window (%s)\n", window_name (win))); 223 frame = find_windows_frame (win); 224 if (frame) 225 { 226 cleanup_frame (frame); 227 if (frame->number == win->scr->current_frame 228 && rp_current_screen == win->scr) 229 set_active_frame (frame, 0); 230 /* Since we may have switched windows, call the hook. */ 231 if (frame->win_number != EMPTY) 232 hook_run (&rp_switch_win_hook); 233 } 234 withdraw_window (win); 235 } 236 237 /* Now that the window is guaranteed to be in the unmapped window 238 list, we can safely stop managing it. */ 239 unmanage (win); 240 ignore_badwindow--; 241} 242 243static void 244configure_request (XConfigureRequestEvent *e) 245{ 246 XWindowChanges changes; 247 rp_window *win; 248 249 win = find_window (e->window); 250 251 if (win) 252 { 253 if (e->value_mask & CWStackMode) 254 { 255 if (e->detail == Above && win->state != WithdrawnState) 256 { 257 /* Depending on the rudeness level, actually map the 258 window. */ 259 if ((rp_honour_transient_raise && win->transient) 260 || (rp_honour_normal_raise && !win->transient)) 261 { 262 if (win->state == IconicState) 263 set_active_window (win); 264 else if (find_windows_frame (win)) 265 goto_window (win); 266 } 267 else if (current_window() != win) 268 { 269 show_rudeness_msg (win, 1); 270 } 271 272 } 273 274 PRINT_DEBUG(("request CWStackMode %d\n", e->detail)); 275 } 276 277 PRINT_DEBUG (("'%s' window size: %d %d %d %d %d\n", window_name (win), 278 win->x, win->y, win->width, win->height, win->border)); 279 280 /* Collect the changes to be granted. */ 281 if (e->value_mask & CWBorderWidth) 282 { 283 changes.border_width = e->border_width; 284 win->border = e->border_width; 285 PRINT_DEBUG(("request CWBorderWidth %d\n", e->border_width)); 286 } 287 288 if (e->value_mask & CWWidth) 289 { 290 changes.width = e->width; 291 win->width = e->width; 292 PRINT_DEBUG(("request CWWidth %d\n", e->width)); 293 } 294 295 if (e->value_mask & CWHeight) 296 { 297 changes.height = e->height; 298 win->height = e->height; 299 PRINT_DEBUG(("request CWHeight %d\n", e->height)); 300 } 301 302 if (e->value_mask & CWX) 303 { 304 changes.x = e->x; 305 win->x = e->x; 306 PRINT_DEBUG(("request CWX %d\n", e->x)); 307 } 308 309 if (e->value_mask & CWY) 310 { 311 changes.y = e->y; 312 win->y = e->y; 313 PRINT_DEBUG(("request CWY %d\n", e->y)); 314 } 315 316 if (e->value_mask & (CWX|CWY|CWBorderWidth|CWWidth|CWHeight)) 317 { 318 /* Grant the request, then immediately maximize it. */ 319 XConfigureWindow (dpy, win->w, 320 e->value_mask & (CWX|CWY|CWBorderWidth|CWWidth|CWHeight), 321 &changes); 322 XSync(dpy, False); 323 if (win->state == NormalState) 324 maximize (win); 325 } 326 } 327 else 328 { 329 /* Its an unmanaged window, so give it what it wants. But don't 330 change the stack mode.*/ 331 if (e->value_mask & CWX) changes.x = e->x; 332 if (e->value_mask & CWY) changes.x = e->x; 333 if (e->value_mask & CWWidth) changes.x = e->x; 334 if (e->value_mask & CWHeight) changes.x = e->x; 335 if (e->value_mask & CWBorderWidth) changes.x = e->x; 336 XConfigureWindow (dpy, e->window, 337 e->value_mask & (CWX|CWY|CWBorderWidth|CWWidth|CWHeight), 338 &changes); 339 } 340} 341 342static void 343client_msg (XClientMessageEvent *ev) 344{ 345 PRINT_DEBUG (("Received client message.\n")); 346 347 if (ev->message_type == wm_change_state) 348 { 349 rp_window *win; 350 351 PRINT_DEBUG (("WM_CHANGE_STATE\n")); 352 353 win = find_window (ev->window); 354 if (win == NULL) return; 355 if (ev->format == 32 && ev->data.l[0] == IconicState) 356 { 357 /* FIXME: This means clients can hide themselves without the 358 user's intervention. This is bad, but Emacs is the only 359 program I know of that iconifies itself and this is 360 generally from the user pressing C-z. */ 361 PRINT_DEBUG (("Iconify Request.\n")); 362 if (win->state == NormalState) 363 { 364 rp_window *w = find_window_other(win->scr); 365 366 if (w) 367 set_active_window (w); 368 else 369 blank_frame (screen_get_frame (win->scr, win->scr->current_frame)); 370 } 371 } 372 else 373 { 374 PRINT_ERROR (("Non-standard WM_CHANGE_STATE format\n")); 375 } 376 } 377} 378 379static void 380handle_key (KeySym ks, unsigned int mod, rp_screen *s) 381{ 382 rp_action *key_action; 383 rp_keymap *map = find_keymap (defaults.top_kmap); 384 385 if (map == NULL) 386 { 387 PRINT_ERROR (("Unable to find %s keymap\n", defaults.top_kmap)); 388 return; 389 } 390 391 PRINT_DEBUG (("handling key...\n")); 392 393 /* All functions hide the program bar and the frame indicator. */ 394 if (defaults.bar_timeout > 0) hide_bar (s); 395 hide_frame_indicator(); 396 397 /* Disable any alarm that was going to go off. */ 398 alarm (0); 399 alarm_signalled = 0; 400 401 /* Call the top level key pressed hook. */ 402 hook_run (&rp_key_hook); 403 404 PRINT_DEBUG (("handle_key\n")); 405 406 /* Read a key and execute the command associated with it on the 407 default keymap. Ignore the key if it doesn't have a binding. */ 408 if ((key_action = find_keybinding (ks, x11_mask_to_rp_mask (mod), map))) 409 { 410 cmdret *result; 411 412 PRINT_DEBUG(("%s\n", key_action->data)); 413 414 result = command (1, key_action->data); 415 416 if (result) 417 { 418 if (result->output) 419 message (result->output); 420 cmdret_free (result); 421 } 422 } 423 else 424 { 425 PRINT_DEBUG(("Impossible: No matching key")); 426 } 427} 428 429static void 430key_press (XEvent *ev) 431{ 432 rp_screen *s; 433 unsigned int modifier; 434 KeySym ks; 435 436 s = rp_current_screen; 437 if (!s) return; 438 439#ifdef HIDE_MOUSE 440 XWarpPointer (dpy, None, s->root, 0, 0, 0, 0, s->left + s->width - 2, s->top + s->height - 2); 441#endif 442 443 modifier = ev->xkey.state; 444 cook_keycode ( &ev->xkey, &ks, &modifier, NULL, 0, 1); 445 446 handle_key (ks, modifier, s); 447} 448 449/* Read a command off the window and execute it. Some commands return 450 text. This text is passed back using the RP_COMMAND_RESULT 451 Atom. The client will wait for this property change so something 452 must be returned. */ 453static cmdret * 454execute_remote_command (Window w) 455{ 456 int status; 457 cmdret *ret; 458 Atom type_ret; 459 int format_ret; 460 unsigned long nitems; 461 unsigned long bytes_after; 462 unsigned char *req; 463 464 status = XGetWindowProperty (dpy, w, rp_command, 465 0, 0, False, xa_string, 466 &type_ret, &format_ret, &nitems, &bytes_after, 467 &req); 468 469 if (status != Success || req == NULL) 470 { 471 return cmdret_new (RET_FAILURE, "Couldn't get RP_COMMAND Property"); 472 } 473 474 /* XGetWindowProperty always allocates one extra byte even if 475 the property is zero length. */ 476 XFree (req); 477 478 status = XGetWindowProperty (dpy, w, rp_command, 479 0, (bytes_after / 4) + (bytes_after % 4 ? 1 : 0), 480 True, xa_string, &type_ret, &format_ret, &nitems, 481 &bytes_after, &req); 482 483 if (status != Success || req == NULL) 484 { 485 return cmdret_new (RET_FAILURE, "Couldn't get RP_COMMAND Property"); 486 } 487 488 PRINT_DEBUG (("command: %s\n", req)); 489 ret = command (req[0], (char *)&req[1]); 490 XFree (req); 491 492 return ret; 493} 494 495/* Command requests are posted as a property change using the 496 RP_COMMAND_REQUEST Atom on the root window. A Command request is a 497 Window that holds the actual command as a property using the 498 RP_COMMAND Atom. receive_command reads the list of Windows and 499 executes their associated command. */ 500static void 501receive_command (Window root) 502{ 503 cmdret *cmd_ret; 504 char *result; 505 Atom type_ret; 506 int format_ret; 507 unsigned long nitems; 508 unsigned long bytes_after; 509 unsigned char *prop_return; 510 int offset; 511 512 /* Init offset to 0. In the case where there is more than one window 513 in the property, a partial read does not delete the property and 514 we need to grab the next window by incementing offset to the 515 offset of the next window. */ 516 offset = 0; 517 do 518 { 519 int ret; 520 int length; 521 Window w; 522 523 length = sizeof (Window) / 4 + (sizeof (Window) % 4 ?1:0); 524 ret = XGetWindowProperty (dpy, root, 525 rp_command_request, 526 offset, length, 527 True, XA_WINDOW, &type_ret, &format_ret, 528 &nitems, 529 &bytes_after, &prop_return); 530 531 /* Update the offset to point to the next window (if there is 532 another one). */ 533 offset += length; 534 535 if (ret != Success) 536 { 537 PRINT_ERROR (("XGetWindowProperty Failed\n")); 538 if (prop_return) 539 XFree (prop_return); 540 break; 541 } 542 543 /* If there was no window, then we're done. */ 544 if (prop_return == NULL) 545 { 546 PRINT_DEBUG (("No property to read\n")); 547 break; 548 } 549 550 /* We grabbed a window, so now read the command stored in 551 this window and execute it. */ 552 w = *(Window *)prop_return; 553 XFree (prop_return); 554 cmd_ret = execute_remote_command (w); 555 556 /* notify the client of any text that was returned by the 557 command. see communications.c:receive_command_result() */ 558 if (cmd_ret->output) 559 result = xsprintf ("%c%s", cmd_ret->success ? '1':'0', cmd_ret->output); 560 else if (!cmd_ret->success) 561 result = xstrdup("0"); 562 else 563 result = NULL; 564 565 if (result) 566 XChangeProperty (dpy, w, rp_command_result, xa_string, 567 8, PropModeReplace, (unsigned char *)result, strlen (result)); 568 else 569 XChangeProperty (dpy, w, rp_command_result, xa_string, 570 8, PropModeReplace, NULL, 0); 571 free (result); 572 cmdret_free (cmd_ret); 573 } while (bytes_after > 0); 574} 575 576static void 577property_notify (XEvent *ev) 578{ 579 rp_window *win; 580 581 PRINT_DEBUG (("atom: %ld\n", ev->xproperty.atom)); 582 583 if (ev->xproperty.atom == rp_command_request 584 && is_a_root_window (ev->xproperty.window) 585 && ev->xproperty.state == PropertyNewValue) 586 { 587 PRINT_DEBUG (("ratpoison command\n")); 588 receive_command(ev->xproperty.window); 589 } 590 591 win = find_window (ev->xproperty.window); 592 593 if (win) 594 { 595 if (ev->xproperty.atom == _net_wm_pid) 596 { 597 struct rp_child_info *child_info; 598 599 PRINT_DEBUG (("updating _NET_WM_PID\n")); 600 child_info = get_child_info(win->w); 601 if (child_info && !child_info->window_mapped) 602 { 603 if (child_info->frame) 604 { 605 PRINT_DEBUG (("frame=%p\n", child_info->frame)); 606 win->intended_frame_number = child_info->frame->number; 607 /* Only map the first window in the launch frame. */ 608 child_info->window_mapped = 1; 609 } 610 /* TODO: also adopt group information? */ 611 } 612 } else 613 switch (ev->xproperty.atom) 614 { 615 case XA_WM_NAME: 616 PRINT_DEBUG (("updating window name\n")); 617 if (update_window_name (win)) { 618 update_window_names (win->scr, defaults.window_fmt); 619 hook_run (&rp_title_changed_hook); 620 } 621 break; 622 623 case XA_WM_NORMAL_HINTS: 624 PRINT_DEBUG (("updating window normal hints\n")); 625 update_normal_hints (win); 626 if (win->state == NormalState) 627 maximize (win); 628 break; 629 630 case XA_WM_TRANSIENT_FOR: 631 PRINT_DEBUG (("Transient for\n")); 632 win->transient = XGetTransientForHint (dpy, win->w, &win->transient_for); 633 break; 634 635 default: 636 PRINT_DEBUG (("Unhandled property notify event: %ld\n", ev->xproperty.atom)); 637 break; 638 } 639 } 640} 641 642static void 643colormap_notify (XEvent *ev) 644{ 645 rp_window *win; 646 647 win = find_window (ev->xcolormap.window); 648 649 if (win != NULL) 650 { 651 XWindowAttributes attr; 652 653 /* SDL sets the colormap just before destroying the window, so 654 ignore BadWindow errors. */ 655 ignore_badwindow++; 656 657 XGetWindowAttributes (dpy, win->w, &attr); 658 win->colormap = attr.colormap; 659 660 if (win == current_window() 661 && !rp_current_screen->bar_is_raised) 662 { 663 XInstallColormap (dpy, win->colormap); 664 } 665 666 ignore_badwindow--; 667 } 668} 669 670static void 671focus_change (XFocusChangeEvent *ev) 672{ 673 rp_window *win; 674 675 /* We're only interested in the NotifyGrab mode */ 676 if (ev->mode != NotifyGrab) return; 677 678 win = find_window (ev->window); 679 680 if (win != NULL) 681 { 682 PRINT_DEBUG (("Re-grabbing prefix key\n")); 683 grab_top_level_keys (win->w); 684 } 685} 686 687static void 688mapping_notify (XMappingEvent *ev) 689{ 690 ungrab_keys_all_wins(); 691 692 switch (ev->request) 693 { 694 case MappingModifier: 695 update_modifier_map(); 696 /* This is meant to fall through. */ 697 case MappingKeyboard: 698 XRefreshKeyboardMapping (ev); 699 break; 700 } 701 702 grab_keys_all_wins(); 703} 704 705static void 706configure_notify (XConfigureEvent *ev) 707{ 708 rp_screen *s; 709 710 s = find_screen(ev->window); 711 if (s != NULL) 712 /* This is a root window of a screen, 713 * look if its width or height changed: */ 714 screen_update (s, ev->x, ev->y, ev->width, ev->height); 715} 716 717/* This is called when an application has requested the 718 selection. Copied from rxvt. */ 719static void 720selection_request (XSelectionRequestEvent *rq) 721{ 722 XEvent ev; 723 CARD32 target_list[4]; 724 Atom target; 725 static Atom xa_targets = None; 726 static Atom xa_text = None; /* XXX */ 727 XTextProperty ct; 728 XICCEncodingStyle style; 729 char *cl[4]; 730 731 if (xa_text == None) 732 xa_text = XInternAtom(dpy, "TEXT", False); 733 if (xa_targets == None) 734 xa_targets = XInternAtom(dpy, "TARGETS", False); 735 736 ev.xselection.type = SelectionNotify; 737 ev.xselection.property = None; 738 ev.xselection.display = rq->display; 739 ev.xselection.requestor = rq->requestor; 740 ev.xselection.selection = rq->selection; 741 ev.xselection.target = rq->target; 742 ev.xselection.time = rq->time; 743 744 if (rq->target == xa_targets) { 745 target_list[0] = (CARD32) xa_targets; 746 target_list[1] = (CARD32) xa_string; 747 target_list[2] = (CARD32) xa_text; 748 target_list[3] = (CARD32) xa_compound_text; 749 XChangeProperty(dpy, rq->requestor, rq->property, rq->target, 750 (8 * sizeof(target_list[0])), PropModeReplace, 751 (unsigned char *)target_list, 752 (sizeof(target_list) / sizeof(target_list[0]))); 753 ev.xselection.property = rq->property; 754 } else if (rq->target == xa_string 755 || rq->target == xa_compound_text 756 || rq->target == xa_text) { 757 if (rq->target == xa_string) { 758 style = XStringStyle; 759 target = xa_string; 760 } else { 761 target = xa_compound_text; 762 style = (rq->target == xa_compound_text) ? XCompoundTextStyle 763 : XStdICCTextStyle; 764 } 765 cl[0] = selection.text; 766 XmbTextListToTextProperty(dpy, cl, 1, style, &ct); 767 XChangeProperty(dpy, rq->requestor, rq->property, 768 target, 8, PropModeReplace, 769 ct.value, ct.nitems); 770 ev.xselection.property = rq->property; 771 } 772 XSendEvent(dpy, rq->requestor, False, 0, &ev); 773} 774 775static void 776selection_clear (void) 777{ 778 free (selection.text); 779 selection.text = NULL; 780 selection.len = 0; 781} 782 783/* Given an event, call the correct function to handle it. */ 784static void 785delegate_event (XEvent *ev) 786{ 787 788 if (rp_have_xrandr) 789 xrandr_notify (ev); 790 791 switch (ev->type) 792 { 793 case ConfigureRequest: 794 PRINT_DEBUG (("--- Handling ConfigureRequest ---\n")); 795 configure_request (&ev->xconfigurerequest); 796 break; 797 798 case CreateNotify: 799 PRINT_DEBUG (("--- Handling CreateNotify ---\n")); 800 new_window (&ev->xcreatewindow); 801 break; 802 803 case DestroyNotify: 804 PRINT_DEBUG (("--- Handling DestroyNotify ---\n")); 805 destroy_window (&ev->xdestroywindow); 806 break; 807 808 case ClientMessage: 809 PRINT_DEBUG (("--- Handling ClientMessage ---\n")); 810 client_msg (&ev->xclient); 811 break; 812 813 case ColormapNotify: 814 PRINT_DEBUG (("--- Handling ColormapNotify ---\n")); 815 colormap_notify (ev); 816 break; 817 818 case PropertyNotify: 819 PRINT_DEBUG (("--- Handling PropertyNotify ---\n")); 820 property_notify (ev); 821 break; 822 823 case MapRequest: 824 PRINT_DEBUG (("--- Handling MapRequest ---\n")); 825 map_request (ev); 826 break; 827 828 case KeyPress: 829 PRINT_DEBUG (("--- Handling KeyPress ---\n")); 830 key_press (ev); 831 break; 832 833 case UnmapNotify: 834 PRINT_DEBUG (("--- Handling UnmapNotify ---\n")); 835 unmap_notify (ev); 836 break; 837 838 case FocusOut: 839 PRINT_DEBUG (("--- Handling FocusOut ---\n")); 840 focus_change (&ev->xfocus); 841 break; 842 843 case FocusIn: 844 PRINT_DEBUG (("--- Handling FocusIn ---\n")); 845 focus_change (&ev->xfocus); 846 break; 847 848 case MappingNotify: 849 PRINT_DEBUG (("--- Handling MappingNotify ---\n")); 850 mapping_notify( &ev->xmapping ); 851 break; 852 853 case SelectionRequest: 854 selection_request(&ev->xselectionrequest); 855 break; 856 857 case SelectionClear: 858 selection_clear(); 859 break; 860 861 case ConfigureNotify: 862 if (!rp_have_xrandr) 863 { 864 PRINT_DEBUG (("--- Handling ConfigureNotify ---\n")); 865 configure_notify (&ev->xconfigure); 866 } 867 break; 868 869 case MapNotify: 870 case Expose: 871 case MotionNotify: 872 case KeyRelease: 873 case ReparentNotify: 874 case EnterNotify: 875 case SelectionNotify: 876 case CirculateRequest: 877 /* Ignore these events. */ 878 break; 879 880 default: 881 PRINT_DEBUG (("--- Unknown event %d ---\n",- ev->type)); 882 } 883} 884 885static void 886handle_signals (void) 887{ 888 /* An alarm means we need to hide the popup windows. */ 889 if (alarm_signalled > 0) 890 { 891 rp_screen *cur; 892 893 PRINT_DEBUG (("Alarm received.\n")); 894 895 /* Only hide the bar if it times out. */ 896 if (defaults.bar_timeout > 0) 897 { 898 list_for_each_entry (cur, &rp_screens, node) 899 { 900 hide_bar (cur); 901 } 902 } 903 904 hide_frame_indicator(); 905 alarm_signalled = 0; 906 } 907 908 if (chld_signalled > 0) 909 { 910 rp_child_info *cur; 911 struct list_head *iter, *tmp; 912 913 /* Report and remove terminated processes. */ 914 list_for_each_safe_entry (cur, iter, tmp, &rp_children, node) 915 { 916 if (cur->terminated) 917 { 918 /* Report any child that didn't return 0. */ 919 if (cur->status != 0) 920 marked_message_printf (0,0, "/bin/sh -c \"%s\" finished (%d)", 921 cur->cmd, cur->status); 922 list_del (&cur->node); 923 free (cur->cmd); 924 free (cur); 925 } 926 } 927 928 chld_signalled = 0; 929 } 930 931 if (rp_exec_newwm) 932 { 933 rp_screen *cur; 934 935 PRINT_DEBUG (("Switching to %s\n", rp_exec_newwm)); 936 937 putenv (rp_current_screen->display_string); 938 unhide_all_windows(); 939 XSync(dpy, False); 940 941 list_for_each_entry (cur, &rp_screens, node) 942 { 943 deactivate_screen (cur); 944 } 945 946 execlp (rp_exec_newwm, rp_exec_newwm, (char *)NULL); 947 948 /* Failed. Clean up. */ 949 PRINT_ERROR (("exec %s ", rp_exec_newwm)); 950 perror(" failed"); 951 free (rp_exec_newwm); 952 rp_exec_newwm = NULL; 953 954 list_for_each_entry (cur, &rp_screens, node) 955 { 956 activate_screen (cur); 957 } 958 } 959 960 if (hup_signalled > 0) 961 { 962 PRINT_DEBUG (("Restarting\n")); 963 hook_run (&rp_restart_hook); 964 clean_up (); 965 execvp(myargv[0], myargv); 966 } 967 968 if (kill_signalled > 0) 969 { 970 PRINT_DEBUG (("Exiting\n")); 971 hook_run (&rp_quit_hook); 972 clean_up (); 973 exit (EXIT_SUCCESS); 974 } 975 976 /* Report any X11 errors that have occurred. */ 977 if (rp_error_msg) 978 { 979 marked_message_printf (0, 6, "ERROR: %s", rp_error_msg); 980 free (rp_error_msg); 981 rp_error_msg = NULL; 982 } 983} 984 985/* The main loop. */ 986void 987listen_for_events (void) 988{ 989 int x_fd; 990 fd_set fds; 991 992 x_fd = ConnectionNumber (dpy); 993 FD_ZERO (&fds); 994 995 /* Loop forever. */ 996 for (;;) 997 { 998 handle_signals (); 999 1000 /* Handle the next event. */ 1001 FD_SET (x_fd, &fds); 1002 XFlush(dpy); 1003 1004 if (QLength (dpy) > 0 1005 || select(x_fd+1, &fds, NULL, NULL, NULL) == 1) 1006 { 1007 XNextEvent (dpy, &rp_current_event); 1008 delegate_event (&rp_current_event); 1009 XSync(dpy, False); 1010 } 1011 } 1012}