0 /*

1 * window.c - window management routines

2 */

3

4 /*

5 * Copyright 2006-2007 Johan Veenhuizen

6 *

7 * Permission is hereby granted, free of charge, to any person obtaining a

8 * copy of this software and associated documentation files (the "Software"),

9 * to deal in the Software without restriction, including without limitation

10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,

11 * and/or sell copies of the Software, and to permit persons to whom the

12 * Software is furnished to do so, subject to the following conditions:

13 *

14 * The above copyright notice and this permission notice shall be included

15 * in all copies or substantial portions of the Software.

16 *

17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

23 * DEALINGS IN THE SOFTWARE.

24 */

25

26 #include <X11/X.h>

27 #include <assert.h>

28 #include <limits.h>

29 #include <stdio.h>

30 #include <stdlib.h>

31 #include <string.h>

32 #include <unistd.h>

33

34 #include <X11/cursorfont.h>

35 #include <X11/Xatom.h>

36 #include <X11/Xlib.h>

37 #include <X11/Xutil.h>

38

39 #include "button.h"

40 #include "global.h"

41 #include "hints.h"

42 #include "lib.h"

43 #include "menu.h"

44 #include "resizer.h"

45 #include "title.h"

46 #include "widget.h"

47 #include "window.h"

48 #include "monitor.h"

49 #include "ewmh.h"

50

51 #define NBTN 3

52

53 struct window *active = NULL;

54

55 static Atom WM_STATE;

56

57 static Window front;

58

59 static LIST_DEFINE(normallayer);

60 static LIST_DEFINE(toplayer);

61 static int needrestack = 0;

62 static int nwindows = 0;

63

64 static Cursor movecurs;

65 static Cursor normalcurs;

66

67 static void client_to_window_geom(XWindowAttributes *, XSizeHints *,

68 int *x, int *y, int *width, int *height, int decoration);

69 static void window_to_client_geom(struct window *,

70 int *x, int *y, int *width, int *height);

71 static void confevent(struct window *, XConfigureRequestEvent *);

72 static void windowevent(struct widget *, XEvent *);

73 static void setgrav(Window, int);

74 static void restack_transient_windows(struct window *);

75 static void put_window_group_below(struct window *);

76 static void selectfrommenu(void *ptr);

77 static struct window *topmost_window(void);

78 static void fitwin(struct window *);

79 static void smartpos(int, int, int *, int *, int);

80 static void make_window_visible(struct window *);

81

82 // TOCHECK

83 void *getprop(Window w, Atom prop, Atom type, int fmt, unsigned long *rcountp)

84 {

85 void *ptr = NULL;

86 unsigned long count = 32;

87 Atom rtype;

88 int rfmt;

89 unsigned long rafter;

90 for (;;) {

91 if (XGetWindowProperty(display, w, prop, 0L, count,

92 False, type, &rtype, &rfmt, rcountp,

93 &rafter, (unsigned char **)&ptr) != Success) {

94 // Error

95 return NULL;

96 } else if (rtype != type || rfmt != fmt) {

97 // Does not exist (type=None), or wrong type/format

98 return NULL;

99 } else if (rafter > 0) {

100 XFree(ptr);

101 ptr = NULL;

102 count *= 2;

103 } else {

104 return ptr;

105 }

106 }

107 }

108

109 static int ismapped(Window client)

110 {

111 XWindowAttributes attr;

112 int rval = 0;

113

114 clerr();

115 if (XGetWindowAttributes(display, client, &attr))

116 rval = attr.map_state != IsUnmapped;

117 sterr();

118

119 return rval;

120 }

121

122 void window_init(void)

123 {

124 XSetWindowAttributes attr;

125 Window *winlist;

126 Window d1, d2;

127 unsigned int i, n;

128

129 attr.override_redirect = True;

130 front = XCreateWindow(display, root, 0, 0, 1, 1, 0, 0, InputOnly,

131 CopyFromParent, CWOverrideRedirect, &attr);

132 movecurs = XCreateFontCursor(display, XC_fleur);

133 normalcurs = XCreateFontCursor(display, XC_left_ptr);

134 XDefineCursor(display, root, normalcurs);

135

136 if (XQueryTree(display, root, &d1, &d2, &winlist, &n)) {

137 for (i = 0; i < n; i++)

138 if (find_widget(winlist[i], WIDGET_ANY) == NULL

139 && ismapped(winlist[i]))

140 manage_window(winlist[i], 1);

141 if (winlist != NULL)

142 XFree(winlist);

143 }

144 }

145

146 void window_fini(void)

147 {

148 struct window *win;

149 LIST *lp;

150

151 while (!LIST_EMPTY(&normallayer)) {

152 lp = LIST_TAIL(&normallayer);

153 win = LIST_ITEM(lp, struct window, layerlink);

154 unmanage_window(win, 0);

155 }

156 while (!LIST_EMPTY(&toplayer)) {

157 lp = LIST_TAIL(&toplayer);

158 win = LIST_ITEM(lp, struct window, layerlink);

159 unmanage_window(win, 0);

160 }

161

162 XDestroyWindow(display, front);

163 }

164

165 void raise_window(struct window *win)

166 {

167 LIST_REMOVE(&win->layerlink);

168 LIST_INSERT_HEAD(win->layer, &win->layerlink);

169 needrestack = 1;

170 }

171

172 void lower_window(struct window *win)

173 {

174 LIST_REMOVE(&win->layerlink);

175 win->layer = &normallayer;

176 LIST_INSERT_TAIL(win->layer, &win->layerlink);

177 needrestack = 1;

178 repaint_window(win); /* might have changed layer */

179 }

180

181 static void lower_window_within_layer(struct window *win)

182 {

183 LIST_REMOVE(&win->layerlink);

184 LIST_INSERT_TAIL(win->layer, &win->layerlink);

185 needrestack = 1;

186 }

187

188 void put_window_above(struct window *win, struct window *ref)

189 {

190 LIST_REMOVE(&win->layerlink);

191 win->layer = ref->layer;

192 LIST_INSERT_BEFORE(&ref->layerlink, &win->layerlink);

193 needrestack = 1;

194 repaint_window(win); /* might have changed layer */

195 }

196

197 void put_window_below(struct window *win, struct window *ref)

198 {

199 LIST_REMOVE(&win->layerlink);

200 win->layer = ref->layer;

201 LIST_INSERT_AFTER(&ref->layerlink, &win->layerlink);

202 needrestack = 1;

203 repaint_window(win); /* might have changed layer */

204 }

205

206 void toggle_window_ontop(struct window *win)

207 {

208 win->layer = win->layer == &toplayer ? &normallayer : &toplayer;

209 LIST_REMOVE(&win->layerlink);

210 LIST_INSERT_HEAD(win->layer, &win->layerlink);

211 needrestack = 1;

212 restack_transient_windows(win);

213 repaint_window(win); /* changed layer */

214 }

215

216 int window_is_ontop(struct window *win)

217 {

218 return win->layer == &toplayer;

219 }

220

221 void get_window_stack(struct window ***wins_return, int *nwins_return)

222 {

223 LIST *lp;

224 int i;

225

226 *wins_return = MALLOC(nwindows * sizeof (struct window *));

227 *nwins_return = nwindows;

228 i = 0;

229 LIST_FOREACH(lp, &toplayer) {

230 assert(i < nwindows);

231 (*wins_return)[i++] = LIST_ITEM(lp, struct window, layerlink);

232 }

233 LIST_FOREACH(lp, &normallayer) {

234 assert(i < nwindows);

235 (*wins_return)[i++] = LIST_ITEM(lp, struct window, layerlink);

236 }

237 assert(i == nwindows);

238 }

239

240 void get_client_stack(Window **clients_return, int *nclients_return)

241 {

242 LIST *lp;

243 struct window *win;

244 int i;

245

246 *clients_return = MALLOC(nwindows * sizeof (Window));

247 *nclients_return = nwindows;

248 i = 0;

249 LIST_FOREACH(lp, &toplayer) {

250 assert(i < nwindows);

251 win = LIST_ITEM(lp, struct window, layerlink);

252 (*clients_return)[i++] = win->client;

253 }

254 LIST_FOREACH(lp, &normallayer) {

255 assert(i < nwindows);

256 win = LIST_ITEM(lp, struct window, layerlink);

257 (*clients_return)[i++] = win->client;

258 }

259 assert(i == nwindows);

260 }

261

262 void restack_all_windows(void)

263 {

264 Window *xwins;

265 struct window *win;

266 LIST *lp;

267 int i;

268

269 if (!needrestack)

270 return;

271

272 xwins = MALLOC((nwindows + 1) * sizeof (Window));

273 xwins[0] = front;

274 i = 1;

275 LIST_FOREACH(lp, &toplayer) {

276 assert(i < nwindows + 1);

277 win = LIST_ITEM(lp, struct window, layerlink);

278 xwins[i++] = WIDGET_XWINDOW(win);

279 }

280 LIST_FOREACH(lp, &normallayer) {

281 assert(i < nwindows + 1);

282 win = LIST_ITEM(lp, struct window, layerlink);

283 xwins[i++] = WIDGET_XWINDOW(win);

284 }

285 assert(i == nwindows + 1);

286 XRestackWindows(display, xwins, nwindows + 1);

287 FREE(xwins);

288 needrestack = 0;

289

290 hints_restack();

291 }

292

293 static struct window *topmost_window(void)

294 {

295 struct window *win;

296 LIST *lp;

297 /*

298 LIST_FOREACH(lp, &toplayer) {

299 win = LIST_ITEM(lp, struct window, layerlink);

300 if (WIDGET_MAPPED(win))

301 return win;

302 }*/

303 LIST_FOREACH(lp, &normallayer) {

304 win = LIST_ITEM(lp, struct window, layerlink);

305 if (WIDGET_MAPPED(win))

306 return win;

307 }

308 return NULL;

309 }

310

311 void map_window(struct window *win)

312 {

313 if (WIDGET_MAPPED(win))

314 return;

315

316 clerr();

317 XMapWindow(display, win->client);

318 sterr();

319

320 map_widget((struct widget *)win);

321

322 hints_map(win);

323 }

324

325 void unmap_window(struct window *win)

326 {

327 if (!WIDGET_MAPPED(win))

328 return;

329

330 unmap_widget((struct widget *)win);

331

332 if (win == active)

333 set_active_window(NULL);

334

335 clerr();

336 win->ignoreunmap++;

337 XUnmapWindow(display, win->client);

338 sterr();

339

340 hints_unmap(win);

341

342 lower_window_within_layer(win);

343

344 if (win->menuitem != NULL)

345 put_menuitem_last(win->menuitem);

346 /*

347 if (!LIST_EMPTY(&normallayer)) {

348 struct listnode* lp = LIST_TAIL(&normallayer);

349 win = LIST_ITEM(lp, struct window, layerlink);

350 set_active_window(win);

351 }*/

352 }

353

354 void user_unmap_window(struct window *win)

355 {

356 struct window **wins;

357 int i, n, wasactive;

358

359 wasactive = window_is_active(win);

360

361 unmap_window(win);

362

363 get_window_stack(&wins, &n);

364 for (i = 0; i < n; i++) {

365 if (windows_are_transient_related(wins[i], win)

366 && WIDGET_MAPPED(wins[i]))

367 unmap_window(wins[i]);

368 }

369 FREE(wins);

370

371 if (wasactive)

372 set_active_window(topmost_window());

373 }

374

375 static int getwmstate(Window xwindow, long *statp)

376 {

377 unsigned long nitems, bytes_after;

378 unsigned char *prop;

379 Atom actual_type;

380 int actual_format;

381 int rval = -1;

382

383 if (XGetWindowProperty(display, xwindow,

384 WM_STATE, 0L, 2L, False, WM_STATE, &actual_type, &actual_format,

385 &nitems, &bytes_after, &prop) == Success) {

386 if (nitems > 0) {

387 *statp = ((unsigned long *)prop)[0];

388 rval = 0;

389 }

390 XFree(prop);

391 }

392

393 return rval;

394 }

395

396 static void client_to_window_geom(XWindowAttributes *attr, XSizeHints *sz,

397 int *x, int *y, int *width, int *height, int decoration)

398 {

399

400 int _border_width = border_width;

401 int _button_size = button_size;

402 if (!decoration) {

403 _border_width = 0;

404 _button_size = 0;

405 }

406

407 int north, south, east, west, stat, center;

408

409 north = south = east = west = stat = center = 0;

410

411 if (sz->flags & PWinGravity) {

412 switch (sz->win_gravity) {

413 case SouthGravity:

414 south = 1;

415 break;

416 case SouthWestGravity:

417 south = 1;

418 west = 1;

419 break;

420 case SouthEastGravity:

421 south = 1;

422 east = 1;

423 break;

424 break;

425 case NorthGravity:

426 north = 1;

427 break;

428 case NorthWestGravity:

429 north = 1;

430 west = 1;

431 break;

432 case NorthEastGravity:

433 north = 1;

434 east = 1;

435 break;

436 case CenterGravity:

437 center = 1;

438 break;

439 case StaticGravity:

440 stat = 1;

441 break;

442 default:

443 north = 1;

444 west = 1;

445 break;

446 }

447 } else {

448 north = 1;

449 west = 1;

450 }

451

452 if (north)

453 *y = attr->y;

454 else if (south)

455 *y = attr->y + 2 * attr->border_width

456 - 2 * _border_width - _button_size;

457 else if (center)

458 *y = attr->y + attr->border_width

459 + attr->height / 2

460 - (attr->height + 2 * _border_width + _button_size) / 2;

461 else if (stat)

462 *y = attr->y + attr->border_width - _border_width - _button_size;

463 else

464 *y = attr->y;

465

466 if (west)

467 *x = attr->x;

468 else if (east)

469 *x = attr->x + 2 * attr->border_width

470 - 2 * _border_width;

471 else if (center)

472 *x = attr->x + attr->border_width

473 + attr->width / 2

474 - (attr->width + 2 * _border_width) / 2;

475 else if (stat)

476 *x = attr->x + attr->border_width - _border_width;

477 else

478 *x = attr->x;

479

480 *width = attr->width + 2 * _border_width;

481 *height = attr->height + 2 * _border_width + _button_size;

482 }

483

484 static void window_to_client_geom(struct window *win,

485 int *x, int *y, int *width, int *height)

486 {

487

488 int _border_width = border_width;

489 int _button_size = button_size;

490 if (!win->decoration) {

491 _border_width = 0;

492 _button_size = 0;

493 }

494

495 int north, south, east, west, stat, center;

496

497 north = south = east = west = stat = center = 0;

498

499 if (win->wmnormalhints->flags & PWinGravity) {

500 switch (win->wmnormalhints->win_gravity) {

501 case SouthGravity:

502 south = 1;

503 break;

504 case SouthWestGravity:

505 south = 1;

506 west = 1;

507 break;

508 case SouthEastGravity:

509 south = 1;

510 east = 1;

511 break;

512 break;

513 case NorthGravity:

514 north = 1;

515 break;

516 case NorthWestGravity:

517 north = 1;

518 west = 1;

519 break;

520 case NorthEastGravity:

521 north = 1;

522 east = 1;

523 break;

524 case CenterGravity:

525 center = 1;

526 break;

527 case StaticGravity:

528 stat = 1;

529 break;

530 default:

531 north = 1;

532 west = 1;

533 break;

534 }

535 } else {

536 north = 1;

537 west = 1;

538 }

539

540 if (north)

541 *y = WIDGET_Y(win);

542 else if (south)

543 *y = WIDGET_Y(win) - 2*win->cborder

544 + 2*_border_width + _button_size;

545 else if (center)

546 *y = WIDGET_Y(win) + WIDGET_HEIGHT(win) / 2

547 - (WIDGET_HEIGHT(win) - 2*_border_width - _button_size) / 2

548 - win->cborder;

549 else if (stat)

550 *y = WIDGET_Y(win) - win->cborder + _border_width + _button_size;

551 else

552 *y = WIDGET_Y(win);

553

554 if (west)

555 *x = WIDGET_X(win);

556 else if (east)

557 *x = WIDGET_X(win) - 2*win->cborder + 2*_border_width;

558 else if (center)

559 *x = WIDGET_X(win) + WIDGET_WIDTH(win) / 2

560 - (WIDGET_WIDTH(win) - 2*_border_width) / 2 - win->cborder;

561 else if (stat)

562 *x = WIDGET_X(win) - win->cborder + _border_width;

563 else

564 *x = WIDGET_X(win);

565

566 *width = WIDGET_WIDTH(win) - 2*_border_width;

567 *height = WIDGET_HEIGHT(win) - 2*_border_width - _button_size;

568 }

569

570 void delete_window(struct window *win)

571 {

572 if (!hints_delete(win)) {

573 clerr();

574 XKillClient(display, win->client);

575 sterr();

576 }

577 }

578

579 /*

580 * See ICCCM 4.1.5 and EWMH "Implementation notes".

581 */

582 static void confevent(struct window *win, XConfigureRequestEvent *ep)

583 {

584 XWindowAttributes attr;

585 int x;

586 int y;

587 int width;

588 int height;

589

590 if (ep->value_mask & CWBorderWidth)

591 win->cborder = ep->border_width;

592

593 window_to_client_geom(win, &attr.x, &attr.y,

594 &attr.width, &attr.height);

595 attr.border_width = win->cborder;

596

597 if (ep->value_mask & CWX)

598 attr.x = ep->x;

599 if (ep->value_mask & CWY)

600 attr.y = ep->y;

601 if (ep->value_mask & CWWidth)

602 attr.width = ep->width;

603 if (ep->value_mask & CWHeight)

604 attr.height = ep->height;

605

606 /*

607 * FIXME: handle stacking order

608 */

609 // cause vbox resize bug

610 client_to_window_geom(&attr, win->wmnormalhints,

611 &x, &y, &width, &height, win->decoration);

612 moveresize_window(win, x, y, width, height); // resize to 0

613 }

614

615 static void prepare_repaint(struct widget *widget)

616 {

617 struct window *win = (struct window *)widget;

618

619 if (window_family_is_active(win))

620 XSetWindowBackground(display, WIDGET_XWINDOW(win),

621 color_title_active_bg.normal);

622 else

623 XSetWindowBackground(display, WIDGET_XWINDOW(win),

624 color_title_inactive_bg.normal);

625 }

626

627 static void repaint(struct widget *widget)

628 {

629 struct window *win = (struct window *)widget;

630 if(!win->decoration) {

631 return;

632 }

633 GC gc = win->title->gc;

634 struct color *color =

635 window_family_is_active(win) ?

636 &color_title_active_bg : &color_title_inactive_bg;

637 int w = WIDGET_WIDTH(win);

638 int h = WIDGET_HEIGHT(win);

639 int bw = border_width;

640

641 drawraised(WIDGET_XWINDOW(win), gc, color,

642 0, 0, WIDGET_WIDTH(win), WIDGET_HEIGHT(win));

643 drawlowered(WIDGET_XWINDOW(win), gc, color,

644 border_width - 2, border_width - 2,

645 WIDGET_WIDTH(win) - 2 * border_width + 3,

646 WIDGET_HEIGHT(win) - 2 * border_width + 3);

647

648 XSetForeground(display, gc, color->normal);

649

650 XFillRectangle(display, WIDGET_XWINDOW(win), gc,

651 1, 1, w - 3, bw - 3);

652 XFillRectangle(display, WIDGET_XWINDOW(win), gc,

653 1, h - bw + 1, w - 3, bw - 3);

654 XFillRectangle(display, WIDGET_XWINDOW(win), gc,

655 1, bw - 2, bw - 3, h - 2 * bw + 3);

656 XFillRectangle(display, WIDGET_XWINDOW(win), gc,

657 w - bw + 1, bw - 2, bw - 3, h - 2 * bw + 3);

658

659 /* Also paint behind client window in case it is shaped. */

660 XFillRectangle(display, WIDGET_XWINDOW(win), gc,

661 bw, bw + button_size, w - 2 * bw, h - 2 * bw - button_size);

662 }

663

664 static void windowevent(struct widget *widget, XEvent *ep)

665 {

666 struct window *win = (struct window *)widget;

667 long stap;

668 //printf("event %!d(MISSING)\n", ep->type);

669 switch (ep->type) {

670 case ButtonPress:

671 //printf("!step 1\n");

672 if (ep->xbutton.button < 4) {

673 //printf("!step 1.5\n");

674 set_active_window_(win, ep->xbutton.button);

675 } else {

676 //printf("!step 2\n");

677 //struct window *ptr = active;

678 //set_active_window(win);

679 //beginfastmove(WIDGET_XWINDOW(win));

680 set_active_window_(win, ep->xbutton.button);

681 break;

682 }

683 //printf("!step 3\n");

684 if (ep->xbutton.state & Mod1Mask) {

685 win->altmove.xoff = ep->xbutton.x;

686 win->altmove.yoff = ep->xbutton.y;

687 win->altmove.moving = 1;

688 beginfastmove(WIDGET_XWINDOW(win));

689 }

690 //printf("!step 4\n");

691 break;

692 case MotionNotify:

693 if (win->altmove.moving) {

694 if (ep->xmotion.state & ControlMask)

695 move_window_family(win,

696 ep->xmotion.x_root - win->altmove.xoff,

697 ep->xmotion.y_root - win->altmove.yoff);

698 else

699 move_window(win,

700 ep->xmotion.x_root - win->altmove.xoff,

701 ep->xmotion.y_root - win->altmove.yoff);

702 }

703 break;

704 case ButtonRelease:

705 //if (ep->xbutton.button < 4) {

706 win->altmove.moving = 0;

707 endfastmove();

708 //}

709 break;

710 case MapRequest:

711 set_active_window(win);

712 break;

713 case UnmapNotify:

714 /* This can be a real or synthetic unmap event. */

715 if (ep->xunmap.window != win->client)

716 break;

717 if (win->ignoreunmap > 0)

718 win->ignoreunmap--;

719 else if (win->ignoreunmap == 0) {

720 if ((win->title&&fastmovewin_current==WIDGET_XWINDOW(win->title)) || fastmovewin_current==WIDGET_XWINDOW(win))

721 endfastmove();

722 hints_withdraw(win);

723 unmanage_window(win, 1);

724 } else

725 abort();

726 break;

727 case ConfigureRequest:

728 confevent(win, &ep->xconfigurerequest);

729 break;

730 case ClientMessage:

731 hints_clientmessage(win, &ep->xclient);

732 break;

733 case PropertyNotify:

734 hints_propertynotify(win, &ep->xproperty);

735 break;

736 case DestroyNotify:

737 if (ep->xdestroywindow.window == win->client)

738 unmanage_window(win, 1);

739 break;

740 case Expose:

741 if (ep->xexpose.count == 0)

742 repaint(widget);

743 break;

744 case GravityNotify:

745 case CreateNotify:

746 if (ep->xcreatewindow.x == monitors[0].x && ep->xcreatewindow.y == monitors[0].y

747 && ep->xcreatewindow.width == monitors[0].w && ep->xcreatewindow.height == monitors[0].h )//&&

748 // ep->xcreatewindow.override_redirect)

749 printf("createnotify\n");

750 case MapNotify:

751 case ReparentNotify:

752 case ConfigureNotify:

753 /* ignore */

754 break;

755 default:

756 debug("windowevent(): unhandled event -- %!s(MISSING) (%!d(MISSING))",

757 eventname(ep->type), ep->type);

758 break;

759 }

760 }

761

762 void low_limit_size(int *width, int *height, int decoration)

763 {

764 *width = MAX(*width, decoration*(2 * border_width) + 1);

765 *height = MAX(*height, decoration*(2 * border_width + button_size) + 1);

766 }

767

768 void window_calcsize(struct window *win, int width, int height,

769 int *rwidth, int *rheight, int *rxdim, int *rydim)

770 {

771 int decwidth = 2 * border_width;

772 int decheight = 2 * border_width + button_size;

773 if(!win->decoration) {

774 decwidth = decheight = 0;

775 }

776 int havemin = 0;

777 int minwidth = 0;

778 int minheight = 0;

779 int wmminwidth = 0;

780 int wmminheight = 0;

781

782 low_limit_size(&width, &height, win->decoration);

783 low_limit_size(&wmminwidth, &wmminheight, win->decoration);

784

785 width -= decwidth;

786 height -= decheight;

787

788 if (win->wmnormalhints->flags & PMaxSize) {

789 width = MIN(width, win->wmnormalhints->max_width);

790 height = MIN(height, win->wmnormalhints->max_height);

791 }

792

793 havemin = 0;

794 if (win->wmnormalhints->flags & PMinSize) {

795 minwidth = win->wmnormalhints->min_width;

796 minheight = win->wmnormalhints->min_height;

797 havemin = 1;

798 } else if (win->wmnormalhints->flags & PBaseSize) {

799 minwidth = win->wmnormalhints->base_width;

800 minheight = win->wmnormalhints->base_height;

801 havemin = 1;

802 }

803 if (havemin) {

804 width = MAX(width, minwidth);

805 height = MAX(height, minheight);

806 }

807

808 if (win->wmnormalhints->flags & PResizeInc) {

809 if (win->wmnormalhints->width_inc != 0) {

810 int wb;

811 if (win->wmnormalhints->flags & PBaseSize)

812 wb = win->wmnormalhints->base_width;

813 else if (win->wmnormalhints->flags & PMinSize)

814 wb = win->wmnormalhints->min_width;

815 else

816 wb = 0;

817 width -= wb;

818 width -= width %!w(MISSING)in->wmnormalhints->width_inc;

819 if (havemin)

820 width = MAX(width, minwidth - wb);

821 while (wb + width + decwidth < wmminwidth)

822 width += win->wmnormalhints->width_inc;

823 if (rxdim != NULL)

824 *rxdim = width / win->wmnormalhints->width_inc;

825 width += wb;

826 } else if (rxdim != NULL)

827 *rxdim = width;

828 if (win->wmnormalhints->height_inc != 0) {

829 int hb;

830 if (win->wmnormalhints->flags & PBaseSize)

831 hb = win->wmnormalhints->base_height;

832 else if (win->wmnormalhints->flags & PMinSize)

833 hb = win->wmnormalhints->min_height;

834 else

835 hb = 0;

836 height -= hb;

837 height -= height %!w(MISSING)in->wmnormalhints->height_inc;

838 if (havemin)

839 height = MAX(height, minheight - hb);

840 while (hb + height + decheight < wmminheight)

841 height += win->wmnormalhints->height_inc;

842 if (rydim != NULL)

843 *rydim =

844 height / win->wmnormalhints->height_inc;

845 height += hb;

846 } else if (rydim != NULL)

847 *rydim = height;

848 } else {

849 if (rxdim != NULL)

850 *rxdim = width;

851 if (rydim != NULL)

852 *rydim = height;

853 }

854

855 width += 2 * border_width;

856 height += 2 * border_width + button_size;

857

858 if (rwidth != NULL)

859 *rwidth = width;

860 if (rheight != NULL)

861 *rheight = height;

862 }

863

864 static void setgrav(Window xwin, int grav)

865 {

866 XSetWindowAttributes attr;

867

868 attr.win_gravity = grav;

869 XChangeWindowAttributes(display, xwin, CWWinGravity, &attr);

870 }

871

872 void expand_window(struct window* win) {

873 win->odim = win->widget.dim;

874 maximize_window(win, -1, -1);

875 }

876

877 int maximize_window(struct window *win, int posx, int posy)

878 {

879 if(!win->resizable) {

880 return -1;

881 }

882 if(posx == -1) {

883 posx = win->widget.dim.x;

884 }

885 if(posy == -1) {

886 posy = win->widget.dim.y;

887 }

888 int x, y, rwidth, rheight;

889 int id = 0;

890 if (!win->fullscreen&&win->maximized) {

891 set_button_image(win->expandbtn, &expand_image);

892 moveresize_window(win, win->odim.x, win->odim.y, win->odim.width, win->odim.height);

893 win->maximized = 0;

894 for(; id<monitors_len-1; id++) {

895 if(monitors[id].x<=posx&&

896 monitors[id].y<=posy&&

897 monitors[id].x+monitors[id].w>=posx&&

898 monitors[id].y+monitors[id].h>=posy) break;

899 }

900 } else {

901 set_button_image(win->expandbtn, &expanded_image);

902 win->odim = win->widget.dim;

903 for(; id<monitors_len-1; id++) {

904 if(monitors[id].x<=posx&&

905 monitors[id].y<=posy&&

906 monitors[id].x+monitors[id].w>posx&&

907 monitors[id].y+monitors[id].h>posy) break;

908 }

909 //moveresize_window(win, monitors[id].x-(win->fullscreen?border_width:0), monitors[id].y-(win->fullscreen?button_size+border_width:0), monitors[id].w+(win->fullscreen?border_width*2:0), monitors[id].h+(win->fullscreen?button_size/2+border_width*2:0)-(id==0&&!win->fullscreen?panel_height:0));

910 //printf("%!d(MISSING)\n", monitors[id].h-((id==0&&!win->fullscreen)?panel_height:0));

911 XResizeWindow(display, win->client, monitors[id].w, monitors[id].h);

912 //XResizeWindow(display, WIDGET_XWINDOW(win), monitors[id].w, monitors[id].h);

913 moveresize_window(win, monitors[id].x, monitors[id].y, monitors[id].w, monitors[id].h-((id==0&&!win->fullscreen)?panel_height:0));

914 win->maximized = 1;

915 }

916 return id;

917 }

918

919 int window_is_resizable(struct window* win) {

920 if(win&&win->wmnormalhints&&win->wmnormalhints->flags & PMinSize && win->wmnormalhints->flags & PMaxSize && win->wmnormalhints->min_width==win->wmnormalhints->max_width) return 0;

921 return 1;

922 }

923

924 struct window *manage_window(Window client, int wmstart)

925 {

926 struct window *win;

927 XWindowAttributes attr;

928 XSizeHints *sz;

929 XWMHints *wmhints;

930 long state;

931 long dummy;

932 int x, y, width, height;

933

934 clerr();

935 if (!XGetWindowAttributes(display, client, &attr)) {

936 sterr();

937 return NULL;

938 }

939 sterr();

940

941 if (attr.override_redirect)

942 return NULL;

943

944 if (find_widget(client, WIDGET_ANY) != NULL) {

945 debug("XXX: Trying to remanage a window!");

946 return NULL;

947 }

948

949 clerr();

950 if (getwmstate(client, &state) == -1 || state == WithdrawnState) {

951 wmhints = XGetWMHints(display, client);

952 if (wmhints == NULL)

953 state = NormalState;

954 else {

955 if (wmhints->flags & StateHint)

956 state = wmhints->initial_state;

957 else

958 state = NormalState;

959 XFree(wmhints);

960 }

961 }

962 sterr();

963

964 if (state == WithdrawnState) {

965 debug("skipping withdrawn window");

966 return NULL;

967 }

968

969 while ((sz = XAllocSizeHints()) == NULL)

970 sleep(1);

971 clerr();

972 XGetWMNormalHints(display, client, sz, &dummy);

973 sterr();

974 client_to_window_geom(&attr, sz, &x, &y, &width, &height, 1);

975 low_limit_size(&width, &height, 1);

976 if (!wmstart && ~sz->flags & USPosition && ~sz->flags & PPosition)

977 smartpos(width, height, &x, &y, get_monitor_cursor());

978 XFree(sz);

979

980 win = MALLOC(sizeof (struct window));

981

982 create_widget(&win->widget, WIDGET_WINDOW,

983 root, InputOutput, x, y, width, height);

984

985

986 /*

987 * Initialize struct members

988 */

989

990 win->name[0] = '\0';

991 win->decoration = 1;

992 win->fullscreen = 0;

993 win->iconname = NULL;

994 win->title = NULL;

995 win->deletebtn = NULL;

996 win->unmapbtn = NULL;

997 win->expandbtn = NULL;

998 win->rsz_northwest = NULL;

999 win->rsz_north = NULL;

1000 win->rsz_northeast = NULL;

1001 win->rsz_west = NULL;

1002 win->rsz_east = NULL;

1003 win->rsz_southwest = NULL;

1004 win->rsz_south = NULL;

1005 win->rsz_southeast = NULL;

1006 win->menuitem = NULL;

1007 win->color = &color_title_active_bg;

1008 win->client = client;

1009 win->colormap = attr.colormap;

1010 win->wmnormalhints = NULL;

1011 win->wmhints = NULL;

1012 win->wmtransientfor = None;

1013 win->cborder = attr.border_width;

1014 win->altmove.moving = 0;

1015 win->altmove.xoff = 0;

1016 win->altmove.yoff = 0;

1017 win->ignoreunmap = 0;

1018 win->maximized = 0;

1019 win->odim.x = attr.x;

1020 win->odim.y = attr.y;

1021 win->odim.width = attr.width;

1022 win->odim.height = attr.height;

1023 win->layer = &normallayer;

1024 LIST_INIT(&win->layerlink);

1025

1026 /*

1027 * Everything initialized. Time to get some work done.

1028 */

1029

1030 LIST_INSERT_HEAD(win->layer, &win->layerlink);

1031 nwindows++;

1032 needrestack = 1;

1033 save_widget_context(&win->widget, client);

1034

1035 grabbutton(display, Button1, Mod1Mask,

1036 WIDGET_XWINDOW(win), False,

1037 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,

1038 GrabModeAsync, GrabModeAsync, None, movecurs);

1039 grabbutton(display, Button1, Mod1Mask | ControlMask,

1040 WIDGET_XWINDOW(win), False,

1041 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,

1042 GrabModeAsync, GrabModeAsync, None, movecurs);

1043

1044 /*XSelectInput(display, WIDGET_XWINDOW(win),

1045 //EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);

1046 SubstructureRedirectMask|SubstructureNotifyMask

1047 |ButtonPressMask|PointerMotionMask|EnterWindowMask

1048 |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask);

1049 //ExposureMask | SubstructureRedirectMask | SubstructureNotifyMask);*/

1050 XSelectInput(display, WIDGET_XWINDOW(win),

1051 ExposureMask | SubstructureRedirectMask | SubstructureNotifyMask);

1052

1053 win->widget.event = windowevent;

1054 win->widget.prepare_repaint = prepare_repaint;

1055 win->widget.repaint = repaint;

1056

1057 win->deletebtn = create_button(win,

1058 width - border_width - button_size,

1059 border_width, button_size, button_size);

1060 setgrav(WIDGET_XWINDOW(win->deletebtn), NorthEastGravity);

1061 set_button_image(win->deletebtn, &delete_image);

1062 set_button_handler(win->deletebtn, delete_window);

1063

1064 win->expandbtn = create_button(win,

1065 width - border_width - 2 * button_size,

1066 border_width, button_size, button_size);

1067 setgrav(WIDGET_XWINDOW(win->expandbtn), NorthEastGravity);

1068 set_button_image(win->expandbtn, &expand_image);

1069 set_button_handler(win->expandbtn, expand_window);

1070

1071 win->unmapbtn = create_button(win,

1072 width - border_width - 3 * button_size,

1073 border_width, button_size, button_size);

1074 setgrav(WIDGET_XWINDOW(win->unmapbtn), NorthEastGravity);

1075 set_button_image(win->unmapbtn, &unmap_image);

1076 set_button_handler(win->unmapbtn, user_unmap_window);

1077

1078 win->title = create_title(win,

1079 border_width, border_width,

1080 width - 2 * border_width - NBTN * button_size, button_size);

1081

1082 update_window_type(win);

1083 fetch_wm_hints(win);

1084 fetch_wm_normal_hints(win);

1085 clerr();

1086 XAddToSaveSet(display, client);

1087

1088 XSetWindowBorderWidth(display, client, 0);

1089 XReparentWindow(display, client, WIDGET_XWINDOW(win),

1090 win->decoration?border_width:0, win->decoration?(border_width + button_size):0);

1091 if (win->decoration==0)

1092 XResizeWindow(display, win->client, win->widget.dim.width+border_width*2, win->widget.dim.height+button_size+border_width*2);

1093 XLowerWindow(display, client);

1094 XSelectInput(display, client, PropertyChangeMask);

1095 setgrav(client, NorthWestGravity);

1096 grabbutton(display, AnyButton, 0, client, True,

1097 ButtonPressMask, GrabModeSync, GrabModeSync, None, None);

1098 sterr();

1099

1100 win->resizable = window_is_resizable(win);

1101 if(win->decoration&&win->resizable) {

1102 win->rsz_northwest = create_resizer(win, NORTHWEST);

1103 win->rsz_north = create_resizer(win, NORTH);

1104 win->rsz_northeast = create_resizer(win, NORTHEAST);

1105 win->rsz_west = create_resizer(win, WEST);

1106 win->rsz_east = create_resizer(win, EAST);

1107 win->rsz_southwest = create_resizer(win, SOUTHWEST);

1108 win->rsz_south = create_resizer(win, SOUTH);

1109 win->rsz_southeast = create_resizer(win, SOUTHEAST);

1110 }

1111

1112 fetch_window_name(win);

1113 //printf("window name : %!s(MISSING) %!d(MISSING) %!d(MISSING)\n", win->name, win->widget.dim.x, win->widget.dim.y);

1114 if (win->widget.dim.x==0 && win->widget.dim.y==0) {

1115 smartpos(width, height, &x, &y, get_monitor_cursor());

1116 move_window(win, x, y);

1117 }

1118 fetch_icon_name(win);

1119

1120 fetch_wm_transient_for_hint(win);

1121

1122 repaint_window(win);

1123

1124 #if 1

1125 if (win->wmtransientfor != None) {

1126 struct window *w;

1127 w = (struct window *)find_widget(win->wmtransientfor,

1128 WIDGET_WINDOW);

1129 if (w != NULL) {

1130 raise_window(w);

1131 restack_transient_windows(w);

1132 }

1133 }

1134 #endif

1135

1136 hints_manage(win);

1137

1138 map_window(win);

1139

1140 if (state == IconicState)

1141 unmap_window(win);

1142 else

1143 set_active_window(win);

1144

1145 XSync(display, False);

1146

1147 debug("manage \"%!s(MISSING)\" (Window=0x%!x(MISSING))", win->name, (int)win->client);

1148

1149 clerr();

1150 if (!XGetWindowAttributes(display, client, &attr)) {

1151 sterr();

1152 debug("Oops, client window disappeared in manage_window()");

1153 unmanage_window(win, 1);

1154 return NULL;

1155 }

1156 sterr();

1157

1158 //if (!win->decoration)

1159 // resize_window(win, width, height);

1160

1161 return win;

1162 }

1163

1164 static void ranpos(int width, int height, int *rx, int *ry, int monitor)

1165 {

1166 int dx, dy;

1167

1168 dx = monitors[monitor].w - width;

1169 dy = monitors[monitor].h - height;

1170 *rx = dx > 0 ? rand() %!d(MISSING)x + monitors[monitor].x : 0;

1171 *ry = dy > 0 ? rand() %!d(MISSING)y + monitors[monitor].y : 0;

1172 }

1173

1174 static long badness(int x, int y, int width, int height,

1175 struct window **wins, int n)

1176 {

1177 long x1, x2, y1, y2;

1178 long w, h;

1179 long area;

1180 int nwin;

1181 int i;

1182

1183 nwin = 0;

1184 area = 0;

1185 for (i = 0; i < n; i++)

1186 if (WIDGET_MAPPED(wins[i])) {

1187 x1 = WIDGET_X(wins[i]);

1188 x2 = x1 + WIDGET_WIDTH(wins[i]);

1189 y1 = WIDGET_Y(wins[i]);

1190 y2 = y1 + WIDGET_HEIGHT(wins[i]);

1191 if (x + width > x1 && x < x2 &&

1192 y + height > y1 && y < y2) {

1193 w = MIN(x + width, x2) - MAX(x, x1);

1194 h = MIN(y + height, y2) - MAX(y, y1);

1195 if (LONG_MAX - area < w * h)

1196 area = LONG_MAX;

1197 else

1198 area += w * h;

1199 nwin++;

1200 }

1201 }

1202 if (nwin != 0 && LONG_MAX / nwin < area) {

1203 nwin = 1;

1204 area = LONG_MAX;

1205 }

1206 return area * nwin;

1207 }

1208

1209 // add multi monitors support

1210 static void smartpos(int width, int height, int *rx, int *ry, int monitor)

1211 {

1212 struct window **wins;

1213 int n;

1214 int x, y;

1215 long best = -1;

1216 long score;

1217 int i;

1218

1219 get_window_stack(&wins, &n);

1220 for (i = 0; best != 0 && i < 100; i++) {

1221 ranpos(width, height, &x, &y, monitor);

1222 score = badness(x, y, width, height, wins, n);

1223 if (best == -1 || score < best) {

1224 best = score;

1225 *rx = x;

1226 *ry = y;

1227 }

1228 }

1229 FREE(wins);

1230 }

1231

1232 void fetch_wm_normal_hints(struct window *win)

1233 {

1234 long dummy;

1235

1236 if (win->wmnormalhints != NULL)

1237 XFree(win->wmnormalhints);

1238 while ((win->wmnormalhints = XAllocSizeHints()) == NULL)

1239 sleep(1);

1240 clerr();

1241 XGetWMNormalHints(display, win->client, win->wmnormalhints, &dummy);

1242 if(win->wmnormalhints->min_height>2000) {

1243 win->wmnormalhints->min_height = win->wmnormalhints->min_width/3*4;

1244 }

1245 sterr();

1246 }

1247

1248 void fetch_wm_hints(struct window *win)

1249 {

1250 if (win->wmhints != NULL)

1251 XFree(win->wmhints);

1252 clerr();

1253 win->wmhints = XGetWMHints(display, win->client);

1254 sterr();

1255 }

1256

1257 char* window_getname(Window win) {

1258 Atom prop = XInternAtom(display,"_NET_WM_NAME",False), type;

1259 int form;

1260 unsigned long remain, len;

1261 unsigned char *list;

1262

1263 if (XGetWindowProperty(display,win,prop,0,1024,False,XA_STRING,

1264 &type,&form,&len,&remain,&list) != Success) {

1265 return NULL;

1266 }

1267

1268 return (char*)list;

1269 }

1270

1271 int

1272 gettextprop(Window w, Atom atom, char *text, unsigned int size)

1273 {

1274 char **list = NULL;

1275 int n;

1276 XTextProperty name;

1277

1278 if (!text || size == 0)

1279 return 0;

1280 text[0] = '\0';

1281 if (!XGetTextProperty(display, w, &name, atom) || !name.nitems)

1282 return 0;

1283 if (name.encoding == XA_STRING)

1284 strncpy(text, (char *)name.value, size - 1);

1285 else {

1286 if (XmbTextPropertyToTextList(display, &name, &list, &n) >= Success && n > 0 && *list) {

1287 strncpy(text, *list, size - 1);

1288 XFreeStringList(list);

1289 }

1290 }

1291 text[size - 1] = '\0';

1292 XFree(name.value);

1293 return 1;

1294 }

1295

1296 void updatetitle(struct window *win)

1297 {

1298 if (!gettextprop(win->client, XInternAtom(display, "_NET_WM_NAME", False), win->name, 1024))

1299 gettextprop(win->client, XA_WM_NAME, win->name, sizeof win->name);

1300 if (win->name[0] == '\0')

1301 strcpy(win->name, "broken name");

1302 }

1303

1304 void fetch_window_name(struct window *win)

1305 {

1306 //XGetWindowProperty(Display *, Window, Atom, long, long, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **)

1307 updatetitle(win);

1308 char *name;

1309 if (strlen(win->name) == 0)

1310 name = "<< Anonymous >>";

1311 else

1312 name = win->name;

1313

1314 if (win->menuitem == NULL)

1315 win->menuitem = create_menuitem(winmenu, name,

1316 selectfrommenu, win);

1317 else

1318 rename_menuitem(win->menuitem, name);

1319

1320 REPAINT(win->title);

1321 }

1322

1323 void fetch_icon_name(struct window *win)

1324 {

1325 if (win->iconname != NULL) {

1326 XFree(win->iconname);

1327 win->iconname = NULL;

1328 }

1329

1330 clerr();

1331 XGetIconName(display, win->client, &win->iconname);

1332 if (win->iconname == NULL || strlen(win->iconname) == 0) {

1333 if (win->iconname != NULL) {

1334 XFree(win->iconname);

1335 win->iconname = NULL;

1336 }

1337 XFetchName(display, win->client, &win->iconname);

1338 }

1339 sterr();

1340 }

1341

1342 static void selectfrommenu(void *ptr)

1343 {

1344 set_active_window(ptr);

1345 }

1346

1347 void fetch_wm_transient_for_hint(struct window *win)

1348 {

1349 win->wmtransientfor = None;

1350 clerr();

1351 XGetTransientForHint(display, win->client, &win->wmtransientfor);

1352 sterr();

1353

1354 fitwin(win);

1355 }

1356

1357 static void fitwin(struct window *win)

1358 {

1359 int nbtn = 0;

1360

1361 int resizable = 0;

1362 if (win->resizable &&

1363 WIDGET_WIDTH(win) >= 2 * border_width + 2 * button_size + 1) {

1364 map_widget((struct widget *)win->expandbtn);

1365 resizable = 1;

1366 } else {

1367 unmap_widget((struct widget *)win->expandbtn);

1368 move_widget(&win->unmapbtn->widget, win->odim.width - border_width - 2 * button_size + button_size/2, border_width);

1369 }

1370

1371 if (

1372 WIDGET_WIDTH(win) >= 2 * border_width + (2+resizable) * button_size + 1) {

1373 map_widget((struct widget *)win->unmapbtn);

1374 } else

1375 unmap_widget((struct widget *)win->unmapbtn);

1376

1377 if (WIDGET_WIDTH(win) >= 2 * border_width + button_size + 1)

1378 map_widget((struct widget *)win->deletebtn);

1379 else

1380 unmap_widget((struct widget *)win->deletebtn);

1381

1382 if (!win->decoration) return;

1383

1384 if (win->deletebtn && WIDGET_MAPPED(win->deletebtn))

1385 nbtn++;

1386 if (win->expandbtn && WIDGET_MAPPED(win->expandbtn))

1387 nbtn++;

1388 if (win->unmapbtn && WIDGET_MAPPED(win->unmapbtn))

1389 nbtn++;

1390

1391 resize_title(win->title, MAX(1, WIDGET_WIDTH(win) - 2 * border_width - nbtn * button_size), button_size);

1392 }

1393

1394 void moveresize_window(struct window *win, int x, int y, int width, int height)

1395 {

1396 int move;

1397 int resize;

1398

1399 low_limit_size(&width, &height, win->decoration);

1400

1401 move = x != WIDGET_X(win) || y != WIDGET_Y(win);

1402 if(win->resizable)

1403 resize = width != WIDGET_WIDTH(win) || height != WIDGET_HEIGHT(win);

1404 else

1405 resize = 0;

1406

1407 if (resize) {

1408 clerr();

1409 XResizeWindow(display, win->client,

1410 width - 2 * border_width * win->decoration,

1411 height - (2 * border_width + button_size) * win->decoration);

1412 sterr();

1413 if (win->maximized) {

1414 set_button_image(win->expandbtn, &expand_image);

1415 }

1416 }

1417

1418 moveresize_widget((struct widget *)win, x, y, width, height);

1419 win->maximized = 0;

1420

1421 if (resize && win->decoration) {

1422 fitwin(win);

1423 fit_resizer(win->rsz_northwest);

1424 fit_resizer(win->rsz_north);

1425 fit_resizer(win->rsz_northeast);

1426 fit_resizer(win->rsz_west);

1427 fit_resizer(win->rsz_east);

1428 fit_resizer(win->rsz_southwest);

1429 fit_resizer(win->rsz_south);

1430 fit_resizer(win->rsz_southeast);

1431 }

1432

1433 if (move && !resize)

1434 hints_move(win);

1435 else if (!move && resize)

1436 hints_resize(win);

1437 else if (move && resize)

1438 hints_moveresize(win);

1439 }

1440

1441 void move_window(struct window *win, int x, int y)

1442 {

1443 if(win->maximized&&win->title->moving) {

1444 int m = maximize_window(win, x+1, y+1);

1445 //moveresize_window(win, win->title->xoff+((float)win->title->xoff)/monitors[m].w*WIDGET_WIDTH(win), win->title->yoff, WIDGET_WIDTH(win), WIDGET_HEIGHT(win));

1446 win->title->xoff = ((float)win->title->xoff)/monitors[m].w*(0.9f*WIDGET_WIDTH(win));

1447 } else

1448 moveresize_window(win, x, y, WIDGET_WIDTH(win), WIDGET_HEIGHT(win));

1449 }

1450

1451 void move_window_family(struct window *win, int x, int y)

1452 {

1453 struct window *wp;

1454 LIST *lp;

1455 int dx, dy;

1456

1457 dx = x - WIDGET_X(win);

1458 dy = y - WIDGET_Y(win);

1459

1460 LIST_FOREACH(lp, &toplayer) {

1461 wp = LIST_ITEM(lp, struct window, layerlink);

1462 if (WIDGET_MAPPED(wp) && windows_are_related(wp, win))

1463 move_window(wp, WIDGET_X(wp) + dx, WIDGET_Y(wp) + dy);

1464 }

1465 LIST_FOREACH(lp, &normallayer) {

1466 wp = LIST_ITEM(lp, struct window, layerlink);

1467 if (WIDGET_MAPPED(wp) && windows_are_related(wp, win))

1468 move_window(wp, WIDGET_X(wp) + dx, WIDGET_Y(wp) + dy);

1469 }

1470 }

1471

1472 void resize_window(struct window *win, int width, int height)

1473 {

1474 moveresize_window(win, WIDGET_X(win), WIDGET_Y(win), width, height);

1475 }

1476

1477 void unmanage_window(struct window *win, int clientquit)

1478 {

1479 int x, y, width, height;

1480 int wasactive;

1481

1482 debug("unmanage \"%!s(MISSING)\" (Window=0x%!x(MISSING))",win->name, (int)win->client);

1483

1484 wasactive = win == active;

1485

1486 if (wasactive)

1487 set_active_window(NULL);

1488

1489 if (WIDGET_MAPPED(win))

1490 unmap_widget(&win->widget);

1491

1492 hints_unmanage(win);

1493

1494 /*

1495 * Begin teardown.

1496 * Not safe to call WM related functions from now on.

1497 */

1498

1499 if (win->menuitem != NULL)

1500 destroy_menuitem(win->menuitem);

1501 LIST_REMOVE(&win->layerlink);

1502 nwindows--;

1503

1504 window_to_client_geom(win, &x, &y, &width, &height);

1505 delete_widget_context(win->client);

1506

1507 clerr();

1508 XReparentWindow(display, win->client, root, x, y);

1509 if (!clientquit)

1510 XMapWindow(display, win->client);

1511 ungrabbutton(display, AnyButton, AnyModifier, win->client);

1512 XSelectInput(display, win->client, 0);

1513 XSetWindowBorderWidth(display, win->client, win->cborder);

1514 if (win->wmnormalhints->flags & PWinGravity)

1515 setgrav(win->client, win->wmnormalhints->win_gravity);

1516 XRemoveFromSaveSet(display, win->client);

1517 sterr();

1518

1519 if(win->decoration) {

1520 if(win->title)

1521 destroy_title(win->title);

1522 if(win->deletebtn)

1523 destroy_button(win->deletebtn);

1524 if(win->unmapbtn)

1525 destroy_button(win->unmapbtn);

1526 if(win->expandbtn)

1527 destroy_button(win->expandbtn);

1528

1529 if(win->resizable) {

1530 destroy_resizer(win->rsz_northwest);

1531 destroy_resizer(win->rsz_north);

1532 destroy_resizer(win->rsz_northeast);

1533 destroy_resizer(win->rsz_west);

1534 destroy_resizer(win->rsz_east);

1535 destroy_resizer(win->rsz_southwest);

1536 destroy_resizer(win->rsz_south);

1537 destroy_resizer(win->rsz_southeast);

1538 }

1539 }

1540

1541 if (win->wmhints != NULL)

1542 XFree(win->wmhints);

1543 assert(win->wmnormalhints != NULL);

1544 XFree(win->wmnormalhints);

1545

1546 destroy_widget(&win->widget);

1547 //if (win->name != NULL)

1548 // XFree(win->name);

1549 if (win->iconname != NULL)

1550 XFree(win->iconname);

1551 FREE(win);

1552

1553 XSync(display, False);

1554

1555 /*

1556 * Teardown finished

1557 */

1558

1559 if (wasactive)

1560 set_active_window(topmost_window());

1561

1562 }

1563

1564 void remove_decoration(struct window *win) {

1565 win->decoration = 0;

1566 XMoveWindow(display, win->client, 0, 0);

1567 }

1568

1569 void create_decoration(struct window *win) {

1570

1571 win->decoration = 1;

1572

1573 XMoveWindow(display, win->client, border_width, border_width+button_size);

1574 XResizeWindow(display, win->client, win->widget.dim.width-border_width*2, win->widget.dim.height-button_size-border_width*2);

1575

1576 if (!win->deletebtn) {

1577 win->deletebtn = create_button(win,

1578 win->widget.dim.width - border_width - button_size,

1579 border_width, button_size, button_size);

1580 setgrav(WIDGET_XWINDOW(win->deletebtn), NorthEastGravity);

1581 set_button_image(win->deletebtn, &delete_image);

1582 set_button_handler(win->deletebtn, delete_window);

1583 }

1584

1585 if (!win->expandbtn) {

1586 win->expandbtn = create_button(win,

1587 win->widget.dim.width - border_width - 2 * button_size,

1588 border_width, button_size, button_size);

1589 setgrav(WIDGET_XWINDOW(win->expandbtn), NorthEastGravity);

1590 set_button_image(win->expandbtn, &expand_image);

1591 set_button_handler(win->expandbtn, expand_window);

1592 }

1593

1594 if (!win->unmapbtn) {

1595 win->unmapbtn = create_button(win,

1596 win->widget.dim.width - border_width - 3 * button_size,

1597 border_width, button_size, button_size);

1598 setgrav(WIDGET_XWINDOW(win->unmapbtn), NorthEastGravity);

1599 set_button_image(win->unmapbtn, &unmap_image);

1600 set_button_handler(win->unmapbtn, user_unmap_window);

1601 }

1602

1603 if (!win->title) {

1604 win->title = create_title(win,

1605 border_width, border_width,

1606 win->widget.dim.width - 2 * border_width - NBTN * button_size, button_size);

1607 }

1608

1609 }

1610

1611 void repaint_window(struct window *win)

1612 {

1613 if(!win->decoration) {

1614 if(win->title)

1615 destroy_title(win->title);

1616 if(win->deletebtn)

1617 destroy_button(win->deletebtn);

1618 if(win->unmapbtn)

1619 destroy_button(win->unmapbtn);

1620 if(win->expandbtn)

1621 destroy_button(win->expandbtn);

1622 win->deletebtn = win->unmapbtn = win->expandbtn = NULL;

1623 win->title = NULL;

1624 return;

1625 }

1626 REPAINT(win->title);

1627 REPAINT(win->deletebtn);

1628 REPAINT(win->unmapbtn);

1629 REPAINT(win->expandbtn);

1630 REPAINT(win);

1631 }

1632

1633 void repaint_window_family(struct window *win)

1634 {

1635 struct window *wp;

1636 LIST *lp;

1637

1638 LIST_FOREACH(lp, &toplayer) {

1639 wp = LIST_ITEM(lp, struct window, layerlink);

1640 if (windows_are_related(wp, win))

1641 repaint_window(wp);

1642 }

1643 LIST_FOREACH(lp, &normallayer) {

1644 wp = LIST_ITEM(lp, struct window, layerlink);

1645 if (windows_are_related(wp, win))

1646 repaint_window(wp);

1647 }

1648 }

1649

1650 /*

1651 * This function assumes that 'win' already has the desired stacking.

1652 */

1653 static void restack_transient_windows(struct window *win)

1654 {

1655 struct window *leader;

1656 struct window **wins;

1657 int i, n;

1658

1659 leader = NULL;

1660 if (win->wmtransientfor != None)

1661 leader = (struct window *)find_widget(win->wmtransientfor,

1662 WIDGET_WINDOW);

1663 if (leader == NULL)

1664 leader = win;

1665

1666 if (win != leader)

1667 put_window_below(leader, win);

1668

1669 get_window_stack(&wins, &n);

1670 for (i = 0; i < n; i++) {

1671 if (wins[i]->wmtransientfor == leader->client)

1672 put_window_above(wins[i], leader);

1673 }

1674 FREE(wins);

1675 }

1676

1677 static void map_transient_windows(struct window *win)

1678 {

1679 struct window *leader;

1680 struct window **wins;

1681 int i, n;

1682

1683 leader = NULL;

1684 if (win->wmtransientfor != None)

1685 leader = (struct window *)find_widget(win->wmtransientfor,

1686 WIDGET_WINDOW);

1687 if (leader == NULL)

1688 leader = win;

1689

1690 get_window_stack(&wins, &n);

1691 for (i = 0; i < n; i++)

1692 if (wins[i]->wmtransientfor == leader->client)

1693 make_window_visible(wins[i]);

1694 FREE(wins);

1695 make_window_visible(leader);

1696 }

1697

1698 static void put_window_group_below(struct window *win)

1699 {

1700 struct window **wins, *wp;

1701 int n;

1702

1703 if (win->wmhints == NULL

1704 || ~win->wmhints->flags & WindowGroupHint

1705 || win->wmhints->window_group == None

1706 || win->wmhints->window_group == root)

1707 return;

1708

1709 get_window_stack(&wins, &n);

1710 while (n > 1 && wins[--n] != win) {

1711 wp = wins[n];

1712 if (wp->wmhints != NULL

1713 && wp->wmhints->flags & WindowGroupHint

1714 && wp->wmhints->window_group == win->wmhints->window_group)

1715 put_window_below(wp, win);

1716 }

1717 FREE(wins);

1718 }

1719

1720 int window_is_active(struct window *win)

1721 {

1722 return win == active;

1723 }

1724

1725 int window_is_transient_active(struct window *win)

1726 {

1727 return window_is_active(win)

1728 || (active != NULL && windows_are_transient_related(win, active));

1729 }

1730

1731 int window_group_is_active(struct window *win)

1732 {

1733 return window_is_active(win)

1734 || (active != NULL && windows_are_group_related(win, active));

1735 }

1736

1737 int window_family_is_active(struct window *win)

1738 {

1739 return window_is_active(win)

1740 || window_is_transient_active(win) || window_group_is_active(win);

1741 }

1742

1743 int windows_are_related(struct window *win1, struct window *win2)

1744 {

1745 return win1 == win2

1746 || windows_are_group_related(win1, win2)

1747 || windows_are_transient_related(win1, win2);

1748 }

1749

1750 int windows_are_transient_related(struct window *win1, struct window *win2)

1751 {

1752 return win1 == win2

1753 || win1->wmtransientfor == win2->client

1754 || win2->wmtransientfor == win1->client

1755 || (win1->wmtransientfor != None

1756 && win1->wmtransientfor == win2->wmtransientfor);

1757 }

1758

1759 int windows_are_group_related(struct window *win1, struct window *win2)

1760 {

1761 return win1 == win2

1762 || (win1->wmhints != NULL && win2->wmhints != NULL

1763 && win1->wmhints->flags & WindowGroupHint

1764 && win2->wmhints->flags & WindowGroupHint

1765 && win1->wmhints->window_group == win2->wmhints->window_group);

1766 }

1767

1768 /*

1769 * Activate window.

1770 */

1771 void set_active_window_(struct window *win, int button)

1772 {

1773 struct window *old;

1774

1775 if (win != NULL&&button<4) {

1776 raise_window(win); // ???

1777 //if (!window_group_is_active(win))

1778 // put_window_group_below(win);

1779 restack_transient_windows(win);

1780 }

1781

1782 if (win == active)

1783 return;

1784

1785 old = active;

1786 active = win;

1787

1788 if (old != NULL) {

1789 clerr();

1790 grabbutton(display, AnyButton, 0, old->client, True,

1791 ButtonPressMask, GrabModeSync, GrabModeSync, None, None);

1792 sterr();

1793 if(button<4) {

1794 repaint_window_family(old);

1795 hints_deactivate(old);

1796 }

1797 }

1798

1799 if (win != NULL) {

1800 if(button<4)

1801 repaint_window_family(win);

1802 map_transient_windows(win);

1803 make_window_visible(win);

1804

1805 clerr();

1806 XSetInputFocus(display, win->client, RevertToPointerRoot,

1807 CurrentTime);

1808 ungrabbutton(display, AnyButton, 0, win->client);

1809 XAllowEvents(display, ReplayPointer, CurrentTime);

1810 sterr();

1811

1812 if (win->menuitem != NULL)

1813 put_menuitem_first(win->menuitem);

1814 } else {

1815 XSetInputFocus(display, PointerRoot, RevertToPointerRoot,

1816 CurrentTime);

1817 }

1818

1819 if(button<4)

1820 hints_activate(win);

1821 else {

1822 //hints_activate(old);

1823 //active = old;

1824 }

1825 /*if(button>3) {

1826 set_active_window(old);

1827 }*/

1828 }

1829

1830 void set_active_window(struct window *win) {

1831 set_active_window_(win, -1);

1832 }

1833

1834 int get_monitor_cursor() {

1835 Bool result;

1836 Window window_returned;

1837 int root_x, root_y;

1838 int win_x, win_y;

1839 unsigned int mask_return;

1840 result = XQueryPointer(display, root, &window_returned,

1841 &window_returned, &root_x, &root_y, &win_x, &win_y,

1842 &mask_return);

1843 if (result != True) {

1844 fprintf(stderr, "No mouse found.\n");

1845 return -1;

1846 }

1847 for(int i=0; i<monitors_len; i++)

1848 if(root_x>monitors[i].x&&root_x<monitors[i].x+monitors[i].w&&root_y>monitors[i].y&&root_y<monitors[i].y+monitors[i].h)

1849 return i;

1850 return 0;

1851 }

1852

1853 static void make_window_visible(struct window *win)

1854 {

1855 int x, y;

1856

1857 if (WIDGET_X(win) >= DisplayWidth(display, screen) - border_width ||

1858 WIDGET_Y(win) >= DisplayHeight(display, screen) - border_width ||

1859 WIDGET_X(win) + WIDGET_WIDTH(win) < border_width ||

1860 WIDGET_Y(win) + WIDGET_HEIGHT(win) < border_width) {

1861 smartpos(WIDGET_WIDTH(win), WIDGET_HEIGHT(win), &x, &y, get_monitor_cursor());

1862 move_window(win, x, y);

1863 }

1864

1865 if (!WIDGET_MAPPED(win))

1866 map_window(win);

1867 }

1868

1869 Atom getatomprop(struct window *win, Atom prop)

1870 {

1871 int di;

1872 unsigned long dl;

1873 unsigned char *p = NULL;

1874 Atom da, atom = None;

1875

1876 if (XGetWindowProperty(display, win->client, prop, 0L, sizeof atom, False, XA_ATOM,

1877 &da, &di, &dl, &dl, &p) == Success && p) {

1878 atom = *(Atom *)p;

1879 XFree(p);

1880 }

1881 return atom;

1882 }

1883

1884 /*

1885 typedef struct {

1886 long flags;

1887 long functions;

1888 long decorations;

1889 long inputmode;

1890 long status;

1891 } mwmhints;

1892

1893 static Atom MOTIF_WM_HINTS = None;

1894 static mwmhints *getmwmhints(Window w)

1895 {

1896 if (MOTIF_WM_HINTS == None) {

1897 MOTIF_WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", False);

1898 }

1899 unsigned long n = 0;

1900 mwmhints *h = getprop(w, MOTIF_WM_HINTS,

1901 MOTIF_WM_HINTS, 32, &n);

1902 if (h != NULL && n != 5) {

1903 XFree(h);

1904 h = NULL;

1905 }

1906 return h;

1907 }

1908 */

1909 static Atom MOTIF_WM_HINTS = None;

1910 void fetch_wm_motif(struct window *win) {

1911 if (MOTIF_WM_HINTS == None) {

1912 MOTIF_WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", False);

1913 }

1914 long* hints;

1915 Atom ret;

1916 int format;

1917 unsigned long nitems;

1918 unsigned long toberead;

1919 int success = XGetWindowProperty(display, win->client, MOTIF_WM_HINTS, 0, sizeof(long[5]), False, MOTIF_WM_HINTS, &ret, &format, &nitems, &toberead, (unsigned char**)&hints)==Success;

1920 if (success && nitems*format >= sizeof(long[5]))

1921 win->decoration = hints[2]?1:0;

1922 else win->decoration = 1;

1923 }

1924

1925 void window_set_fullscreen(struct window* win, int fullscreen) {

1926 if (fullscreen && !win->fullscreen) {

1927 XChangeProperty(display, win->client, atom[NET_WM_STATE], XA_ATOM, 32,

1928 PropModeReplace, (unsigned char*)&atom[NET_WM_STATE_FULLSCREEN], 1);

1929 win->fullscreen = 1;

1930 remove_decoration(win);

1931 toggle_window_ontop(win);

1932 maximize_window(win, -1, -1);

1933 set_active_window(win);

1934 } else if (!fullscreen && win->fullscreen){

1935 XChangeProperty(display, win->client, atom[NET_WM_STATE], XA_ATOM, 32,

1936 PropModeReplace, (unsigned char*)0, 0);

1937 win->fullscreen = 0;

1938 win->decoration = 1;

1939 toggle_window_ontop(win);

1940 maximize_window(win, -1, -1);

1941 create_decoration(win);

1942 }

1943 }

1944

1945 void update_window_type(struct window *win) {

1946 Atom state = getatomprop(win, atom[NET_WM_STATE]);

1947 Atom wtype = getatomprop(win, atom[NET_WM_WINDOW_TYPE]);

1948 //printf("state %!l(MISSING)d %!l(MISSING)d %!l(MISSING)d\n", state, wtype, atom[NET_WM_WINDOW_TYPE_NORMAL]);

1949 if (state == atom[NET_WM_STATE_FULLSCREEN])

1950 printf("FULL SCREEN!!!\n");

1951

1952 if (wtype == atom[NET_WM_WINDOW_TYPE_TOOLBAR] || wtype == atom[NET_WM_WINDOW_TYPE_DOCK])

1953 toggle_window_ontop(win);

1954 if (wtype == atom[NET_WM_WINDOW_TYPE_SPLASH] || wtype == atom[NET_WM_WINDOW_TYPE_TOOLBAR] || wtype == atom[NET_WM_WINDOW_TYPE_DOCK] || wtype == atom[NET_WM_WINDOW_TYPE_DESKTOP] || wtype == atom[NET_WM_WINDOW_TYPE_MENU])

1955 remove_decoration(win);

1956 else

1957 fetch_wm_motif(win);

1958

1959 }

1960