2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2009 Kim Woelders
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include "e16-ecore_list.h"
46 unsigned int startup_id;
48 unsigned int match_flags;
49 unsigned int use_flags;
59 unsigned int flags[2];
73 static Ecore_List *ss_list = NULL;
74 static Timer *ss_timer = NULL;
77 _SnapCreate(const char *name)
81 sn = ECALLOC(Snapshot, 1);
86 ss_list = ecore_list_new();
87 ecore_list_append(ss_list, sn);
89 sn->name = Estrdup(name);
95 _SnapDestroy(Snapshot * sn)
97 /* Just making sure */
98 sn = (Snapshot *) ecore_list_node_remove(ss_list, sn);
103 sn->used->snap = NULL;
106 Efree(sn->win_title);
108 Efree(sn->win_class);
110 Efree(sn->border_name);
118 * Stupid hack to fix apps that set WM_WINDOW_ROLE to
119 * a <name>-<pid>-<something>-<time> like thing.
120 * Is this even ICCCM compliant?
123 _ParseRole(const char *role, char *buf, int len)
134 for (l2 = l1; l2 > 0; l2--)
136 if (role[l2 - 1] != '-' &&
137 !(role[l2 - 1] >= '0' && role[l2 - 1] <= '9'))
142 memcpy(buf, role, l1);
148 #define SEQ(s1, s2) ((s1) && (s2) && !strcmp(s1, s2))
151 _SnapEwinMatch(const Snapshot * sn, const EWin * ewin)
155 /* Don't allow matching anything */
156 if (!sn->match_flags)
159 if (ewin->state.identified)
160 return sn->win == EwinGetClientXwin(ewin);
162 if (sn->startup_id && !sn->cmd)
165 if (sn->match_flags & SNAP_MATCH_TITLE
166 && !SEQ(sn->win_title, EwinGetIcccmName(ewin)))
169 if (sn->match_flags & SNAP_MATCH_NAME
170 && !SEQ(sn->win_name, EwinGetIcccmCName(ewin)))
173 if (sn->match_flags & SNAP_MATCH_CLASS
174 && !SEQ(sn->win_class, EwinGetIcccmClass(ewin)))
177 if (sn->match_flags & SNAP_MATCH_ROLE)
179 s = _ParseRole(ewin->icccm.wm_role, buf, sizeof(buf));
180 if (!SEQ(sn->win_role, s))
189 _SnapEwinFindMatchCmd(const void *data, const void *match)
191 const Snapshot *sn = (Snapshot *) data;
192 const EWin *ewin = (EWin *) match;
195 !(sn->startup_id && SEQ(sn->cmd, ewin->icccm.wm_command) &&
196 _SnapEwinMatch(sn, ewin));
200 _SnapEwinFindMatch(const void *data, const void *match)
202 const Snapshot *sn = (Snapshot *) data;
203 const EWin *ewin = (EWin *) match;
205 return sn->used || !_SnapEwinMatch(sn, ewin);
208 /* find a snapshot state that applies to this ewin */
210 _SnapEwinFind(EWin * ewin)
217 if (ecore_list_count(ss_list) <= 0)
220 /* If exec'ed by snap try matching command exactly */
221 sn = (Snapshot *) ecore_list_find(ss_list, _SnapEwinFindMatchCmd, ewin);
224 sn = (Snapshot *) ecore_list_find(ss_list, _SnapEwinFindMatch, ewin);
226 if (sn && !(sn->match_flags & SNAP_MATCH_MULTIPLE))
235 #define ST(s) ((s) ? (s) : "")
237 /* find a snapshot state that applies to this ewin Or if that doesnt exist */
238 /* create a new one */
240 _SnapEwinGet(EWin * ewin, unsigned int match_flags)
245 sn = _SnapEwinFind(ewin);
249 if ((match_flags & SNAP_MATCH_TITLE) && !EwinGetIcccmName(ewin))
250 match_flags ^= SNAP_MATCH_TITLE;
251 if ((match_flags & SNAP_MATCH_NAME) && !EwinGetIcccmCName(ewin))
252 match_flags ^= SNAP_MATCH_NAME;
253 if ((match_flags & SNAP_MATCH_CLASS) && !EwinGetIcccmClass(ewin))
254 match_flags ^= SNAP_MATCH_CLASS;
255 if ((match_flags & SNAP_MATCH_ROLE) && !ewin->icccm.wm_role)
256 match_flags ^= SNAP_MATCH_ROLE;
257 if (match_flags == 0)
259 if (!EwinGetIcccmName(ewin))
261 match_flags = SNAP_MATCH_TITLE;
264 sn = _SnapCreate(NULL);
268 sn->match_flags = match_flags;
269 if (match_flags & SNAP_MATCH_TITLE)
270 sn->win_title = Estrdup(EwinGetIcccmName(ewin));
271 if (match_flags & SNAP_MATCH_NAME)
272 sn->win_name = Estrdup(EwinGetIcccmCName(ewin));
273 if (match_flags & SNAP_MATCH_CLASS)
274 sn->win_class = Estrdup(EwinGetIcccmClass(ewin));
275 if (match_flags & SNAP_MATCH_ROLE)
277 s = _ParseRole(ewin->icccm.wm_role, buf, sizeof(buf));
278 sn->win_role = Estrdup(s);
281 /* Set the snap name. Has no particular significance. */
282 if ((sn->win_name || sn->win_class) && sn->win_role)
283 Esnprintf(buf, sizeof(buf), "%s.%s:%s", ST(sn->win_name),
284 ST(sn->win_class), sn->win_role);
285 else if (sn->win_name || sn->win_class)
286 Esnprintf(buf, sizeof(buf), "%s.%s", ST(sn->win_name), ST(sn->win_class));
287 else if (sn->win_title)
288 Esnprintf(buf, sizeof(buf), "TITLE.%s", sn->win_title);
289 else /* We should not go here */
290 Esnprintf(buf, sizeof(buf), "TITLE.%s", EwinGetIcccmName(ewin));
291 sn->name = Estrdup(buf);
293 if (!(sn->match_flags & SNAP_MATCH_MULTIPLE))
302 /* record info about this Ewin's attributes */
305 _SnapUpdateEwinBorder(Snapshot * sn, const EWin * ewin)
307 Efree(sn->border_name);
308 sn->border_name = Estrdup(BorderGetName(ewin->normal_border));
312 _SnapUpdateEwinDesktop(Snapshot * sn, const EWin * ewin)
314 sn->desktop = EoGetDeskNum(ewin);
318 _SnapUpdateEwinSize(Snapshot * sn, const EWin * ewin)
320 sn->w = ewin->client.w;
321 sn->h = ewin->client.h;
325 _SnapUpdateEwinLocation(Snapshot * sn, const EWin * ewin)
329 sn->x = EoGetX(ewin);
330 sn->y = EoGetY(ewin);
331 sn->area_x = ewin->area_x;
332 sn->area_y = ewin->area_y;
333 if (!EoIsSticky(ewin))
335 DeskGetArea(EoGetDesk(ewin), &ax, &ay);
336 sn->x += ((ax - sn->area_x) * WinGetW(VROOT));
337 sn->y += ((ay - sn->area_y) * WinGetH(VROOT));
342 _SnapUpdateEwinLayer(Snapshot * sn, const EWin * ewin)
344 sn->layer = EoGetLayer(ewin);
348 _SnapUpdateEwinSticky(Snapshot * sn, const EWin * ewin)
350 sn->sticky = EoIsSticky(ewin);
354 _SnapUpdateEwinShade(Snapshot * sn, const EWin * ewin)
356 sn->shaded = ewin->state.shaded;
360 _SnapUpdateEwinSkipLists(Snapshot * sn, const EWin * ewin)
362 sn->skiptask = ewin->props.skip_ext_task;
363 sn->skipwinlist = ewin->props.skip_winlist;
364 sn->skipfocus = ewin->props.skip_focuslist;
368 _SnapUpdateEwinFlags(Snapshot * sn, const EWin * ewin)
370 EwinFlagsEncode(ewin, sn->flags);
374 _SnapUpdateEwinCmd(Snapshot * sn, const EWin * ewin)
376 if (ewin->icccm.wm_machine &&
377 strcmp(ewin->icccm.wm_machine, Mode.wm.machine_name))
381 sn->cmd = Estrdup(ewin->icccm.wm_command);
385 _SnapUpdateEwinGroups(Snapshot * sn, const EWin * ewin, char onoff)
388 Group *const *groups;
389 int i, j, num, num_groups;
403 ListWinGroupMembersForEwin(ewin, GROUP_ACTION_ANY, Mode.nogroup, &num);
404 for (i = 0; i < num; i++)
408 groups = EwinGetGroups(gwins[i], &num_groups);
414 sn = _SnapEwinGet(gwins[i], SNAP_MATCH_DEFAULT);
418 sn->num_groups = num_groups;
420 sn->groups = EMALLOC(int, num_groups);
422 for (j = 0; j < num_groups; j++)
424 sn->groups[j] = groups[j]->index;
448 _SnapUpdateEwinOpacity(Snapshot * sn, const EWin * ewin)
450 sn->opacity = OpacityToPercent(ewin->ewmh.opacity);
451 sn->focused_opacity = OpacityToPercent(ewin->props.focused_opacity);
455 _SnapUpdateEwinShadow(Snapshot * sn, const EWin * ewin)
457 sn->shadow = EoGetShadow(ewin);
463 _SnapUpdateEwin(Snapshot * sn, const EWin * ewin, unsigned int flags)
465 /* FIXME - We should check if anything is actually changed */
467 if (flags & SNAP_USE_BORDER)
468 _SnapUpdateEwinBorder(sn, ewin);
469 if (flags & SNAP_USE_COMMAND)
470 _SnapUpdateEwinCmd(sn, ewin);
471 if (flags & SNAP_USE_DESK)
472 _SnapUpdateEwinDesktop(sn, ewin);
473 if (flags & SNAP_USE_POS)
474 _SnapUpdateEwinLocation(sn, ewin);
475 if (flags & SNAP_USE_SIZE)
476 _SnapUpdateEwinSize(sn, ewin);
477 if (flags & SNAP_USE_LAYER)
478 _SnapUpdateEwinLayer(sn, ewin);
479 if (flags & SNAP_USE_STICKY)
480 _SnapUpdateEwinSticky(sn, ewin);
481 if (flags & SNAP_USE_SHADED)
482 _SnapUpdateEwinShade(sn, ewin);
483 if (flags & SNAP_USE_SKIP_LISTS)
484 _SnapUpdateEwinSkipLists(sn, ewin);
485 if (flags & SNAP_USE_FLAGS)
486 _SnapUpdateEwinFlags(sn, ewin);
488 if (flags & SNAP_USE_OPACITY)
489 _SnapUpdateEwinOpacity(sn, ewin);
490 if (flags & SNAP_USE_SHADOW)
491 _SnapUpdateEwinShadow(sn, ewin);
493 if (flags & SNAP_USE_GROUPS)
494 _SnapUpdateEwinGroups(sn, ewin, ewin->num_groups);
500 _EwinSnapSet(EWin * ewin, unsigned int match_flags, unsigned int use_flags)
504 /* Quit if nothing to be saved */
505 if (!match_flags || !(use_flags & SNAP_USE_ALL))
508 sn = _SnapEwinGet(ewin, match_flags);
512 if (use_flags & SNAP_AUTO)
513 sn->track_changes = 1;
515 sn->use_flags = use_flags & SNAP_USE_ALL;
517 _SnapUpdateEwin(sn, ewin, use_flags);
521 SnapshotEwinUpdate(const EWin * ewin, unsigned int flags)
526 if (!sn || !sn->track_changes)
530 Eprintf("SnapshotEwinUpdate %s: %#x\n", EwinGetTitle(ewin), flags);
533 if (flags & sn->use_flags)
534 _SnapUpdateEwin(sn, ewin, flags);
537 /* unsnapshot any saved info about this ewin */
539 _EwinSnapRemove(EWin * ewin)
542 _SnapDestroy(ewin->snap);
581 CB_ApplySnap(Dialog * d, int val, void *data __UNUSED__)
584 SnapDlgData *sd = (SnapDlgData *) DialogGetData(d);
585 unsigned int match_flags, use_flags;
590 ewin = EwinFindByClient(sd->client);
594 _EwinSnapRemove(ewin);
598 match_flags |= SNAP_MATCH_TITLE;
600 match_flags |= SNAP_MATCH_NAME;
602 match_flags |= SNAP_MATCH_CLASS;
604 match_flags |= SNAP_MATCH_ROLE;
610 if (sd->track_changes)
611 use_flags |= SNAP_AUTO;
613 use_flags |= SNAP_USE_BORDER;
615 use_flags |= SNAP_USE_COMMAND;
616 if (sd->snap_desktop)
617 use_flags |= SNAP_USE_DESK;
618 if (sd->snap_location)
619 use_flags |= SNAP_USE_POS;
621 use_flags |= SNAP_USE_SIZE;
623 use_flags |= SNAP_USE_LAYER;
625 use_flags |= SNAP_USE_STICKY;
627 use_flags |= SNAP_USE_SHADED;
628 if (sd->snap_skiplists)
629 use_flags |= SNAP_USE_SKIP_LISTS;
631 use_flags |= SNAP_USE_FLAGS;
633 if (sd->snap_opacity)
634 use_flags |= SNAP_USE_OPACITY;
636 use_flags |= SNAP_USE_SHADOW;
639 use_flags |= SNAP_USE_GROUPS;
644 _EwinSnapSet(ewin, match_flags, use_flags);
650 DialogSetData(d, NULL);
657 _DlgFillSnap(Dialog * d, DItem * table, void *data)
663 const EWin *ewin = (EWin *) data;
665 sd = ECALLOC(SnapDlgData, 1);
666 DialogSetData(d, sd);
667 sd->client = EwinGetClientXwin(ewin);
672 sd->match.title = (sn->match_flags & SNAP_MATCH_TITLE) != 0;
673 sd->match.name = (sn->match_flags & SNAP_MATCH_NAME) != 0;
674 sd->match.clss = (sn->match_flags & SNAP_MATCH_CLASS) != 0;
675 sd->match.role = (sn->match_flags & SNAP_MATCH_ROLE) != 0;
677 if (sn->track_changes)
678 sd->track_changes = 1;
679 if (sn->use_flags & SNAP_USE_BORDER)
681 if (sn->use_flags & SNAP_USE_COMMAND)
683 if (sn->use_flags & SNAP_USE_DESK)
684 sd->snap_desktop = 1;
685 if (sn->use_flags & SNAP_USE_POS)
686 sd->snap_location = 1;
687 if (sn->use_flags & SNAP_USE_SIZE)
689 if (sn->use_flags & SNAP_USE_LAYER)
691 if (sn->use_flags & SNAP_USE_STICKY)
693 if (sn->use_flags & SNAP_USE_SHADED)
695 if (sn->use_flags & SNAP_USE_SKIP_LISTS)
696 sd->snap_skiplists = 1;
697 if (sn->use_flags & SNAP_USE_FLAGS)
700 if (sn->use_flags & SNAP_USE_OPACITY)
701 sd->snap_opacity = 1;
702 if (sn->use_flags & SNAP_USE_SHADOW)
705 if (sn->use_flags & SNAP_USE_GROUPS)
710 if (EwinGetIcccmCName(ewin))
714 sd->match.role = ewin->icccm.wm_role != NULL;
718 sd->match.title = EwinGetIcccmName(ewin) != NULL;
722 table = DialogAddItem(table, DITEM_TABLE);
723 DialogItemTableSetOptions(table, 4, 0, 0, 0);
725 di = DialogAddItem(table, DITEM_CHECKBUTTON);
726 DialogItemSetAlign(di, 0, 512);
727 DialogItemSetText(di, _("Title:"));
728 DialogItemCheckButtonSetPtr(di, &sd->match.title);
730 di = DialogAddItem(table, DITEM_TEXT);
731 DialogItemSetColSpan(di, 3);
732 DialogItemSetAlign(di, 1024, 512);
733 DialogItemSetText(di, EwinGetIcccmName(ewin));
735 if (EwinGetIcccmCName(ewin))
737 di = DialogAddItem(table, DITEM_CHECKBUTTON);
738 DialogItemSetAlign(di, 0, 512);
739 DialogItemSetText(di, _("Name:"));
740 DialogItemCheckButtonSetPtr(di, &sd->match.name);
742 di = DialogAddItem(table, DITEM_TEXT);
743 DialogItemSetColSpan(di, 3);
744 DialogItemSetAlign(di, 1024, 512);
745 DialogItemSetText(di, EwinGetIcccmCName(ewin));
748 if (EwinGetIcccmClass(ewin))
750 di = DialogAddItem(table, DITEM_CHECKBUTTON);
751 DialogItemSetAlign(di, 0, 512);
752 DialogItemSetText(di, _("Class:"));
753 DialogItemCheckButtonSetPtr(di, &sd->match.clss);
755 di = DialogAddItem(table, DITEM_TEXT);
756 DialogItemSetColSpan(di, 3);
757 DialogItemSetAlign(di, 1024, 512);
758 DialogItemSetText(di, EwinGetIcccmClass(ewin));
761 if (ewin->icccm.wm_role)
763 di = DialogAddItem(table, DITEM_CHECKBUTTON);
764 DialogItemSetAlign(di, 0, 512);
765 DialogItemSetText(di, _("Role:"));
766 DialogItemCheckButtonSetPtr(di, &sd->match.role);
768 di = DialogAddItem(table, DITEM_TEXT);
769 DialogItemSetColSpan(di, 3);
770 DialogItemSetAlign(di, 1024, 512);
771 DialogItemSetText(di, ewin->icccm.wm_role);
774 if (ewin->icccm.wm_command)
776 di = DialogAddItem(table, DITEM_TEXT);
777 DialogItemSetAlign(di, 0, 512);
778 DialogItemSetText(di, _("Command:"));
780 di = DialogAddItem(table, DITEM_TEXT);
781 DialogItemSetColSpan(di, 3);
782 DialogItemSetAlign(di, 1024, 512);
784 /* if the command is long, cut in into slices of about 80 characters */
785 if (strlen(ewin->icccm.wm_command) > 80)
787 int i = 0, slice, last;
791 while ((i <= (int)strlen(ewin->icccm.wm_command))
792 && (i < (int)(sizeof(s) / 4)))
797 /* and make sure that we don't cut in the middle of a word. */
798 while ((ewin->icccm.wm_command[i++] != ' ')
799 && (i < (int)(sizeof(s) / 4)))
801 strncat(s, ewin->icccm.wm_command + last, slice);
802 if (i < (int)(sizeof(s) / 4))
807 DialogItemSetText(di, s);
810 DialogItemSetText(di, ewin->icccm.wm_command);
813 di = DialogAddItem(table, DITEM_SEPARATOR);
814 DialogItemSetColSpan(di, 4);
816 di = DialogAddItem(table, DITEM_CHECKBUTTON);
817 DialogItemSetColSpan(di, 4);
818 DialogItemSetText(di, _("Track Changes"));
819 DialogItemCheckButtonSetPtr(di, &sd->track_changes);
821 di = DialogAddItem(table, DITEM_CHECKBUTTON);
822 DialogItemSetColSpan(di, 2);
823 DialogItemSetText(di, _("Location"));
824 DialogItemCheckButtonSetPtr(di, &sd->snap_location);
826 di = DialogAddItem(table, DITEM_CHECKBUTTON);
827 DialogItemSetColSpan(di, 2);
828 DialogItemSetText(di, _("Border style"));
829 DialogItemCheckButtonSetPtr(di, &sd->snap_border);
831 di = DialogAddItem(table, DITEM_CHECKBUTTON);
832 DialogItemSetColSpan(di, 2);
833 DialogItemSetText(di, _("Size"));
834 DialogItemCheckButtonSetPtr(di, &sd->snap_size);
836 di = DialogAddItem(table, DITEM_CHECKBUTTON);
837 DialogItemSetColSpan(di, 2);
838 DialogItemSetText(di, _("Desktop"));
839 DialogItemCheckButtonSetPtr(di, &sd->snap_desktop);
841 di = DialogAddItem(table, DITEM_CHECKBUTTON);
842 DialogItemSetColSpan(di, 2);
843 DialogItemSetText(di, _("Shaded state"));
844 DialogItemCheckButtonSetPtr(di, &sd->snap_shaded);
846 di = DialogAddItem(table, DITEM_CHECKBUTTON);
847 DialogItemSetColSpan(di, 2);
848 DialogItemSetText(di, _("Sticky state"));
849 DialogItemCheckButtonSetPtr(di, &sd->snap_sticky);
851 di = DialogAddItem(table, DITEM_CHECKBUTTON);
852 DialogItemSetColSpan(di, 2);
853 DialogItemSetText(di, _("Stacking layer"));
854 DialogItemCheckButtonSetPtr(di, &sd->snap_layer);
856 di = DialogAddItem(table, DITEM_CHECKBUTTON);
857 DialogItemSetColSpan(di, 2);
858 DialogItemSetText(di, _("Window List Skip"));
859 DialogItemCheckButtonSetPtr(di, &sd->snap_skiplists);
862 di = DialogAddItem(table, DITEM_CHECKBUTTON);
863 DialogItemSetColSpan(di, 2);
864 DialogItemSetText(di, _("Opacity"));
865 DialogItemCheckButtonSetPtr(di, &sd->snap_opacity);
867 di = DialogAddItem(table, DITEM_CHECKBUTTON);
868 DialogItemSetColSpan(di, 2);
869 DialogItemSetText(di, _("Shadowing"));
870 DialogItemCheckButtonSetPtr(di, &sd->snap_shadow);
873 di = DialogAddItem(table, DITEM_CHECKBUTTON);
874 DialogItemSetColSpan(di, 2);
875 DialogItemSetText(di, _("Flags"));
876 DialogItemCheckButtonSetPtr(di, &sd->snap_flags);
878 di = DialogAddItem(table, DITEM_NONE);
879 DialogItemSetColSpan(di, 2);
881 if (ewin->icccm.wm_command)
885 if (ewin->icccm.wm_machine)
887 if (strcmp(ewin->icccm.wm_machine, Mode.wm.machine_name))
892 di = DialogAddItem(table, DITEM_CHECKBUTTON);
893 DialogItemSetColSpan(di, 4);
894 DialogItemSetText(di, _("Restart application on login"));
895 DialogItemCheckButtonSetPtr(di, &sd->snap_cmd);
899 di = DialogAddItem(table, DITEM_NONE);
900 DialogItemSetColSpan(di, 4);
905 di = DialogAddItem(table, DITEM_NONE);
906 DialogItemSetColSpan(di, 4);
911 di = DialogAddItem(table, DITEM_CHECKBUTTON);
912 DialogItemSetColSpan(di, 4);
913 DialogItemSetText(di, _("Remember this window's group(s)"));
914 DialogItemCheckButtonSetPtr(di, &sd->snap_group);
918 static const DialogDef DlgSnap = {
921 N_("Remembered Application Attributes"),
924 N_("Select the attributes of this\n"
925 "window you wish to Remember\n" "from now on\n"),
927 DLG_OAC, CB_ApplySnap,
931 _EwinSnapDialog(const EWin * ewin)
935 Esnprintf(s, sizeof(s), "SNAPSHOT_WINDOW-%#lx", EwinGetClientXwin(ewin));
937 DialogShowSimpleWithName(&DlgSnap, s, (void *)ewin);
940 /* list of remembered items for the remember dialog -- it's either
941 * _another_ global var, or a wrapper struct to pass data to the
942 * callback funcs besides the dialog itself -- this is much easier */
944 typedef struct _remwinlist {
949 static RememberWinList *rd_ewin_list;
952 CB_ApplyRemember(Dialog * d __UNUSED__, int val, void *data __UNUSED__)
956 if (val < 2 && rd_ewin_list)
958 for (i = 0; rd_ewin_list[i].snap; i++)
960 if (!rd_ewin_list[i].remove)
963 _SnapDestroy(rd_ewin_list[i].snap);
965 /* save snapshot info to disk */
969 if (((val == 0) || (val == 2)) && rd_ewin_list)
977 CB_RememberWindowSettings(Dialog * d __UNUSED__, int val __UNUSED__, void *data)
984 rd = (RememberWinList *) data;
986 /* Make sure its still there */
987 sn = (Snapshot *) ecore_list_goto(ss_list, rd->snap);
989 if (!sn || !sn->used)
991 _EwinSnapDialog(sn->used);
995 _DlgFillRemember(Dialog * d __UNUSED__, DItem * table, void *data __UNUSED__)
1003 DialogItemTableSetOptions(table, 3, 0, 0, 0);
1005 num = ecore_list_count(ss_list);
1006 rd_ewin_list = EMALLOC(RememberWinList, num + 1);
1010 di = DialogAddItem(table, DITEM_TEXT);
1011 DialogItemSetColSpan(di, 3);
1012 DialogItemSetFill(di, 0, 0);
1013 DialogItemSetAlign(di, 0, 512);
1014 DialogItemSetText(di, _("Delete"));
1018 ECORE_LIST_FOR_EACH(ss_list, sn)
1020 rd_ewin_list[i].snap = sn;
1021 rd_ewin_list[i].remove = 0;
1023 di = DialogAddItem(table, DITEM_CHECKBUTTON);
1024 DialogItemSetColSpan(di, 2);
1025 DialogItemSetAlign(di, 0, 512);
1027 s = EwinGetTitle(sn->used);
1028 else if (sn->win_title)
1032 Esnprintf(buf, sizeof(buf), "%s.%s", sn->win_name, sn->win_class);
1035 DialogItemSetText(di, s);
1036 DialogItemCheckButtonSetPtr(di, &(rd_ewin_list[i].remove));
1040 di = DialogAddItem(table, DITEM_BUTTON);
1041 DialogItemSetAlign(di, 0, 512);
1042 DialogItemSetText(di, _("Remembered Settings..."));
1043 DialogItemSetCallback(di, CB_RememberWindowSettings, 0,
1044 (char *)(&rd_ewin_list[i]));
1048 di = DialogAddItem(table, DITEM_TEXT);
1049 DialogItemSetText(di, _("Unused"));
1053 rd_ewin_list[num].snap = NULL;
1055 /* finish remember window */
1058 di = DialogAddItem(table, DITEM_TEXT);
1059 DialogItemSetColSpan(di, 3);
1060 DialogItemSetText(di,
1062 ("There are no active windows with remembered attributes."));
1066 const DialogDef DlgRemember = {
1069 N_("Remembered Windows Settings"),
1070 SOUND_SETTINGS_PAGER,
1071 "pix/snapshots.png",
1072 N_("Enlightenment Remembered\n" "Windows Settings Dialog\n"),
1074 DLG_OC, CB_ApplyRemember,
1076 #endif /* ENABLE_DIALOGS */
1078 /* ... combine writes, only save after a timeout */
1082 TIMER_DEL(ss_timer);
1083 TIMER_ADD(ss_timer, 5.0, SnapshotsSaveReal, NULL);
1086 /* save out all snapped info to disk */
1088 SnapshotsSaveReal(void *data __UNUSED__)
1092 char buf[4096], s[4096];
1095 if (!Mode.wm.save_ok)
1103 ECORE_LIST_FOR_EACH(ss_list, sn)
1105 fprintf(f, "NEW: %s\n", sn->name);
1107 fprintf(f, "WIN: %#lx\n", EwinGetClientXwin(sn->used));
1108 if ((sn->match_flags & SNAP_MATCH_TITLE) && sn->win_title)
1109 fprintf(f, "TITLE: %s\n", sn->win_title);
1110 if ((sn->match_flags & SNAP_MATCH_NAME) && sn->win_name)
1111 fprintf(f, "NAME: %s\n", sn->win_name);
1112 if ((sn->match_flags & SNAP_MATCH_CLASS) && sn->win_class)
1113 fprintf(f, "CLASS: %s\n", sn->win_class);
1114 if ((sn->match_flags & SNAP_MATCH_ROLE) && sn->win_role)
1115 fprintf(f, "ROLE: %s\n", sn->win_role);
1116 if (sn->track_changes)
1117 fprintf(f, "AUTO: yes\n");
1118 if ((sn->use_flags & SNAP_USE_BORDER) && sn->border_name)
1119 fprintf(f, "BORDER: %s\n", sn->border_name);
1120 if ((sn->use_flags & SNAP_USE_COMMAND) && sn->cmd)
1121 fprintf(f, "CMD: %s\n", sn->cmd);
1122 if (sn->use_flags & SNAP_USE_DESK)
1123 fprintf(f, "DESKTOP: %i\n", sn->desktop);
1124 if (sn->use_flags & SNAP_USE_POS)
1125 fprintf(f, "RES: %i %i\n", WinGetW(VROOT), WinGetH(VROOT));
1126 if (sn->use_flags & SNAP_USE_SIZE)
1127 fprintf(f, "WH: %i %i\n", sn->w, sn->h);
1128 if (sn->use_flags & SNAP_USE_POS)
1129 fprintf(f, "XY: %i %i %i %i\n", sn->x, sn->y, sn->area_x, sn->area_y);
1130 if (sn->use_flags & SNAP_USE_LAYER)
1131 fprintf(f, "LAYER: %i\n", sn->layer);
1132 if (sn->use_flags & SNAP_USE_STICKY)
1133 fprintf(f, "STICKY: %i\n", sn->sticky);
1134 if (sn->use_flags & SNAP_USE_SHADED)
1135 fprintf(f, "SHADE: %i\n", sn->shaded);
1136 if (sn->use_flags & SNAP_USE_SKIP_LISTS)
1138 fprintf(f, "SKIPTASK: %i\n", sn->skiptask);
1139 fprintf(f, "SKIPWINLIST: %i\n", sn->skipwinlist);
1140 fprintf(f, "SKIPFOCUS: %i\n", sn->skipfocus);
1142 if (sn->use_flags & SNAP_USE_FLAGS)
1143 fprintf(f, "FLAGS: %#x %#x\n", sn->flags[0], sn->flags[1]);
1145 if (sn->use_flags & SNAP_USE_OPACITY)
1146 fprintf(f, "OPACITY: %i %i\n", sn->opacity, sn->focused_opacity);
1147 if (sn->use_flags & SNAP_USE_SHADOW)
1148 fprintf(f, "SHADOW: %i\n", sn->shadow);
1152 for (j = 0; j < sn->num_groups; j++)
1153 fprintf(f, "GROUP: %i\n", sn->groups[j]);
1160 Esnprintf(buf, sizeof(buf), "%s.snapshots", EGetSavePrefix());
1162 if (EDebug(EDBUG_TYPE_SNAPS))
1163 Eprintf("SnapshotsSaveReal: %s\n", buf);
1166 Alert(_("Error saving snaps file\n"));
1171 TIMER_DEL(ss_timer);
1176 SnapshotsSpawn(void)
1180 ECORE_LIST_FOR_EACH(ss_list, sn)
1182 if ((sn->use_flags & SNAP_USE_COMMAND) && (sn->cmd) &&
1183 !sn->used && !(sn->match_flags & SNAP_MATCH_MULTIPLE))
1185 sn->startup_id = ++Mode.apps.startup_id;
1191 /* load all snapped info */
1195 Snapshot *sn = NULL;
1198 int res_w, res_h, a, b, c, d;
1202 Esnprintf(buf, sizeof(buf), "%s.snapshots", EGetSavePrefix());
1203 f = fopen(buf, "r");
1207 res_w = WinGetW(VROOT);
1208 res_h = WinGetH(VROOT);
1209 while (fgets(buf, sizeof(buf), f))
1211 s = strchr(buf, ':');
1216 if (!buf[0] || !s[0])
1218 if (!strcmp(buf, "NEW"))
1220 res_w = WinGetW(VROOT);
1221 res_h = WinGetH(VROOT);
1222 sn = _SnapCreate(s);
1226 if (!strcmp(buf, "WIN"))
1228 sn->win = strtoul(s, NULL, 0);
1230 else if (!strcmp(buf, "TITLE"))
1232 sn->win_title = Estrdup(s);
1233 sn->match_flags |= SNAP_MATCH_TITLE;
1235 else if (!strcmp(buf, "NAME"))
1237 sn->win_name = Estrdup(s);
1238 sn->match_flags |= SNAP_MATCH_NAME;
1240 else if (!strcmp(buf, "CLASS"))
1242 sn->win_class = Estrdup(s);
1243 sn->match_flags |= SNAP_MATCH_CLASS;
1245 else if (!strcmp(buf, "ROLE"))
1247 sn->win_role = Estrdup(s);
1248 sn->match_flags |= SNAP_MATCH_ROLE;
1250 else if (!strcmp(buf, "AUTO"))
1252 sn->track_changes = 1;
1254 else if (!strcmp(buf, "BORDER"))
1256 sn->use_flags |= SNAP_USE_BORDER;
1257 sn->border_name = Estrdup(s);
1259 else if (!strcmp(buf, "CMD"))
1261 sn->use_flags |= SNAP_USE_COMMAND;
1262 sn->cmd = Estrdup(s);
1264 else if (!strcmp(buf, "DESKTOP"))
1266 sn->use_flags |= SNAP_USE_DESK;
1267 sn->desktop = atoi(s);
1269 else if (!strcmp(buf, "RES"))
1271 if (sscanf(s, "%u %u", &a, &b) < 2)
1273 if (a <= 0 || b <= 0)
1278 else if (!strcmp(buf, "WH"))
1280 if (sscanf(s, "%u %u", &a, &b) < 2)
1282 if (a <= 0 || b <= 0)
1284 sn->use_flags |= SNAP_USE_SIZE;
1288 else if (!strcmp(buf, "XY"))
1290 if (sscanf(s, "%d %d %u %u", &a, &b, &c, &d) < 4)
1292 sn->use_flags |= SNAP_USE_POS;
1295 /* we changed reses since we last used this snapshot file */
1296 if (res_w != WinGetW(VROOT))
1298 if (sn->use_flags & SNAP_USE_SIZE)
1300 if ((res_w - sn->w) <= 0)
1304 (sn->x * (WinGetW(VROOT) - sn->w)) /
1309 if (sn->x >= WinGetW(VROOT))
1310 sn->x = WinGetW(VROOT) - 32;
1313 if (res_h != WinGetH(VROOT))
1315 if (sn->use_flags & SNAP_USE_SIZE)
1317 if ((res_h - sn->h) <= 0)
1321 (sn->y * (WinGetH(VROOT) - sn->h)) /
1326 if (sn->y >= WinGetH(VROOT))
1327 sn->y = WinGetH(VROOT) - 32;
1333 else if (!strcmp(buf, "LAYER"))
1335 sn->use_flags |= SNAP_USE_LAYER;
1336 sn->layer = atoi(s);
1338 else if (!strcmp(buf, "STICKY"))
1340 sn->use_flags |= SNAP_USE_STICKY;
1341 sn->sticky = atoi(s);
1343 else if (!strcmp(buf, "SHADE"))
1345 sn->use_flags |= SNAP_USE_SHADED;
1346 sn->shaded = atoi(s);
1348 else if (!strcmp(buf, "SKIPFOCUS"))
1350 sn->use_flags |= SNAP_USE_SKIP_LISTS;
1351 sn->skipfocus = atoi(s);
1353 else if (!strcmp(buf, "SKIPTASK"))
1355 sn->use_flags |= SNAP_USE_SKIP_LISTS;
1356 sn->skiptask = atoi(s);
1358 else if (!strcmp(buf, "SKIPWINLIST"))
1360 sn->use_flags |= SNAP_USE_SKIP_LISTS;
1361 sn->skipwinlist = atoi(s);
1363 else if (!strcmp(buf, "FLAGS"))
1365 sn->use_flags |= SNAP_USE_FLAGS;
1366 sn->flags[0] = sn->flags[1] = 0;
1367 sscanf(s, "%i %i", sn->flags, sn->flags + 1);
1369 else if (!strcmp(buf, "GROUP"))
1371 sn->use_flags |= SNAP_USE_GROUPS;
1373 sn->groups = EREALLOC(int, sn->groups, sn->num_groups);
1375 sn->groups[sn->num_groups - 1] = atoi(s);
1376 GroupRemember(sn->groups[sn->num_groups - 1]);
1379 else if (!strcmp(buf, "OPACITY"))
1381 sn->use_flags |= SNAP_USE_OPACITY;
1384 sscanf(s, "%i %i", &a, &b);
1386 b = 100; /* BW compat - focused is opaque */
1388 sn->focused_opacity = b;
1390 else if (!strcmp(buf, "SHADOW"))
1392 sn->use_flags |= SNAP_USE_SHADOW;
1393 sn->shadow = atoi(s);
1401 /* make a client window conform to snapshot info */
1403 SnapshotEwinApply(EWin * ewin)
1407 unsigned int use_flags;
1409 _SnapEwinFind(ewin); /* Find a saved settings match */
1414 if (ewin->props.autosave)
1415 _EwinSnapSet(ewin, SNAP_MATCH_DEFAULT, SNAP_USE_ALL | SNAP_AUTO);
1419 if (ewin->props.autosave)
1420 sn->track_changes = 1;
1422 use_flags = sn->use_flags;
1423 /* If restarting don't override stuff set in attributes/properties */
1424 if (ewin->state.identified)
1425 use_flags &= SNAP_USE_LAYER | SNAP_USE_SHADOW | SNAP_USE_GROUPS |
1428 if (use_flags & SNAP_USE_STICKY)
1429 EoSetSticky(ewin, sn->sticky);
1431 if (use_flags & SNAP_USE_DESK)
1432 EoSetDesk(ewin, DeskGet(sn->desktop));
1434 if (use_flags & SNAP_USE_SIZE)
1436 ewin->client.w = sn->w;
1437 ewin->client.h = sn->h;
1438 ewin->state.maximized_horz = ewin->state.maximized_vert = 0;
1441 if (use_flags & SNAP_USE_POS)
1443 ewin->state.placed = 1;
1444 ewin->client.x = sn->x;
1445 ewin->client.y = sn->y;
1446 #if 0 /* No, do later in EwinDetermineArea() */
1447 ewin->area_x = sn->area_x;
1448 ewin->area_y = sn->area_y;
1450 if (!EoIsSticky(ewin))
1452 DeskGetArea(EoGetDesk(ewin), &ax, &ay);
1453 ewin->client.x += ((sn->area_x - ax) * WinGetW(VROOT));
1454 ewin->client.y += ((sn->area_y - ay) * WinGetH(VROOT));
1458 if (use_flags & SNAP_USE_LAYER)
1459 EoSetLayer(ewin, sn->layer);
1461 if (use_flags & SNAP_USE_SKIP_LISTS)
1463 ewin->props.skip_focuslist = sn->skipfocus;
1464 ewin->props.skip_ext_task = sn->skiptask;
1465 ewin->props.skip_winlist = sn->skipwinlist;
1468 if (use_flags & SNAP_USE_FLAGS)
1469 EwinFlagsDecode(ewin, sn->flags);
1471 if (use_flags & SNAP_USE_SHADED)
1472 ewin->state.shaded = sn->shaded;
1474 if (use_flags & SNAP_USE_BORDER)
1475 EwinBorderSetInitially(ewin, sn->border_name);
1477 if (use_flags & SNAP_USE_GROUPS)
1478 GroupsEwinAdd(ewin, sn->groups, sn->num_groups);
1481 if (use_flags & SNAP_USE_OPACITY)
1483 sn->opacity = OpacityFix(sn->opacity, 0);
1484 sn->focused_opacity = OpacityFix(sn->focused_opacity, 0);
1485 ewin->ewmh.opacity = OpacityFromPercent(sn->opacity);
1486 ewin->props.focused_opacity = OpacityFromPercent(sn->focused_opacity);
1489 if (use_flags & SNAP_USE_SHADOW)
1490 EoSetShadow(ewin, sn->shadow);
1493 if (EDebug(EDBUG_TYPE_SNAPS))
1494 Eprintf("Snap get snap %#lx: %4d+%4d %4dx%4d: %s\n",
1495 EwinGetClientXwin(ewin), ewin->client.x, ewin->client.y,
1496 ewin->client.w, ewin->client.h, EwinGetTitle(ewin));
1499 /* Detach snapshot from ewin */
1501 SnapshotEwinUnmatch(EWin * ewin)
1514 SnapshotEwinParse(EWin * ewin, const char *params)
1519 unsigned int match_flags, use_flags;
1525 match_flags = SNAP_MATCH_DEFAULT;
1532 sscanf(p, "%s %n", param, &len);
1537 if (!strcmp(param, "all"))
1539 use_flags = SNAP_USE_ALL;
1542 else if (!strcmp(param, "dialog"))
1544 _EwinSnapDialog(ewin);
1548 else if (!strcmp(param, "none"))
1549 _EwinSnapRemove(ewin);
1550 else if (!strcmp(param, "auto"))
1551 use_flags |= SNAP_AUTO;
1552 else if (!strcmp(param, "border"))
1553 use_flags |= SNAP_USE_BORDER;
1554 else if (!strcmp(param, "command"))
1555 use_flags |= SNAP_USE_COMMAND;
1556 else if (!strcmp(param, "desktop"))
1557 use_flags |= SNAP_USE_DESK;
1558 else if (!strcmp(param, "location"))
1559 use_flags |= SNAP_USE_POS;
1560 else if (!strcmp(param, "size"))
1561 use_flags |= SNAP_USE_SIZE;
1562 else if (!strcmp(param, "layer"))
1563 use_flags |= SNAP_USE_LAYER;
1564 else if (!strcmp(param, "shade"))
1565 use_flags |= SNAP_USE_SHADED;
1566 else if (!strcmp(param, "sticky"))
1567 use_flags |= SNAP_USE_STICKY;
1569 else if (!strcmp(param, "opacity"))
1570 use_flags |= SNAP_USE_OPACITY;
1571 else if (!strcmp(param, "shadow"))
1572 use_flags |= SNAP_USE_SHADOW;
1574 else if (!strcmp(param, "group"))
1575 use_flags |= SNAP_USE_GROUPS;
1580 match_flags = ewin->snap->match_flags;
1581 use_flags |= ewin->snap->use_flags;
1584 _EwinSnapSet(ewin, match_flags, use_flags);
1593 const char SnapshotsIpcText[] =
1594 "usage:\n" " list_remember [full]\n"
1595 " Retrieve a list of remembered windows. with full, the list\n"
1596 " includes the window's remembered attributes\n";
1598 #define SS(s) ((s) ? (s) : NoText)
1599 static const char NoText[] = "-NONE-";
1602 _SnapShow(void *data, void *prm)
1604 Snapshot *sn = (Snapshot *) data;
1605 int full = prm != NULL;
1606 char buf[FILEPATH_LEN_MAX];
1609 name = (sn->name) ? sn->name : "???";
1614 IpcPrintf("%s\n", name);
1616 IpcPrintf("%s (unused)\n", name);
1620 #define SU(sn, item) ((sn->match_flags & item) ? '>' : ':')
1623 Esnprintf(buf, sizeof(buf), "In use - %#lx", EwinGetClientXwin(sn->used));
1625 Esnprintf(buf, sizeof(buf), "*** Unused ***");
1626 IpcPrintf(" Snapshot Name: %s %s\n", name, buf);
1628 IpcPrintf(" Window Title%c %s\n", SU(sn, SNAP_MATCH_TITLE),
1631 IpcPrintf(" Window Name%c %s\n", SU(sn, SNAP_MATCH_NAME),
1634 IpcPrintf(" Window Class%c %s\n", SU(sn, SNAP_MATCH_CLASS),
1637 IpcPrintf(" Window Role%c %s\n", SU(sn, SNAP_MATCH_ROLE),
1640 if (sn->track_changes)
1641 IpcPrintf(" Tracking changes\n");
1642 if (sn->use_flags & SNAP_USE_BORDER)
1643 IpcPrintf(" Border Name: %s\n", SS(sn->border_name));
1644 if (sn->use_flags & SNAP_USE_DESK)
1645 IpcPrintf(" desktop: %d\n", sn->desktop);
1646 if (sn->use_flags & SNAP_USE_POS)
1647 IpcPrintf(" (x, y): %d, %d area (x, y): %d, %d\n",
1648 sn->x, sn->y, sn->area_x, sn->area_y);
1649 if (sn->use_flags & SNAP_USE_SIZE)
1650 IpcPrintf(" (w, h): %d, %d\n", sn->w, sn->h);
1651 if (sn->use_flags & SNAP_USE_LAYER)
1652 IpcPrintf(" layer: %d\n", sn->layer);
1653 if (sn->use_flags & SNAP_USE_STICKY)
1654 IpcPrintf(" sticky: %d\n", sn->sticky);
1655 if (sn->use_flags & SNAP_USE_SHADED)
1656 IpcPrintf(" shade: %d\n", sn->shaded);
1657 if (sn->use_flags & SNAP_USE_COMMAND)
1658 IpcPrintf(" command: %s\n", SS(sn->cmd));
1659 if (sn->use_flags & SNAP_USE_SKIP_LISTS)
1661 (" skiptask: %d skipfocus: %d skipwinlist: %d\n",
1662 sn->skiptask, sn->skipfocus, sn->skipwinlist);
1663 if (sn->use_flags & SNAP_USE_FLAGS)
1664 IpcPrintf(" flags: %#x %#x\n", sn->flags[0], sn->flags[1]);
1669 SnapshotsIpcFunc(const char *params)
1672 char cmd[128], prm[4096];
1675 cmd[0] = prm[0] = '\0';
1680 sscanf(p, "%100s %4000s %n", cmd, prm, &len);
1684 if (ecore_list_count(ss_list) <= 0)
1686 IpcPrintf("No remembered windows\n");
1690 if (!p || cmd[0] == '?')
1692 ecore_list_for_each(ss_list, _SnapShow, NULL);
1696 ecore_list_for_each(ss_list, _SnapShow, (void *)1L);