/*
* Copyright (c) 2003 FlashCode <flashcode@flashtux.org>
* Xahlexx <xahlexx@tuxfamily.org>
* Bounga <bounga@altern.org>
* See README for Licence detail.
*
* 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
*/
/* events.c: events clients management */
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include "weewm.h"
#include "events.h"
#include "client.h"
#include "screen.h"
#include "config.h"
#include "memorize.h"
int switch_to_desktop;
/*
* launch_command: creates a new process and launch a command with (optional) parameters
*/
void launch_command(char *cmd, char *const argv[], int screen)
{
pid_t pid;
char *buf, *display;
if ( (pid = fork()) == 0 )
{
buf = (char *)malloc(35*sizeof(char));
display = (char *)malloc(35*sizeof(char));
sprintf(buf, "%s.%i", display_name ? display_name : DEFAULT_DISPLAY, screen);
#ifdef DEBUG
fprintf(stderr, "\nStarting command '%s', on display %i - %s\n",
cmd, screen, buf);
#endif
display = strcat(strcpy(display, "DISPLAY="), buf);
putenv(display);
execvp(cmd, argv);
}
}
/*
* action_key: do the right action correspondig to the key pressed
*/
void action_key(t_keymap *km, KeySym key, KeySym mask, XKeyEvent *event)
{
t_keymap *ptr_keymap;
t_client *ptr_client;
#ifdef DEBUG
fprintf(stderr, "action_key called with key = %d, mask = %d\n", (int)key, (int)mask);
#endif
switch_to_desktop = -1;
for (ptr_keymap = km; ptr_keymap != NULL; ptr_keymap = ptr_keymap->next)
{
if ( (ptr_keymap->keysym == (int)key) && (ptr_keymap->modifier_mask == (int)mask) )
{
if (ptr_keymap->command_file == NULL)
{
if (ptr_keymap->handler == NULL)
return;
else
{
switch_to_desktop = -1;
if (ptr_keymap->key_switch_desktop >= 0)
switch_to_desktop = ptr_keymap->key_switch_desktop;
ptr_keymap->handler(event);
return;
}
}
else
{
if (ptr_keymap->only_one)
{
for (ptr_client = head_client; ptr_client; ptr_client = ptr_client->next)
{
if (strcmp(ptr_client->application_name, ptr_keymap->application_name) == 0)
{
switch_desktop(ptr_client->vdesk[ScreenOfRootWindow(event->root)],
ScreenOfRootWindow(event->root));
return;
}
}
return;
}
if (ptr_keymap->initial_desktop > 0)
{
if (ptr_keymap->initial_desktop <= config_num_desktops)
switch_desktop(ptr_keymap->initial_desktop - 1,
ScreenOfRootWindow(event->root));
else
fprintf(stderr, "WeeWM: can't switch to desktop %d for command %s\n",
ptr_keymap->initial_desktop, ptr_keymap->application_name);
}
launch_command(ptr_keymap->command_file,
ptr_keymap->command_args, ScreenOfRootWindow(event->root));
}
}
}
}
/*
* handle_key_event: handler for key event
*/
void handle_key_event(XKeyEvent *event)
{
t_client *client;
KeySym key, state;
client = find_client(event->window);
key = XKeycodeToKeysym(display, event->keycode, 0);
state = event->state;
if (!client)
{
client = current_client;
}
action_key(keymap, key, state, event);
}
/*
* handle_button_event: handler for button event
*/
void handle_button_event(XButtonEvent *event)
{
t_client *client;
client = find_client(event->window);
if (client && event->window != RootWindow(display, client->screen))
{
switch (event->button)
{
case Button1:
XRaiseWindow(display, client->parent);
client_move(client, 0);
break;
case Button3:
XRaiseWindow(display, client->parent);
client_resize(client, 0);
break;
case Button2:
XLowerWindow(display, client->parent);
break;
}
}
}
/*
* handle_convfigure_request: handler for configure request event
*/
void handle_configure_request(XConfigureRequestEvent *event)
{
t_client *client;
XWindowChanges wc;
client = find_client(event->window);
wc.sibling = event->above;
wc.stack_mode = event->detail;
if (client)
{
change_gravity(client, -1);
if (event->value_mask & CWX) client->x = event->x;
if (event->value_mask & CWY) client->y = event->y;
if (event->value_mask & CWWidth) client->width = event->width;
if (event->value_mask & CWHeight) client->height = event->height;
change_gravity(client, 1);
wc.x = client->x - client->border;
wc.y = client->y - client->border;
wc.width = client->width + (client->border*2);
wc.height = client->height + (client->border*2);
wc.border_width = 0;
XConfigureWindow(display, client->parent, event->value_mask, &wc);
send_config(client);
if (client->dock_position != NO_DOCK)
recalculate_dock_positions();
}
wc.x = client ? client->border : event->x;
wc.y = client ? client->border : event->y;
wc.width = event->width;
wc.height = event->height;
XConfigureWindow(display, event->window, event->value_mask, &wc);
}
/*
* handle_map_request: handler for map request event
*/
void handle_map_request(XMapRequestEvent *event)
{
t_client *client;
client = find_client(event->window);
if (client)
{
if (client->vdesk[client->screen] != vdesk[client->screen])
switch_desktop(client->vdesk[client->screen], client->screen);
unhide(client, 1);
}
else
create_new_client(event->window, ScreenOfWindow(event->window));
}
/*
* handle_unmap_event: handler for unmap event
*/
void handle_unmap_event(XUnmapEvent *event)
{
t_client *client;
client = find_client(event->window);
if (client)
{
if (client->ignore_unmap)
client->ignore_unmap--;
else
remove_client(client, 0);
}
}
/*
* handle_property_change: handler for property change event
*/
void handle_property_change(XPropertyEvent *event)
{
t_client *client;
long dummy;
client = find_client(event->window);
if (client)
{
if (event->atom == XA_WM_NORMAL_HINTS)
XGetWMNormalHints(display, client->window, client->size, &dummy);
}
}
/*
* handle_enter_event: handler for enter event
*/
void handle_enter_event(XCrossingEvent *event)
{
int screen, wdesk, i;
t_client *client;
screen = ScreenOfRootWindow(event->root);
client = find_client(event->window);
if (client)
{
wdesk = client->vdesk[screen];
if ( (wdesk != vdesk[screen]) && (wdesk != -1) )
return;
if (current_client && (client != current_client))
{
XSetWindowBackground(display, current_client->parent,
color_border0.pixel);
XClearWindow(display, current_client->parent);
}
XSetWindowBackground(display, client->parent,
(wdesk == FIXED_WINDOW) ? color_sticky.pixel : color_border1.pixel);
XClearWindow(display, client->parent);
/*for (i = 0; i < 15; i++)
XDrawLine(display, client->parent, invert_gc[client->screen], 0, i, i*4, i);*/
current_client = client;
XSetInputFocus(display, client->window, RevertToPointerRoot, CurrentTime);
for (i = 0; i < NUM_IGNORE_MODIFIERS; i++)
{
XGrabButton(display, AnyButton, ignore_modifiers[i] | mouse_mask,
client->parent, False, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeSync, None, None);
}
}
}
/*
* action_next_win: focuses the next window
*/
void action_next_win(XKeyEvent *event)
{
t_client *client, *ptr_client, *client_found;
int screen;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
screen = ScreenOfRootWindow(event->root);
if (!client)
client_found = get_first_client_desktop(vdesk[screen], screen);
else
{
ptr_client = (client->next) ? client->next : head_client;
client_found = NULL;
while (ptr_client != client)
{
if ( ( (ptr_client->vdesk[ptr_client->screen] == FIXED_WINDOW) ||
(ptr_client->vdesk[ptr_client->screen] == client->vdesk[client->screen]) )
&& (ptr_client->dock_position == NO_DOCK)
&& (ptr_client->vdesk[ptr_client->screen] != -1) )
client_found = ptr_client;
ptr_client = (ptr_client->next) ? ptr_client->next : head_client;
}
}
if (client_found)
{
unhide(client_found, 1);
XWarpPointer(display, None, client_found->window, 0, 0, 0, 0,
client_found->width-1, client_found->height-1);
}
}
/*
* action_previous_win: focuses the previous window
*/
void action_previous_win(XKeyEvent *event)
{
t_client *client, *ptr_client;
int screen;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
screen = ScreenOfRootWindow(event->root);
if (!client)
ptr_client = get_first_client_desktop(vdesk[screen], screen);
else
{
ptr_client = (client->next) ? client->next : head_client;
while (ptr_client != client)
{
if ( ( (ptr_client->vdesk[ptr_client->screen] == FIXED_WINDOW) ||
(ptr_client->vdesk[ptr_client->screen] == client->vdesk[client->screen]) )
&& (ptr_client->dock_position == NO_DOCK)
&& (ptr_client->vdesk[ptr_client->screen] != -1) )
break;
ptr_client = (ptr_client->next) ? ptr_client->next : head_client;
}
}
if (ptr_client)
{
unhide(ptr_client, 1);
XWarpPointer(display, None, ptr_client->window, 0, 0, 0, 0,
ptr_client->width-1, ptr_client->height-1);
}
}
/*
* action_pos_top_left: moves the window to the top left corner
*/
void action_pos_top_left(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '7');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_pos_top: moves the window to the top edge of the screen
*/
void action_pos_top(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '8');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_pos_top_right: moves the window to the top right corner
*/
void action_pos_top_right(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '9');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_pos_left: moves the window to the left edge of the screen
*/
void action_pos_left(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '4');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_pos_center: centers the window on the screen
*/
void action_pos_center(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '5');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_pos_right: moves the window to the right edge of the screen
*/
void action_pos_right(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '6');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_pos_bottom_left: moves the window to the bottom left corner of the screen
*/
void action_pos_bottom_left(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '1');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_pos_bottom: moves the window to the bottom edge of the screen
*/
void action_pos_bottom(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '2');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_pos_bottom_right: moves the window to the bottom right corner of the screen
*/
void action_pos_bottom_right(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
set_smart_position(client, '3');
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_move_left: moves the window to the left (of <offset> pixels)
*/
void action_move_left(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
client->x -= config_move_offset;
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_move_right: moves the window to the right (of <offset> pixels)
*/
void action_move_right(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
client->x += config_move_offset;
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_move_up: moves the window up (of <offset> pixels)
*/
void action_move_up(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
client->y -= config_move_offset;
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_move_down: moves the window down (of <offset> pixels)
*/
void action_move_down(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
client->y += config_move_offset;
client_move(client, 1);
XWarpPointer(display, None, client->window, 0, 0, 0, 0,
client->width-1, client->height-1);
}
/*
* action_previous_desktop: displays previous desktop
*/
void action_previous_desktop(XKeyEvent *event)
{
int screen;
t_client *client;
screen = ScreenOfRootWindow(event->root);
if (vdesk[screen] > 0)
{
client = find_client(event->window);
if (client == NULL)
client = current_client;
switch_desktop(vdesk[screen]-1, screen);
}
}
/*
* action_next_desktop: displays next desktop
*/
void action_next_desktop(XKeyEvent *event)
{
int screen;
t_client *client;
screen = ScreenOfRootWindow(event->root);
if (vdesk[screen] < config_num_desktops)
{
client = find_client(event->window);
if (client == NULL)
client = current_client;
switch_desktop(vdesk[screen]+1, screen);
}
}
/*
* action_go_to_desktop: go to desktop N
*/
void action_go_to_desktop(XKeyEvent *event)
{
int screen;
t_client *client;
screen = ScreenOfRootWindow(event->root);
client = find_client(event->window);
if (client == NULL)
client = current_client;
if ( (switch_to_desktop >= 0) && (switch_to_desktop < config_num_desktops) )
switch_desktop(switch_to_desktop, screen);
}
/*
* action_send_previous_desktop: sends the window to the previous desktop
*/
void action_send_previous_desktop(XKeyEvent *event)
{
int screen;
t_client *client;
if (head_client == NULL)
return;
screen = ScreenOfRootWindow(event->root);
if (vdesk[screen] > 0)
{
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
if (client->vdesk[screen] != FIXED_WINDOW)
client->vdesk[screen]--;
switch_desktop(vdesk[screen]-1, screen);
}
}
/*
* action_send_next_desktop: sends the window to the next desktop
*/
void action_send_next_desktop(XKeyEvent *event)
{
int screen;
t_client *client;
if (head_client == NULL)
return;
screen = ScreenOfRootWindow(event->root);
if (vdesk[screen] < config_num_desktops)
{
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
if (client->vdesk[screen] != FIXED_WINDOW)
client->vdesk[screen]++;
switch_desktop(vdesk[screen]+1, screen);
}
}
/*
* action_max_horizontal: maximizes window horizontally
*/
void action_max_horizontal(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
if (client->oldw)
{
client->x = client->oldx;
client->width = client->oldw;
client->oldw = 0;
}
else
{
client->oldx = client->x;
client->oldw = client->width;
recalculate_sweep(client, get_x_min(client->screen), client->y,
get_x_max(client->screen), client->y + client->height);
}
client_resize(client, 1);
}
/*
* action_max_vertical: maximizes window vertically
*/
void action_max_vertical(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
if (client->oldh)
{
client->y = client->oldy;
client->height = client->oldh;
client->oldh = 0;
}
else
{
client->oldy = client->y;
client->oldh = client->height;
recalculate_sweep(client, client->x, get_y_min(client->screen),
client->x + client->width, get_y_max(client->screen));
}
client_resize(client, 1);
}
/*
* action_maximize: maximizes window
*/
void action_maximize(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
if (client->dock_position != NO_DOCK)
return;
if (client->oldmh && client->oldmw)
{
client->y = client->oldmy;
client->height = client->oldmh;
client->oldmh = 0;
client->x = client->oldmx;
client->width = client->oldmw;
client->oldmw = 0;
}
else
{
client->oldmy = client->y;
client->oldmh = client->height;
client->oldmx = client->x;
client->oldmw = client->width;
recalculate_sweep(client,
get_x_min(client->screen) + client->border,
get_y_min(client->screen) + client->border,
get_x_max(client->screen) - client->border,
get_y_max(client->screen) - client->border);
}
client_resize(client, 1);
}
/*
* action_fix_window: fix/unfix window
*/
void action_fix_window(XKeyEvent *event)
{
t_client *client;
int screen;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
screen = ScreenOfRootWindow(event->root);
if (client->vdesk[client->screen] == FIXED_WINDOW)
client->vdesk[client->screen] = vdesk[screen];
else
client->vdesk[client->screen] = FIXED_WINDOW;
XSetWindowBackground(display, client->parent,
(client->vdesk[client->screen] == FIXED_WINDOW) ? color_sticky.pixel : color_border1.pixel);
XClearWindow(display, client->parent);
}
/*
* action_memo_position: memorize position & size of window
*/
void action_memo_position(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
memorize_client_position(client);
}
/*
* action_memo_desktop: memorize desktop of window
*/
void action_memo_desktop(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
memorize_client_desktop(client);
}
/*
* action_forget_position: forget position & size of window
*/
void action_forget_position(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
forget_client_position(client);
}
/*
* action_forget_desktop: forget desktop of window
*/
void action_forget_desktop(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
forget_client_desktop(client);
}
/*
* action_win_kill: kills the window
*/
void action_win_kill(XKeyEvent *event)
{
t_client *client;
if (head_client == NULL)
return;
client = find_client(event->window);
if (client == NULL)
client = current_client;
if (client == NULL)
return;
send_wm_delete(client);
}
/*
* action_reconfigure: reloads WeeWM configuration (config & bindings)
*/
void action_reconfigure(XKeyEvent *event)
{
/* NOT DEVELOPED ! */
(void)event;
}
/*
* action_quit: quit WeeWM (oh no!)
*/
void action_quit(XKeyEvent *event)
{
(void)event;
while (head_client)
{
remove_client(head_client, 1);
}
free_keymap();
wee_shutdown();
}
syntax highlighted by Code2HTML, v. 0.9.1