00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <stdlib.h>
00015 #include <assert.h>
00016
00017 #include <xcb/xcb.h>
00018 #include <xcb/xcb_event.h>
00019
00020 #include "i3.h"
00021 #include "data.h"
00022 #include "resize.h"
00023 #include "util.h"
00024 #include "xcb.h"
00025 #include "debug.h"
00026 #include "layout.h"
00027 #include "randr.h"
00028 #include "config.h"
00029 #include "floating.h"
00030 #include "workspace.h"
00031 #include "log.h"
00032
00033
00034
00035
00036
00037
00038
00039
00040 struct callback_params {
00041 resize_orientation_t orientation;
00042 Output *screen;
00043 xcb_window_t helpwin;
00044 uint32_t *new_position;
00045 };
00046
00047 DRAGGING_CB(resize_callback) {
00048 struct callback_params *params = extra;
00049 Output *screen = params->screen;
00050 DLOG("new x = %d, y = %d\n", new_x, new_y);
00051 if (params->orientation == O_VERTICAL) {
00052
00053 if (new_x > (screen->rect.x + screen->rect.width - 25) ||
00054 new_x < (screen->rect.x + 25))
00055 return;
00056
00057 *(params->new_position) = new_x;
00058 xcb_configure_window(conn, params->helpwin, XCB_CONFIG_WINDOW_X, params->new_position);
00059 } else {
00060 if (new_y > (screen->rect.y + screen->rect.height - 25) ||
00061 new_y < (screen->rect.y + 25))
00062 return;
00063
00064 *(params->new_position) = new_y;
00065 xcb_configure_window(conn, params->helpwin, XCB_CONFIG_WINDOW_Y, params->new_position);
00066 }
00067
00068 xcb_flush(conn);
00069 }
00070
00071
00072
00073
00074
00075
00076 int resize_graphical_handler(xcb_connection_t *conn, Workspace *ws, int first, int second,
00077 resize_orientation_t orientation, xcb_button_press_event_t *event) {
00078 uint32_t new_position;
00079 Output *screen = get_output_containing(event->root_x, event->root_y);
00080 if (screen == NULL) {
00081 ELOG("BUG: No screen found at this position (%d, %d)\n", event->root_x, event->root_y);
00082 return 1;
00083 }
00084
00085
00086
00087
00088
00089
00090 Output *most_right = get_output_most(D_RIGHT, screen),
00091 *most_bottom = get_output_most(D_DOWN, screen);
00092
00093 DLOG("event->event_x = %d, event->root_x = %d\n", event->event_x, event->root_x);
00094
00095 DLOG("Screen dimensions: (%d, %d) %d x %d\n", screen->rect.x, screen->rect.y, screen->rect.width, screen->rect.height);
00096
00097 uint32_t mask = 0;
00098 uint32_t values[2];
00099
00100 mask = XCB_CW_OVERRIDE_REDIRECT;
00101 values[0] = 1;
00102
00103
00104
00105 Rect grabrect = {0,
00106 0,
00107 most_right->rect.x + most_right->rect.width,
00108 most_bottom->rect.x + most_bottom->rect.height};
00109 xcb_window_t grabwin = create_window(conn, grabrect, XCB_WINDOW_CLASS_INPUT_ONLY, -1, true, mask, values);
00110
00111 Rect helprect;
00112 if (orientation == O_VERTICAL) {
00113 helprect.x = event->root_x;
00114 helprect.y = screen->rect.y;
00115 helprect.width = 2;
00116 helprect.height = screen->rect.height;
00117 new_position = event->root_x;
00118 } else {
00119 helprect.x = screen->rect.x;
00120 helprect.y = event->root_y;
00121 helprect.width = screen->rect.width;
00122 helprect.height = 2;
00123 new_position = event->root_y;
00124 }
00125
00126 mask = XCB_CW_BACK_PIXEL;
00127 values[0] = config.client.focused.border;
00128
00129 mask |= XCB_CW_OVERRIDE_REDIRECT;
00130 values[1] = 1;
00131
00132 xcb_window_t helpwin = create_window(conn, helprect, XCB_WINDOW_CLASS_INPUT_OUTPUT,
00133 (orientation == O_VERTICAL ?
00134 XCB_CURSOR_SB_H_DOUBLE_ARROW :
00135 XCB_CURSOR_SB_V_DOUBLE_ARROW), true, mask, values);
00136
00137 xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, helpwin);
00138
00139 xcb_flush(conn);
00140
00141 struct callback_params params = { orientation, screen, helpwin, &new_position };
00142
00143 drag_pointer(conn, NULL, event, grabwin, BORDER_TOP, resize_callback, ¶ms);
00144
00145 xcb_destroy_window(conn, helpwin);
00146 xcb_destroy_window(conn, grabwin);
00147 xcb_flush(conn);
00148
00149 int pixels;
00150 if (orientation == O_VERTICAL)
00151 pixels = (new_position - event->root_x);
00152 else pixels = (new_position - event->root_y);
00153 resize_container(conn, ws, first, second, orientation, pixels);
00154
00155 return 1;
00156 }
00157
00158
00159
00160
00161
00162
00163
00164 void resize_container(xcb_connection_t *conn, Workspace *ws, int first, int second,
00165 resize_orientation_t orientation, int pixels) {
00166
00167
00168 if (orientation == O_VERTICAL) {
00169 int default_width = ws->rect.width / ws->cols;
00170 int old_unoccupied_x = get_unoccupied_x(ws);
00171
00172
00173
00174 int new_unoccupied_x = old_unoccupied_x;
00175
00176 if (old_unoccupied_x == 0)
00177 old_unoccupied_x = ws->rect.width;
00178
00179 if (ws->width_factor[first] == 0)
00180 new_unoccupied_x += default_width;
00181
00182 if (ws->width_factor[second] == 0)
00183 new_unoccupied_x += default_width;
00184
00185 DLOG("\n\n\n");
00186 DLOG("old = %d, new = %d\n", old_unoccupied_x, new_unoccupied_x);
00187
00188 int cols_without_wf = 0;
00189 int old_width, old_second_width;
00190 for (int col = 0; col < ws->cols; col++)
00191 if (ws->width_factor[col] == 0)
00192 cols_without_wf++;
00193
00194 DLOG("old_unoccupied_x = %d\n", old_unoccupied_x);
00195
00196 DLOG("Updating first (before = %f)\n", ws->width_factor[first]);
00197
00198 if (ws->width_factor[first] == 0)
00199 old_width = (old_unoccupied_x / max(cols_without_wf, 1));
00200 else old_width = ws->width_factor[first] * old_unoccupied_x;
00201
00202 DLOG("second (before = %f)\n", ws->width_factor[second]);
00203 if (ws->width_factor[second] == 0)
00204 old_second_width = (old_unoccupied_x / max(cols_without_wf, 1));
00205 else old_second_width = ws->width_factor[second] * old_unoccupied_x;
00206
00207 DLOG("middle = %f\n", ws->width_factor[first]);
00208
00209
00210
00211 if (new_unoccupied_x != old_unoccupied_x)
00212 for (int col = 0; col < ws->cols; col++) {
00213 if (ws->width_factor[col] == 0)
00214 continue;
00215
00216 DLOG("Updating other column (%d) (current width_factor = %f)\n", col, ws->width_factor[col]);
00217 ws->width_factor[col] = (ws->width_factor[col] * old_unoccupied_x) / new_unoccupied_x;
00218 DLOG("to %f\n", ws->width_factor[col]);
00219 }
00220
00221 DLOG("Updating first (before = %f)\n", ws->width_factor[first]);
00222
00223 if (ws->width_factor[first] == 0)
00224 ws->width_factor[first] = ((float)ws->rect.width / ws->cols) / new_unoccupied_x;
00225
00226 DLOG("first->width = %d, pixels = %d\n", old_width, pixels);
00227 ws->width_factor[first] *= (float)(old_width + pixels) / old_width;
00228 DLOG("-> %f\n", ws->width_factor[first]);
00229
00230
00231 DLOG("Updating second (before = %f)\n", ws->width_factor[second]);
00232 if (ws->width_factor[second] == 0)
00233 ws->width_factor[second] = ((float)ws->rect.width / ws->cols) / new_unoccupied_x;
00234
00235 DLOG("middle = %f\n", ws->width_factor[second]);
00236 DLOG("second->width = %d, pixels = %d\n", old_second_width, pixels);
00237 ws->width_factor[second] *= (float)(old_second_width - pixels) / old_second_width;
00238 DLOG("-> %f\n", ws->width_factor[second]);
00239
00240 DLOG("new unoccupied_x = %d\n", get_unoccupied_x(ws));
00241
00242 DLOG("\n\n\n");
00243 } else {
00244 int ws_height = workspace_height(ws);
00245 int default_height = ws_height / ws->rows;
00246 int old_unoccupied_y = get_unoccupied_y(ws);
00247
00248
00249
00250 int new_unoccupied_y = old_unoccupied_y;
00251
00252 if (old_unoccupied_y == 0)
00253 old_unoccupied_y = ws_height;
00254
00255 if (ws->height_factor[first] == 0)
00256 new_unoccupied_y += default_height;
00257
00258 if (ws->height_factor[second] == 0)
00259 new_unoccupied_y += default_height;
00260
00261 int cols_without_hf = 0;
00262 int old_height, old_second_height;
00263 for (int row = 0; row < ws->rows; row++)
00264 if (ws->height_factor[row] == 0)
00265 cols_without_hf++;
00266
00267 DLOG("old_unoccupied_y = %d\n", old_unoccupied_y);
00268
00269 DLOG("Updating first (before = %f)\n", ws->height_factor[first]);
00270
00271
00272 if (ws->height_factor[first] == 0)
00273 old_height = (old_unoccupied_y / max(cols_without_hf, 1));
00274 else old_height = ws->height_factor[first] * old_unoccupied_y;
00275
00276 DLOG("second (before = %f)\n", ws->height_factor[second]);
00277 if (ws->height_factor[second] == 0)
00278 old_second_height = (old_unoccupied_y / max(cols_without_hf, 1));
00279 else old_second_height = ws->height_factor[second] * old_unoccupied_y;
00280
00281 DLOG("middle = %f\n", ws->height_factor[first]);
00282
00283
00284 DLOG("\n\n\n");
00285 DLOG("old = %d, new = %d\n", old_unoccupied_y, new_unoccupied_y);
00286
00287
00288
00289 if (new_unoccupied_y != old_unoccupied_y)
00290 for (int row = 0; row < ws->rows; row++) {
00291 if (ws->height_factor[row] == 0)
00292 continue;
00293
00294 DLOG("Updating other column (%d) (current width_factor = %f)\n", row, ws->height_factor[row]);
00295 ws->height_factor[row] = (ws->height_factor[row] * old_unoccupied_y) / new_unoccupied_y;
00296 DLOG("to %f\n", ws->height_factor[row]);
00297 }
00298
00299
00300 DLOG("Updating first (before = %f)\n", ws->height_factor[first]);
00301
00302 if (ws->height_factor[first] == 0)
00303 ws->height_factor[first] = ((float)ws_height / ws->rows) / new_unoccupied_y;
00304
00305 DLOG("first->width = %d, pixels = %d\n", old_height, pixels);
00306 ws->height_factor[first] *= (float)(old_height + pixels) / old_height;
00307 DLOG("-> %f\n", ws->height_factor[first]);
00308
00309
00310 DLOG("Updating second (before = %f)\n", ws->height_factor[second]);
00311 if (ws->height_factor[second] == 0)
00312 ws->height_factor[second] = ((float)ws_height / ws->rows) / new_unoccupied_y;
00313 DLOG("middle = %f\n", ws->height_factor[second]);
00314 DLOG("second->width = %d, pixels = %d\n", old_second_height, pixels);
00315 ws->height_factor[second] *= (float)(old_second_height - pixels) / old_second_height;
00316 DLOG("-> %f\n", ws->height_factor[second]);
00317
00318 DLOG("new unoccupied_y = %d\n", get_unoccupied_y(ws));
00319
00320 DLOG("\n\n\n");
00321 }
00322
00323 render_layout(conn);
00324 }