/* Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts * * This file is part of ratpoison. * * ratpoison is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * ratpoison is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ #include "ratpoison.h" #include /* for usleep(). */ int alarm_signalled = 0; int kill_signalled = 0; int hup_signalled = 0; int chld_signalled = 0; int rat_x; int rat_y; int rat_visible = 1; /* rat is visible by default */ char *rp_exec_newwm = NULL; int rp_font_ascent, rp_font_descent, rp_font_width; Atom wm_name; Atom wm_state; Atom wm_change_state; Atom wm_protocols; Atom wm_delete; Atom wm_take_focus; Atom wm_colormaps; Atom rp_command; Atom rp_command_request; Atom rp_command_result; Atom rp_selection; /* netwm atoms */ Atom _net_wm_pid; Atom _net_supported; Atom _net_wm_window_type; Atom _net_wm_window_type_dialog; Atom _net_wm_name; Atom utf8_string; int rp_current_screen; rp_screen *screens; int num_screens; Display *dpy; rp_group *rp_current_group; LIST_HEAD (rp_groups); LIST_HEAD (rp_children); struct rp_defaults defaults; int ignore_badwindow = 0; char **myargv; struct rp_key prefix_key; struct modifier_info rp_modifier_info; /* rudeness levels */ int rp_honour_transient_raise = 1; int rp_honour_normal_raise = 1; int rp_honour_transient_map = 1; int rp_honour_normal_map = 1; char *rp_error_msg = NULL; /* Global frame numset */ struct numset *rp_frame_numset; /* The X11 selection globals */ rp_xselection selection; static void x_export_selection (void) { /* Hang the selections off screen 0's key window. */ XSetSelectionOwner(dpy, XA_PRIMARY, screens[0].key_window, CurrentTime); if (XGetSelectionOwner(dpy, XA_PRIMARY) != screens[0].key_window) PRINT_ERROR(("can't get primary selection")); XChangeProperty(dpy, screens[0].root, XA_CUT_BUFFER0, XA_STRING, 8, PropModeReplace, selection.text, selection.len); } void set_nselection (char *txt, int len) { int i; /* Update the selection structure */ if (selection.text != NULL) free(selection.text); /* Copy the string by hand. */ selection.text = malloc(len+1); selection.len = len + 1; for (i=0; i 0; nread += ct.nitems) { if ((XGetWindowProperty(dpy, current_screen()->input_window, rp_selection, (nread / 4), 4096, True, AnyPropertyType, &ct.encoding, &ct.format, &ct.nitems, &bytes_after, &ct.value) != Success)) { XFree(ct.value); sbuf_free(s); return NULL; } if (ct.value == NULL) continue; /* Accumulate the data. FIXME: ct.value may not be NULL terminated. */ sbuf_nconcat (s, ct.value, ct.nitems); XFree(ct.value); } return sbuf_free_struct (s); } char * get_selection (void) { Atom property; XEvent ev; rp_screen *s = current_screen (); int loops = 1000; /* Just insert our text, if we own the selection. */ if (selection.text) { return xstrdup (selection.text); } else { /* be a good icccm citizen */ XDeleteProperty (dpy, s->input_window, rp_selection); /* TODO: we shouldn't use CurrentTime here, use the time of the XKeyEvent, should we fake it? */ XConvertSelection (dpy, XA_PRIMARY, XA_STRING, rp_selection, s->input_window, CurrentTime); /* This seems like a hack. */ while (!XCheckTypedWindowEvent (dpy, s->input_window, SelectionNotify, &ev)) { if (loops == 0) { PRINT_ERROR (("selection request timed out\n")); return NULL; } usleep (10000); loops--; } PRINT_DEBUG (("SelectionNotify event\n")); property = ev.xselection.property; if (property != None) return get_primary_selection (); else return get_cut_buffer (); } } /* The hook dictionary globals. */ LIST_HEAD (rp_key_hook); LIST_HEAD (rp_switch_win_hook); LIST_HEAD (rp_switch_frame_hook); LIST_HEAD (rp_switch_group_hook); LIST_HEAD (rp_switch_screen_hook); LIST_HEAD (rp_quit_hook); LIST_HEAD (rp_restart_hook); LIST_HEAD (rp_delete_window_hook); struct rp_hook_db_entry rp_hook_db[]= {{"key", &rp_key_hook}, {"switchwin", &rp_switch_win_hook}, {"switchframe", &rp_switch_frame_hook}, {"switchgroup", &rp_switch_group_hook}, {"switchscreen", &rp_switch_screen_hook}, {"deletewindow", &rp_delete_window_hook}, {"quit", &rp_quit_hook}, {"restart", &rp_restart_hook}, {NULL, NULL}}; void set_rp_window_focus (rp_window *win) { PRINT_DEBUG (("Giving focus to '%s'\n", window_name (win))); XSetInputFocus (dpy, win->w, RevertToPointerRoot, CurrentTime); } void set_window_focus (Window window) { PRINT_DEBUG (("Giving focus to %ld\n", window)); XSetInputFocus (dpy, window, RevertToPointerRoot, CurrentTime); } LIST_HEAD (rp_frame_undos); LIST_HEAD (rp_frame_redos); void init_globals (void) { selection.text = NULL; selection.len = 0; } /* Wrapper font functions to support Xft */ void rp_draw_string (rp_screen *s, Drawable d, GC gc, int x, int y, char *string, int length) { if (length < 0) length = strlen (string); #ifdef USE_XFT_FONT if (s->xft_font) { XftDraw *draw; draw = XftDrawCreate (dpy, d, DefaultVisual (dpy, s->screen_num), DefaultColormap (dpy, s->screen_num)); if (draw) { XftDrawString8 (draw, &s->xft_color, s->xft_font, x, y, (FcChar8*) string, length); XftDrawDestroy (draw); } else PRINT_ERROR(("Failed to allocate XftDraw object\n")); } else #endif XmbDrawString (dpy, d, defaults.font, gc, x, y, string, length); } int rp_text_width (rp_screen *s, XFontSet font, char *string, int count) { if (count < 0) count = strlen (string); #ifdef USE_XFT_FONT if (s->xft_font) { XGlyphInfo extents; XftTextExtents8 (dpy, s->xft_font, (FcChar8*) string, count, &extents); return extents.xOff; } else #endif return XmbTextEscapement (font, string, count); }