2012-10-22 06:52:53 +04:00
/*
* Compositor
*
* This is the window compositor application .
* It serves shared memory regions to clients
* and renders them to the screen .
*/
# include <stdio.h>
# include <stdint.h>
# include <syscall.h>
# include <string.h>
# include <stdlib.h>
2014-03-17 02:13:27 +04:00
# include <fcntl.h>
2012-10-22 06:52:53 +04:00
# include <unistd.h>
# include <time.h>
2012-12-08 12:25:16 +04:00
# include <math.h>
2012-10-22 06:52:53 +04:00
# include <assert.h>
# include <sys/stat.h>
# include <cairo.h>
2013-05-06 02:00:24 +04:00
# include <signal.h>
2012-10-22 06:52:53 +04:00
# include "lib/list.h"
# include "lib/graphics.h"
# include "lib/window.h"
# include "lib/pthread.h"
# include "lib/kbd.h"
# include "../kernel/include/mouse.h"
2012-11-22 11:29:27 +04:00
# define SPRITE_COUNT 2
2012-10-22 06:52:53 +04:00
# define WIN_D 32
# define WIN_B (WIN_D / 8)
# define MOUSE_SCALE 3
# define MOUSE_OFFSET_X 26
# define MOUSE_OFFSET_Y 26
2012-11-22 11:29:27 +04:00
# define SPRITE_MOUSE 1
2012-11-24 12:18:14 +04:00
# define WINDOW_LAYERS 0x10000
2012-11-22 11:29:27 +04:00
# define FONT_PATH " / usr / share / fonts / "
# define FONT(a,b) {WINS_SERVER_IDENTIFIER ".fonts." a, FONT_PATH b}
2013-06-13 10:37:07 +04:00
# define BUFFER_SAFE_ZONE 7680
2012-10-22 06:52:53 +04:00
2013-06-19 10:43:50 +04:00
# define MODE_NORMAL 0x001
# define MODE_SCALE 0x002
# define MODE_WINDOW_PICKER 0x003
2012-12-08 12:25:16 +04:00
2013-07-23 09:42:24 +04:00
# define SCREENSHOT_WHOLE_SCREEN 1
# define SCREENSHOT_THIS_WINDOW 2
2013-05-30 08:31:59 +04:00
unsigned int tick_count = 0 ;
int animation_lengths [ ] = {
0 ,
256 ,
256 ,
256 ,
10000 ,
} ;
2013-05-22 08:11:30 +04:00
2012-11-22 11:29:27 +04:00
struct font_def {
char * identifier ;
char * path ;
} ;
2012-10-22 06:52:53 +04:00
2012-11-22 11:29:27 +04:00
/* Non-public bits from window.h */
extern FILE * fdopen ( int fd , const char * mode ) ;
2012-10-22 06:52:53 +04:00
2013-05-30 08:31:59 +04:00
void actually_destroy_window ( server_window_t * win ) ;
server_window_t * focused = NULL ;
server_window_t * windows [ WINDOW_LAYERS ] ;
2012-11-22 11:29:27 +04:00
sprite_t * sprites [ SPRITE_COUNT ] ;
gfx_context_t * ctx ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
gfx_context_t * select_ctx ;
2012-11-22 11:29:27 +04:00
list_t * process_list ;
2013-05-30 08:31:59 +04:00
list_t * windows_to_clean ;
2012-11-22 11:29:27 +04:00
int32_t mouse_x , mouse_y ;
int32_t click_x , click_y ;
uint32_t mouse_discard = 0 ;
volatile int am_drawing = 0 ;
2013-05-30 08:31:59 +04:00
server_window_t * moving_window = NULL ;
2012-11-22 11:29:27 +04:00
int32_t moving_window_l = 0 ;
int32_t moving_window_t = 0 ;
2013-05-30 08:31:59 +04:00
server_window_t * resizing_window = NULL ;
2012-11-22 11:29:27 +04:00
int32_t resizing_window_w = 0 ;
int32_t resizing_window_h = 0 ;
cairo_t * cr ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
cairo_t * cs ;
2012-11-22 11:29:27 +04:00
cairo_surface_t * surface ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
cairo_surface_t * selface ;
2012-11-22 11:29:27 +04:00
wid_t volatile _next_wid = 1 ;
wins_server_global_t volatile * _request_page ;
int error ;
2012-12-08 12:25:16 +04:00
int focus_next_scale = 0 ;
2013-06-19 10:43:50 +04:00
int window_picker_index = 0 ;
2013-07-23 09:42:24 +04:00
int take_screenshot_now = 0 ;
2012-12-08 12:25:16 +04:00
int management_mode = MODE_NORMAL ;
2012-10-22 06:52:53 +04:00
2012-11-22 11:29:27 +04:00
struct font_def fonts [ ] = {
FONT ( " sans-serif " , " DejaVuSans.ttf " ) ,
FONT ( " sans-serif.bold " , " DejaVuSans-Bold.ttf " ) ,
FONT ( " sans-serif.italic " , " DejaVuSans-Oblique.ttf " ) ,
FONT ( " sans-serif.bolditalic " , " DejaVuSans-BoldOblique.ttf " ) ,
FONT ( " monospace " , " DejaVuSansMono.ttf " ) ,
FONT ( " monospace.bold " , " DejaVuSansMono-Bold.ttf " ) ,
FONT ( " monospace.italic " , " DejaVuSansMono-Oblique.ttf " ) ,
FONT ( " monospace.bolditalic " , " DejaVuSansMono-BoldOblique.ttf " ) ,
{ NULL , NULL }
} ;
static void spin_lock ( int volatile * lock ) {
while ( __sync_lock_test_and_set ( lock , 0x01 ) ) {
syscall_yield ( ) ;
2012-10-22 06:52:53 +04:00
}
2012-11-22 11:29:27 +04:00
}
2012-10-22 06:52:53 +04:00
2012-11-22 11:29:27 +04:00
static void spin_unlock ( int volatile * lock ) {
__sync_lock_release ( lock ) ;
}
void redraw_cursor ( ) {
draw_sprite ( ctx , sprites [ SPRITE_MOUSE ] , mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X , mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y ) ;
2012-10-22 06:52:53 +04:00
}
2013-05-30 08:31:59 +04:00
static server_window_t * get_window_with_process ( process_windows_t * pw , wid_t wid ) {
2012-10-22 06:52:53 +04:00
foreach ( m , pw - > windows ) {
2013-05-30 08:31:59 +04:00
server_window_t * w = ( server_window_t * ) m - > value ;
2012-10-22 06:52:53 +04:00
if ( w - > wid = = wid ) {
return w ;
}
}
return NULL ;
}
void init_process_list ( ) {
process_list = list_create ( ) ;
2013-05-30 08:31:59 +04:00
memset ( windows , 0x00000000 , sizeof ( server_window_t * ) * WINDOW_LAYERS ) ;
2012-10-22 06:52:53 +04:00
}
2012-11-22 11:29:27 +04:00
void send_window_event ( process_windows_t * pw , uint8_t event , w_window_t * packet ) {
/* Construct the header */
wins_packet_t header ;
header . magic = WINS_MAGIC ;
header . command_type = event ;
header . packet_size = sizeof ( w_window_t ) ;
/* Send them */
2013-06-13 10:37:07 +04:00
struct stat buf ;
fstat ( pw - > event_pipe , & buf ) ;
if ( buf . st_size < BUFFER_SAFE_ZONE ) {
write ( pw - > event_pipe , & header , sizeof ( wins_packet_t ) ) ;
write ( pw - > event_pipe , packet , sizeof ( w_window_t ) ) ;
kill ( pw - > pid , SIGWINEVENT ) ; // SIGWINEVENT
syscall_yield ( ) ;
} else {
fprintf ( stderr , " [compositor] This client (pid=%d) is lagging, we are dropping WINDOW EVENTS! \n " , pw - > pid ) ;
kill ( pw - > pid , SIGWINEVENT ) ; // SIGWINEVENT
syscall_yield ( ) ;
}
2012-11-22 11:29:27 +04:00
}
void send_keyboard_event ( process_windows_t * pw , uint8_t event , w_keyboard_t packet ) {
/* Construct the header */
wins_packet_t header ;
header . magic = WINS_MAGIC ;
header . command_type = event ;
header . packet_size = sizeof ( w_keyboard_t ) ;
/* Send them */
2013-06-13 10:37:07 +04:00
struct stat buf ;
fstat ( pw - > event_pipe , & buf ) ;
if ( buf . st_size < BUFFER_SAFE_ZONE ) {
write ( pw - > event_pipe , & header , sizeof ( wins_packet_t ) ) ;
write ( pw - > event_pipe , & packet , sizeof ( w_keyboard_t ) ) ;
kill ( pw - > pid , SIGWINEVENT ) ; // SIGWINEVENT
syscall_yield ( ) ;
} else {
fprintf ( stderr , " [compositor] This client (pid=%d) is lagging, we are dropping keyboard packets. \n " , pw - > pid ) ;
kill ( pw - > pid , SIGWINEVENT ) ; // SIGWINEVENT
syscall_yield ( ) ;
}
2012-11-22 11:29:27 +04:00
}
void send_mouse_event ( process_windows_t * pw , uint8_t event , w_mouse_t * packet ) {
/* Construct the header */
wins_packet_t header ;
header . magic = WINS_MAGIC ;
header . command_type = event ;
header . packet_size = sizeof ( w_mouse_t ) ;
/* Send them */
2013-06-13 10:37:07 +04:00
struct stat buf ;
fstat ( pw - > event_pipe , & buf ) ;
if ( buf . st_size < BUFFER_SAFE_ZONE ) {
fwrite ( & header , 1 , sizeof ( wins_packet_t ) , pw - > event_pipe_file ) ;
fwrite ( packet , 1 , sizeof ( w_mouse_t ) , pw - > event_pipe_file ) ;
fflush ( pw - > event_pipe_file ) ;
} else {
fprintf ( stderr , " [compositor] This client (pid=%d) is lagging, we are dropping mouse packets. \n " , pw - > pid ) ;
}
2013-05-06 02:00:24 +04:00
//kill(pw->pid, SIGWINEVENT); // SIGWINEVENT
2012-11-22 11:29:27 +04:00
//syscall_yield();
}
2012-10-22 06:52:53 +04:00
int32_t min ( int32_t a , int32_t b ) {
return ( a < b ) ? a : b ;
}
int32_t max ( int32_t a , int32_t b ) {
return ( a > b ) ? a : b ;
}
uint8_t is_between ( int32_t lo , int32_t hi , int32_t val ) {
if ( val > = lo & & val < hi ) return 1 ;
return 0 ;
}
2013-05-30 08:31:59 +04:00
server_window_t * top_at ( uint16_t x , uint16_t y ) {
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
uint32_t c = GFXR ( select_ctx , x , y ) ;
unsigned int w = ( _GRE ( c ) < < 8 ) | ( _BLU ( c ) ) ;
return windows [ w ] ;
2012-10-22 06:52:53 +04:00
}
void rebalance_windows ( ) {
uint32_t i = 1 ;
for ( ; i < 0xFFF8 ; + + i ) {
if ( ! windows [ i ] ) break ;
}
uint32_t j = i + 1 ;
for ( ; j < 0xFFF8 ; + + j ) {
if ( ! windows [ j ] ) break ;
}
if ( j = = i + 1 ) {
return ;
} else {
for ( j = i ; j < 0xFFF8 ; + + j ) {
windows [ j ] = windows [ j + 1 ] ;
if ( windows [ j + 1 ] = = NULL ) return ;
windows [ j ] - > z = j ;
}
}
}
2013-05-30 08:31:59 +04:00
void reorder_window ( server_window_t * window , uint16_t new_zed ) {
2012-10-22 06:52:53 +04:00
if ( ! window ) {
return ;
}
int z = window - > z ;
window - > z = new_zed ;
if ( windows [ z ] = = window ) {
windows [ z ] = NULL ;
}
if ( new_zed = = 0 | | new_zed = = 0xFFFF ) {
windows [ new_zed ] = window ;
if ( z ! = new_zed ) {
rebalance_windows ( ) ;
}
return ;
}
if ( windows [ new_zed ] ! = window ) {
reorder_window ( windows [ new_zed ] , new_zed + 1 ) ;
windows [ new_zed ] = window ;
}
if ( z ! = new_zed ) {
rebalance_windows ( ) ;
}
}
2013-05-30 08:31:59 +04:00
void make_top ( server_window_t * window ) {
2012-10-22 06:52:53 +04:00
uint16_t index = window - > z ;
if ( index = = 0 ) return ;
if ( index = = 0xFFFF ) return ;
uint16_t highest = 0 ;
foreach ( n , process_list ) {
process_windows_t * pw = ( process_windows_t * ) n - > value ;
foreach ( node , pw - > windows ) {
2013-05-30 08:31:59 +04:00
server_window_t * win = ( server_window_t * ) node - > value ;
2012-10-22 06:52:53 +04:00
if ( win = = window ) continue ;
if ( win - > z = = 0 ) continue ;
if ( win - > z = = 0xFFFF ) continue ;
if ( highest < win - > z ) highest = win - > z ;
if ( win = = window ) continue ;
if ( win - > z > window - > z ) continue ;
}
}
reorder_window ( window , highest + 1 ) ;
}
2013-05-30 08:31:59 +04:00
server_window_t * focused_window ( ) {
2012-11-20 09:27:24 +04:00
if ( ! focused ) {
return windows [ 0 ] ;
} else {
return focused ;
}
}
2013-05-30 08:31:59 +04:00
void set_focused_window ( server_window_t * n_focused ) {
2012-11-20 09:27:24 +04:00
if ( n_focused = = focused ) {
return ;
} else {
if ( focused ) {
w_window_t wwt ;
wwt . wid = focused - > wid ;
wwt . left = 0 ;
send_window_event ( focused - > owner , WE_FOCUSCHG , & wwt ) ;
}
focused = n_focused ;
2012-12-11 08:17:25 +04:00
if ( focused ) {
w_window_t wwt ;
wwt . wid = focused - > wid ;
wwt . left = 1 ;
send_window_event ( focused - > owner , WE_FOCUSCHG , & wwt ) ;
make_top ( focused ) ;
2012-12-11 08:26:46 +04:00
} else {
focused = windows [ 0 ] ;
2012-12-11 08:17:25 +04:00
}
2012-11-20 09:27:24 +04:00
}
2012-11-24 12:18:14 +04:00
}
void set_focused_at ( int x , int y ) {
2013-05-30 08:31:59 +04:00
server_window_t * n_focused = top_at ( x , y ) ;
2012-11-24 12:18:14 +04:00
set_focused_window ( n_focused ) ;
2012-10-22 06:52:53 +04:00
}
2013-05-30 08:31:59 +04:00
server_window_t * init_window ( process_windows_t * pw , wid_t wid , int32_t x , int32_t y , uint16_t width , uint16_t height , uint16_t index ) {
server_window_t * window = malloc ( sizeof ( server_window_t ) ) ;
if ( ! window ) {
fprintf ( stderr , " [%d] [window] Could not malloc a server_window_t! " , getpid ( ) ) ;
return NULL ;
}
window - > owner = pw ;
window - > wid = wid ;
window - > bufid = 0 ;
window - > width = width ;
window - > height = height ;
window - > x = x ;
window - > y = y ;
window - > z = index ;
window - > rotation = 0 ;
char key [ 1024 ] ;
SHMKEY ( key , 1024 , window ) ;
size_t size = ( width * height * WIN_B ) ;
window - > buffer = ( uint8_t * ) syscall_shm_obtain ( key , & size ) ;
if ( ! window - > buffer ) {
fprintf ( stderr , " [%d] [window] Could not create a buffer for a new window for pid %d! " , getpid ( ) , pw - > pid ) ;
free ( window ) ;
return NULL ;
}
list_insert ( pw - > windows , window ) ;
return window ;
}
void free_window ( server_window_t * window ) {
/* Free the window buffer */
if ( ! window ) return ;
char key [ 256 ] ;
SHMKEY ( key , 256 , window ) ;
syscall_shm_release ( key ) ;
/* Now, kill the object itself */
process_windows_t * pw = window - > owner ;
node_t * n = list_find ( pw - > windows , window ) ;
if ( n ) {
list_delete ( pw - > windows , n ) ;
free ( n ) ;
}
}
void resize_window_buffer ( server_window_t * window , int16_t left , int16_t top , uint16_t width , uint16_t height ) {
2012-10-22 06:52:53 +04:00
2013-05-30 08:31:59 +04:00
if ( ! window ) {
return ;
}
/* If the window has enlarged, we need to create a new buffer */
if ( ( width * height ) > ( window - > width * window - > height ) ) {
/* Release the old buffer */
char key [ 256 ] , keyn [ 256 ] ;
SHMKEY ( key , 256 , window ) ;
/* Create the new one */
window - > bufid + + ;
SHMKEY ( keyn , 256 , window ) ;
size_t size = ( width * height * WIN_B ) ;
char * new_buffer = ( uint8_t * ) syscall_shm_obtain ( keyn , & size ) ;
memset ( new_buffer , 0x44 , size ) ;
window - > buffer = new_buffer ;
syscall_shm_release ( key ) ;
}
if ( left ! = 0 & & top ! = 0 ) {
window - > x = left ;
window - > y = top ;
}
window - > width = width ;
window - > height = height ;
}
void window_add ( server_window_t * window ) {
2012-10-22 06:52:53 +04:00
int z = window - > z ;
while ( windows [ z ] ) {
z + + ;
}
window - > z = z ;
2013-05-23 09:59:23 +04:00
2013-05-30 08:31:59 +04:00
window - > anim_start = tick_count ;
window - > anim_mode = 1 ;
2013-05-23 09:59:23 +04:00
memset ( window - > buffer , 0x00 , WIN_B * window - > width * window - > height ) ;
2012-10-22 06:52:53 +04:00
windows [ z ] = window ;
}
2013-05-30 08:31:59 +04:00
void unorder_window ( server_window_t * window ) {
2012-10-22 06:52:53 +04:00
int z = window - > z ;
2012-12-08 12:25:16 +04:00
if ( z < WINDOW_LAYERS & & windows [ z ] ) {
2012-10-22 06:52:53 +04:00
windows [ z ] = 0 ;
}
window - > z = 0 ;
return ;
}
2013-05-30 08:31:59 +04:00
void blit_window_cairo ( server_window_t * window , int32_t left , int32_t top ) {
2012-10-22 06:52:53 +04:00
int stride = window - > width * 4 ; //cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, window->width);
cairo_surface_t * win = cairo_image_surface_create_for_data ( window - > buffer , CAIRO_FORMAT_ARGB32 , window - > width , window - > height , stride ) ;
if ( cairo_surface_status ( win ) ! = CAIRO_STATUS_SUCCESS ) {
return ;
}
assert ( win ) ;
cairo_save ( cr ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
cairo_save ( cs ) ;
cairo_translate ( cr , left , top ) ;
cairo_translate ( cs , left , top ) ;
if ( window - > z ! = 0xFFFF & & window - > z ! = 0 ) {
2013-04-02 13:10:45 +04:00
double r = window - > rotation * M_PI / 180.0 ;
cairo_translate ( cr , ( int ) ( window - > width / 2 ) , ( int ) ( window - > height / 2 ) ) ;
cairo_rotate ( cr , r ) ;
cairo_translate ( cr , ( int ) ( - window - > width / 2 ) , ( int ) ( - window - > height / 2 ) ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
2013-04-02 13:10:45 +04:00
cairo_translate ( cs , ( int ) ( window - > width / 2 ) , ( int ) ( window - > height / 2 ) ) ;
cairo_rotate ( cs , r ) ;
cairo_translate ( cs , ( int ) ( - window - > width / 2 ) , ( int ) ( - window - > height / 2 ) ) ;
2013-06-28 11:15:32 +04:00
cairo_pattern_set_filter ( cairo_get_source ( cr ) , CAIRO_FILTER_FAST ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
}
2012-10-22 06:52:53 +04:00
2014-04-02 08:29:36 +04:00
if ( window - > anim_mode ) {
2013-05-30 08:31:59 +04:00
int frame = tick_count - window - > anim_start ;
if ( frame > = animation_lengths [ window - > anim_mode ] ) {
if ( window - > anim_mode = = 1 ) {
window - > anim_mode = 0 ;
window - > anim_start = 0 ;
goto paint_window ;
} else if ( window - > anim_mode = = 2 ) {
window - > anim_mode = 1 ;
window - > anim_start = tick_count ;
} else if ( window - > anim_mode = = 3 ) {
window - > anim_mode = 4 ;
list_insert ( windows_to_clean , window ) ;
}
} else {
if ( window - > anim_mode = = 4 ) {
goto done_drawing ;
}
if ( window - > anim_mode = = 2 ) {
frame = 255 - frame ;
}
if ( window - > anim_mode = = 3 ) {
frame = 255 - frame ;
}
double x = 0.75 + ( ( double ) frame / 256.0 ) * 0.25 ;
2013-05-22 08:11:30 +04:00
2013-05-30 08:31:59 +04:00
int t_x = ( window - > width * ( 1.0 - x ) ) / 2 ;
int t_y = ( window - > height * ( 1.0 - x ) ) / 2 ;
2013-05-22 08:11:30 +04:00
2014-04-02 08:29:36 +04:00
if ( window - > z ! = 0xFFFF & & window - > z ! = 0 ) {
cairo_translate ( cr , t_x , t_y ) ;
cairo_scale ( cr , x , x ) ;
}
2013-05-30 08:31:59 +04:00
cairo_set_source_surface ( cr , win , 0 , 0 ) ;
2013-06-19 10:48:04 +04:00
cairo_pattern_set_filter ( cairo_get_source ( cr ) , CAIRO_FILTER_FAST ) ;
2013-05-30 08:31:59 +04:00
cairo_paint_with_alpha ( cr , ( double ) frame / 256.0 ) ;
}
2013-05-22 08:11:30 +04:00
} else {
2013-05-30 08:31:59 +04:00
paint_window :
2013-05-22 08:11:30 +04:00
cairo_set_source_surface ( cr , win , 0 , 0 ) ;
cairo_paint ( cr ) ;
}
2013-05-30 08:31:59 +04:00
done_drawing :
2012-10-22 06:52:53 +04:00
cairo_surface_destroy ( win ) ;
2012-11-18 01:01:02 +04:00
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
cairo_set_source_rgb ( cs , 0 , ( ( window - > z & 0xFF00 ) > > 8 ) / 255.0 , ( window - > z & 0xFF ) / 255.0 ) ;
cairo_rectangle ( cs , 0 , 0 , window - > width , window - > height ) ;
cairo_set_antialias ( cs , CAIRO_ANTIALIAS_NONE ) ;
cairo_fill ( cs ) ;
2012-10-22 06:52:53 +04:00
cairo_restore ( cr ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
cairo_restore ( cs ) ;
2012-10-22 06:52:53 +04:00
}
2012-12-08 12:25:16 +04:00
void redraw_scale_mode ( ) {
int stride = cairo_format_stride_for_width ( CAIRO_FORMAT_ARGB32 , ctx - > width ) ;
surface = cairo_image_surface_create_for_data ( ctx - > backbuffer , CAIRO_FORMAT_ARGB32 , ctx - > width , ctx - > height , stride ) ;
2013-04-02 13:14:35 +04:00
selface = cairo_image_surface_create_for_data ( select_ctx - > backbuffer , CAIRO_FORMAT_ARGB32 , ctx - > width , ctx - > height , stride ) ;
2012-12-08 12:25:16 +04:00
cr = cairo_create ( surface ) ;
2013-04-02 13:14:35 +04:00
cs = cairo_create ( selface ) ;
2012-12-08 12:25:16 +04:00
/* Draw background window */
if ( windows [ 0 ] ) {
blit_window_cairo ( windows [ 0 ] , windows [ 0 ] - > x , windows [ 0 ] - > y ) ;
}
/* Draw panel window */
if ( windows [ WINDOW_LAYERS - 1 ] ) {
blit_window_cairo ( windows [ WINDOW_LAYERS - 1 ] , windows [ WINDOW_LAYERS - 1 ] - > x , windows [ WINDOW_LAYERS - 1 ] - > y ) ;
}
/* Fade all of that out */
cairo_save ( cr ) ;
cairo_rectangle ( cr , 0 , 0 , ctx - > width , ctx - > height ) ;
cairo_set_source_rgba ( cr , 0 , 0 , 0 , 0.4 ) ;
cairo_fill ( cr ) ;
cairo_restore ( cr ) ;
int window_count = 0 ;
for ( uint32_t i = 1 ; i < WINDOW_LAYERS - 1 ; + + i ) {
if ( windows [ i ] ) {
window_count + + ;
}
}
int columns ;
int rows ;
switch ( window_count ) {
case 0 :
management_mode = MODE_NORMAL ;
goto _finish ;
case 1 :
columns = 1 ;
rows = 1 ;
break ;
case 2 :
columns = 2 ;
rows = 1 ;
break ;
case 3 :
columns = 3 ;
rows = 1 ;
break ;
case 4 :
columns = 2 ;
rows = 2 ;
break ;
case 5 :
columns = 3 ;
rows = 2 ;
break ;
default :
{
double sqr = sqrt ( ( double ) window_count ) ;
rows = ( int ) sqr ;
columns = ( window_count ) / rows ;
if ( rows * columns < window_count ) {
columns + = 1 ;
}
}
}
double cell_height = ( double ) ctx - > height / ( double ) rows ;
double cell_width = ( double ) ctx - > width / ( double ) columns ;
int x = 0 ;
int y = 0 ;
double last_row_width = cell_width ;
if ( columns * rows > window_count ) {
int remaining = window_count - ( rows - 1 ) * columns ;
last_row_width = ( double ) ctx - > width / ( double ) remaining ;
}
2013-05-30 08:31:59 +04:00
server_window_t * n_focus = NULL ;
2012-12-08 12:25:16 +04:00
for ( uint32_t i = 1 ; i < WINDOW_LAYERS - 1 ; + + i ) {
if ( windows [ i ] ) {
2013-05-30 08:31:59 +04:00
server_window_t * window = windows [ i ] ;
2012-12-08 12:25:16 +04:00
int w = window - > width ;
int h = window - > height ;
int stride = window - > width * 4 ;
cairo_surface_t * win = cairo_image_surface_create_for_data ( window - > buffer , CAIRO_FORMAT_ARGB32 , window - > width , window - > height , stride ) ;
if ( cairo_surface_status ( win ) ! = CAIRO_STATUS_SUCCESS ) {
continue ;
}
if ( y = = rows - 1 ) {
cell_width = last_row_width ;
}
cairo_save ( cr ) ;
double y_scale = cell_height / ( double ) h ;
double x_scale = cell_width / ( double ) w ;
cairo_translate ( cr , cell_width * x , cell_height * y ) ;
if ( x_scale < y_scale ) {
cairo_translate ( cr , 0 , ( cell_height - h * x_scale ) / 2 ) ;
cairo_scale ( cr , x_scale , x_scale ) ;
} else {
cairo_translate ( cr , ( cell_width - w * y_scale ) / 2 , 0 ) ;
cairo_scale ( cr , y_scale , y_scale ) ;
}
cairo_set_source_surface ( cr , win , 0 , 0 ) ;
2013-06-19 10:43:50 +04:00
if ( ( x_scale < y_scale & & x_scale < 1.0 ) | | ( x_scale > y_scale & & y_scale < 1.0 ) ) {
2013-06-19 10:48:04 +04:00
cairo_pattern_set_filter ( cairo_get_source ( cr ) , CAIRO_FILTER_FAST ) ;
} else {
cairo_pattern_set_filter ( cairo_get_source ( cr ) , CAIRO_FILTER_GOOD ) ;
2013-06-19 10:43:50 +04:00
}
2012-12-08 12:25:16 +04:00
if ( mouse_x / MOUSE_SCALE > = x * cell_width & &
mouse_x / MOUSE_SCALE < x * cell_width + cell_width & &
mouse_y / MOUSE_SCALE > = y * cell_height & &
mouse_y / MOUSE_SCALE < y * cell_height + cell_height ) {
cairo_paint ( cr ) ;
if ( focus_next_scale ) {
n_focus = window ;
management_mode = MODE_NORMAL ;
}
} else {
cairo_paint_with_alpha ( cr , 0.7 ) ;
}
cairo_surface_destroy ( win ) ;
cairo_restore ( cr ) ;
x + + ;
if ( x = = columns ) {
y + + ;
x = 0 ;
}
}
}
if ( focus_next_scale ) {
set_focused_window ( n_focus ) ;
focus_next_scale = 0 ;
}
_finish :
cairo_surface_flush ( surface ) ;
cairo_destroy ( cr ) ;
cairo_surface_flush ( surface ) ;
cairo_surface_destroy ( surface ) ;
2013-04-02 13:14:35 +04:00
cairo_surface_flush ( selface ) ;
cairo_destroy ( cs ) ;
cairo_surface_destroy ( selface ) ;
2012-12-08 12:25:16 +04:00
}
2012-11-22 11:29:27 +04:00
void redraw_windows ( ) {
2012-10-22 06:52:53 +04:00
int stride = cairo_format_stride_for_width ( CAIRO_FORMAT_ARGB32 , ctx - > width ) ;
surface = cairo_image_surface_create_for_data ( ctx - > backbuffer , CAIRO_FORMAT_ARGB32 , ctx - > width , ctx - > height , stride ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
selface = cairo_image_surface_create_for_data ( select_ctx - > backbuffer , CAIRO_FORMAT_ARGB32 , ctx - > width , ctx - > height , stride ) ;
2012-10-22 06:52:53 +04:00
cr = cairo_create ( surface ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
cs = cairo_create ( selface ) ;
2012-10-22 06:52:53 +04:00
2012-12-08 12:25:16 +04:00
for ( uint32_t i = 0 ; i < WINDOW_LAYERS ; + + i ) {
2013-05-30 08:31:59 +04:00
server_window_t * window = NULL ;
2012-10-22 06:52:53 +04:00
if ( windows [ i ] ) {
window = windows [ i ] ;
if ( window = = moving_window ) {
blit_window_cairo ( moving_window , moving_window_l , moving_window_t ) ;
} else {
blit_window_cairo ( window , window - > x , window - > y ) ;
}
}
}
2012-12-11 08:38:34 +04:00
/* Resizing window outline */
if ( resizing_window ) {
cairo_save ( cr ) ;
cairo_set_line_width ( cr , 3 ) ;
cairo_set_source_rgba ( cr , 0.0 , 0.4 , 1.0 , 0.9 ) ;
cairo_rectangle ( cr , resizing_window - > x , resizing_window - > y , resizing_window_w , resizing_window_h ) ;
cairo_stroke_preserve ( cr ) ;
cairo_set_source_rgba ( cr , 0.33 , 0.55 , 1.0 , 0.5 ) ;
cairo_fill ( cr ) ;
cairo_restore ( cr ) ;
}
2012-10-22 06:52:53 +04:00
cairo_surface_flush ( surface ) ;
cairo_destroy ( cr ) ;
cairo_surface_destroy ( surface ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
cairo_surface_flush ( selface ) ;
cairo_destroy ( cs ) ;
cairo_surface_destroy ( selface ) ;
2012-10-22 06:52:53 +04:00
}
2013-06-19 10:43:50 +04:00
void cairo_rounded_rectangle ( cairo_t * cr , double x , double y , double width , double height , double radius ) {
double degrees = M_PI / 180.0 ;
cairo_new_sub_path ( cr ) ;
cairo_arc ( cr , x + width - radius , y + radius , radius , - 90 * degrees , 0 * degrees ) ;
cairo_arc ( cr , x + width - radius , y + height - radius , radius , 0 * degrees , 90 * degrees ) ;
cairo_arc ( cr , x + radius , y + height - radius , radius , 90 * degrees , 180 * degrees ) ;
cairo_arc ( cr , x + radius , y + radius , radius , 180 * degrees , 270 * degrees ) ;
cairo_close_path ( cr ) ;
}
void draw_window_picker ( ) {
/* TODO draw window picker */
int window_count = 0 ;
for ( uint32_t i = 1 ; i < WINDOW_LAYERS - 1 ; + + i ) {
if ( windows [ i ] ) {
window_count + + ;
}
}
if ( window_count < 2 ) {
fprintf ( stderr , " [compositor] Exiting window picker (<2 regular windows) \n " ) ;
management_mode = MODE_NORMAL ;
return ;
}
2013-06-28 11:15:32 +04:00
window_picker_index = ( window_picker_index + window_count ) % window_count ;
2013-06-19 10:43:50 +04:00
int stride = cairo_format_stride_for_width ( CAIRO_FORMAT_ARGB32 , ctx - > width ) ;
surface = cairo_image_surface_create_for_data ( ctx - > backbuffer , CAIRO_FORMAT_ARGB32 , ctx - > width , ctx - > height , stride ) ;
cr = cairo_create ( surface ) ;
/* Don't need a select surface, already have one */
cairo_set_line_cap ( cr , CAIRO_LINE_CAP_ROUND ) ;
cairo_set_line_join ( cr , CAIRO_LINE_JOIN_ROUND ) ;
2013-06-28 11:15:32 +04:00
/* Draw the background */
int width = 600 ;
int height = 230 ;
2013-06-19 10:43:50 +04:00
cairo_rounded_rectangle ( cr , ( ctx - > width - width ) / 2 , ( ctx - > height - height ) / 2 , width , height , 20.0 ) ;
cairo_set_source_rgba ( cr , 44.0 / 255.0 , 71.0 / 255.0 , 91.0 / 255.0 , 29.0 / 255.0 ) ;
cairo_set_line_width ( cr , 4 ) ;
cairo_stroke ( cr ) ;
cairo_rounded_rectangle ( cr , ( ctx - > width - width ) / 2 + 3 , ( ctx - > height - height ) / 2 + 3 , width - 6 , height - 6 , 18.0 ) ;
cairo_set_source_rgba ( cr , 158.0 / 255.0 , 169.0 / 255.0 , 177.0 / 255.0 , 0.9 ) ;
cairo_fill ( cr ) ;
2013-06-28 11:15:32 +04:00
/* Now draw the previous, current, and next window. */
2013-06-19 10:43:50 +04:00
}
2013-05-30 08:31:59 +04:00
void internal_free_window ( server_window_t * window ) {
2012-11-24 12:18:14 +04:00
if ( window = = focused_window ( ) ) {
if ( window - > z = = 0xFFFF ) {
focused = NULL ;
return ;
}
for ( int i = window - > z ; i > 0 ; - - i ) {
if ( windows [ i - 1 ] ) {
set_focused_window ( windows [ i - 1 ] ) ;
return ;
}
}
}
}
2013-05-30 08:31:59 +04:00
void actually_destroy_window ( server_window_t * win ) {
2012-12-10 11:06:42 +04:00
win - > x = 0xFFFF ;
internal_free_window ( win ) ;
unorder_window ( win ) ;
/* Wait until we're done drawing */
spin_lock ( & am_drawing ) ;
spin_unlock ( & am_drawing ) ;
free_window ( win ) ;
}
2013-05-30 08:31:59 +04:00
void destroy_window ( server_window_t * win ) {
win - > anim_mode = 3 ;
win - > anim_start = tick_count ;
}
2012-10-22 06:52:53 +04:00
void process_window_command ( int sig ) {
foreach ( n , process_list ) {
process_windows_t * pw = ( process_windows_t * ) n - > value ;
/* Are there any messages in this process's command pipe? */
struct stat buf ;
fstat ( pw - > command_pipe , & buf ) ;
int max_requests_per_cycle = 1 ;
while ( ( buf . st_size > 0 ) & & ( max_requests_per_cycle > 0 ) ) {
w_window_t wwt ;
wins_packet_t header ;
int bytes_read = read ( pw - > command_pipe , & header , sizeof ( wins_packet_t ) ) ;
while ( header . magic ! = WINS_MAGIC ) {
2012-11-22 11:29:27 +04:00
fprintf ( stderr , " [compositor] Magic is wrong from pid %d, expected 0x%x but got 0x%x [read %d bytes of %d] \n " , pw - > pid , WINS_MAGIC , header . magic , bytes_read , sizeof ( header ) ) ;
2012-10-22 06:52:53 +04:00
max_requests_per_cycle - - ;
goto bad_magic ;
memcpy ( & header , ( void * ) ( ( uintptr_t ) & header + 1 ) , ( sizeof ( header ) - 1 ) ) ;
read ( pw - > event_pipe , ( char * ) ( ( uintptr_t ) & header + sizeof ( header ) - 1 ) , 1 ) ;
}
max_requests_per_cycle - - ;
switch ( header . command_type ) {
case WC_NEWWINDOW :
{
read ( pw - > command_pipe , & wwt , sizeof ( w_window_t ) ) ;
wwt . wid = _next_wid ;
2013-05-30 08:31:59 +04:00
server_window_t * new_window = init_window ( pw , _next_wid , wwt . left , wwt . top , wwt . width , wwt . height , _next_wid ) ;
2012-10-22 06:52:53 +04:00
window_add ( new_window ) ;
_next_wid + + ;
send_window_event ( pw , WE_NEWWINDOW , & wwt ) ;
}
break ;
case WC_SET_ALPHA :
{
read ( pw - > command_pipe , & wwt , sizeof ( w_window_t ) ) ;
2013-05-30 08:31:59 +04:00
/* XXX ignored */
2012-10-22 06:52:53 +04:00
}
break ;
case WC_RESIZE :
{
read ( pw - > command_pipe , & wwt , sizeof ( w_window_t ) ) ;
2013-05-30 08:31:59 +04:00
server_window_t * window = get_window_with_process ( pw , wwt . wid ) ;
2012-10-22 06:52:53 +04:00
resize_window_buffer ( window , window - > x , window - > y , wwt . width , wwt . height ) ;
send_window_event ( pw , WE_RESIZED , & wwt ) ;
}
break ;
case WC_DESTROY :
read ( pw - > command_pipe , & wwt , sizeof ( w_window_t ) ) ;
2013-05-30 08:31:59 +04:00
server_window_t * win = get_window_with_process ( pw , wwt . wid ) ;
2012-12-10 11:06:42 +04:00
destroy_window ( win ) ;
2012-10-22 06:52:53 +04:00
send_window_event ( pw , WE_DESTROYED , & wwt ) ;
break ;
case WC_DAMAGE :
read ( pw - > command_pipe , & wwt , sizeof ( w_window_t ) ) ;
break ;
case WC_REDRAW :
read ( pw - > command_pipe , & wwt , sizeof ( w_window_t ) ) ;
send_window_event ( pw , WE_REDRAWN , & wwt ) ;
break ;
case WC_REORDER :
read ( pw - > command_pipe , & wwt , sizeof ( w_window_t ) ) ;
reorder_window ( get_window_with_process ( pw , wwt . wid ) , wwt . left ) ;
break ;
default :
2012-11-22 11:29:27 +04:00
fprintf ( stderr , " [compositor] WARN: Unknown command type %d... \n " , header . command_type ) ;
2012-10-22 06:52:53 +04:00
void * nullbuf = malloc ( header . packet_size ) ;
read ( pw - > command_pipe , nullbuf , header . packet_size ) ;
free ( nullbuf ) ;
break ;
}
bad_magic :
fstat ( pw - > command_pipe , & buf ) ;
}
}
syscall_yield ( ) ;
}
/* Request page system */
void reset_request_system ( ) {
_request_page - > lock = 0 ;
_request_page - > server_done = 0 ;
_request_page - > client_done = 0 ;
_request_page - > client_pid = 0 ;
_request_page - > event_pipe = 0 ;
_request_page - > command_pipe = 0 ;
_request_page - > server_pid = getpid ( ) ;
_request_page - > server_width = ctx - > width ;
_request_page - > server_height = ctx - > height ;
_request_page - > server_depth = ctx - > depth ;
_request_page - > magic = WINS_MAGIC ;
}
void init_request_system ( ) {
size_t size = sizeof ( wins_server_global_t ) ;
_request_page = ( wins_server_global_t * ) syscall_shm_obtain ( WINS_SERVER_IDENTIFIER , & size ) ;
if ( ! _request_page ) {
2012-11-22 11:29:27 +04:00
fprintf ( stderr , " [compositor] Could not get a shm block for its request page! Bailing... " ) ;
2012-10-22 06:52:53 +04:00
exit ( - 1 ) ;
}
reset_request_system ( ) ;
}
void process_request ( ) {
fflush ( stdout ) ;
if ( _request_page - > client_done ) {
process_windows_t * pw = malloc ( sizeof ( process_windows_t ) ) ;
pw - > pid = _request_page - > client_pid ;
pw - > event_pipe = syscall_mkpipe ( ) ;
pw - > event_pipe_file = fdopen ( pw - > event_pipe , " a " ) ;
pw - > command_pipe = syscall_mkpipe ( ) ;
pw - > windows = list_create ( ) ;
_request_page - > event_pipe = syscall_share_fd ( pw - > event_pipe , pw - > pid ) ;
_request_page - > command_pipe = syscall_share_fd ( pw - > command_pipe , pw - > pid ) ;
_request_page - > client_done = 0 ;
_request_page - > server_done = 1 ;
list_insert ( process_list , pw ) ;
2012-11-22 11:29:27 +04:00
syscall_yield ( ) ;
2012-10-22 06:52:53 +04:00
}
if ( ! _request_page - > lock ) {
reset_request_system ( ) ;
}
}
void delete_process ( process_windows_t * pw ) {
2012-11-22 11:29:27 +04:00
/* XXX: this is not used anywhere! We need a closing handshake signal. */
2012-10-22 06:52:53 +04:00
list_destroy ( pw - > windows ) ;
list_free ( pw - > windows ) ;
free ( pw - > windows ) ;
close ( pw - > command_pipe ) ;
close ( pw - > event_pipe ) ;
node_t * n = list_find ( process_list , pw ) ;
list_delete ( process_list , n ) ;
free ( n ) ;
free ( pw ) ;
}
/* Signals */
void * ignore ( void * value ) {
return NULL ;
}
void init_signal_handlers ( ) {
#if 0
syscall_signal ( SIGWINEVENT , process_window_command ) ; // SIGWINEVENT
# else
syscall_signal ( SIGWINEVENT , ignore ) ; // SIGWINEVENT
# endif
}
/* Sprite stuff */
void init_sprite ( int i , char * filename , char * alpha ) {
2012-11-22 11:29:27 +04:00
sprite_t alpha_tmp ;
2012-10-22 06:52:53 +04:00
sprites [ i ] = malloc ( sizeof ( sprite_t ) ) ;
load_sprite ( sprites [ i ] , filename ) ;
if ( alpha ) {
sprites [ i ] - > alpha = 1 ;
load_sprite ( & alpha_tmp , alpha ) ;
sprites [ i ] - > masks = alpha_tmp . bitmap ;
} else {
sprites [ i ] - > alpha = 0 ;
}
sprites [ i ] - > blank = 0x0 ;
}
2012-11-24 12:18:14 +04:00
void init_sprite_png ( int id , char * path ) {
sprites [ id ] = malloc ( sizeof ( sprite_t ) ) ;
load_sprite_png ( sprites [ id ] , path ) ;
}
2012-10-22 06:52:53 +04:00
int center_x ( int x ) {
return ( ctx - > width - x ) / 2 ;
}
int center_y ( int y ) {
return ( ctx - > height - y ) / 2 ;
}
void display ( ) {
2012-11-24 12:18:14 +04:00
draw_fill ( ctx , rgb ( 0 , 0 , 0 ) ) ;
2012-10-22 06:52:53 +04:00
draw_sprite ( ctx , sprites [ 0 ] , center_x ( sprites [ 0 ] - > width ) , center_y ( sprites [ 0 ] - > height ) ) ;
flip ( ctx ) ;
}
2012-11-22 11:29:27 +04:00
char * precacheMemFont ( char * ident , char * name ) {
2012-10-22 06:52:53 +04:00
FILE * f = fopen ( name , " r " ) ;
size_t s = 0 ;
fseek ( f , 0 , SEEK_END ) ;
s = ftell ( f ) ;
fseek ( f , 0 , SEEK_SET ) ;
size_t shm_size = s ;
char * font = ( char * ) syscall_shm_obtain ( ident , & shm_size ) ; //malloc(s);
assert ( ( shm_size > = s ) & & " shm_obtain returned too little memory to load a font into! " ) ;
fread ( font , s , 1 , f ) ;
fclose ( f ) ;
return font ;
}
2012-11-22 11:29:27 +04:00
void load_fonts ( ) {
int i = 0 ;
while ( fonts [ i ] . identifier ) {
fprintf ( stderr , " [compositor] Loading font %s -> %s \n " , fonts [ i ] . path , fonts [ i ] . identifier ) ;
precacheMemFont ( fonts [ i ] . identifier , fonts [ i ] . path ) ;
+ + i ;
}
2012-10-22 06:52:53 +04:00
}
2013-05-22 08:11:30 +04:00
/**
* Keybindings
*/
2013-05-30 08:31:59 +04:00
int handle_key_press ( w_keyboard_t * keyboard , server_window_t * window ) {
2012-12-08 12:25:16 +04:00
2013-06-19 10:43:50 +04:00
fprintf ( stderr , " [compositor] Key event: %x %x %x \n " , keyboard - > event . action , keyboard - > event . keycode , keyboard - > event . modifiers ) ;
if ( ( management_mode = = MODE_WINDOW_PICKER ) & &
( keyboard - > event . action = = KEY_ACTION_UP ) & &
( ! ( keyboard - > event . modifiers & KEY_MOD_LEFT_ALT ) ) ) {
management_mode = MODE_NORMAL ;
fprintf ( stderr , " [compositor] Exiting window picker. \n " ) ;
return 1 ;
}
2012-12-08 12:25:16 +04:00
if ( keyboard - > event . action ! = KEY_ACTION_DOWN ) return 0 ;
2012-12-10 11:06:42 +04:00
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_CTRL ) & &
( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) & &
( keyboard - > event . keycode = = KEY_F4 ) ) {
/* kill the currently focused window */
destroy_window ( focused_window ( ) ) ;
}
2013-05-22 08:11:30 +04:00
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_CTRL ) & &
( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) & &
( keyboard - > event . keycode = = ' a ' ) ) {
/* reset the animation and start from scratch */
2013-05-30 08:31:59 +04:00
server_window_t * win = focused_window ( ) ;
win - > anim_mode = 1 ;
win - > anim_start = tick_count ;
2013-05-22 08:11:30 +04:00
return 1 ;
}
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_CTRL ) & &
( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) & &
( keyboard - > event . keycode = = ' s ' ) ) {
/* reset the animation and go backwards */
2013-05-30 08:31:59 +04:00
server_window_t * win = focused_window ( ) ;
win - > anim_mode = 2 ;
win - > anim_start = tick_count ;
2013-05-22 08:11:30 +04:00
return 1 ;
}
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_CTRL ) & &
( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) & &
( keyboard - > event . keycode = = ' z ' ) ) {
2013-05-30 08:31:59 +04:00
server_window_t * win = focused_window ( ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
if ( win ) {
2013-04-02 12:39:48 +04:00
win - > rotation - = 5 ;
2013-04-02 13:10:45 +04:00
if ( win - > rotation < 0 ) win - > rotation + = 360 ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
return 1 ;
}
}
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_CTRL ) & &
( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) & &
( keyboard - > event . keycode = = ' x ' ) ) {
2013-05-30 08:31:59 +04:00
server_window_t * win = focused_window ( ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
if ( win ) {
2013-04-02 12:39:48 +04:00
win - > rotation + = 5 ;
2013-04-02 13:10:45 +04:00
if ( win - > rotation > = 360 ) win - > rotation - = 360 ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
return 1 ;
}
}
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_CTRL ) & &
( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) & &
( keyboard - > event . keycode = = ' c ' ) ) {
2013-05-30 08:31:59 +04:00
server_window_t * win = focused_window ( ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
if ( win ) {
2013-04-02 12:39:48 +04:00
win - > rotation = 0 ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
return 1 ;
}
}
2012-12-08 12:25:16 +04:00
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_CTRL ) & &
( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) & &
( keyboard - > event . keycode = = ' e ' ) ) {
switch ( management_mode ) {
case MODE_NORMAL :
management_mode = MODE_SCALE ;
2013-06-19 10:43:50 +04:00
return 1 ;
2012-12-08 12:25:16 +04:00
case MODE_SCALE :
management_mode = MODE_NORMAL ;
2013-06-19 10:43:50 +04:00
return 1 ;
2012-12-08 12:25:16 +04:00
default :
break ;
}
2013-06-19 10:43:50 +04:00
}
2013-07-23 09:42:24 +04:00
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_CTRL ) & &
( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) & &
( keyboard - > event . keycode = = ' p ' ) ) {
if ( keyboard - > event . modifiers & KEY_MOD_LEFT_ALT ) {
take_screenshot_now = SCREENSHOT_THIS_WINDOW ;
} else {
take_screenshot_now = SCREENSHOT_WHOLE_SCREEN ;
}
return 1 ;
}
2013-06-19 10:43:50 +04:00
if ( ( keyboard - > event . modifiers & KEY_MOD_LEFT_ALT ) & &
( keyboard - > event . keycode = = ' \t ' ) ) {
int direction = ( keyboard - > event . modifiers & KEY_MOD_LEFT_SHIFT ) ? - 1 : 1 ;
switch ( management_mode ) {
case MODE_NORMAL :
fprintf ( stderr , " [compositor] Entering window picker. \n " ) ;
window_picker_index = 0 ;
case MODE_WINDOW_PICKER :
management_mode = MODE_WINDOW_PICKER ;
break ;
default :
goto _not_valid ;
}
fprintf ( stderr , " [compositor] Setting pick window %d \n " , direction ) ;
2012-12-08 12:25:16 +04:00
2013-06-19 10:43:50 +04:00
window_picker_index + = direction ;
2012-12-08 12:25:16 +04:00
return 1 ;
}
2013-06-19 10:43:50 +04:00
_not_valid :
2012-12-08 12:25:16 +04:00
return 0 ;
}
2013-05-30 08:31:59 +04:00
void device_to_window ( server_window_t * window , int32_t x , int32_t y , int32_t * out_x , int32_t * out_y ) {
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
* out_x = x - window - > x ;
* out_y = y - window - > y ;
double t_x = * out_x - ( window - > width / 2 ) ;
double t_y = * out_y - ( window - > height / 2 ) ;
2013-04-02 13:10:45 +04:00
double s = sin ( - ( window - > rotation * M_PI / 180.0 ) ) ;
double c = cos ( - ( window - > rotation * M_PI / 180.0 ) ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
double n_x = t_x * c - t_y * s ;
double n_y = t_x * s + t_y * c ;
* out_x = ( int32_t ) n_x + ( window - > width / 2 ) ;
* out_y = ( int32_t ) n_y + ( window - > height / 2 ) ;
}
2012-10-22 06:52:53 +04:00
void * process_requests ( void * garbage ) {
2014-04-06 04:06:28 +04:00
int mfd = open ( " /dev/mouse " , O_RDONLY ) ;
2012-10-22 06:52:53 +04:00
mouse_x = MOUSE_SCALE * ctx - > width / 2 ;
mouse_y = MOUSE_SCALE * ctx - > height / 2 ;
click_x = 0 ;
click_y = 0 ;
uint16_t _mouse_state = 0 ;
2013-05-30 08:31:59 +04:00
server_window_t * _mouse_window = NULL ;
2012-10-22 06:52:53 +04:00
int32_t _mouse_init_x ;
int32_t _mouse_init_y ;
int32_t _mouse_win_x ;
int32_t _mouse_win_y ;
int8_t _mouse_moved = 0 ;
int32_t _mouse_win_x_p ;
int32_t _mouse_win_y_p ;
2012-12-10 11:06:42 +04:00
char buf [ sizeof ( mouse_device_packet_t ) ] ;
2012-10-22 06:52:53 +04:00
while ( 1 ) {
2012-12-10 11:06:42 +04:00
mouse_device_packet_t * packet = ( mouse_device_packet_t * ) & buf ;
int r = read ( mfd , & buf , sizeof ( mouse_device_packet_t ) ) ;
if ( packet - > magic ! = MOUSE_MAGIC ) {
int r = read ( mfd , buf , 1 ) ;
break ;
}
/* Apply mouse movement */
int l ;
l = 3 ;
mouse_x + = packet - > x_difference * l ;
mouse_y - = packet - > y_difference * l ;
if ( mouse_x < 0 ) mouse_x = 0 ;
if ( mouse_y < 0 ) mouse_y = 0 ;
if ( mouse_x > = ctx - > width * MOUSE_SCALE ) mouse_x = ( ctx - > width ) * MOUSE_SCALE ;
if ( mouse_y > = ctx - > height * MOUSE_SCALE ) mouse_y = ( ctx - > height ) * MOUSE_SCALE ;
if ( management_mode = = MODE_SCALE ) {
if ( packet - > buttons & MOUSE_BUTTON_LEFT ) {
focus_next_scale = 1 ;
2012-10-22 06:52:53 +04:00
}
2012-12-10 11:06:42 +04:00
} else {
if ( _mouse_state = = 0 & & ( packet - > buttons & MOUSE_BUTTON_LEFT ) & & k_alt ) {
set_focused_at ( mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE ) ;
_mouse_window = focused_window ( ) ;
if ( _mouse_window ) {
if ( _mouse_window - > z ! = 0 & & _mouse_window - > z ! = 0xFFFF ) {
_mouse_state = 1 ;
_mouse_init_x = mouse_x ;
_mouse_init_y = mouse_y ;
_mouse_win_x = _mouse_window - > x ;
_mouse_win_y = _mouse_window - > y ;
_mouse_win_x_p = _mouse_win_x ;
_mouse_win_y_p = _mouse_win_y ;
moving_window = _mouse_window ;
moving_window_l = _mouse_win_x_p ;
moving_window_t = _mouse_win_y_p ;
make_top ( _mouse_window ) ;
}
2012-10-22 06:52:53 +04:00
}
2012-12-10 11:06:42 +04:00
} else if ( _mouse_state = = 0 & & ( packet - > buttons & MOUSE_BUTTON_MIDDLE ) & & k_alt ) {
set_focused_at ( mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE ) ;
_mouse_window = focused_window ( ) ;
if ( _mouse_window ) {
if ( _mouse_window - > z ! = 0 & & _mouse_window - > z ! = 0xFFFF ) {
_mouse_state = 3 ;
_mouse_init_x = mouse_x ;
_mouse_init_y = mouse_y ;
_mouse_win_x = _mouse_window - > x ;
_mouse_win_y = _mouse_window - > y ;
resizing_window = _mouse_window ;
resizing_window_w = _mouse_window - > width ;
resizing_window_h = _mouse_window - > height ;
make_top ( _mouse_window ) ;
}
}
} else if ( _mouse_state = = 0 & & ( packet - > buttons & MOUSE_BUTTON_LEFT ) & & ! k_alt ) {
set_focused_at ( mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE ) ;
_mouse_window = focused_window ( ) ;
if ( _mouse_window ) {
_mouse_state = 2 ; /* Dragging */
/* In window coordinates, that's... */
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
device_to_window ( _mouse_window , mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE , & click_x , & click_y ) ;
2012-12-10 11:06:42 +04:00
mouse_discard = 1 ;
_mouse_moved = 0 ;
}
#if 0
_mouse_window = focused_window ( ) ;
if ( _mouse_window ) {
if ( _mouse_window - > z = = 0 | | _mouse_window - > z = = 0xFFFF ) {
2012-10-22 06:52:53 +04:00
2012-12-10 11:06:42 +04:00
} else {
_mouse_state = 2 ;
_mouse_init_x = mouse_x ;
_mouse_init_y = mouse_y ;
_mouse_win_x = _mouse_window - > width ;
_mouse_win_y = _mouse_window - > height ;
_mouse_win_x_p = _mouse_win_x ;
_mouse_win_y_p = _mouse_win_y ;
make_top ( _mouse_window ) ;
2012-10-22 06:52:53 +04:00
}
2012-12-10 11:06:42 +04:00
}
# endif
} else if ( _mouse_state = = 0 ) {
2013-06-13 10:37:07 +04:00
w_mouse_t _packet ;
if ( packet - > buttons ) {
set_focused_at ( mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE ) ;
}
_mouse_window = focused_window ( ) ;
2014-04-02 08:39:08 +04:00
if ( _mouse_window ) {
_packet . wid = _mouse_window - > wid ;
2012-12-10 11:06:42 +04:00
2014-04-02 08:39:08 +04:00
_packet . old_x = click_x ;
_packet . old_y = click_y ;
2012-12-10 11:06:42 +04:00
2014-04-02 08:39:08 +04:00
device_to_window ( _mouse_window , mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE , & click_x , & click_y ) ;
2012-12-10 11:06:42 +04:00
2014-04-02 08:39:08 +04:00
_packet . new_x = click_x ;
_packet . new_y = click_y ;
2012-12-10 11:06:42 +04:00
2014-04-02 08:39:08 +04:00
_packet . buttons = packet - > buttons ;
_packet . command = WE_MOUSEMOVE ;
2012-12-10 11:06:42 +04:00
2014-04-02 08:39:08 +04:00
if ( _packet . new_x ! = _packet . old_x | | _packet . new_y ! = _packet . old_y ) {
send_mouse_event ( _mouse_window - > owner , WE_MOUSEMOVE , & _packet ) ;
}
2012-12-10 11:06:42 +04:00
}
} else if ( _mouse_state = = 1 ) {
if ( ! ( packet - > buttons & MOUSE_BUTTON_LEFT ) ) {
_mouse_window - > x = _mouse_win_x + ( mouse_x - _mouse_init_x ) / MOUSE_SCALE ;
_mouse_window - > y = _mouse_win_y + ( mouse_y - _mouse_init_y ) / MOUSE_SCALE ;
moving_window = NULL ;
_mouse_state = 0 ;
} else {
_mouse_win_x_p = _mouse_win_x + ( mouse_x - _mouse_init_x ) / MOUSE_SCALE ;
_mouse_win_y_p = _mouse_win_y + ( mouse_y - _mouse_init_y ) / MOUSE_SCALE ;
moving_window_l = _mouse_win_x_p ;
moving_window_t = _mouse_win_y_p ;
}
} else if ( _mouse_state = = 2 ) {
if ( ! ( packet - > buttons & MOUSE_BUTTON_LEFT ) ) {
/* Released */
_mouse_state = 0 ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
device_to_window ( _mouse_window , mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE , & click_x , & click_y ) ;
2012-12-10 11:06:42 +04:00
if ( ! _mouse_moved ) {
w_mouse_t _packet ;
_packet . wid = _mouse_window - > wid ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
device_to_window ( _mouse_window , mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE , & click_x , & click_y ) ;
2012-12-10 11:06:42 +04:00
_packet . new_x = click_x ;
_packet . new_y = click_y ;
_packet . old_x = - 1 ;
_packet . old_y = - 1 ;
_packet . buttons = packet - > buttons ;
_packet . command = WE_MOUSECLICK ;
send_mouse_event ( _mouse_window - > owner , WE_MOUSEMOVE , & _packet ) ;
2012-12-08 12:25:16 +04:00
}
2012-12-10 11:06:42 +04:00
} else {
/* Still down */
_mouse_moved = 1 ;
2013-06-13 10:37:07 +04:00
w_mouse_t _packet ;
_packet . wid = _mouse_window - > wid ;
2012-10-22 06:52:53 +04:00
2013-06-13 10:37:07 +04:00
_packet . old_x = click_x ;
_packet . old_y = click_y ;
2012-10-22 06:52:53 +04:00
2013-06-13 10:37:07 +04:00
device_to_window ( _mouse_window , mouse_x / MOUSE_SCALE , mouse_y / MOUSE_SCALE , & click_x , & click_y ) ;
2012-10-22 06:52:53 +04:00
2013-06-13 10:37:07 +04:00
_packet . new_x = click_x ;
_packet . new_y = click_y ;
2012-10-22 06:52:53 +04:00
2013-06-13 10:37:07 +04:00
_packet . buttons = packet - > buttons ;
_packet . command = WE_MOUSEMOVE ;
2012-10-22 06:52:53 +04:00
2013-06-13 10:37:07 +04:00
if ( _packet . new_x ! = _packet . old_x | | _packet . new_y ! = _packet . old_y ) {
2012-10-22 06:52:53 +04:00
send_mouse_event ( _mouse_window - > owner , WE_MOUSEMOVE , & _packet ) ;
}
2012-12-10 11:06:42 +04:00
}
2012-12-08 12:25:16 +04:00
2012-12-10 11:06:42 +04:00
} else if ( _mouse_state = = 3 ) {
int width_diff = ( mouse_x - _mouse_init_x ) / MOUSE_SCALE ;
int height_diff = ( mouse_y - _mouse_init_y ) / MOUSE_SCALE ;
resizing_window_w = resizing_window - > width + width_diff ;
resizing_window_h = resizing_window - > height + height_diff ;
if ( ! ( packet - > buttons & MOUSE_BUTTON_MIDDLE ) ) {
/* Resize */
w_window_t wwt ;
wwt . wid = resizing_window - > wid ;
wwt . width = resizing_window_w ;
wwt . height = resizing_window_h ;
resize_window_buffer ( resizing_window , resizing_window - > x , resizing_window - > y , wwt . width , wwt . height ) ;
send_window_event ( resizing_window - > owner , WE_RESIZED , & wwt ) ;
resizing_window = NULL ;
_mouse_state = 0 ;
2012-10-22 06:52:53 +04:00
}
}
}
2012-12-10 11:06:42 +04:00
}
return NULL ;
}
void * keyboard_input ( void * garbage ) {
2014-04-06 04:06:28 +04:00
int kfd = open ( " /dev/kbd " , O_RDONLY ) ;
2012-12-10 11:06:42 +04:00
char buf [ 1 ] ;
while ( 1 ) {
2012-12-08 12:25:16 +04:00
/* Read keyboard */
2014-04-06 04:06:28 +04:00
int r = read ( kfd , buf , 1 ) ;
2012-12-10 11:06:42 +04:00
if ( r > 0 ) {
w_keyboard_t packet ;
packet . ret = kbd_scancode ( buf [ 0 ] , & packet . event ) ;
2013-05-30 08:31:59 +04:00
server_window_t * focused = focused_window ( ) ;
2012-12-10 11:06:42 +04:00
if ( ! handle_key_press ( & packet , focused ) ) {
if ( focused ) {
packet . wid = focused - > wid ;
packet . command = 0 ;
packet . key = packet . ret ? packet . event . key : 0 ;
send_keyboard_event ( focused - > owner , WE_KEYDOWN , packet ) ;
2012-10-22 06:52:53 +04:00
}
}
}
}
return NULL ;
}
2013-07-23 09:42:24 +04:00
void take_screenshot ( int of_what ) {
cairo_surface_t * srf ;
if ( of_what = = SCREENSHOT_WHOLE_SCREEN ) {
int stride = ctx - > width * 4 ;
srf = cairo_image_surface_create_for_data ( ctx - > backbuffer , CAIRO_FORMAT_ARGB32 , ctx - > width , ctx - > height , stride ) ;
} else if ( of_what = = SCREENSHOT_THIS_WINDOW ) {
server_window_t * window = focused_window ( ) ;
if ( ! window ) { return ; }
int stride = window - > width * 4 ;
srf = cairo_image_surface_create_for_data ( window - > buffer , CAIRO_FORMAT_ARGB32 , window - > width , window - > height , stride ) ;
}
cairo_surface_write_to_png ( srf , " /tmp/screenshot.png " ) ;
cairo_surface_destroy ( srf ) ;
}
2012-10-22 06:52:53 +04:00
void * redraw_thread ( void * derp ) {
while ( 1 ) {
spin_lock ( & am_drawing ) ;
2012-12-08 12:25:16 +04:00
switch ( management_mode ) {
case MODE_SCALE :
redraw_scale_mode ( ) ;
break ;
2013-06-19 10:43:50 +04:00
case MODE_WINDOW_PICKER :
redraw_windows ( ) ;
draw_window_picker ( ) ;
break ;
2012-12-08 12:25:16 +04:00
default :
redraw_windows ( ) ;
}
2012-10-22 06:52:53 +04:00
/* Other stuff */
redraw_cursor ( ) ;
2013-07-23 09:42:24 +04:00
if ( take_screenshot_now ) {
take_screenshot ( take_screenshot_now ) ;
take_screenshot_now = 0 ;
}
2012-10-22 06:52:53 +04:00
spin_unlock ( & am_drawing ) ;
2013-05-30 08:31:59 +04:00
tick_count + = 10 ;
node_t * win ;
while ( windows_to_clean - > head ) {
win = list_pop ( windows_to_clean ) ;
server_window_t * w = ( server_window_t * ) win - > value ;
actually_destroy_window ( w ) ;
}
2012-10-22 06:52:53 +04:00
flip ( ctx ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
flip ( select_ctx ) ;
2012-10-22 06:52:53 +04:00
syscall_yield ( ) ;
}
}
int main ( int argc , char * * argv ) {
/* Initialize graphics setup */
ctx = init_graphics_fullscreen_double_buffer ( ) ;
EXPERIMENTAL: Rotating windows.
* Dumb bounding box top_at logic replaced with select buffer
* Select buffer rendered through cairo with AA disabled
Using rectangles for window shapes - this should easily
be expandable to 1bpp bitmaps. Currently, the select buffer
is very inefficient, using twice the space it needs (plus,
it's double buffered, so in reality, 4x the space needed),
however, it's also very accurate and fast, and I like that.
* Window rotation is controlled through Ctrl+Shift+{z,x,c} where
z = rotate 1 degree left
x = rotate 1 degree right
c = reset rotation
* Input is remapped based on window rotation, so you *can* use the
draw app, and it is totally epic.
2013-04-02 12:26:32 +04:00
/* Initialize the select buffer */
select_ctx = malloc ( sizeof ( gfx_context_t ) ) ;
select_ctx - > buffer = malloc ( sizeof ( uint32_t ) * ctx - > width * ctx - > height ) ;
select_ctx - > backbuffer = malloc ( sizeof ( uint32_t ) * ctx - > width * ctx - > height ) ;
select_ctx - > width = ctx - > width ;
select_ctx - > height = ctx - > height ;
select_ctx - > size = ctx - > size ;
select_ctx - > depth = ctx - > depth ;
2012-10-22 06:52:53 +04:00
/* Initialize the client request system */
init_request_system ( ) ;
/* Initialize process list */
init_process_list ( ) ;
/* Initialize signal handlers */
init_signal_handlers ( ) ;
/* Load sprites */
2012-11-24 12:18:14 +04:00
init_sprite_png ( 0 , " /usr/share/logo_login.png " ) ;
2012-10-22 06:52:53 +04:00
display ( ) ;
2012-11-22 11:29:27 +04:00
/* Precache shared memory fonts */
load_fonts ( ) ;
2012-10-22 06:52:53 +04:00
/* load the mouse cursor */
2012-11-22 11:29:27 +04:00
init_sprite ( SPRITE_MOUSE , " /usr/share/arrow.bmp " , " /usr/share/arrow_alpha.bmp " ) ;
2012-10-22 06:52:53 +04:00
2013-05-30 08:31:59 +04:00
windows_to_clean = list_create ( ) ;
2012-10-22 06:52:53 +04:00
/* Grab the mouse */
2012-12-10 11:06:42 +04:00
pthread_t mouse_thread ;
2014-04-06 04:06:28 +04:00
pthread_create ( & mouse_thread , NULL , process_requests , NULL ) ;
2012-12-10 11:06:42 +04:00
pthread_t keyboard_thread ;
pthread_create ( & keyboard_thread , NULL , keyboard_input , NULL ) ;
2012-10-22 06:52:53 +04:00
pthread_t redraw_everything_thread ;
pthread_create ( & redraw_everything_thread , NULL , redraw_thread , NULL ) ;
setenv ( " DISPLAY " , WINS_SERVER_IDENTIFIER , 1 ) ;
if ( ! fork ( ) ) {
2014-03-16 07:05:07 +04:00
char * foo = " /dev/null " ;
syscall_system_function ( 5 , ( char * * ) foo ) ;
2013-06-28 11:33:03 +04:00
if ( argc < 2 ) {
char * args [ ] = { " /bin/glogin " , NULL } ;
execvp ( args [ 0 ] , args ) ;
} else {
execvp ( argv [ 1 ] , & argv [ 1 ] ) ;
}
2012-10-22 06:52:53 +04:00
}
/* Sit in a run loop */
while ( 1 ) {
process_request ( ) ;
process_window_command ( 0 ) ;
syscall_yield ( ) ;
}
// XXX: Better have SIGINT/SIGSTOP handlers
return 0 ;
}