1 #include "e_mod_tiling.h"
2 
3 /* HACK: Needed to get subobjs of the widget. Is there a better way? */
4 typedef struct _E_Widget_Smart_Data E_Widget_Smart_Data;
5 
6 struct _E_Widget_Smart_Data
7 {
8    Evas_Object *parent_obj;
9    Evas_Coord   x, y, w, h;
10    Evas_Coord   minw, minh;
11    Eina_List   *subobjs;
12 };
13 
14 static void
_open_browser_help_cb(void * data EINA_UNUSED,void * obj EINA_UNUSED)15 _open_browser_help_cb(void *data EINA_UNUSED, void *obj EINA_UNUSED)
16 {
17    e_util_open("https://phab.enlightenment.org/w/emodules/tiling2/", NULL);
18 }
19 
20 /* Some defines to make coding with the e_widget_* easier for configuration
21  * panel */
22 #define RADIO(title, value, radiogroup) \
23   e_widget_radio_add(evas, _(title), value, radiogroup)
24 #define LIST_ADD(list, object) \
25   e_widget_list_object_append(list, object, 1, 1, 0.5)
26 
27 struct _Config_vdesk *
get_vdesk(Eina_List * vdesks,int x,int y,unsigned int zone_num)28 get_vdesk(Eina_List *vdesks, int x, int y, unsigned int zone_num)
29 {
30    Eina_List *l;
31 
32    for (l = vdesks; l; l = l->next)
33      {
34         struct _Config_vdesk *vd = l->data;
35 
36         if (!vd)
37           continue;
38         if (vd->nb_stacks < 0 || vd->nb_stacks > 1)
39           vd->nb_stacks = 0;
40         if (vd->x == x && vd->y == y && vd->zone_num == zone_num)
41           return vd;
42      }
43 
44    return NULL;
45 }
46 
47 /*
48  * Fills the E_Config_Dialog-struct with the data currently in use
49  *
50  */
51 static void *
_create_data(E_Config_Dialog * cfd EINA_UNUSED)52 _create_data(E_Config_Dialog *cfd EINA_UNUSED)
53 {
54    E_Config_Dialog_Data *cfdata;
55    Eina_List *l;
56 
57    cfdata = E_NEW(E_Config_Dialog_Data, 1);
58 
59    /* Because we save a lot of lines here by using memcpy, the structs have to
60     * be ordered the same */
61    memcpy(cfdata, tiling_g.config, sizeof(Config));
62 
63    /* Handle things which can't be easily memcpy'd */
64    cfdata->config.vdesks = NULL;
65 
66    for (l = tiling_g.config->vdesks; l; l = l->next)
67      {
68         struct _Config_vdesk *vd = l->data, *newvd;
69 
70         if (!vd)
71           continue;
72 
73         newvd = E_NEW(struct _Config_vdesk, 1);
74 
75         newvd->x = vd->x;
76         newvd->y = vd->y;
77         newvd->zone_num = vd->zone_num;
78         newvd->nb_stacks = vd->nb_stacks;
79 
80         EINA_LIST_APPEND(cfdata->config.vdesks, newvd);
81      }
82 
83    return cfdata;
84 }
85 
86 static void
_free_data(E_Config_Dialog * cfd EINA_UNUSED,E_Config_Dialog_Data * cfdata)87 _free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
88 {
89    eina_list_free(cfdata->config.vdesks);
90    free(cfdata);
91 }
92 
93 static void
_fill_zone_config(E_Zone * zone,E_Config_Dialog_Data * cfdata)94 _fill_zone_config(E_Zone *zone, E_Config_Dialog_Data *cfdata)
95 {
96    Evas *evas;
97    int i;
98 
99    evas = cfdata->evas;
100 
101    /* Clear old entries first */
102    evas_object_del(cfdata->o_desklist);
103 
104    cfdata->o_desklist = e_widget_list_add(evas, 1, 0);
105 
106    for (i = 0; i < zone->desk_y_count * zone->desk_x_count; i++)
107      {
108         E_Desk *desk = zone->desks[i];
109         struct _Config_vdesk *vd;
110         Evas_Object *list, *checkbox;
111 
112         if (!desk)
113           continue;
114 
115         vd = get_vdesk(cfdata->config.vdesks, desk->x, desk->y, zone->num);
116         if (!vd)
117           {
118              vd = E_NEW(struct _Config_vdesk, 1);
119 
120              vd->x = desk->x;
121              vd->y = desk->y;
122              vd->zone_num = zone->num;
123              vd->nb_stacks = 0;
124 
125              EINA_LIST_APPEND(cfdata->config.vdesks, vd);
126           }
127 
128         list = e_widget_list_add(evas, false, true);
129 
130         LIST_ADD(list, e_widget_label_add(evas, desk->name));
131         checkbox = e_widget_check_add(evas, "", &vd->nb_stacks);
132         LIST_ADD(list, checkbox);
133 
134         LIST_ADD(cfdata->o_desklist, list);
135      }
136 
137    /* Get the correct sizes of desklist and scrollframe */
138    LIST_ADD(cfdata->osf, cfdata->o_desklist);
139 }
140 
141 static void
_cb_zone_change(void * data,Evas_Object * obj EINA_UNUSED)142 _cb_zone_change(void *data, Evas_Object *obj EINA_UNUSED)
143 {
144    int n;
145    E_Config_Dialog_Data *cfdata = data;
146    E_Zone *zone;
147 
148    if (!cfdata || !cfdata->o_zonelist)
149      return;
150 
151    n = e_widget_ilist_selected_get(cfdata->o_zonelist);
152    zone = e_widget_ilist_nth_data_get(cfdata->o_zonelist, n);
153    if (!zone)
154      return;
155    _fill_zone_config(zone, cfdata);
156 }
157 
158 static Evas_Object *
_basic_create_widgets(E_Config_Dialog * cfd EINA_UNUSED,Evas * evas,E_Config_Dialog_Data * cfdata)159 _basic_create_widgets(E_Config_Dialog *cfd EINA_UNUSED, Evas *evas,
160                       E_Config_Dialog_Data *cfdata)
161 {
162    Evas_Object *o, *oc, *of, *slider;
163    E_Zone *zone;
164    Eina_List *l;
165 
166    o = e_widget_list_add(evas, 0, 0);
167 
168    /* General settings */
169    of = e_widget_framelist_add(evas, _("General"), 0);
170    e_widget_framelist_object_append(of, e_widget_check_add(evas,
171                                                            _("Show window titles"), &cfdata->config.show_titles));
172    e_widget_framelist_object_append(of, e_widget_check_add(evas,
173                                                            _("Tile dialog windows"), &cfdata->config.tile_dialogs));
174    e_widget_framelist_object_append(of, e_widget_check_add(evas,
175                                                            _("Enable floating split-mode"), &cfdata->config.have_floating_mode));
176 
177    LIST_ADD(o, of);
178 
179    /* Virtual desktop settings */
180    of = e_widget_label_add(evas, _("Enable/disable tiling per desktop."));
181    LIST_ADD(o, of);
182    of = e_widget_framelist_add(evas, _("Virtual Desktops"), 0);
183    cfdata->osf = e_widget_list_add(evas, 0, 1);
184 
185    /* Zone list */
186    cfdata->o_zonelist = e_widget_ilist_add(evas, 0, 0, NULL);
187    e_widget_ilist_multi_select_set(cfdata->o_zonelist, false);
188    e_widget_size_min_set(cfdata->o_zonelist, 100, 100);
189    e_widget_on_change_hook_set(cfdata->o_zonelist, _cb_zone_change, cfdata);
190    for (l = e_comp->zones; l; l = l->next)
191      {
192         if (!(zone = l->data))
193           continue;
194         e_widget_ilist_append(cfdata->o_zonelist, NULL, zone->name, NULL, zone,
195                               NULL);
196      }
197    e_widget_ilist_go(cfdata->o_zonelist);
198    e_widget_ilist_thaw(cfdata->o_zonelist);
199 
200    LIST_ADD(cfdata->osf, cfdata->o_zonelist);
201 
202    /* List of individual tiling modes */
203    cfdata->evas = evas;
204 
205    _fill_zone_config(eina_list_data_get(e_comp->zones), cfdata);
206 
207    e_widget_ilist_selected_set(cfdata->o_zonelist, 0);
208 
209    e_widget_framelist_object_append(of, cfdata->osf);
210 
211    LIST_ADD(o, of);
212 
213    of = e_widget_label_add(evas, _("Padding between windows"));
214    LIST_ADD(o, of);
215    slider = e_widget_slider_add(evas, 1, 0, ("%1.0f px"), 0.0, TILING_MAX_PADDING,
216                                 1.0, 0, NULL, &cfdata->config.window_padding, 150);
217    LIST_ADD(o, slider);
218 
219    oc = e_widget_button_add(evas, _("Help"), "help", _open_browser_help_cb,
220                             NULL, NULL);
221    LIST_ADD(o, oc);
222 
223    return o;
224 }
225 
226 static int
_basic_apply_data(E_Config_Dialog * cfd EINA_UNUSED,E_Config_Dialog_Data * cfdata)227 _basic_apply_data(E_Config_Dialog *cfd EINA_UNUSED,
228                   E_Config_Dialog_Data *cfdata)
229 {
230    struct _Config_vdesk *vd;
231    Eina_List *l, *vdesks;
232 
233    tiling_g.config->tile_dialogs = cfdata->config.tile_dialogs;
234    tiling_g.config->show_titles = cfdata->config.show_titles;
235    tiling_g.config->have_floating_mode = cfdata->config.have_floating_mode;
236    tiling_g.config->window_padding = cfdata->config.window_padding;
237 
238    /* Check if the layout for one of the vdesks has changed */
239    for (l = tiling_g.config->vdesks; l; l = l->next)
240      {
241         struct _Config_vdesk *newvd;
242 
243         vd = l->data;
244 
245         if (!vd)
246           continue;
247         if (!(newvd =
248                 get_vdesk(cfdata->config.vdesks, vd->x, vd->y, vd->zone_num)))
249           {
250              change_desk_conf(vd);
251              continue;
252           }
253 
254         if (newvd->nb_stacks != vd->nb_stacks)
255           {
256              DBG("number of columns for (%d, %d, %d) changed from %d" " to %d",
257                  vd->x, vd->y, vd->zone_num, vd->nb_stacks, newvd->nb_stacks);
258              change_desk_conf(newvd);
259              free(vd);
260              l->data = NULL;
261           }
262         else if (vd->nb_stacks > 0)
263           {
264              change_desk_conf(vd);
265           }
266      }
267 
268    vdesks = tiling_g.config->vdesks;
269    tiling_g.config->vdesks = NULL;
270 
271    for (l = cfdata->config.vdesks; l; l = l->next)
272      {
273         struct _Config_vdesk *newvd;
274 
275         vd = l->data;
276         if (!vd)
277           continue;
278 
279         newvd = E_NEW(struct _Config_vdesk, 1);
280 
281         newvd->x = vd->x;
282         newvd->y = vd->y;
283         newvd->zone_num = vd->zone_num;
284         newvd->nb_stacks = vd->nb_stacks;
285 
286         EINA_LIST_APPEND(tiling_g.config->vdesks, newvd);
287      }
288 
289    e_tiling_update_conf();
290 
291    EINA_LIST_FREE(vdesks, vd)
292      {
293         free(vd);
294      }
295 
296    e_config_save_queue();
297 
298    return EINA_TRUE;
299 }
300 
301 E_Config_Dialog *
e_int_config_tiling_module(Evas_Object * parent EINA_UNUSED,const char * params EINA_UNUSED)302 e_int_config_tiling_module(Evas_Object *parent EINA_UNUSED, const char *params EINA_UNUSED)
303 {
304    E_Config_Dialog *cfd;
305    E_Config_Dialog_View *v;
306    char buf[PATH_MAX];
307 
308    if (e_config_dialog_find("E", "windows/tiling"))
309      return NULL;
310 
311    v = E_NEW(E_Config_Dialog_View, 1);
312 
313    v->create_cfdata = _create_data;
314    v->free_cfdata = _free_data;
315    v->basic.apply_cfdata = _basic_apply_data;
316    v->basic.create_widgets = _basic_create_widgets;
317 
318    snprintf(buf, sizeof(buf), "%s/e-module-tiling.edj",
319             e_module_dir_get(tiling_g.module));
320    cfd =
321      e_config_dialog_new(NULL, _("Tiling Configuration"), "E",
322                          "windows/tiling", buf, 0, v, NULL);
323    return cfd;
324 }
325 
326