/* * This file is part of firk's window manager for x11 (fwm) * Copyright (C) 2016-2022 firk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include "main.h" #include "base.h" #include "config.h" #include "winlist.h" #include "taskbar.h" #include #include #include "tick.h" #include "runprog.h" Display * display; Screen * screen; int sw, sh; Window rootwin; Cursor cur_left_ptr; static unsigned long colors[16]; Atom atom_PROTOCOLS; Atom atom_DELETE; Atom atom_TAKEFOCUS; Atom atom_STATE; static unsigned int super_keycode[2]; static void init_atoms(void) { atom_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", False); atom_DELETE = XInternAtom(display, "WM_DELETE_WINDOW", False); atom_TAKEFOCUS = XInternAtom(display, "WM_TAKE_FOCUS", False); atom_STATE = XInternAtom(display, "WM_STATE", False); } extern int send_atom_message(Window window, Atom msg) { Atom * protos; int nprotos, n; XEvent ev; if(!XGetWMProtocols(display, window, &protos, &nprotos)) return 0; for(n=0;n8) m=8; for(n=0; n<(1U<keycode = XKeysymToKeycode(display, hk->keysym); if(hk->keycode) grabkey(hk->keycode, SPECMASK|hk->shift); } if(super_keycode[0]=XKeysymToKeycode(display, XK_Super_L)) { grabkey(super_keycode[0], 0); grabkey(super_keycode[0], ControlMask); grabkey(super_keycode[0], ShiftMask); grabkey(super_keycode[0], ControlMask|ShiftMask); } if(super_keycode[1]=XKeysymToKeycode(display, XK_Super_R)) { grabkey(super_keycode[1], 0); grabkey(super_keycode[1], ControlMask); grabkey(super_keycode[1], ShiftMask); grabkey(super_keycode[1], ControlMask|ShiftMask); } } extern int base_get_event(XEvent * ev) { if(XCheckMaskEvent(display, -1, ev)==False) return 0; return 1; } extern void base_wait_event(XEvent * ev) { XNextEvent(display, ev); } /* window creation: got CreateNotify (parent=rootwin) got ConfigureRequest (parent=rootwin) call XConfigureWindow got ConfigureNotify (event=rootwin) got ConfigureRequest call XConfigureWindow got ConfigureNotify (event=rootwin) got MapRequest (parent=rootwin) call XMapWindow got MapNotify (event=rootwin) on destroying: got UnmapNotify (event=rootwin) got DestroyNotify (event=rootwin) */ extern int base_handle_event(XEvent * ev) { WInfo * wi; XWindowChanges wchg; unsigned long t; char const * cmd; unsigned int shift; switch(ev->type) { /* just say we handled these useless events */ case CreateNotify: if(ev->xcreatewindow.parent!=rootwin) return 0; return 1; case ConfigureNotify: if(ev->xconfigure.window==rootwin) { #ifndef WATCH_ROOTWIN_RESIZE return 0; #else sw = ev->xconfigure.width; if(sw<0) sw=0; sh = ev->xconfigure.height; if(sh<0) sh=0; return 1; #endif } if(ev->xconfigure.event!=rootwin) return 0; taskbar_upd_winfo(ev->xconfigure.window); return 1; case MapNotify: if(ev->xmap.event!=rootwin) return 0; return 1; /* real useful events */ case ConfigureRequest: if(ev->xconfigurerequest.parent!=rootwin) return 0; /* this event can be for both mapped and not mapped window just retranslate it */ wchg.x = ev->xconfigurerequest.x; wchg.y = ev->xconfigurerequest.y; wchg.width = ev->xconfigurerequest.width; wchg.height = ev->xconfigurerequest.height; #ifndef FORCE_BORDERS_WIDTH wchg.border_width = ev->xconfigurerequest.border_width; #else wchg.border_width = FORCE_BORDERS_WIDTH; ev->xconfigurerequest.value_mask |= CWBorderWidth; #endif #ifdef MIN_BORDERS_WIDTH if(wchg.border_widthxconfigurerequest.above; wchg.stack_mode = ev->xconfigurerequest.detail;*/ XConfigureWindow(display, ev->xconfigurerequest.window, ev->xconfigurerequest.value_mask & ~CWSibling & ~CWStackMode , &wchg); return 1; case MapRequest: if(ev->xmaprequest.parent!=rootwin) return 0; /* ignore map requests for system windows from other clients */ if(ev->xmaprequest.window==taskbar_window || ev->xmaprequest.window==bg_window) return 1; if(taskbar_add_winfo(ev->xmaprequest.window)) { XSelectInput(display, ev->xmaprequest.window, FocusChangeMask|PropertyChangeMask); XMapWindow(display, ev->xmaprequest.window); taskbar_focus_window(ev->xmaprequest.window); } else { logprint("ERROR! too many windows! destroying new one!"); XDestroyWindow(display, ev->xmaprequest.window); } return 1; case UnmapNotify: if(ev->xunmap.event!=rootwin) return 0; taskbar_del_winfo(ev->xunmap.window); return 1; case DestroyNotify: if(ev->xdestroywindow.event!=rootwin) return 0; taskbar_del_winfo(ev->xdestroywindow.window); return 1; case FocusIn: wi = taskbar_search_winfo(ev->xfocus.window); if(!wi) return 1; if(!wi->is_active) taskbar_fix_focus(); /* prevent focus stealing */ return 1; case FocusOut: wi = taskbar_search_winfo(ev->xfocus.window); if(!wi) return 1; return 1; case PropertyNotify: if(!taskbar_upd_winfo(ev->xproperty.window)) return 0; return 1; case ButtonPress: wi = taskbar_search_winfo(ev->xbutton.window); if(!wi) return 0; if(!wi->is_active) taskbar_focus_window(wi->window); if(CLRMOD(ev->xbutton.state)==SPECMASK) { t = get_ticks(); if(ev->xbutton.button==Button1) { if(wi->specstate==2 && t-wi->spec1ticksspecstate = 3; } else if(wi->specstate==0 || wi->specstate==2) { wi->specstate=1; wi->spec1ticks = t; wi->spec1x=ev->xbutton.x_root; wi->spec1y=ev->xbutton.y_root; wi->spec2x=wi->x0; wi->spec2y=wi->y0; } } else if(ev->xbutton.button==Button3) { wi->specstate=5; wi->spec1x=ev->xbutton.x_root; wi->spec1y=ev->xbutton.y_root; wi->spec2x=wi->w; wi->spec2y=wi->h; } } return 1; case ButtonRelease: wi = taskbar_search_winfo(ev->xbutton.window); if(!wi) return 0; if(wi->specstate==1) { wi->specstate=2; } else if(wi->specstate==3) { wi->specstate = 0; taskbar_toggle_maximize(wi->window); } else wi->specstate = 0; return 1; case MotionNotify: wi = taskbar_search_winfo(ev->xmotion.window); if(!wi) return 0; if(wi->specstate==1) { int dx, dy; dx = ev->xmotion.x_root-wi->spec1x; dy = ev->xmotion.y_root-wi->spec1y; wi->spec2x += dx; wi->spec2y += dy; wi->x0 = wi->spec2x; wi->y0 = wi->spec2y; XMoveWindow(display, wi->window, wi->x0, wi->y0); wi->spec1x += dx; wi->spec1y += dy; } else if(wi->specstate==5) { int dx, dy; dx = ev->xmotion.x_root-wi->spec1x; dy = ev->xmotion.y_root-wi->spec1y; wi->spec2x += dx; wi->spec2y += dy; if(wi->spec2x<1) wi->spec2x=1; if(wi->spec2y<1) wi->spec2y=1; wi->w = wi->spec2x; wi->h = wi->spec2y; XResizeWindow(display, wi->window, wi->w, wi->h); wi->spec1x += dx; wi->spec1y += dy; } return 1; case KeyPress: if(ev->xkey.window!=rootwin) return 0; if(!ev->xkey.keycode) return 0; shift = CLRMOD(ev->xkey.state); if((shift & SPECMASK)!=SPECMASK) return 0; cmd = get_hotkey_by_keycode(ev->xkey.keycode, shift-SPECMASK); /* gcc does not allow switch() for pointers for some reason */ if(!cmd) return 0; else if(cmd==OP_CLOSE_WINDOW) { if(wi = taskbar_get_focuswin()) { if(!send_atom_message(wi->window, atom_DELETE)) { XDestroyWindow(display, wi->window); XSync(display, False); } } } else if(cmd==OP_KILL_WINDOW) { if(wi = taskbar_get_focuswin()) { XDestroyWindow(display, wi->window); XSync(display, False); } } else if(cmd==OP_TOGGLE_FULL) { taskbar_toggle_fullscreen_focus(); } else if(cmd==OP_NEXT_WINDOW) { taskbar_next_window(); } else if(cmd==OP_PREV_WINDOW) { taskbar_prev_window(); } else if(cmd==OP_ZPREV_WINDOW) { taskbar_zprev_window(); } else if(cmd==OP_TOGGLE_ONTOP) { taskbar_toggle_ontop_focus(); } else if(cmd==OP_QUIT) { exit(0); } else { run_command(cmd); } return 1; case KeyRelease: if(ev->xkey.window!=rootwin) return 0; if(ev->xkey.keycode==super_keycode[0] || ev->xkey.keycode==super_keycode[1]) taskbar_zprev_window_finish(); return 1; default: return 0; } } extern unsigned long base_color(unsigned char c) { return colors[c&15]; }