/* * button.c * * Part of gwm, the Gratuitous Window Manager, * by Gary Wong, . * * Copyright (C) 2009 Gary Wong * * This program is free software: you can redistribute it and/or modify * it under the terms of version 3 of the GNU General Public License 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, see . * * $Id$ */ #include #include #include #include "gwm.h" #include "button.h" #include "window-table.h" #define BUTTON_SIZE 12 /* size of buttons in title bar; excludes X border */ #define BUTTON_X_BORDER 1 extern int button_size( struct gwm_window *window, int include_x_border ) { assert( window->type == WINDOW_BUTTON ); return BUTTON_SIZE + ( include_x_border ? BUTTON_X_BORDER << 1 : 0 ); } extern int button_xb( struct gwm_window *window ) { assert( window->type == WINDOW_BUTTON ); return BUTTON_X_BORDER; } static int button_active; static void set_button_active( struct gwm_window *window, int new ) { uint32_t n; if( new == button_active ) return; n = gwm_screens[ window->screen ].pixels[ ( button_active = new ) ? COL_BUTTON_ACTIVE : COL_BUTTON_INACTIVE ]; xcb_change_window_attributes( c, window->w, XCB_CW_BACK_PIXEL, &n ); queue_window_update( window, 0, 0, button_size( window, FALSE ), button_size( window, FALSE ), FALSE ); } static void button_button_press( struct gwm_window *window, xcb_button_press_event_t *ev ) { if( !pointer_demux ) { /* Initiate grab. */ pointer_demux = window->w; set_button_active( window, TRUE ); } if( ( window->u.button.frame->u.frame.child->u.managed.protocols & PROTOCOL_DELETE_WINDOW ) && ( ev->detail == 3 || ( ev->state & XCB_BUTTON_MASK_3 ) ) ) /* Button 3 will kill the client, even if it supports WM_DELETE_WINDOW. Change to CURSOR_DESTROY to indicate the distinction. */ xcb_change_active_pointer_grab( c, cursors[ CURSOR_DESTROY ], ev->time, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW ); } static void button_button_release( struct gwm_window *window, xcb_button_release_event_t *ev ) { if( !pointer_demux ) return; if( final_release( ev ) ) { /* Final button released; grab terminates. */ if( button_active ) { if( ev->detail == 3 || !( window->u.button.frame->u.frame.child-> u.managed.protocols & PROTOCOL_DELETE_WINDOW ) ) xcb_kill_client( c, window->u.button.frame->u.frame.child->w ); else { xcb_client_message_event_t msg; struct gwm_window *frame = window->u.button.frame; msg.response_type = XCB_CLIENT_MESSAGE; msg.format = 32; msg.sequence = 0; msg.window = frame->u.frame.child->w; msg.type = atoms[ ATOM_WM_PROTOCOLS ]; msg.data.data32[ 0 ] = atoms[ ATOM_WM_DELETE_WINDOW ]; msg.data.data32[ 1 ] = ev->time; msg.data.data32[ 2 ] = 0; msg.data.data32[ 3 ] = 0; msg.data.data32[ 4 ] = 0; xcb_send_event( c, FALSE, frame->u.frame.child->w, 0, (char *) &msg ); } set_button_active( window, FALSE ); } pointer_demux = XCB_NONE; } else if( ev->detail == 3 && ( window->u.button.frame->u.frame.child-> u.managed.protocols & PROTOCOL_DELETE_WINDOW ) ) /* Button 3 released; we'll no longer kill the client. Remove the temporary CURSOR_DESTROY. */ xcb_change_active_pointer_grab( c, XCB_NONE, ev->time, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW ); } static void button_enter_notify( struct gwm_window *window, xcb_enter_notify_event_t *ev ) { if( !pointer_demux ) return; if( ev->event == window->w ) set_button_active( window, TRUE ); } static void button_leave_notify( struct gwm_window *window, xcb_leave_notify_event_t *ev ) { if( !pointer_demux ) return; if( ev->event == window->w ) set_button_active( window, FALSE ); } const event_handler button_handlers[ NUM_EXTENDED_EVENTS ] = { NULL, /* Error */ NULL, /* Reply */ NULL, /* KeyPress */ NULL, /* KeyRelease */ (event_handler) button_button_press, (event_handler) button_button_release, NULL, /* MotionNotify */ (event_handler) button_enter_notify, (event_handler) button_leave_notify, NULL, /* FocusIn */ NULL, /* FocusOut */ NULL, /* KeymapNotify */ NULL, /* Expose */ NULL, /* GraphicsExpose */ NULL, /* NoExposure */ NULL, /* VisibilityNotify */ NULL, /* CreateNotify */ NULL, /* DestroyNotify */ NULL, /* UnmapNotify */ NULL, /* MapNotify */ NULL, /* MapRequest */ NULL, /* ReparentNotify */ NULL, /* ConfigureNotify */ NULL, /* ConfigureRequest */ NULL, /* GravityNotify */ NULL, /* ResizeRequest */ NULL, /* CirculateNotify */ NULL, /* CirculateRequest */ NULL, /* PropertyNotify */ NULL, /* SelectionClear */ NULL, /* SelectionRequest */ NULL, /* SelectionNotify */ NULL, /* ColormapNotify */ NULL, /* ClientMessage */ NULL, /* MappingNotify */ NULL, /* (synthetic) */ NULL, /* RRScreenChangeNotify */ NULL /* ShapeNotify */ };