📄 focus.c
字号:
/* focus.c - records a history of focusses for reverting focus, also does focus cycling Copyright (C) 1996-2000 Paul Sheer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */#include <config.h>#include <stdio.h>#include <my_string.h>#include <stdlib.h>#include <stdarg.h>#include <X11/Intrinsic.h>#include "stringtools.h"#include "app_glob.c"#include "coolwidget.h"#include "coollocal.h"#include "mad.h"/* Focus stack: This stack remembers the focus historyso that when widgets are destroyed, the focus returns tothe most recent widget in the history. This is equivalentto the revert_to in the XSetInputFocus() function,however XSetInputFocus() has an effective history ofonly one.The commands to change focus are CFocus(CWidget *w)*/extern struct look *look;#define FOCUS_STACK_SIZE 128static Window focus_stack[FOCUS_STACK_SIZE];static int focus_sp = 0;static Window current_focus = -1;static Window current_ic_focus = -1;static Window dnd_focus = -1;void save_current_focus_for_dnd (Window new_focus){ dnd_focus = current_focus; current_focus = new_focus;}void restore_current_focus_for_dnd (void){ current_focus = dnd_focus;}void add_to_focus_stack (Window w){ int i; i = focus_sp; while (i--) if (focus_stack[i] == w) { focus_sp = i + 1; return; } if (focus_sp >= FOCUS_STACK_SIZE) {#ifdef FOCUS_DEBUG/* NLS ? */ printf ("add_to_focus_stack(): focus_sp overflow\n");#endif return; } focus_stack[focus_sp++] = w;#ifdef FOCUS_DEBUG/* NLS ? */ printf ("add_to_focus_stack(%x): focus_sp = %d\n", (unsigned int) w, focus_sp);#endif}void focus_stack_remove_window (Window w){ int i; i = focus_sp; while (i--) if (focus_stack[i] == w) { focus_stack[i] = 0; while (focus_sp && !focus_stack[focus_sp - 1]) focus_sp--;#ifdef FOCUS_DEBUG/* NLS ? */ printf ("focus_stack_remove_window(): focus_sp = %d\n", focus_sp);#endif return; }}Window CGetFocus(void){ return current_focus;}Window CGetICFocus(void){ return current_ic_focus;}void CFocusLast (void){ Window w; if (!focus_sp) return; w = focus_stack[focus_sp - 1]; if (w == current_focus) return; if (w) focus_window (w);}/* Each main window must record its last focussed window. This is so that when the window manager sets the focus to a main window. We can look up what widget within that window last had the focus, and move focus to that widget. */static Window *get_last_focussed_in_main (Window main){ static Window dummy; CWidget *w; w = CWidgetOfWindow (main); if (w) return &(w->last_child_focussed); dummy = 0; return &dummy; /* instead of 'return 0;' to prevent segfaults */}/* {{{ Focus border creation and rendering *//* this is four windows that surround the focussed window */struct focus_win focus_border ={ 0, 0, 0, 0, 0, 0, 0};Window get_focus_border_widget (void){ return focus_border.current;}/* draw a focus window around wodget w */void create_focus_border (CWidget * w, int border){ int x, y; XSetWindowAttributes xswa; xswa.colormap = CColormap; xswa.bit_gravity = NorthWestGravity; if (border > 2) xswa.background_pixel = color_palette(17); /* for drag and drop highlight borders */ else xswa.background_pixel = COLOR_FLAT; if (w->parentid == CRoot) { xswa.override_redirect = 1; } else { xswa.override_redirect = 0; } focus_border.border = border; x = w->x; y = w->y; if (w->parentid == CRoot) { Window child; XTranslateCoordinates(CDisplay, w->winid, CRoot, 0, 0, &x, &y, &child); } focus_border.top = XCreateWindow (CDisplay, w->parentid, x - WIDGET_FOCUS_RING, y - WIDGET_FOCUS_RING, w->width + WIDGET_FOCUS_RING * 2, WIDGET_FOCUS_RING, 0, CDepth, InputOutput, CVisual, CWOverrideRedirect | CWColormap | CWBackPixel | CWBitGravity, &xswa); focus_border.bottom = XCreateWindow (CDisplay, w->parentid, x - WIDGET_FOCUS_RING, y + w->height, w->width + WIDGET_FOCUS_RING * 2, WIDGET_FOCUS_RING, 0, CDepth, InputOutput, CVisual, CWOverrideRedirect | CWColormap | CWBackPixel | CWBitGravity, &xswa); focus_border.left = XCreateWindow (CDisplay, w->parentid, x - WIDGET_FOCUS_RING, y, WIDGET_FOCUS_RING, w->height, 0, CDepth, InputOutput, CVisual, CWOverrideRedirect | CWColormap | CWBackPixel | CWBitGravity, &xswa); focus_border.right = XCreateWindow (CDisplay, w->parentid, x + w->width, y, WIDGET_FOCUS_RING, w->height, 0, CDepth, InputOutput, CVisual, CWOverrideRedirect | CWColormap | CWBackPixel | CWBitGravity, &xswa); focus_border.current = w->winid; focus_border.width = w->width; focus_border.height = w->height; XSelectInput (CDisplay, focus_border.top, ExposureMask); XSelectInput (CDisplay, focus_border.bottom, ExposureMask); XSelectInput (CDisplay, focus_border.left, ExposureMask); XSelectInput (CDisplay, focus_border.right, ExposureMask); XMapWindow (CDisplay, focus_border.top); XMapWindow (CDisplay, focus_border.bottom); XMapWindow (CDisplay, focus_border.left); XMapWindow (CDisplay, focus_border.right);}void destroy_focus_border (void){ if (!focus_border.top) return; XDestroyWindow (CDisplay, focus_border.top); XDestroyWindow (CDisplay, focus_border.bottom); XDestroyWindow (CDisplay, focus_border.left); XDestroyWindow (CDisplay, focus_border.right); memset (&focus_border, 0, sizeof (focus_border));}int window_of_focus_border (Window win){ if (!focus_border.top) return 0; if (win == focus_border.top) return 1; if (win == focus_border.bottom) return 1; if (win == focus_border.left) return 1; if (win == focus_border.right) return 1; return 0;}void render_focus_border (Window win){ (*look->render_focus_border) (win);}static void set_ic_focus (CWidget * w){#ifdef USE_XIM if (w->mainid) { CIC = (CWidgetOfWindow (w->mainid))->input_context; current_ic_focus = w->mainid; } else { CIC = w->input_context; current_ic_focus = w->mainid; } if (CIC) XSetICFocus (CIC);#endif}/* }}} Focus border creation and rendering *//* This is called when the app (and not the WM) wants to change focus. */static void focus_widget (CWidget * w){ CWidget *old; if (current_focus == w->winid) {#ifdef FOCUS_DEBUG printf ("current_focus == w->winid, returning\n");#endif return; } destroy_focus_border (); if ((w->options & WIDGET_TAKES_FOCUS_RING)) create_focus_border (w, 1); old = CWidgetOfWindow (current_focus); current_focus = w->winid; /* notify library of new focus */ CSendMessage (old, FocusOut); /* unfocus the current focus *//* focus on the widgets main window if it has changed */ if (old) { if (old->mainid != w->mainid) goto set_main; } else { set_main:/* set that main windows 'last_child_focussed' */ XSetInputFocus (CDisplay, w->mainid, RevertToNone, CurrentTime); set_ic_focus (w); } *(get_last_focussed_in_main (w->mainid)) = w->winid;#ifdef FOCUS_DEBUG printf ("setting last_focus of %s = %s\n", (char *) CWidgetOfWindow (w->mainid), w->ident);#endif add_to_focus_stack (w->winid); /* record focus history *//* focus the new widget */ CSendMessage (w, FocusIn);}static void focus_main (Window main, int type){ CWidget *w; if (type == FocusOut) { w = CWidgetOfWindow (current_focus);#ifdef FOCUS_DEBUG printf ("focus_main(Out): %s\n", w->ident);#endif current_focus = -1; /* inform the library that nothing is focussed */ CSendMessage (w, FocusOut); destroy_focus_border (); } else { /* type == FocusIn *//* find the widget within this main that last had the focus: */ current_focus = *(get_last_focussed_in_main (main)); w = CWidgetOfWindow (current_focus);#ifdef FOCUS_DEBUG printf ("focus_main(In): %s\n", w->ident);#endif if (w) { add_to_focus_stack (w->winid); /* record focus history */ CSendMessage (w, FocusIn); /* focus the new widget */ if ((w->options & WIDGET_TAKES_FOCUS_RING)) create_focus_border (w, 2); set_ic_focus (w); } }}/* This is called from CNextEvent when the WM sends focus to a new different main window. */void process_external_focus (Window win, int type){ CWidget *w;#ifdef FOCUS_DEBUG printf ("Entering process_external_focus()\n");#endif w = CWidgetOfWindow (win); if (!w) {#ifdef FOCUS_DEBUG printf ("Leaving process_external_focus() - not our window\n");#endif return; }#ifdef FOCUS_DEBUG printf ("widget = %s\n", w->ident);#endif if (w->parentid == CRoot) { /* should always be true since only main windows have FocusChangeMask */ focus_main (w->winid, type);#ifdef FOCUS_DEBUG printf ("Leaving process_external_focus() - main window\n");#endif return; } else {#ifdef FOCUS_DEBUG printf ("Leaving process_external_focus() - not main window\n");#endif }}void focus_window (Window win){ CWidget *w; w = CWidgetOfWindow (win); if (w) CFocusNormal (w);}/* CFocus() is a macro for */void CFocusNormal (CWidget * w){ if (!w) return; if (!w->takes_focus) return; if (w->mapped & WINDOW_MAPPED) { focus_widget (w); } else { w->mapped |= WINDOW_FOCUS_WHEN_MAPPED; }}void CFocusDebug (CWidget *w, int line, char *file){/* NLS ? */ printf ("CFocus(%x): %s:%d (ident = %s)\n", (unsigned int) w->winid, file, line, w->ident); CFocusNormal (w);}/* get next sibling of w that has takes_focus set (i.e. that takes user input of any sort) */CWidget *CNextFocus (CWidget * w){ int i, j; i = j = find_next_child_of (w->parentid, w->winid); for (;;) { if (!i) { i = find_first_child_of (w->parentid); if (!i) return 0; } if (CIndex (i)->takes_focus && !CIndex(i)->disabled) return CIndex (i); w = CIndex (i); i = find_next_child_of (w->parentid, w->winid); if (i == j) /* done a round trip */ return 0; }}/* previous sibling of same */CWidget *CPreviousFocus (CWidget * w){ int i, j; i = j = find_previous_child_of (w->parentid, w->winid); for (;;) { if (!i) { i = find_last_child_of (w->parentid); if (!i) return 0; } if (CIndex (i)->takes_focus && !CIndex(i)->disabled) return CIndex (i); w = CIndex (i); i = find_previous_child_of (w->parentid, w->winid); if (i == j) /* done a round trip */ return 0; }}/* first child of widget that takes focus (eg w is a window and a button in the window is returned) */CWidget *CChildFocus (CWidget * w){ int j, i = find_first_child_of (w->winid); if(!i) return 0; w = CIndex (i); if(w->takes_focus) return w; j = i = find_next_child_of (w->parentid, w->winid); for (;;) { if (!i) { i = find_first_child_of (w->parentid); if (!i) return 0; } if (CIndex (i)->takes_focus) return CIndex (i); w = CIndex (i); i = find_next_child_of (w->parentid, w->winid); if (i == j) /* done a round trip */ return 0; }}/* search for two generations down for the first descendent that is a widget. If it does not take focus, then its first child is focussed. If it has no children, the next descendent is searched for. */CWidget *CFindFirstDescendent (Window win){ int i, j; i = find_first_child_of (win); if (i) { /* is it a child ? */ if (CIndex (i)->takes_focus && !CIndex (i)->disabled) { return (CIndex (i)); } else { CWidget *w; w = CChildFocus (CIndex (i)); if (w) return w; } } else { /* not a child */ Window root, parent, *children = 0; unsigned int nchildren = 0; if (!win) return 0; XQueryTree (CDisplay, win, &root, &parent, &children, &nchildren); if (!nchildren) { if (children) XFree (children); return 0; } for (j = 0; j < nchildren; j++) if ((i = find_first_child_of (children[j]))) { /* is it a grandchild ? */ if (CIndex (i)->takes_focus && !CIndex (i)->disabled) { XFree (children); return (CIndex (i)); } else { CWidget *w; w = CChildFocus (CIndex (i)); if (w) { XFree (children); return w; } } } XFree (children); } return 0; /* not a grandchild */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -