Пример #1
0
int client_handle_request(struct clients *cls, int fd)
{
	int n, t;
	int toread;

	struct buffer *buffer = cls->clients[fd].msg;
	char *str;


        if (ioctl(fd, FIONREAD, &toread)) {
		debugprintf("%s: FIONREAD\n", errno);
		return -1;
        }

	if (buffer->used + toread >= MAX_MSG_SIZE) {
		debugprintf("client sent %d bytes, too much data!\n", 
				buffer->used + toread);
		client_remove(cls, fd);
		close(fd);
		return -1;
	}

	buffer_grow(buffer, toread);

	n = recv(fd, buffer->buf + buffer->used, MAX_MSG_SIZE - buffer->used, 0);
	buffer->used += n;

	if (n <= 0) {
		if (n < 0) perror("recv");
		client_remove(cls, fd);
		close(fd);
		return;
	}

	if (buffer->buf[buffer->used - 1] != '\n')
		return 0;

	buffer->buf[buffer->used] = '\0';

	str = malloc(MAX_MSG_SIZE);
	if (!str)
		perror("malloc");

	t = snprintf(str, MAX_MSG_SIZE, "%i: %s", fd, buffer->buf);
	spam_everyone(cls, fd, str, t);
	buffer->used = 0;
	free(str);
}
Пример #2
0
static void
event_unmapnotify(XEvent *e)
{
     XUnmapEvent *ev = &e->xunmap;
     struct client *c;
     struct _systray *s;

     if((c = client_gb_win(ev->window))
        && ev->send_event
        && ev->event == W->root)
     {
          int d;
          unsigned char *ret = NULL;

          if(XGetWindowProperty(EVDPY(e), c->win, W->net_atom[wm_state], 0, 2,
                                False, W->net_atom[wm_state], (Atom*)&d, &d,
                                (long unsigned int*)&d, (long unsigned int*)&d, &ret) == Success)
               if(*ret == NormalState)
                    client_remove(c);
     }
     else if((s = systray_find(ev->window)))
     {
          systray_del(s);
          systray_update();
     }
}
Пример #3
0
static void
client_cb(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask) {
    struct node *client = (struct node *)clientData;

    /* read */
    char buffer[512];
    int len = read(fd, buffer, 512);
    if (len <= 0) {
        fprintf(stderr, "Client closed: %d.", fd);
        aeDeleteFileEvent(eventLoop, fd, mask);
        client_remove(client);
        return;
    }

    /* push to total and split */
    int count = 0;
    client->buffer = sdscatlen(client->buffer, buffer, len);
    sds *lines = sdssplitlen(client->buffer, sdslen(client->buffer), "\n", 1, &count);

    /* translate */
    int i;
    for (i = 0; i < count; i++) {
        translate(lines[i], client);
        sdsfree(lines[i]);
    }
    free(lines);

    sdsclear(client->buffer);
}
Пример #4
0
/* close all clients and then close server */
void
close_server(int fd) {
    struct node *it = client_list->next;
    while (it) {
        struct node *next = it->next;
        client_remove(it);

        it = next;
    }
}
Пример #5
0
static void
event_destroynotify(XEvent *e)
{
     XDestroyWindowEvent *ev = &e->xdestroywindow;
     struct client *c;
     struct _systray *s;

     if((c = client_gb_win(ev->window)))
          client_remove(c);
     else if((s = systray_find(ev->window)))
     {
          ewmh_set_wm_state(s->win, WithdrawnState);
          systray_del(s);
          systray_update();
     }
}
Пример #6
0
static void client_exited_disable_cb(const struct ofono_error *error,
								void *data)
{
	struct ofono_location_reporting *lr = data;

	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
		ofono_error("Disabling location-reporting failed");

		return;
	}

	client_remove(lr);
	lr->enabled = FALSE;

	signal_enabled(lr);
}
Пример #7
0
static void location_reporting_disable_cb(const struct ofono_error *error,
								void *data)
{
	struct ofono_location_reporting *lr = data;
	DBusMessage *reply;

	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
		ofono_error("Disabling location-reporting failed");

		reply = __ofono_error_failed(lr->pending);
		__ofono_dbus_pending_reply(&lr->pending, reply);

		return;
	}

	client_remove(lr);
	lr->enabled = FALSE;

	reply = dbus_message_new_method_return(lr->pending);
	__ofono_dbus_pending_reply(&lr->pending, reply);

	signal_enabled(lr);
}
Пример #8
0
int main_loop( CamConfig *ccfg, Socket *picture_sock, char *picture_mem  ){
  Socket *listen_socket;
  SockSet *readset = NULL, *writeset = NULL;
  list_t *client_sockets;
  lnode_t *node;
  int cfg_listen_port, highest_fd, picture_client_ready;
  int num_sclients, num_clients;
  ClientInfo *clientinfo, *clientinfo2;

  if( (client_sockets = list_create( -1 )) == NULL)
    return -1;

  cfg_listen_port = camconfig_query_def_int( ccfg, SEC_SOCKET, 
					     "listen_port",
					     CAMCONFIG_DEF_LISTEN_PORT );

  if( (readset = sockset_new()) == NULL ||
      (writeset = sockset_new()) == NULL )
  {
    camserv_log( MODNAME, "Error allocating memory for socksets!");
    if( readset ) sockset_dest( readset );
    if( writeset ) sockset_dest( writeset );
    list_destroy( client_sockets );
    return -1;
  }

  if((listen_socket = socket_serve_tcp( NULL, cfg_listen_port, 100 )) == NULL )
  {
      camserv_log( MODNAME, "Error setting up socket on port \"%d\".  Exiting",
	       cfg_listen_port  );
      list_destroy( client_sockets );
      sockset_dest( readset );
      sockset_dest( writeset );
      return -1;
  }

  highest_fd = MAX( socket_query_fd( listen_socket ), 
		    socket_query_fd( picture_sock ));
  clientinfo = clientinfo_new( listen_socket );
  clientinfo2 = clientinfo_new( picture_sock );

  if( !clientinfo || !clientinfo2 ||
      sockset_add_fd( readset, listen_socket, clientinfo ) == -1 ||
      sockset_add_fd( readset, picture_sock, clientinfo2 ) == -1 )
  {
    camserv_log( MODNAME, "Error adding initial sockets to sockset!");
    sockset_dest( readset );
    sockset_dest( writeset );
    if( clientinfo )  clientinfo_dest( clientinfo );
    if( clientinfo2 ) clientinfo_dest( clientinfo2 );
    list_destroy( client_sockets );
    return -1;
  }

  num_clients = 0;
  num_sclients = 0;
  picture_client_ready = 1;

  setup_signals();
  Abort = 0;
  while( !Abort ){
    int sel_res, i, nset_socks;
    void **set_socks;

    /* Only need to execute this if we have a streaming client */
    if( (num_sclients > 0) && picture_client_ready == 1 ){
      send( socket_query_fd( picture_sock ), "0", sizeof( "0" ), 0 );
      picture_client_ready = 0;
    }

    sockset_reset( readset );
    sockset_reset( writeset );

    sel_res = sockset_select( highest_fd + 1, readset, writeset, NULL );
    /* Service the event */
    if( sel_res == -1 ){
      camserv_log( MODNAME, "select() failure: %s", strerror( errno ));
      break;
    } else if( sel_res == 0 ){
      camserv_log( MODNAME, "Unexpected select() fall through!" );
      continue;
    } 

    /* Readable sockets */
    set_socks = sockset_query_socks( readset );
    nset_socks = sockset_query_nsocks( readset );
    for( i=0; i< nset_socks; i++ ){
      ClientInfo *new_cinfo;

      clientinfo = set_socks[ i ];

      if( clientinfo->socket == listen_socket ) {
	/* New client */
	if( (new_cinfo = accept_client( listen_socket )) == NULL )
	  continue;

	if( (node = lnode_create( new_cinfo )) == NULL ){
	  clientinfo_dest( new_cinfo );
	  continue;
	}

	if( sockset_add_fd( readset, new_cinfo->socket, new_cinfo ) == -1 ){
	  camserv_log( MODNAME, "Failed to add socket %d to socket read set!",
		   socket_query_fd( new_cinfo->socket ));
	  clientinfo_dest( new_cinfo );
	  lnode_destroy( node );
	  continue;
	}

	if( socket_query_fd( new_cinfo->socket ) > highest_fd )
	  highest_fd = socket_query_fd( new_cinfo->socket );

	list_append( client_sockets, node );
	num_clients++;
	/* Init resource limit for this client */
	new_cinfo->create_time = time( NULL );
	new_cinfo->bytes       = 0;
	new_cinfo->frames      = 0;
	new_cinfo->max_seconds = camconfig_query_def_int( ccfg, SEC_SOCKET,
							  "max_seconds", 0 );
	new_cinfo->max_bytes   = camconfig_query_def_int( ccfg, SEC_SOCKET,
							  "max_bytes", 0 );
	new_cinfo->max_frames  = camconfig_query_def_int( ccfg, SEC_SOCKET,
							  "max_frames", 0 );

	/* Send fresh request for a picture */
	send( socket_query_fd( picture_sock ), "0", sizeof( "0" ), 0 );
	picture_client_ready = 0;
	/* Put this read socket on hold until the picture comes back */
	sockset_hold( readset, new_cinfo->socket );	

      } else {
	char cmdbuf[ 1024 ];
	int readlen;

	clientinfo = set_socks[ i ];

	/* Regular joe client, set readable */
	if( (readlen = read( socket_query_fd( clientinfo->socket), cmdbuf, 
			     sizeof( cmdbuf ) - 1)) <= 0 )
	{
	  camserv_log( MODNAME, "Closing socket: %s", 
		       socket_query_remote_name( clientinfo->socket ));

	  if (clientinfo->client_type == CLIENT_T_BROWSER ||
	      clientinfo->client_type == CLIENT_T_PROXY) {
	      num_sclients--;
	  }
	  client_remove( client_sockets, clientinfo );
	  sockset_del_fd( readset, clientinfo->socket );
	  sockset_unhold_all( writeset );
	  sockset_del_fd( writeset, clientinfo->socket );
	  clientinfo_dest( clientinfo );
	  num_clients--;
	} else {
	  if( clientinfo->socket == picture_sock ) {
	    if( dispatch_pictaker( cmdbuf, picture_mem ) == -1 )
	      camserv_log( MODNAME, "Pictaker dispatch failure!");
	    sockset_unhold_all( writeset );
	    /* Release the read hold as the picture has now been taken */
	    sockset_unhold_all( readset );
	    picture_client_ready = 1;
	  } else {
	    /* Information from a regular client */
	    cmdbuf[ readlen ] = '\0';
	    if( clientinfo->client_type == CLIENT_T_UNINIT ) {
	      char *preamble;
	      int pre_size;

	      /* Figure out what type of client we have */
	      if( !strncmp( cmdbuf, "GET", 3 )) {
		if( strstr( cmdbuf, "/singleframe" )) {
		  clientinfo->client_type = CLIENT_T_SINGLE;
		} else {
		  clientinfo->client_type = CLIENT_T_BROWSER;
		  num_sclients++;
	        }
	      } else if( !strncmp( cmdbuf, "PROXY", 5 )) {
		clientinfo->client_type = CLIENT_T_PROXY;
		/* Here we are in the same state as being done writing a pic */
		clientinfo->state       = CINFO_STATE_PICTURE;
		num_sclients++;	
		databuf_buf_set( clientinfo->writebuf, NULL, 0 ); 
	      } else 
		clientinfo->client_type = CLIENT_T_BROWSER;

	      if( clientinfo->client_type != CLIENT_T_PROXY ) {
		/* Send the initial preamble.  Only now we can decide which 
		   type of preamble to send (single vs. multi-part) */
		if( clientinfo->client_type == CLIENT_T_SINGLE )
		  preamble = get_single_preamble_text( &pre_size );
		else
		  preamble = get_multi_preamble_text( &pre_size );
		databuf_buf_set( clientinfo->writebuf, preamble, pre_size );
	      }

	      if( sockset_add_fd( writeset, clientinfo->socket, 
				  clientinfo ) == -1 )
	      {
  		  camserv_log( MODNAME, "Failed to add socket %d to write set!",
			   socket_query_fd( clientinfo->socket ));
	      }
	  } 
	} 
      } 
    } 
  } 

    if( set_socks != NULL ) free( set_socks );

    /* Writable sockets */
    set_socks = sockset_query_socks( writeset );
    nset_socks = sockset_query_nsocks( writeset );
    for( i=0; i< nset_socks; i++ ){
      ClientInfo *cinfo;

      cinfo = set_socks[ i ];
      if( cinfo->client_type == CLIENT_T_BROWSER ||
	  cinfo->client_type == CLIENT_T_SINGLE ) 
      {
	int result;

	if( (result = write_regular_client( cinfo, writeset )) != 0 ){
	  /* result: 1=close requested, -1=error detected */
	  if( result == -1 )
	    camserv_log( MODNAME, "Databuf write error on socket: %s\n",
			 socket_query_remote_name( cinfo->socket ));
	  
	  if (cinfo->client_type == CLIENT_T_BROWSER) {
	      num_sclients--;
	  }

	  client_remove( client_sockets, cinfo );
	  sockset_del_fd( readset, cinfo->socket );
	  sockset_del_fd( writeset, cinfo->socket );
	  clientinfo_dest( cinfo );
	  num_clients--;
	}
      } else {
	if( write_proxy_client( cinfo, writeset ) == -1 ){
	  camserv_log( MODNAME, "Databuf write error on socket: %d",
		   socket_query_fd( cinfo->socket ));

	  /* Should be proxy, but better check */
	  if (cinfo->client_type == CLIENT_T_PROXY) {
	      num_sclients--;
	  }
	  client_remove( client_sockets, cinfo );
	  sockset_del_fd( readset, cinfo->socket );
	  sockset_del_fd( writeset, cinfo->socket );
	  clientinfo_dest( cinfo );
	  num_clients--;
	}
      }
    }
    if( set_socks != NULL ) free( set_socks );
  }

  camserv_log( MODNAME, "Aborting.");
  sockset_dest( readset );
  sockset_dest( writeset );

  for( node = list_first( client_sockets) ; node; 
       node=list_next( client_sockets, node ))
  {
    clientinfo_dest( node->data );
  }

  /* Tell the picture taker to get out!  Get out! */
  camserv_log( MODNAME, "Closing picture taker");
  send( socket_query_fd( picture_sock ), "9", sizeof( "9" ), 0 );
  sleep( 3 );
  camserv_log( MODNAME, "done\n");

  list_destroy_nodes( client_sockets );
  list_destroy( client_sockets );
  socket_dest( listen_socket );
  return 0;
}
Пример #9
0
void handle_event(XEvent *ev) {
	client *c = owner(ev->xany.window);
	#ifdef DEBUG_EVENTS
	if(ev->type != Expose && ev->type != MotionNotify && !(ev->type == ConfigureNotify && ev->xconfigure.window != root)) /* this makes the output slightly more manageable */
		printf(NAME ": handle_event(): got %s\n\twindow: 0x%X (%s)\n", event_name(ev), (unsigned int) ev->xany.window, c ? c->name : ((ev->xany.window == root) ? "root" : "unknown"));
	#endif
	if((evh && evh(ev)) || button_handle_event(ev) || ewmh_handle_event(ev) || screens_handle_event(ev)) {
		#ifdef DEBUG_EVENTS
		if(ev->type != Expose && ev->type != MotionNotify && (ev->type != ConfigureNotify && ev->xconfigure.window != root))
			printf(NAME ": handle_event(): external event handler claimed last event\n");
		#endif
		return;
	}
	if(c) {
		if(!has_child(c->parent, c->window) && ev->type != DestroyNotify && ev->type != UnmapNotify)
			return;
		switch(ev->type) {
			case UnmapNotify:
				if(c->window == ev->xunmap.window) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handle_event(): handling UnmapNotify event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name);
					#endif
					if(has_child(c->parent, c->window)) {
						client_deparent(c);
						set_wm_state(c->window, WithdrawnState);
					}
					client_remove(c);
					ewmh_update_clist();
				}
				return;
			case PropertyNotify:
				if(ev->xproperty.atom == XA_WM_NAME) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handle_event(): handling PropertyNotify event\n\twindow: 0x%X (%s)\n\tproperty: XA_WM_NAME\n", (unsigned int) c->window, c->name);
					#endif
					if(c->name != no_title)
						XFree(c->name);
					#ifdef USE_XFT
					if(xftfont)
						XftDrawDestroy(c->title_draw);
					#endif
					XFreePixmap(dpy, c->title_pixmap);
					XFetchName(dpy, c->window, &c->name);
					client_update_name(c);
					XClearWindow(dpy, c->title);
					if(evh == wlist_handle_event) {
						XClearWindow(dpy, c->wlist_item);
						wlist_item_draw(c);
					}
				}
				if(ev->xproperty.atom == XA_WM_NORMAL_HINTS) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handle_event(): handling PropertyNotify event\n\twindow: 0x%X (%s)\n\tproperty: XA_WM_NORMAL_HINTS\n", (unsigned int) c->window, c->name);
					#endif
					get_normal_hints(c);
				}
				return;
			case ClientMessage:
				if(ev->xclient.message_type == xa_wm_change_state && ev->xclient.data.l[0] == IconicState) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handling ClientMessage event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name);
					#endif
					client_iconify(c);
					return;
				}
				break; /* we might later need this event */
			case EnterNotify:
				if(c != current && !(c->flags & CLICK_FOCUS) && !click_focus && ev->xcrossing.mode != NotifyGrab && ev->xcrossing.mode != NotifyUngrab && ev->xcrossing.detail != NotifyInferior && (ev->xcrossing.window == c->parent || ev->xcrossing.window == c->wlist_item) && ev->xcrossing.send_event == False) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handle_event(): handling EnterNotify event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name);
					#endif
					client_focus(c, true);
				}
				return;
			case Expose:
				if(ev->xexpose.count == 0 && evh == wlist_handle_event && c && ev->xexpose.window == c->wlist_item)
					wlist_item_draw(c);
				return;
			case ButtonPress:
				#ifdef DEBUG_EVENTS
				printf(NAME ": handle_event(): handling ButtonPress event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name);
				#endif
				if(c != current)
					client_focus(c, true);
				XAllowEvents(dpy, ReplayPointer, CurrentTime);
				if(ev->xbutton.window != c->window) {
					if(lastclick + doubleclick_time > ev->xbutton.time && lastbutton == ev->xbutton.button && lastclick_client == c) {
						client_action(c, buttonaction(ev->xbutton.button, true), ev);
						lastclick = 0;
						lastclick_client = NULL;
						lastbutton = None;
						return;
					}
					lastclick = ev->xbutton.time;
					lastclick_client = c;
					lastbutton = ev->xbutton.button;
					client_action(c, buttonaction(ev->xbutton.button, false), ev);
				} else if(click_raise)
					client_raise(c);
				return;
			case FocusIn: /* we ignore pointer events, these happen if the input focus is on the root window */
				if(allow_focus_stealing && c != current && ev->xfocus.mode != NotifyGrab && ev->xfocus.mode != NotifyUngrab && ev->xfocus.detail != NotifyPointer) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handle_event(): handling FocusIn event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name);
					#endif
					client_focus(c, false);
				}
				return;
			case FocusOut:
				if(c == current && ev->xfocus.mode != NotifyGrab && ev->xfocus.mode != NotifyUngrab && ev->xfocus.detail != NotifyInferior) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handle_event(): handling FocusOut event\n\twindow: 0x%X (%s)\n", (unsigned int) c->window, c->name);
					#endif
					if(allow_focus_stealing && ev->xfocus.detail != NotifyAncestor) {
						#ifdef DEBUG_EVENTS
						printf("\tfocus lost\n");
						#endif
						client_focus(NULL, false); /* we do this so windows that aren't managed can take focus */
					} else {
						#ifdef DEBUG_EVENTS
						printf("\tre-focussing this window\n");
						#endif
						take_focus(c);
					}
				}
				return;
			#ifdef USE_SHAPE
			default:
				if(ev->type == shape_event) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handle_event(): handling ShapeNotify event\n\twindow 0x%X (%s)\n", (unsigned int) c->window, c->name);
					#endif
					set_shape(c);
					return;
				}
			#endif
		}
	}
	switch(ev->type) {
		case MapRequest:
			c = owner(ev->xmaprequest.window);
			#ifdef DEBUG_EVENTS
			printf(NAME ": handle_event(): handling MapRequest event\n\twindow: 0x%X (%s)\n", (unsigned int) ev->xmaprequest.window, c ? c->name : "unknown");
			#endif
			if(c) {
				if(c->flags & ICONIC && has_child(c->parent, c->window)) {
					client_restore(c);
					if(focus_new)
						client_focus(c, true);
				}
			} else if(has_child(root, ev->xmaprequest.window))
				client_add(ev->xmaprequest.window, false);
			return;
		case DestroyNotify:
			c = owner(ev->xdestroywindow.window);
			if(c)
				if(c->window == ev->xdestroywindow.window) {
					#ifdef DEBUG_EVENTS
					printf(NAME ": handle_event(): handling DestroyNotify event\n\twindow 0x%X (%s)\n", (unsigned int) c->window, c->name);
					#endif
					client_remove(c);
				}
			return;
		case ConfigureRequest:
			c = owner(ev->xconfigurerequest.window);
			#ifdef DEBUG_EVENTS
			printf(NAME ": handle_event(): handling ConfigureRequest event\n\twindow 0x%X (%s)\n", (unsigned int) ev->xconfigurerequest.window, c ? c->name : "unknown");
			#endif
			if(correct_center)
				screens_correct_center(&ev->xconfigurerequest.x, &ev->xconfigurerequest.y, &ev->xconfigurerequest.width, &ev->xconfigurerequest.height);
			if(c) {
				if(!has_child(c->parent, c->window))
					return;
				if(ev->xconfigurerequest.value_mask & CWX)
					c->x = ev->xconfigurerequest.x - gxo(c, false);
				if(ev->xconfigurerequest.value_mask & CWY)
					c->y = ev->xconfigurerequest.y - gyo(c, false);
				if(ev->xconfigurerequest.value_mask & CWWidth)
					c->width = ev->xconfigurerequest.width;
				if(ev->xconfigurerequest.value_mask & CWHeight)
					c->height = ev->xconfigurerequest.height;
				client_update(c);
				#ifdef DEBUG
				printf(NAME ": handle_event(): reconfigured client 0x%X (%s) to %ix%i+%i+%i\n", (unsigned int) c->window, c->name, c->width, c->height, c->x, c->y);
				#endif
			} else if(has_child(root, ev->xconfigurerequest.window)) {
				XWindowChanges wc;
				wc.sibling = ev->xconfigurerequest.above;
				wc.stack_mode = ev->xconfigurerequest.detail;
				wc.x = ev->xconfigurerequest.x;
				wc.y = ev->xconfigurerequest.y;
				wc.width = ev->xconfigurerequest.width;
				wc.height = ev->xconfigurerequest.height;
				XConfigureWindow(dpy, ev->xconfigurerequest.window, ev->xconfigurerequest.value_mask, &wc);
			}
			return;
		case MapNotify:
			if(correct_center_unmanaged && ev->xany.window == root && !owner(ev->xmap.window)) {
				#ifdef DEBUG_EVENTS
				printf(NAME ": handle_event(): handling MapNotify event\n\twindow 0x%X (unknown)\n", (unsigned int) ev->xmap.window);
				#endif
				window_correct_center(ev->xmap.window);
			}
			return;
		case MappingNotify:
			if(ev->xmapping.request != MappingPointer) {
				#ifdef DEBUG_EVENTS
				printf(NAME ": handle_event(): handling MappingNotify event\n");
				#endif
				keys_ungrab();
				XRefreshKeyboardMapping(&ev->xmapping);
				keys_update();
			}
			return;
		case KeyPress:
			#ifdef DEBUG_EVENTS
			printf(NAME ": handle_event(): handling KeyPress event\n");
			#endif
			client_action(current, keyaction(ev), ev);
			return;
		case ButtonPress:
			if(ev->xbutton.window != root)
				return;
			#ifdef DEBUG_EVENTS
			printf(NAME ": handle_event(): handling ButtonPress event\n");
			#endif
			if(lastclick + doubleclick_time > ev->xbutton.time && lastbutton == ev->xbutton.button && lastclick_client == NULL) {
				client_action(current, root_buttonaction(ev->xbutton.button, true), ev);
				lastclick = 0;
				lastclick_client = NULL;
				lastbutton = None;
				return;
			}
			lastclick = ev->xbutton.time;
			lastclick_client = NULL;
			lastbutton = ev->xbutton.button;
			client_action(current, root_buttonaction(ev->xbutton.button, false), ev);
			return;
		case ClientMessage:
			if(ev->xclient.message_type == xa_internal_message) {
				if(((Atom) ev->xclient.data.l[0]) == xa_quit) {
					#ifdef DEBUG
					printf(NAME ": handle_event(): quit message received\n");
					#endif
					exit(0);
				}
				if(((Atom) ev->xclient.data.l[0]) == xa_reinit) {
					#ifdef DEBUG
					printf(NAME ": handle_event(): reinitialize message received\n");
					#endif
					cfg_reinitialize();
				}
			}
	}
}