From 85308715ea3eb40d3af59a81527d049fe560f977 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 7 Mar 2010 19:00:34 +0100 Subject: [PATCH] Turn nested functions into real functions or macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables compilation with llvm-clang and thus closes ticket #101. While it makes the code more ugly, I don’t see a beautiful solution which would enable us to stay with the more elegant solution of nested functions and still allow compilation with any other compiler than gcc. --- common.mk | 4 +- include/floating.h | 13 +++- src/commands.c | 19 ++--- src/floating.c | 177 +++++++++++++++++++++++++-------------------- src/resize.c | 70 +++++++++++------- 5 files changed, 165 insertions(+), 118 deletions(-) diff --git a/common.mk b/common.mk index 3b88b6fe4..ab9c050a8 100644 --- a/common.mk +++ b/common.mk @@ -7,7 +7,9 @@ VERSION:=$(shell git describe --tags --abbrev=0) CFLAGS += -std=c99 CFLAGS += -pipe CFLAGS += -Wall -CFLAGS += -Wunused +# unused-function, unused-label, unused-variable are turned on by -Wall +# We don’t want unused-parameter because of the use of many callbacks +CFLAGS += -Wunused-value CFLAGS += -Iinclude CFLAGS += -I/usr/local/include CFLAGS += -DI3_VERSION=\"${GIT_VERSION}\" diff --git a/include/floating.h b/include/floating.h index 5cf3deddc..03da9e088 100644 --- a/include/floating.h +++ b/include/floating.h @@ -3,7 +3,7 @@ * * i3 - an improved dynamic tiling window manager * - * © 2009 Michael Stapelberg and contributors + * © 2009-2010 Michael Stapelberg and contributors * * See file LICENSE for license information. * @@ -12,7 +12,13 @@ #define _FLOATING_H /** Callback for dragging */ -typedef void(*callback_t)(Rect*, uint32_t, uint32_t); +typedef void(*callback_t)(xcb_connection_t*, Client*, Rect*, uint32_t, uint32_t, void*); + +/** Macro to create a callback function for dragging */ +#define DRAGGING_CB(name) \ + static void name(xcb_connection_t *conn, Client *client, \ + Rect *old_rect, uint32_t new_x, uint32_t new_y, \ + void *extra) /** On which border was the dragging initiated? */ typedef enum { BORDER_LEFT, BORDER_RIGHT, BORDER_TOP, BORDER_BOTTOM} border_t; @@ -97,6 +103,7 @@ void floating_toggle_hide(xcb_connection_t *conn, Workspace *workspace); * */ void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event, - xcb_window_t confine_to, border_t border, callback_t callback); + xcb_window_t confine_to, border_t border, callback_t callback, + void *extra); #endif diff --git a/src/commands.c b/src/commands.c index a2d9ea4ef..184394b40 100644 --- a/src/commands.c +++ b/src/commands.c @@ -89,12 +89,13 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t Workspace *t_ws = c_ws; /* Makes sure new_col and new_row are within bounds of the new workspace */ - void check_colrow_boundaries() { - if (new_col >= t_ws->cols) - new_col = (t_ws->cols - 1); - if (new_row >= t_ws->rows) - new_row = (t_ws->rows - 1); - } +#define CHECK_COLROW_BOUNDARIES \ + do { \ + if (new_col >= t_ws->cols) \ + new_col = (t_ws->cols - 1); \ + if (new_row >= t_ws->rows) \ + new_row = (t_ws->rows - 1); \ + } while (0) /* There always is a container. If not, current_col or current_row is wrong */ assert(container != NULL); @@ -174,7 +175,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t new_row = (direction == D_UP ? (t_ws->rows - 1) : 0); } - check_colrow_boundaries(); + CHECK_COLROW_BOUNDARIES; DLOG("new_col = %d, new_row = %d\n", new_col, new_row); if (t_ws->table[new_col][new_row]->currently_focused == NULL) { @@ -216,7 +217,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t new_col = (direction == D_LEFT ? (t_ws->cols - 1) : 0); } - check_colrow_boundaries(); + CHECK_COLROW_BOUNDARIES; DLOG("new_col = %d, new_row = %d\n", new_col, new_row); if (t_ws->table[new_col][new_row]->currently_focused == NULL) { @@ -235,7 +236,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t return; } - check_colrow_boundaries(); + CHECK_COLROW_BOUNDARIES; if (t_ws->table[new_col][new_row]->currently_focused != NULL) set_focus(conn, t_ws->table[new_col][new_row]->currently_focused, true); diff --git a/src/floating.c b/src/floating.c index 02397bfc4..e5e802358 100644 --- a/src/floating.c +++ b/src/floating.c @@ -3,7 +3,7 @@ * * i3 - an improved dynamic tiling window manager * - * © 2009 Michael Stapelberg and contributors + * © 2009-2010 Michael Stapelberg and contributors * * See file LICENSE for license information. * @@ -163,64 +163,79 @@ void floating_assign_to_workspace(Client *client, Workspace *new_workspace) { } /* - * Called whenever the user clicks on a border (not the titlebar!) of a floating window. - * Determines on which border the user clicked and launches the drag_pointer function - * with the resize_callback. + * This is an ugly data structure which we need because there is no standard + * way of having nested functions (only available as a gcc extension at the + * moment, clang doesn’t support it) or blocks (only available as a clang + * extension and only on Mac OS X systems at the moment). * */ -int floating_border_click(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event) { - DLOG("floating border click\n"); - +struct callback_params { border_t border; + xcb_button_press_event_t *event; +}; + +DRAGGING_CB(resize_callback) { + struct callback_params *params = extra; + xcb_button_press_event_t *event = params->event; + switch (params->border) { + case BORDER_RIGHT: { + int new_width = old_rect->width + (new_x - event->root_x); + if ((new_width < 0) || + (new_width < client_min_width(client) && client->rect.width >= new_width)) + return; + client->rect.width = new_width; + break; + } - void resize_callback(Rect *old_rect, uint32_t new_x, uint32_t new_y) { - switch (border) { - case BORDER_RIGHT: { - int new_width = old_rect->width + (new_x - event->root_x); - if ((new_width < 0) || - (new_width < client_min_width(client) && client->rect.width >= new_width)) - return; - client->rect.width = new_width; - break; - } - - case BORDER_BOTTOM: { - int new_height = old_rect->height + (new_y - event->root_y); - if ((new_height < 0) || - (new_height < client_min_height(client) && client->rect.height >= new_height)) - return; - client->rect.height = old_rect->height + (new_y - event->root_y); - break; - } - - case BORDER_TOP: { - int new_height = old_rect->height + (event->root_y - new_y); - if ((new_height < 0) || - (new_height < client_min_height(client) && client->rect.height >= new_height)) - return; + case BORDER_BOTTOM: { + int new_height = old_rect->height + (new_y - event->root_y); + if ((new_height < 0) || + (new_height < client_min_height(client) && client->rect.height >= new_height)) + return; + client->rect.height = old_rect->height + (new_y - event->root_y); + break; + } - client->rect.y = old_rect->y + (new_y - event->root_y); - client->rect.height = new_height; - break; - } + case BORDER_TOP: { + int new_height = old_rect->height + (event->root_y - new_y); + if ((new_height < 0) || + (new_height < client_min_height(client) && client->rect.height >= new_height)) + return; - case BORDER_LEFT: { - int new_width = old_rect->width + (event->root_x - new_x); - if ((new_width < 0) || - (new_width < client_min_width(client) && client->rect.width >= new_width)) - return; - client->rect.x = old_rect->x + (new_x - event->root_x); - client->rect.width = new_width; - break; - } + client->rect.y = old_rect->y + (new_y - event->root_y); + client->rect.height = new_height; + break; } - /* Push the new position/size to X11 */ - reposition_client(conn, client); - resize_client(conn, client); - xcb_flush(conn); + case BORDER_LEFT: { + int new_width = old_rect->width + (event->root_x - new_x); + if ((new_width < 0) || + (new_width < client_min_width(client) && client->rect.width >= new_width)) + return; + client->rect.x = old_rect->x + (new_x - event->root_x); + client->rect.width = new_width; + break; + } } + /* Push the new position/size to X11 */ + reposition_client(conn, client); + resize_client(conn, client); + xcb_flush(conn); +} + + +/* + * Called whenever the user clicks on a border (not the titlebar!) of a floating window. + * Determines on which border the user clicked and launches the drag_pointer function + * with the resize_callback. + * + */ +int floating_border_click(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event) { + DLOG("floating border click\n"); + + border_t border; + if (event->event_y < 2) border = BORDER_TOP; else if (event->event_y >= (client->rect.height - 2)) @@ -236,11 +251,25 @@ int floating_border_click(xcb_connection_t *conn, Client *client, xcb_button_pre DLOG("border = %d\n", border); - drag_pointer(conn, client, event, XCB_NONE, border, resize_callback); + struct callback_params params = { border, event }; + + drag_pointer(conn, client, event, XCB_NONE, border, resize_callback, ¶ms); return 1; } +DRAGGING_CB(drag_window_callback) { + struct xcb_button_press_event_t *event = extra; + + /* Reposition the client correctly while moving */ + client->rect.x = old_rect->x + (new_x - event->root_x); + client->rect.y = old_rect->y + (new_y - event->root_y); + reposition_client(conn, client); + /* Because reposition_client does not send a faked configure event (only resize does), + * we need to initiate that on our own */ + fake_absolute_configure_notify(conn, client); + /* fake_absolute_configure_notify flushes */ +} /* * Called when the user clicked on the titlebar of a floating window. @@ -250,18 +279,23 @@ int floating_border_click(xcb_connection_t *conn, Client *client, xcb_button_pre void floating_drag_window(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event) { DLOG("floating_drag_window\n"); - void drag_window_callback(Rect *old_rect, uint32_t new_x, uint32_t new_y) { - /* Reposition the client correctly while moving */ - client->rect.x = old_rect->x + (new_x - event->root_x); - client->rect.y = old_rect->y + (new_y - event->root_y); - reposition_client(conn, client); - /* Because reposition_client does not send a faked configure event (only resize does), - * we need to initiate that on our own */ - fake_absolute_configure_notify(conn, client); - /* fake_absolute_configure_notify flushes */ - } + drag_pointer(conn, client, event, XCB_NONE, BORDER_TOP /* irrelevant */, drag_window_callback, event); +} + +DRAGGING_CB(resize_window_callback) { + xcb_button_press_event_t *event = extra; + int32_t new_width = old_rect->width + (new_x - event->root_x); + int32_t new_height = old_rect->height + (new_y - event->root_y); + + /* Obey minimum window size and reposition the client */ + if (new_width > 0 && new_width >= client_min_width(client)) + client->rect.width = new_width; + + if (new_height > 0 && new_height >= client_min_height(client)) + client->rect.height = new_height; - drag_pointer(conn, client, event, XCB_NONE, BORDER_TOP /* irrelevant */, drag_window_callback); + /* resize_client flushes */ + resize_client(conn, client); } /* @@ -273,22 +307,7 @@ void floating_drag_window(xcb_connection_t *conn, Client *client, xcb_button_pre void floating_resize_window(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event) { DLOG("floating_resize_window\n"); - void resize_window_callback(Rect *old_rect, uint32_t new_x, uint32_t new_y) { - int32_t new_width = old_rect->width + (new_x - event->root_x); - int32_t new_height = old_rect->height + (new_y - event->root_y); - - /* Obey minimum window size and reposition the client */ - if (new_width > 0 && new_width >= client_min_width(client)) - client->rect.width = new_width; - - if (new_height > 0 && new_height >= client_min_height(client)) - client->rect.height = new_height; - - /* resize_client flushes */ - resize_client(conn, client); - } - - drag_pointer(conn, client, event, XCB_NONE, BORDER_TOP /* irrelevant */, resize_window_callback); + drag_pointer(conn, client, event, XCB_NONE, BORDER_TOP /* irrelevant */, resize_window_callback, event); } @@ -301,7 +320,7 @@ void floating_resize_window(xcb_connection_t *conn, Client *client, xcb_button_p * */ void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event, - xcb_window_t confine_to, border_t border, callback_t callback) { + xcb_window_t confine_to, border_t border, callback_t callback, void *extra) { xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root; uint32_t new_x, new_y; Rect old_rect; @@ -371,7 +390,7 @@ void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event new_x = ((xcb_motion_notify_event_t*)last_motion_notify)->root_x; new_y = ((xcb_motion_notify_event_t*)last_motion_notify)->root_y; - callback(&old_rect, new_x, new_y); + callback(conn, client, &old_rect, new_x, new_y, extra); FREE(last_motion_notify); } done: diff --git a/src/resize.c b/src/resize.c index 4dd035233..a32e57551 100644 --- a/src/resize.c +++ b/src/resize.c @@ -30,6 +30,44 @@ #include "workspace.h" #include "log.h" +/* + * This is an ugly data structure which we need because there is no standard + * way of having nested functions (only available as a gcc extension at the + * moment, clang doesn’t support it) or blocks (only available as a clang + * extension and only on Mac OS X systems at the moment). + * + */ +struct callback_params { + resize_orientation_t orientation; + Output *screen; + xcb_window_t helpwin; + uint32_t *new_position; +}; + +DRAGGING_CB(resize_callback) { + struct callback_params *params = extra; + Output *screen = params->screen; + DLOG("new x = %d, y = %d\n", new_x, new_y); + if (params->orientation == O_VERTICAL) { + /* Check if the new coordinates are within screen boundaries */ + if (new_x > (screen->rect.x + screen->rect.width - 25) || + new_x < (screen->rect.x + 25)) + return; + + *(params->new_position) = new_x; + xcb_configure_window(conn, params->helpwin, XCB_CONFIG_WINDOW_X, params->new_position); + } else { + if (new_y > (screen->rect.y + screen->rect.height - 25) || + new_y < (screen->rect.y + 25)) + return; + + *(params->new_position) = new_y; + xcb_configure_window(conn, params->helpwin, XCB_CONFIG_WINDOW_Y, params->new_position); + } + + xcb_flush(conn); +} + /* * Renders the resize window between the first/second container and resizes * the table column/row. @@ -37,8 +75,8 @@ */ int resize_graphical_handler(xcb_connection_t *conn, Workspace *ws, int first, int second, resize_orientation_t orientation, xcb_button_press_event_t *event) { - int new_position; - struct xoutput *screen = get_output_containing(event->root_x, event->root_y); + uint32_t new_position; + Output *screen = get_output_containing(event->root_x, event->root_y); if (screen == NULL) { ELOG("BUG: No screen found at this position (%d, %d)\n", event->root_x, event->root_y); return 1; @@ -49,8 +87,8 @@ int resize_graphical_handler(xcb_connection_t *conn, Workspace *ws, int first, i * screens during runtime. Instead, we just use the most right and most * bottom Xinerama screen and use their position + width/height to get * the area of pixels currently in use */ - struct xoutput *most_right = get_output_most(D_RIGHT, screen), - *most_bottom = get_output_most(D_DOWN, screen); + Output *most_right = get_output_most(D_RIGHT, screen), + *most_bottom = get_output_most(D_DOWN, screen); DLOG("event->event_x = %d, event->root_x = %d\n", event->event_x, event->root_x); @@ -100,29 +138,9 @@ int resize_graphical_handler(xcb_connection_t *conn, Workspace *ws, int first, i xcb_flush(conn); - void resize_callback(Rect *old_rect, uint32_t new_x, uint32_t new_y) { - DLOG("new x = %d, y = %d\n", new_x, new_y); - if (orientation == O_VERTICAL) { - /* Check if the new coordinates are within screen boundaries */ - if (new_x > (screen->rect.x + screen->rect.width - 25) || - new_x < (screen->rect.x + 25)) - return; - - values[0] = new_position = new_x; - xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_X, values); - } else { - if (new_y > (screen->rect.y + screen->rect.height - 25) || - new_y < (screen->rect.y + 25)) - return; - - values[0] = new_position = new_y; - xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_Y, values); - } - - xcb_flush(conn); - } + struct callback_params params = { orientation, screen, helpwin, &new_position }; - drag_pointer(conn, NULL, event, grabwin, BORDER_TOP, resize_callback); + drag_pointer(conn, NULL, event, grabwin, BORDER_TOP, resize_callback, ¶ms); xcb_destroy_window(conn, helpwin); xcb_destroy_window(conn, grabwin);