Compile warning
[notion/jeffpc.git] / ioncore / screen.c
blobbe6fc925ea0c8186307478287cfbb7a466d0a5a6
1 /*
2 * ion/ioncore/screen.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #include <libtu/objp.h>
12 #include <libtu/minmax.h>
14 #include "common.h"
15 #include "global.h"
16 #include "screen.h"
17 #include "region.h"
18 #include "attach.h"
19 #include "manage.h"
20 #include "focus.h"
21 #include "property.h"
22 #include "names.h"
23 #include "reginfo.h"
24 #include "saveload.h"
25 #include "resize.h"
26 #include "event.h"
27 #include "bindmaps.h"
28 #include "regbind.h"
29 #include "frame-pointer.h"
30 #include "rectangle.h"
31 #include "extlconv.h"
32 #include "llist.h"
33 #include "group-ws.h"
34 #include "mplex.h"
35 #include "conf.h"
36 #include "activity.h"
37 #include "screen-notify.h"
40 WHook *screen_managed_changed_hook=NULL;
43 /*{{{ Init/deinit */
46 bool screen_init(WScreen *scr, WRootWin *parent, const WFitParams *fp, int id)
48 Window win;
49 XSetWindowAttributes attr;
50 ulong attrflags=0;
52 scr->id=id;
53 scr->atom_workspace=None;
54 scr->managed_off.x=0;
55 scr->managed_off.y=0;
56 scr->managed_off.w=0;
57 scr->managed_off.h=0;
58 scr->next_scr=NULL;
59 scr->prev_scr=NULL;
61 watch_init(&(scr->notifywin_watch));
62 watch_init(&(scr->infowin_watch));
64 attr.background_pixmap=ParentRelative;
65 attrflags=CWBackPixmap;
67 win=XCreateWindow(ioncore_g.dpy, WROOTWIN_ROOT(parent),
68 fp->g.x, fp->g.y, fp->g.w, fp->g.h, 0,
69 DefaultDepth(ioncore_g.dpy, parent->xscr),
70 InputOutput,
71 DefaultVisual(ioncore_g.dpy, parent->xscr),
72 attrflags, &attr);
73 if(win==None)
74 return FALSE;
76 if(!mplex_do_init((WMPlex*)scr, (WWindow*)parent, fp, win, "WScreen")){
77 XDestroyWindow(ioncore_g.dpy, win);
78 return FALSE;
81 /*scr->mplex.win.region.rootwin=rootwin;
82 region_set_parent((WRegion*)scr, (WRegion*)rootwin);*/
83 scr->mplex.flags|=MPLEX_ADD_TO_END;
84 scr->mplex.win.region.flags|=REGION_BINDINGS_ARE_GRABBED;
86 scr->mplex.win.region.flags|=REGION_MAPPED;
87 window_select_input((WWindow*)scr, IONCORE_EVENTMASK_SCREEN);
89 if(id==0){
90 scr->atom_workspace=XInternAtom(ioncore_g.dpy,
91 "_ION_WORKSPACE", False);
92 }else if(id>=0){
93 char *str;
94 libtu_asprintf(&str, "_ION_WORKSPACE%d", id);
95 if(str!=NULL){
96 scr->atom_workspace=XInternAtom(ioncore_g.dpy, str, False);
97 free(str);
101 /* Add all the needed bindings here; mplex does nothing so that
102 * frames don't have to remove extra bindings.
104 region_add_bindmap((WRegion*)scr, ioncore_screen_bindmap);
105 region_add_bindmap((WRegion*)scr, ioncore_mplex_bindmap);
106 region_add_bindmap((WRegion*)scr, ioncore_mplex_toplevel_bindmap);
108 LINK_ITEM(ioncore_g.screens, scr, next_scr, prev_scr);
110 return TRUE;
114 WScreen *create_screen(WRootWin *parent, const WFitParams *fp, int id)
116 CREATEOBJ_IMPL(WScreen, screen, (p, parent, fp, id));
120 void screen_deinit(WScreen *scr)
122 UNLINK_ITEM(ioncore_g.screens, scr, next_scr, prev_scr);
124 screen_unnotify(scr);
125 screen_nowindowinfo(scr);
127 mplex_deinit((WMPlex*)scr);
131 /*}}}*/
134 /*{{{ Attach/detach */
137 void screen_managed_geom(WScreen *scr, WRectangle *geom)
139 geom->x=scr->managed_off.x;
140 geom->y=scr->managed_off.y;
141 geom->w=REGION_GEOM(scr).w+scr->managed_off.w;
142 geom->h=REGION_GEOM(scr).h+scr->managed_off.h;
143 geom->w=maxof(geom->w, 0);
144 geom->h=maxof(geom->h, 0);
148 static bool screen_handle_drop(WScreen *scr, int x, int y, WRegion *dropped)
150 WRegion *curr=mplex_mx_current(&(scr->mplex));
152 /* This code should handle dropping tabs on floating workspaces. */
153 if(curr && HAS_DYN(curr, region_handle_drop)){
154 int rx, ry;
155 region_rootpos(curr, &rx, &ry);
156 if(rectangle_contains(&REGION_GEOM(curr), x-rx, y-ry)){
157 if(region_handle_drop(curr, x, y, dropped))
158 return TRUE;
162 /* Do not attach to ourselves unlike generic WMPlex. */
163 return FALSE;
167 /*}}}*/
170 /*{{{ Region dynfun implementations */
173 static void screen_managed_changed(WScreen *scr, int mode, bool sw,
174 WRegion *reg_)
176 if(ioncore_g.opmode==IONCORE_OPMODE_DEINIT)
177 return;
179 if(sw && scr->atom_workspace!=None){
180 WRegion *reg=mplex_mx_current(&(scr->mplex));
181 const char *n=NULL;
183 if(reg!=NULL)
184 n=region_displayname(reg);
186 xwindow_set_string_property(region_root_of((WRegion*)scr),
187 scr->atom_workspace,
188 n==NULL ? "" : n);
191 if(region_is_activity_r((WRegion*)scr))
192 screen_update_notifywin(scr);
194 screen_update_infowin(scr);
196 mplex_call_changed_hook((WMPlex*)scr,
197 screen_managed_changed_hook,
198 mode, sw, reg_);
202 static void screen_map(WScreen *scr)
204 mplex_map((WMPlex*)scr);
208 static void screen_unmap(WScreen *scr)
210 mplex_unmap((WMPlex*)scr);
213 void screen_inactivated(WScreen *scr)
215 screen_update_infowin(scr);
219 void screen_activated(WScreen *scr)
221 screen_update_infowin(scr);
225 /*}}}*/
228 /*{{{ Misc. */
231 /*EXTL_DOC
232 * Find the screen with numerical id \var{id}.
234 EXTL_SAFE
235 EXTL_EXPORT
236 WScreen *ioncore_find_screen_id(int id)
238 WScreen *scr=NULL;
240 FOR_ALL_SCREENS(scr){
241 if(scr->id==id)
242 return scr;
245 return NULL;
249 /*EXTL_DOC
250 * Switch focus to the screen with id \var{id} and return it.
252 * Note that this function is asynchronous; the screen will not
253 * actually have received the focus when this function returns.
255 EXTL_EXPORT
256 WScreen *ioncore_goto_nth_screen(int id)
258 WScreen *scr=ioncore_find_screen_id(id);
259 if(scr!=NULL){
260 if(!region_goto((WRegion*)scr))
261 return NULL;
263 return scr;
267 static WScreen *current_screen()
269 if(ioncore_g.focus_current==NULL)
270 return ioncore_g.screens;
271 else
272 return region_screen_of(ioncore_g.focus_current);
276 /*EXTL_DOC
277 * Switch focus to the next screen and return it.
279 * Note that this function is asynchronous; the screen will not
280 * actually have received the focus when this function returns.
282 EXTL_EXPORT
283 WScreen *ioncore_goto_next_screen()
285 WScreen *scr=current_screen();
287 if(scr!=NULL)
288 scr=scr->next_scr;
289 if(scr==NULL)
290 scr=ioncore_g.screens;
291 if(scr!=NULL){
292 if(!region_goto((WRegion*)scr))
293 return NULL;
295 return scr;
299 /*EXTL_DOC
300 * Switch focus to the previous screen and return it.
302 * Note that this function is asynchronous; the screen will not
303 * actually have received the focus when this function returns.
305 EXTL_EXPORT
306 WScreen *ioncore_goto_prev_screen()
308 WScreen *scr=current_screen();
310 if(scr!=NULL)
311 scr=scr->prev_scr;
312 else
313 scr=ioncore_g.screens;
314 if(scr!=NULL){
315 if(!region_goto((WRegion*)scr))
316 return NULL;
318 return scr;
322 /*EXTL_DOC
323 * Return the numerical id for screen \var{scr}.
325 EXTL_SAFE
326 EXTL_EXPORT_MEMBER
327 int screen_id(WScreen *scr)
329 return scr->id;
333 static WRegion *screen_managed_disposeroot(WScreen *scr, WRegion *reg)
335 bool onmxlist=FALSE, others=FALSE;
336 WLListNode *lnode;
337 WLListIterTmp tmp;
339 if(scr==scr->prev_scr && OBJ_IS(reg, WGroupWS)){
340 FOR_ALL_NODES_ON_LLIST(lnode, scr->mplex.mx_list, tmp){
341 if(lnode->st->reg==reg){
342 onmxlist=TRUE;
343 }else if(OBJ_IS(lnode->st->reg, WGroupWS)){
344 others=TRUE;
345 break;
349 if(onmxlist && !others){
350 warn(TR("Only workspace on only screen may not be destroyed/detached."));
351 return NULL;
355 return reg;
359 static bool screen_may_dispose(WScreen *scr)
361 return TRUE;
366 void screen_set_managed_offset(WScreen *scr, const WRectangle *off)
368 scr->managed_off=*off;
369 mplex_fit_managed((WMPlex*)scr);
373 /*EXTL_DOC
374 * Set offset of objects managed by the screen from actual screen geometry.
375 * The table \var{offset} should contain the entries \code{x}, \code{y},
376 * \code{w} and \code{h} indicating offsets of that component of screen
377 * geometry.
379 EXTL_EXPORT_AS(WScreen, set_managed_offset)
380 bool screen_set_managed_offset_extl(WScreen *scr, ExtlTab offset)
382 WRectangle g;
384 if(!extl_table_to_rectangle(offset, &g))
385 goto err;
387 if(-g.w>=REGION_GEOM(scr).w)
388 goto err;
389 if(-g.h>=REGION_GEOM(scr).h)
390 goto err;
392 screen_set_managed_offset(scr, &g);
394 return TRUE;
395 err:
396 warn(TR("Invalid offset."));
397 return FALSE;
401 /*}}}*/
404 /*{{{ Save/load */
407 ExtlTab screen_get_configuration(WScreen *scr)
409 return mplex_get_configuration(&scr->mplex);
413 static WRegion *do_create_initial(WWindow *parent, const WFitParams *fp,
414 WRegionLoadCreateFn *fn)
416 return fn(parent, fp, extl_table_none());
420 static bool create_initial_ws(WScreen *scr)
422 WRegion *reg=NULL;
423 WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
424 ExtlTab lo=ioncore_get_layout("default");
426 if(lo==extl_table_none()){
427 reg=mplex_do_attach_new(&scr->mplex, &par,
428 (WRegionCreateFn*)create_groupws, NULL);
429 }else{
430 reg=mplex_attach_new_(&scr->mplex, &par, 0, lo);
431 extl_unref_table(lo);
434 if(reg==NULL){
435 warn(TR("Unable to create a workspace on screen %d."), scr->id);
436 return FALSE;
439 return TRUE;
443 bool screen_init_layout(WScreen *scr, ExtlTab tab)
445 char *name;
446 ExtlTab substab, subtab;
447 int n, i;
449 if(tab==extl_table_none())
450 return create_initial_ws(scr);
452 mplex_load_contents(&scr->mplex, tab);
454 return TRUE;
457 /*}}}*/
460 /*{{{ Dynamic function table and class implementation */
463 static DynFunTab screen_dynfuntab[]={
464 {region_map,
465 screen_map},
467 {region_unmap,
468 screen_unmap},
470 {region_activated,
471 screen_activated},
473 {region_inactivated,
474 screen_inactivated},
476 {(DynFun*)region_managed_disposeroot,
477 (DynFun*)screen_managed_disposeroot},
479 {(DynFun*)region_may_dispose,
480 (DynFun*)screen_may_dispose},
482 {mplex_managed_changed,
483 screen_managed_changed},
485 {region_managed_notify,
486 screen_managed_notify},
488 {mplex_managed_geom,
489 screen_managed_geom},
491 {(DynFun*)region_get_configuration,
492 (DynFun*)screen_get_configuration},
494 {(DynFun*)region_handle_drop,
495 (DynFun*)screen_handle_drop},
497 END_DYNFUNTAB
501 EXTL_EXPORT
502 IMPLCLASS(WScreen, WMPlex, screen_deinit, screen_dynfuntab);
505 /*}}}*/